FFMPEG-初探認識-YUV轉RGB用例

來源:互聯網
上載者:User

前段時間因為項目需要,嘗試通過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
有具體的測試資料

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.