FFMPEG-初探认识-YUV转RGB用例

来源:互联网 发布:淘宝号实名认证几个 编辑:程序博客网 时间:2024/05/16 04:59

前段时间因为项目需要,尝试通过FFMPEG将图像帧进行格式转换,评估测试了一下,记录一下FFMPEG的一些基本信息资料


概念:

来自百科:
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它包括了领先的音/视频编码库libavcodec等。
libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构
和读取音视频帧等功能;
libavcodec:用于各种类型声音/图像编解码;
libavutil:包含一些公共的工具函数;
libswscale:用于视频场景比例缩放、色彩映射转换;
libpostproc:用于后期效果处理;
ffmpeg:该项目提供的一个工具,可用于格式转换、解码或电视卡即时编码等;
ffsever:一个 HTTP 多媒体即时广播串流服务器;
ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示;

通俗理解为一个 音视频流处理库集合,跟之前接触过的opencv有相同之处,都涉及不深,个人感觉感觉侧重点不同,ffmpeg侧重音视频源数据流的格式编解码,opencv侧重的是对已存在视图的算法处理操作

ffmpeg 官网下载:https://ffmpeg.org/


编译:

ubuntu 32bit 下编译,目标平台android,需要配置NDK ,下载ffmpeg-3.1.4的根目录下创建一个编译脚本build_android.sh,内容如下:

#!/bin/bashNDK=/home/xxx/tool/android-ndk-r10SYSROOT=$NDK/platforms/android-19/arch-arm/TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86function build_one{./configure \    --prefix=$PREFIX \    --enable-shared \    --disable-static \    --disable-doc \    --disable-ffmpeg \    --disable-ffplay \    --disable-ffprobe \    --disable-ffserver \    --enable-gpl \    --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \    --target-os=linux \    --arch=arm \    --enable-cross-compile \    --sysroot=$SYSROOT \    --extra-cflags="-Os -fpic $ADDI_CFLAGS" \    --extra-ldflags="$ADDI_LDFLAGS" \    $ADDITIONAL_CONFIGURE_FLAG#make cleanmakemake install}CPU=armPREFIX=$(pwd)/android/$CPU ADDI_CFLAGS="-marm"build_one

关键是NDK的路径,根据实际情况配置,native-api 的版本以及交叉编译工具链的选择,需注意 32-64 x86主机区别,目标平台为arm
按上面编译之后对应ffmpeg-3.1.4\android\arm 目录下生成 头文件以及 lib库,直接拿到android上使用


YUV格式概念:

网上的总结:
YUV。分为三个分量,“Y”表示明亮度(Luminance或Luma)。也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),
作用是描写叙述影像色彩及饱和度,用于指定像素的颜色。

与我们熟知的RGB类似。YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,
没有UV信息一样能够显示完整的图像,仅仅只是是黑白的,这种设计非常好地攻克了彩色电视机与黑白电视的兼容问题。

而且,YUV不像RGB那样要求三个独立的视频信号同一时候传输,所以用YUV方式传送占用极少的频宽。

通过YUV与RGB的转换公式提取出每一个像素点的RGB值,然后显示出来。

YUV 4:4:4採样,每个Y相应一组UV分量。
YUV 4:2:2採样。每两个Y共用一组UV分量。
YUV 4:2:0採样,每四个Y共用一组UV分量。

参考网上的博客 http://blog.csdn.net/beyond_cn/article/details/12998247


YUV转RGB:

通过ffmpeg将一帧YUV格式的图像转换成成RGB格式并存储,需要用到 libavutil 以及 libswscale
网上摘的转换实现:

