FFmpeg多媒體格式轉(zhuǎn)換(二)

本章節(jié)講述多媒體格式流程的操作步驟:

多媒體文件轉(zhuǎn)封裝格式流程

1, 創(chuàng)建輸入和輸出文件的上下文

AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;

 // 通過 avformat_open_input() 打開/創(chuàng)建輸入文件的上下文吃环,in_filename 多媒體文件路徑
 if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
        fprintf(stderr, "Could not open input file '%s'", in_filename);
        goto end;
    }
    // 判斷是否有視頻流信息
    if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
        fprintf(stderr, "Failed to retrieve input stream information");
        goto end;
    }
    // 輸出多媒體文件信息
    av_dump_format(ifmt_ctx, 0, in_filename, 0);
   // 創(chuàng)建輸出封裝格式上下文
    avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);

2, 創(chuàng)建輸出流信息郁轻,并且將原文件音視頻流信息的參數(shù)復(fù)制到輸出音視頻流中

多媒體格式轉(zhuǎn)換其實只是改變視頻的封裝格式(即只是改變視頻的殼,里面的音視頻及字幕流信息是沒有改變的好唯,所以我們需要保留原有多媒體文件的參數(shù))

如下是創(chuàng)建流信息及參數(shù)復(fù)制的關(guān)鍵代碼:

// 從輸入 ifmt_ctx 中遍歷流信息
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
        AVStream *out_stream;
        AVStream *in_stream = ifmt_ctx->streams[i];

        // 原多媒體中的流參數(shù)
        AVCodecParameters *in_codecpar = in_stream->codecpar;

        // 判斷是否是音頻流骑篙、視頻流、字幕流
        if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
            in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
            in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
            stream_mapping[i] = -1;
            continue;
        }

        stream_mapping[i] = stream_index++;

        // 從輸出上下文中創(chuàng)建新的stream贯溅,并且返回該stream
        out_stream = avformat_new_stream(ofmt_ctx, NULL);
        if (!out_stream) {
            fprintf(stderr, "Failed allocating output stream\n");
            ret = AVERROR_UNKNOWN;
            goto end;
        }
        // 拷貝原視頻中的參數(shù)到輸出流信息中
        ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
        if (ret < 0) {
            fprintf(stderr, "Failed to copy codec parameters\n");
            goto end;
        }
        out_stream->codecpar->codec_tag = 0;
    }

3, 循環(huán)讀取每一幀的AVPacket信息它浅,并且將音頻镣煮、視頻、字幕流信息寫入輸出文件中

以下是寫入輸出文件的核心代碼:

/*
   需要寫入視頻的頭信息镊折,avformat_write_header 是ffmpeg一個通用的API介衔,
   它內(nèi)部會根據(jù)輸出多媒體的格式(mp4炎咖、mov等)來寫入相應(yīng)的多媒體頭信息
*/
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
   fprintf(stderr, "Error occurred when opening output file\n");
   goto end; 
}

while (1) {
        AVStream *in_stream, *out_stream;

       // 讀取每一幀的 AVPacket *pkt 數(shù)據(jù)
        ret = av_read_frame(ifmt_ctx, &pkt);
        if (ret < 0)
            break;

        in_stream  = ifmt_ctx->streams[pkt.stream_index];

        // 通過stream_index 判斷是否是我們第二步中查找的流
        if (pkt.stream_index >= stream_mapping_size ||
            stream_mapping[pkt.stream_index] < 0) {
            av_packet_unref(&pkt);
            continue;
        }

        out_stream = ofmt_ctx->streams[pkt.stream_index];

        // AVPacket pts、dts升熊、duration轉(zhuǎn)換
        pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
        pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);

        //packet 在流信息中的位置级野,封裝格式改變之后pos也不一樣粹胯,設(shè)置-1,表示需要重算
        pkt.pos = -1;

        // 寫入packet 信息渊抽,av_interleaved_write_frame 與 av_write_frame 兩個函數(shù)都可以寫入
        ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
        if (ret < 0) {
            fprintf(stderr, "Error muxing packet\n");
            break;
        }
        // 釋放AVPacket
        av_packet_unref(&pkt);
   }

 // 寫入視頻尾部信息议忽,與 avformat_write_header 相對應(yīng)
 av_write_trailer(ofmt_ctx);

