zoukankan      html  css  js  c++  java
  • 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
            );
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

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

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

    ③ 转换图像格式 : sws_scale ( )

    sws_scale(
            //SwsContext *swsContext 转换上下文
            swsContext,
            //要转换的数据内容
            avFrame->data,
            //数据中每行的字节长度
            avFrame->linesize,
            0,
            avFrame->height,
            //转换后目标图像数据存放在这里
            dst_data,
            //转换后的目标图像行数
            dst_linesize
            );
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14


    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);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    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
                );
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19


    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);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    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);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10


    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[]);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

    4 . sws_scale ( ) 使用示例 :

    sws_scale(
            //SwsContext *swsContext 转换上下文
            swsContext,
            //要转换的数据内容
            avFrame->data,
            //数据中每行的字节长度
            avFrame->linesize,
            0,
            avFrame->height,
            //转换后目标图像数据存放在这里
            dst_data,
            //转换后的目标图像行数
            dst_linesize
            );
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14


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

    from:https://blog.csdn.net/shulianghan/article/details/104772549

  • 相关阅读:
    nodejs pm2使用
    react生命周期
    It's a start!
    关于react-native报错: Invariant Violation: WebView has been removed from React Native. It can ....
    react-native 页面使用WebView布满整个页面,导航栏不显示问题
    两个函数执行顺序,异步问题处理(已解决)
    react-native webView乱码问题
    react-native 多页面之间传值
    时间戳转换为时间日期格式
    React Native返回刷新页面(this.props.navigation.goBack())
  • 原文地址:https://www.cnblogs.com/lidabo/p/15038829.html
Copyright © 2011-2022 走看看