ffmpeg源码学习-1、音频解码编码,视频解码编码四个试例程序

本文详细介绍了如何使用FFmpeg库进行音频解码、编码以及视频解码和编码的实际操作。通过示例代码展示了从mp3文件解码为pcm,将pcm编码为mp3,以及将h264解码为yuv和将yuv编码为h264的过程。涉及到的关键技术包括AVCodecParserContext、AVCodecContext、AVPacket和AVFrame等FFmpeg核心组件的使用。
摘要由CSDN通过智能技术生成

笔记参考借鉴于ffmpeg源码中的

1、音频解码 Decode_audio

将mp3文件解码出原始的pcm文件,最后由Audacity工具根据对应音频参数打开播放
新学习一个API介绍一下

/**
 * Parse a packet.
 *
 * @param s             parser context.	//解析一个数据包,将数据封装到av包里面,便于解码.
 * @param avctx         codec context.//编码器上下文
 * @param poutbuf       set to pointer to parsed buffer or NULL if not yet finished.//设置为指向解析缓冲区的指针
 * @param poutbuf_size  set to size of parsed buffer or zero if not yet finished.//设置为指向解析缓冲区的大小
 * @param buf           input buffer.//输入数据
 //没有填充的缓冲区大小(以字节为单位)。即整个缓冲区的大小被假定为buf_size+ AV_INPUT_BUFFER_PADDING_SIZE。信号的EOF,这应该是0(以便最后一帧
可以输出)。
 * @param buf_size      buffer size in bytes without the padding. I.e. the full buffer
                        size is assumed to be buf_size + AV_INPUT_BUFFER_PADDING_SIZE.
                        To signal EOF, this should be 0 (so that the last frame
                        can be output).
//可以使用#define AV_NOPTS_VALUE          ((int64_t)UINT64_C(0x8000000000000000)) 通常由deuxer报告,工作在不提供pts或dts的容器上。
 * @param pts           input presentation timestamp.//输入显示时间戳  
 * @param dts           input decoding timestamp.
 * @param pos           input byte position in stream.
 * @return the number of bytes of the input bitstream used.	//所使用的输入比特流的字节数
 *
 * Example:
 * @code
 *   while(in_len){
 *       len = av_parser_parse2(myparser, AVCodecContext, &data, &size,
 *                                        in_data, in_len,
 *                                        pts, dts, pos);
 *       in_data += len;
 *       in_len  -= len;
 *
 *       if(size)
 *          decode_frame(data, size);
 *   }
 * @endcode
 */
int av_parser_parse2(AVCodecParserContext *s,
                     AVCodecContext *avctx,
                     uint8_t **poutbuf, int *poutbuf_size,
                     const uint8_t *buf, int buf_size,
                     int64_t pts, int64_t dts,
                     int64_t pos);

在这里插入图片描述

#include <iostream>
#include <thread>
using namespace std;

/*
文件解封装测试
*/
#ifdef __cplusplus
extern "C"
{
#endif // !__cplusplus
#include "libavutil/opt.h"
#include <libavutil/imgutils.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include "libswresample/swresample.h"//包含头文件
#include <libavutil/imgutils.h>
#include <libavutil/time.h>
#ifdef __cplusplus
}
#endif // !__cplusplus
#pragma comment(lib,"avformat.lib")//添加库文件,也可以在属性处添加
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"swresample.lib")
#pragma comment(lib,"swscale.lib")
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096

static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame,FILE *outfile)
{
	int i, ch;
	int ret, data_size;

	/* send the packet with the compressed data to the decoder
		发送包数据到解码器
		*/
	ret = avcodec_send_packet(dec_ctx, pkt);
	if (ret < 0) {
		fprintf(stderr, "Error submitting the packet to the decoder\n");
		exit(1);
	}

	/* read all the output frames (in general there may be any number of them 
		从解码器接收解码好的帧数据
	*/
	while (ret >= 0) {
		ret = avcodec_receive_frame(dec_ctx, frame);
		if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
			return;
		else if (ret < 0) {
			fprintf(stderr, "Error during decoding\n");
			exit(1);
		}
		//返回每个采用点单通道的字节大小
		data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
		if (data_size < 0) {
			/* This should not occur, checking just for paranoia */
			fprintf(stderr, "Failed to calculate data size\n");
			exit(1);
		}
		//一个采样点中有多个通道 每个通道有data_size个字节
		for (i = 0; i < frame->nb_samples; i++)
			for (ch = 0; ch < dec_ctx->channels; ch++)
				fwrite(frame->data[ch] + data_size*i, 1, data_size, outfile);
	}
}

