使用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