简介
使用FFmpeg SDK实现的H.264码流合成MPEG2-TS文件
一、源代码
int main(int argc, char* argv[])
{
const char* input = NULL;
const char* output= NULL;
/* Obtain input params */
if (argc <= 1) {
printf("Usage:\n");
printf("%s <input_file.264> <output_file.ts>\n", argv[0]);
return 0;
}
input = argv[1];
output= argv[2];
AVInputFormat* ifmt = NULL;
AVOutputFormat* ofmt = NULL;
AVFormatContext* ic = NULL;
AVFormatContext* oc = NULL;
AVStream* video_st = NULL;
AVStream* audio_st = NULL;
AVCodec* codec = NULL;
AVDictionary* pAVDictionary = NULL;
avcodec_init();
avcodec_register_all();
av_register_all();
ifmt = av_find_input_format("avc");
ic = avformat_alloc_context();
if (!ic)
{
printf("Call avformat_alloc_context failed!\n");
return 0;
}
char szError[256] = {0};
int nRet = avformat_open_input(&ic, input, ifmt, &pAVDictionary);
if (nRet != 0)
{
av_strerror(nRet, szError, 256);
printf(szError);
printf("\n");
printf("Call avformat_open_input function failed!\n");
return 0;
}
if (avformat_find_stream_info(ic, NULL) < 0)
{
printf("Call av_find_stream_info function failed!\n");
return 0;
}
ofmt = av_guess_format("mpegts", NULL, NULL);
if (!ofmt)
{
printf("Call av_guess_format function failed!\n");
return 0;
}
oc = avformat_alloc_context();
if (!oc)
{
printf("Call av_guess_format function failed!\n");
return 0;
}
oc->oformat = ofmt;
int video_index = -1, audio_index = -1;
unsigned int i;
for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++)
{
switch (ic->streams[i]->codec->codec_type)
{
case AVMEDIA_TYPE_VIDEO:
video_index = i;
ic->streams[i]->discard = AVDISCARD_NONE;
video_st = add_output_stream(oc, ic->streams[i]);
break;
case AVMEDIA_TYPE_AUDIO:
audio_index = i;
ic->streams[i]->discard = AVDISCARD_NONE;
audio_st = add_output_stream(oc, ic->streams[i]);
break;
default:
ic->streams[i]->discard = AVDISCARD_ALL;
break;
}
}
codec = avcodec_find_decoder(video_st->codec->codec_id);
if (codec == NULL)
{
printf("Call avcodec_find_decoder function failed!\n");
return 0;
}
if (avcodec_open(video_st->codec, codec) < 0)
{
printf("Call avcodec_open function failed !\n");
return 0;
}
if (avio_open(&oc->pb, output, AVIO_FLAG_WRITE) < 0)
{
return 0;
}
if (avformat_write_header(oc, &pAVDictionary))
{
printf("Call avformat_write_header function failed.\n");
return 0;
}
uint8_t *dummy = NULL;
int dummy_size = 0;
AVBitStreamFilterContext* bsfc = av_bitstream_filter_init("h264_mp4toannexb");
if(bsfc == NULL)
{
return -1;
}
int decode_done = 0;
do
{
double segment_time = 0;
AVPacket packet;
decode_done = av_read_frame(ic, &packet);
if (decode_done < 0)
break;
if (av_dup_packet(&packet) < 0)
{
printf("Call av_dup_packet function failed\n");
av_free_packet(&packet);
break;
}
static int nCount = 0;
if (nCount++ < 20)
{
printf("The packet.stream_index is %ld\n", packet.stream_index);
}
if (packet.stream_index == video_index)
{
if (packet.pts != (u_int)AV_NOPTS_VALUE)
{
packet.pts = av_rescale_q(packet.pts,ic->streams[video_index]->time_base,video_st->time_base);
}
if (packet.dts != (u_int)AV_NOPTS_VALUE)
{
packet.dts = av_rescale_q(packet.dts,ic->streams[video_index]->time_base,video_st->time_base);
}
}
nRet = av_interleaved_write_frame(oc, &packet);
if (nRet < 0)
{
printf("Call av_interleaved_write_frame function failed\n");
}
else if (nRet > 0)
{
printf("End of stream requested\n");
av_free_packet(&packet);
break;
}
av_free_packet(&packet);
}while(!decode_done);
av_write_trailer(oc);
av_bitstream_filter_close(bsfc);
avcodec_close(video_st->codec);
unsigned int k;
for(k = 0; k < oc->nb_streams; k++)
{
av_freep(&oc->streams[k]->codec);
av_freep(&oc->streams[k]);
}
av_free(ic);
av_free(oc);
getchar();
return 0;
}
二、源码分析
01 avcodec_init(); 初始化libavcodec
02 avcodec_register_all(); 注册所有的codec, 解析器、码流过滤器
03 av_register_all(); 初始化libavformat并注册所有的muxer, demuxer和协议
/* 处理输入文件的格式 并初始化上下文 */
04 ifmt = av_find_input_format("avc");
05 ic = avformat_alloc_context();
06 avformat_open_input(&ic, input, ifmt, &pAVDictionary);
07 avformat_find_stream_info(ic, NULL);
/* 处理输出文件的格式 并初始化上下文 */
08 ofmt = av_guess_format("mpegts", NULL, NULL);
09 oc = avformat_alloc_context();
10 oc->oformat = ofmt;
/* 将输入文件的音视频流映射到输出文件,并初始化 */
11 int video_index = -1, audio_index = -1;
12 unsigned int i;
13 for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++){
14 switch (ic->streams[i]->codec->codec_type){
15 case AVMEDIA_TYPE_VIDEO:
16 video_index = i;
17 ic->streams[i]->discard = AVDISCARD_NONE;
18 video_st = add_output_stream(oc, ic->streams[i]);
19 break;
20 case AVMEDIA_TYPE_AUDIO:
21 audio_index = i;
22 ic->streams[i]->discard = AVDISCARD_NONE;
23 audio_st = add_output_stream(oc, ic->streams[i]);
24 break;
25 default:
26 ic->streams[i]->discard = AVDISCARD_ALL;
27 break;
28 }
29 }
30 codec = avcodec_find_decoder(video_st->codec->codec_id); 查找输出视频流的解码器;
31 avcodec_open(video_st->codec, codec); 使用codec初始化上下文video_st->codec;
32 avio_open(&oc->pb, output, AVIO_FLAG_WRITE); 打开输出文件
33 avformat_write_header(oc, &pAVDictionary); 将MPEG2-TS流的头写到输出文件
34 AVBitStreamFilterContext* bsfc = av_bitstream_filter_init("h264_mp4toannexb"); 初始化流过滤器上下文
35 int decode_done = 0;
36 do{
double segment_time = 0;
AVPacket packet;
37 decode_done = av_read_frame(ic, &packet); 从输入文件中读取一帧
38 if (decode_done < 0)
break;
39 if (av_dup_packet(&packet) < 0){ 包数据空间扩展
printf("Call av_dup_packet function failed\n");
av_free_packet(&packet);
break;
}
40 static int nCount = 0; 前20个包的流信息输出
if (nCount++ < 20){
printf("The packet.stream_index is %ld\n", packet.stream_index);
}
41 if (packet.stream_index == video_index){ 计算视频流的时间戳
42 if (packet.pts != (u_int)AV_NOPTS_VALUE){ 计算PTS值
packet.pts = av_rescale_q(packet.pts,ic->streams[video_index]->time_base,video_st->time_base);
}
43 if (packet.dts != (u_int)AV_NOPTS_VALUE){ 计算DTS值
packet.dts = av_rescale_q(packet.dts,ic->streams[video_index]->time_base,video_st->time_base);
}
}
44 nRet = av_interleaved_write_frame(oc, &packet); 将数据包混合插入输出文件
45 if (nRet < 0){
printf("Call av_interleaved_write_frame function failed\n");
}
46 else if (nRet > 0)
{
printf("End of stream requested\n");
av_free_packet(&packet); 释放包
break;
}
47 av_free_packet(&packet);
48 }while(!decode_done);
49 av_write_trailer(oc); 写MPEG-TS流的结尾
50 av_bitstream_filter_close(bsfc); 释放所有的资源
avcodec_close(video_st->codec);
unsigned int k;
for(k = 0; k < oc->nb_streams; k++)
{
av_freep(&oc->streams[k]->codec);
av_freep(&oc->streams[k]);
}
av_free(ic);
av_free(oc);
51 getchar(); 等待用户输出任意字符结束
return 0;
}
三、其它
1. 编译选项
# gcc tsmuxer.c -g -o tsmuxer
-I/YOUR_SDK_INSTALL_PATH/include -L/YOUR_SDK_INSTALL_PATH/lib
-lavformat -lavdevice -lavcodec -lavutil -lavfilter -pthread -ldl -lswscale -lbz2 -lasound
-lmp3lame -lfaac -lx264 -lrtmp -lz -lm
2. 完整代码下载
http://download.csdn.net/detail/fireroll/7292853
FFmpeg SDK开发模型之三:muxer,布布扣,bubuko.com