從上一篇文章我們了解到栈幸,AVPacket中包含pts(顯示時間戳)dts(解碼時間戳),這些參數(shù)是AVPacket顯示及渲染出來的關(guān)鍵參數(shù)速址,而這些參數(shù)根據(jù)不同的封裝格式得出值也不一樣的芍锚,所以需要通過算法轉(zhuǎn)換將原來封裝格式的值轉(zhuǎn)換到新的封裝格式想要的值蔓榄,而ffmpeg提供了av_rescale_q_rnd()av_rescale_q()函數(shù)來轉(zhuǎn)換甥郑。

  • av_rescale_q()是采用默認的方式轉(zhuǎn)換
  • av_rescale_q_rnd()多一個AVRounding參數(shù)荤西,設(shè)置算法中數(shù)值的保留值方式

AVRounding提供以下5種方式
AV_ROUND_ZERO = 0, // Round toward zero. 趨近于0
AV_ROUND_INF = 1, // Round away from zero. 趨遠于0
AV_ROUND_DOWN = 2,// Round toward -infinity. 趨于更小的整數(shù)
AV_ROUND_UP = 3,// Round toward +infinity. 趨于更大的整數(shù)
AV_ROUND_NEAR_INF = 5,// Round to nearest and halfway cases away from zero.
// 四舍五入,小于0.5取值趨向0,大于0.5取值趨遠于0

至此FFmpeg格式轉(zhuǎn)換的流程就完成了邪锌,總結(jié)之前感覺FFmpeg好多API觅丰,腦子里面也是混亂的,經(jīng)過這兩篇文章的梳理舶胀,現(xiàn)在感覺對這塊流程思路清晰了很多,并且發(fā)現(xiàn)也沒什么難的糖赔。

完整代碼稍后再補充放典。基茵。拱层。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市径缅,隨后出現(xiàn)的幾起案子烙肺,更是在濱河造成了極大的恐慌,老刑警劉巖氏堤,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鼠锈,死亡現(xiàn)場離奇詭異,居然都是意外死亡购笆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來行您,“玉大人剪廉,你說我怎么就攤上這事“聘” “怎么了泉沾?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵跷究,是天一觀的道長。 經(jīng)常有香客問我丁存,道長解寝,這世上最難降的妖魔是什么艘儒? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任彤悔,我火速辦了婚禮,結(jié)果婚禮上抑片,老公的妹妹穿的比我還像新娘杨赤。我一直安慰自己,他們只是感情好植捎,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布蚓峦。 她就那樣靜靜地躺著济锄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荐绝。 梳的紋絲不亂的頭發(fā)上低滩,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天恕沫,我揣著相機與錄音,去河邊找鬼枫虏。 笑死爬虱,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的死讹。 我是一名探鬼主播曲梗,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼愧旦,長吁一口氣:“原來是場噩夢啊……” “哼笤虫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起酬凳,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤宁仔,失蹤者是張志新(化名)和其女友劉穎翎苫,沒想到半個月后榨了,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阻逮,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年瓜富,在試婚紗的時候發(fā)現(xiàn)自己被綠了与柑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片价捧。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡结蟋,死狀恐怖渔彰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宝惰,我是刑警寧澤再沧,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站夜郁,受9級特大地震影響竞端,放射性物質(zhì)發(fā)生泄漏庙睡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望啡邑。 院中可真熱鬧谤逼,春花似錦、人聲如沸流部。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枝冀。三九已至舞丛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間果漾,已是汗流浹背球切。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绒障,地道東北人欧聘。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像端盆,于是被迫代替她去往敵國和親怀骤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容