FFmpeg縮放swscale詳解 <轉>

縮放:

           

利用ffmpeg進行圖像數據格式的轉換以及圖片的縮放應用中,主要用到了swscale.h文件中的三個函數,分別是:算法

  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);
      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[]);
      void sws_freeContext(struct SwsContext *swsContext);


sws_getContext函數能夠看作是初始化函數,它的參數定義分別爲:數組

      int srcW,int srcH 爲原始圖像數據的高和寬;數據結構

      int dstW,int dstH 爲輸出圖像數據的高和寬;ide

      enum AVPixelFormat srcFormat 爲輸入和輸出圖片數據的類型;eg:AV_PIX_FMT_YUV420、PAV_PIX_FMT_RGB24;函數

      int flags 爲scale算法種類;eg:SWS_BICUBIC、SWS_BICUBLIN、SWS_POINT、SWS_SINC;ui

      SwsFilter *srcFilter ,SwsFilter *dstFilter,const double *param 能夠不用管,全爲NULL便可;spa

  sws_scale函數則爲執行函數,它的參數定義分別爲:.net

      struct SwsContext *c 爲sws_getContext函數返回的值;指針

      const uint8_t *const srcSlice[],uint8_t *const dst[] 爲輸入輸出圖像數據各顏色通道的buffer指針數組;code

      const int srcStride[],const int dstStride[] 爲輸入輸出圖像數據各顏色通道每行存儲的字節數數組;     

      int srcSliceY 爲從輸入圖像數據的第多少列開始逐行掃描,一般設爲0;

      int srcSliceH 爲須要掃描多少行,一般爲輸入圖像數據的高度;

  sws_freeContext函數爲結束函數,它的參數即爲sws_getContext函數返回的值;

       作一個實際縮放YUV420函數打包實例以下:

int ScaleImg(AVCodecContext *pCodecCtx,AVFrame *src_picture,AVFrame *dst_picture,int nDstH ,int nDstW )
{
int i ;
int nSrcStride[3];
int nDstStride[3];
int nSrcH = pCodecCtx->height;
int nSrcW = pCodecCtx->width;
struct SwsContext* m_pSwsContext;


uint8_t *pSrcBuff[3] = {src_picture->data[0],src_picture->data[1], src_picture->data[2]};


nSrcStride[0] = nSrcW ;
nSrcStride[1] = nSrcW/2 ;
nSrcStride[2] = nSrcW/2 ;




dst_picture->linesize[0] = nDstW;
dst_picture->linesize[1] = nDstW / 2;
dst_picture->linesize[2] = nDstW / 2;


printf("nSrcW%d\n",nSrcW);


m_pSwsContext = sws_getContext(nSrcW, nSrcH, PIX_FMT_YUV420P,
nDstW, nDstH, PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL, NULL, NULL);


if (NULL == m_pSwsContext)
{
printf("ffmpeg get context error!\n");
exit (-1);
}


sws_scale(m_pSwsContext, src_picture->data,src_picture->linesize, 0, pCodecCtx->height,dst_picture->data,dst_picture->linesize);


printf("line0:%d line1:%d line2:%d\n",dst_picture->linesize[0] ,dst_picture->linesize[1] ,dst_picture->linesize[2]);
sws_freeContext(m_pSwsContext);


return 1 ;
}

函數很簡單,申請環境初始指針,後縮放便可。讀到此文的朋友,這個函數能夠直接拷貝使用喲。若是有疑問能夠留言或者郵件:leoluopy@gmail.com

 

RGB的縮放能夠參考下面:

int ScaleYUVImgToRGB(int nSrcW,int nSrcH ,uint8_t* src_data,int *linesize,int nDstW ,int nDstH )  
{  
    int i ; int ret ;  FILE *nRGB_file ;

    AVFrame *nDst_picture ;
    struct SwsContext* m_pSwsContext;  

    nDst_picture = avcodec_alloc_frame();
    if (!nDst_picture){
        printf("nDst_picture avcodec_alloc_frame failed\n");
        exit(1);
    }
    if(avpicture_alloc((AVPicture *)nDst_picture,PIX_FMT_RGB24,nDstW, nDstH)<0){
        printf("dst_picture avpicture_alloc failed\n");
        exit(1);
    }
    m_pSwsContext = sws_getContext(nSrcW, nSrcH, PIX_FMT_YUV420P,  
        nDstW, nDstH, PIX_FMT_RGB24,  
        SWS_BICUBIC,  
        NULL, NULL, NULL);  

    if (NULL == m_pSwsContext)  
    {  
        printf("ffmpeg get context error!\n");  
        exit (-1);  
    }   

    ret = sws_scale(m_pSwsContext, src_data,linesize, 0,nSrcH,nDst_picture->data,nDst_picture->linesize);  

    nRGB_file = fopen("..\\YUV_STREAM\\RGBFile.rgb","ab+");
    fwrite(nDst_picture->data[0],nDstW*nDstH*3,1,nRGB_file);
    fclose(nRGB_file);

    sws_freeContext(m_pSwsContext);  
    avpicture_free((AVPicture *)nDst_picture);

    return 0;  
}

參數data  和 linesize 參考yuv平面指針便可。

 

 同時若是不想使用AVPicture結構的話,能夠參考下面的:(注意不一樣圖像類型,linesize必定要寫對)