int main()
{
	const char *outfilename, *filename;
	const AVCodec *codec;
	AVCodecContext *c = NULL;
	AVCodecParserContext *parser = NULL;
	int len, ret;
	FILE *f, *outfile;
	uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
	uint8_t *data;
	size_t   data_size;
	AVPacket *pkt;
	AVFrame *decoded_frame = NULL;

	filename = "OpenCV-day-019.mp3";
	outfilename = "OpenCV-day-019.pcm";

	pkt = av_packet_alloc();

	//指定解码器
	/* find the MPEG audio decoder */
	codec = avcodec_find_decoder(AV_CODEC_ID_MP2);
	if (!codec) {
		fprintf(stderr, "Codec not found\n");
		exit(1);
	}

	//AVCodecParserContext 决定了码流该以怎样的标准进行解析;
	parser = av_parser_init(codec->id);
	if (!parser) {
		fprintf(stderr, "Parser not found\n");
		exit(1);
	}

	//获取解码器上下文
	c = avcodec_alloc_context3(codec);
	if (!c) {
		fprintf(stderr, "Could not allocate audio codec context\n");
		exit(1);
	}

	/* open it */
	if (avcodec_open2(c, codec, NULL) < 0) {
		fprintf(stderr, "Could not open codec\n");
		exit(1);
	}

	f = fopen(filename, "rb");
	if (!f) {
		fprintf(stderr, "Could not open %s\n", filename);
		exit(1);
	}
	outfile = fopen(outfilename, "wb");
	if (!outfile) {
		av_free(c);
		exit(1);
	}

	/* decode until eof */
	data = inbuf;
	data_size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);

	while (data_size > 0) {
		if (!decoded_frame) {
			if (!(decoded_frame = av_frame_alloc())) {
				fprintf(stderr, "Could not allocate audio frame\n");
				exit(1);
			}
		}

		/*
			函数作用就是解析一个数据包,将数据封装到av包里面,便于解码.
			返回值为 所使用的输入比特流的字节数
		*/
		ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
			data, data_size,
			AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
		if (ret < 0) {
			fprintf(stderr, "Error while parsing\n");
			exit(1);
		}

		//指针移动,大小变化
		data += ret;
		data_size -= ret;

		//将解析好的数据包进行编码
		if (pkt->size)
			decode(c, pkt, decoded_frame, outfile);

		if (data_size < AUDIO_REFILL_THRESH) {
			memmove(inbuf, data, data_size);
			data = inbuf;
			len = fread(data + data_size, 1,
				AUDIO_INBUF_SIZE - data_size, f);
			if (len > 0)
				data_size += len;
		}
	}

	/* flush the decoder 
		编码一个空的将缓冲中的数据进行编码
	*/ 
	pkt->data = NULL;
	pkt->size = 0;
	decode(c, pkt, decoded_frame, outfile);

	fclose(outfile);
	fclose(f);

	avcodec_free_context(&c);
	av_parser_close(parser);
	av_frame_free(&decoded_frame);
	av_packet_free(&pkt);

	return 0;
}

2、音频编码 Encode_audio

将原始数pcm文件编码成mp3,可直接双击播放的
在这里插入图片描述

#include <iostream>
#include <thread>
using namespace std;

/*
文件解封装测试
*/
#ifdef __cplusplus
extern "C"
{
#endif // !__cplusplus
#include "libavutil/opt.h"
#include <libavutil/imgutils.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include "libswresample/swresample.h"//包含头文件
#include <libavutil/imgutils.h>
#include <libavutil/time.h>
#ifdef __cplusplus
}
#endif // !__cplusplus
#pragma comment(lib,"avformat.lib")//添加库文件,也可以在属性处添加
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"swresample.lib")
#pragma comment(lib,"swscale.lib")

