第二章 利用ffmpeg把rgb转mp4

本文章介绍ffmpeg基本使用流程

1. 创建编码器

//通过枚举id选择编码器类型

AVCodec *avcodec_find_encoder(enum AVCodecID id);

enum AVCodecID id                --通过枚举选择编码器类型  AV_CODEC_ID_H264

//通过文件名称后缀选择编码器类型

AVCodec *avcodec_find_encoder_by_name(const char *name);

const char *name                    --文件名称  "1.mp4"

AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
	cout << " avcodec_find_encoder AV_CODEC_ID_H264 failed!" << endl;
	return -1;
}

2. 创建编码上下文

AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);

const AVCodec *codec                --上面创建的编码器

AVCodecContext *c = avcodec_alloc_context3(codec);
if (!c)
{
	cout << " avcodec_alloc_context3  failed!" << endl;
	return -1;
}

c->bit_rate = 400000000;//压缩比特率 视频压缩比例
c->width = width;			//视频宽度
c->height = height;			//视频高度
c->time_base = { 1, fps };	//时间基准 基本不用
c->framerate = { fps, 1 };	//帧率
c->gop_size = 50;           //画面组大小,关键帧
c->max_b_frames = 0;		//B帧 同等比特率下B帧越多压缩率越高画面越清晰
c->pix_fmt = AV_PIX_FMT_YUV420P;	//像素格式
c->codec_id = AV_CODEC_ID_H264;		//解码器id
c->thread_count = 8;                //开的线程数量

//全局的编码信息
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

3. 打开编码器

int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, 
                        AVDictionary **options);

AVCodecContext *avctx                        --编码器上下文

const AVCodec *codec                          --编码格式

AVDictionary **options                          --NULL

4. 创建输出的上下文

avformat_alloc_output_context2                --详见第一章

5. 创建视频流信息

avformat_new_stream                                --详见第一章

6. 根据提供的编解码器中的值填充参数结构

int avcodec_parameters_from_context(AVCodecParameters *par,
                                        const AVCodecContext *codec);    

AVCodecParameters *par       --par中的任何分配字段都将被释放并替换为重复字段

const AVCodecContext *codec       --编解码器中相应字段

AVFormatContext *oc = NULL;
avformat_alloc_output_context2(&oc, 0, 0, outfile);  //创建上下文

AVStream *st = avformat_new_stream(oc, NULL);        //创建视频流信息
//st->codec = c;
st->id = 0;
st->codecpar->codec_tag = 0;

//将编码上下文c的参数信息赋值分配给st->codecpar(存到视频流里面 封装文件头部)
avcodec_parameters_from_context(st->codecpar, c);

cout << "===============================================" << endl;
av_dump_format(oc, 0, outfile, 1);        //打印编码器信息
cout << "===============================================" << endl;

7. 视频格式转换

struct SwsContext *sws_getCachedContext(struct SwsContext *context,
                                        int srcW, int srcH, enum AVPixelFormat srcFormat,
                                        int dstW, int dstH, enum AVPixelFormat dstFormat,
                                        int flags, SwsFilter *srcFilter,
                                        SwsFilter *dstFilter, const double *param);
 

struct SwsContext *context                                        --上下文

int srcW, int srcH, enum AVPixelFormat srcFormat   --输入宽度,输入高度,输入格式

int dstW, int dstH, enum AVPixelFormat dstFormat   --输出宽度,输出高度,输出格式

int flags                                                                      --选择算法

SwsFilter *srcFilter,SwsFilter *dstFilter                   --视频过滤器

const double *param                                                  --默认参数

8. 分配输入空间和输出空间

//输入空间
unsigned char *rgb = new unsigned char[width*height * 4];

//输出的空间
AVFrame *yuv = av_frame_alloc();	//存放编码前没有经过压缩的原始数据
yuv->format = AV_PIX_FMT_YUV420P;	//像素输出格式
yuv->width = width;
yuv->height = height;
ret = av_frame_get_buffer(yuv, 32);//空间分配   32-》对齐方式
if (ret < 0)
{
	cout << " av_frame_get_buffer  failed!" << endl;
	return -1;
}

9. 写入mp4头部

avformat_write_header                        --详见第一章

10. 

int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
                          const int srcStride[], int srcSliceY, int srcSliceH,
                          uint8_t *const dst[], const int dstStride[]);

struct SwsContext *c                        --上下文

const uint8_t *const srcSlice[]          --

const int srcStride[],

int srcSliceY, int srcSliceH                --深度值,高度

 uint8_t *const dst[]                        --输出

const int dstStride[]

11. 

//5 wirte mp4 head
ret = avio_open(&oc->pb, outfile, AVIO_FLAG_WRITE);		//打开视频文件
if (ret < 0)
{
	cout << " avio_open  failed!" << endl;
	getchar();
	return -1;
}
ret = avformat_write_header(oc, NULL);		//写入视频文件头部
if (ret < 0)
{
	cout << " avformat_write_header  failed!" << endl;
	getchar();
	return -1;
}
int p = 0;
for (;;)
{
	int len = fread(rgb, 1, width*height * 4, fp);
	if (len <= 0)
	{
		break;
	}
	uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
	indata[0] = rgb;
	int inlinesize[AV_NUM_DATA_POINTERS] = { 0 };
	inlinesize[0] = width * 4;

	int h = sws_scale(ctx, indata, inlinesize, 0, height,
		yuv->data, yuv->linesize
		);
	if (h <= 0)
		break;

	//6 encode frame  编码
	yuv->pts = p;
	//yuv->pict_type = AV_PICTURE_TYPE_I;	//指定该帧为关键帧
	p = p + 3600;
	ret = avcodec_send_frame(c, yuv);
	if (ret != 0)
	{
		continue;
	}
	AVPacket pkt;		//存放已编码的数据
	av_init_packet(&pkt);
	ret = avcodec_receive_packet(c, &pkt);
	if (ret != 0)
		continue;

	//av_write_frame(oc, &pkt);
	//av_packet_unref(&pkt);	//清理pkt
	av_interleaved_write_frame(oc, &pkt);	//等价上面两步

	cout << "<"<<pkt.size<<">";
}

//写入视频索引(尾部)
av_write_trailer(oc);

//关闭视频输出io
avio_close(oc->pb);

//清理封装输出上下文
avformat_free_context(oc);

//关闭编码器
avcodec_close(c);

//清理编码器上下文
avcodec_free_context(&c);

//清理视频重采样上下文
sws_freeContext(ctx);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值