06 使用ffmpeg sws_scale NV12转YUV420P,自己创建linesize和地址参数

使用ffmpeg sws_scale NV12转YUV420P,自己创建linesize和地址参数

作者将狼才鲸
创建日期2022-04-03
  • ffmpeg4.3.1版本

  • 因为在网上没找到教怎么自己生成sws_scale()函数参数的,我也是摸索了好几个钟头才弄清楚,所以,特写此文章。

我的整个工程Gitee源码目录:qt_gui_simple2complex/ source / 007_Embeded_Player

  • 代码展示:
#include "libswscale/swscale.h"   // NV12转YUV420

#define MDATA_LEN (2 * 1024 * 1024) // for 1280 * 720 max

static unsigned char mdata[MDATA_LEN]; // NV12原始的一帧数据
static unsigned char yuv420_mdata[MDATA_LEN];
static int ySize = 0;		// 宽乘以高
static int width = 1280;
static int height = 720;
static struct SwsContext *m_pSwsCtx = NULL;// NV12转YUV420P

int nv12_to_yuv420p()
{
	int ret;

	ySize = width * height;

    // 注册NV12转YUV420P的句柄,当前编码器只支持YUV420P输入
    m_pSwsCtx = sws_getContext(width,
           height,
           AV_PIX_FMT_NV12,
           width,
           height,
           AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);

    char *indata = mdata;
    char *outdata = yuv420_mdata;

    /* NV12转YUV420 */
    //[使用ffmpeg编码原始nv12帧](http://cn.voidcc.com/question/p-rajvdmfe-dw.html)
    //[全网首发:FFMpeg使用NVIDIA DECODER,解码后的数据是NV12,不是YUV420P](https://blog.51cto.com/u_13161667/3306044)
    int nv12_linesize[3];
    int yuv420_linesize[3];
    yuv420_linesize[0] = width;     // YUV各个分量的长度
    yuv420_linesize[1] = width / 2;
    yuv420_linesize[2] = width / 2;
    nv12_linesize[0] = width;
    nv12_linesize[1] = width;
    nv12_linesize[2] = 0;
    unsigned char *inaddr[3] = {indata, indata + ySize, 0};
    unsigned char *outaddr[3] = {outdata, outdata + ySize, outdata + ySize + ySize / 4};
   	do {
    	ret = sws_scale(m_pSwsCtx, inaddr, nv12_linesize, 0, pCodecCtx->height,
                    outaddr, yuv420_linesize);
        // 转换完的数据在outdata中
        // 函数如果返回720则说明转换成功,如果返回0则说明函数内部处理出错
	} while (0); // 可以修改为循环处理多帧

    // 释放内存
    sws_freeContext(m_pSwsCtx);
    
	return 0;
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
假设你的 YUV422 数据是存储在一个名为 `yuv422_data` 的一维数组中,长为 `width`,宽为 `height`,那么可以通过下面的公式计算出 `linesize`: ```c++ int linesize = width * 2; // 因为每个像素占用 2 字节 ``` 接下来,你可以使用 FFmpeg 中的 `libswscale` 库来进行 YUV422 到 YUV420P换。下面是一个简单的代码示例: ```c++ #include <iostream> #include <fstream> #include <cstring> #include <cmath> extern "C" { #include <libswscale/swscale.h> } int main() { // 输入参数 const int width = 640; const int height = 480; const int linesize = width * 2; // YUV422 数据 std::ifstream ifs("input.yuv422", std::ios::binary); std::vector<uint8_t> yuv422_data(linesize * height); ifs.read(reinterpret_cast<char*>(yuv422_data.data()), yuv422_data.size()); // 初始化 sws 上下文 SwsContext* sws_ctx = sws_getContext(width, height, AV_PIX_FMT_YUYV422, width, height, AV_PIX_FMT_YUV420P, 0, nullptr, nullptr, nullptr); if (!sws_ctx) { std::cerr << "Failed to create SwsContext" << std::endl; return -1; } // 换为 YUV420P std::vector<uint8_t> yuv420p_data(width * height * 3 / 2); uint8_t* src_data[1] = { yuv422_data.data() }; int src_linesize[1] = { linesize }; uint8_t* dst_data[3] = { yuv420p_data.data(), yuv420p_data.data() + width * height, yuv420p_data.data() + width * height * 5 / 4 }; int dst_linesize[3] = { width, width / 2, width / 2 }; int ret = sws_scale(sws_ctx, src_data, src_linesize, 0, height, dst_data, dst_linesize); if (ret < 0) { std::cerr << "Failed to sws_scale" << std::endl; return -1; } // 输出 YUV420P 数据 std::ofstream ofs("output.yuv420p", std::ios::binary); ofs.write(reinterpret_cast<const char*>(yuv420p_data.data()), yuv420p_data.size()); // 释放资源 sws_freeContext(sws_ctx); return 0; } ``` 上述代码中,我们首先读取 YUV422 数据,并计算出 `linesize`。接着,我们初始化一个 `SwsContext` 对象,用于进行格式换。这里我们将 YUV422 换为 YUV420P,因此输入格式为 `AV_PIX_FMT_YUYV422`,输出格式为 `AV_PIX_FMT_YUV420P`。然后我们定义输入和输出的数据指针和行宽数组,并调用 `sws_scale` 函数进行换。最后,我们将换后的 YUV420P 数据保存到文件中,并释放资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值