日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

FFmpeg学习1:视频解码

發布時間:2024/8/26 编程问答 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FFmpeg学习1:视频解码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在視頻解碼前,先了解以下幾個基本的概念:

  • 編解碼器(CODEC):能夠進行視頻和音頻壓縮(CO)與解壓縮(DEC),是視頻編解碼的核心部分。
  • 容器/多媒體文件(Container/File):沒有了解視頻的編解碼之前,總是錯誤的認為平常下載的電影的文件的后綴(avi,mkv,rmvb等)就是視頻的編碼方式。事實上,剛才提到的幾種文件的后綴
    并不是視頻的編碼方式,只是其封裝的方式。一個視頻文件通常有視頻數據、音頻數據以及字幕等,封裝的格式決定這些數據在文件中是如何的存放的,封裝在一起音頻、視頻等數據組成的多媒體文件,也可以叫做容器(其中包含了視音頻數據)。所以,只看多媒體文件的后綴名是難以知道視音頻的編碼方式的。
  • 流數據 Stream,例如視頻流(Video Stream),音頻流(Audio Stream)。流中的數據元素被稱為幀Frame

FFmpeg視頻解碼過程

通常來說,FFmpeg的視頻解碼過程有以下幾個步驟:

  • 注冊所支持的所有的文件(容器)格式及其對應的CODEC av_register_all()
  • 打開文件 avformat_open_input()
  • 從文件中提取流信息 avformat_find_stream_info()
  • 在多個數據流中找到視頻流 video stream(類型為MEDIA_TYPE_VIDEO)
  • 查找video stream 相對應的解碼器 avcodec_find_decoder
  • 打開解碼器 avcodec_open2()
  • 為解碼幀分配內存 av_frame_alloc()
  • 從流中讀取讀取數據到Packet中 av_read_frame()
  • 對video 幀進行解碼,調用 avcodec_decode_video2()
  • 解碼過程的具體說明

    1. 注冊

    av_register_all該函數注冊支持的所有的文件格式(容器)及其對應的CODEC,只需要調用一次,故一般放在main函數中。也可以注冊某個特定的容器格式,但通常來說不需要這么做。

    2. 打開文件

    avformat_open_input該函數讀取文件的頭信息,并將其信息保存到AVFormatContext結構體中。其調用如下

    AVFormatContext* pFormatCtx = nullptr; avformat_open_input(&pFormatCtx, filenName, nullptr, nullptr)

    第一個參數是AVFormatContext結構體的指針,第二個參數為文件路徑;第三個參數用來設定輸入文件的格式,如果設為null,將自動檢測文件格式;第四個參數用來填充AVFormatContext一些字段以及Demuxer的private選項。
    AVFormatContext包含有較多的碼流信息參數,通常由avformat_open_input創建并填充關鍵字段。

    3. 獲取必要的CODEC參數

    avformat_open_input通過解析多媒體文件或流的頭信息及其他的輔助數據,能夠獲取到足夠多的關于文件、流和CODEC的信息,并將這些信息填充到AVFormatContext結構體中。但任何一種多媒體格式(容器)提供的信息都是有限的,而且不同的多媒體制作軟件對頭信息的設置也不盡相同,在制作多媒體文件的時候難免會引入一些錯誤。也就是說,僅僅通過avformat_open_input并不能保證能夠獲取所需要的信息,所以一般要使用

    avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)

    avformat_find_stream_info主要用來獲取必要的CODEC參數,設置到ic->streams[i]->codec。
    在解碼的過程中,首先要獲取到各個stream所對應的CODEC類型和id,CODEC的類型和id是兩個枚舉值,其定義如下:

    enum AVMediaType { AVMEDIA_TYPE_UNKNOWN = -1, AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA, AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_ATTACHMENT, AVMEDIA_TYPE_NB}; enum CodecID { CODEC_ID_NONE, /* video codecs */ CODEC_ID_MPEG1VIDEO, CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding CODEC_ID_MPEG2VIDEO_XVMC, CODEC_ID_H261, CODEC_ID_H263, ... }

    通常,如果多媒體文件具有完整而正確的頭信息,通過avformat_open_input即可用獲得這兩個參數。

    4. 打開解碼器

    經過上面的步驟,已經將文件格式信息讀取到了AVFormatContext中,要打開流數據相應的CODEC需要經過下面幾個步驟

    • 找到視頻流 video stream
      一個多媒體文件包含有多個原始流,例如 movie.mkv這個多媒體文件可能包含下面的流數據
    • 原始流 1 h.264 video
    • 原始流 2 aac audio for Chinese
    • 原始流 3 aac audio for English
    • 原始流 4 Chinese Subtitle
    • 原始流 5 English Subtitle

    要解碼視頻,首先要在AVFormatContext包含的多個流中找到CODEC類型為AVMEDIA_TYPE_VIDEO,代碼如下:

    //查找視頻流 video streamint videoStream = -1;for (int i = 0; i < pFormatCtx->nb_streams; i++){if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){videoStream = i;break;}}if (videoStream == -1)return -1; // 沒有找到視頻流video stream

    結構體AVFormatContext中的streams字段是一個AVStream指針的數組,包含了文件所有流的描述,上述上述代碼在該數組中查找CODEC類型為
    AVMEDIA_TYPE_VIDEO的流的下標。

    • 根據codec_id找到相應的CODEC,并打開
      結構體AVCodecContext描述了CODEC上下文,包含了眾多CODEC所需要的參數信息。
    AVCodecContext* pCodecCtxOrg = nullptr; AVCodec* pCodec = nullptr; pCodecCtxOrg = pFormatCtx->streams[videoStream]->codec; // codec context // 找到video stream的 decoder pCodec = avcodec_find_decoder(pCodecCtxOrg->codec_id); // open codecif (avcodec_open2(pCodecCtxOrg , pCodec, nullptr) < 0)return -1; // Could open codec

    上述代碼,首先通過codec_id找到相應的CODEC,然后調用avcodec_open2打開相應的CODEC。

    5. 讀取數據幀并解碼

    已經有了相應的解碼器,下面的工作就是將數據從流中讀出,并解碼為沒有壓縮的原始數據

    AVPacket packet; while (av_read_frame(pFormatCtx, &packet) >= 0) {if (packet.stream_index == videoStream){int frameFinished = 0;avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);if (frameFinished){doSomething();}}}

    上述代碼調用av_read_frame將數據從流中讀取數據到packet中,并調用avcodec_decode_video2對讀取的數據進行解碼。

    6. 關閉

    需要關閉avformat_open_input打開的輸入流,avcodec_open2打開的CODEC

    avcodec_close(pCodecCtxOrg);avformat_close_input(&pFormatCtx);

    補充

    在配置好FFmpeg的開發環境后,在C++中使用FFmpeg的庫函數,會出現解析不出函數的名稱鏈接錯誤,這是由于FFmpeg庫是C語言實現,要在C++調用C函數需要 extern "C"的聲明。

    extern "C" {# include <libavcodec\avcodec.h># include <libavformat\avformat.h># include <libswscale\swscale.h> }

    哎,博客園的Markdown用著好不方便啊,不知道怎么畫流程圖....

    代碼 FFmpeg0.cpp

    轉載于:https://www.cnblogs.com/wangguchangqing/p/5734998.html

    總結

    以上是生活随笔為你收集整理的FFmpeg学习1:视频解码的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。