]> git.sesse.net Git - vlc/blobdiff - src/video_output/vout_pictures.c
vout_pictures: Use unsigned for width and height in picture_Export.
[vlc] / src / video_output / vout_pictures.c
index 8033f38ec6b356c8adce906879b881cde8a5a252..83bfb59651df88267d19c0eabcae30295da83834 100644 (file)
@@ -38,6 +38,8 @@
 #include <vlc_filter.h>
 #include <vlc_image.h>
 #include <vlc_block.h>
+#include <vlc_picture_fifo.h>
+#include <vlc_picture_pool.h>
 
 #include "vout_pictures.h"
 #include "vout_internal.h"
@@ -333,7 +335,7 @@ static void vout_UnlockPicture( vout_thread_t *p_vout, picture_t *p_picture )
  * thread which direct buffer needs to be displayed.
  */
 picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
-                               subpicture_t *p_subpic, bool b_paused )
+                               subpicture_t *p_subpic, mtime_t render_date )
 {
     if( p_pic == NULL )
         return NULL;
@@ -354,7 +356,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
 
             spu_RenderSubpictures( p_vout->p_spu,
                                    PP_OUTPUTPICTURE[0], &p_vout->fmt_out,
-                                   p_subpic, &p_vout->fmt_in, b_paused );
+                                   p_subpic, &p_vout->fmt_in, render_date );
 
             vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );
 
@@ -381,7 +383,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
         picture_Copy( PP_OUTPUTPICTURE[0], p_pic );
         spu_RenderSubpictures( p_vout->p_spu,
                                PP_OUTPUTPICTURE[0], &p_vout->fmt_out,
-                               p_subpic, &p_vout->fmt_in, b_paused );
+                               p_subpic, &p_vout->fmt_in, render_date );
 
         vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );
 
@@ -417,7 +419,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
         /* Render subpictures on the first direct buffer */
         spu_RenderSubpictures( p_vout->p_spu,
                                p_tmp_pic, &p_vout->fmt_out,
-                               p_subpic, &p_vout->fmt_in, b_paused );
+                               p_subpic, &p_vout->fmt_in, render_date );
 
         if( vout_LockPicture( p_vout, &p_vout->p_picture[0] ) )
             return NULL;
@@ -436,7 +438,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
         /* Render subpictures on the first direct buffer */
         spu_RenderSubpictures( p_vout->p_spu,
                                &p_vout->p_picture[0], &p_vout->fmt_out,
-                               p_subpic, &p_vout->fmt_in, b_paused );
+                               p_subpic, &p_vout->fmt_in, render_date );
     }
 
     vout_UnlockPicture( p_vout, &p_vout->p_picture[0] );
@@ -552,6 +554,7 @@ int __vout_AllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
                             vlc_fourcc_t i_chroma,
                             int i_width, int i_height, int i_aspect )
 {
+    VLC_UNUSED(p_this);
     int i_bytes, i_index, i_width_aligned, i_height_aligned;
 
     /* Make sure the real dimensions are a multiple of 16 */
@@ -649,6 +652,20 @@ static void PictureReleaseCallback( picture_t *p_picture )
     picture_Delete( p_picture );
 }
 
+/*****************************************************************************
+ *
+ *****************************************************************************/
+void picture_Reset( picture_t *p_picture )
+{
+    /* */
+    p_picture->date = VLC_TS_INVALID;
+    p_picture->b_force = false;
+    p_picture->b_progressive = false;
+    p_picture->i_nb_fields = 0;
+    p_picture->b_top_field_first = false;
+    picture_CleanupQuant( p_picture );
+}
+
 /*****************************************************************************
  *
  *****************************************************************************/
