久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

FFMPEG解碼流程1(轉(zhuǎn))

 quasiceo 2013-08-23

FFMPEG解碼流程1(轉(zhuǎn))  

2012-11-06 17:45:10|  分類: 視頻圖像 |字號 訂閱

FFMPEG解碼流程:
  1. 注冊所有容器格式和CODEC: av_register_all()
  2. 打開文件: av_open_input_file()
  3. 從文件中提取流信息: av_find_stream_info()
  4. 窮舉所有的流,,查找其中種類為CODEC_TYPE_VIDEO
  5. 查找對應(yīng)的解碼器: avcodec_find_decoder()
  6. 打開編解碼器: avcodec_open()
  7. 為解碼幀分配內(nèi)存: avcodec_alloc_frame()
  8. 不停地從碼流中提取出幀數(shù)據(jù): av_read_frame()
  9. 判斷幀的類型,對于視頻幀調(diào)用: avcodec_decode_video()
  10. 解碼完后,,釋放解碼器: avcodec_close()
  11. 關(guān)閉輸入文件: avformat_close_input_file()
主要數(shù)據(jù)結(jié)構(gòu):

基本概念:
   編解碼器,、數(shù)據(jù)幀,、媒體流和容器是數(shù)字媒體處理系統(tǒng)的四個基本概念。
首先需要統(tǒng)一術(shù)語:
    容器/文件(Conainer/File):即特定格式的多媒體文件,。
    媒體流(Stream):指時間軸上的一段連續(xù)數(shù)據(jù),,如一段聲音數(shù)據(jù),一段視頻數(shù)據(jù)或一段字幕數(shù)據(jù),,可以是壓縮的,,也可以是非壓縮的,壓縮的數(shù)據(jù)需要關(guān)聯(lián)特定的編解碼器,。
    數(shù)據(jù)幀/數(shù)據(jù)包(Frame/Packet):通常,,一個媒體流由大量的數(shù)據(jù)幀組成,對于壓縮數(shù)據(jù),,幀對應(yīng)著編解碼器的最小處理單元,。通常,分屬于不同媒體流的數(shù)據(jù)幀交錯復(fù)用于容器之中,,參見交錯,。
    編解碼器:編解碼器以幀為單位實現(xiàn)壓縮數(shù)據(jù)和原始數(shù)據(jù)之間的相互轉(zhuǎn)換。
在FFMPEG中,,使用AVFormatContext、AVStream,、AVCodecContext,、AVCodec及AVPacket等結(jié)構(gòu)來抽象這些基本要素,它們的關(guān)系如上圖所示:
AVCodecContext:
    這是一個描述編解碼器上下文的數(shù)據(jù)結(jié)構(gòu),,包含了眾多編解碼器需要的參數(shù)信息,,如下列出了部分比較重要的域:
