热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

YUV像素格式转换

本文像素格式转换用到的库是FFmpeg的libswscale,将YUV像素格式数据转换成RGB像素格式数据。一、使用的相关函数说明:1、获取像素

本文像素格式转换用到的库是 FFmpeg 的 libswscale,将 YUV 像素格式数据转换成 RGB 像素格式数据。

一、使用的相关函数说明:

1、获取像素格式转换上下文函数:

struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param);

参数说明:

srcW, srcH, srcFormat:原始宽高和原始像素格式(我们这里原始像素格式是yuv420p);
dstW, dstH, dstFormat:目标宽高和目标像素格式(我们这里原始像素格式是rgb24),不仅可以转换像素格式,也可以转换宽高;
flag:指定使用何种算法,例如快速线性、差值和矩阵等等,不同的算法性能也不同,快速线性算法性能相对较高。只针对尺寸的变换。

/* values for the flags, the stuff on the command line is different */ #define SWS_FAST_BILINEAR 1 #define SWS_BILINEAR 2 #define SWS_BICUBIC 4 #define SWS_X 8 #define SWS_POINT 0x10 #define SWS_AREA 0x20 #define SWS_BICUBLIN 0x40 #define SWS_GAUSS 0x80 #define SWS_SINC 0x100 #define SWS_LANCZOS 0x200 #define SWS_SPLINE 0x400

srcFilter, stFilter:这两个参数是做过滤器用的,可以传 nullptr;
param:和 flag 算法相关,也可以传 nullptr;

返回值:成功返回转换格式上下文指针,失败返回 NULL;

注意:使用完格式转换上下文最后不要忘记调用函数 void sws_freeContext(struct SwsContext *swsContext) 释放上下文;有人可能会有疑问,调用的是 sws_getContext 函数,函数名里并没有 create 或者 alloc 字眼,也需要释放吗?我们可以参考一下源码:

YUV像素格式转换

发现源码当中调用了 sws_alloc_set_opts,所以最后是需要释放上下文的。我们也可以使用以下函数来创建上下文:

struct SwsContext *sws_alloc_context(void); int av_opt_set(void *obj, const char *name, const char *val, int search_flags);

2、转换函数:

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

参数说明:

struct SwsContext *c:像素格式转换上下文;
const uint8_t *const srcSlice[]:输入的数据,silice可以理解为一帧;
const int srcStride[]:输入数据的每一个平面的每一行的大小(linesize),而不是每一个平面的总大小;
int srcSliceY:从哪个位置开始处理,直接传0即可;
int srcSliceH:图像的高度;
uint8_t *const dst[]:输出的数据;
const int dstStride[]:输出数据的每一个平面的每一行的大小;

注意:sws_scale 函数不会为传入的输入数据和输出数据创建堆空间

3、创建输入输出缓冲区:

#include int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align);

参数说明:

(uint8_t *pointers[4]:缓冲区数组(除了 Y、U 和 V 三个分量,可能会有透明度分量,所以数组 size 为 4);
int linesizes[4]:每个平面的每一行的大小数组;
int w, int h, enum AVPixelFormat pix_fmt:图片的宽、高和像素格式;
int align:是否对齐,一般传1;

创建的缓冲区数组指向堆空间,最后我们需要使用函数 av_pfree 释放它;不确定缓冲区是否需要释放的话,可以参考函数注释或者源码;源码内部是有调用 av_malloc 函数的,所以需要我们去释放。

二、示例代码:

示例代码中 inData 输入缓冲区分成了四块,每一块指向一个分量,为了兼容透明分量,指针数组size为4,以YUV420P为例,inData的第1个元素指向 Y 分量,第2个元素指向 U 分量,第3个元素指向 V 分量,一帧的 YUV 数据是连续的,如图:

YUV像素格式转换

在音频中没有行的概念 linesize 就是一个平面的大小,但是在视频中是有行的概念的,inStrides中存储的是一帧数据每一行中 Y、U 和 V 分量的长度,以 YUV420P 为例,Y 的长度是一帧的宽度,U 的长度是一帧的宽度的一半,V 的长度也是一帧的宽度的一半。outData 和 outStrides 是同样的道理。

#include "ffmpegutils.h" #include #include extern "C" { #include #include #include } FFmpegUtils::FFmpegUtils() { } //void FFmpegUtils::convretRawVideo(RawVideoFile &in, RawVideoFile &out) void FFmpegUtils::convretRawVideo(RawVideoFrame &in, RawVideoFrame &out) { int ret = 0; // 转换格式上下文 SwsContext *ctx = nullptr; // 输入输出缓冲区 // inData 和 outData 指向一帧的数据 uint8_t *inData[4], *outData[4]; // 每个平面一行的大小 int inStrides[4], outStrides[4]; // 每一帧图片的大小 int inFrameSize, outFrameSize; /* QFile inFile(in.filename); QFile outFile(out.filename); */ ret = av_image_alloc(inData, inStrides, in.width, in.height, in.format, 1); if (ret

推荐阅读
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 实现一个通讯录系统,可添加、删除、修改、查找、显示、清空、排序通讯录信息
    本文介绍了如何实现一个通讯录系统,该系统可以实现添加、删除、修改、查找、显示、清空、排序通讯录信息的功能。通过定义结构体LINK和PEOPLE来存储通讯录信息,使用相关函数来实现各项功能。详细介绍了每个功能的实现方法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 如何在跨函数中使用内存?
    本文介绍了在跨函数中使用内存的方法,包括使用指针变量、动态分配内存和静态分配内存的区别。通过示例代码说明了如何正确地在不同函数中使用内存,并提醒程序员在使用动态分配内存时要手动释放内存,以防止内存泄漏。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
author-avatar
gerardlong
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有