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

目录

前言:

环境:

代码

结论:


前言:

现在很多网上的代码,由于不是最新的ffmpeg库,导致很多不能运行。这里发一下自己运行过的最新的ffmpeg软解码代码。

环境:

        ffmpeg库代码:ffmpeg6.1.1

        qt环境

        windows系统

代码

#include <QCoreApplication>
#include <QDebug>

extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavdevice/avdevice.h"
#include "libavutil/imgutils.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/time.h"
#include "libavutil/mathematics.h"
#include "libavutil/channel_layout.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/opt.h"

#include "libavutil/mem.h"
#include "libavutil/buffer.h"
#include "libavutil/error.h"
#include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_qsv.h"
#define HAVE_STRUCT_TIMESPEC
//#include "pthread.h"
}


AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
{
    AVFrame *picture;
    int ret;

    picture = av_frame_alloc();
    if (!picture)
        return NULL;

    picture->format = pix_fmt;
    picture->width = width;
    picture->height = height;

    /* allocate the buffers for the frame data */
    ret = av_frame_get_buffer(picture, 4);
    if (ret < 0)
    {
        qCritical()<<__FUNCTION__<<__LINE__<<"Could not allocate frame data.";
        return NULL;
    }

    return picture;
}

int getRotateAngle(AVStream* avStream)
{
    AVDictionaryEntry *tag = NULL;
    int   m_Rotate = -1;
    tag = av_dict_get(avStream->metadata, "rotate", tag, 0);
    if (tag == NULL)

    {
        m_Rotate = 0;
    }
    else
    {
        int angle = atoi(tag->value);
        angle %= 360;
        m_Rotate = angle;
    }

    return m_Rotate;
}


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QString filename = "1.mp4";

    /*描述一个媒体文件或媒体流的构成和基本信息的结构体*/
    AVFormatContext *avFormatContext = nullptr;
    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;
    }

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

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

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

    const AVCodec*  m_codec = nullptr;/*解码器*/
    AVCodecContext *avCodecContext = nullptr;/*解码器上下文*/
    m_codec = avcodec_find_decoder(avFormatContext->streams[video_index]->codecpar->codec_id);
    avCodecContext = avcodec_alloc_context3(m_codec);
    avcodec_parameters_to_context(avCodecContext, avFormatContext->streams[video_index]->codecpar);

    if (avcodec_open2(avCodecContext, m_codec, nullptr) < 0)
    {
        qCritical()<<__FUNCTION__<<__LINE__<<"Init_Soft_DecoderCodec error";
        return false;
    }


    struct SwsContext *img_convert_ctx = nullptr;

    AVFrame *bgrFrame = NULL;
    AVFrame *avFrame = nullptr;
    AVPacket *avPacket;

    avPacket  =    av_packet_alloc();
    avFrame   =    av_frame_alloc();

    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);

    bgrFrame = alloc_picture(
                AV_PIX_FMT_BGRA,
                m_width,
                m_height);


    while (true)
    {
        int ret = av_read_frame(avFormatContext, avPacket);
        if (ret < 0){
            qDebug()<< "read end";
            break;
        }
        else if (avPacket->stream_index == video_index){
            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 ret;
                }
                else
                {
                    int m_rotat = getRotateAngle(avFormatContext->streams[video_index]);

                    sws_scale(img_convert_ctx,
                              (const unsigned char* const*)avFrame->data,
                              avFrame->linesize, 0,
                              avFrame->height,
                              bgrFrame->data,
                              bgrFrame->linesize);


                    av_frame_unref(avFrame);
                }
            }
        }
        av_packet_unref(avPacket);
    }

    if(bgrFrame)
    {
        av_frame_free(&bgrFrame);
        bgrFrame= nullptr;
    }

    m_codec = nullptr;

    if(avPacket)
    {
        av_packet_free(&avPacket);
        avPacket = nullptr;
    }

    if(avFrame)
    {
        av_frame_free(&avFrame);
        avFrame = nullptr;
    }

    if(img_convert_ctx)
    {
        sws_freeContext(img_convert_ctx);
        img_convert_ctx = nullptr;
    }

    if(avCodecContext != nullptr)
    {
        avcodec_close(avCodecContext);
        avCodecContext = nullptr;
    }

    if(avFormatContext != nullptr)
    {
        avformat_free_context(avFormatContext);
    }
qDebug()<<"=========end========";
    return a.exec();
}

结论:

        上面的代码用c语言写的,下次整一个c++的代码,可以更方便的来使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值