[vlc-devel] [PATCH/RFC] transcode: Do not encode if decoder output fourcc is the target fourcc

Hugo Beauzée-Luyssen hugo at beauzee.fr
Mon Jun 9 22:45:04 CEST 2014


Hi,

This patch fixes a problem when trying to transcode a file to an arbitrary
fourcc which happens to be the decoder output fourcc.
Consider a case where the user wants to transcode any file's video track to
I420, if the video track is encoded using H264, there's a high chance,
depending on which profile is used, that no re-encoding will be required.

This patch attempts to solve the problem by checking if encoding is required
as soon as the information is available.
I'm not sure this is the best way to do so (hence the RFC), nor that I'm sure
this code is correct.
Obviously, adding picture_ToBlock to libvlccore is not required, however, it
felt more natural to add it there. I'll gladly let it live in video.c only if
you feel it's a better solution.
Another way which crossed my mind would be to have a "clone" encoder that would
basically be the picture_ToBlock function. This would avoid cluttering the
transcode code for what seems to me as a corner(-ish) case. It would also
avoid having to add a picture_ToBlock function, of which the use seems limited.
However, having a module for this sole purpose seems a bit overkill.

Please share your thoughts/comments!

Best regards,

---
 include/vlc_picture.h                    |  1 +
 modules/stream_out/transcode/transcode.h |  2 ++
 modules/stream_out/transcode/video.c     | 57 +++++++++++++++++++++++++-------
 src/libvlccore.sym                       |  1 +
 src/misc/picture.c                       | 19 +++++++++++
 5 files changed, 68 insertions(+), 12 deletions(-)

diff --git a/include/vlc_picture.h b/include/vlc_picture.h
index d3e3b99..7dbc4ae 100644
--- a/include/vlc_picture.h
+++ b/include/vlc_picture.h
@@ -250,6 +250,7 @@ VLC_API int picture_Setup( picture_t *, const video_format_t * );
  */
 VLC_API unsigned picture_BlendSubpicture( picture_t *, filter_t *p_blend, subpicture_t * );
 
+VLC_API block_t* picture_ToBlock( const picture_t* );
 
 /*****************************************************************************
  * Shortcuts to access image components
diff --git a/modules/stream_out/transcode/transcode.h b/modules/stream_out/transcode/transcode.h
index 66daca0..ed56d7d 100644
--- a/modules/stream_out/transcode/transcode.h
+++ b/modules/stream_out/transcode/transcode.h
@@ -78,6 +78,8 @@ struct aout_filters;
 struct sout_stream_id_sys_t
 {
     bool            b_transcode;
+    /* Will be true if transcode output fourcc != decoder output fourcc */
+    bool            b_encode;
 
     /* id of the out stream */
     void *id;
diff --git a/modules/stream_out/transcode/video.c b/modules/stream_out/transcode/video.c
index 60b66bb..64173aa 100644
--- a/modules/stream_out/transcode/video.c
+++ b/modules/stream_out/transcode/video.c
@@ -604,14 +604,33 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream,
              id->p_encoder->fmt_in.video.i_width,
              id->p_encoder->fmt_in.video.i_height );
 
-    id->p_encoder->p_module =
-        module_need( id->p_encoder, "encoder", p_sys->psz_venc, true );
-    if( !id->p_encoder->p_module )
+    if ( id->b_encode )
     {
-        msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)",
-                 p_sys->psz_venc ? p_sys->psz_venc : "any",
-                 (char *)&p_sys->i_vcodec );
-        return VLC_EGENERIC;
+        id->p_encoder->p_module =
+            module_need( id->p_encoder, "encoder", p_sys->psz_venc, true );
+        if( !id->p_encoder->p_module )
+        {
+            msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)",
+                     p_sys->psz_venc ? p_sys->psz_venc : "any",
+                     (char *)&p_sys->i_vcodec );
+            return VLC_EGENERIC;
+        }
+    }
+    else if ( p_sys->i_threads >= 1 )
+    {
+        vlc_mutex_lock( &p_stream->p_sys->lock_out );
+        p_stream->p_sys->b_abort = true;
+        vlc_cond_signal( &p_stream->p_sys->cond );
+        vlc_mutex_unlock( &p_stream->p_sys->lock_out );
+
+        vlc_join( p_stream->p_sys->thread, NULL );
+        vlc_mutex_destroy( &p_stream->p_sys->lock_out );
+        vlc_cond_destroy( &p_stream->p_sys->cond );
+
+        picture_fifo_Delete( p_stream->p_sys->pp_pics );
+        block_ChainRelease( p_stream->p_sys->p_buffers );
+        p_stream->p_sys->pp_pics = NULL;
+        p_sys->i_threads = 0;
     }
 
     id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec;