@@ -900,25 +917,65 @@ int picture_Setup( picture_t *p_picture, vlc_fourcc_t i_chroma, int i_width, int
 /*****************************************************************************
  *
  *****************************************************************************/
-picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_aspect )
+picture_t *picture_NewFromResource( const video_format_t *p_fmt, const picture_resource_t *p_resource )
 {
+    video_format_t fmt = *p_fmt;
+
+    /* It is needed to be sure all informations are filled */
+    video_format_Setup( &fmt, p_fmt->i_chroma,
+                              p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
+
+    /* */
     picture_t *p_picture = calloc( 1, sizeof(*p_picture) );
     if( !p_picture )
         return NULL;
 
-    if( __vout_AllocatePicture( NULL, p_picture,
-                                i_chroma, i_width, i_height, i_aspect ) )
+    if( p_resource )
     {
-        free( p_picture );
-        return NULL;
-    }
+        if( picture_Setup( p_picture, fmt.i_chroma, fmt.i_width, fmt.i_height, fmt.i_aspect ) )
+        {
+            free( p_picture );
+            return NULL;
+        }
+        p_picture->p_sys = p_resource->p_sys;
 
+        for( int i = 0; i < p_picture->i_planes; i++ )
+        {
+            p_picture->p[i].p_pixels = p_resource->p[i].p_pixels;
+            p_picture->p[i].i_lines  = p_resource->p[i].i_lines;
+            p_picture->p[i].i_pitch  = p_resource->p[i].i_pitch;
+        }
+    }
+    else
+    {
+        if( __vout_AllocatePicture( NULL, p_picture,
+                                    fmt.i_chroma, fmt.i_width, fmt.i_height, fmt.i_aspect ) )
+        {
+            free( p_picture );
+            return NULL;
+        }
+    }
+    /* */
+    p_picture->format = fmt;
     p_picture->i_refcount = 1;
     p_picture->pf_release = PictureReleaseCallback;
     p_picture->i_status = RESERVED_PICTURE;
 
     return p_picture;
 }
+picture_t *picture_NewFromFormat( const video_format_t *p_fmt )
+{
+    return picture_NewFromResource( p_fmt, NULL );
+}
+picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_aspect )
+{
+    video_format_t fmt;
+
+    memset( &fmt, 0, sizeof(fmt) );
+    video_format_Setup( &fmt, i_chroma, i_width, i_height, i_aspect );
+
+    return picture_NewFromFormat( &fmt );
+}
 
 /*****************************************************************************
  *
@@ -985,7 +1042,7 @@ int picture_Export( vlc_object_t *p_obj,
                     video_format_t *p_fmt,
                     picture_t *p_picture,
                     vlc_fourcc_t i_format,
-                    int i_override_width, int i_override_height )
+                    unsigned i_override_width, unsigned i_override_height )
 {
     /* */
     video_format_t fmt_in = p_picture->format;
