Closed TRYOKETHEPEN closed 6 months ago
应该还是用 1 的方式来处理,mpi_dec_test 解码 jpeg 本身能正常么?
应该还是用 1 的方式来处理,mpi_dec_test 解码 jpeg 本身能正常么?
mpi_dec_test例程解码jpeg文件,保存为本地raw yuv文件,通过YUView查看是正常的。
用1的方式的话,slot->buf和slot->data没区别吗: https://github.com/rockchip-linux/mpp/blob/4cc3fb25f72fd862596743778575b1aae5b2e9aa/utils/mpi_dec_utils.h#L96
另外,我补充了一些syslog信息。
@alexanderdumas 你好,请问可以分享下你在https://github.com/rockchip-linux/mpp/issues/477#issuecomment-1827256689 中是怎么写的吗
找到了,参考以下: https://github.com/rockchip-linux/mpp/blob/4cc3fb25f72fd862596743778575b1aae5b2e9aa/mpp/legacy/vpu_api_legacy.cpp#L698 https://github.com/rockchip-linux/mpp/blob/4cc3fb25f72fd862596743778575b1aae5b2e9aa/mpp/legacy/vpu_api_legacy.cpp#L731 https://github.com/rockchip-linux/mpp/blob/4cc3fb25f72fd862596743778575b1aae5b2e9aa/mpp/legacy/vpu_api_legacy.cpp#L736 https://github.com/rockchip-linux/mpp/blob/4cc3fb25f72fd862596743778575b1aae5b2e9aa/mpp/legacy/vpu_api_legacy.cpp#L767
共享最终的advanced接口应用代码如下,分为对象初始化Init以及每帧Decode. 参考https://github.com/rockchip-linux/rknn-toolkit2/blob/master/rknpu2/examples/rknn_yolov5_demo/utils/mpp_decoder.cpp
int MppDecoder::Init(MppCodingType video_type, int fps, int width, int height, void *userdata, bool isAdvanced)
{
MPP_RET ret = MPP_OK;
this->last_frame_time_ms = 0;
this->mpp_type = video_type;
this->fps = fps;
this->width_mpp = width;
this->height_mpp = height;
this->userdata = userdata;
memset(&(this->loop_data), 0, sizeof(this->loop_data));
LOGD("mpi_dec_test decoder test start mpp_type=%d,fps=%d \n", this->mpp_type, this->fps);
// 创建mpp
ret = mpp_create(&mpp_ctx, &mpp_mpi);
if (MPP_OK != ret)
{
LOGD("mpp_create failed ");
return 0;
}
ret = mpp_init(mpp_ctx, MPP_CTX_DEC, this->mpp_type);
if (ret != MPP_OK)
{
LOGD("%p mpp_init failed ", mpp_ctx);
return -1;
}
// mpp 配置
MppDecCfg cfg = NULL;
mpp_dec_cfg_init(&cfg);
// 加载默认配置
ret = mpp_mpi->control(mpp_ctx, MPP_DEC_GET_CFG, cfg);
if (ret != MPP_OK)
{
LOGD("%p failed to get decoder cfg ret %d ", mpp_ctx, ret);
return -1;
}
// 设置内部分帧
ret = mpp_dec_cfg_set_u32(cfg, "base:split_parse", this->need_split);
if (ret != MPP_OK)
{
LOGD("%p failed to set split_parse ret %d ", mpp_ctx, ret);
return -1;
}
// 设置输出帧格式
MppFrameFormat dstFormat = MPP_FMT_YUV420SP;
ret = mpp_mpi->control(mpp_ctx, MPP_DEC_SET_OUTPUT_FORMAT, &(dstFormat));
if (ret != MPP_OK)
{
LOGD("Failed to set output format 0x%x\n", dstFormat);
return -1;
}
// 使配置生效
ret = mpp_mpi->control(mpp_ctx, MPP_DEC_SET_CFG, cfg);
if (ret != MPP_OK)
{
LOGD("%p failed to set cfg %p ret %d ", mpp_ctx, cfg, ret);
return -1;
}
// 释放配置内存
mpp_dec_cfg_deinit(cfg);
if (isAdvanced)
{
//! 设置输出frame的buffer
MppBuffer frm_buf = NULL;
ret = dec_buf_mgr_init(&(loop_data.buf_mgr));
if (ret != MPP_OK)
{
LOGD("dec_buf_mgr_init failed\n");
}
ret = mpp_frame_init(&frame); /* output frame */
if (ret != MPP_OK)
{
LOGD("mpp_frame_init failed\n");
}
loop_data.frm_grp = dec_buf_mgr_setup(loop_data.buf_mgr, MPP_ALIGN(width_mpp, 16) * MPP_ALIGN(height_mpp, 16) * 4, 4, MPP_DEC_BUF_HALF_INT);
if (!(loop_data.frm_grp))
{
LOGD("failed to get buffer group for input frame ret %d\n", ret);
ret = MPP_NOK;
}
ret = mpp_buffer_get(loop_data.frm_grp, &frm_buf, MPP_ALIGN(width_mpp, 16) * MPP_ALIGN(height_mpp, 16) * 4);
if (ret != MPP_OK)
{
LOGD("failed to get buffer for input frame ret %d\n", ret);
}
mpp_frame_set_buffer(frame, frm_buf);
}
loop_data.ctx = mpp_ctx;
loop_data.mpi = mpp_mpi;
loop_data.eos = 0;
loop_data.packet_size = this->packet_size;
loop_data.frame = 0;
loop_data.frame_count = 0;
return 1;
}
int MppDecoder::Decode_advanced(uint8_t *pkt_data, int pkt_size, int pkt_eos) //! 对应mpi_dec_test.c中的advanced接口
{
MPP_RET ret = MPP_OK;
MpiDecLoopData *data = &loop_data;
MppCtx ctx = data->ctx;
MppApi *mpi = data->mpi;
//! 设置输入packet
MppBuffer input_buf = NULL;
ret = mpp_buffer_get(data->pkt_grp, &input_buf, pkt_size);
if (ret != MPP_OK)
{
LOGD("allocate input picture buffer failed\n");
}
memcpy((RK_U8 *)mpp_buffer_get_ptr(input_buf), pkt_data, pkt_size);
ret = mpp_packet_init_with_buffer(&packet, input_buf);
//! 使用mpptask进行解码
MppTask task = NULL;
ret = mpi->poll(ctx, MPP_PORT_INPUT, MPP_POLL_BLOCK); // 查询INPUT端口 是否有数据可供出列 //阻塞
if (ret != MPP_OK)
{
LOGD("%p mpp input poll failed\n", ctx);
return ret;
}
ret = mpi->dequeue(ctx, MPP_PORT_INPUT, &task); // INPUT端口 task出列
if (ret != MPP_OK)
{
LOGD("%p mpp task input dequeue failed\n", ctx);
return ret;
}
// mpp_assert(task);
ret = mpp_task_meta_set_packet(task, KEY_INPUT_PACKET, packet); // 将packet赋给task
ret = mpp_task_meta_set_frame(task, KEY_OUTPUT_FRAME, frame); // 将frame赋给task
ret = mpi->enqueue(ctx, MPP_PORT_INPUT, task); // INPUT端口 task入列
if (ret != MPP_OK)
{
LOGD("%p mpp task input enqueue failed\n", ctx);
return ret;
}
ret = mpi->poll(ctx, MPP_PORT_OUTPUT, MPP_POLL_BLOCK); // 查询OUTPUT端口 是否有数据可供出列 //阻塞
if (ret != MPP_OK)
{
LOGD("%p mpp output poll failed\n", ctx);
return ret;
}
ret = mpi->dequeue(ctx, MPP_PORT_OUTPUT, &task); // OUTPUT端口 task出列
if (ret != MPP_OK)
{
LOGD("%p mpp task output dequeue failed\n", ctx);
return ret;
}
// mpp_assert(task);
if (task) // 如果出列的task不为空
{
if (frame)
{
if (callback != nullptr) // 如果用户设置了解码完成的回调
{
RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); // 获取frame信息
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
RK_U32 hor_width = mpp_frame_get_width(frame);
RK_U32 ver_height = mpp_frame_get_height(frame);
MppFrameFormat format = mpp_frame_get_fmt(frame); // 获取解码输出帧格式
char *data_vir = (char *)mpp_buffer_get_ptr(mpp_frame_get_buffer(frame)); // 获取解码输出帧地址
int fd = mpp_buffer_get_fd(mpp_frame_get_buffer(frame));
callback(this->userdata, hor_stride, ver_stride, hor_width, ver_height, format, fd, data_vir); //! 调用callback
}
}
ret = mpi->enqueue(ctx, MPP_PORT_OUTPUT, task); /* output queue */
if (ret != MPP_OK)
{
LOGD("%p mpp task output enqueue failed\n", ctx);
}
}
if (packet)
{
mpp_packet_deinit(&packet); // 释放packet占用内存
}
if (input_buf)
{
mpp_buffer_put(input_buf); // 释放buf1占用内存
input_buf = NULL;
}
return ret;
}
共享最终的advanced接口应用代码如下,分为对象初始化Init以及每帧Decode. 参考https://github.com/rockchip-linux/rknn-toolkit2/blob/master/rknpu2/examples/rknn_yolov5_demo/utils/mpp_decoder.cpp
int MppDecoder::Init(MppCodingType video_type, int fps, int width, int height, void *userdata, bool isAdvanced) { MPP_RET ret = MPP_OK; this->last_frame_time_ms = 0; this->mpp_type = video_type; this->fps = fps; this->width_mpp = width; this->height_mpp = height; this->userdata = userdata; memset(&(this->loop_data), 0, sizeof(this->loop_data)); LOGD("mpi_dec_test decoder test start mpp_type=%d,fps=%d \n", this->mpp_type, this->fps); // 创建mpp ret = mpp_create(&mpp_ctx, &mpp_mpi); if (MPP_OK != ret) { LOGD("mpp_create failed "); return 0; } ret = mpp_init(mpp_ctx, MPP_CTX_DEC, this->mpp_type); if (ret != MPP_OK) { LOGD("%p mpp_init failed ", mpp_ctx); return -1; } // mpp 配置 MppDecCfg cfg = NULL; mpp_dec_cfg_init(&cfg); // 加载默认配置 ret = mpp_mpi->control(mpp_ctx, MPP_DEC_GET_CFG, cfg); if (ret != MPP_OK) { LOGD("%p failed to get decoder cfg ret %d ", mpp_ctx, ret); return -1; } // 设置内部分帧 ret = mpp_dec_cfg_set_u32(cfg, "base:split_parse", this->need_split); if (ret != MPP_OK) { LOGD("%p failed to set split_parse ret %d ", mpp_ctx, ret); return -1; } // 设置输出帧格式 MppFrameFormat dstFormat = MPP_FMT_YUV420SP; ret = mpp_mpi->control(mpp_ctx, MPP_DEC_SET_OUTPUT_FORMAT, &(dstFormat)); if (ret != MPP_OK) { LOGD("Failed to set output format 0x%x\n", dstFormat); return -1; } // 使配置生效 ret = mpp_mpi->control(mpp_ctx, MPP_DEC_SET_CFG, cfg); if (ret != MPP_OK) { LOGD("%p failed to set cfg %p ret %d ", mpp_ctx, cfg, ret); return -1; } // 释放配置内存 mpp_dec_cfg_deinit(cfg); if (isAdvanced) { //! 设置输出frame的buffer MppBuffer frm_buf = NULL; ret = dec_buf_mgr_init(&(loop_data.buf_mgr)); if (ret != MPP_OK) { LOGD("dec_buf_mgr_init failed\n"); } ret = mpp_frame_init(&frame); /* output frame */ if (ret != MPP_OK) { LOGD("mpp_frame_init failed\n"); } loop_data.frm_grp = dec_buf_mgr_setup(loop_data.buf_mgr, MPP_ALIGN(width_mpp, 16) * MPP_ALIGN(height_mpp, 16) * 4, 4, MPP_DEC_BUF_HALF_INT); if (!(loop_data.frm_grp)) { LOGD("failed to get buffer group for input frame ret %d\n", ret); ret = MPP_NOK; } ret = mpp_buffer_get(loop_data.frm_grp, &frm_buf, MPP_ALIGN(width_mpp, 16) * MPP_ALIGN(height_mpp, 16) * 4); if (ret != MPP_OK) { LOGD("failed to get buffer for input frame ret %d\n", ret); } mpp_frame_set_buffer(frame, frm_buf); } loop_data.ctx = mpp_ctx; loop_data.mpi = mpp_mpi; loop_data.eos = 0; loop_data.packet_size = this->packet_size; loop_data.frame = 0; loop_data.frame_count = 0; return 1; } int MppDecoder::Decode_advanced(uint8_t *pkt_data, int pkt_size, int pkt_eos) //! 对应mpi_dec_test.c中的advanced接口 { MPP_RET ret = MPP_OK; MpiDecLoopData *data = &loop_data; MppCtx ctx = data->ctx; MppApi *mpi = data->mpi; //! 设置输入packet MppBuffer input_buf = NULL; ret = mpp_buffer_get(data->pkt_grp, &input_buf, pkt_size); if (ret != MPP_OK) { LOGD("allocate input picture buffer failed\n"); } memcpy((RK_U8 *)mpp_buffer_get_ptr(input_buf), pkt_data, pkt_size); ret = mpp_packet_init_with_buffer(&packet, input_buf); //! 使用mpptask进行解码 MppTask task = NULL; ret = mpi->poll(ctx, MPP_PORT_INPUT, MPP_POLL_BLOCK); // 查询INPUT端口 是否有数据可供出列 //阻塞 if (ret != MPP_OK) { LOGD("%p mpp input poll failed\n", ctx); return ret; } ret = mpi->dequeue(ctx, MPP_PORT_INPUT, &task); // INPUT端口 task出列 if (ret != MPP_OK) { LOGD("%p mpp task input dequeue failed\n", ctx); return ret; } // mpp_assert(task); ret = mpp_task_meta_set_packet(task, KEY_INPUT_PACKET, packet); // 将packet赋给task ret = mpp_task_meta_set_frame(task, KEY_OUTPUT_FRAME, frame); // 将frame赋给task ret = mpi->enqueue(ctx, MPP_PORT_INPUT, task); // INPUT端口 task入列 if (ret != MPP_OK) { LOGD("%p mpp task input enqueue failed\n", ctx); return ret; } ret = mpi->poll(ctx, MPP_PORT_OUTPUT, MPP_POLL_BLOCK); // 查询OUTPUT端口 是否有数据可供出列 //阻塞 if (ret != MPP_OK) { LOGD("%p mpp output poll failed\n", ctx); return ret; } ret = mpi->dequeue(ctx, MPP_PORT_OUTPUT, &task); // OUTPUT端口 task出列 if (ret != MPP_OK) { LOGD("%p mpp task output dequeue failed\n", ctx); return ret; } // mpp_assert(task); if (task) // 如果出列的task不为空 { if (frame) { if (callback != nullptr) // 如果用户设置了解码完成的回调 { RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); // 获取frame信息 RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); RK_U32 hor_width = mpp_frame_get_width(frame); RK_U32 ver_height = mpp_frame_get_height(frame); MppFrameFormat format = mpp_frame_get_fmt(frame); // 获取解码输出帧格式 char *data_vir = (char *)mpp_buffer_get_ptr(mpp_frame_get_buffer(frame)); // 获取解码输出帧地址 int fd = mpp_buffer_get_fd(mpp_frame_get_buffer(frame)); callback(this->userdata, hor_stride, ver_stride, hor_width, ver_height, format, fd, data_vir); //! 调用callback } } ret = mpi->enqueue(ctx, MPP_PORT_OUTPUT, task); /* output queue */ if (ret != MPP_OK) { LOGD("%p mpp task output enqueue failed\n", ctx); } } if (packet) { mpp_packet_deinit(&packet); // 释放packet占用内存 } if (input_buf) { mpp_buffer_put(input_buf); // 释放buf1占用内存 input_buf = NULL; } return ret; }
你好,请问这个接口能拿来用到摄像头采集到的MJPEG数据解码吗?
问题: 使用mpp解码UVC视频流,格式为MJPEG,只能使用advanced接口(见https://github.com/rockchip-linux/mpp/issues/586 )。 例程mpp/test/mpi_dec_test.c中只有读取二进制文件的示例: https://github.com/rockchip-linux/mpp/blob/develop/test/mpi_dec_test.c#L278
请问读取视频流帧数据应该怎样设置packet? 我能拿到的是帧数据的pkt_data、pkt_size,类似 https://github.com/rockchip-linux/rknn-toolkit2/blob/master/rknpu2/examples/rknn_yolov5_demo/utils/mpp_decoder.cpp#L119
分析及尝试: (1)直接
mpp_packet_init_with_buffer(&packet, (MppBuffer)pkt_data)
,将pkt_data强制转换为MppBuffer来设置packet。 会在https://github.com/rockchip-linux/mpp/blob/develop/mpp/base/mpp_buffer_impl.cpp#L170 处出现段错误。 并且syslog报错mpp_buffer: group 1296911693 buffer 1296911693 fd 16843013 ops buf ref inc ref_count 263174 caller mpp_packet_init_with_buffer
根据https://github.com/rockchip-linux/mpp/blob/develop/test/mpi_dec_test.c#L94 以及https://github.com/rockchip-linux/rknn-toolkit2/blob/master/rknpu2/examples/rknn_yolov5_demo/utils/mpp_decoder.cpp#L139 可知
pkt_data
对应的是slot->data
,而不是slot->buf
所以不能直接mpp_packet_init_with_buffer(&packet, (MppBuffer)pkt_data)
来设置packet。(2)尝试按照simple接口的packet设置写法:
代码运行到
mpi->poll(ctx, MPP_PORT_OUTPUT, MPP_POLL_BLOCK)
时,syslog出现报错:相关代码: 参考https://github.com/rockchip-linux/rknn-toolkit2/blob/master/rknpu2/examples/rknn_yolov5_demo/utils/mpp_decoder.cpp 的写法,UVC视频流获取pkt_data的部分见https://github.com/rockchip-linux/mpp/issues/586