[vlc-devel] [PATCH] Added libvlc_video_take_snapshot_addr to libvlc and related functions to libvlccore

Rémi Denis-Courmont remi at remlab.net
Mon Nov 28 21:28:50 CET 2011


diff --git a/include/vlc/libvlc_media_player.h 
b/include/vlc/libvlc_media_player.h
index a2b5748..30ed0cd 100644
--- a/include/vlc/libvlc_media_player.h
+++ b/include/vlc/libvlc_media_player.h
@@ -1151,6 +1151,25 @@ int libvlc_video_take_snapshot( libvlc_media_player_t 
*p_mi, unsigned num,
                                 unsigned int i_height );
 
 /**
+ * Take a snapshot of the current video window and return the snapshot 
address.
+ *
+ * If i_width AND i_height is 0, original size is used.
+ * If i_width XOR i_height is 0, original aspect-ratio is preserved.
+ *
+ * \param p_mi media player instance
+ * \param num number of video output (typically 0 for the first/only one)
+ * \param psz_addr place to return the snapshot address (you MUST free it 
after use)
+ * \param i_width the snapshot's width
+ * \param i_height the snapshot's height
+ * \return the snapshot memory area size on success, -1 if there was a 
problem
+ */
+LIBVLC_API
+size_t
+libvlc_video_take_snapshot_addr( libvlc_media_player_t *p_mi, unsigned num,
+                                 void **psz_addr, unsigned int i_width, 
+                                 unsigned int i_height );
+
+/**
  * Enable or disable deinterlace filter
  *
  * \param p_mi libvlc media player
diff --git a/lib/libvlc.sym b/lib/libvlc.sym
index 6582a96..0a15838 100644
--- a/lib/libvlc.sym
+++ b/lib/libvlc.sym
@@ -216,6 +216,7 @@ libvlc_video_set_subtitle_file
 libvlc_video_set_teletext
 libvlc_video_set_track
 libvlc_video_take_snapshot
+libvlc_video_take_snapshot_addr

libvlc_video_snapshot or whatever. The function name is long enough as it is.

 libvlc_vlm_add_broadcast
 libvlc_vlm_add_vod
 libvlc_vlm_add_input
diff --git a/lib/video.c b/lib/video.c
index 6e1ea06..deb45b1 100644
--- a/lib/video.c
+++ b/lib/video.c
@@ -34,6 +34,7 @@
 #include <vlc/libvlc_media_player.h>
 
 #include <vlc_common.h>
+#include <vlc_block.h>
 #include <vlc_input.h>
 #include <vlc_vout.h>
 
@@ -158,6 +159,45 @@ libvlc_video_take_snapshot( libvlc_media_player_t *p_mi, 
unsigned num,
     return 0;
 }
 
+size_t
+libvlc_video_take_snapshot_addr( libvlc_media_player_t *p_mi, unsigned num,
+                                 void **psz_addr, unsigned int i_width, 
+                                 unsigned int i_height )
+{
+    block_t *block_buffer;
+    size_t buffer_len = 0;
+    char *buffer = NULL;
+
+    vout_thread_t *p_vout = GetVout( p_mi, num );
+    if (p_vout == NULL)
+        return -1;
+
+    var_SetInteger( p_vout, "snapshot-width", i_width);
+    var_SetInteger( p_vout, "snapshot-height", i_height );
+    var_SetString( p_vout, "snapshot-format", "png" );
+
+    var_TriggerCallback( p_vout, "video-snapshot-addr" );
+
+    block_buffer = (block_t *) var_GetAddress( p_vout, "snapshot-addr" );

You reproduced the bug in the file snapshot code. All those var_* calls are 
not atomic, and thus this function is not reentrant.

You should use a single var_SetAddress() with a big fat ugly structure 
containing all the input and output parameters as the sole parameter. If you 
want to be cleaner, you can define a new dedicated function in the video 
output core. Or you can even write a core function with a nice looking 
prototype, but that does use a big fat ugly structure internally.

+    if( block_buffer == NULL )
+        return -1;
+
+    buffer_len = block_buffer->i_buffer;
+    if( buffer_len <= 0 )
+        return -1;
+
+    buffer = malloc( buffer_len );
+    if( buffer == NULL )
+        return -1;
+
+    psz_addr[0] = buffer;
+    memcpy( buffer, block_buffer->p_buffer, buffer_len );
+
+    var_TriggerCallback( p_vout, "video-snapshot-addr-free" );

You could call block_Release() directly.

But I would postpone the block_Release() to a dedicated "free" function to 
avoid one memory copy.

+
+    return buffer_len;
+}
+
 int libvlc_video_get_size( libvlc_media_player_t *p_mi, unsigned num,
                            unsigned *restrict px, unsigned *restrict py )
 {
diff --git a/src/video_output/vout_intf.c b/src/video_output/vout_intf.c
index e53f41e..09525bf 100644
--- a/src/video_output/vout_intf.c
+++ b/src/video_output/vout_intf.c
@@ -63,6 +63,10 @@ static int FullscreenCallback( vlc_object_t *, char const 
*,
                                vlc_value_t, vlc_value_t, void * );
 static int SnapshotCallback( vlc_object_t *, char const *,
                              vlc_value_t, vlc_value_t, void * );
+static int SnapshotAddrCallback( vlc_object_t *p_this, char const *psz_cmd,
+                       vlc_value_t oldval, vlc_value_t newval, void *p_data 
);
+static int SnapshotAddrFreeCallback( vlc_object_t *p_this, char const 
*psz_cmd,
+                       vlc_value_t oldval, vlc_value_t newval, void *p_data 
);
 static int VideoFilterCallback( vlc_object_t *, char const *,
                                 vlc_value_t, vlc_value_t, void * );
 static int SubSourceCallback( vlc_object_t *, char const *,
@@ -151,6 +155,7 @@ void vout_IntfInit( vout_thread_t *p_vout )
 
     /* Create a few object variables we'll need later on */
     var_Create( p_vout, "snapshot-path", VLC_VAR_STRING | VLC_VAR_DOINHERIT 
);
+    var_Create( p_vout, "snapshot-addr", VLC_VAR_ADDRESS | VLC_VAR_DOINHERIT 
);
     var_Create( p_vout, "snapshot-prefix", VLC_VAR_STRING | VLC_VAR_DOINHERIT 
);
     var_Create( p_vout, "snapshot-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT 
);
     var_Create( p_vout, "snapshot-preview", VLC_VAR_BOOL | VLC_VAR_DOINHERIT 
);
@@ -310,6 +315,18 @@ void vout_IntfInit( vout_thread_t *p_vout )
     var_Change( p_vout, "video-snapshot", VLC_VAR_SETTEXT, &text, NULL );
     var_AddCallback( p_vout, "video-snapshot", SnapshotCallback, NULL );
 
