• FFmpeg RGB转YUV


    前言

    下面这个例子是使用 FFmpeg 将 RGB 格式像素数据转换成 YUV 格式像素数据,在本地生成的 YUV 文本使用雷霄骅大神改写的 yuvplayer 成功播放。

    我测试的 rgb 文件像素格式是 RGB24 的,如果你的是其它像素格式,请自行替换 "像素格式ID" 和申请的内存空间大小等等。如果有些同学没有 rgb 测试文件,可以留言我发给你。


    效果

    设置好分辨率,将本地生成的 YUV 文本直接拖到 yuvplayer 窗口中,即可正常播放,如下图所示:


    完整代码

    #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_RGB24.rgb";
    	char outfile[] = "out.yuv";
    
    	// 源图像参数(这里参数要设置正确,否则会转换异常)
    	int width = 640;
    	int height = 360;
    
    	//1 打开RGB和YUV文件
    	FILE *fpin = fopen(infile, "rb");
    	if (!fpin)
    	{
    		cout << infile << "open infile failed!" << endl;
    		getchar();
    		return -1;
    	}
    
    	FILE* fpout = fopen(outfile, "wb");
    	if (!fpout)
    	{
    		cout << infile << "open outfile failed!" << endl;
    		getchar();
    		return -1;
    	}
    	// 创建RGB缓冲区同时分配内存
    	unsigned char *rgbBuf = new unsigned char[width * height * 3];
    
    	// 注册所有和编解码器有关的组件
    	av_register_all();
    
    	//2 创建视频重采样上下文:指定源和目标图像分辨率、格式
    	SwsContext *swsCtx = NULL;
    	swsCtx = sws_getCachedContext(swsCtx,
    		width, height, AV_PIX_FMT_RGB24,
    		width, height, AV_PIX_FMT_YUV420P,
    		SWS_BICUBIC,
    		NULL, NULL, NULL
    		);
    
    	//3 创建YUV视频帧并配置
    	AVFrame *yuvFrame = av_frame_alloc();
    	yuvFrame->format = AV_PIX_FMT_YUV420P;
    	yuvFrame->width = width;
    	yuvFrame->height = height;
    	av_frame_get_buffer(yuvFrame, 3 * 8);
    
    	// 循环写视频文件
    	for (;;)
    	{
    		//4 每次读取一帧RGB数据到rgbBuf,读取完毕则退出
    		int len = fread(rgbBuf, width*height * 3, 1, 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_BGR24, width, height);
    
    		//6 像素格式转换,转换后的YUV数据存放在yuvFrame
    		int outSliceH = sws_scale(swsCtx, rgbFrame->data, rgbFrame->linesize, 0, height,
    			yuvFrame->data, yuvFrame->linesize);
    		if (outSliceH <= 0)
    			break;
    
    		//7 将YUV各分量数据写入文件
    		fwrite(yuvFrame->data[0], width * height, 1, fpout);
    		fwrite(yuvFrame->data[1], width * height / 4, 1, fpout);
    		fwrite(yuvFrame->data[2], width * height / 4, 1, fpout);
    
    		cout << ".";
    	}
    
    	cout << "
    ======================end=========================" << endl;
    
    	// 关闭RGB和YUV文件
    	fclose(fpin);
    	fclose(fpout);
        
    	// 释放RGB缓冲区
    	delete rgbBuf;    
    
    	//清理视频重采样上下文
    	sws_freeContext(swsCtx);
    
    	getchar();
    
    	return 0;
    }
    

    代码分析

    因为是要做的 RGB 转 YUV,这个过程中最重要的函数是 sws_scale,其函数原型如下:

    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[]);
    

    所以我们先要创建并配置好 sws_scale 需要的参数,下面我们分别讲解一下:

    (1)参数 c,用于指定源和目标图像分辨率、格式,在第 2 步创建;

    (2)参数 srcSlice[] 和 srcStride[],即源图像的数据指针和行字节数,可以通过rgbFrame->datargbFrame->linesize获得,而 rgbFrame 在第 5 步创建 ;

    (3)参数 dst[] 和 dstStride[],即目标图像的数据指针和行字节数,可以通过yuvFrame->datayuvFrame->linesize获得,而 yuvFrame 在第 3 步创建 ;


    总而言之,就是先打开 RGB 和 YUV 文本,配置好 sws_scale 需要的参数,在循环中每次读取一帧 RGB 视频帧数据保存在 rgbFrame 结构体中,然后经过 swscale 函数转换,将得到的一帧 YUV 视频帧数据保存在 pFrameYUV 中,最后将 yuvFrame 中的数据写入 YUV 文件。

    注意:源图像参数要跟你的本地 RGB 文件一致,否则会转换异常。


    参考:

    雷霄骅 - FFMPEG 实现 YUV,RGB各种图像原始数据之间的转换(swscale)


  • 相关阅读:
    vue :调用子组件 ,watch props 时,监听不到
    table 》 td 超出内容过长显示...
    kendo 服务端排序
    Highcharts的基本属性和方法详解
    使用vue element table 自定义列模版
    vue 结合JQ ajax 作用域会改变
    实用的javascript 简写--读后感~
    【iOS】iOS13新增的暗黑模式(Dark Mode)
    【iOS】iOS13后新增的Scene Delegate和不使用工程自带的Main.storyboard
    【iOS】检测项目中是否包含UIWebView
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/12127975.html
Copyright © 2020-2023  润新知