Page 1 of 1

【技术干货】流媒体参数动态更新对接demo

Posted: 2023年 Apr 21日 10:35
by 0x1abin

1. 功能接入

1.1 代码导入

tuya_ipc_media_update_demo.tar.bz2
(1.01 KiB) Downloaded 119 times

include/tuya_ipc_media_update_demo.h
src/tuya_ipc_media_update_demo.c

1.2 tuya_ipc_media_demo取流适配

音频取流线程

Code: Select all

void *thread_live_audio(void *arg)
{
    char fullpath[128] = {0};
    sprintf(fullpath, "%s/resource/media/demo_audio.raw", s_raw_path);

    FILE *aFp = fopen(fullpath, "rb");
    if(aFp == NULL)
    {
        PR_ERR("can't read live audio file %s\n",fullpath);
        pthread_exit(0);
    }
    char audioBuf[AUDIO_FRAME_SIZE];
    MEDIA_FRAME_T pcm_frame = {0};
    pcm_frame.type = E_AUDIO_FRAME;

    while(1)
    {
        if( g_media_update_wait == 1) {
            usleep(100*1000);
            continue ;
        }

        if(g_a_handle[0] == NULL) {
        	g_a_handle[0] = tuya_ipc_ring_buffer_open(0, 0, E_IPC_STREAM_AUDIO_MAIN, E_RBUF_WRITE);
            if (g_a_handle[0] == NULL) {
                PR_ERR("tuya_ipc_ring_buffer_open err  ");
                sleep(1);
                continue;
            }
            PR_DEBUG("tuya_ipc_ring_buffer_open success  ");
        }
        int size = fread(audioBuf, 1, AUDIO_FRAME_SIZE, aFp);
        if(size < AUDIO_FRAME_SIZE)
        {
            rewind(aFp);
            continue;
        }
        int frameRate = AUDIO_FPS;
        int sleepTick = 1000000/frameRate;
        static UINT64_T pts = 0;
        pts += sleepTick;
        pcm_frame.size = size;
        pcm_frame.p_buf = audioBuf;
        pcm_frame.pts = pts;
        TUYA_APP_Put_Frame(g_a_handle[0],&pcm_frame);

        usleep(sleepTick);
    }
    if(g_a_handle[0]) {
	    tuya_ipc_ring_buffer_close(g_a_handle[0]);   
	    g_a_handle[0] = NULL ;
    }
    pthread_exit(0);
}

h265码率读取:

Code: Select all

int read_one_frame_from_demo_video_file_hevc(unsigned char *pVideoBuf,unsigned int offset,unsigned int BufSize,unsigned int *IskeyFrame,unsigned int
*FramLen,unsigned int *Frame_start)
{
    int pos = 0;
    int bNeedCal = 0;
    unsigned char NalType=0;
    int idx=0;
    if(BufSize<=5)
    {
        printf("bufSize is too small\n");
        return -1;
    }
    for(pos=0;pos <= BufSize-5;pos++)
    {
        if(pVideoBuf[pos]==0x00
            &&pVideoBuf[pos+1]==0x00
            &&pVideoBuf[pos+2]==0x00
            &&pVideoBuf[pos+3]==0x01)
        {
            NalType = (pVideoBuf[pos + 4] & 0x7E) >> 1;
            if(NalType == 0x20)
            {
                if(bNeedCal==1)
                {
                    *FramLen=pos-idx;
                    return 0;
                }

                *IskeyFrame = 1;
                *Frame_start = offset+pos;
                bNeedCal=1;
                idx=pos;
            }
            else if(NalType ==0x1)
            {
               if(bNeedCal)
               {
                  *FramLen=pos-idx;
                  return 0;
               }
               *Frame_start=offset+pos;
               *IskeyFrame = 0;
               idx = pos;
               bNeedCal=1;
            }
        }
    }

    *FramLen = BufSize;
    return 0;
}

视频取流线程打开264和265视频文件,根据g_meida_update_type标志位切换。

Code: Select all