int main()
{
	AVFormatContext* pFormatCtx;
	AVOutputFormat* fmt;
	AVStream* audio_st;
	AVCodecContext* pCodecCtx;
	AVCodec* pCodec;

	uint8_t* frame_buf;
	AVFrame* pFrame;
	AVPacket pkt;

	int got_frame = 0;
	int ret = 0;
	int size = 0;

	FILE *in_file = NULL;	                        //Raw PCM data
	int framenum = 10000;                          //Audio frame number
	const char* out_file = "test.mp3";          //Output URL
	int i;

	in_file = fopen("D:/yuv_file11.pcm", "rb");

	av_register_all();

	//Method 1.
	pFormatCtx = avformat_alloc_context();
	fmt = av_guess_format(NULL, out_file, NULL);
	pFormatCtx->oformat = fmt;

	//Method 2. 
	//avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);
	//fmt = pFormatCtx->oformat;

	//Open output URL
	if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {
		printf("Failed to open output file!\n");
		return -1;
	}

	audio_st = avformat_new_stream(pFormatCtx, 0);
	if (audio_st == NULL) {
		return -1;
	}
	pCodecCtx = audio_st->codec;
	pCodecCtx->codec_id = fmt->audio_codec;
	pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
	pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;// AV_SAMPLE_FMT_FLTP;// AV_SAMPLE_FMT_S16;
	pCodecCtx->sample_rate = 44100;// 44100; 16000
	pCodecCtx->channel_layout = av_get_default_channel_layout(1);
	pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
	pCodecCtx->bit_rate = 64000; //64000; 15000

	pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
	if (!pCodec) {
		printf("Can not find encoder!\n");
		return -1;
	}
	if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
		printf("Failed to open encoder!\n");
		return -1;
	}
	pFrame = av_frame_alloc();
	pFrame->nb_samples = pCodecCtx->frame_size;
	pFrame->format = pCodecCtx->sample_fmt;

	size = av_samples_get_buffer_size(NULL, pCodecCtx->channels, pCodecCtx->frame_size, pCodecCtx->sample_fmt, 1);
	frame_buf = (uint8_t *)av_malloc(size);
	avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt, (const uint8_t*)frame_buf, size, 1);
	//Write Header
	avformat_write_header(pFormatCtx, NULL);

	av_new_packet(&pkt, size);
	for (i = 0; ; i++) {
		//Read PCM
		if (fread(frame_buf, 1, size, in_file) <= 0) {
			printf("Failed to read raw data! \n");
			return -1;
		}
		else if (feof(in_file)) {
			break;
		}
		pFrame->data[0] = frame_buf;  //PCM Data

		pFrame->pts = i * 100;
		got_frame = 0;
		//Encode
		ret = avcodec_encode_audio2(pCodecCtx, &pkt, pFrame, &got_frame);
		if (ret < 0) {
			printf("Failed to encode!\n");
			return -1;
		}
		if (got_frame == 1) {
			printf("Succeed to encode 1 frame! \tsize:%5d\n", pkt.size);
			pkt.stream_index = audio_st->index;
			ret = av_write_frame(pFormatCtx, &pkt);
			av_free_packet(&pkt);
		}
	}

	Flush Encoder
	//ret = flush_encoder(pFormatCtx, 0);
	//if (ret < 0) {
	//	printf("Flushing encoder failed\n");
	//	return -1;
	//}

	//Write Trailer
	av_write_trailer(pFormatCtx);

	//Clean
	if (audio_st) {
		avcodec_close(audio_st->codec);
		av_free(pFrame);
		av_free(frame_buf);
	}
	avio_close(pFormatCtx->pb);
	avformat_free_context(pFormatCtx);

	fclose(in_file);
	getchar();
	return 0;
}

3、视频解码 Decode_video

将h264文件解码生成yuv文件在这里插入图片描述

#include <iostream>
#include <thread>
using namespace std;

