zoukankan      html  css  js  c++  java
  • 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;
    }
    

  • 相关阅读:
    基于Metaweblog API 接口一键发布到国内外主流博客平台
    uva144 Student Grants
    Uva 10452
    Uva 439 Knight Moves
    Uva 352 The Seasonal War
    switch语句
    java——基础知识
    我的lua学习2
    codeforces 431 D. Random Task 组合数学
    codeforces 285 D. Permutation Sum 状压 dfs打表
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/12131721.html
Copyright © 2011-2022 走看看