void *thread_live_video(void *arg)
{
    char raw_fullpath[128] = {0};
    char info_fullpath[128] = {0};
    unsigned int FrameLen=0,Frame_start=0;
    unsigned int offset=0;
    unsigned int IsKeyFrame=0;
    unsigned char *pVideoBuf = NULL;
    int channel = 0;
    sprintf(raw_fullpath, "%s/resource/media/demo_video.264", s_raw_path);

    PR_DEBUG("start live video using %s",raw_fullpath);

    FILE *streamBin_fp = fopen(raw_fullpath, "rb");
    if((streamBin_fp == NULL))
    {
        PR_ERR("can't read live video file %s\n",raw_fullpath);
        pthread_exit(0);
    }
    fseek(streamBin_fp, 0, SEEK_END);
    UINT_T file_size = ftell(streamBin_fp);
    fseek(streamBin_fp, 0, SEEK_SET);
    pVideoBuf = malloc(file_size);
    fread(pVideoBuf, 1, file_size, streamBin_fp);

    char raw_fullpath_hevc[128] = { 0 };
    sprintf(raw_fullpath_hevc, "%s/resource/media/demo_video.265", s_raw_path);
    PR_DEBUG("start live video using %s",raw_fullpath_hevc);
    FILE *streamBin_fp_hevc = fopen(raw_fullpath_hevc, "rb");
    if ((streamBin_fp_hevc == NULL)) {
        PR_DEBUG("can't read live video file %s\n", raw_fullpath_hevc);
        pthread_exit(0);
    }
    fseek(streamBin_fp_hevc, 0, SEEK_END);
    UINT_T file_size_hevc = ftell(streamBin_fp_hevc);
    fseek(streamBin_fp_hevc, 0, SEEK_SET);
    unsigned char *pVideoBuf_hevc  = malloc(file_size_hevc);
    fread(pVideoBuf_hevc, 1, file_size_hevc, streamBin_fp_hevc);
    
    MEDIA_FRAME_T video_frame = {0};
    
    while(1)
    {
        if( g_media_update_wait == 1) {
            offset = 0 ;
            Frame_start = 0 ;
            FrameLen = 0 ;
            IsKeyFrame = 0 ;
            usleep(100*1000);
            continue ;
        }

		if(g_v_handle[channel] == NULL) {
			g_v_handle[channel] = tuya_ipc_ring_buffer_open(0, channel, E_IPC_STREAM_VIDEO_MAIN, E_RBUF_WRITE);
		    if (g_v_handle[channel] == NULL) {
		        PR_ERR("tuya_ipc_ring_buffer_open err  ");
		        sleep(1);
		        continue;
		    }
		    PR_DEBUG("tuya_ipc_ring_buffer_open success  ");
		}
		if(g_v_handle_sub[channel] == NULL) {
		    g_v_handle_sub[channel] = tuya_ipc_ring_buffer_open(0, channel, E_IPC_STREAM_VIDEO_SUB, E_RBUF_WRITE);
		    if (g_v_handle_sub[channel] == NULL) {
		         PR_ERR("tuya_ipc_ring_buffer_open err  ");
		        sleep(1);
		        continue;
		    }
		    PR_DEBUG("tuya_ipc_ring_buffer_open success  ");
		}

        if(g_meida_update_type != MEDIA_UPDATE_H265) {

            offset=Frame_start+FrameLen;
            if(offset>=file_size)
            {
                offset=0;
            }
            read_one_frame_from_demo_video_file(pVideoBuf+offset,offset,file_size-offset,&IsKeyFrame,&FrameLen,&Frame_start);
            //Note: For I frame of H264, SPS/PPS/SEI/IDR should be combined within one frame, and the NALU separator should NOT be deleted.
            if(IsKeyFrame==1)
            {
                video_frame.type = E_VIDEO_I_FRAME;
                video_frame.size = FrameLen;
            }
            else
            {
                video_frame.type = E_VIDEO_PB_FRAME;
                video_frame.size = FrameLen;
            }

            int frameRate = 30;
            int sleepTick = 1000000/frameRate;
            static UINT64_T pts = 0;
            pts += sleepTick;

            video_frame.p_buf = pVideoBuf+Frame_start;
            video_frame.pts = pts;
            /* Send HD video data to the SDK */
            TUYA_APP_Put_Frame(g_v_handle[channel], &video_frame);
            /* Send SD video data to the SDK */
            TUYA_APP_Put_Frame(g_v_handle_sub[channel], &video_frame);
            usleep(sleepTick);
            } else  {

                offset = Frame_start + FrameLen;
                if (offset >= file_size_hevc) {
                    offset = 0;
                }
                read_one_frame_from_demo_video_file_hevc(pVideoBuf_hevc + offset, offset, file_size_hevc - offset, &IsKeyFrame, &FrameLen, &Frame_start);
                //Note: For I frame of H264, SPS/PPS/SEI/IDR should be combined within one frame, and the NALU separator should NOT be deleted.
                if (IsKeyFrame == 1) {
                    video_frame.type = E_VIDEO_I_FRAME;
                    video_frame.size = FrameLen;
                } else {
                    video_frame.type = E_VIDEO_PB_FRAME;
                    video_frame.size = FrameLen;
                }

                int frameRate = 25;        //30;
                int sleepTick = 1000000 / frameRate;
                static UINT64_T pts = 0;
                pts += sleepTick;

                video_frame.p_buf = pVideoBuf_hevc + Frame_start;
                video_frame.pts = pts;
                /* Send HD video data to the SDK */
                TUYA_APP_Put_Frame(g_v_handle[channel], &video_frame);
                /* Send SD video data to the SDK */
                 TUYA_APP_Put_Frame(g_v_handle_sub[channel], &video_frame);
                usleep(sleepTick);
        }
    }
    if(g_v_handle[channel]) {
        tuya_ipc_ring_buffer_close(g_v_handle[channel]);
        g_v_handle[channel] = NULL ;
    }

    if(g_v_handle_sub[channel]) {
        tuya_ipc_ring_buffer_close(g_v_handle_sub[channel]);
        g_v_handle_sub[channel] = NULL ;
    }
    
    pthread_exit(0);
}

