【Android FFMPEG 开发】FFMPEG AVFrame 图像格式转换 YUV -> RGBA ( 获取 SwsContext | 初始化图像数据存储内存 | 图像格式转换 )

简介: 【Android FFMPEG 开发】FFMPEG AVFrame 图像格式转换 YUV -> RGBA ( 获取 SwsContext | 初始化图像数据存储内存 | 图像格式转换 )

文章目录

I . FFMPEG AVFrame 图像数据帧处理 前置操作

II . FFMPEG 解码 AVPacket 数据到 AVFrame 流程

III. FFMPEG 解码前后的图像格式

IV . FFMPEG 获取 SwsContext

V . FFMPEG 初始化图像数据存储内存

VI . FFMPEG 初图像格式转换

VII . FFMPEG AVFrame 图像格式转换 YUV -> RGBA 代码示例



I . FFMPEG AVFrame 图像数据帧处理 前置操作


FFMPEG 解码 AVPacket 数据到 AVFrame 数据前置操作 :



① FFMPEG 初始化 : 参考博客 【Android FFMPEG 开发】FFMPEG 初始化 ( 网络初始化 | 打开音视频 | 查找音视频流 )


② FFMPEG 获取 AVStream 音视频流 : 参考博客 【Android FFMPEG 开发】FFMPEG 获取 AVStream 音视频流 ( AVFormatContext 结构体 | 获取音视频流信息 | 获取音视频流个数 | 获取音视频流 )


③ FFMPEG 获取 AVCodec 编解码器 : 参考博客 【Android FFMPEG 开发】FFMPEG 获取编解码器 ( 获取编解码参数 | 查找编解码器 | 获取编解码器上下文 | 设置上下文参数 | 打开编解码器 )


④ FFMPEG 读取音视频流中的数据到 AVPacket : 参考博客 【Android FFMPEG 开发】FFMPEG 读取音视频流中的数据到 AVPacket ( 初始化 AVPacket 数据 | 读取 AVPacket )


⑤ FFMPEG 解码 AVPacket 数据到 AVFrame : 参考博客 【Android FFMPEG 开发】FFMPEG 解码 AVPacket 数据到 AVFrame ( AVPacket->解码器 | 初始化 AVFrame | 解码为 AVFrame 数据 )




II . FFMPEG 解码 AVPacket 数据到 AVFrame 流程


FFMPEG 解码 AVPacket 数据到 AVFrame 流程 :



〇 前置操作 : FFMPEG 环境初始化 , 获取 AVStream 音视频流 , 获取 AVCodec 编解码器 , 读取音视频流中的数据到 AVPacket , 解码 AVPacket 数据到 AVFrame , 然后才能进行下面的操作 ;



① 获取 SwsContext : sws_getContext ( )


SwsContext *swsContext = sws_getContext(
        //源图像的 宽 , 高 , 图像像素格式
        avCodecContext->width, avCodecContext->height, avCodecContext->pix_fmt,
        //目标图像 大小不变 , 不进行缩放操作 , 只将像素格式设置成 RGBA 格式的
        avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
        //使用的转换算法 , FFMPEG 提供了许多转换算法 , 有快速的 , 有高质量的 , 需要自己测试
        SWS_BILINEAR,
        //源图像滤镜 , 这里传 NULL 即可
        0,
        //目标图像滤镜 , 这里传 NULL 即可
        0,
        //额外参数 , 这里传 NULL 即可
        0
        );



② 初始化图像数据存储空间 : av_image_alloc ( )


av_image_alloc(dst_data, dst_linesize,
               avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
               1);


③ 转换图像格式 : sws_scale ( )


sws_scale(
        //SwsContext *swsContext 转换上下文
        swsContext,
        //要转换的数据内容
        avFrame->data,
        //数据中每行的字节长度
        avFrame->linesize,
        0,
        avFrame->height,
        //转换后目标图像数据存放在这里
        dst_data,
        //转换后的目标图像行数
        dst_linesize
        );



