本文爲做者原創,轉載請註明出處:http://www.javashuo.com/article/p-ajbxpuef-dp.htmlhtml
FFmpeg封裝格式處理相關內容分爲以下幾篇文章:
[1]. FFmpeg封裝格式處理-簡介
[2]. FFmpeg封裝格式處理-解複用例程
[3]. FFmpeg封裝格式處理-複用例程
[4]. FFmpeg封裝格式處理-轉封裝例程git
解複用(demux),表示從一路輸入中分離出多路流(視頻、音頻、字幕等)。github
本例實現,將輸入文件中的視頻流和音頻流分離出來,保存爲單獨的文件,所保存的文件是不含封裝格式的裸流文件。ide
源碼很短,用於演示demux的用法。源碼中大部分函數返回值的判斷均已省略。函數
#include <libavformat/avformat.h> int main (int argc, char **argv) { if (argc != 4) { fprintf(stderr, "usage: %s test.ts test.h264 test.aac\n", argv[0]); exit(1); } const char *input_fname = argv[1]; const char *output_v_fname = argv[2]; const char *output_a_fname = argv[3]; FILE *video_dst_file = fopen(output_v_fname, "wb"); FILE *audio_dst_file = fopen(output_a_fname, "wb"); AVFormatContext *fmt_ctx = NULL; int ret = avformat_open_input(&fmt_ctx, input_fname, NULL, NULL); ret = avformat_find_stream_info(fmt_ctx, NULL); int video_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); int audio_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); if (video_idx < 0 || audio_idx < 0) { printf("find stream failed: %d %d\n", video_idx, audio_idx); return -1; } av_dump_format(fmt_ctx, 0, input_fname, 0); AVPacket pkt; av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; while (av_read_frame(fmt_ctx, &pkt) >= 0) { if (pkt.stream_index == video_idx) { ret = fwrite(pkt.data, 1, pkt.size, video_dst_file); //printf("vp %x %3"PRId64" %3"PRId64" (size=%5d)\n", pkt.pos, pkt.pts, pkt.dts, ret); } else if (pkt.stream_index == audio_idx) { ret = fwrite(pkt.data, 1, pkt.size, audio_dst_file); //printf("ap %x %3"PRId64" %3"PRId64" (size=%5d)\n", pkt.pos, pkt.pts, pkt.dts, ret); } av_packet_unref(&pkt); } printf("Demuxing succeeded.\n"); end: avformat_close_input(&fmt_ctx); fclose(video_dst_file); fclose(audio_dst_file); return 0; }
源文件爲demuxing.c,在SHELL中執行以下編譯命令:測試
gcc -o demuxing demuxing.c -lavformat -lavcodec -g
生成可執行文件demuxing編碼
測試文件下載:tnshih.flv
先看一下測試用資源文件的格式:.net
think@opensuse> ffprobe tnshih.flv ffprobe version 4.1 Copyright (c) 2007-2018 the FFmpeg developers Input #0, flv, from 'tnshih.flv': Metadata: encoder : Lavf58.20.100 Duration: 00:00:37.20, start: 0.000000, bitrate: 1182 kb/s Stream #0:0: Video: h264 (High), yuv420p(progressive), 800x450, 25 fps, 25 tbr, 1k tbn, 50 tbc Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp
能夠看到視頻文件'tnshih.flv'封裝格式爲flv,包含一路h264編碼的視頻流和一路aac編碼的音頻流。3d
運行以下命令進行測試:code
./demuxing tnshih.flv tnshih_flv.h264 tnshih_flv.aac
使用ffplay播放視頻文件thshih_flv.h264及音頻文件tnshih_flv.aac,均沒法播放。使用ffprobe檢測發現這兩個文件異常。
緣由參考雷霄驊博士的文章:
「使用FFMPEG類庫分離出多媒體文件中的H.264碼流」
「最簡單的基於FFmpeg的封裝格式處理:視音頻分離器簡化版」
本節代碼僅關注最簡單的解複用功能,FLV、MP4等特定容器中分離出來的h264視頻流和aac音頻流沒法播放。
那換一種封裝格式測一下,利用FFmpeg轉碼命令將flv封裝格式轉換爲mpegts封裝格式:
測試:
ffmpeg -i tnshih.flv -map 0 -c copy tnshih.ts
運行以下命令進行測試:
./demuxing tnshih.ts tnshih_ts.h264 tnshih_ts.aac
使用ffplay播放視頻文件thshih_ts.h264及音頻文件tnshih_ts.aac,播放正常。使用ffprobe檢測發現這兩個文件正常。