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函数的用法-具体应用


  • 相关阅读:
    【转】 java中Class对象详解和类名.class, class.forName(), getClass()区别
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    107. Binary Tree Level Order Traversal II
    109. Convert Sorted List to Binary Search Tree
    108. Convert Sorted Array to Binary Search Tree
    110. Balanced Binary Tree
    STL容器迭代器失效问题讨论
    113. Path Sum II
    112. Path Sum
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/12119915.html
Copyright © 2011-2022 走看看