get_sdl_pix_fmt_and_blendmode()
这个函数的作用,获取输入参数format(FFmpeg像素格式)在SDL中的像素格式,取到的SDL像素格式存在输出参数sdl_pix_fmt中
static void get_sdl_pix_fmt_and_blendmode(int format, Uint32 *sdl_pix_fmt, SDL_BlendMode *sdl_blendmode)
{
int i;
*sdl_blendmode = SDL_BLENDMODE_NONE;
*sdl_pix_fmt = SDL_PIXELFORMAT_UNKNOWN;
if (format == AV_PIX_FMT_RGB32 ||
format == AV_PIX_FMT_RGB32_1 ||
format == AV_PIX_FMT_BGR32 ||
format == AV_PIX_FMT_BGR32_1)
*sdl_blendmode = SDL_BLENDMODE_BLEND;
for (i = 0; i < FF_ARRAY_ELEMS(sdl_texture_format_map) - 1; i++) {
if (format == sdl_texture_format_map[i].format) {
*sdl_pix_fmt = sdl_texture_format_map[i].texture_fmt;
return;
}
}
}
在ffplay.c中定义了一个表sdl_texture_format_map[],其中定义了FFmpeg中一些像素格式与SDL像素格式的映射关系,如下:
static const struct TextureFormatEntry {
enum AVPixelFormat format;
int texture_fmt;
} sdl_texture_format_map[] = {
{ AV_PIX_FMT_RGB8,
SDL_PIXELFORMAT_RGB332 },
{ AV_PIX_FMT_RGB444,
SDL_PIXELFORMAT_RGB444 },
{ AV_PIX_FMT_RGB555,
SDL_PIXELFORMAT_RGB555 },
{ AV_PIX_FMT_BGR555,
SDL_PIXELFORMAT_BGR555 },
{ AV_PIX_FMT_RGB565,
SDL_PIXELFORMAT_RGB565 },
{ AV_PIX_FMT_BGR565,
SDL_PIXELFORMAT_BGR565 },
{ AV_PIX_FMT_RGB24,
SDL_PIXELFORMAT_RGB24 },
{ AV_PIX_FMT_BGR24,
SDL_PIXELFORMAT_BGR24 },
{ AV_PIX_FMT_0RGB32,
SDL_PIXELFORMAT_RGB888 },
{ AV_PIX_FMT_0BGR32,
SDL_PIXELFORMAT_BGR888 },
{ AV_PIX_FMT_NE(RGB0, 0BGR), SDL_PIXELFORMAT_RGBX8888 },
{ AV_PIX_FMT_NE(BGR0, 0RGB), SDL_PIXELFORMAT_BGRX8888 },
{ AV_PIX_FMT_RGB32,
SDL_PIXELFORMAT_ARGB8888 },
{ AV_PIX_FMT_RGB32_1,
SDL_PIXELFORMAT_RGBA8888 },
{ AV_PIX_FMT_BGR32,
SDL_PIXELFORMAT_ABGR8888 },
{ AV_PIX_FMT_BGR32_1,
SDL_PIXELFORMAT_BGRA8888 },
{ AV_PIX_FMT_YUV420P,
SDL_PIXELFORMAT_IYUV },
{ AV_PIX_FMT_YUYV422,
SDL_PIXELFORMAT_YUY2 },
{ AV_PIX_FMT_UYVY422,
SDL_PIXELFORMAT_UYVY },
{ AV_PIX_FMT_NONE,
SDL_PIXELFORMAT_UNKNOWN },
};
可以看到,除了最后一项,其他格式的图像送给SDL是可以直接显示的,不必进行图像转换。
关于这些像素格式的含义,可参考“色彩空间与像素格式”
5.2 重新分配vid_texture
realloc_texture()
根据新得到的SDL像素格式,为&is->vid_texture重新分配空间,如下所示,先SDL_DestroyTexture()销毁,再SDL_CreateTexture()创建
static int realloc_texture(SDL_Texture **texture, Uint32 new_format, int new_width, int new_height, SDL_BlendMode blendmode, int init_texture)
{
Uint32 format;
int access, w, h;
if (!*texture || SDL_QueryTexture(*texture, &format, &access, &w, &h) < 0 || new_width != w || new_height != h || new_format != format) {
void *pixels;
int pitch;
if (*texture)
SDL_DestroyTexture(*texture);
if (!(*texture = SDL_CreateTexture(renderer, new_format, SDL_TEXTUREACCESS_STREAMING, new_width, new_height)))
return -1;
if (SDL_SetTextureBlendMode(*texture, blendmode) < 0)
return -1;
if (init_texture) {
if (SDL_LockTexture(*texture, NULL, &pixels, &pitch) < 0)
return -1;
memset(pixels, 0, pitch * new_height);
SDL_UnlockTexture(*texture);
}
av_log(NULL, AV_LOG_VERBOSE, "Created %dx%d texture with %s.\n", new_width, new_height, SDL_GetPixelFormatName(new_format));
}
return 0;
}
5.3 复用或新分配一个SwsContext
sws_getCachedContext()
*img_convert_ctx = sws_getCachedContext(*img_convert_ctx,
frame->width, frame->height, frame->format, frame->width, frame->height,
AV_PIX_FMT_BGRA, sws_flags, NULL, NULL, NULL);
检查输入参数,第一个输入参数*img_convert_ctx对应形参struct SwsContext *context。
如果context是NULL,调用sws_getContext()重新获取一个context。
如果context不是NULL,检查其他项输入参数是否和context中存储的各参数一样,若不一样,则先释放context再按照新的输入参数重新分配一个context。若一样,直接使用现有的context。
5.4 图像格式转换
if (*img_convert_ctx != NULL) {
uint8_t *pixels[4];
int pitch[4];
if (!SDL_LockTexture(*tex, NULL, (void **)pixels, pitch)) {
sws_scale(*img_convert_ctx, (const uint8_t * const *)frame->data, frame->linesize,
0, frame->height, pixels, pitch);
SDL_UnlockTexture(*tex);
}
}
上述代码有三个步骤:
1) SDL_LockTexture()锁定texture中的一个rect(此处是锁定整个texture),锁定区具有只写属性,用于更新图像数据。pixels指向锁定区。
2) sws_scale()进行图像格式转换,转换后的数据写入pixels指定的区域。pixels包含4个指针,指向一组图像plane。
3) SDL_UnlockTexture()将锁定的区域解锁,将改变的数据更新到视频缓冲区中。
上述三步完成后,texture中已包含经过格式转换后新的图像数据。
补充一下细节,sws_scale()函数原型如下:
/**
* Scale the image slice in srcSlice and put the resulting scaled
* slice in the image in dst. A slice is a sequence of consecutive
* rows in an image.
*
* Slices have to be provided in sequential order, either in
* top-bottom or bottom-top order. If slices are provided in
* non-sequential order the behavior of the function is undefined.
*
* @param c
the scaling context previously created with
*
sws_getContext()
* @param srcSlice the array containing the pointers to the planes of
*
the source slice
* @param srcStride the array containing the strides for each plane of
*
the source image
* @param srcSliceY the position in the source image of the slice to
*
process, that is the number (counted starting from
*
zero) in the image of the first row of the slice
* @param srcSliceH the height of the source slice, that is the number
*
of rows in the slice
* @param dst
the array containing the pointers to the planes of
*
the destination image
* @param dstStride the array containing the strides for each plane of
*
the destination image
* @return
the height of the output slice
*/
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[]);
5.5 图像显示