利用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); }
初始化後便可以用於縮放了。
上文已經比較詳細的闡述了ffmpeg的解碼以及縮放原理及流程,然而在實際運用環境中,不管是從實時播放或者是從歷史回放來看,咱們須要的是像素位圖,而不是ffmpeg的結構體。那麼怎麼轉換呢?下文介紹了相關的內容。
做爲實際運用環境中,像素位圖格式,筆者使用的是比較經常使用的YUV格式。
http://blog.csdn.net/searchsun/article/details/2443867
好了,對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