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

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

/*
文件解封装测试
*/
#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,可直接双击播放的  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/4d4714e9d4ca4444a3b89b1515ece2a5.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAencxOTk2,size_20,color_FFFFFF,t_70,g_se,x_16)



#include
#include
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文件![在这里插入图片描述](https://img-blog.csdnimg.cn/e136e5631a1444d7bc81694d0fb2b6c3.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAencxOTk2,size_20,color_FFFFFF,t_70,g_se,x_16)



#include
#include
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;

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

kt, 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;

[外链图片转存中…(img-36tr1qHW-1715745418453)]
[外链图片转存中…(img-2eQq3HwP-1715745418454)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值