指導8:軟體縮放
軟體縮放庫libswscale
近來ffmpeg添加了新的介面:libswscale來處理映像縮放。
但是在前面我們使用img_convert來把RGB轉換成YUV12,我們現在使用新的介面。新介面更加標準和快速,而且我相信裡面有了MMX最佳化代碼。換句話說,它是做縮放更好的方式。
我們將用來縮放的基本函數是sws_scale。但一開始,我們必需建立一個SwsContext的概念。這將讓我們進行想要的轉換,然後把它傳遞給 sws_scale函數。類似於在SQL中的預備階段或者是在Python中編譯的規則運算式regexp。要準備這個上下文,我們使用 sws_getContext函數,它需要我們源的寬度和高度,我們想要的寬度和高度,源的格式和想要轉換成的格式,同時還有一些其它的參數和標誌。然後我們像使用img_convert一樣來使用sws_scale函數,唯一不同的是我們傳遞給的是SwsContext:
#include <ffmpeg/swscale.h> // include the header!
int queue_picture(VideoState *is, AVFrame *pFrame, double pts) {
static struct SwsContext *img_convert_ctx;
…
if(vp->bmp) {
SDL_LockYUVOverlay(vp->bmp);
dst_pix_fmt = PIX_FMT_YUV420P;
pict.data[0] = vp->bmp->pixels[0];
pict.data[1] = vp->bmp->pixels[2];
pict.data[2] = vp->bmp->pixels[1];
pict.linesize[0] = vp->bmp->pitches[0];
pict.linesize[1] = vp->bmp->pitches[2];
pict.linesize[2] = vp->bmp->pitches[1];
// Convert the image into YUV format that SDL uses
if(img_convert_ctx == NULL) {
int w = is->video_st->codec->width;
int h = is->video_st->codec->height;
img_convert_ctx = sws_getContext(w, h,
is->video_st->codec->pix_fmt,
w, h, dst_pix_fmt, SWS_BICUBIC,
NULL, NULL, NULL);
if(img_convert_ctx == NULL) {
fprintf(stderr, “Cannot initialize the conversion context!\n”);
exit(1);
}
}
sws_scale(img_convert_ctx, pFrame->data,
pFrame->linesize, 0,
is->video_st->codec->height,
pict.data, pict.linesize);
我們把新的縮放器放到了合適的位置。希望這會讓你知道libswscale能做什麼。
就這樣,我們做完了!編譯我們的播放器:
gcc -o tutorial08 tutorial08.c -lavutil -lavformat -lavcodec -lz -lm `sdl-config –cflags –libs`
享受我們用C寫的少於1000行的電影播放器吧。
當然,還有很多事情要做。
現在還要做什嗎?
我們已經有了一個可以工作的播放器,但是它肯定還不夠好。我們做了很多,但是還有很多要添加的效能:
·錯誤處理。我們代碼中的錯誤處理是無窮的,多處理一些會更好。
·暫停。我們不能暫停電影,這是一個很有用的功能。我們可以在大結構體中使用一個內部暫停變數,當使用者暫停時候就設定它。然後我們的音頻,視頻和解碼線程檢測到它後就不再輸出任何東西。我們也使用av_read_play來支援網路。這很容易解釋,但是你卻不能明顯的計算出,所以把這個作為一個家庭作業,如果你想嘗試的話。提示,可以參考ffplay.c。
·可使用視訊硬體特性。一個參考的例子,請參考Frame Grabbing在Martin的舊的指導中的相關部分。http://www.inb.uni-luebeck.de/~boehme/libavcodec_update.html
·按位元組跳轉。如果你可以按照位元組而不是秒的方式來計算出跳轉位置,那麼對於像VOB檔案一樣的有不連續時間戳記的視頻檔案來說,定位會更加精確。
·丟棄幀。如果視頻落後的太多,我們應當把下一幀丟棄掉而不是設定一個短的重新整理時間。
·支援網路。現在的電影播放器還不能播放網路流媒體。
·支援像YUV檔案一樣的原始視頻流。如果我們的播放器支援的話,因為我們不能猜測出時基和大小,我們應該加入一些參數來進行相應的設定。
·全屏。
·多種參數,例如:不同映像格式;參考ffplay.c中的命令開關。
·其它事情,例如:在結構體中的音頻緩衝區應該對齊。
如果你想瞭解關於ffmpeg更多的事情,我們已經包含了其中的一部分。下一步應該學習的就是如何來編碼多媒體。一個好的入手點是在ffmpeg中的output_example.c檔案。我可以為它寫另外一個指導,但是我沒有足夠的時間來做。