わかりやすいFFmpeg学習(04) - QT+FFmpegでローカル動画をデコード(後編)


序文

  この記事では、FFmpeg 関数ライブラリを使用して QT 環境でローカル ビデオをデコードする方法 (パート 2) - ローカル ビデオをデコードし、ウィンドウで再生する方法を共有します。


1.FFmpegのデコード処理

  • 下図はデコードのフローチャートで、黄色の部分がデコードで呼び出される関数、緑色の部分がデコードに必要なパラメータ(構造体)です。
    ここに画像の説明を挿入

2. デコードと再生の効果

  • ローカル ビデオがデコードされた後、次の図に示すように、デコードされたビデオ フレームがウィンドウで再生されます。
    ここに画像の説明を挿入

3.具体的な手順とソースコード

1. FFmpeg ヘッダー ファイル リファレンス

//当前C++兼容C语言
extern "C"
{
    
    
//avcodec:编解码(最重要的库)
#include <libavcodec/avcodec.h>
//avformat:封装格式处理
#include <libavformat/avformat.h>
//swscale:视频像素数据格式转换
#include <libswscale/swscale.h>
//avdevice:各种设备的输入输出
#include <libavdevice/avdevice.h>
//avutil:工具库(大部分库都需要这个库的支持)
#include <libavutil/avutil.h>
}

2. 環境登録

  • ハードウェア デバイス、ネットワーク レジスタ、マルチプレクサ、エンコーダなどを登録する必要があります。
	//环境注册
    av_register_all();        	  //复用器、编码器等注册
    avdevice_register_all();  	  //硬件设备注册
    avformat_network_init();   	 //网络注册

3. カプセル化形式のコンテキストを作成する

  • 関数 avformat_alloc_context() を使用して、カプセル化形式のコンテキストを作成および初期化します。
	AVFormatContext *formatContext = avformat_alloc_context();

4. マルチメディア ファイルを開く

  • ローカル ファイルをカプセル化形式のコンテキストで開きます。オープンに失敗すると、エラー メッセージが出力されます。
    int avformat_open_ret = avformat_open_input(&formatContext,filename.toLatin1(),NULL,NULL);
    if(avformat_open_ret < 0)
    {
    
    
        char *result = new char[64];
        av_strerror(avformat_open_ret,result,64);
        qDebug() << QString("错误信息:%1").arg(result);
    }
    qDebug() << "打开多媒体文件成功!";

5. オーディオおよびビデオ ストリーム情報を取得する

  • カプセル化形式のコンテキストでオーディオおよびビデオ ストリーム情報を取得します。取得に失敗すると、エラー メッセージが表示されます。
    int avformat_find_ret = avformat_find_stream_info(formatContext,NULL);
    if(avformat_find_ret < 0)
    {
    
    
        char *result = new char[64];
        av_strerror(avformat_open_ret,result,64);
        qDebug() << QString("错误信息:%1").arg(result);
    }
    qDebug() << "获取音视频流信息成功!";

6. ビデオ ストリームを見つける

  • ビデオ ストリームを検索し、カプセル化形式のコンテキストですべてのストリーム情報をトラバースして、ビデオ ストリーム インデックスを保存します。
    int streamIndex = -1;
    for(int i=0;i<formatContext->nb_streams;i++)
    {
    
    
        if(formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
    
    
            streamIndex = i;
            break;
        }
    }
    if(streamIndex == -1)
    {
    
    
        qDebug() << "找不到相应的流信息!";
    }

7. デコーダーのコンテキストを取得する

  • ビデオ ストリーム インデックスを介してデコーダ コンテキストを取得します。
	AVCodecContext *codecContext = formatContext->streams[streamIndex]->codec;

8. 適切なデコーダーを見つける

  • デコード コンテキストの属性 ID で適切なデコーダを見つけます。
	AVCodec *codec = avcodec_find_decoder(codecContext->codec_id);
    if(codec == NULL)
    {
    
    
        qDebug() << "找不到合适的解码器!";
    }

9. デコーダーを開きます

  • デコーダーのコンテキストで、見つかったデコーダーを開きます。
    int avcodec_open_ret = avcodec_open2(codecContext,codec,NULL);
    if(avcodec_open_ret < 0)
    {
    
    
        char *result = new char[64];
        av_strerror(avformat_open_ret,result,64);
        qDebug() << QString("错误信息:%1").arg(result);
    }
    qDebug() << "打开解码器成功!";

10. データコンテナの初期化

  • 受信したデータのデータ パケット、データ フレーム、およびデータ バッファー コンテナーにメモリ領域を動的に割り当てます。
	//数据包初始化
	AVPacket *packet = av_packet_alloc();			
	
	//输入视频帧初始化
    AVFrame *frame = av_frame_alloc();				
    
    //输出RGB帧初始化
    AVFrame *frameRGB = av_frame_alloc();			
    
    //给缓冲区动态分配内存
    uint8_t *pOutbuffer = (uint8_t*)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB32,codecContext->width,codecContext->height));

    //初始化缓冲区
    avpicture_fill((AVPicture *)frameRGB, pOutbuffer,AV_PIX_FMT_RGB32, codecContext->width,codecContext->height);

11. 画像変換コンテキストを取得する

  • デコーダ コンテキストを介して画像変換コンテキストを取得します。
    SwsContext *sws = sws_getContext(codecContext->width,codecContext->height,codecContext->pix_fmt,
                               codecContext->width,codecContext->height,AV_PIX_FMT_RGB32,
                               SWS_BICUBIC,NULL,NULL,NULL);

12. ビデオ フレームの読み取りと表示

  • カプセル化形式のコンテキストからデータ パケットに情報を読み取り、次にデータ パケットからデータ フレームに読み取り、最後にデータを画像に変換して表示します。
	//计算解码帧数
    int frameNum = 0;
    //创建标签显示图像
    QLabel *imgLabel = new QLabel(this);
    imgLabel ->setGeometry(0,0,600,330);
    //读取视频帧
    while(av_read_frame(formatContext,packet) >= 0)
    {
    
    
        if(packet->stream_index == streamIndex)
        {
    
    
            avcodec_send_packet(codecContext,packet);
            int decode_video_ret = avcodec_receive_frame(codecContext,frame);
            if(decode_video_ret >= 0)
            {
    
    
            	//计算帧数
                frameNum++;
				qDebug() << QString("正在解码播放第%1帧数据").arg(frameNum);
				//视频流数据转换为RGB图像数据
                sws_scale(sws, (const unsigned char* const*)frame->data,frame->linesize, 0,
                          codecContext->height,frameRGB->data,frameRGB->linesize);
				//数据转换为图像
                QImage  *tmpImg  = new QImage((uchar *)pOutbuffer,codecContext->width,
                                              codecContext->height,QImage::Format_RGB32);
               	//加载到标签中显示
				imgLabel->setPixmap(QPixmap::fromImage(img));
   				imgLabel->setScaledContents(true);
            }
        }
    }

四、FFmpeg参考資料

著作権表示: この記事の内容の一部は、参照および使用のために、CSDN ブロガー "Lei Xiaohua" の元の記事を参照して編集されています。
ブログアドレス: https://blog.csdn.net/leixiaohua1020?type=blog .


要約する

   以上がFFmpegの分かりやすい学習(04)~QT+FFmpegでローカル動画をデコードする(後編)の全内容ですので、読んで少しでも何かを得られれば幸いです!オリジナリティは簡単ではありません。転載のソースを示してください。記事に誤りがある場合は、読者がメッセージを残して修正し、批判することを歓迎します。

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_59134387/article/details/127235290