III. FFMPEG 解码前后的图像格式


AVPacket 数据解码后的数据存储在 AVFrame 结构体中 , 如果是视频数据 , 那么存储的是一帧图像 , 图像的像素格式是 YUV 格式的 , 一般 Android 中绘制需要使用 ARGB 的像素格式 , 这里需要将图像的存储格式由 YUV 格式转为 ARGB 格式 ;




IV . FFMPEG 获取 SwsContext


1 . SwsContext 结构体 : 转换图像格式 , 首先要获取 SwsContext 结构体指针 , 在该 SwsContext 结构体中封装了图像转换相关的参数信息 , 如 源图像 目标图像的宽高 , 像素格式信息等 ; 调用 sws_getContext ( ) 方法可以获取 SwsContext * 结构体指针 ;



2 . SwsContext ( ) 函数原型 : 为 SwsContext 结构体分配内存 , 并返回其结构体指针 ;



① int srcW 参数 : 源图像的宽度 ;


② int srcH 参数 : 源图像的高度 ;


③ enum AVPixelFormat srcFormat 参数 : 源图像的像素格式 ;


④ int dstW 参数 : 目标图像的宽度 ;


⑤ int dstH 参数 : 目标图像的高度 ;


⑥ enum AVPixelFormat dstFormat 参数 : 目标图像的像素格式 ;


⑦ int flags 参数 : 使用的转换算法 , 可以选择高速度 , 或者高质量等参数 ;


⑧ SwsFilter *srcFilter 参数 : 源图像滤镜 ;


⑨ SwsFilter *dstFilter 参数 : 目标图像滤镜 ;


⑩ const double *param 参数 : 额外参数 ;


/**
 * Allocate and return an SwsContext. You need it to perform
 * scaling/conversion operations using sws_scale().
 *
 * @param srcW the width of the source image
 * @param srcH the height of the source image
 * @param srcFormat the source image format
 * @param dstW the width of the destination image
 * @param dstH the height of the destination image
 * @param dstFormat the destination image format
 * @param flags specify which algorithm and options to use for rescaling
 * @param param extra parameters to tune the used scaler
 *              For SWS_BICUBIC param[0] and [1] tune the shape of the basis
 *              function, param[0] tunes f(1) and param[1] f´(1)
 *              For SWS_GAUSS param[0] tunes the exponent and thus cutoff
 *              frequency
 *              For SWS_LANCZOS param[0] tunes the width of the window function
 * @return a pointer to an allocated context, or NULL in case of error
 * @note this function is to be removed after a saner alternative is
 *       written
 */
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);



3 . 获取 SwsContext 代码示例 :


 

SwsContext *swsContext = sws_getContext(
            //源图像的 宽 , 高 , 图像像素格式
            avCodecContext->width, avCodecContext->height, avCodecContext->pix_fmt,
            //目标图像 大小不变 , 不进行缩放操作 , 只将像素格式设置成 RGBA 格式的
            avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
            //使用的转换算法 , FFMPEG 提供了许多转换算法 , 有快速的 , 有高质量的 , 需要自己测试
            SWS_BILINEAR,
            //源图像滤镜 , 这里传 NULL 即可
            0,
            //目标图像滤镜 , 这里传 NULL 即可
            0,
            //额外参数 , 这里传 NULL 即可
            0
            );



V . FFMPEG 初始化图像数据存储内存


1 . 图像数据保存 : 需要两个变量来进行存储 , 一个是指针 , 指向一块内存 , 该内存中存储实际的图像数据 , 一个是 int 数值 , 存储该内存中存储了多少数据 ;


① 指针 : 将图像数据保存到 uint8_t *dst_data[4] 指针数组中的指针元素指向的内存中 ;


② 行数 : int dst_linesize[4] 中存储其行数 , 代表了上面指针指向的内存每行存储了多少数据 ;



2 . 图像数据指针的操作 :