typedef struct AVCodecContext {
 / **
     *一些編解碼器需要/可以像使用extradata Huffman表。
     * MJPEG:Huffman表
     * RV10其他標(biāo)志
     * MPEG4:全球頭(也可以是在比特流或這里)
     *分配的內(nèi)存應(yīng)該是FF_INPUT_BUFFER_PADDING_SIZE字節(jié)較大
     *,,比extradata_size避免比特流器,,如果它與讀prolems。
     * extradata按字節(jié)的內(nèi)容必須不依賴于架構(gòu)或CPU的字節(jié)順序,。
     * - 編碼:設(shè)置/分配/釋放由libavcodec的,。
     * - 解碼:由用戶設(shè)置/分配/釋放。
     * /
    uint8_t *extradata;
    int extradata_size;
   / **
     *這是時間的基本單位,,在條件(以秒為單位)
     *幀時間戳派代表出席了會議,。對于固定fps的內(nèi)容,
     *基應(yīng)該1/framerate和時間戳的增量應(yīng)該
     *相同的1,。
     * - 編碼:必須由用戶設(shè)置,。
     * - 解碼:libavcodec的設(shè)置。
     * /
    AVRational time_base;
 /*視頻* /
    / **
     *圖片寬度/高度,。
     * - 編碼:必須由用戶設(shè)置,。
     * - 解碼:libavcodec的設(shè)置,。
     *請注意:兼容性,它是可能的,,而不是設(shè)置此
     * coded_width/高解碼之前,。
     * /
    int width, height;
    ......
    / *僅音頻* /
    int sample_rate; ///< 每秒采樣
    int channels; ///< 音頻通道數(shù)

    / **
     *音頻采樣格式
     * - 編碼:由用戶設(shè)置。
     * - 解碼:libavcodec的設(shè)置,。
     * /
    enum SampleFormat sample_fmt; ///< 樣本格式
 
    / *下面的數(shù)據(jù)不應(yīng)該被初始化,。* /
    / **
     *每包樣品,初始化時調(diào)用“init”,。
     * /
    int frame_size;
    int frame_number; ///<音頻或視頻幀數(shù)量
    char codec_name[32];
    enum AVMediaType codec_type; /* 看到AVMEDIA_TYPE_xxx */
    enum CodecID codec_id; /* see CODEC_ID_xxx */
 / **
     *的fourcc(LSB在前,,所以“的ABCD” - >(“D”<< 24)(“C”<< 16)(“B”<< 8)+“A”)。
     *這是用來解決一些編碼錯誤,。
     *分路器應(yīng)設(shè)置什么是編解碼器用于識別領(lǐng)域中,。
     *如果有分路器等多個領(lǐng)域,在一個容器,,然后選擇一個
     *最大化使用的編解碼器有關(guān)的信息,。
     *如果在容器中的編解碼器標(biāo)記字段然后32位大分路器應(yīng)該
     *重新映射到一個表或其他結(jié)構(gòu)的32位編號。也可選擇新
     * extra_codec_tag+大小可以添加,,但必須證明這是一個明顯的優(yōu)勢
     *第一,。
     * - 編碼:由用戶設(shè)置,如果沒有則默認(rèn)基礎(chǔ)上codec_id將使用,。
     * - 解碼:由用戶設(shè)置,,將被轉(zhuǎn)換成在初始化libavcodec的大寫。
     * /
    unsigned int codec_tag;
    ......
    / **
     *在解碼器的幀重排序緩沖區(qū)的大小,。
     *對于MPEG-2,,這是IPB1或0低延時IP。
     * - 編碼:libavcodec的設(shè)置,。
     * - 解碼:libavcodec的設(shè)置,。
     * /
    int has_b_frames;
 
   / **
     *每包的字節(jié)數(shù),如果常量和已知或0
     *用于一些WAV的音頻編解碼器,。
     * /
    int block_align;
    / **
     *從分路器位每個樣品/像素(huffyuv需要),。
     * - 編碼:libavcodec的設(shè)置。
     * - 解碼:由用戶設(shè)置,。
     * /
     int bits_per_coded_sample;
     .....
} AVCodecContext;

如果是單純使用libavcodec,,這部分信息需要調(diào)用者進(jìn)行初始化;如果是使用整個FFMPEG庫,,這部分信息在調(diào)用avformat_open_input和avformat_find_stream_info的過程中根據(jù)文件的頭信息及媒體流內(nèi)的頭部信息完成初始化,。其中幾個主要域的釋義如下:
    extradata/extradata_size:這個buffer中存放了解碼器可能會用到的額外信息,在av_read_frame中填充,。一般來說,,首先,,某種具體格式的demuxer在讀取格式頭信息的時候會填充extradata,其次,,如果demuxer沒有做這個事情,,比如可能在頭部壓根兒就沒有相關(guān)的編解碼信息,則相應(yīng)的parser會繼續(xù)從已經(jīng)解復(fù)用出來的媒體流中繼續(xù)尋找,。在沒有找到任何額外信息的情況下,,這個buffer指針為空。
    time_base:
    width/height:視頻的寬和高,。
    sample_rate/channels:音頻的采樣率和信道數(shù)目,。
    sample_fmt: 音頻的原始采樣格式。
        codec_name/codec_type/codec_id/codec_tag:編解碼器的信息,。
AVStrea
   該結(jié)構(gòu)體描述一個媒體流,,定義如下:
