Page 1 of 1

【技术干货】双镜头对接demo

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

1. 功能接入

1.1 摄像头参数设置

在TUYA_IPC_SDK_START中,需要设置第二路摄像头的流媒体参数:

Code: Select all

/************************************** second camera parameter  begin*****************************************************/
#if defined(IPC_CHANNEL_NUM) && (IPC_CHANNEL_NUM==2)
    ipc_sdk_run_var.media_info.media_info2.stream_enable[E_IPC_STREAM_VIDEO_MAIN] = TRUE;    /* Whether to enable local HD video streaming */
    ipc_sdk_run_var.media_info.media_info2.video_fps[E_IPC_STREAM_VIDEO_MAIN] = 30;  /* FPS */
    ipc_sdk_run_var.media_info.media_info2.video_gop[E_IPC_STREAM_VIDEO_MAIN] = 60;  /* GOP */
    ipc_sdk_run_var.media_info.media_info2.video_bitrate[E_IPC_STREAM_VIDEO_MAIN] = TUYA_VIDEO_BITRATE_1M; /* Rate limit */
    ipc_sdk_run_var.media_info.media_info2.video_width[E_IPC_STREAM_VIDEO_MAIN] = 426; /* Single frame resolution of width*/
    ipc_sdk_run_var.media_info.media_info2.video_height[E_IPC_STREAM_VIDEO_MAIN] = 240;/* Single frame resolution of height */
    ipc_sdk_run_var.media_info.media_info2.video_freq[E_IPC_STREAM_VIDEO_MAIN] = 90000; /* Clock frequency */
    ipc_sdk_run_var.media_info.media_info2.video_codec[E_IPC_STREAM_VIDEO_MAIN] = TUYA_CODEC_VIDEO_H264; /* Encoding format */
										 
    ipc_sdk_run_var.media_info.media_info2.stream_enable[E_IPC_STREAM_VIDEO_SUB] = TRUE;     /* Whether to enable local SD video stream */
    ipc_sdk_run_var.media_info.media_info2.video_fps[E_IPC_STREAM_VIDEO_SUB] = 30;  /* FPS */
    ipc_sdk_run_var.media_info.media_info2.video_gop[E_IPC_STREAM_VIDEO_SUB] = 60;  /* GOP */
    ipc_sdk_run_var.media_info.media_info2.video_bitrate[E_IPC_STREAM_VIDEO_SUB] = TUYA_VIDEO_BITRATE_512K; /* Rate limit */
    ipc_sdk_run_var.media_info.media_info2.video_width[E_IPC_STREAM_VIDEO_SUB] = 426; /* Single frame resolution of width */
    ipc_sdk_run_var.media_info.media_info2.video_height[E_IPC_STREAM_VIDEO_SUB] = 240;/* Single frame resolution of height */
    ipc_sdk_run_var.media_info.media_info2.video_freq[E_IPC_STREAM_VIDEO_SUB] = 90000; /* Clock frequency */
    ipc_sdk_run_var.media_info.media_info2.video_codec[E_IPC_STREAM_VIDEO_SUB] = TUYA_CODEC_VIDEO_H264; /* Encoding format */
										
    ipc_sdk_run_var.media_info.media_info2.stream_enable[E_IPC_STREAM_AUDIO_MAIN] = TRUE;         /* Whether to enable local sound collection */
    ipc_sdk_run_var.media_info.media_info2.audio_codec[E_IPC_STREAM_AUDIO_MAIN] = TUYA_CODEC_AUDIO_PCM;/* Encoding format */
    ipc_sdk_run_var.media_info.media_info2.audio_sample [E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_SAMPLE_8K;/* Sampling Rate */
    ipc_sdk_run_var.media_info.media_info2.audio_databits [E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_DATABITS_16;/* Bit width */
    ipc_sdk_run_var.media_info.media_info2.audio_channel[E_IPC_STREAM_AUDIO_MAIN]= TUYA_AUDIO_CHANNEL_MONO;/* channel */
    ipc_sdk_run_var.media_info.media_info2.audio_fps[E_IPC_STREAM_AUDIO_MAIN] = 25;/* Fragments per second */
#endif
/************************************** second camera parameter end *****************************************************/

1.2 媒体参数初始化

在IPC_APP_Media_Adapter_Init中,将第二路镜头的多媒体参数设置给sdk

Code: Select all

#if defined(IPC_CHANNEL_NUM) && (IPC_CHANNEL_NUM==2)
    memcpy(&device_media_info.av_encode_info, &p_media_infos->media_info2,sizeof(IPC_MEDIA_INFO_T));
    tuya_ipc_media_adapter_set_media_info(0, 1, device_media_info);
#endif

1.3 Ring Buffer初始化

在tuya_ipc_app_start中,增加第二路摄像头的Ring Buffer初始化

Code: Select all

#if defined(IPC_CHANNEL_NUM) && (IPC_CHANNEL_NUM==2)
    ret = TUYA_APP_Init_Ring_Buffer(&pRunInfo->media_info.media_info2, 1);
	if(OPRT_OK != ret)
	{
		PR_ERR("create ring buffer is error\n");
		return ret;
	}
#endif

1.4 创建取流线程

在IPC_APP_Init_Media_Task函数中,创建第二路摄像头取流线程

Code: Select all

#if defined(IPC_CHANNEL_NUM) && (IPC_CHANNEL_NUM==2)
    pthread_t h264_output_thread2;
    pthread_create(&h264_output_thread2, NULL, thread_live_video2, NULL);
    pthread_detach(h264_output_thread2);
#endif

thread_live_video2线程如下:

Code: Select all

#if defined(IPC_CHANNEL_NUM) && (IPC_CHANNEL_NUM==2)
void *thread_live_video2(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 = 1;
    sprintf(raw_fullpath, "%s/resource/media2/demo_video.264", s_raw_path);

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

    g_v_handle[channel] = tuya_ipc_ring_buffer_open(0, channel, E_IPC_STREAM_VIDEO_MAIN, E_RBUF_WRITE);
    g_v_handle_sub[channel] = tuya_ipc_ring_buffer_open(0, channel, E_IPC_STREAM_VIDEO_SUB, E_RBUF_WRITE);
    if(g_v_handle[channel] == NULL || g_v_handle_sub[channel] == NULL)
    {
        pthread_exit(0);
    }

    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);
    
    MEDIA_FRAME_T video_frame = {0};    
    while(1)
    {
        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);
    }
    
    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);
}
#endif

1.5 媒体参数更新

调用IPC_APP_Media_Adapter_Set更新媒体参数时,需要同时更新第二路摄像头的参数

Code: Select all

#if defined(IPC_CHANNEL_NUM) && (IPC_CHANNEL_NUM==2)
    memcpy(&device_media_info.av_encode_info, &p_media_infos->media_info2, sizeof(IPC_MEDIA_INFO_T));
    tuya_ipc_media_adapter_set_media_info(0, 1, device_media_info);
#endif