① 初始化 : 这个内存需要用专门的函数 av_image_alloc ( ) 进行初始化 ;


② 释放 : 这个指针需要使用专门的函数 void av_freep(void *ptr) 进行释放 ;



3 . av_image_alloc ( ) 函数原型 : 根据图像的宽高 , 像素格式 , 为 相应的 指向图像数据的指针 和 行数 进行初始化 ;



① uint8_t *pointers[4] 参数 : 指向图像数据的指针 , 这是四个指针 , 这里只是用了一个 , 也就是第一个 ;


② int linesizes[4] 参数 : 存储每个图像数据存储的数据行数 ;


③ int w 参数 : 图像的宽度 ;


④ int h 参数 : 图像的高度 ;


⑤ enum AVPixelFormat pix_fmt : 图像的像素格式 , ARGB 格式的 ;


⑥ int align 参数 : 设置 1 即可 ;


/**
 * Allocate an image with size w and h and pixel format pix_fmt, and
 * fill pointers and linesizes accordingly.
 * The allocated image buffer has to be freed by using
 * av_freep(&pointers[0]).
 *
 * @param align the value to use for buffer size alignment
 * @return the size in bytes required for the image buffer, a negative
 * error code in case of failure
 */
int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
                   int w, int h, enum AVPixelFormat pix_fmt, int align);


4 . av_image_alloc ( ) 代码示例 :


//指针数组 , 数组中存放的是指针
uint8_t *dst_data[4];
//普通的 int 数组
int dst_linesize[4];
//初始化 dst_data 和 dst_linesize , 为其申请内存 , 注意使用完毕后需要释放内存
av_image_alloc(dst_data, dst_linesize,
               avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
               1);




VI . FFMPEG 初图像格式转换


1 . 准备工作完毕 : 转换使用的上下文 SwsContext , 转换后的数据存储 指针 和 行数 , 准备就绪后 , 可以开始转换 AVFrame 中的 YUV 像素格式的图像为 RGBA 像素格式 ;



2 . 转换使用方法 : 调用 sws_scale ( ) 方法 , 执行转换操作 ;



3 . sws_scale ( ) 函数原型 : 转换图像像素格式 ;



① struct SwsContext *c 参数 : 转换上下文 ;


② const uint8_t *const srcSlice[] 参数 : 源图像数据指针 ;


③ const int srcStride[] 参数 : 源图像每行有多少个数据 ;


④ int srcSliceY 参数 : 源图像数据数组处理的索引值 , 从 0 开始计数 , 一般是 0 ;


⑤ int srcSliceH 参数 : 源图像的高度 , 即有多少行数据 ;


⑥ uint8_t *const dst[] 参数 : 图像数组指针数组 ;


⑦ const int dstStride[] 参数 : 图像数据每行的数据个数 ;


/**
 * Scale the image slice in srcSlice and put the resulting scaled
 * slice in the image in dst. A slice is a sequence of consecutive
 * rows in an image.
 *
 * Slices have to be provided in sequential order, either in
 * top-bottom or bottom-top order. If slices are provided in
 * non-sequential order the behavior of the function is undefined.
 *
 * @param c         the scaling context previously created with
 *                  sws_getContext()
 * @param srcSlice  the array containing the pointers to the planes of
 *                  the source slice
 * @param srcStride the array containing the strides for each plane of
 *                  the source image
 * @param srcSliceY the position in the source image of the slice to
 *                  process, that is the number (counted starting from
 *                  zero) in the image of the first row of the slice
 * @param srcSliceH the height of the source slice, that is the number
 *                  of rows in the slice
 * @param dst       the array containing the pointers to the planes of
 *                  the destination image
 * @param dstStride the array containing the strides for each plane of
 *                  the destination image
 * @return          the height of the output slice
 */
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[]);


4 . sws_scale ( ) 使用示例 :


