From: Reinhard N. <rn...@gm...> - 2008-03-04 16:41:46
|
# HG changeset patch # User Reinhard Nißl <rn...@gm...> # Date 1204485867 -3600 # Node ID 492257577b4d7e541b7207e36dd0b08f9fb2cdcc # Parent 4d6ffe8aac0a9ee031b44d9b4fbf835596e12de5 Provide safe and convenient implementations of xine_get_current_frame(). xine_get_current_frame() relies on the caller to provide a sufficiently sized buffer. To calculate the required size of the buffer, one has to call xine_get_current_frame() to retrieve the necessary parameters. But as the image can change between two successive calls one has to pause the stream for consistency. To improve the situation, xine_get_current_frame_s() has been introduced which requires to specify the buffer size when an image is going to be retrieved. Furthermore, it will return the required/used buffer size. In that way, it can prevent copying data into a too small buffer and therefore can be considered safe. For convenience, xine_get_current_frame_alloc() is provided which takes care to allocate a sufficiently sized buffer. This function avoids pausing the stream as the image will be returned in a single call. diff -r 492257577b4d7e541b7207e36dd0b08f9fb2cdcc -r 4d6ffe8aac0a9ee031b44d9b4fbf835596e12de5 include/xine.h.in --- a/include/xine.h.in Sun Mar 02 20:24:27 2008 +0100 +++ b/include/xine.h.in Sun Mar 02 18:57:51 2008 +0100 @@ -418,13 +418,37 @@ int xine_get_param (xine_stream_t *stre * image format can be YUV 4:2:0 or 4:2:2 * will copy the image data into memory that <img> points to * (interleaved for yuv 4:2:2 or planary for 4:2:0) - * - * returns 1 on success, 0 failure. + * + * xine_get_current_frame() requires that <img> must be able + * to hold the image data. Use a NULL pointer to retrieve the + * necessary parameters for calculating the buffer size. Be + * aware that the image can change between two successive calls + * so you better pause the stream. + * + * xine_get_current_frame_s() requires to specify the buffer + * size and it returns the needed / used size. It won't copy + * image data into a too small buffer. + * + * xine_get_current_frame_alloc() takes care of allocating + * a buffer on it's own, so image data can be retrieved by + * a single call without the need to pause the stream. + * + * all functions return 1 on success, 0 failure. */ int xine_get_current_frame (xine_stream_t *stream, int *width, int *height, int *ratio_code, int *format, uint8_t *img) XINE_PROTECTED; + +int xine_get_current_frame_s (xine_stream_t *stream, + int *width, int *height, + int *ratio_code, int *format, + uint8_t *img, int *size) XINE_PROTECTED; + +int xine_get_current_frame_alloc (xine_stream_t *stream, + int *width, int *height, + int *ratio_code, int *format, + uint8_t **img, int *size) XINE_PROTECTED; /* xine image formats */ #define XINE_IMGFMT_YV12 (('2'<<24)|('1'<<16)|('V'<<8)|'Y') diff -r 492257577b4d7e541b7207e36dd0b08f9fb2cdcc -r 4d6ffe8aac0a9ee031b44d9b4fbf835596e12de5 src/xine-engine/xine.c --- a/src/xine-engine/xine.c Sun Mar 02 20:24:27 2008 +0100 +++ b/src/xine-engine/xine.c Sun Mar 02 18:57:51 2008 +0100 @@ -1915,11 +1915,12 @@ int xine_get_pos_length (xine_stream_t * return 1; } -int xine_get_current_frame (xine_stream_t *stream, int *width, int *height, - int *ratio_code, int *format, - uint8_t *img) { +static int _x_get_current_frame_impl (xine_stream_t *stream, int *width, int *height, + int *ratio_code, int *format, + uint8_t **img, int *size, int alloc_img) { vo_frame_t *frame; + int required_size; stream->xine->port_ticket->acquire(stream->xine->port_ticket, 0); frame = stream->video_out->get_last_frame (stream->video_out); @@ -1945,20 +1946,58 @@ int xine_get_current_frame (xine_stream_ *format = frame->format; - if (img){ + switch (*format) { + + case XINE_IMGFMT_YV12: + required_size = *width * *height + + ((*width + 1) / 2) * ((*height + 1) / 2) + + ((*width + 1) / 2) * ((*height + 1) / 2); + break; + + case XINE_IMGFMT_YUY2: + required_size = *width * *height + + ((*width + 1) / 2) * *height + + ((*width + 1) / 2) * *height; + break; + + default: + xprintf (stream->xine, XINE_VERBOSITY_DEBUG, + "xine: error, snapshot function not implemented for format 0x%x\n", frame->format); + _x_abort (); + } + + if (alloc_img) { + /* return size if requested */ + if (size) + *size = required_size; + /* allocate img or fail */ + if (!(*img = xine_xmalloc (required_size))) + return 0; + } else { + /* fail if supplied buffer is to small */ + if (*img && size && *size < required_size) { + *size = required_size; + return 0; + } + /* return size if requested */ + if (size) + *size = required_size; + } + + if (*img) { switch (frame->format) { case XINE_IMGFMT_YV12: yv12_to_yv12( /* Y */ frame->base[0], frame->pitches[0], - img, frame->width, + *img, frame->width, /* U */ frame->base[1], frame->pitches[1], - img+frame->width*frame->height, frame->width/2, + *img+frame->width*frame->height, frame->width/2, /* V */ frame->base[2], frame->pitches[2], - img+frame->width*frame->height+frame->width*frame->height/4, frame->width/2, + *img+frame->width*frame->height+frame->width*frame->height/4, frame->width/2, /* width x height */ frame->width, frame->height); break; @@ -1968,7 +2007,7 @@ int xine_get_current_frame (xine_stream_ /* src */ frame->base[0], frame->pitches[0], /* dst */ - img, frame->width*2, + *img, frame->width*2, /* width x height */ frame->width, frame->height); break; @@ -1980,6 +2019,25 @@ int xine_get_current_frame (xine_stream_ } } return 1; +} + +int xine_get_current_frame_alloc (xine_stream_t *stream, int *width, int *height, + int *ratio_code, int *format, + uint8_t **img, int *size) { + uint8_t *no_img = NULL; + return _x_get_current_frame_impl(stream, width, height, ratio_code, format, img ? img : &no_img, size, img != NULL); +} + +int xine_get_current_frame_s (xine_stream_t *stream, int *width, int *height, + int *ratio_code, int *format, + uint8_t *img, int *size) { + return (!img || size) && _x_get_current_frame_impl(stream, width, height, ratio_code, format, &img, size, 0); +} + +int xine_get_current_frame (xine_stream_t *stream, int *width, int *height, + int *ratio_code, int *format, + uint8_t *img) { + return _x_get_current_frame_impl(stream, width, height, ratio_code, format, &img, NULL, 0); } int xine_get_video_frame (xine_stream_t *stream, |