/*
文件解封装测试
*/
#ifdef __cplusplus
extern "C"
{
#endif // !__cplusplus
#include "libavutil/opt.h"
#include <libavutil/imgutils.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include "libswresample/swresample.h"//包含头文件
#include <libavutil/imgutils.h>
#include <libavutil/time.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/frame.h>
#include <libavutil/samplefmt.h>
#ifdef __cplusplus
}
#endif // !__cplusplus
#pragma comment(lib,"avformat.lib")//添加库文件,也可以在属性处添加
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"swresample.lib")
#pragma comment(lib,"swscale.lib")

#define INBUF_SIZE 4096
/*
	将h264文件解码成一张张YUV图片
*/
static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
	char *filename)
{
	FILE *f;
	int i;

	f = fopen(filename, "w");
	fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
	for (i = 0; i < ysize; i++)
		fwrite(buf + i * wrap, 1, xsize, f);
	fclose(f);
}

static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt,
	const char *filename)
{
	char buf[1024];
	int ret;

	ret = avcodec_send_packet(dec_ctx, pkt);
	if (ret < 0) {
		fprintf(stderr, "Error sending a packet for decoding\n");
		exit(1);
	}

	while (ret >= 0) {
		ret = avcodec_receive_frame(dec_ctx, frame);
		if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
			return;
		else if (ret < 0) {
			fprintf(stderr, "Error during decoding\n");
			exit(1);
		}

		printf("saving frame %3d\n", dec_ctx->frame_number);
		fflush(stdout);

		/* the picture is allocated by the decoder. no need to
		free it */
		snprintf(buf, sizeof(buf), "%s-%d", filename, dec_ctx->frame_number);
		pgm_save(frame->data[0], frame->linesize[0],
			frame->width, frame->height, buf);
	}
}

int main(int argc, char **argv)
{
	const char *filename, *outfilename;
	const AVCodec *codec;
	AVCodecParserContext *parser;
	AVCodecContext *c = NULL;
	FILE *f;
	AVFrame *frame;
	uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
	uint8_t *data;
	size_t   data_size;
	int ret;
	AVPacket *pkt;

	filename = "ds.h264";
	outfilename = "ds.yuv";

	pkt = av_packet_alloc();
	if (!pkt)
		exit(1);

	/* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
	memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);

	/* find the MPEG-1 video decoder */
	codec = avcodec_find_decoder(AV_CODEC_ID_H264);
	if (!codec) {
		fprintf(stderr, "Codec not found\n");
		exit(1);
	}

	parser = av_parser_init(codec->id);
	if (!parser) {
		fprintf(stderr, "parser not found\n");
		exit(1);
	}

	c = avcodec_alloc_context3(codec);
	if (!c) {
		fprintf(stderr, "Could not allocate video codec context\n");
		exit(1);
	}

	/* For some codecs, such as msmpeg4 and mpeg4, width and height
	MUST be initialized there because this information is not
	available in the bitstream. */

	/* open it */
	if (avcodec_open2(c, codec, NULL) < 0) {
		fprintf(stderr, "Could not open codec\n");
		exit(1);
	}

	f = fopen(filename, "rb");
	if (!f) {
		fprintf(stderr, "Could not open %s\n", filename);
		exit(1);
	}

	frame = av_frame_alloc();
	if (!frame) {
		fprintf(stderr, "Could not allocate video frame\n");
		exit(1);
	}

	while (!feof(f)) {
		/* read raw data from the input file */
		data_size = fread(inbuf, 1, INBUF_SIZE, f);
		if (!data_size)
			break;

		/* use the parser to split the data into frames */
		data = inbuf;
		while (data_size > 0) {
			ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
				data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
			if (ret < 0) {
				fprintf(stderr, "Error while parsing\n");
				exit(1);
			}
			data += ret;
			data_size -= ret;

			if (pkt->size)
				decode(c, frame, pkt, outfilename);
		}
	}

	/* flush the decoder */
	decode(c, frame, NULL, outfilename);

	fclose(f);

	av_parser_close(parser);
	avcodec_free_context(&c);
	av_frame_free(&frame);
	av_packet_free(&pkt);

	return 0;
}

4、视频编码 Encode_video

将YUV编码生成H264文件
在这里插入图片描述

#include <iostream>
#include <thread>
using namespace std;

