FFmpeg编解码的那些事(2)-视频软解码

软解码

1.构建输入AVFormatContext

    AVFormatContext* avFormatContext = avformat_alloc_context();
    int res = avformat_open_input(&avFormatContext,filename.toUtf8().data(), NULL, NULL);//打开文件
    if (res < 0) {
        qCritical()<<__FUNCTION__<<__LINE__<<"error "<<res<<"in avformat_open_input";
        return res;
    }

2.查找视频信息流

    res = avformat_find_stream_info(avFormatContext, nullptr);//取出流信息
    if (res < 0)
    {
        return res;
    }
    //查找视频流和音频流
    av_dump_format(avFormatContext, 0,filename.toUtf8().data(), 0);//列出输入文件的相关流信息

    for (unsigned int i = 0; i < avFormatContext->nb_streams; i++)
    {
        if (avFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            if(video_index==-1)
            {
                video_index = i;
            }
        }
    }

    m_width   = avFormatContext->streams[video_index]->codec->width;
    m_height  = avFormatContext->streams[video_index]->codec->height;

3.初始化软解码

    AVCodecContext *avCodecContext = avFormatContext->streams[video_index]->codec;

    AVCodec* m_codec = avcodec_find_decoder(avCodecContext->codec_id);
    if (avcodec_open2(avCodecContext, m_codec, NULL) < 0)
    {
        return false;
    }

4.初始化SwsContext图像转换上下文

    img_convert_ctx = sws_getContext(
                m_width,
                m_height,
                avCodecContext->pix_fmt,
                m_width,
                m_height,
                AV_PIX_FMT_BGRA,
                SWS_BICUBIC,
                NULL, NULL, NULL);

5.循环读取数据

    while (true)
    {
        int ret = av_read_frame(avFormatContext, avPacket);
        if (ret < 0){
            qDebug()<< "read end";
            break;
        }
        else if (avPacket->stream_index == video_index){
            decode_to_photo(avPacket);
        }
        av_packet_unref(avPacket);
    }

void decode_to_photo(const AVPacket *avPacket)
{
    int ret = avcodec_send_packet(avCodecContext, avPacket);
    if (ret < 0) {
        char error[1024];
        av_strerror(ret, error, 1024);
        qDebug() << "发送解码失败:" << error;
    }
    while (true)
    {
        ret = avcodec_receive_frame(avCodecContext, avFrame);

        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
        {
            //qDebug() << "avcodec_receive_frame end:" << ret;
            break;
        }
        else if (ret < 0)
        {
            //qDebug()<< "获取解码数据失败"<<ret;
            return;
        }
        else
        {
            QImage pixLogo2;
            int m_rotat = getRotateAngle(avFormatContext->streams[video_index]);

            if(dec_st == AV_SOFTWARE_DECODER)
            {
                sws_scale(img_convert_ctx,
                          (const unsigned char* const*)avFrame->data,
                          avFrame->linesize, 0,
                          avFrame->height,
                          bgrFrame->data,
                          bgrFrame->linesize);

                QImage pixLogo(bgrFrame->data[0],bgrFrame->width,bgrFrame->height,
                        bgrFrame->width * 4, QImage::Format_ARGB32);

                QMatrix matrix;
                matrix.rotate(m_rotat);
                pixLogo2 = pixLogo.transformed(matrix,Qt::FastTransformation);

                /*这里可以进行必要的图片处理操作*/
            }
            curcount++;
            av_frame_unref(sw_frame);
            av_frame_unref(avFrame);
        }
    }
}

tips:

根据pts来计算一桢在整个视频中的时间位置

timestamp(秒) = pts * av_q2d(st->time_base) 
timestamp(毫秒) = pts * av_q2d(st->time_base) * 1000 

计算视频长度的方法

time(秒) = st->duration * av_q2d(st->time_base)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值