ffmpeg将mp4解封装为yuv以及pcm测试代码2

#include <stdio.h>
#include <stdint.h>
#include <conio.h>

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

#define errReport(info, val) do{ \
	fprintf(stderr, "ERR(func=%s,line=%d): %s code=%d\n",__FUNCTION__, __LINE__, info, val);\
	getch();\
	exit(0);\
}while (0);

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

FILE *pOutputAudio = NULL;
FILE *pOutputVideo = NULL;

AVStream *st = NULL;
AVCodec *dec = NULL;
AVCodecContext *dec_ctx = NULL;
AVFormatContext *fmt_ctx = NULL;

AVStream *videoStream = NULL, *audioStream = NULL;
AVCodecContext *videoDecCtx = NULL, *audioDecCtx = NULL;

int frame_width = 0, frame_height = 0;
enum AVPixelFormat pix_fmt;

unsigned char *video_dst_data[4];
int video_dst_linesize[4];
int video_dst_bufsize;

AVFrame *frame = NULL;
AVPacket packet;

int decode_packet(int *got_frame) {
	int ret = 0;
	*got_frame = 0;
	if (packet.stream_index == videoStream->index) {
		ret = avcodec_decode_video2(videoDecCtx, frame, got_frame, &packet);
		if (ret < 0)	return -1;
		if (*got_frame) {
			printf("Decode 1 frame.\n");
			/* copy decoded frame to destination buffer:
			* this is required since rawvideo expects non aligned data */
			av_image_copy(video_dst_data, video_dst_linesize, (const unsigned char **)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) {
		ret = avcodec_decode_audio4(audioDecCtx, frame, got_frame, &packet);
		if (ret < 0)	return -2;
		if (*got_frame) {
			/*av_get_bytes_per_sample((enum AVSampleFormat)frame->format)返回的是采样位数16bits or 8 bits,
			此函数进行了右移操作,即除以8来获得字节数nb_samples指每个声道每一帧所包含的采样个数*/
			size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample((enum AVSampleFormat)frame->format);
			fwrite(frame->extended_data[0], 1, unpadded_linesize, pOutputAudio);
		}
	}
	return FFMIN(ret, packet.size);
}

int open_codec_context(enum AVMediaType type) {
	int ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
	if (ret < 0)	return -1;

	st = fmt_ctx->streams[ret];
	dec_ctx = st->codec;
	dec = avcodec_find_decoder(dec_ctx->codec_id);
	if (!dec)	return -2;

	ret = avcodec_open2(dec_ctx, dec, NULL);
	if (ret < 0)	return -3;
	return 0;
}

int main(int argc, char **argv) {
	int ret, got_frame = 0;
	src_filename = "test.mp4";
	video_dst_filename = "out1.yuv";
	audio_dst_filename = "out1.pcm";

	av_register_all();
	if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0)
		errReport("avformat_open_input", -1);

	if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
		errReport("avformat_find_stream_info", -1);

	if ((ret = open_codec_context(AVMEDIA_TYPE_VIDEO)) < 0)
		errReport("open_codec_context:VIDEO", ret);
	
	videoStream = st;
	videoDecCtx = dec_ctx;
	frame_width = videoDecCtx->width;
	frame_height = videoDecCtx->height;
	pix_fmt = videoDecCtx->pix_fmt;

	/*分配像素的存储空间该函数的四个参数分别表示AVFrame结构中的缓存指针、各个颜色分量的宽度、
	图像分辨率(宽、高)、像素格式和内存对其的大小。该函数会返回分配的内存的大小。
	其实就是对video_dst_data,video_dst_linesize内存进行分配*/
	ret = av_image_alloc(video_dst_data, video_dst_linesize, frame_width, frame_height, pix_fmt, 1);
	if (ret < 0)	errReport("av_image_alloc", ret);

	video_dst_bufsize = ret;
	printf("av image alloc size:%d\n", video_dst_bufsize);
	if (!(pOutputVideo = fopen(video_dst_filename, "wb")))
		errReport("fopen:video_dst_filename", -1);

	if ((ret = open_codec_context(AVMEDIA_TYPE_AUDIO)) < 0) 
		errReport("open_codec_context:AUDIO", ret);
	
	audioStream = st;
	audioDecCtx = dec_ctx;
	if (!(pOutputAudio = fopen(audio_dst_filename, "wb")))
		errReport("fopen:audio_dst_filename", -1);
	
	av_dump_format(fmt_ctx, 0, src_filename, 0);
	frame = av_frame_alloc();
	if (!frame)  errReport("av_frame_alloc", -1);

	av_init_packet(&packet);
	packet.data = NULL;
	packet.size = 0;
	while (av_read_frame(fmt_ctx, &packet) >= 0){
		do{
			ret = decode_packet(&got_frame);
			printf("decode packet size:%d\n", ret);
			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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值