#include <stdio.h>#include <utils/Log.h>#define LOG_TAG "ffmpeg"extern "C"{#include "libswscale/swscale.h"#include "libavutil/opt.h"#include "libavutil/imgutils.h"};#include <android/log.h>#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "ffmpeg", __VA_ARGS__)int main(int argc, char* argv[]){    //Parameters        FILE *src_file =fopen("1088p_yuv420p.yuv", "rb");    const int src_w=1920,src_h=1088;    AVPixelFormat src_pixfmt=AV_PIX_FMT_YUV420P;    int src_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(src_pixfmt));    FILE *dst_file = fopen("480p_rgb24.rgb", "wb");    const int dst_w=800,dst_h=480;    AVPixelFormat dst_pixfmt=AV_PIX_FMT_RGB565LE/*AV_PIX_FMT_RGB24*/;    int dst_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(dst_pixfmt));    //Structures    uint8_t *src_data[4];    int src_linesize[4];    uint8_t *dst_data[4];    int dst_linesize[4];    int rescale_method=SWS_BILINEAR/*SWS_POINT*//*SWS_BICUBIC*/;    struct SwsContext *img_convert_ctx;    uint8_t *temp_buffer=(uint8_t *)malloc(src_w*src_h*src_bpp/8);    int frame_idx=0;    int ret=0;    ret= av_image_alloc(src_data, src_linesize,src_w, src_h, src_pixfmt, 1);    if (ret< 0) {        printf( "Could not allocate source image\n");        return -1;    }    ret = av_image_alloc(dst_data, dst_linesize,dst_w, dst_h, dst_pixfmt, 1);    if (ret< 0) {        printf( "Could not allocate destination image\n");        return -1;    }    //-----------------------------     //Init Method 1//  img_convert_ctx =sws_alloc_context();//  //Show AVOption//  av_opt_show2(img_convert_ctx,stdout,AV_OPT_FLAG_VIDEO_PARAM,NULL);//  //Set Value//  av_opt_set_int(img_convert_ctx,"sws_flags",SWS_BICUBIC|SWS_PRINT_INFO,NULL);//  av_opt_set_int(img_convert_ctx,"srcw",src_w,NULL);//  av_opt_set_int(img_convert_ctx,"srch",src_h,NULL);//  av_opt_set_int(img_convert_ctx,"src_format",src_pixfmt,NULL);//  //'0' for MPEG (Y:0-235);'1' for JPEG (Y:0-255)//  av_opt_set_int(img_convert_ctx,"src_range",1,NULL);//  av_opt_set_int(img_convert_ctx,"dstw",dst_w,NULL);//  av_opt_set_int(img_convert_ctx,"dsth",dst_h,NULL);//  av_opt_set_int(img_convert_ctx,"dst_format",dst_pixfmt,NULL);//  av_opt_set_int(img_convert_ctx,"dst_range",1,NULL);//  sws_init_context(img_convert_ctx,NULL,NULL);    //Init Method 2    img_convert_ctx = sws_getContext(src_w, src_h,src_pixfmt, dst_w, dst_h, dst_pixfmt,        rescale_method, NULL, NULL, NULL);    //-----------------------------    /*    //Colorspace    ret=sws_setColorspaceDetails(img_convert_ctx,sws_getCoefficients(SWS_CS_ITU601),0,        sws_getCoefficients(SWS_CS_ITU709),0,         0, 1 << 16, 1 << 16);    if (ret==-1) {        printf( "Colorspace not support.\n");        return -1;    }    */    while(1)    {        if (fread(temp_buffer, 1, src_w*src_h*src_bpp/8, src_file) != src_w*src_h*src_bpp/8){            break;        }        switch(src_pixfmt){        case AV_PIX_FMT_GRAY8:{            memcpy(src_data[0],temp_buffer,src_w*src_h);            break;                              }        case AV_PIX_FMT_YUV420P:{            memcpy(src_data[0],temp_buffer,src_w*src_h);                    //Y            memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/4);      //U            memcpy(src_data[2],temp_buffer+src_w*src_h*5/4,src_w*src_h/4);  //V            break;                                }        case AV_PIX_FMT_YUV422P:{            memcpy(src_data[0],temp_buffer,src_w*src_h);                    //Y            memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/2);      //U            memcpy(src_data[2],temp_buffer+src_w*src_h*3/2,src_w*src_h/2);  //V            break;                                }        case AV_PIX_FMT_YUV444P:{            memcpy(src_data[0],temp_buffer,src_w*src_h);                    //Y            memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h);        //U            memcpy(src_data[2],temp_buffer+src_w*src_h*2,src_w*src_h);      //V            break;                                }        case AV_PIX_FMT_YUYV422:{            memcpy(src_data[0],temp_buffer,src_w*src_h*2);                  //Packed            break;                                }        case AV_PIX_FMT_RGB24:{            memcpy(src_data[0],temp_buffer,src_w*src_h*3);                  //Packed            break;                                }        default:{            printf("Not Support Input Pixel Format.\n");            break;                              }        }        ALOGE("-Finish process frame %5d\n",frame_idx);        sws_scale(img_convert_ctx, src_data, src_linesize, 0, src_h, dst_data, dst_linesize);        ALOGE("*Finish process frame %5d\n",frame_idx);        printf("test-Finish process frame %5d\n",frame_idx);        frame_idx++;        switch(dst_pixfmt){        case AV_PIX_FMT_GRAY8:{            fwrite(dst_data[0],1,dst_w*dst_h,dst_file);             break;                              }        case AV_PIX_FMT_YUV420P:{            fwrite(dst_data[0],1,dst_w*dst_h,dst_file);                 //Y            fwrite(dst_data[1],1,dst_w*dst_h/4,dst_file);               //U            fwrite(dst_data[2],1,dst_w*dst_h/4,dst_file);               //V            break;                                }        case AV_PIX_FMT_YUV422P:{            fwrite(dst_data[0],1,dst_w*dst_h,dst_file);                 //Y            fwrite(dst_data[1],1,dst_w*dst_h/2,dst_file);               //U            fwrite(dst_data[2],1,dst_w*dst_h/2,dst_file);               //V            break;                                }        case AV_PIX_FMT_YUV444P:{            fwrite(dst_data[0],1,dst_w*dst_h,dst_file);                 //Y            fwrite(dst_data[1],1,dst_w*dst_h,dst_file);                 //U            fwrite(dst_data[2],1,dst_w*dst_h,dst_file);                 //V            break;                                }        case AV_PIX_FMT_YUYV422:{            fwrite(dst_data[0],1,dst_w*dst_h*2,dst_file);               //Packed            break;                                }        case AV_PIX_FMT_RGB24:{            fwrite(dst_data[0],1,dst_w*dst_h*3,dst_file);               //Packed            break;                              }        case AV_PIX_FMT_RGB565LE:{            fwrite(dst_data[0],1,dst_w*dst_h*2,dst_file);               //Packed            break;                              }        default:{            printf("Not Support Output Pixel Format.\n");            break;                            }        }    }    sws_freeContext(img_convert_ctx);    free(temp_buffer);    fclose(dst_file);    av_freep(&src_data[0]);    av_freep(&dst_data[0]);    printf("ffmpeg_scale complete \n");    return 0;}

代码比较简单明了,需要注意的是 img_convert_ctx Init Method 方法有两种,
调用swscale中的接口 sws_scale(…)实现缩放,第一种init默认缩放算法为 SWS_BICUBIC ,第二种可以自己设定指定rescale_method

支持格式头文件:ffmpeg-3.1.4\libavutil\pixfmt.h

scale算法种类: ffmpeg-3.1.4\libswscale\swscale.h

至于算法的选择可参考 http://www.cnblogs.com/acloud/archive/2011/10/29/sws_scale.html
有具体的测试数据

0 0
原创粉丝点击