视频文件的解封装

视频的封装

。音视频文件 = (音频流+视频流)*同步信息

。实现方式:音频信号和视频信号通过某种标准格式进行服用,生成封装格式

。封装格式:文件扩展名-------.mp4/.avi/.flv/.mkv等


封装的视频文件的处理

。在底层,只能解析纯视频或者音频数据,不能直接处理封装的文件

。如果要实现视频文件的播放,所以想将封装的视频文件分离为音频,视频和字幕等其他辅助信息等

。FFmpeg中处理文件封装格式功能的库:libavformat.dll


源代码


extern"C"
{
	#include "libavcodec/avcodec.h"
	#include "libavutil/imgutils.h"
	#include "libavformat/avformat.h"
	#include "libavutil/samplefmt.h"
}

const char *src_filename = NULL;
const char *video_dst_filename = NULL;
const char *audio_dst_filename = NULL;

FILE *pOutputAudio = NULL;
FILE *pOutputVideo = NULL;
AVFormatContext *fmt_ctx = NULL;
AVStream *st = NULL; //一路视频或者音频或者字母流
AVCodec *dec = NULL;
AVCodecContext *dec_ctx = NULL;
AVStream *videoStream = NULL, *audioStream = NULL;
AVCodecContext *videoDecCtx = NULL, *audioDecCtx = NULL;
int frame_width = 0, frame_height = 0;
enum AVPixelFormat pix_fmt;
uint8_t *video_dst_data[4];
int video_dst_linesize[4];
int video_dst_bufsize;

AVFrame *frame = NULL;
AVPacket packet;
static int open_codec_context(enum AVMediaType type)
{
	int ret = 0;
	//查找音视频流,并返回对应的索引
	ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
	if (ret < 0)
	{
		printf("Error:find stream failed.\n");
		return -1;
	}
	else
	{
		
		st = fmt_ctx->streams[ret];//指向一路流
		dec_ctx = st->codec;//编解码器上下文
		dec = avcodec_find_decoder(dec_ctx->codec_id);//查找解码器
		if (avcodec_open2(dec_ctx, dec, NULL) < 0)//打开解码器
		{
			printf("Error:avcodec_open2 failed.\n");
			return -1;
		}
		
	}
	return 0;
}

static int decode_packet(int &got_frame)
{
	int ret = 0;
	got_frame = 0;
	if (packet.stream_index == videoStream->index)
	{
		//读packet属于视频流
		ret = avcodec_decode_video2(videoDecCtx, frame, &got_frame, &packet);
		if (ret < 0)
		{
			printf("Error:decode video frame failed.\n");
			return -1;
		}
		if (got_frame)
		{
			printf("Decode 1 frame OK.\n");
			av_image_copy(video_dst_data, video_dst_linesize, (const uint8_t**)frame->data, frame->linesize, pix_fmt, frame_width,frame_height);
			fwrite(video_dst_data[0],1, video_dst_bufsize, pOutputVideo);
		}
	}
	else if (packet.stream_index == audioStream->index)
	{
		//读packet属于音频流
		ret = avcodec_decode_audio4(audioDecCtx, frame, &got_frame, &packet);
		if (ret < 0)
		{
			printf("Error:decode audio frame failed.\n");
			return -1;
		}
		if (got_frame)
		{
			size_t unpadded_linesize = frame->nb_samples*av_get_bytes_per_sample(AVSampleFormat(frame->format));
			fwrite(frame->extended_data[0], 1, unpadded_linesize ,pOutputAudio);
		}
	}
	return FFMIN(ret, packet.size);
}
int main(int argc, char **argv)
{
	int ret = 0;
	src_filename = argv[1];//test.mp4
	video_dst_filename = argv[2];//out.yuv
	audio_dst_filename = argv[3];//out.acc
	//注册编解码器,解复用器
	av_register_all();
	if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0)
	{
		printf("Error:avformat open input failed.\n");
		return -1;
	}
	if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
	{
		printf("Error:avformat_find_stream_info failed.\n");
		return -1;
	}
	//打开音视频流
	if (open_codec_context(AVMEDIA_TYPE_VIDEO) >= 0)
	{
		videoStream = st;
		videoDecCtx = dec_ctx;
		frame_width = videoDecCtx->width;
		frame_height = videoDecCtx->height;
		pix_fmt = videoDecCtx->pix_fmt;
		//分配像素空间
		ret = av_image_alloc(video_dst_data, video_dst_linesize, frame_width, frame_height, pix_fmt, 1);
		if (ret < 0)
		{
			printf("Error:Raw video buffer alloc failed.\n");
			return -1;
		}
		else
		{
			video_dst_bufsize = ret;
		}
		fopen_s(&pOutputVideo,video_dst_filename, "wb+");
		if (!pOutputVideo)
		{
			printf("Error:Open output yuv file failed.\n");
			return -1;
		}
	}
	if (open_codec_context(AVMEDIA_TYPE_AUDIO) >= 0)
	{
		audioStream = st;
		audioDecCtx = dec_ctx;
		fopen_s(&pOutputAudio, audio_dst_filename, "wb+");
		if (!pOutputAudio)
		{
			printf("Error:Open output aac file failed.\n");
			return -1;
		}
		
	}
	//打印文件的格式信息
	av_dump_format(fmt_ctx, 0, src_filename, 0);
	//读取和处理音视频数据
	frame = av_frame_alloc();
	if (!frame)
	{
		printf("Error:alloc AVFrame failed.\n");
		return -1;
	}
	av_init_packet(&packet);
	packet.data = NULL;
	packet.size = 0;
	int got_frame = 0;
	while (av_read_frame(fmt_ctx, &packet) >= 0)
	{
		do
		{
			ret = decode_packet(got_frame);
			packet.data += ret;
			packet.size -= ret;
		} while (packet.size > 0);
	}
	//解码缓存里的残留的数据
	packet.data = NULL;
	packet.size = 0;
	do
	{
		ret = decode_packet(got_frame);
		packet.data += ret;
		packet.size -= ret;
	} while (got_frame);
	//收尾工作
	avcodec_close(videoDecCtx);
	avcodec_close(audioDecCtx);
	avformat_close_input(&fmt_ctx);
	av_frame_free(&frame);
	av_free(video_dst_data[0]);
	fclose(pOutputAudio);
	fclose(pOutputVideo);

	return 0;
}


你可能感兴趣的:(FFmpeg)