@@ -738,11 +757,14 @@ static void OutputFrame( sout_stream_t *p_stream, picture_t *p_pic, sout_stream_
     /*This pts is handled, increase clock to next one*/
     date_Increment( &id->next_output_pts, id->p_encoder->fmt_in.video.i_frame_rate_base );
 
-    if( p_sys->i_threads == 0 )
+    if( p_sys->i_threads == 0 || id->b_encode == false )
     {
         block_t *p_block;
 
-        p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic );
+        if ( id->b_encode == false )
+            p_block = picture_ToBlock( p_pic );
+        else
+            p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic );
         block_ChainAppend( out, p_block );
     }
 
@@ -766,6 +788,7 @@ static void OutputFrame( sout_stream_t *p_stream, picture_t *p_pic, sout_stream_
 
     while( (p_sys->b_master_sync && b_need_duplicate ))
     {
+        /* At this point we are sure the user wants to encode if i_threads > 0 */
         if( p_sys->i_threads >= 1 )
         {
             picture_t *p_tmp = NULL;
@@ -785,7 +808,10 @@ static void OutputFrame( sout_stream_t *p_stream, picture_t *p_pic, sout_stream_
         {
             block_t *p_block;
             p_pic->date = date_Get( &id->next_output_pts );
-            p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic);
+            if ( id->b_encode == true )
+                p_block = picture_ToBlock( p_pic );
+            else
+                p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic);
             block_ChainAppend( out, p_block );
         }
 #if 0
@@ -811,7 +837,11 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
 
     if( unlikely( in == NULL ) )
     {
-        if( p_sys->i_threads == 0 )
+        if ( id->b_encode == false )
+        {
+            block_ChainAppend( out, NULL );
+        }
+        else if( p_sys->i_threads == 0 )
         {
             block_t *p_block;
             do {
@@ -872,7 +902,7 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
         }
 
 
-        if( unlikely( !id->p_encoder->p_module ) )
+        if( unlikely( !id->p_encoder->p_module && id->b_encode ) )
         {
             if( id->p_f_chain )
                 filter_chain_Delete( id->p_f_chain );
@@ -880,6 +910,8 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
                 filter_chain_Delete( id->p_uf_chain );
             id->p_f_chain = id->p_uf_chain = NULL;
 
+            /* Now we have enough information to check if re-encoding is really needed */
+            id->b_encode = id->p_decoder->fmt_out.i_codec != p_sys->i_vcodec;
             transcode_video_filter_init( p_stream, id );
             transcode_video_encoder_init( p_stream, id );
             conversion_video_filter_append( id );
@@ -1005,6 +1037,7 @@ bool transcode_video_add( sout_stream_t *p_stream, es_format_t *p_fmt,
     /* Stream will be added later on because we don't know
      * all the characteristics of the decoded stream yet */
     id->b_transcode = true;
+    id->b_encode = true;
 
     if( p_sys->fps_num )
     {
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index e583c21..5f42bd9 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -310,6 +310,7 @@ picture_pool_NonEmpty
 picture_pool_Reserve
 picture_Reset
 picture_Setup
+picture_ToBlock
 plane_CopyPixels
 playlist_Add
 playlist_AddExt
diff --git a/src/misc/picture.c b/src/misc/picture.c
index 7c6fa6a..544b4ee 100644
--- a/src/misc/picture.c
+++ b/src/misc/picture.c
@@ -459,3 +459,22 @@ unsigned picture_BlendSubpicture(picture_t *dst,
     }
     return done;
 }
+
+block_t* picture_ToBlock( const picture_t* pic )
+{
+    size_t nbBytes = pic->format.i_width * pic->format.i_height * pic->format.i_bits_per_pixel;
+
+    block_t* block = block_Alloc( nbBytes );
+    if ( unlikely( block == NULL ) )
+        return NULL;
+    uint8_t* b = block->p_buffer;
+    for (unsigned int i = 0; i < pic->i_planes; ++i )
+    {
+        const plane_t* p = &pic->p[i];
+        size_t planeBytes = p->i_lines * p->i_pitch;
+        memcpy( b, p->p_pixels, planeBytes );
+        b += planeBytes;
+    }
+    block->i_dts = block->i_pts = pic->date;
+    return block;
+}
-- 
2.0.0




More information about the vlc-devel mailing list