FFmpeg —— 10.示例程序(四):音视频分离(分离为AAC、H264格式)

参考:https://blog.csdn.net/leixiaohua1020/article/details/39802819

流程图

 

程序源码 

/*
 *
 * 本程序可以将封装格式中的视频码流数据和音频码流数据分离出来
 *
 */

#include <stdio.h>

#define __STDC_CONSTANT_MACROS

extern "C"
{
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
}

/*
 FIX: H.264 in some container format (FLV, MP4, MKV etc.) need
 "h264_mp4toannexb" bitstream filter (BSF)
 *Add SPS,PPS in front of IDR frame
 *Add start code ("0,0,0,1") in front of NALU
 H.264 in some container (MPEG2TS) don't need this BSF.
 */
//'1': Use H.264 Bitstream Filter
#define USE_H264BSF 0

int open_codec_context(int *streamIndex, AVFormatContext *&ofmtCtx, AVFormatContext *ifmtCtx, AVMediaType type)
{
	AVStream *outStream = NULL, *inStream = NULL;
	int ret = -1, index = -1;

	index = av_find_best_stream(ifmtCtx, type, -1, -1, NULL, 0);
	if (index < 0)
	{
		printf("can't find %s stream in input file\n", av_get_media_type_string(type));
		return ret;
	}

	inStream = ifmtCtx->streams[index];

	outStream = avformat_new_stream(ofmtCtx, NULL);
	if (!outStream)
	{
		printf("failed to allocate output stream\n");
		return ret;
	}

	ret = avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);
	if (ret < 0)
	{
		printf("failed to copy codec parametes\n");
		return ret;
	}

	outStream->codecpar->codec_tag = 0;

	if (ofmtCtx->oformat->flags & AVFMT_GLOBALHEADER)
	{
		outStream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
	}

	*streamIndex = index;

	return 0;
}