typedef struct AVStream {
    int index; /** <在AVFormatContext流的索引* /
    int id; /**< 特定格式的流ID */
    AVCodecContext *codec; /**< codec context */
    / **
     *流的實時幀率基地。
     *這是所有時間戳可以最低幀率
     *準(zhǔn)確代表(它是所有的最小公倍數(shù)
     *流的幀率),。請注意,,這個值只是一個猜測!
     *例如,,如果時間基數(shù)為1/90000和所有幀
     *約3600或1800計時器刻度,,,然后r_frame_rate將是50/1,。
     * /
    AVRational r_frame_rate;
   / **
     *這是時間的基本單位,,在條件(以秒為單位)
     *幀時間戳派代表出席了會議。對于固定fps的內(nèi)容,,
     *時基應(yīng)該是1/framerate的時間戳的增量應(yīng)為1。
     * /
    AVRational time_base;
    ......
    / **
     *解碼流量的第一幀,,在流量時-base分,。
     *如果你是絕對100%的把握,設(shè)定值
     *它真的是第一幀點,。
     *這可能是未定義(AV_NOPTS_VALUE)的,。
     *@注意的業(yè)余頭不弱者受制與正確的START_TIME的業(yè)余
     *分路器必須不設(shè)定此。
     * /
    int64_t start_time;
    / **
     *解碼:時間流流時基,。
     *如果源文件中沒有指定的時間,,但不指定
     *比特率,這個值將被從碼率和文件大小的估計,。
     * /
    int64_t duration;
#if LIBAVFORMAT_VERSION_INT < (53<<16)
    char language[4]; /** ISO 639-2/B 3-letter language code (empty string if undefined) */
#endif
  /* av_read_frame()支持* /
    enum AVStreamParseType need_parsing;
    struct AVCodecParserContext *parser;
    .....
   /*函數(shù)av_seek_frame()支持* /
    AVIndexEntry *index_entries; / **<僅用于如果格式不notsupport尋求本身,。* /
    int nb_index_entries;
    unsigned int index_entries_allocated_size;
    int64_t nb_frames; ///< 在此流的幀,如果已知或0
    ......
    //*平均幀率

    AVRational avg_frame_rate;
    ......
} AVStream;

主要域的釋義如下,,其中大部分域的值可以由avformat_open_input根據(jù)文件頭的信息確定,,缺少的信息需要通過調(diào)用avformat_find_stream_info讀幀及軟解碼進(jìn)一步獲?。?br>
    index/id:index對應(yīng)流的索引,這個數(shù)字是自動生成的,,根據(jù)index可以從AVFormatContext::streams表中索引到該流,;而id則是流的標(biāo)識,依賴于具體的容器格式,。比如對于MPEG TS格式,,id就是pid。
    time_base:流的時間基準(zhǔn),,是一個實數(shù),,該流中媒體數(shù)據(jù)的pts和dts都將以這個時間基準(zhǔn)為粒度。通常,,使用av_rescale/av_rescale_q可以實現(xiàn)不同時間基準(zhǔn)的轉(zhuǎn)換,。
    start_time:流的起始時間,以流的時間基準(zhǔn)為單位,,通常是該流中第一個幀的pts,。
    duration:流的總時間,以流的時間基準(zhǔn)為單位,。
    need_parsing:對該流parsing過程的控制域,。
    nb_frames:流內(nèi)的幀數(shù)目。
    r_frame_rate/framerate/avg_frame_rate:幀率相關(guān),。
    codec:指向該流對應(yīng)的AVCodecContext結(jié)構(gòu),,調(diào)用avformat_open_input時生成。
        parser:指向該流對應(yīng)的AVCodecParserContext結(jié)構(gòu),,調(diào)用avformat_find_stream_info時生成,。。
AVFormatContext
        這個結(jié)構(gòu)體描述了一個媒體文件或媒體流的構(gòu)成和基本信息,,定義如下:
        typedef struct AVFormatContext {
            const AVClass *av_class; /**<由avformat_alloc_context設(shè)置的,。* /
            / *只能是iFormat的,或在同一時間oformat,,不是兩個,。* /
            struct AVInputFormat *iformat;
            struct AVOutputFormat *oformat;
            void *priv_data;
            ByteIOContext *pb;
            unsigned int nb_streams;
            AVStream *streams[MAX_STREAMS];
            char filename[1024]; / **<輸入或輸出的文件名*/
            / *流信息* /
            int64_t timestamp;
        #if LIBAVFORMAT_VERSION_INT < (53<<16)
            char title[512];
            char author[512];
            char copyright[512];
            char comment[512];
            char album[512];
            int year; /**< ID3 year, 0 if none */
            int track; /**< track number, 0 if none */
            char genre[32]; /**< ID3 genre */
        #endif
            int ctx_flags; /** <格式特定的標(biāo)志,看到AVFMTCTX_xx* /
            /*分處理的私人數(shù)據(jù)(不直接修改),。* /
            / **此緩沖區(qū)只需要當(dāng)數(shù)據(jù)包已經(jīng)被緩沖,,但
               不解碼,例如,,在MPEG編解碼器的參數(shù)
               流,。 * /
            struct AVPacketList *packet_buffer;
            / **解碼元件的第一幀的位置,在
               AV_TIME_BASE分?jǐn)?shù)秒,。從來沒有設(shè)置這個值直接:
               推導(dǎo)的AVStream值,。 * /
            int64_t start_time;
            / **解碼流的時間,,在AV_TIME_BASE分?jǐn)?shù)
               秒。只設(shè)置這個值,,如果你知道沒有個人流
               工期,,也不要設(shè)置任何他們。這是從推導(dǎo)
               AVStream值如果沒有設(shè)置,。
            int64_t duration;
            / **解碼:總的文件大小,,如果未知0* /
            int64_t file_size;
            / **解碼:在比特/秒的總流率,如果不
               可用,。從來沒有直接設(shè)置它如果得到file_size和
               時間是已知的如FFmpeg的自動計算,。 * /
            int bit_rate;
            /* av_read_frame()支持* /
            AVStream *cur_st;
        #if LIBAVFORMAT_VERSION_INT < (53<<16)
            const uint8_t *cur_ptr_deprecated;
            int cur_len_deprecated;
            AVPacket cur_pkt_deprecated;
        #endif
            /* av_seek_frame() 支持 */
            int64_t data_offset; /** 第一包抵消 */
            int index_built;
            int mux_rate;
            unsigned int packet_size;
            int preload;
            int max_delay;
        #define AVFMT_NOOUTPUTLOOP -1
        #define AVFMT_INFINITEOUTPUTLOOP 0
            /** 次循環(huán)輸出的格式支持它的數(shù)量 */
            int loop_output;
            int flags;
        #define AVFMT_FLAG_GENPTS 0x0001 ///< 生成失蹤分,即使它需要解析未來框架,。
        #define AVFMT_FLAG_IGNIDX 0x0002 ///< 忽略指數(shù),。
        #define AVFMT_FLAG_NONBLOCK 0x0004 ///<從輸入中讀取數(shù)據(jù)包時,不要阻止,。
        #define AVFMT_FLAG_IGNDTS 0x0008 ///< 忽略幀的DTS包含DTS與PTS
        #define AVFMT_FLAG_NOFILLIN 0x0010 ///< 不要從任何其他值推斷值,,只是返回存儲在容器中
        #define AVFMT_FLAG_NOPARSE 0x0020 ///< 不要使用AVParsers,你還必須設(shè)置為FILLIN幀代碼的工作,,沒有解析AVFMT_FLAG_NOFILLIN - >無幀,。也在尋求框架不能工作,如果找到幀邊界的解析已被禁用
        #define AVFMT_FLAG_RTP_HINT 0x0040 ///< 暗示到輸出文件添加的RTP
            int loop_input;
           /**解碼:對探測數(shù)據(jù)的大小;編碼:未使用,。* /
            unsigned int probesize;
            / **
             在此期間,,輸入*最大時間(在AV_TIME_BASE單位)應(yīng)
             *進(jìn)行分析在avformat_find_stream_info()。
             * /
            int max_analyze_duration;
            const uint8_t *key;
            int keylen;
            unsigned int nb_programs;
            AVProgram **programs;
           / **
             *強迫影片codec_id,。
             * Demuxing:由用戶設(shè)置,。
             * /
            enum CodecID video_codec_id;
            / **
             *強迫音頻codec_id。
             * Demuxing:由用戶設(shè)置,。
             * /
            enum CodecID audio_codec_id;
            / **
             *強制的:字幕codec_id,。
             * Demuxing:由用戶設(shè)置。
             * /
            enum CodecID subtitle_codec_id;
            / **
             *以字節(jié)為單位的最高限額為每個數(shù)據(jù)流的索引使用的內(nèi)存,。
             *如果該指數(shù)超過此大小,,條目將被丟棄
             *需要保持一個較小的規(guī)模,。這可能會導(dǎo)致較慢或更少
             *準(zhǔn)確的尋求(分路器),。
             *分路器內(nèi)存中的一個完整的指數(shù)是強制性的將忽略
             *此。
             *混流:未使用
             * demuxing:由用戶設(shè)置* /
            unsigned int max_index_size;
           / **
             *以字節(jié)為單位的最高限額使用幀緩沖內(nèi)存
             *從實時捕獲設(shè)備獲得,。* /
            unsigned int max_picture_buffer;
            unsigned int nb_chapters;
            AVChapter **chapters;
            / **
             *標(biāo)志啟用調(diào)試,。* /
            int debug;
        #define FF_FDEBUG_TS 0x0001
            / **
             *原始數(shù)據(jù)包從分路器之前,解析和解碼,。
             *此緩沖區(qū)用于緩沖數(shù)據(jù)包,,直到編解碼器可以
             *確定,,因為不知道不能做解析
             *編解碼器。* /
            struct AVPacketList *raw_packet_buffer;
            struct AVPacketList *raw_packet_buffer_end;
            struct AVPacketList *packet_buffer_end;
            AVMetadata *metadata;
            / **
             *剩余的大小可為raw_packet_buffer,,以字節(jié)為單位,。
             *不屬于公共API* /
        #define RAW_PACKET_BUFFER_SIZE 2500000
            int raw_packet_buffer_remaining_size;
            / **
             *在現(xiàn)實世界中的時間流的開始時間,以微秒
             *自Unix紀(jì)元(1970年1月1日起00:00),。也就是說,,pts= 0
             在這個現(xiàn)實世界的時間*流被抓獲。
             * - 編碼:由用戶設(shè)置,。
             * - 解碼:未使用,。 * /
            int64_t start_time_realtime;
        } AVFormatContext;
        這是FFMpeg中最為基本的一個結(jié)構(gòu),是其他所有結(jié)構(gòu)的根,,是一個多媒體文件或流的根本抽象,。其中:
         nb_streams和streams所表示的AVStream結(jié)構(gòu)指針數(shù)組包含了所有內(nèi)嵌媒體流的描述;
         iformat和oformat指向?qū)?yīng)的demuxer和muxer指針,;
         pb則指向一個控制底層數(shù)據(jù)讀寫的ByteIOContext結(jié)構(gòu),。
         start_time和duration是從streams數(shù)組的各個AVStream中推斷出的多媒體文件的起始時間和長度,以微妙為單位,。
        通常,,這個結(jié)構(gòu)由avformat_open_input在內(nèi)部創(chuàng)建并以缺省值初始化部分成員。但是,,如果調(diào)用者希望自己創(chuàng)建該結(jié)構(gòu),,則需要顯式為該結(jié)構(gòu)的一些成員置缺省值——如果沒有缺省值的話,會導(dǎo)致之后的動作產(chǎn)生異常,。以下成員需要被關(guān)注:
            probesize
            mux_rate
            packet_size
            flags
            max_analyze_duration
            key
            max_index_size
            max_picture_buffer
            max_delay
AVPacket
        
        AVPacket定義在avcodec.h中,,如下:
        
        typedef struct AVPacket {
            / **
             AVStream->基time_base單位介紹時間戳的時間
             *解壓縮包將被提交給用戶。
             *可AV_NOPTS_VALUE如果沒有存儲在文件中,。
             *分必須大于或等于DTS作為演示不能發(fā)生之前
             *減壓,,除非要查看十六進(jìn)制轉(zhuǎn)儲。有些格式濫用
             * DTS和PTS/ CTS的條款意味著不同的東西,。如時間戳
             *必須轉(zhuǎn)換為真正的PTS / DTS之前,,他們在AVPacket存儲。 * /
            int64_t pts;
            / **
             AVStream->基time_base單位時間的減壓時間戳記;
             *包解壓,。
             *可AV_NOPTS_VALUE如果沒有存儲在文件中,。 * /
            int64_t dts;
            uint8_t *data;
            int size;
            int stream_index;
            int flags;
            / **
             *這個包的時間AVStream->基time_base單位,如果未知,。
             *等于next_pts - 在呈現(xiàn)順序this_pts,。* /
            int duration;
            void (*destruct)(struct AVPacket *);
            void *priv;
            int64_t pos; ///< 如果未知字節(jié)的位置,在流,-1
            / **
             * AVStream->基time_base單位的時差,,這點
             *包從解碼器輸出的已融合在哪個點
             *獨立的前一幀的情況下,。也就是說,
             *框架幾乎是一致的,,沒有問題,,如果解碼開始從
             *第一幀或從這個關(guān)鍵幀。
             * AV_NOPTS_VALUE如果不明,。
             *此字段是不是當(dāng)前數(shù)據(jù)包的顯示時間,。
             *
             *這一領(lǐng)域的目的是允許在流,沒有尋求
             *在傳統(tǒng)意義上的關(guān)鍵幀,。它所對應(yīng)的
             *恢復(fù)點SEI的H.264和match_time_delta在螺母,。這也是
             *必不可少的一些類型的字幕流,以確保所有
             *后尋求正確顯示字幕,。* /
            int64_t convergence_duration;
        } AVPacket;
        FFMPEG使用AVPacket來暫存解復(fù)用之后,、解碼之前的媒體數(shù)據(jù)(一個音/視頻幀、一個字幕包等)及附加信息(解碼時間戳,、顯示時間戳,、時長等)。其中:
            dts表示解碼時間戳,,pts表示顯示時間戳,,它們的單位是所屬媒體流的時間基準(zhǔn)。
            stream_index給出所屬媒體流的索引,;
            data為數(shù)據(jù)緩沖區(qū)指針,,size為長度;
            duration為數(shù)據(jù)的時長,,也是以所屬媒體流的時間基準(zhǔn)為單位,;
            pos表示該數(shù)據(jù)在媒體流中的字節(jié)偏移量;
            destruct為用于釋放數(shù)據(jù)緩沖區(qū)的函數(shù)指針,;
            flags為標(biāo)志域,,其中,最低為置1表示該數(shù)據(jù)是一個關(guān)鍵幀,。
        AVPacket結(jié)構(gòu)本身只是個容器,,它使用data成員引用實際的數(shù)據(jù)緩沖區(qū)。這個緩沖區(qū)通常是由av_new_packet創(chuàng)建的,,但也可能由FFMPEG的API創(chuàng)建(如av_read_frame),。當(dāng)某個AVPacket結(jié)構(gòu)的數(shù)據(jù)緩沖區(qū)不再被使用時,要需要通過調(diào)用av_free_packet釋放,。av_free_packet調(diào)用的是結(jié)構(gòu)體本身的destruct函數(shù),,它的值有兩種情況:1)av_destruct_packet_nofree或0;2)av_destruct_packet,,其中,,情況1)僅僅是將data和size的值清0而已,情況2)才會真正地釋放緩沖區(qū),。
        FFMPEG內(nèi)部使用AVPacket結(jié)構(gòu)建立緩沖區(qū)裝載數(shù)據(jù),,同時提供destruct函數(shù),如果FFMPEG打算自己維護緩沖區(qū),,則將destruct設(shè)為av_destruct_packet_nofree,,用戶調(diào)用av_free_packet清理緩沖區(qū)時并不能夠?qū)⑵溽尫牛蝗绻鸉FMPEG打算將該緩沖區(qū)徹底交給調(diào)用者,,則將destruct設(shè)為av_destruct_packet,,表示它能夠被釋放。安全起見,,如果用戶希望自由地使用一個FFMPEG內(nèi)部創(chuàng)建的AVPacket結(jié)構(gòu),,最好調(diào)用av_dup_packet進(jìn)行緩沖區(qū)的克隆,將其轉(zhuǎn)化為緩沖區(qū)能夠被釋放的AVPacket,,以免對緩沖區(qū)的不當(dāng)占用造成異常錯誤,。av_dup_packet會為destruct指針為av_destruct_packet_nofree的AVPacket新建一個緩沖區(qū),然后將原緩沖區(qū)的數(shù)據(jù)拷貝至新緩沖區(qū),,置data的值為新緩沖區(qū)的地址,,同時設(shè)destruct指針為av_destruct_packet。
時間信息
        時間信息用于實現(xiàn)多媒體同步,。
        同步的目的在于展示多媒體信息時,,能夠保持媒體對象之間固有的時間關(guān)系。同步有兩類,,一類是流內(nèi)同步,,其主要任務(wù)是保證單個媒體流內(nèi)的時間關(guān)系,以滿足感知要求,,如按照規(guī)定的幀率播放一段視頻,;另一類是流間同步,主要任務(wù)是保證不同媒體流之間的時間關(guān)系,,如音頻和視頻之間的關(guān)系(lipsync),。
        對于固定速率的媒體,如固定幀率的視頻或固定比特率的音頻,,可以將時間信息(幀率或比特率)置于文件首部(header),,如AVI的hdrl List、MP4的moov box,,還有一種相對復(fù)雜的方案是將時間信息嵌入媒體流的內(nèi)部,,如MPEG TS和Real video,這種方案可以處理變速率的媒體,亦可有效避免同步過程中的時間漂移,。
        FFMPEG會為每一個數(shù)據(jù)包打上時間標(biāo)簽,,以更有效地支持上層應(yīng)用的同步機制。時間標(biāo)簽有兩種,,一種是DTS,,稱為解碼時間標(biāo)簽,另一種是PTS,,稱為顯示時間標(biāo)簽,。對于聲音來說 ,這兩個時間標(biāo)簽是相同的,,但對于某些視頻編碼格式,,由于采用了雙向預(yù)測技術(shù),會造成DTS和PTS的不一致,。
        無雙向預(yù)測幀的情況:
        圖像類型: I P P P P P P ... I P P
        DTS: 0 1 2 3 4 5 6... 100 101 102
        PTS: 0 1 2 3 4 5 6... 100 101 102
        有雙向預(yù)測幀的情況:
        圖像類型: I P B B P B B ... I P B
        DTS: 0 1 2 3 4 5 6 ... 100 101 102
        PTS: 0 3 1 2 6 4 5 ... 100 104 102
        對于存在雙向預(yù)測幀的情況,,通常要求解碼器對圖像重排序,以保證輸出的圖像順序為顯示順序:
        解碼器輸入:I P B B P B B
         (DTS) 0 1 2 3 4 5 6
         (PTS) 0 3 1 2 6 4 5
        解碼器輸出:X I B B P B B P
         (PTS) X 0 1 2 3 4 5 6
時間信息的獲?。?br>        通過調(diào)用avformat_find_stream_info,,多媒體應(yīng)用可以從AVFormatContext對象中拿到媒體文件的時間信息:主要是總時間長度和開始時間,此外還有與時間信息相關(guān)的比特率和文件大小,。其中時間信息的單位是AV_TIME_BASE:微秒,。
        typedef struct AVFormatContext {
            / **解碼元件的第一幀的位置,在
               AV_TIME_BASE分?jǐn)?shù)秒,。從來沒有設(shè)置這個值直接:
               推導(dǎo)的AVStream值,。 * /
            int64_t start_time;
            / **解碼流的時間,在AV_TIME_BASE分?jǐn)?shù)秒,。只設(shè)置這個值,,如果你知道沒有個人流工期,也不要設(shè)置任何他們,。這是從推導(dǎo)AVStream值如果沒有設(shè)置,。 * /
            int64_t duration;
            / **解碼:總的文件大小,如果未知=0* /
            int64_t file_size;
            / **解碼:在比特/秒的總流率,,如果不可用,。從來沒有直接設(shè)置它如果得到file_size和時間是已知的如FFmpeg的自動計算。 * /
            int bit_rate;
            .....
        } AVFormatContext;
        以上4個成員變量都是只讀的,,基于FFMpeg的中間件需要將其封裝到某個接口中,,如:
        LONG GetDuratioin(IntfX*);
        LONG GetStartTime(IntfX*);
        LONG GetFileSize(IntfX*);
        LONG GetBitRate(IntfX*);
APIs
 avformat_open_input:
        int avformat_open_input(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, AVDictionary **options);
        avformat_open_input完成兩個任務(wù):
            打開一個文件或URL,基于字節(jié)流的底層輸入模塊得到初始化,。
            解析多媒體文件或多媒體流的頭信息,,創(chuàng)建AVFormatContext結(jié)構(gòu)并填充其中的關(guān)鍵字段,,依次為各個原始流建立AVStream結(jié)構(gòu)。
        一個多媒體文件或多媒體流與其包含的原始流的關(guān)系如下:
        多媒體文件/多媒體流 (movie.mkv)
          原始流 1 (h.264 video)
          原始流 2 (aac audio for Chinese)
          原始流 3 (aac audio for english)
          原始流 4 (Chinese Subtitle)
          原始流 5 (English Subtitle)
          ...
        關(guān)于輸入?yún)?shù):
            ic_ptr,,這是一個指向指針的指針,,用于返回avformat_open_input內(nèi)部構(gòu)造的一個AVFormatContext結(jié)構(gòu)體。
            filename,,指定文件名。
            fmt,,用于顯式指定輸入文件的格式,,如果設(shè)為空則自動判斷其輸入格式。
            options
        這個函數(shù)通過解析多媒體文件或流的頭信息及其他輔助數(shù)據(jù),,能夠獲取足夠多的關(guān)于文件,、流和編解碼器的信息,但由于任何一種多媒體格式提供的信息都是有限的,,而且不同的多媒體內(nèi)容制作軟件對頭信息的設(shè)置不盡相同,,此外這些軟件在產(chǎn)生多媒體內(nèi)容時難免會引入一些錯誤,因此這個函數(shù)并不保證能夠獲取所有需要的信息,,在這種情況下,,則需要考慮另一個函數(shù):
avformat_find_stream_info:
        int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
        這個函數(shù)主要用于獲取必要的編解碼器參數(shù),設(shè)置到ic→streams[i]→codec中,。
        首先必須得到各媒體流對應(yīng)編解碼器的類型和id,,這是兩個定義在avutils.h和avcodec.h中的枚舉:
        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,
            ...
        };
        通常,如果某種媒體格式具備完備而正確的頭信息,,調(diào)用avformat_open_input即可以得到這兩個參數(shù),,但若是因某種原因avformat_open_input無法獲取它們,這一任務(wù)將由avformat_find_stream_info完成,。
        其次還要獲取各媒體流對應(yīng)編解碼器的時間基準(zhǔn),。
        此外,對于音頻編解碼器,,還需要得到:
            采樣率,,
            聲道數(shù),
            位寬,,
           幀長度(對于某些編解碼器是必要的),,
        對于視頻編解碼器,則是:
            圖像大小,,
            色彩空間及格式,,
        av_read_frame
        int av_read_frame(AVFormatContext *s, AVPacket *pkt);
        這個函數(shù)用于從多媒體文件或多媒體流中讀取媒體數(shù)據(jù),獲取的數(shù)據(jù)由AVPacket結(jié)構(gòu)pkt來存放,。對于音頻數(shù)據(jù),,如果是固定比特率,,則pkt中裝載著一個或多個音頻幀;如果是可變比特率,,則pkt中裝載有一個音頻幀,。對于視頻數(shù)據(jù),pkt中裝載有一個視頻幀,。需要注意的是:再次調(diào)用本函數(shù)之前,,必須使用av_free_packet釋放pkt所占用的資源。
        通過pkt→stream_index可以查到獲取的媒體數(shù)據(jù)的類型,,從而將數(shù)據(jù)送交相應(yīng)的解碼器進(jìn)行后續(xù)處理,。
        av_seek_frame
        int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
        這個函數(shù)通過改變媒體文件的讀寫指針來實現(xiàn)對媒體文件的隨機訪問,支持以下三種方式:
            基于時間的隨機訪問:具體而言就是將媒體文件讀寫指針定位到某個給定的時間點上,,則之后調(diào)用av_read_frame時能夠讀到時間標(biāo)簽等于給定時間點的媒體數(shù)據(jù),,通常用于實現(xiàn)媒體播放器的快進(jìn)、快退等功能,。
            基于文件偏移的隨機訪問:相當(dāng)于普通文件的seek函數(shù),,timestamp也成為文件的偏移量。
            基于幀號的隨機訪問:timestamp為要訪問的媒體數(shù)據(jù)的幀號,。
        關(guān)于參數(shù):
            s:是個AVFormatContext指針,,就是avformat_open_input返回的那個結(jié)構(gòu)。
            stream_index:指定媒體流,,如果是基于時間的隨機訪問,,則第三個參數(shù)timestamp將以此媒體流的時間基準(zhǔn)為單位;如果設(shè)為負(fù)數(shù),,則相當(dāng)于不指定具體的媒體流,,F(xiàn)FMPEG會按照特定的算法尋找缺省的媒體流,此時,,timestamp的單位為AV_TIME_BASE(微秒),。
            timestamp:時間標(biāo)簽,單位取決于其他參數(shù),。
            flags:定位方式,,AVSEEK_FLAG_BYTE表示基于字節(jié)偏移,AVSEEK_FLAG_FRAME表示基于幀號,,其它表示基于時間,。
av_close_input_file:
        void av_close_input_file(AVFormatContext *s);
        關(guān)閉一個媒體文件:釋放資源,關(guān)閉物理IO,。
avcodec_find_decoder:
        AVCodec *avcodec_find_decoder(enum CodecID id);
        AVCodec *avcodec_find_decoder_by_name(const char *name);
        
        根據(jù)給定的codec id或解碼器名稱從系統(tǒng)中搜尋并返回一個AVCodec結(jié)構(gòu)的指針,。
avcodec_open:
        int avcodec_open(AVCodecContext *avctx, AVCodec *codec);
        此函數(shù)根據(jù)輸入的AVCodec指針具體化AVCodecContext結(jié)構(gòu)。在調(diào)用該函數(shù)之前,,需要首先調(diào)用avcodec_alloc_context分配一個AVCodecContext結(jié)構(gòu),,或調(diào)用avformat_open_input獲取媒體文件中對應(yīng)媒體流的AVCodecContext結(jié)構(gòu),;此外還需要通過avcodec_find_decoder獲取AVCodec結(jié)構(gòu)。
        這一函數(shù)還將初始化對應(yīng)的解碼器,。
avcodec_decode_video2
        int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, AVPacket *avpkt);
        解碼一個視頻幀,。got_picture_ptr指示是否有解碼數(shù)據(jù)輸出。
        輸入數(shù)據(jù)在AVPacket結(jié)構(gòu)中,,輸出數(shù)據(jù)在AVFrame結(jié)構(gòu)中,。AVFrame是定義在avcodec.h中的一個數(shù)據(jù)結(jié)構(gòu):
        typedef struct AVFrame {
            FF_COMMON_FRAME
        } AVFrame;
        
        FF_COMMON_FRAME定義了諸多數(shù)據(jù)域,大部分由FFMpeg內(nèi)部使用,,對于用戶來說,,比較重要的主要包括:
        #define FF_COMMON_FRAME \
        ......
            uint8_t *data[4];\
            int linesize[4];\
            int key_frame;\
            int pict_type;\
            int64_t pts;\
            int reference;\
        ......
        FFMpeg內(nèi)部以planar的方式存儲原始圖像數(shù)據(jù),即將圖像像素分為多個平面(R/G/B或Y/U/V),,data數(shù)組內(nèi)的指針分別指向四個像素平面的起始位置,,linesize數(shù)組則存放各個存貯各個平面的緩沖區(qū)的行寬:
        +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        +++data[0]->#################################++++++++++++
        ++++++++++++###########picture data##########++++++++++++
                    ........................
        ++++++++++++#################################++++++++++++
        |<-------------------line_size[0]---------------------->|
        此外,,key_frame標(biāo)識該圖像是否是關(guān)鍵幀,;pict_type表示該圖像的編碼類型:I(1)/P(2)/B(3)……;pts是以time_base為單位的時間標(biāo)簽,,對于部分解碼器如H.261,、H.263和MPEG4,可以從頭信息中獲??;reference表示該圖像是否被用作參考。
avcodec_decode_audio4
        int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt);
        解碼一個音頻幀,。輸入數(shù)據(jù)在AVPacket結(jié)構(gòu)中,,輸出數(shù)據(jù)在frame中,got_frame_ptr表示是否有數(shù)據(jù)輸出,。
avcodec_close
        int avcodec_close(AVCodecContext *avctx);
        關(guān)閉解碼器,,釋放avcodec_open中分配的資源。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多