执笔蘸墨

执笔蘸墨

3个粉丝

5

问答

0

专栏

0

资料

执笔蘸墨  发布于  2024-06-24 16:20:29
采纳率 20%
5个问答
279

RV1126 ffmpeg rkmedia vdec 播放器,播放本地mp4问题

悬赏金¥ 10
已结题
     

流程如下:
1.解码器初始化

    VDEC_CHN_ATTR_S stVdecAttr;
    stVdecAttr.enCodecType = RK_CODEC_TYPE_H264;
    stVdecAttr.enMode = VIDEO_MODE_FRAME;
    stVdecAttr.enDecodecMode = VIDEO_DECODEC_HADRWARE;
    ret = RK_MPI_VDEC_CreateChn(0, &stVdecAttr);

2.ffmpeg读取AVPacket


AVPacket XFFmpeg::Read()
{
    AVPacket pkt;
    memset(&pkt, 0, sizeof(AVPacket));
    mutex.lock();
    if (!ic)
    {
        mutex.unlock();
        return pkt;
    }
    int err = av_read_frame(ic, &pkt);
    if (err != 0)
    {
        av_strerror(err, errorbuf, sizeof(errorbuf));
    }
    mutex.unlock();
    return pkt;
}

3.周期性将AVPacket的数据发送给解码器

    connect(&m_tmrVideoUpdate, &QTimer::timeout, this, [this]()
    {
        if(XFFmpeg::Get()->isPlay)
        {
            AVPacket pkt = XFFmpeg::Get()->Read();

            if (pkt.size > 0)
            {
                if (pkt.stream_index == XFFmpeg::Get()->audioStream)
                {
                    qDebug() << "定时器刷新音频";
//                    CRkProcessWidget::Get()->cAudioDecode(reinterpret_cast<char*>(pkt.data), pkt.size);
                    int tmp_apts = XFFmpeg::Get()->GetPts(&pkt);  // 更新音频的 pts

                    if(tmp_apts % 1000 == 0)
                    {
                        emit CRkProcessWidget::Get()->signalPtsUpdate(tmp_apts);
                    }
                }


                if (pkt.stream_index == XFFmpeg::Get()->videoStream)
                {
                    qDebug() << "定时器刷新视频";
                    qDebug() << "视频数据:"<<pkt.size;
                    CRkProcessWidget::Get()->cVideoDecode(reinterpret_cast<char*>(pkt.buf->buffer), pkt.buf->size);

//                    CMppH264Decoder::Get()->cDecode(&pkt);
                }
            }
            av_packet_unref(&pkt);
        }

        m_tmrVideoUpdate.start(30);
    });

int CRkProcessWidget::cVideoDecode(char* data, int size)
{

//    saveDataToFile(data, size, "/userdata/packet.bin");

    m_mutex.lock();
    qDebug()<<"进入Rk视频解码"<<endl;
    // 创建媒体缓冲区
    MEDIA_BUFFER mb = RK_MPI_MB_CreateBuffer((RK_U32)size, RK_FALSE, 0);

    // 检查缓冲区创建是否成功
    if (mb == nullptr)
    {
        qDebug() << "Error: Failed to create media buffer";
        return -1;
    }

    // 将数据复制到媒体缓冲区
    memcpy(RK_MPI_MB_GetPtr(mb), data, (size_t)size);

    qDebug() << " buffer size"<<RK_MPI_MB_GetSize(mb);

    RK_MPI_MB_SetSize(mb, (size_t)size);
//    printf("#Send packet(%p, %zuBytes) to VDEC[0].\n", RK_MPI_MB_GetPtr(mb),
//           RK_MPI_MB_GetSize(mb));


//    saveDataToFile(reinterpret_cast<char*>(RK_MPI_MB_GetPtr(mb)), static_cast<size_t>(RK_MPI_MB_GetSize(mb)), "/userdata/mb.bin");

    // 发送媒体缓冲区到解码通道
    int ret = RK_MPI_SYS_SendMediaBuffer(RK_ID_VDEC, 0, mb);
    qDebug()<<"发送视频解码"<<endl;
    if (ret != 0)
    {
        qDebug() << "Error: Failed to send media buffer, ret=" << ret;
        RK_MPI_MB_ReleaseBuffer(mb);
        return -1;
    }
    RK_MPI_MB_ReleaseBuffer(mb);

    m_mutex.unlock();

    CRkProcessWidget::Get()->cGetImage();

    return 0;



}