char* H264Decoder_c::ScaleYUVImgToRGB(int nSrcW,int nSrcH ,uint8_t** src_data,int *linesize,int nDstW ,int nDstH )
{
    int i ; int ret ;  FILE *nRGB_file ;

    struct SwsContext* m_pSwsContext;
    char*  out_Img[3];
    int out_linesize[3];
    out_linesize[0] = 2*nDstW ; //out_linesize[1] = nDstW ;out_linesize[2] = nDstW ;
    out_Img[0] = g_RGBImg ;

    m_pSwsContext = sws_getContext(nSrcW, nSrcH, PIX_FMT_YUV420P,
        nDstW, nDstH, PIX_FMT_RGB565,
        SWS_BICUBIC,
        NULL, NULL, NULL);

    if (NULL == m_pSwsContext)
    {
        printf("ffmpeg get context error!\n");
        exit (-1);
    }

    ret = sws_scale(m_pSwsContext, src_data,linesize, 0,nSrcH,(uint8_t**)out_Img,out_linesize);
#if 0
    nRGB_file = fopen("./RGBFile.rgb","ab+");
    fwrite(out_Img[0],nDstW*nDstH*2,1,nRGB_file);
    fclose(nRGB_file);

#endif

    sws_freeContext(m_pSwsContext);

    return out_Img[0];
}

目的位圖的空間申請:

       注意:上面的縮放函數若是直接使用而在沒有解碼成功或者沒有申請目的位圖空間時,將報段錯誤。

      緣由:沒有解碼成功,位圖源地址將是指向空的地址,目的位圖地址一樣。   

      申請目的位圖的方式:

dst_picture = avcodec_alloc_frame();
if (!dst_picture){
return ;
}
if(avpicture_alloc((AVPicture *)dst_picture, c->pix_fmt,c->width*2, c->height*2)<0){
printf("dst_picture allocate failed\n");
exit(1);
}

初始化後便可以用於縮放了。

 

 

圖像的內存Dump方法:

        上文已經比較詳細的闡述了ffmpeg的解碼以及縮放原理及流程,然而在實際運用環境中,不管是從實時播放或者是從歷史回放來看,咱們須要的是像素位圖,而不是ffmpeg的結構體。那麼怎麼轉換呢?下文介紹了相關的內容。

 

        做爲實際運用環境中,像素位圖格式,筆者使用的是比較經常使用的YUV格式。

 

        編解碼圖像格式

          承接上文繼續,在大部分現場環境下,爲了節省傳送帶寬以及提升系統工做效率,視頻原始位圖格式以及解碼後展現格式通常使用YUV420。
          其中YV12以及IYUV是最多見的格式。
          簡單的說,YUV格式又分爲平面格式以及打包格式。他們各有利弊。本文使用的是YUV平面格式即三通道分別使用不一樣入口地址存儲,這樣的好處是,與ffmpeg解碼接口方面,AVFrame中數據結構能夠便捷拷貝圖像信息。

         YV12:

     

         IYUV 

 
 
          這裏作簡單的敘述:詳細能夠參考:
 

 

          http://blog.csdn.net/searchsun/article/details/2443867

 

     如何Dump

           好了,對YUV格式又初步瞭解後,下面介紹若是導出這像素位圖數據。ffmpeg將圖像的亮度以及色差信息保存在AVFrame中的data[0]、data[1]、data[2]中。

          詳細參考:

 

AVFrame和AVPicture對比:

http://yul100887.blog.163.com/blog/static/200336135201211143525930/

 

           全部操做均是針對這三個指針展開的,以下:

pgm_save(picture->data[0], picture->linesize[0], //Y
c->width, c->height, outfilename);
pgm_save(picture->data[1], picture->linesize[1],
c->width/2, c->height/2, outfilename); //U
pgm_save(picture->data[2], picture->linesize[2],
c->width/2, c->height/2, outfilename);  //V
void pgm_save(unsigned char *buf,int wrap, int xsize,int ysize,char *filename)
{
    FILE *f;
    int i;


f=fopen(filename,"ab+");   


for(i=0;i<ysize;i++)
{
fwrite(buf + i * wrap, 1, xsize, f ); 
}
fclose(f);
}

 代碼對YUV三個像素通道分開dump,讀者能夠根據本身的須要對函數進行包裝。data[0] 是亮度信息入口指針,同時傳入圖像長寬,以及存儲內存區域行寬。 data[1]  data[2] 相似。

 

                最後須要注意的是:linesize老是容易被遺忘,livesize[0]=height ,livesize[1]=height/2 ,livesize[2]=height /2,

==================================================================================

原帖地址:http://blog.csdn.net/gubenpeiyuan/article/details/19548019?utm_source=tuicool

其參考地址:

參考文章:

 

使用ffmpeg進行圖像格式轉換及縮放

http://blog.csdn.net/skys_broyal/article/details/10337147

AVFrame和AVPicture對比:

http://yul100887.blog.163.com/blog/static/200336135201211143525930/

FFMPEG 實現 YUV,RGB各類圖像原始數據之間的轉換(swscale)

http://blog.csdn.net/leixiaohua1020/article/details/14215391

ffmpeg編解碼H264

http://blog.csdn.net/chinabinlang/article/details/7088590

h264檢測是I幀仍是P幀

http://blog.csdn.net/zgyulongfei/article/details/7558031

相關文章
相關標籤/搜索