• FFmpeg RGB转H264


    前言

    下面代码是在我的上一篇博客:FFmpeg RGB转YUV 的代码的基础上修改而来的,创建了编码器并进行 H264 编码,进一步将 RGB 格式像素数据转换成 H264 格式像素数据,亲测有效。


    完整代码

    #include <iostream>
    
    extern "C"
    {
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
    }
    
    #pragma comment(lib,"avformat.lib")
    #pragma comment(lib,"avcodec.lib")
    #pragma comment(lib,"avutil.lib")
    #pragma comment(lib,"swscale.lib")
    
    using namespace std;
    
    int main()
    {
    	char infile[] = "dove_BGRA.rgb";
    	char outfile[] = "out.264";
    
    	// 源图像参数
    	int width = 640;
    	int height = 360;
    	int fps = 25;
    
    	//1 打开RGB和H264文件
    	FILE *fpin = fopen(infile, "rb");
    	if (!fpin)
    	{
    		cout << infile << "open infile failed!" << endl;
    		getchar();
    		return -1;
    	}
    
    	FILE *fpout = fopen(outfile, "wb");
    	if (!fpout)
    	{
    		cout << "open outfile failed!" << endl;
    		exit(1);
    	}
    	// 创建RGB缓冲区同时分配内存
    	unsigned char *rgbBuf = new unsigned char[width*height * 4];
    
    	// 注册所有和编解码器有关的组件
    	av_register_all();
    
    	/* 2 创建编码器 */
    	// 查找编码器
    	AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    	if (!codec)
    	{
    		cout << "avcodec_find_encoder AV_CODEC_ID_H264 failed!" << endl;
    		getchar();
    		return -1;
    	}
    
    	// 给编码器分配内存,返回对应编码器上下文
    	AVCodecContext *codecCtx = avcodec_alloc_context3(codec);
    	if (!codecCtx)
    	{
    		cout << "avcodec_alloc_context3  failed!" << endl;
    		getchar();
    		return -1;
    	}
    	// 配置编码器上下文的成员
    	codecCtx->width = width; // 设置编码视频宽度 
    	codecCtx->height = height; // 设置编码视频高度
    	codecCtx->time_base.num = 1;
    	codecCtx->time_base.den = 25; // 设置帧率,num为分子,den为分母,如果是1/25则表示25帧/s
    	codecCtx->pix_fmt = AV_PIX_FMT_YUV420P; // 设置输出像素格式
    
    	// 打开编码器
    	int ret = avcodec_open2(codecCtx, codec, NULL);
    	if (ret < 0)
    	{
    		cout << "avcodec_open2  failed!" << endl;
    		getchar();
    		return -1;
    	}
    	cout << "avcodec_open2 success!" << endl;
    
    	// 3 创建视频重采样上下文:指定源和目标图像分辨率、格式
    	SwsContext *swsCtx = NULL;
    	swsCtx = sws_getCachedContext(swsCtx,
    		width, height, AV_PIX_FMT_BGRA,
    		width, height, AV_PIX_FMT_YUV420P,
    		SWS_BICUBIC,
    		NULL, NULL, NULL
    		);
    
    	//4 创建YUV视频帧并配置
    	AVFrame *yuvFrame = av_frame_alloc();
    	yuvFrame->format = AV_PIX_FMT_YUV420P;
    	yuvFrame->width = width;
    	yuvFrame->height = height;
    	ret = av_frame_get_buffer(yuvFrame, 32);
    	if (ret < 0)
    	{
    		cout << "av_frame_get_buffer  failed!" << endl;
    		getchar();
    		return -1;
    	}
    
    	// 循环写视频文件
    	int pts = 0;
    	int count = 0;
    	for (;;)
    	{
    		//5 每次读取一帧RGB数据到rgbBuf,读取完毕则退出
    		int len = fread(rgbBuf, 1, width*height * 4, fpin);
    		if (len <= 0)
    		{
    			break;
    		}
    
    		//5 创建RGB视频帧并绑定RGB缓冲区(avpicture_fill是给rgbFrame初始化一些字段,并且会自动填充data和linesize)
    		AVFrame *rgbFrame = av_frame_alloc();
    		avpicture_fill((AVPicture *)rgbFrame, rgbBuf, AV_PIX_FMT_BGRA, width, height);
    
    		//7 像素格式转换,转换后的YUV数据存放在yuvFrame
    		int outSliceH = sws_scale(swsCtx, rgbFrame->data, rgbFrame->linesize, 0, height,
    			yuvFrame->data, yuvFrame->linesize
    			);
    		if (outSliceH <= 0)
    			break;
    
    		/* 8 H264编码 */
    		// 将未压缩的AVFrame数据(yuv)给编码器
    		yuvFrame->pts = count++ * (codecCtx->time_base.num * 1000 / codecCtx->time_base.den);
    		ret = avcodec_send_frame(codecCtx, yuvFrame);
    		if (ret != 0)
    		{
    			continue;
    		}
    		// 将编码数据保存在AVPacket
    		AVPacket pkt;
    		av_init_packet(&pkt);
    		ret = avcodec_receive_packet(codecCtx, &pkt);
    		if (ret != 0)
    			continue;
    
    		//9 写入H264文件
    		fwrite(pkt.data, 1, pkt.size, fpout);
    		//av_packet_unref(&pkt);
    
    		cout << "<" << pkt.size << ">";
    	}
    
    	// 关闭RGB和YUV文件
    	fclose(fpin);
    	fclose(fpout);
    
    	// 释放RGB缓冲区
    	delete rgbBuf;
    
    	//关闭编码器
    	avcodec_close(codecCtx);
    
    	//清理编码器上下文
    	avcodec_free_context(&codecCtx);
    
    	//清理视频重采样上下文
    	sws_freeContext(swsCtx);
    
    	cout << "======================end=========================" << endl;
    
    	getchar();
    
    	return 0;
    }
    

  • 相关阅读:
    模板之导入include
    模板之继承
    jQuery ajax简单用法
    Django 路由系统URL
    Django 的简单使用
    python selenium web自动化的三种等待的区别
    Django的数据库介绍
    Django 安装与介绍
    插件轮播
    bootstrap 简单使用(实现图标和按钮下拉)
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/12131721.html
Copyright © 2020-2023  润新知