[讀書心得] ffmpeg tutorial (二) Drawing images to screen

這集介紹透過 ffmpeg 將 stream 轉為 Images 輸出, 採用的是 SDL (Simple Direct Layer).
  SDL 的簡單說明:
     (1) Simple DirectMedia Layer
     (2) written by c, but C++ compatible.
     (3) cross-platform (Linux, Windows, Windows CE, BeOS, MacOS, Mac OS X, FreeBSD, OpenBSD, BSD/OS, Solaris and QNX)
     (4) low level access to hardware device, ex. keyboard, audio, mose, joystick, 3D hardware(via OpenGL), 2D video framebuffer.
     (5) GNU LGPL v2 (表示只要透過dynamic library, 即可作為商業用途; 只有再修改SDL源碼才要公布修改的部分跟使用的代碼)
     (6) Language biding (ex. C#, Java, Lisp, Lua, Object-C, PHP, Python, Ruby and smalltalk)
     (7) DirectX之於Windows, 等同SDL之於nonWindows
     (8) Current Version 1.2.15 (Jan. 20, 2012) resource click here.

SDL 對於呈現 image 很多方法, 這裡介紹一種 YUV overlay.(這以前在學校有接觸過, 可當時根本不知道在幹嘛... )
YUV(technically, YCbrCr) 是一種儲存 raw image 的格式, 其他的格式像是 RGB.
Y: brightness/luma component, U and V: color compoents.
SDL接受4種不同的 YUV format, 而 處理速度YV12 是最快的. 另外有個 format YUV420P, 指的是 subsampling rate 4:2:0, 每 4 luma samples 伴隨 1 color sample, 即 color information 只剩 1/4, 通常較省頻寬. P 指的是  planar (Y,U,V 存在不同的Arrays).
ffmpeg 可以將 images 轉為 YUV420P, 這好處是大部分 video stream 已經是這種格式.

所以接下來要做的, 是將 ffmpeg tutorial (一) 原先存成 file 改為傳到 screen.
Initialize SDL
#include 
#include 

if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
  fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
  exit(1); 
}

Creating a Display
SDL_Surface *screen;
screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
if (!screen){
  fprintf(stderr, "SDL: Could not set video mode - existing.\n");
  exit(1);
}
SDL_Surface: SDL 中定義 screen 為 surface.
SDL_SetVideoMode(): 設置一個 大小為 pCodecCtx->width, pCodecCtx->height 的 screen.
(Q1) SDL_SetVideoMode() 第三個參數是 depth. 可 Image 要 depth 幹嘛?
(Q2) 所以 surface (term in SDL) = screen (general term) = window (visible) ?

SDL_Overlap *bmp
bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);
將 Picture 轉為 format YV12.

Displaying the Image
if (frameFinished) {
  SDL_LockYUVOverlay(bmp);
  AVPicture pic;
  pic.data[0] = bmp->pixels[0];
  pic.data[1] = bmp->pixels[2];
  pic.data[2] = bmp->pixels[1];

  pic.linesize[0] = bmp->pitches[0];
  pic.linesize[1] = bmp->pitches[2];
  pic.linesize[2] = bmp->pitches[1];

   img_convert(&pic, PIX_FMT_YUV420P, (AVFrame *) pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);

  SDL_UnlockYUVOverlay(bmp);
  ...
}
這裡主要是將 pFrame 轉為 format PIX_FMT_YUV420P.
* AVPicture 為一個 array of 4 pointers. 因為 YUV420P 只有三個 channels, 所以只有 3 sets.
* pitches 指的是 SDL 上指定的 line data 長度.

Drawing the Image
SDL_Rect rect;
if (frameFinished) {
  ...
  SDL_UnlockYUVOverlay(bmp);
  rect.x = 0;
  rect.y = 0;
  rect.w = pCodecCtx->width;
  rect.h = pCodecCtx->height;
  SDL_DisplayYUVOverlay(bmp, &rect);
}



WARNING: This tutorial is slightly out of date.


參考來源


Comments

Popular posts from this blog

股票評價(Stock Valuation) - 股利折現模型

openwrt feed的使用

How to convert Markdown into HTML