使用SDL2.0在mac OS上渲染視頻畫面
SDL下載:
使用 SDL 來渲染視頻到屏幕。SDL 是 Simple Direct Layer 的縮寫,是一個優秀的跨平臺多媒體庫,你可以從 http://www.libsdl.org 下載 SDL 的庫。需要講SDL導入/Library/Frameworks
目錄下,否則在SDL編譯時會提示Image no found
.SDL 渲染的相關代碼
- 初始化
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
exit(1);
}
- 創建一個screen,用來視頻的展示,一個texture用來加載視頻數據,一個渲染器用來渲染紋理。
//2. create window, Make a screen to put our video
screen = SDL_CreateWindow(
"FFmpeg Tutorial",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
pCodecCtx->width,
pCodecCtx->height,
0
);
if (!screen) {
fprintf(stderr, "SDL: could not create window - exiting\n");
exit(1);
}
// 3. create Render
renderer = SDL_CreateRenderer(screen, -1, 0);
if (!renderer) {
fprintf(stderr, "SDL: could not create renderer - exiting\n");
exit(1);
}
//4. create texture, Allocate a place to put our YUV image on that screen
texture = SDL_CreateTexture(
renderer,
SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STREAMING,
pCodecCtx->width,
pCodecCtx->height
);
if (!texture) {
fprintf(stderr, "SDL: could not create texture - exiting\n");
exit(1);
}
-
YUV數據處理,SDL 創建紋理時使用YV12是最快的,ffmpeg 解碼出來的視頻數據默認是YUV420p,需要使用
sws_scale
函數講420p轉化為YV12.SDL 的 YUV overlay 可以接收一組 YUV 數據然后顯示它。它支持 4 種不同的 YUV 格式,其中 「YV12」 是最快的。另一種 YUV 格式是 「YUV420P」也叫 「I420」,基本上和 「YV12」 是一樣的,就是把 U 和 V 數組換了一下位置。
- YV12:亮度(行×列) + U(行×列/4) + V(行×列/4)
- I420:亮度(行×列) + V(行×列/4) + U(行×列/4)
sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
PIX_FMT_YUV420P,
SWS_BILINEAR,
NULL,
NULL,
NULL);
// set up YV12 pixel array (12 bits per pixel)
yPlaneSz = pCodecCtx->width * pCodecCtx->height;
uvPlaneSz = pCodecCtx->width * pCodecCtx->height / 4;
yPlane = (Uint8*)malloc(yPlaneSz);
uPlane = (Uint8*)malloc(uvPlaneSz);
vPlane = (Uint8*)malloc(uvPlaneSz);
if (!yPlane || !uPlane || !vPlane) {
fprintf(stderr, "Could not allocate pixel buffers - exiting\n");
exit(1);
}
- 創建一個
AVPicture
,給pict賦值,將解碼后的pFrame中的數據填充給pict
AVPicture pict;
uvPitch = pCodecCtx->width / 2;
pict.data[0] = yPlane;
pict.data[1] = uPlane;
pict.data[2] = vPlane;
pict.linesize[0] = pCodecCtx->width;
pict.linesize[1] = uvPitch;
pict.linesize[2] = uvPitch;
// Convert the image into YUV format that SDL uses
sws_scale(sws_ctx, (uint8_t const * const *) pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pict.data,
pict.linesize);
- 將視頻數據轉化為一張紋理圖,并且在屏幕中展示出來
// 紋理繪制
SDL_UpdateYUVTexture(
texture,
NULL,
yPlane,
pCodecCtx->width,
uPlane,
uvPitch,
vPlane,
uvPitch
);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
// 紋理填充到屏幕
SDL_RenderPresent(renderer);
- 最終的效果圖
測試代碼:https://github.com/zjunchao/ffmpeg_tutorial/tree/master/tutorial02