int CRkProcessWidget::cVideoDecode(char* data, int size)
{

//    saveDataToFile(data, size, "/userdata/packet.bin");

    m_mutex.lock();
    qDebug()<<"进入Rk视频解码"<<endl;
    // 创建媒体缓冲区
    MEDIA_BUFFER mb = RK_MPI_MB_CreateBuffer((RK_U32)size, RK_FALSE, 0);

    // 检查缓冲区创建是否成功
    if (mb == nullptr)
    {
        qDebug() << "Error: Failed to create media buffer";
        return -1;
    }

    // 将数据复制到媒体缓冲区
    memcpy(RK_MPI_MB_GetPtr(mb), data, (size_t)size);

    qDebug() << " buffer size"<<RK_MPI_MB_GetSize(mb);

    RK_MPI_MB_SetSize(mb, (size_t)size);
//    printf("#Send packet(%p, %zuBytes) to VDEC[0].\n", RK_MPI_MB_GetPtr(mb),
//           RK_MPI_MB_GetSize(mb));


//    saveDataToFile(reinterpret_cast<char*>(RK_MPI_MB_GetPtr(mb)), static_cast<size_t>(RK_MPI_MB_GetSize(mb)), "/userdata/mb.bin");

    // 发送媒体缓冲区到解码通道
    int ret = RK_MPI_SYS_SendMediaBuffer(RK_ID_VDEC, 0, mb);
    qDebug()<<"发送视频解码"<<endl;
    if (ret != 0)
    {
        qDebug() << "Error: Failed to send media buffer, ret=" << ret;
        RK_MPI_MB_ReleaseBuffer(mb);
        return -1;
    }
    RK_MPI_MB_ReleaseBuffer(mb);

    m_mutex.unlock();

    CRkProcessWidget::Get()->cGetImage();

    return 0;



}

4.获取解码后的数据并转换为qimage

int CRkProcessWidget::cGetImage()
{
    MEDIA_BUFFER mb = nullptr;
    int ret = 0;


    mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VDEC, 0, 1000);
    if (!mb)
    {

        qDebug()<<"RK_MPI_SYS_GetMediaBuffer get null buffer in 5s.."<<endl;
//        QThread::msleep(20);
        return -1;
    }


//    while(1)
//    {
//        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VDEC, 0, 1000);
//        if (!mb)
//        {

//            qDebug()<<"RK_MPI_SYS_GetMediaBuffer get null buffer in 5s.."<<endl;
//            QThread::msleep(20);
//            continue;
//        }
//        else
//        {
//            qDebug()<<"get buffer"<<endl;
//            break;
//        }
//    }

    MB_IMAGE_INFO_S stImageInfo = {0};
    ret = RK_MPI_MB_GetImageInfo(mb, &stImageInfo);
    if (ret) {
      printf("Get image info failed! ret = %d\n", ret);
      RK_MPI_MB_ReleaseBuffer(mb);
      return -1;
    }

    // 打印图像信息
    printf("Image Info:\n");
    printf("Width: %u\n", stImageInfo.u32Width);
    printf("Height: %u\n", stImageInfo.u32Height);
    printf("Horizontal Stride: %u\n", stImageInfo.u32HorStride);
    printf("Image Type: %u\n", stImageInfo.enImgType);

    printf("#Send packet(%p, %zuBytes) to VDEC[0].\n", RK_MPI_MB_GetPtr(mb),
           RK_MPI_MB_GetSize(mb));

    const int imageSize = VIDEO_WIDTH * VIDEO_HEIGHT;  // RGB888 格式

    // 获取 MEDIA_BUFFER 中的数据指针和大小
    void *dataPtr = RK_MPI_MB_GetPtr(mb);
    size_t dataSize = RK_MPI_MB_GetSize(mb);

    // 检查数据大小是否符合预期
    if (dataSize != imageSize)
    {
        qDebug() << "Error: Data size mismatch";
        RK_MPI_MB_ReleaseBuffer(mb); // 释放 MEDIA_BUFFER
        return -1;
    }

    QImage image((uchar*)dataPtr, VIDEO_WIDTH, VIDEO_HEIGHT, QImage::Format_RGB888);
    if (image.isNull()) {
        qDebug() << "Error: Failed to create QImage";
        RK_MPI_MB_ReleaseBuffer(mb); // 释放 MEDIA_BUFFER
        return -1;
    }
    qDebug()<<"发送显示图像"<<endl;
    emit CRkProcessWidget::Get()->signalImageUpdate(image);

    RK_MPI_MB_ReleaseBuffer(mb);

    return 0;
}