int main(int argc, char *argv[])
{
	AVFormatContext *ifmtCtx = NULL, *ofmtCtxAudio = NULL, *ofmtCtxVideo = NULL;
//	AVCodecContext *codecCtxVideo = NULL, *codecCtxAudio = NULL;
	AVPacket packet;

	int videoIndex = -1, audioIndex = -1;
	int ret = 0;

	char inFilename[128] = "input.mp4";
	char outFilenameAudio[128] = "output.aac";
	char outFilenameVideo[128] = "output.h264";

#if USE_H264BSF
	AVBitStreamFilterContext *h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
#endif

	//注册设备
	avdevice_register_all();

	//打开输入流
	ret = avformat_open_input(&ifmtCtx, inFilename, 0, 0);
	if (ret < 0)
	{
		printf("can't open input file\n");
		goto end;
	}

	//获取流信息
	ret = avformat_find_stream_info(ifmtCtx, 0);
	if (ret < 0)
	{
		printf("can't retrieve input stream information\n");
		goto end;
	}

	//创建输出上下文:视频
	avformat_alloc_output_context2(&ofmtCtxVideo, NULL, NULL, outFilenameVideo);
	if (!ofmtCtxVideo)
	{
		printf("can't create video output context");
		goto end;
	}

	//创建输出上下文:音频
	avformat_alloc_output_context2(&ofmtCtxAudio, NULL, NULL, outFilenameAudio);
	if (!ofmtCtxAudio)
	{
		printf("can't create audio output context");
		goto end;
	}

#if 1
	ret = open_codec_context(&videoIndex, ofmtCtxVideo, ifmtCtx, AVMEDIA_TYPE_VIDEO);
	if (ret < 0)
	{
		printf("can't decode video context\n");
		goto end;
	}


	ret = open_codec_context(&audioIndex, ofmtCtxAudio, ifmtCtx, AVMEDIA_TYPE_AUDIO);
	if (ret < 0)
	{
		printf("can't decode video context\n");
		goto end;
	}
#endif

#if 0
	for (i = 0; i < ifmtCtx->nb_streams; ++i)
	{
		AVFormatContext *ofmtCtx;
		AVStream *inStream = ifmtCtx->streams[i];
		AVStream *outStream = NULL;

		if (ifmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			videoIndex = i;
			outStream = avformat_new_stream(ofmtCtxVideo, inStream->codec->codec);
			ofmtCtx = ofmtCtxVideo;
		}
		else if (ifmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			audioIndex = i;
			outStream = avformat_new_stream(ofmtCtxAudio, inStream->codec->codec);
			ofmtCtx = ofmtCtxAudio;
		}
		else
		{
			break;
		}

		if (!outStream)
		{
			printf("failed to allocate output stream\n");
			goto end;
		}

		if (avcodec_copy_context(outStream->codec, inStream->codec) < 0)
		{
			printf("failed to copy context from input to output stream codec context\n");
			goto end;
		}

		outStream->codec->codec_tag = 0;

		if (ofmtCtx->oformat->flags & AVFMT_GLOBALHEADER)
		{
			outStream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
		}
	}
#endif

	//Dump Format------------------
	printf("\n==============Input Video=============\n");
	av_dump_format(ifmtCtx, 0, inFilename, 0);
	printf("\n==============Output Video============\n");
	av_dump_format(ofmtCtxVideo, 0, outFilenameVideo, 1);
	printf("\n==============Output Audio============\n");
	av_dump_format(ofmtCtxAudio, 0, outFilenameAudio, 1);
	printf("\n======================================\n");

	//打开输出文件:视频
	if (!(ofmtCtxVideo->oformat->flags & AVFMT_NOFILE))
	{
		if (avio_open(&ofmtCtxVideo->pb, outFilenameVideo, AVIO_FLAG_WRITE) < 0)
		{
			printf("can't open output file: %s\n", outFilenameVideo);
			goto end;
		}
	}

	//打开输出文件:音频
	if (!(ofmtCtxAudio->oformat->flags & AVFMT_NOFILE))
	{
		if (avio_open(&ofmtCtxAudio->pb, outFilenameAudio, AVIO_FLAG_WRITE) < 0)
		{
			printf("can't open output file: %s\n", outFilenameVideo);
			goto end;
		}
	}

	//写文件头
	if (avformat_write_header(ofmtCtxVideo, NULL) < 0)
	{
		printf("Error occurred when opening video output file\n");
		goto end;
	}

	if (avformat_write_header(ofmtCtxAudio, NULL) < 0)
	{
		printf("Error occurred when opening audio output file\n");
		goto end;
	}


	while (1)
	{
		AVFormatContext *ofmtCtx;
		AVStream *inStream, *outStream;

		if (av_read_frame(ifmtCtx, &packet) < 0)
		{
			break;
		}

		inStream = ifmtCtx->streams[packet.stream_index];

		if (packet.stream_index == videoIndex)
		{
			outStream = ofmtCtxVideo->streams[0];
			ofmtCtx = ofmtCtxVideo;
#if USE_H264BSF
			av_bitstream_filter_filter(h264bsfc, inStream->codec, NULL, &packet.data, &packet.size, packet.data,
					packet.size, 0);
#endif
		}
		else if (packet.stream_index == audioIndex)
		{
			outStream = ofmtCtxAudio->streams[0];
			ofmtCtx = ofmtCtxAudio;
		}
		else
		{
			continue;
		}

		//convert PTS/DTS
		packet.pts = av_rescale_q_rnd(packet.pts, inStream->time_base, outStream->time_base,
				(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		packet.dts = av_rescale_q_rnd(packet.dts, inStream->time_base, outStream->time_base,
				(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		packet.duration = av_rescale_q(packet.duration, inStream->time_base, outStream->time_base);
		packet.pos = -1;
		packet.stream_index = 0;

		//write
		if (av_interleaved_write_frame(ofmtCtx, &packet) < 0)
		{
			printf("Error muxing packet\n");
			break;
		}

		av_packet_unref(&packet);

	}

#if USE_H264BSF
	av_bitstream_filter_close(h264bsfc);
#endif

	//write file trailer
	av_write_trailer(ofmtCtxVideo);
	av_write_trailer(ofmtCtxAudio);

	end:

	avformat_close_input(&ifmtCtx);

	if (ofmtCtxVideo && !(ofmtCtxVideo->oformat->flags & AVFMT_NOFILE))
	{
		avio_close(ofmtCtxVideo->pb);
	}

	if (ofmtCtxAudio && !(ofmtCtxAudio->oformat->flags & AVFMT_NOFILE))
	{
		avio_close(ofmtCtxAudio->pb);
	}

	avformat_free_context(ofmtCtxVideo);
	avformat_free_context(ofmtCtxAudio);

	return 0;
}
发布了61 篇原创文章 · 获赞 124 · 访问量 70万+

猜你喜欢

转载自blog.csdn.net/guoyunfei123/article/details/105583900