send_vdec_thread线程的用处
send_vdec_thread线程是三个线程里面的第二个线程,因为上篇已经说过了,ffmpeg_read_thread把数据已经放到了队列里了,所以send_vdec_thread线程的主要作用是通过video_queue(视频压缩队列)获取每一帧视频数据,并通过RV1126创建缓冲区的API去创建视频缓冲区,并把数据传输到RV1126硬件解码器。
编码:
void *send_vdec_thread(void *args)
{
pthread_detach(pthread_self());
MEDIA_BUFFER mb = NULL;
int ret;
//初始化图像信息结构体。
MB_IMAGE_INFO_S stImageInfo = {1920, 1080, 1920, 1080, IMAGE_TYPE_NV12};
while (1)
{
video_data_packet_t *video_data_packet = video_queue->getVideoPacketQueue(); // 获取video_queue结构体的数据
MEDIA_BUFFER mb = RK_MPI_MB_CreateImageBuffer(&stImageInfo, RK_TRUE, MB_FLAG_NOCACHED); // 调用RK_MPI_MB_CreateImageBuffer创建视频缓冲区
memcpy(RK_MPI_MB_GetPtr(mb), video_data_packet->buffer, video_data_packet->video_frame_size); // video_data_packet的视频缓冲数据,拷贝到RK_MPI_MB_GetPtr(mb)
RK_MPI_MB_SetSize(mb, video_data_packet->video_frame_size); // 设置缓冲区大小
ret = RK_MPI_SYS_SendMediaBuffer(RK_ID_VDEC, 0, mb); // 调用RK_MPI_SYS_SendMediaBuffer把数据传输到VDEC解码器
RK_MPI_MB_ReleaseBuffer(mb); // free mb
}
return NULL;
}
send_vdec_thread主要的流程图
send_vdec_thread线程主要功能是获取每一帧视频队列的数据,并把每一帧视频压缩数据发送到VDEC解码器。这里需要用到第一个重要的API是RK_MPI_MB_CreateImageBuffer,这个API是创建图像缓冲区,创建完成之后把。视频数据传到视频缓冲区里面把数据赋值完成之后,则调用RK_MPI_SYS_SendMediaBuffer把其数据发送到对应的VDEC解码器进行解码。
创建媒体缓冲区的主要目的是为了在视频解码过程中提供一个临时存储区域,用于存放从输入文件读取的视频帧数据。
为什么要使用RK_MPI_MB_CreateImageBuffer
创建缓冲区,通过 RK_MPI_MB_CreateImageBuffer
创建的媒体缓冲区可以由系统进行统一管理和分配,避免了手动管理内存带来的复杂性和潜在的风险。同时,使用 RK_MPI_MB_ReleaseBuffer
释放缓冲区,确保资源得到及时回收,防止内存泄漏。
下面认识一下RK_MPI_MB_CreateImageBuffer
MEDIA_BUFFER RK_MPI_MB_CreateImageBuffer(MB_IMAGE_INFO_S *pstImageInfo, RK_BOOL boolHardWare, RK_U8 u8Flag);
第一个传入参数:MB_IMAGE_INFO_S结构体指针
第二个传入参数:是否创建硬件类型Buffer
第三个传入参数:硬件类型Buffer附加标记,取值: 0:开辟带缓存类型的硬件Buffer
MB_FLAG_NOCACHED:开辟不带缓存类型的硬件Buffer
MB_IMAGE_INFO_S结构体成员如下:
//视频图像信息
typedef struct rkMB_IMAGE_INFO {
RK_U32 u32Width; //图像的宽度,以像素为单位。
RK_U32 u32Height; //图像的高度,以像素为单位。
RK_U32 u32HorStride;//水平对齐(虚宽),以像素为单位。
RK_U32 u32VerStride; //垂直对齐(虚高),以像素为单位。
IMAGE_TYPE_E enImgType; //图像类型
} MB_IMAGE_INFO_S;
MB_IMAGE_INFO_S image = {1920, 1080, 1920, 1080, IMAGE_TYPE_NV12};
MEDIA_BUFFER mb = RK_MPI_MB_CreateImageBuffer(&stImageInfo, RK_TRUE, MB_FLAG_NOCACHED);
下面通过画图,来解析一下为什么也要创建这个缓冲区
第一步,创建出来这个缓冲区mb,里面规定了图像的宽高和格式,其他的什么都没有,只是创建出来而已。接下来就要往里面填数据
第二步:把从队列里面获取出来的packet数据,拷贝到mb里面去
memcpy(RK_MPI_MB_GetPtr(mb), video_data_packet->buffer, video_data_packet->video_frame_size);
RK_MPI_MB_SetSize(mb, video_data_packet->video_frame_size);
第三步,mb里面的数据填充完了后,就调用RK_MPI_SYS_SendMediaBuffer把数据发送到解码器去。先认识一下RK_MPI_SYS_SendMediaBuffer
虽然文档上面写着是编码器,主要是那个模块号,如果是编码模块就是发生到编码模块,如果是解码模块就是发生到解码模块。
//RK_ID_VDEC解码模块
//0:是创建vedc的时候创建的0号通道
//mb:就是要发送到解码器的数据
ret = RK_MPI_SYS_SendMediaBuffer(RK_ID_VDEC, 0, mb);
这样解码器就可以解码了。
为什么要这样做呢?主要是我的rv1126,只认这个MEDIA_BUFFER mb数据结构,不认packet数据结构,所以要做装换。转换成解码器认识的数据结构才能干活。