问题在于 int CRkProcessWidget::cGetImage() 中的mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VDEC, 0, 1000);一直无法接收到解码后得到数据,一直显示超时
[RKMEDIA][SYS][Info]:INFO: RkmediaChnPopBuffer: Mode[VDEC]:Chn[0] get mediabuffer timeout!

我来回答
回答1个
时间排序
认可量排序

执笔蘸墨

3个粉丝

5

问答

0

专栏

0

资料

执笔蘸墨 2024-07-10 11:40:25
认可1

1.已解决,解决思路来源如下,回答一下供大家参考
https://blog.csdn.net/qq_40170041/article/details/126481941
2.无法正常解码的主要原因(引自上述链接)
H264 annexb模式
H264有两种封装 ⼀种是annexb模式,传统模式,有startcode,SPS和PPS是在ES中 ⼀种是mp4模式,⼀般mp4 mkv都是mp4模式,没有startcode,SPS和PPS以及其它信息 被封装在container中,每⼀个frame前⾯4个字节是这个frame的⻓度 很多解码器只⽀持annexb这种模式,因此需要将mp4做转换:在ffmpeg中⽤ h264_mp4toannexb_filter可以做转换
3.解决方法
上面说要做转换 那就转换一下,但是链接中的代码我没跑通,可能是我和作者的ffmpeg的版本不同导致(我的版本是4.2.2)

//头文件
//除了常规的ffmpeg的参数要加上下面的bit流过滤器
    const AVBitStreamFilter *m_avbsfilter = nullptr;
    AVBSFContext  *bsf_ctx  = nullptr;

//源文件
    //打开文件的时候最后设置下这个过滤器
    // 1 获取相应的比特流过滤器
    //FLV/MP4/MKV等结构中,h264需要h264_mp4toannexb处理。添加SPS/PPS等信息。
    // FLV封装时,可以把多个NALU放在一个VIDEO TAG中,结构为4B NALU长度+NALU1+4B NALU长度+NALU2+...,
    // 需要做的处理把4B长度换成00000001或者000001
    m_avbsfilter = av_bsf_get_by_name(QString("h264_mp4toannexb").toLocal8Bit());
    if(m_avbsfilter == NULL)
    {
        qDebug()<<"av_bsf_alloc FAILD!"<<endl;
    }

    //初始化过滤器上下文  为指定的比特流过滤器分配上下文内存。
    if(av_bsf_alloc(m_avbsfilter, &bsf_ctx) == 0)
    {
        qDebug()<<"av_bsf_alloc succed!"<<endl;
    }
    avcodec_parameters_copy(bsf_ctx->par_in, ic->streams[videoStream]->codecpar);

    if(av_bsf_init(bsf_ctx) == 0)
    {
        qDebug()<<"av_bsf_alloc succed!"<<endl;
    }


//读取到h264的avpacket之后 使用如下的函数转换一下,再传入解码器就可正常解码了

int cH264ModeMp4ToAnnexB(AVPacket *pkt);
int XFFmpeg::cH264ModeMp4ToAnnexB(AVPacket *pkt)
{
    int ret = av_bsf_send_packet(bsf_ctx, pkt); // bitstreamfilter内部去维护内存空间
    if (ret != 0)
    {
        qDebug()<<"av_bsf_send_packet failed!"<<endl;
        return -1;
    }
    qDebug()<<"av_bsf_send_packet send!"<<endl;
    av_packet_unref(pkt);



    while(av_bsf_receive_packet(bsf_ctx, pkt) == 0)
    {
        qDebug()<<"av_bsf_send_packet get!"<<endl;
    }

    qDebug()<<"av_bsf_send_packet get!"<<endl;
    return 0;
}
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区