sws_scale(
        //SwsContext *swsContext 转换上下文
        swsContext,
        //要转换的数据内容
        avFrame->data,
        //数据中每行的字节长度
        avFrame->linesize,
        0,
        avFrame->height,
        //转换后目标图像数据存放在这里
        dst_data,
        //转换后的目标图像行数
        dst_linesize
        );



VII . FFMPEG AVFrame 图像格式转换 YUV -> RGBA 代码示例


//1 . 获取转换上下文
SwsContext *swsContext = sws_getContext(
        //源图像的 宽 , 高 , 图像像素格式
        avCodecContext->width, avCodecContext->height, avCodecContext->pix_fmt,
        //目标图像 大小不变 , 不进行缩放操作 , 只将像素格式设置成 RGBA 格式的
        avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
        //使用的转换算法 , FFMPEG 提供了许多转换算法 , 有快速的 , 有高质量的 , 需要自己测试
        SWS_BILINEAR,
        //源图像滤镜 , 这里传 NULL 即可
        0,
        //目标图像滤镜 , 这里传 NULL 即可
        0,
        //额外参数 , 这里传 NULL 即可
        0
        );
//2 . 初始化图像存储内存
//指针数组 , 数组中存放的是指针
uint8_t *dst_data[4];
//普通的 int 数组
int dst_linesize[4];
//初始化 dst_data 和 dst_linesize , 为其申请内存 , 注意使用完毕后需要释放内存
av_image_alloc(dst_data, dst_linesize,
               avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
               1);
//3 . 格式转换
sws_scale(
        //SwsContext *swsContext 转换上下文
        swsContext,
        //要转换的数据内容
        avFrame->data,
        //数据中每行的字节长度
        avFrame->linesize,
        0,
        avFrame->height,
        //转换后目标图像数据存放在这里
        dst_data,
        //转换后的目标图像行数
        dst_linesize
        );



目录
打赏
0
0
0
0
39
分享
相关文章
数据存储以及内存
数据存储以及内存
106 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
417 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
【C语言】memset()函数(内存块初始化函数)
【C语言】memset()函数(内存块初始化函数)
126 0
|
9月前
|
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
在Linux环境下交叉编译Android所需的FFmpeg so库,首先下载`android-ndk-r21e`,然后解压。接着,上传FFmpeg及相关库(如x264、freetype、lame)源码,修改相关sh文件,将`SYSTEM=windows-x86_64`改为`SYSTEM=linux-x86_64`并删除回车符。对x264的configure文件进行修改,然后编译x264。同样编译其他第三方库。设置环境变量`PKG_CONFIG_PATH`,最后在FFmpeg源码目录执行配置、编译和安装命令,生成的so文件复制到App工程指定目录。
386 9
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
实时计算 Flink版产品使用合集之在Flink Stream API中,可以在任务启动时初始化一些静态的参数并将其存储在内存中吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
147 4
|
4月前
|
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
149 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
4月前
|
API
FFmpeg中AVPacket、AVFrame结构的基本使用
FFmpeg中AVPacket和AVFrame结构的内存分配、释放和引用计数处理,以及如何避免内存泄漏。
97 3
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
|
8月前
|
ffmpeg音频格式转换、合成、速率调整
ffmpeg音频格式转换、合成、速率调整
157 2
Redis:内存数据存储与缓存系统的技术探索
**Redis 概述与最佳实践** Redis,全称Remote Dictionary Server,是流行的内存数据结构存储系统,常用于数据库、缓存和消息中介。它支持字符串、哈希、列表等数据结构,并具备持久化、主从复制、集群部署及发布/订阅功能。Redis适用于缓存系统、计数器、消息队列、分布式锁和实时系统等场景。最佳实践包括选择合适的数据结构、优化缓存策略、监控调优、主从复制与集群部署以及确保安全配置。
171 3

热门文章

最新文章

  • 1
    Android历史版本与APK文件结构
    22
  • 2
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    22
  • 3
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
    4
  • 4
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
    8
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    57
  • 6
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    19
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    9
  • 8
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    16
  • 9
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    35
  • 10
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    10