1.2 测试命令

可以在IPC_APP_simulation中加入以下测试指令

Code: Select all

else if (0 == strcmp(test_input, "update_media_265")) {
    IPC_APP_Set_Media_Update_Wait(1);  //thread_live_xxx取流线程暂停取流
    sleep(1);
    TUYA_IPC_SDK_MEDIA_STREAM_S h265_media_stream = {0};
    __set_media_info_h265(&h265_media_stream);   //将最新的码流参数填入h265_media_stream
    tuya_ipc_media_adapter_notify_media_close(); //关闭sdk流媒体功能
    TUYA_APP_DeInit_Ring_Buffer(0);              //反初始化Ring Buffer
#defined(IPC_CHANNEL_NUM) && (IPC_CHANNEL_NUM==2)
    TUYA_APP_DeInit_Ring_Buffer(1);              //反初始化多镜头设备的第二路码流Ring Buffer
#endif
    TUYA_APP_Init_Ring_Buffer(&h265_media_stream.media_info, 0); //使用新的流媒体参数初始化Ring Buffer
#if defined(IPC_CHANNEL_NUM) && (IPC_CHANNEL_NUM==2)
    TUYA_APP_Init_Ring_Buffer(&h265_media_stream.media_info2, 1);
#endif
    IPC_APP_Media_Adapter_Set(&h265_media_stream);    //将新的流媒体参数设置给sdk,重启流媒体服务
    IPC_APP_Set_Media_Update_Type(MEDIA_UPDATE_H265); //视频编码格式更新为h265
    IPC_APP_Set_Media_Update_Wait(0);                 // thread_live_xxx取流线程恢复取流,塞入Ring Buffer
    PR_DEBUG("media update h265 end\n");
}

Code: Select all

