RK3399 中的ffmpeg对于rkmpp硬件解码的转换
{
AVCodecContext *codecCtx;
size_t unused;
RKMPPDecodeContext *rk_context = codecCtx->priv_data;
RKMPPDecoder *decoder = (RKMPPDecoder *) rk_context->decoder_ref->data;
ret = mpp_buffer_group_limit_config(decoder->frame_group, 0, 30); //重新group为30长度
unused = mpp_buffer_group_unused(decoder->frame_group); //获取未使用个数
log("CH:%d, unused:%d\n", mediaService->chNo, unused);
}
...
while(1) ..... 循环读取视频流并解码
//解码成AVFrame
ret=avcodec_send_packet(codecCtx,pkt);
if(ret!=0){
avcodec_flush_buffers(codecCtx); //刷新后可以重新解码
continue;
}
avcodec_receive_frame(codecCtx, avframe);
{ //移动avframe到其他第放使用 format 为 AV_PIX_FMT_DRM_PRIME,即rkmpp的DRM数据
AVFrame *dst_avframe = av_frame_alloc();
av_frame_move_ref(dst_avframe, avframe);
av_frame_unref(avframe); //必须加
//将AVFrmae转换为rkmpp的数据格式
AVBufferRef* framecontextref = (AVBufferRef*) av_buffer_get_opaque(
avframe->buf[0]);
RKMPPFrameContext *framecontext =
(RKMPPFrameContext *) framecontextref->data;
MppFrame mppframe=framecontext->frame;
MppBuffer mppbuffer = mpp_frame_get_buffer(mppframe);
MppFrameFormat format = mpp_frame_get_fmt(mppframe); //应该为MPP_FMT_YUV420SP(NV12)
int width = mpp_frame_get_width(mppframe);
int height = mpp_frame_get_height(mppframe);
int hor_stride = mpp_frame_get_hor_stride(mppframe);
int ver_stride = mpp_frame_get_ver_stride(mppframe);
uint8_t *yuvDataPtr=mpp_buffer_get_ptr(buffer); //YUV数据(NV12)
//这样可以处理MPP的硬件数据,缩放,截图可以使用RGA
}
...
avcodec_flush_buffers(codecCtx);
{
RKMPPDecodeContext *rk_context = ffContext->pCodecCtx->priv_data;
RKMPPDecoder *decoder = (RKMPPDecoder *) rk_context->decoder_ref->data;
//等待未使用个数为原始的30个
while (30 != (unused = mpp_buffer_group_unused(decoder->frame_group)))
{
logInfo("Media", "CH:%d, mpp_buffer_group_unused:%d\n", mediaService->chNo, unused);
sleep(1);
}
}
RK3399 rga转换
/格式转化
MppFrame srcframe = AVFrame2MppFrame(avframe);
int hor_stride = mpp_frame_get_hor_stride(srcframe);
int ver_stride = mpp_frame_get_ver_stride(srcframe);
int src_width = mpp_frame_get_width(srcframe);
int src_height = mpp_frame_get_height(srcframe);
MppBuffer buffer = mpp_frame_get_buffer(srcframe);
uint8_t *src_yuv_ptr = (uint8_t*) mpp_buffer_get_ptr(buffer);
rga_info_t src_info; //原图像
memset(&src_info, 0, sizeof(rga_info_t));
src_info.fd = mpp_buffer_get_fd(buffer);
src_info.mmuFlag = 1;
rga_set_rect(&src_info.rect, 0, 0, src_width, src_height,hor_stride, ver_stride, RK_FORMAT_YCbCr_420_SP); //NV12
//目标图像存储空间分配
int dst_width = src_width;
int dst_height = src_height;
int dst_hor = MPP_ALIGN(dst_width, 1); //默认16字节对其,才能编码成JPG,这里使用1字节对齐
int dst_ver = MPP_ALIGN(dst_height, 1); //默认16字节对其
int framesize = dst_ver * dst_hor * 3 / 2;
MppBuffer dst_buffer;
mpp_buffer_get(NULL, &dst_buffer, framesize); //申请内存
rga_info_t dst_info; //目标图像
memset(&dst_info, 0, sizeof(rga_info_t));
dst_info.fd = mpp_buffer_get_fd(dst_buffer);
dst_info.mmuFlag = 1;
rga_set_rect(&dst_info.rect, 0, 0, dst_width, dst_height,dst_hor, dst_ver, RK_FORMAT_YCrCb_420_P);
ret = c_RkRgaBlit(&src_info, &dst_info, NULL);
void *yuv_ptr = mpp_buffer_get_ptr(dst_buffer);
//对yuv_ptr做运算,人脸,车辆,车牌等 因为RK3399没有NPU,故而在CPU中处理GPU数据
mpp_buffer_put(dst_buffer); //释放内存
后记
使用MppBufferGroup时的limit数量太多时,最好调用mpp_buffer_group_clear做清理,否则会导致内存增长不退