【FFMPEG应用篇】基于FFmpeg的RGB格式封装MOV文件

/*
*   一笑奈何
*   cn-yixiaonaihe.blog.csdn.net
*/

#include <iostream>
#include <thread>
extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
}
using namespace std;
static double r2d(AVRational r)
{
	return r.den == 0 ? 0 : (double)r.num / (double)r.den;
}
void XSleep(int ms)
{
	//c++ 11
	chrono::milliseconds du(ms);
	this_thread::sleep_for(du);
}
int main(int argc, char *argv[])
{
	cout << "Test Demux FFmpeg.club" << endl;
	const char *url = "test.rgb";
	const char *outfile = "test.mov";
	//初始化封装库
	av_register_all();

	//初始化网络库 (可以打开rtsp rtmp http 协议的流媒体视频)
	avformat_network_init();

	//注册解码器
	avcodec_register_all();

	FILE *fp = fopen(url,"rb");

	int width = 1920;
	int height = 1080;
	int fps = 25;

	static int i = 0;
	char errorbuf[1024];

	if (!fp)
	{
		cout << "open FILE failed!" << endl;
		fclose(fp);
		return -1;
	}
		


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

	AVCodecContext *c = avcodec_alloc_context3(codec);
	if (!c)
	{
		cout << "avcodec_alloc_context3 No" << 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;
	c->pix_fmt = AV_PIX_FMT_YUV420P;
	c->codec_id = AV_CODEC_ID_H264;
	c->thread_count = 8;
	//全局编码
	c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

	int ret = avcodec_open2(c, codec, 0);
	if (ret < 0)
	{
		cout << "avcodec_open2 No" << endl;
		return -1;
	}

	cout << "avcodec_open2 OK" << endl;

	//2 create out context
	AVFormatContext *oc = nullptr;
	avformat_alloc_output_context2(&oc, 0, 0, outfile);

	//3 add video stream
	AVStream *st = avformat_new_stream(oc, NULL);
	//st->codec = c;
	st->id = 0;
	st->codecpar->codec_tag = 0;
	avcodec_parameters_from_context(st->codecpar,c);

	cout << "========================" << endl;
	av_dump_format(oc, 0, outfile, 1);
	cout << "========================" << endl;

	//4 rgb to yuv
	SwsContext *ctx = NULL;
	ctx = sws_getCachedContext(ctx,
		width, height, AV_PIX_FMT_BGRA,
		width, height, AV_PIX_FMT_YUV420P,
		SWS_BICUBIC,NULL,NULL,NULL);

	//输入的空间
	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);
	if (ret < 0)
	{
		cout << "av_frame_get_buffer No" << endl;
		return -1;
	}


	//5 wirte mp4 head
	//写入文件头信息
	ret = avio_open(&oc->pb, outfile, AVIO_FLAG_WRITE);//打开输出文件IO
	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();
	}

	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;//*4字节数

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

		//6 encode frame
		yuv->pts = p;
		p = p + 3600;
		//yuv->pict_type = AV_PICTURE_TYPE_I;
		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)
		{
			av_strerror(ret, errorbuf, sizeof(errorbuf));
			cout << "avcodec_receive_packet  NO ->" << errorbuf << " "<<ret<<endl;
			cout << " Number :" << i << " "<<ret<<endl;
			i++;
			continue;
		}

		//av_write_frame(oc, &pkt);
		//av_packet_unref(&pkt);

		av_interleaved_write_frame(oc, &pkt);

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

	}
	

	//写入视频索引尾部信息
	av_write_trailer(oc);
	//主动关闭后才可以把缓冲区的内容写到文件
	avio_close(oc->pb);
	//清理封装输出上下文
	avformat_free_context(oc);
	//关闭编码器
	avcodec_close(c);
	//清理编码器上下文
	avcodec_free_context(&c);
	//清理视频重采样上下文
	sws_freeContext(ctx);
	delete rgb;
	fclose(fp);
	cout << "==================end===============" << endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

༄yi笑奈何

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值