+    /* Add a snapshot address variable */
+    var_Create( p_vout, "video-snapshot-addr", VLC_VAR_VOID | 
VLC_VAR_ISCOMMAND );
+    text.psz_string = _("Snapshot address");
+    var_Change( p_vout, "video-snapshot-addr", VLC_VAR_SETTEXT, &text, NULL 
);
+    var_AddCallback( p_vout, "video-snapshot-addr", SnapshotAddrCallback, 
NULL );
+
+    /* Add a free snapshot address variable */
+    var_Create( p_vout, "video-snapshot-addr-free", VLC_VAR_VOID | 
VLC_VAR_ISCOMMAND );
+    text.psz_string = _("Free snapshot address");
+    var_Change( p_vout, "video-snapshot-addr-free", VLC_VAR_SETTEXT, &text, 
NULL );
+    var_AddCallback( p_vout, "video-snapshot-addr-free", 
SnapshotAddrFreeCallback, NULL );
+
     /* Add a video-filter variable */
     var_Create( p_vout, "video-filter",
                 VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
@@ -452,6 +469,50 @@ exit:
     free( psz_path );
 }
 
+/**
+ * This function will handle a snapshot request and provide the image pointer
+ */
+static void VoutSnapshotAddr( vout_thread_t *p_vout )
+{
+    char *psz_format = var_GetNonEmptyString( p_vout, "snapshot-format" );
+    char *psz_prefix = var_GetNonEmptyString( p_vout, "snapshot-prefix" );
+
+    /* */
+    picture_t *p_picture;
+    block_t *p_image;
+    video_format_t fmt;
+
+    /* 500ms timeout
+     * XXX it will cause trouble with low fps video (< 2fps) */
+    if( vout_GetSnapshot( p_vout, &p_image, &p_picture, &fmt, psz_format, 
500*1000 ) )
+    {
+        p_picture = NULL;
+        p_image = NULL;
+        goto exit;
+    }
+
+    var_SetAddress( p_vout, "snapshot-addr", (void *) p_image );
+
+exit:
+    if( p_picture )
+        picture_Release( p_picture );
+    free( psz_prefix );
+    free( psz_format );
+}
+
+/**
+ * This function will free the snapshot addr
+ */
+static void VoutSnapshotAddrFree( vout_thread_t *p_vout )
+{
+    block_t *p_image = NULL;
+
+    p_image = (block_t *) var_GetAddress( p_vout, "snapshot-addr" );
+
+    if( p_image != NULL )
+        block_Release( p_image );
+}
+
 /*****************************************************************************
  * Handle filters
  *****************************************************************************/
@@ -653,6 +714,28 @@ static int SnapshotCallback( vlc_object_t *p_this, char 
const *psz_cmd,
     return VLC_SUCCESS;
 }
 
+static int SnapshotAddrCallback( vlc_object_t *p_this, char const *psz_cmd,
+                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    vout_thread_t *p_vout = (vout_thread_t *)p_this;
+    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
+    VLC_UNUSED(newval); VLC_UNUSED(p_data);
+
+    VoutSnapshotAddr( p_vout );
+    return VLC_SUCCESS;
+}
+
+static int SnapshotAddrFreeCallback( vlc_object_t *p_this, char const 
*psz_cmd,
+                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    vout_thread_t *p_vout = (vout_thread_t *)p_this;
+    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
+    VLC_UNUSED(newval); VLC_UNUSED(p_data);
+
+    VoutSnapshotAddrFree( p_vout );
+    return VLC_SUCCESS;
+}
+
 static int VideoFilterCallback( vlc_object_t *p_this, char const *psz_cmd,
                                 vlc_value_t oldval, vlc_value_t newval, void 
*p_data)
 {
-- 
1.7.4.1



-- 
Rémi Denis-Courmont
http://www.remlab.net/
http://fi.linkedin.com/in/remidenis



More information about the vlc-devel mailing list