zoukankan      html  css  js  c++  java
  • ffmpeg源码简析(一)libswscale中的sws_getContext,sws_scale()等

    前言

    libswscale 是一个主要用于处理图片像素数据的类库。可以完成图片像素格式的转换,图片的拉伸,图像的滤波等工作。libswscale 常用的函数数量很少,一般情况下就 3 个:

    sws_getContext():初始化一个SwsContext。
    sws_scale():处理图像数据。
    sws_freeContext():释放一个SwsContext。
    

    SwsContext 结构体

    SwsContext 是转换格式的上下文结构体,也是使用 libswscale 的时候一个贯穿始终的结构体,这个结构体的定义很复杂,里面包含了 libswscale 所需要的全部变量。

    一个个分析这些变量是不太现实的,这里只简单说明下其中的几个变量,即定义源图像和目标图像的宽高、像素格式和图像算法等信息(就是 sws_getContext() 函数中的参数)。


    1. sws_getContext()

    sws_getContext() 是对函数内部定义的 SwsContext 结构体中的各个成员变量进行赋值,成功执行的话返回该 SwsContext,否则返回 NULL,返回的 SwsContext 在之后的 sws_scale() 和 sws_freeContext() 皆会用到。其函数原型:

    struct SwsContext *sws_getContext(
                int srcW, /* 源图像的宽度 */
                int srcH, /* 源图像的宽度 */
                enum AVPixelFormat srcFormat, /* 源图像的像素格式 */
                int dstW, /* 目标图像的宽度 */
                int dstH, /* 目标图像的高度 */
                enum AVPixelFormat dstFormat, /* 目标图像的像素格式 */
                int flags,/* 选择缩放算法(只有当源图像和目标图像大小不同时有效),一般选择SWS_FAST_BILINEAR */
                SwsFilter *srcFilter, /* 源图像的滤波器信息, 若不需要传NULL */
                SwsFilter *dstFilter, /* 目标图像的滤波器信息, 若不需要传NULL */
                const double *param /* 特定缩放算法需要的参数,默认为NULL */
                );
    

    与其类似的函数还有: sws_getCachedContext ,区别在于: sws_getContext 可以用于多路码流转换,为每个不同的码流都指定一个不同的转换上下文,而 sws_getCachedContext 只能用于一路码流转换。


    以下是一个 sws_getContext 的简单例子:

    struct SwsContext *swsContext = sws_getContext(in_width, in_height, AV_PIX_FMT_BGRA, out_width, out_height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);
    

    將 sws_getContext 的返回值赋值给 swsContext。


    2. sws_freeContext()

    void sws_freeContext(struct SwsContext *swsContext);
    

    用来释放 sws_getContext() 返回的 SwsContext 对象指针。


    3. sws_scale()

    sws_scale() 函数主要是用来做视频像素格式和分辨率的转换,其优势在于:可以在同一个函数里实现:1.图像色彩空间转换, 2.分辨率缩放,3.前后图像滤波处理。不足之处在于:效率相对较低,不如 libyuv 或 shader,其关联的函数就是上面的 sws_getContext() 和 sws_freeContext()。

    它的声明位于 libswscaleswscale.h,如下所示:

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

    参数说明:

    • SwsContext *c:转换格式的上下文结构体,也就是 sws_getContext() 函数返回的结果。
    • srcSlice[]:源图像的每个颜色通道的数据指针。其实就是解码后的 AVFrame 中的 data[] 数组。因为不同像素的存储格式不同,所以 srcSlice[] 数组也有可能不同。
    • srcStride[]:源图像的每个颜色通道的跨度。也就是每个通道的行字节数,对应的是解码后的 AVFrame 中的 linesize[] 数组,根据它可以确立下一行的起始位置。
    • srcSliceY、int srcSliceH:定义在源图像上处理区域,srcSliceY 是起始位置,srcSliceH 是处理多少行。如果 srcSliceY=0,srcSliceH=height,表示一次性处理完整个图像。这种设置是为了多线程并行,例如可以创建两个线程,第一个线程处理 [0, h/2-1] 行,第二个线程处理 [h/2, h-1] 行,并行处理加快速度。
    • dst[]、dstStride[]:定义目标图像信息(目标图像输出的每个颜色通道数据指针每个颜色通道行字节数)。

    最后再整理一次,要使用 swscale,只要使用 sws_getContext() 进行初始化、sws_scale() 进行主要转换、sws_freeContext() 结束,即可完成全部动作。


    4. 简单示例

    以下为一个简单的范例程式,可从 foreman.yuv 内取出第一张图,转换大小后存成另一张图。

    /* 
    * 需设定 SRCFILE 及 DSTFILE, 长宽等咨询 
    * 需 link libswscale 
    * 主要有三个 function 
    * sws_getContext() 是 initial 用, sws_freeContext() 是结束用 
    * sws_scale() 是主要运作的 function 
    *预设只会转换第一张 YUV, 如果要转换整个文档, 可以把 Decoding loop 的注解拿掉 
    */ 
    
    #include "libswscale/swscale.h" 
    
    #define SRCFILE "foreman_cif.yuv" 
    #define DSTFILE "out.yuv" 
    
    int main() 
    { 
    // 设定原始 YUV 的长宽 
    const int in_width = 352; 
    const int in_height = 288; 
    // 设定目的 YUV 的长宽
    const int out_width = 640; 
    const int out_height = 480; 
    
    const int read_size = in_width * in_height * 3 / 2; 
    const int write_size = out_width * out_height * 3 / 2; 
    struct SwsContext *img_convert_ctx; 
    uint8_t *inbuf[4]; 
    uint8_t *outbuf[4]; 
    int inlinesize[4] = {in_width, in_width/2, in_width/2, 0}; 
    int outlinesize[4] = {out_width, out_width/2, out_width/2, 0}; 
    
    uint8_t in[352*288*3>>1]; 
    uint8_t out[640*480*3>>1]; 
    
    FILE *fin = fopen(SRCFILE, "rb"); 
    FILE *fout = fopen(DSTFILE, "wb"); 
    
    if(fin == NULL) { 
    printf("open input file %s error.
    ", SRCFILE); 
    return -1; 
    } 
    
    if(fout == NULL) { 
    printf("open output file %s error.
    ", DSTFILE); 
    return -1; 
    } 
    
    inbuf[0] = malloc(in_width*in_height); 
    inbuf[1] = malloc(in_width*in_height>>2); 
    inbuf[2] = malloc(in_width*in_height>>2); 
    inbuf[3] = NULL; 
    
    outbuf[0] = malloc(out_width*out_height); 
    outbuf[1] = malloc(out_width*out_height>>2); 
    outbuf[2] = malloc(out_width*out_height>>2); 
    outbuf[3] = NULL; 
    
    // ********* Initialize software scaling ********* 
    // ********* sws_getContext ********************** 
    img_convert_ctx = sws_getContext(in_width, in_height, PIX_FMT_YUV420P, 
    out_width, out_height, PIX_FMT_YUV420P, SWS_POINT, 
    NULL, NULL, NULL); 
    if(img_convert_ctx == NULL) { 
    fprintf(stderr, "Cannot initialize the conversion context!
    "); 
    return -1; 
    } 
    
    fread(in, 1, read_size, fin); 
    
    memcpy(inbuf[0], in, in_width*in_height); 
    memcpy(inbuf[1], in+in_width*in_height, in_width*in_height>>2); 
    memcpy(inbuf[2], in+(in_width*in_height*5>>2), in_width*in_height>>2); 
    
    // ********* 主要的 function ****** 
    // ********* sws_scale ************ 
    sws_scale(img_convert_ctx, inbuf, inlinesize, 
    0, in_height, outbuf, outlinesize); 
    
    memcpy(out, outbuf[0], out_width*out_height); 
    memcpy(out+out_width*out_height, outbuf[1], out_width*out_height>>2); 
    memcpy(out+(out_width*out_height*5>>2), outbuf[2], out_width*out_height>>2); 
    
    fwrite(out, 1, write_size, fout); 
    
    // ********* 结束的 function ******* 
    // ********* sws_freeContext ******* 
    sws_freeContext(img_convert_ctx); 
    
    fclose(fin); 
    fclose(fout); 
    
    return 0; 
    } 
    

    以下两张图为执行结果:

    Input Image

    img


    Output Image

    img


    参考:

    FFmpeg源代码简单分析:libswscale的sws_getContext()

    FFmpeg源代码简单分析:libswscale的sws_scale()

    sws_scale函数的用法-具体应用


  • 相关阅读:
    Spring学习笔记
    Bash编程(6) String操作
    Bash编程(5) Shell方法
    Bash编程(4) 参数与变量
    Bash编程(2) 循环与分支
    CentOS 升级 openSSH
    Bash编程(1) 基础
    DNS配置
    资料收集:学习 Linux/*BSD/Unix 的 30 个最佳在线文档
    【数位DP】[LOJ10168] 恨7不成妻
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/12119915.html
Copyright © 2011-2022 走看看