void __set_media_info_h265(TUYA_IPC_SDK_MEDIA_STREAM_S* p_media_info)
{
    /*media info (essential)*/
    /* main stream(HD), video configuration*/
    /* NOTE
    FIRST:If the main stream supports multiple video stream configurations, set each item to the upper limit of the allowed configuration.
    SECOND:E_IPC_STREAM_VIDEO_MAIN must exist.It is the data source of SDK.
    please close the E_IPC_STREAM_VIDEO_SUB for only one stream*/
    p_media_info->media_info.stream_enable[E_IPC_STREAM_VIDEO_MAIN] = TRUE;    /* Whether to enable local HD video streaming */
    p_media_info->media_info.video_fps[E_IPC_STREAM_VIDEO_MAIN] = 30;  /* FPS */
    p_media_info->media_info.video_gop[E_IPC_STREAM_VIDEO_MAIN] = 30;  /* GOP */
    p_media_info->media_info.video_bitrate[E_IPC_STREAM_VIDEO_MAIN] = TUYA_VIDEO_BITRATE_2M; /* Rate limit */
    p_media_info->media_info.video_width[E_IPC_STREAM_VIDEO_MAIN] = 640; /* Single frame resolution of width*/
    p_media_info->media_info.video_height[E_IPC_STREAM_VIDEO_MAIN] = 360;/* Single frame resolution of height */
    p_media_info->media_info.video_freq[E_IPC_STREAM_VIDEO_MAIN] = 90000; /* Clock frequency */
    p_media_info->media_info.video_codec[E_IPC_STREAM_VIDEO_MAIN] = TUYA_CODEC_VIDEO_H265; /* Encoding format */
    
    /* substream(HD), video configuration */
    /* Please note that if the substream supports multiple video stream configurations, please set each item to the upper limit of the allowed configuration. */
    p_media_info->media_info.stream_enable[E_IPC_STREAM_VIDEO_SUB] = TRUE;     /* Whether to enable local SD video stream */
    p_media_info->media_info.video_fps[E_IPC_STREAM_VIDEO_SUB] = 30;  /* FPS */
    p_media_info->media_info.video_gop[E_IPC_STREAM_VIDEO_SUB] = 30;  /* GOP */
    p_media_info->media_info.video_bitrate[E_IPC_STREAM_VIDEO_SUB] = TUYA_VIDEO_BITRATE_2M; /* Rate limit */
    p_media_info->media_info.video_width[E_IPC_STREAM_VIDEO_SUB] = 640; /* Single frame resolution of width */
    p_media_info->media_info.video_height[E_IPC_STREAM_VIDEO_SUB] = 360;/* Single frame resolution of height */
    p_media_info->media_info.video_freq[E_IPC_STREAM_VIDEO_SUB] = 90000; /* Clock frequency */
    p_media_info->media_info.video_codec[E_IPC_STREAM_VIDEO_SUB] = TUYA_CODEC_VIDEO_H265; /* Encoding format */
    
    /* Audio stream configuration.
    Note: The internal P2P preview, cloud storage, and local storage of the SDK are all use E_IPC_STREAM_AUDIO_MAIN data. */
    p_media_info->media_info.stream_enable[E_IPC_STREAM_AUDIO_MAIN] = TRUE;         /* Whether to enable local sound collection */
    p_media_info->media_info.audio_codec[E_IPC_STREAM_AUDIO_MAIN] = TUYA_CODEC_AUDIO_PCM;/* Encoding format */
    p_media_info->media_info.audio_sample [E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_SAMPLE_8K;/* Sampling Rate */
    p_media_info->media_info.audio_databits [E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_DATABITS_16;/* Bit width */
    p_media_info->media_info.audio_channel[E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_CHANNEL_MONO;/* channel */
    p_media_info->media_info.audio_fps[E_IPC_STREAM_AUDIO_MAIN] = 25;/* Fragments per second */
    
    /************************************** second camera parameter  begin*****************************************************/
#if defined(IPC_CHANNEL_NUM) && (IPC_CHANNEL_NUM==2)
    p_media_info->media_info2.stream_enable[E_IPC_STREAM_VIDEO_MAIN] = TRUE;    /* Whether to enable local HD video streaming */
    p_media_info->media_info2.video_fps[E_IPC_STREAM_VIDEO_MAIN] = 30;  /* FPS */
    p_media_info->media_info2.video_gop[E_IPC_STREAM_VIDEO_MAIN] = 60;  /* GOP */
    p_media_info->media_info2.video_bitrate[E_IPC_STREAM_VIDEO_MAIN] = TUYA_VIDEO_BITRATE_2M; /* Rate limit */
    p_media_info->media_info2.video_width[E_IPC_STREAM_VIDEO_MAIN] = 426; /* Single frame resolution of width*/
    p_media_info->media_info2.video_height[E_IPC_STREAM_VIDEO_MAIN] = 240;/* Single frame resolution of height */
    p_media_info->media_info2.video_freq[E_IPC_STREAM_VIDEO_MAIN] = 90000; /* Clock frequency */
    p_media_info->media_info2.video_codec[E_IPC_STREAM_VIDEO_MAIN] = TUYA_CODEC_VIDEO_H265; /* Encoding format */
                                             
    p_media_info->media_info2.stream_enable[E_IPC_STREAM_VIDEO_SUB] = TRUE;     /* Whether to enable local SD video stream */
    p_media_info->media_info2.video_fps[E_IPC_STREAM_VIDEO_SUB] = 30;  /* FPS */
    p_media_info->media_info2.video_gop[E_IPC_STREAM_VIDEO_SUB] = 60;  /* GOP */
    p_media_info->media_info2.video_bitrate[E_IPC_STREAM_VIDEO_SUB] = TUYA_VIDEO_BITRATE_2M; /* Rate limit */
    p_media_info->media_info2.video_width[E_IPC_STREAM_VIDEO_SUB] = 426; /* Single frame resolution of width */
    p_media_info->media_info2.video_height[E_IPC_STREAM_VIDEO_SUB] = 240;/* Single frame resolution of height */
    p_media_info->media_info2.video_freq[E_IPC_STREAM_VIDEO_SUB] = 90000; /* Clock frequency */
    p_media_info->media_info2.video_codec[E_IPC_STREAM_VIDEO_SUB] = TUYA_CODEC_VIDEO_H265; /* Encoding format */
                                            
    p_media_info->media_info2.stream_enable[E_IPC_STREAM_AUDIO_MAIN] = TRUE;         /* Whether to enable local sound collection */
    p_media_info->media_info2.audio_codec[E_IPC_STREAM_AUDIO_MAIN] = TUYA_CODEC_AUDIO_PCM;/* Encoding format */
    p_media_info->media_info2.audio_sample [E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_SAMPLE_8K;/* Sampling Rate */
    p_media_info->media_info2.audio_databits [E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_DATABITS_16;/* Bit width */
    p_media_info->media_info2.audio_channel[E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_CHANNEL_MONO;/* channel */
    p_media_info->media_info2.audio_fps[E_IPC_STREAM_AUDIO_MAIN] = 25;/* Fragments per second */
#endif
    /************************************** second camera parameter end *****************************************************/
}