【技术干货】流媒体参数动态更新对接demo
Posted: 2023年 Apr 21日 10:35
1. 功能接入
1.1 代码导入
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 *****************************************************/
}