前段时间基于FFMpeg 写了一个软编软解的 模块 供业务层调用,即利用CPU来做 不需要依赖于特定硬件
最近 又来了一个需求需要基于寒武纪MLU270 来做视频编解码 ,摸索了三四天 发现一个奇怪的现象就是,正常解码没有问题, 但是编码的时候 如果不改变分辨率 可以正常编码 ,
但是如果改变了分辨率发现编出来的数据不对 不能正常播放,最终和寒武纪的人员确认
CNCodec 只能做编解码 不能做视频缩放 ,如果需要做视频缩放需要 自己处理 或者调用CNCV 来实现 ,
ffmpeg-mlu的描述说明里面有 :
如下 :
集成了cambricon 硬件平台的 ffmpeg版本下载ffmpeg-mlu下载
之前没怎么接触过寒武纪平台
发现了和ffmpeg不一样的地方
ffmpeg解码之后 得到yuv数据 直接送给下一步编码就可以了
但是寒武纪的解码之后 得到一个cnvideoDecOutput 的数据结构
得到的这个数据你并不能直接拿来用
根据官方提供的sample大概可以理解为,解码出来的这个数据是放在板卡里面的内存里面的
我们要用的话需要将他从板卡的内存考到电脑的的内存 即从device 拷到 host
这个device就是指寒武纪硬件卡 ,host即指我们的电脑
编码的时候 又需要将host的内存拷到板卡的内存
还有一个就是根据官方文档说明:
解码出来的数据 必须调用
cnvideoDecAddReference 添加引用之后才能操作他
使用完毕之后 需要调用
cnvideoDecReleaseReference 删除引用 ,当引用计数为0 之后 内部会释放掉这块内存。
所以就会得到如下的代码:
static void decode_cb(void* data, void* param)
{
cnvideoEncInput input;
cncodecWorkInfo work_info;
BOOL ret = 0;
if (!data || !param)
{
return;
}
QMCY_MLU270_CODEC *handle = (QMCY_MLU270_CODEC*)param;
QMCY_MLU270_DECODER* pHandle = &handle->m_decoder;
QMCY_MLU270_ENCODER* encoder = &handle->m_encoder;
memset(&work_info, 0, sizeof(work_info));
work_info.inMsg.instance = 0;
work_info.inMsg.cardId = 0;
work_info.inMsg.mode = 0;
cnvideoDecOutput *output_frame = (cnvideoDecOutput*)data;
ret = cnvideoDecAddReference(pHandle->decode_handle,&output_frame->frame);
if(ret < 0)
{
printf("cnvideoDecAddReference failed:ret is %d\n",ret);
return;
}
//dumpSurfaceData(g_fileyuv,&output_frame->frame);
//CopyFrame(&input.frame, frame);
memset(&input, 0, sizeof(cnvideoEncInput));
ret = cnvideoEncWaitAvailInputBuf(encoder->encode_handle, &input.frame, 3000);
if (ret < 0)
{
printf("Call cnvideoEncWaitAvailInputBuf failed, ret(%d)\n", ret);
return;
}
TranscodeDemoVirFrame src_frame(output_frame->frame.width, output_frame->frame.height,
output_frame->frame.pixelFmt, output_frame->frame.planeNum,
output_frame->frame.stride);
// device to host
CopyDevFrame2VirFrame(&src_frame, &output_frame->frame);
#if 0 //Does not support
ret = cncodecImageTransform(&dst_frame, nullptr, &dst_frame, nullptr, CNCODEC_Filter_BiLinear, &work_info);
if(ret != CNCODEC_SUCCESS)
{
printf("cncodecImageTransform failed :%d\n",ret);
}
#endif
// host to device
CopyVirFrame2DevFrame(&input.frame, &src_frame);
src_frame.ReleaseDemoVirFrame();
ret = cnvideoDecReleaseReference(pHandle->decode_handle, &output_frame->frame);
if (ret < 0)
{
printf("Call cnvideoDecReleaseReference failed, ret(%d)\n", ret);
return ;
}
input.pts = encoder->packet_index++ % CNCODEC_PTS_MAX_VALUE;
printf("Pts is %d \n",input.pts);
ret = cnvideoEncFeedFrame(encoder->encode_handle, &input, 5000);
if (ret < 0)
{
printf("Call CN_Encode_Feed_Frame failed, ret(%d)\n", ret);
}
}