summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinhard Nißl <rnissl@gmx.de>2008-03-02 20:24:27 +0100
committerReinhard Nißl <rnissl@gmx.de>2008-03-02 20:24:27 +0100
commitc3247cea37ea7702703826df6b68a9754f9b8984 (patch)
tree3adc342997f995e97436a5dceda1e4ed1ba386ec
parentd93c88ae06cd4452c8cfa5297def0f6e07c25fd5 (diff)
downloadxine-lib-c3247cea37ea7702703826df6b68a9754f9b8984.tar.gz
xine-lib-c3247cea37ea7702703826df6b68a9754f9b8984.tar.bz2
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.
-rw-r--r--include/xine.h.in26
-rw-r--r--src/xine-engine/xine.c74
2 files changed, 91 insertions, 9 deletions
diff --git a/include/xine.h.in b/include/xine.h.in
index ceb87780a..979094779 100644
--- a/include/xine.h.in
+++ b/include/xine.h.in
@@ -418,14 +418,38 @@ int xine_get_param (xine_stream_t *stream, int param) XINE_PROTECTED;
* 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)
+ *
+ * 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.
*
- * returns 1 on success, 0 failure.
+ * 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')
#define XINE_IMGFMT_YUY2 (('2'<<24)|('Y'<<16)|('U'<<8)|'Y')
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index 0558f2f81..fb2c08b04 100644
--- a/src/xine-engine/xine.c
+++ b/src/xine-engine/xine.c
@@ -1915,11 +1915,12 @@ int xine_get_pos_length (xine_stream_t *stream, int *pos_stream,
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_t *stream, int *width, int *height,
*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_t *stream, int *width, int *height,
/* src */
frame->base[0], frame->pitches[0],
/* dst */
- img, frame->width*2,
+ *img, frame->width*2,
/* width x height */
frame->width, frame->height);
break;
@@ -1982,6 +2021,25 @@ int xine_get_current_frame (xine_stream_t *stream, int *width, int *height,
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,
int timestamp, /* msec */
int *width, int *height,