生活随笔
收集整理的這篇文章主要介紹了
ffmpeg解封装及解码实战
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
ffmpeg解封裝及解碼實戰
目錄
封裝格式相關函數解封裝流程補充分離AAC和H264
1. 封裝格式相關函數
1. 基本概念
2. 相關函數
1. avformat_alloc_context();負責申請一個AVFormatContext結構的內存,并進行簡單初始化
2. avformat_free_context();釋放AVFormatContext及其所有流。
3. avformat_close_input();關閉解復用器。關閉后就不再需要使用avformat_free_context 進行釋放
4. avformat_open_input();打開輸入視頻文件
打開一個輸入流并讀取報頭。編解碼器未打開。流必須用avformat_close_input()關閉。ps指向用戶提供的AVFormatContext(由avformat_alloc_context分配)的指針。可能是一個指向NULL的指針,在哪種情況下AVFormatContext是由這個分配的函數并寫入ps。內部有調用avformat_alloc_context()
5. avformat_find_stream_info():獲取音視頻文件信息
6. av_read_frame(); 讀取音視頻包
7. avformat_seek_file(); 定位文件
8. av_seek_frame():定位文件
2. 解封裝流程
3. 補充
1. 區分不同的碼流
AVMEDIA_TYPE_VIDEO視頻流:video_index = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
-1,-1, NULL, 0)AVMEDIA_TYPE_AUDIO音頻流:audio_index = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
-1,-1, NULL, 0)AVPacket 里面也有一個index的字段
2. 補充點
avformat_open_input和avformat_find_stream_info分別用于打開一個流和分析流信息。在初始信息不足的情況下(比如FLV和H264文件),avformat_find_stream_info接口需要在內部調用read_frame_internal接口讀取流數據(音視頻幀),然后再分析后,設置核心數據結構AVFormatContext。由于需要讀取數據包, avformat_find_stream_info接口會帶來很大的延遲
4. 分離AAC和H264
代碼
#include
<stdio
.h
>
#include
<libavformat
/avformat
.h
>int main(int argc
, char
**argv
) {
const char
*default_filename
= "believe.mp4";char
*in_filename
= NULL
;if (argv
[1] == NULL
) {in_filename
= default_filename
;} else {in_filename
= argv
[1];}printf("in_filename = %s\n", in_filename
);AVFormatContext
*ifmt_ctx
= NULL
; int videoindex
= -1; int audioindex
= -1; int ret
= avformat_open_input(&ifmt_ctx
, in_filename
, NULL
, NULL
);if (ret
< 0) {char buf
[1024] = {0};av_strerror(ret
, buf
, sizeof(buf
) - 1);printf("open %s failed:%s\n", in_filename
, buf
);goto failed
;}ret
= avformat_find_stream_info(ifmt_ctx
, NULL
);if (ret
< 0) {char buf
[1024] = {0};av_strerror(ret
, buf
, sizeof(buf
) - 1);printf("avformat_find_stream_info %s failed:%s\n", in_filename
, buf
);goto failed
;}printf_s("\n==== av_dump_format in_filename:%s ===\n", in_filename
);av_dump_format(ifmt_ctx
, 0, in_filename
, 0);printf_s("\n==== av_dump_format finish =======\n\n");printf("media name:%s\n", ifmt_ctx
->url
);printf("stream number:%d\n", ifmt_ctx
->nb_streams
);printf("media average ratio:%lldkbps\n", (int64_t
)(ifmt_ctx
->bit_rate
/ 1024));int total_seconds
, hour
, minute
, second
;total_seconds
= (ifmt_ctx
->duration
) / AV_TIME_BASE
; hour
= total_seconds
/ 3600;minute
= (total_seconds
% 3600) / 60;second
= (total_seconds
% 60);printf("total duration: %02d:%02d:%02d\n", hour
, minute
, second
);printf("\n");for (uint32_t i
= 0; i
< ifmt_ctx
->nb_streams
; i
++) {AVStream
*in_stream
= ifmt_ctx
->streams
[i
];if (AVMEDIA_TYPE_AUDIO
== in_stream
->codecpar
->codec_type
) {printf("----- Audio info:\n");printf("index:%d\n", in_stream
->index
);printf("samplerate:%dHz\n", in_stream
->codecpar
->sample_rate
);if (AV_SAMPLE_FMT_FLTP
== in_stream
->codecpar
->format
) {printf("sampleformat:AV_SAMPLE_FMT_FLTP\n");} else if (AV_SAMPLE_FMT_S16P
== in_stream
->codecpar
->format
) {printf("sampleformat:AV_SAMPLE_FMT_S16P\n");}printf("channel number:%d\n", in_stream
->codecpar
->channels
);if (AV_CODEC_ID_AAC
== in_stream
->codecpar
->codec_id
) {printf("audio codec:AAC\n");} else if (AV_CODEC_ID_MP3
== in_stream
->codecpar
->codec_id
) {printf("audio codec:MP3\n");} else {printf("audio codec_id:%d\n", in_stream
->codecpar
->codec_id
);}if (in_stream
->duration
!= AV_NOPTS_VALUE
) {int duration_audio
= (in_stream
->duration
) * av_q2d(in_stream
->time_base
);printf("audio duration: %02d:%02d:%02d\n",duration_audio
/ 3600, (duration_audio
% 3600) / 60, (duration_audio
% 60));} else {printf("audio duration unknown");}printf("\n");audioindex
= i
; } else if (AVMEDIA_TYPE_VIDEO
== in_stream
->codecpar
->codec_type
) {printf("----- Video info:\n");printf("index:%d\n", in_stream
->index
);printf("fps:%lffps\n", av_q2d(in_stream
->avg_frame_rate
));if (AV_CODEC_ID_MPEG4
== in_stream
->codecpar
->codec_id
) {printf("video codec:MPEG4\n");} else if (AV_CODEC_ID_H264
== in_stream
->codecpar
->codec_id
) {printf("video codec:H264\n");} else {printf("video codec_id:%d\n", in_stream
->codecpar
->codec_id
);}printf("width:%d height:%d\n", in_stream
->codecpar
->width
,in_stream
->codecpar
->height
);if (in_stream
->duration
!= AV_NOPTS_VALUE
) {int duration_video
= (in_stream
->duration
) * av_q2d(in_stream
->time_base
);printf("video duration: %02d:%02d:%02d\n",duration_video
/ 3600,(duration_video
% 3600) / 60,(duration_video
% 60)); } else {printf("video duration unknown");}printf("\n");videoindex
= i
;}}AVPacket
*pkt
= av_packet_alloc();int pkt_count
= 0;int print_max_count
= 10;printf("\n-----av_read_frame start\n");while
(1) {ret
= av_read_frame(ifmt_ctx
, pkt
);if (ret
< 0) {printf("av_read_frame end\n");break;}if (pkt_count
++ < print_max_count
) {if (pkt
->stream_index
== audioindex
) {printf("audio pts: %lld\n", pkt
->pts
);printf("audio dts: %lld\n", pkt
->dts
);printf("audio size: %d\n", pkt
->size
);printf("audio pos: %lld\n", pkt
->pos
);printf("audio duration: %lf\n\n",pkt
->duration
* av_q2d(ifmt_ctx
->streams
[audioindex
]->time_base
));} else if (pkt
->stream_index
== videoindex
) {printf("video pts: %lld\n", pkt
->pts
);printf("video dts: %lld\n", pkt
->dts
);printf("video size: %d\n", pkt
->size
);printf("video pos: %lld\n", pkt
->pos
);printf("video duration: %lf\n\n",pkt
->duration
* av_q2d(ifmt_ctx
->streams
[videoindex
]->time_base
));} else {printf("unknown stream_index:\n", pkt
->stream_index
);}}av_packet_unref(pkt
);}if (pkt
)av_packet_free(&pkt
);failed
:if (ifmt_ctx
)avformat_close_input(&ifmt_ctx
);getchar(); return 0;
}
結果
總結
以上是生活随笔為你收集整理的ffmpeg解封装及解码实战的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。