/*
文件解封装测试
*/
#ifdef __cplusplus
extern "C"
{
#endif // !__cplusplus
#include "libavutil/opt.h"
#include <libavutil/imgutils.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include "libswresample/swresample.h"//包含头文件
#include <libavutil/imgutils.h>
#include <libavutil/time.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/frame.h>
#include <libavutil/samplefmt.h>
#ifdef __cplusplus
}
#endif // !__cplusplus
#pragma comment(lib,"avformat.lib")//添加库文件,也可以在属性处添加
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"swresample.lib")
#pragma comment(lib,"swscale.lib")

/*
	将YUV数据编码成h264文件
*/
int main(int argc, char* argv[])
{
	AVFormatContext* pFormatCtx;
	AVOutputFormat* fmt;
	AVStream* video_st;
	AVCodecContext* pCodecCtx;
	AVCodec* pCodec;
	AVPacket* pkt;
	uint8_t* picture_buf;
	uint8_t*pFrame_buf;
	AVFrame* pFrame;
	int picture_size;
	int y_size;
	int framecnt = 0;
	int ret;
	//FILE *in_file = fopen("src01_480x272.yuv", "rb");	//Input raw YUV data 
	FILE *in_file = fopen("output240X128.yuv", "rb");   //Input raw YUV data
	if (in_file == NULL)
	{
		printf("Failed fopen file! \n");
		return -1;
	}


	int in_w = 240, in_h = 128;                              //Input data's width and height
	int framenum = 100; 
	const char* out_file = "ds.h264";

	av_register_all();
	/*
	//Method1.
	pFormatCtx = avformat_alloc_context();
	//av_guess_format在注册输出格式列表中返回与所提供的参数最匹配的输出格式,如果没有匹配则返回NULL。
	fmt = av_guess_format(NULL, out_file, NULL);//根据文件名去匹配输出格式AVOutputFormat
	pFormatCtx->oformat = fmt;
	*/

	//Method 2.
	//为输出格式分配一个AVFormatContext。
	//int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat,const char *format_name, const char *filename);
	//oformat用于分配上下文的格式,如果为NULL则用format_name、filename代替
	//format_name用于分配上下文的输出格式的名称,如果为NULL则使用filename文件名代替
	//filename用于分配上下文的文件名
	avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);
	fmt = pFormatCtx->oformat;


	//Open output URL
	//创建并初始化一个AVIOContext,用于访问url指示的资源。
	if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {
		printf("Failed to open output file! \n");
		return -1;
	}

	video_st = avformat_new_stream(pFormatCtx, 0);
	//video_st->time_base.num = 1; 
	//video_st->time_base.den = 25;  

	if (video_st == NULL) {
		return -1;
	}
	//Param that must set
	pCodecCtx = video_st->codec;
	//pCodecCtx->codec_id =AV_CODEC_ID_HEVC;
	pCodecCtx->codec_id = fmt->video_codec;
	pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
	pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
	pCodecCtx->width = in_w;
	pCodecCtx->height = in_h;
	pCodecCtx->bit_rate = 400000;
	pCodecCtx->gop_size = 250;

	pCodecCtx->time_base.num = 1;
	pCodecCtx->time_base.den = 25;

	//H264
	//pCodecCtx->me_range = 16;
	//pCodecCtx->max_qdiff = 4;
	//pCodecCtx->qcompress = 0.6;
	pCodecCtx->qmin = 10;
	pCodecCtx->qmax = 51;

	//Optional Param
	pCodecCtx->max_b_frames = 3;

	// Set Option
	AVDictionary *param = 0;
	//H.264
	if (pCodecCtx->codec_id == AV_CODEC_ID_H264) {
		av_dict_set(&param, "preset", "slow", 0);
		av_dict_set(&param, "tune", "zerolatency", 0);
		//av_dict_set(param, "profile", "main", 0);
	}
	//H.265
	if (pCodecCtx->codec_id == AV_CODEC_ID_H265) {
		av_dict_set(&param, "preset", "ultrafast", 0);
		av_dict_set(&param, "tune", "zero-latency", 0);
	}

	//Show some Information
	av_dump_format(pFormatCtx, 0, out_file, 1);

	//查找具有匹配编解码器ID的已注册编码器。
	pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
	if (!pCodec) {
		printf("Can not find encoder! \n");
		return -1;
	}
	if (avcodec_open2(pCodecCtx, pCodec, &param) < 0) {
		printf("Failed to open encoder! \n");
		return -1;
	}


	//存储一帧像素数据缓冲区
	pFrame = av_frame_alloc();
	picture_size = av_image_get_buffer_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 1);
	picture_buf = (uint8_t *)av_malloc(picture_size);
	pFrame_buf = (uint8_t *)av_malloc(picture_size);
	//av_image_fill_arrays((AVPicture *)pFrame, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);//淘汰了
	av_image_fill_arrays(pFrame->data, pFrame->linesize, pFrame_buf, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
	pFrame->width = pCodecCtx->width;
	pFrame->height = pCodecCtx->height;
	pFrame->format = pCodecCtx->pix_fmt;
	/*ret = av_frame_get_buffer(pFrame, picture_size);
	if (ret < 0) {
	fprintf(stderr, "Could not allocate the video frame data\n");
	exit(1);
	}*/
	//Write File Header
	avformat_write_header(pFormatCtx, NULL);
	pkt = av_packet_alloc();
	//av_new_packet(&pkt, picture_size);

	y_size = pCodecCtx->width * pCodecCtx->height;

	for (int i = 0; i<framenum; i++)
	{
		fflush(stdout);
		/*ret = av_frame_make_writable(pFrame);
		if (ret < 0) {
		printf("Failed to av_frame_make_writable! \n");
		getchar();
		return -1;
		}*/
		//Read raw YUV data   一个像素YUV420  4 1 1   4个像素6个字节表示,一个像素1.5个字节
		if (fread(picture_buf, 1, y_size * 3 / 2, in_file) <= 0) {
			printf("Failed to read raw data! \n");
			getchar();
			return -1;
		}
		else if (feof(in_file)) {
			break;
		}
		pFrame->data[0] = picture_buf;              // Y
		pFrame->data[1] = picture_buf + y_size;      // U 
		pFrame->data[2] = picture_buf + y_size * 5 / 4;  // V  y_size+y_size/4个位置的U
		pFrame->pts = i*(video_st->time_base.den) / ((video_st->time_base.num) * 25);
		int got_picture = 0;
		//成功
		//Encode
		int ret = avcodec_encode_video2(pCodecCtx, pkt, pFrame, &got_picture);
		if (ret < 0) {
			printf("Failed to encode! \n");
			return -1;
		}
		if (got_picture == 1) {
			printf("Succeed to encode frame: %5d\tsize:%5d\n", framecnt, pkt->size);
			framecnt++;
			pkt->stream_index = video_st->index;
			ret = av_write_frame(pFormatCtx, pkt);
			av_free_packet(pkt);
		}
		/*  失败 avcodec_receive_packet总是返回EAGAIN导致没有包出来
		//Encode
		ret = avcodec_send_frame(pCodecCtx, pFrame);
		if (ret < 0) {
		printf("Failed to encode! \n");
		getchar();
		return -1;
		}
		while (ret >= 0) {
		ret = avcodec_receive_packet(pCodecCtx, pkt);
		if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
		{
		av_free_packet(pkt);
		break;
		}
		else if (ret < 0) {
		fprintf(stderr, "Error during encoding\n");
		exit(1);
		}
		if (ret == 1) {
		printf("Succeed to encode frame: %5d\tsize:%5d\n", framecnt, pkt->size);
		framecnt++;
		pkt->stream_index = video_st->index;
		ret = av_write_frame(pFormatCtx, pkt);
		av_free_packet(pkt);
		}
		}
		*/
	}
	//Flush Encoder
	/*ret = flush_encoder_Video(pFormatCtx, 0);
	if (ret < 0) {
	printf("Flushing encoder failed\n");
	getchar();
	return -1;
	}*/

	//Write file trailer
	av_write_trailer(pFormatCtx);

	//Clean
	if (video_st) {
		avcodec_close(video_st->codec);
		av_free(pFrame);
		av_free(picture_buf);
	}
	avio_close(pFormatCtx->pb);
	avformat_free_context(pFormatCtx);

	//fclose(in_file);

	getchar();

	return 0;
}

代码工程链接:后续上传git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值