@@ -1001,30 +1058,35 @@ int picture_Export( vlc_object_t *p_obj,
     fmt_out.i_sar_num =
     fmt_out.i_sar_den = 1;
     fmt_out.i_chroma  = i_format;
-    fmt_out.i_width   = i_override_width;
-    fmt_out.i_height  = i_override_height;
 
-    if( fmt_out.i_height == 0 && fmt_out.i_width > 0 )
+    /* compute original width/height */
+    unsigned int i_original_width;
+    unsigned int i_original_height;
+    if( fmt_in.i_sar_num >= fmt_in.i_sar_den )
     {
-        fmt_out.i_height = fmt_in.i_height * fmt_out.i_width / fmt_in.i_width;
-        const int i_height = fmt_out.i_height * fmt_in.i_sar_den / fmt_in.i_sar_num;
-        if( i_height > 0 )
-            fmt_out.i_height = i_height;
+        i_original_width = fmt_in.i_width * fmt_in.i_sar_num / fmt_in.i_sar_den;
+        i_original_height = fmt_in.i_height;
     }
     else
     {
-        if( fmt_out.i_width == 0 && fmt_out.i_height > 0 )
-        {
-            fmt_out.i_width = fmt_in.i_width * fmt_out.i_height / fmt_in.i_height;
-        }
-        else
-        {
-            fmt_out.i_width = fmt_in.i_width;
-            fmt_out.i_height = fmt_in.i_height;
-        }
-        const int i_width = fmt_out.i_width * fmt_in.i_sar_num / fmt_in.i_sar_den;
-        if( i_width > 0 )
-            fmt_out.i_width = i_width;
+        i_original_width =  fmt_in.i_width;
+        i_original_height = fmt_in.i_height * fmt_in.i_sar_den / fmt_in.i_sar_num;
+    }
+
+    /* */
+    fmt_out.i_width  = i_override_width > 0 ? i_override_width : i_original_width;
+    fmt_out.i_height = i_override_height > 0 ? i_override_height : i_original_height;
+
+    /* scale if only one direction is provided */
+    if( fmt_out.i_height == 0 && fmt_out.i_width > 0 )
+    {
+        fmt_out.i_height = fmt_in.i_height * fmt_out.i_width
+                     * fmt_in.i_sar_den / fmt_in.i_width / fmt_in.i_sar_num;
+    }
+    else if( fmt_out.i_width == 0 && fmt_out.i_height > 0 )
+    {
+        fmt_out.i_width  = fmt_in.i_width * fmt_out.i_height
+                     * fmt_in.i_sar_num / fmt_in.i_height / fmt_in.i_sar_den;
     }
 
     image_handler_t *p_image = image_HandlerCreate( p_obj );
@@ -1049,3 +1111,269 @@ int picture_Export( vlc_object_t *p_obj,
 /*****************************************************************************
  *
  *****************************************************************************/
+struct picture_fifo_t
+{
+    vlc_mutex_t lock;
+    picture_t *p_first;
+    picture_t **pp_last;
+};
+
+static void PictureFifoReset( picture_fifo_t *p_fifo )
+{
+    p_fifo->p_first = NULL;
+    p_fifo->pp_last = &p_fifo->p_first;
+}
+static void PictureFifoPush( picture_fifo_t *p_fifo, picture_t *p_picture )
+{
+    assert( !p_picture->p_next );
+    *p_fifo->pp_last = p_picture;
+    p_fifo->pp_last = &p_picture->p_next;
+}
+static picture_t *PictureFifoPop( picture_fifo_t *p_fifo )
+{
+    picture_t *p_picture = p_fifo->p_first;
+
+    if( p_picture )
+    {
+        p_fifo->p_first = p_picture->p_next;
+        if( !p_fifo->p_first )
+            p_fifo->pp_last = &p_fifo->p_first;
+    }
+    return p_picture;
+}
+
+picture_fifo_t *picture_fifo_New(void)
+{
+    picture_fifo_t *p_fifo = malloc( sizeof(*p_fifo) );
+    if( !p_fifo )
+        return NULL;
+
+    vlc_mutex_init( &p_fifo->lock );
+    PictureFifoReset( p_fifo );
+    return p_fifo;
+}
+
+void picture_fifo_Push( picture_fifo_t *p_fifo, picture_t *p_picture )
+{
+    vlc_mutex_lock( &p_fifo->lock );
+    PictureFifoPush( p_fifo, p_picture );
+    vlc_mutex_unlock( &p_fifo->lock );
+}
+picture_t *picture_fifo_Pop( picture_fifo_t *p_fifo )
+{
+    vlc_mutex_lock( &p_fifo->lock );
+    picture_t *p_picture = PictureFifoPop( p_fifo );
+    vlc_mutex_unlock( &p_fifo->lock );
+
+    return p_picture;
+}
+picture_t *picture_fifo_Peek( picture_fifo_t *p_fifo )
+{
+    vlc_mutex_lock( &p_fifo->lock );
+    picture_t *p_picture = p_fifo->p_first;
+    if( p_picture )
+        picture_Hold( p_picture );
+    vlc_mutex_unlock( &p_fifo->lock );
+
+    return p_picture;
+}
+void picture_fifo_Flush( picture_fifo_t *p_fifo, mtime_t i_date, bool b_below )
+{
+    picture_t *p_picture;
+
+    vlc_mutex_lock( &p_fifo->lock );
+
+    p_picture = p_fifo->p_first;
+    PictureFifoReset( p_fifo );
+
+    picture_fifo_t tmp;
+    PictureFifoReset( &tmp );
+
+    while( p_picture )
+    {
+        picture_t *p_next = p_picture->p_next;
+
+        p_picture->p_next = NULL;
+        if( (  b_below && p_picture->date <= i_date ) ||
+            ( !b_below && p_picture->date >= i_date ) )
+            PictureFifoPush( &tmp, p_picture );
+        else
+            PictureFifoPush( p_fifo, p_picture );
+        p_picture = p_next;
+    }
+    vlc_mutex_unlock( &p_fifo->lock );
+
+    for( ;; )
+    {
+        picture_t *p_picture = PictureFifoPop( &tmp );
+        if( !p_picture )
+            break;
+        picture_Release( p_picture );
+    }
+}
+void picture_fifo_OffsetDate( picture_fifo_t *p_fifo, mtime_t i_delta )
+{
+    vlc_mutex_lock( &p_fifo->lock );
+    for( picture_t *p_picture = p_fifo->p_first; p_picture != NULL; )
+    {
+        p_picture->date += i_delta;
+        p_picture = p_picture->p_next;
+    }
+    vlc_mutex_unlock( &p_fifo->lock );
+}
+void picture_fifo_Delete( picture_fifo_t *p_fifo )
+{
+    picture_fifo_Flush( p_fifo, INT64_MAX, true );
+    vlc_mutex_destroy( &p_fifo->lock );
+}
+
+/*****************************************************************************
+ *
+ *****************************************************************************/
+struct picture_release_sys_t
+{
+    /* Saved release */
+    void (*pf_release)( picture_t * );
+    picture_release_sys_t *p_release_sys;
+
+    /* */
+    int64_t i_tick;
+};
+
+struct picture_pool_t
+{
+    int64_t i_tick;
+
+    int i_picture;
+    picture_t **pp_picture;
+};
+
+static void PicturePoolPictureRelease( picture_t * );
+
+picture_pool_t *picture_pool_New( int i_picture, picture_t *pp_picture[] )
+{
+    picture_pool_t *p_pool = calloc( 1, sizeof(*p_pool) );
+    if( !p_pool )
+        return NULL;
+
+    p_pool->i_tick = 1;
+    p_pool->i_picture = i_picture;
+    p_pool->pp_picture = calloc( p_pool->i_picture, sizeof(*p_pool->pp_picture) );
+
+    for( int i = 0; i < i_picture; i++ )
+    {
+        picture_t *p_picture = pp_picture[i];
+
+        /* The pool must be the only owner of the picture */
+        assert( p_picture->i_refcount == 1 );
+
+        /* Install the new release callback */
+        picture_release_sys_t *p_release_sys = malloc( sizeof(*p_release_sys) );
+        p_release_sys->pf_release = p_picture->pf_release;
+        p_release_sys->p_release_sys = p_picture->p_release_sys;
+        p_release_sys->i_tick = 0;
+
+        p_picture->i_refcount = 0;
+        p_picture->pf_release = PicturePoolPictureRelease;
+        p_picture->p_release_sys = p_release_sys;
+
+        /* */
+        p_pool->pp_picture[i] = p_picture;
+    }
+    return p_pool;
+}
+
+picture_pool_t *picture_pool_NewFromFormat( const video_format_t *p_fmt, int i_picture )
+{
+    picture_t *pp_picture[i_picture];
+
+    for( int i = 0; i < i_picture; i++ )
+    {
+        pp_picture[i] = picture_New( p_fmt->i_chroma,
+                                     p_fmt->i_width, p_fmt->i_height,
+                                     p_fmt->i_aspect );
+        if( !pp_picture[i] )
+            goto error;
+    }
+    picture_pool_t *p_pool = picture_pool_New( i_picture, pp_picture );
+    if( !p_pool )
+        goto error;
+
+    return p_pool;
+
+error:
+    for( int i = 0; i < i_picture; i++ )
+    {
+        if( !pp_picture[i] )
+            break;
+        picture_Release( pp_picture[i] );
+    }
+    return NULL;
+}
+
+void picture_pool_Delete( picture_pool_t *p_pool )
+{
+    for( int i = 0; i < p_pool->i_picture; i++ )
+    {
+        picture_t *p_picture = p_pool->pp_picture[i];
+        picture_release_sys_t *p_release_sys = p_picture->p_release_sys;
+
+        assert( p_picture->i_refcount == 0 );
+
+        /* Restore old release callback */
+        p_picture->i_refcount = 1;
+        p_picture->pf_release = p_release_sys->pf_release;
+        p_picture->p_release_sys = p_release_sys->p_release_sys;
+
+        picture_Release( p_picture );
+
+        free( p_release_sys );
+    }
+    free( p_pool );
+}
+
+picture_t *picture_pool_Get( picture_pool_t *p_pool )
+{
+    for( int i = 0; i < p_pool->i_picture; i++ )
+    {
+        picture_t *p_picture = p_pool->pp_picture[i];
+
+        if( p_picture->i_refcount <= 0 )
+        {
+            p_picture->p_release_sys->i_tick = p_pool->i_tick++;
+            picture_Hold( p_picture );
+            return p_picture;
+        }
+    }
+    return NULL;
+}
+
+void picture_pool_NonEmpty( picture_pool_t *p_pool, bool b_reset )
+{
+    picture_t *p_old = NULL;
+
+    for( int i = 0; i < p_pool->i_picture; i++ )
+    {
+        picture_t *p_picture = p_pool->pp_picture[i];
+
+        if( b_reset )
+            p_picture->i_refcount = 0;
+        else if( p_picture->i_refcount == 0 )
+            return;
+        else if( !p_old || p_picture->p_release_sys->i_tick < p_old->p_release_sys->i_tick )
+            p_old = p_picture;
+    }
+    if( !b_reset && p_old )
+        p_old->i_refcount = 0;
+}
+
+static void PicturePoolPictureRelease( picture_t *p_picture )
+{
+    assert( p_picture->i_refcount > 0 );
+
+    if( --p_picture->i_refcount > 0 )
+        return;
+
+    /* Nothing to do for the moment */
+}
+