]> git.sesse.net Git - vlc/blobdiff - modules/packetizer/vc1.c
Added and used a packetizer_Header for packetizers.
[vlc] / modules / packetizer / vc1.c
index 5a8ca95c850566bb072048b3018a86fc16d4526f..f8edd3a64548e695236069b17125e08199f86dd0 100644 (file)
@@ -2,7 +2,7 @@
  * vc1.c
  *****************************************************************************
  * Copyright (C) 2001, 2002, 2006 the VideoLAN team
- * $Id: copy.c 18231 2006-12-03 17:02:02Z courmisch $
+ * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Gildas Bazin <gbazin@videolan.org>
 # include "config.h"
 #endif
 
-#include <vlc/vlc.h>
+#include <vlc_common.h>
+#include <vlc_plugin.h>
 #include <vlc_codec.h>
 #include <vlc_block.h>
 
 #include "vlc_bits.h"
 #include "vlc_block_helper.h"
+#include "packetizer_helper.h"
 
 /*****************************************************************************
  * Module descriptor
 static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
 
-vlc_module_begin();
-    set_category( CAT_SOUT );
-    set_subcategory( SUBCAT_SOUT_PACKETIZER );
-    set_description( _("VC-1 packetizer") );
-    set_capability( "packetizer", 50 );
-    set_callbacks( Open, Close );
-vlc_module_end();
+vlc_module_begin ()
+    set_category( CAT_SOUT )
+    set_subcategory( SUBCAT_SOUT_PACKETIZER )
+    set_description( N_("VC-1 packetizer") )
+    set_capability( "packetizer", 50 )
+    set_callbacks( Open, Close )
+vlc_module_end ()
 
 /*****************************************************************************
  * Local prototypes
@@ -59,30 +61,27 @@ struct decoder_sys_t
     /*
      * Input properties
      */
-    block_bytestream_t bytestream;
-    int i_state;
-    int i_offset;
-    uint8_t p_startcode[3];
+    packetizer_t packetizer;
 
     /* Current sequence header */
-    vlc_bool_t b_sequence_header;
+    bool b_sequence_header;
     struct
     {
         block_t *p_sh;
-        vlc_bool_t b_advanced_profile;
-        vlc_bool_t b_interlaced;
-        vlc_bool_t b_frame_interpolation;
-        vlc_bool_t b_range_reduction;
-        vlc_bool_t b_has_bframe;
+        bool b_advanced_profile;
+        bool b_interlaced;
+        bool b_frame_interpolation;
+        bool b_range_reduction;
+        bool b_has_bframe;
     } sh;
-    vlc_bool_t b_entry_point;
+    bool b_entry_point;
     struct
     {
         block_t *p_ep;
     } ep;
 
     /* */
-    vlc_bool_t  b_frame;
+    bool  b_frame;
 
     /* Current frame being built */
     block_t    *p_frame;
@@ -92,12 +91,6 @@ struct decoder_sys_t
     mtime_t i_interpolated_dts;
 };
 
-enum
-{
-    STATE_NOSYNC,
-    STATE_NEXT_SYNC
-};
-
 typedef enum
 {
     IDU_TYPE_SEQUENCE_HEADER = 0x0f,
@@ -105,7 +98,7 @@ typedef enum
     IDU_TYPE_FRAME = 0x0D,
     IDU_TYPE_FIELD = 0x0C,
     IDU_TYPE_SLICE = 0x0B,
-    IDU_TYPE_END_OF_SEQUENCE = 0x0B,
+    IDU_TYPE_END_OF_SEQUENCE = 0x0A,
 
     IDU_TYPE_SEQUENCE_LEVEL_USER_DATA = 0x1F,
     IDU_TYPE_ENTRY_POINT_USER_DATA = 0x1E,
@@ -116,6 +109,13 @@ typedef enum
 
 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block );
 
+static void PacketizeReset( void *p_private, bool b_broken );
+static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t * );
+static int PacketizeValidate( void *p_private, block_t * );
+
+static block_t *ParseIDU( decoder_t *p_dec, bool *pb_used_ts, block_t *p_frag );
+
+static const uint8_t p_vc1_startcode[3] = { 0x00, 0x00, 0x01 };
 /*****************************************************************************
  * Open: probe the packetizer and return score
  *****************************************************************************
@@ -136,35 +136,37 @@ static int Open( vlc_object_t *p_this )
     es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
 
-    p_sys->i_state = STATE_NOSYNC;
-    p_sys->bytestream = block_BytestreamInit( p_dec );
-    p_sys->p_startcode[0] = 0x00;
-    p_sys->p_startcode[1] = 0x00;
-    p_sys->p_startcode[2] = 0x01;
-    p_sys->i_offset = 0;
+    packetizer_Init( &p_sys->packetizer,
+                     p_vc1_startcode, sizeof(p_vc1_startcode),
+                     NULL, 0,
+                     PacketizeReset, PacketizeParse, PacketizeValidate, p_dec );
 
-    p_sys->b_sequence_header = VLC_FALSE;
+    p_sys->b_sequence_header = false;
     p_sys->sh.p_sh = NULL;
-    p_sys->b_entry_point = VLC_FALSE;
+    p_sys->b_entry_point = false;
     p_sys->ep.p_ep = NULL;
 
-    p_sys->b_frame = VLC_FALSE;
+    p_sys->b_frame = false;
     p_sys->p_frame = NULL;
     p_sys->pp_last = &p_sys->p_frame;
 
     p_sys->i_interpolated_dts = -1;
 
-
-    if( p_dec->fmt_in.i_extra > 0 )
+    if( p_dec->fmt_out.i_extra > 0 )
     {
-        block_t *p_init = block_New( p_dec, p_dec->fmt_in.i_extra );
-        block_t *p_pic;
+        uint8_t *p_extra = p_dec->fmt_out.p_extra;
 
-        memcpy( p_init->p_buffer, p_dec->fmt_in.p_extra,
-                p_dec->fmt_in.i_extra );
+        /* With (some) ASF the first byte has to be stripped */
+        if( p_extra[0] != 0x00 )
+        {
+            memcpy( &p_extra[0], &p_extra[1], p_dec->fmt_out.i_extra - 1 );
+            p_dec->fmt_out.i_extra--;
+        }
 
-        while( ( p_pic = Packetize( p_dec, &p_init ) ) )
-            block_Release( p_pic ); /* Should not happen (only sequence header) */
+        /* */
+        if( p_dec->fmt_out.i_extra > 0 )
+            packetizer_Header( &p_sys->packetizer,
+                               p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
     }
 
     return VLC_SUCCESS;
@@ -178,7 +180,7 @@ static void Close( vlc_object_t *p_this )
     decoder_t     *p_dec = (decoder_t*)p_this;
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    block_BytestreamRelease( &p_sys->bytestream );
+    packetizer_Clean( &p_sys->packetizer );
     if( p_sys->p_frame )
         block_Release( p_sys->p_frame );
     free( p_sys );
@@ -187,113 +189,50 @@ static void Close( vlc_object_t *p_this )
 /*****************************************************************************
  * Packetize: packetize an access unit
  *****************************************************************************/
-static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag );
-
 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t       *p_pic;
-
-    if( pp_block == NULL || *pp_block == NULL )
-        return NULL;
 
-    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
-    {
-        if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED )
-        {
-            p_sys->i_state = STATE_NOSYNC;
-            block_BytestreamFlush( &p_sys->bytestream );
-
-            if( p_sys->p_frame )
-                block_ChainRelease( p_sys->p_frame );
-            p_sys->p_frame = NULL;
-            p_sys->pp_last = &p_sys->p_frame;
-            p_sys->b_frame = VLC_FALSE;
-        }
-//        p_sys->i_interpolated_dts = 0;
-        block_Release( *pp_block );
-        return NULL;
-    }
+    return packetizer_Packetize( &p_sys->packetizer, pp_block );
+}
 
-    block_BytestreamPush( &p_sys->bytestream, *pp_block );
+static void PacketizeReset( void *p_private, bool b_broken )
+{
+    decoder_t *p_dec = p_private;
+    decoder_sys_t *p_sys = p_dec->p_sys;
 
-    for( ;; )
+    if( b_broken )
     {
-        switch( p_sys->i_state )
-        {
-
-        case STATE_NOSYNC:
-            if( block_FindStartcodeFromOffset( &p_sys->bytestream, &p_sys->i_offset, p_sys->p_startcode, 3 ) == VLC_SUCCESS )
-                p_sys->i_state = STATE_NEXT_SYNC;
-
-            if( p_sys->i_offset )
-            {
-                block_SkipBytes( &p_sys->bytestream, p_sys->i_offset );
-                p_sys->i_offset = 0;
-                block_BytestreamFlush( &p_sys->bytestream );
-            }
-
-            if( p_sys->i_state != STATE_NEXT_SYNC )
-                return NULL; /* Need more data */
-
-            p_sys->i_offset = 4; /* To find next startcode */
-
-        case STATE_NEXT_SYNC:
-            /* TODO: If p_block == NULL, flush the buffer without checking the
-             * next sync word */
-
-            /* Find the next startcode */
-            if( block_FindStartcodeFromOffset( &p_sys->bytestream, &p_sys->i_offset, p_sys->p_startcode, 3 ) != VLC_SUCCESS )
-                return NULL; /* Need more data */
-
-            /* Get the new fragment and set the pts/dts */
-            p_pic = block_New( p_dec, p_sys->i_offset );
-            block_BytestreamFlush( &p_sys->bytestream );
-            p_pic->i_pts = p_sys->bytestream.p_block->i_pts;
-            p_pic->i_dts = p_sys->bytestream.p_block->i_dts;
-            p_pic->i_rate = p_sys->bytestream.p_block->i_rate;
-
-            block_GetBytes( &p_sys->bytestream, p_pic->p_buffer, p_pic->i_buffer );
-
-            p_sys->i_offset = 0;
-
-            /* Parse and return complete frame */
-            p_pic = ParseIDU( p_dec, p_pic );
-
-            /* Don't reuse the same timestamps several times */
-            if( p_sys->p_frame &&
-                p_sys->p_frame->i_dts == p_sys->bytestream.p_block->i_dts &&
-                p_sys->p_frame->i_pts == p_sys->bytestream.p_block->i_pts )
-            {
-                p_sys->bytestream.p_block->i_pts = -1;
-                p_sys->bytestream.p_block->i_dts = -1;
-            }
-
-            /* */
-            if( !p_pic )
-            {
-                p_sys->i_state = STATE_NOSYNC;
-                break;
-            }
-            /* */
-            if( p_sys->i_interpolated_dts < 0 )
-            {
-                msg_Dbg( p_dec, "need a starting pts/dts" );
-                p_sys->i_state = STATE_NOSYNC;
-                block_Release( p_pic );
-                break;
-            }
+        if( p_sys->p_frame )
+            block_ChainRelease( p_sys->p_frame );
+        p_sys->p_frame = NULL;
+        p_sys->pp_last = &p_sys->p_frame;
+        p_sys->b_frame = false;
+    }
+    p_sys->i_interpolated_dts = 0;
+}
+static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block )
+{
+    decoder_t *p_dec = p_private;
 
-            /* So p_block doesn't get re-added several times */
-            *pp_block = block_BytestreamPop( &p_sys->bytestream );
+    return ParseIDU( p_dec, pb_ts_used, p_block );
+}
 
-            p_sys->i_state = STATE_NOSYNC;
+static int PacketizeValidate( void *p_private, block_t *p_au )
+{
+    decoder_t *p_dec = p_private;
+    decoder_sys_t *p_sys = p_dec->p_sys;
 
-            return p_pic;
-        }
+    if( p_sys->i_interpolated_dts < 0 )
+    {
+        msg_Dbg( p_dec, "need a starting pts/dts" );
+        return VLC_EGENERIC;
     }
+    VLC_UNUSED(p_au);
+    return VLC_SUCCESS;
 }
 
+
 /* DecodeRIDU: decode the startcode emulation prevention (same than h264) */
 static void DecodeRIDU( uint8_t *p_ret, int *pi_ret, uint8_t *src, int i_src )
 {
@@ -337,13 +276,14 @@ static void BuildExtraData( decoder_t *p_dec )
     memcpy( (uint8_t*)p_es->p_extra + p_sys->sh.p_sh->i_buffer,
             p_sys->ep.p_ep->p_buffer, p_sys->ep.p_ep->i_buffer );
 }
-/* ParseIDU: parse an Independant Decoding Unit */
-static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
+/* ParseIDU: parse an Independent Decoding Unit */
+static block_t *ParseIDU( decoder_t *p_dec, bool *pb_used_ts, block_t *p_frag )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_pic;
     const idu_type_t idu = p_frag->p_buffer[3];
 
+    *pb_used_ts = false;
     if( !p_sys->b_sequence_header && idu != IDU_TYPE_SEQUENCE_HEADER )
     {
         msg_Warn( p_dec, "waiting for sequence header" );
@@ -370,14 +310,23 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
         /* */
         p_pic = block_ChainGather( p_sys->p_frame );
 
+        /* */
+        if( p_pic->i_dts > 0 )
+            p_sys->i_interpolated_dts = p_pic->i_dts;
+
         /* We can interpolate dts/pts only if we have a frame rate */
         if( p_dec->fmt_out.video.i_frame_rate != 0 && p_dec->fmt_out.video.i_frame_rate_base != 0 )
         {
-            //msg_Dbg( p_dec, "-------------- XXX0 dts="I64Fd" pts="I64Fd" interpolated="I64Fd, p_pic->i_dts, p_pic->i_pts, p_sys->i_interpolated_dts );
+            if( p_sys->i_interpolated_dts > 0 )
+                p_sys->i_interpolated_dts += INT64_C(1000000) *
+                                             p_dec->fmt_out.video.i_frame_rate_base /
+                                             p_dec->fmt_out.video.i_frame_rate;
+
+            //msg_Dbg( p_dec, "-------------- XXX0 dts=%"PRId64" pts=%"PRId64" interpolated=%"PRId64,
+            //         p_pic->i_dts, p_pic->i_pts, p_sys->i_interpolated_dts );
             if( p_pic->i_dts <= 0 )
                 p_pic->i_dts = p_sys->i_interpolated_dts;
 
-            p_sys->i_interpolated_dts += I64C(1000000) * p_dec->fmt_out.video.i_frame_rate_base / p_dec->fmt_out.video.i_frame_rate;
             if( p_pic->i_pts <= 0 )
             {
                 if( !p_sys->sh.b_has_bframe || (p_pic->i_flags & BLOCK_FLAG_TYPE_B ) )
@@ -385,11 +334,11 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
                 /* TODO compute pts for other case */
             }
         }
-        p_sys->i_interpolated_dts = p_pic->i_dts;
 
-        //msg_Dbg( p_dec, "-------------- dts="I64Fd" pts="I64Fd, p_pic->i_dts, p_pic->i_pts );
+        //msg_Dbg( p_dec, "-------------- dts=%"PRId64" pts=%"PRId64, p_pic->i_dts, p_pic->i_pts );
 
         /* Reset context */
+        p_sys->b_frame = false;
         p_sys->p_frame = NULL;
         p_sys->pp_last = &p_sys->p_frame;
     }
@@ -398,10 +347,12 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
     if( p_sys->p_frame )
     {
         block_t *p_frame = p_sys->p_frame;
-        if( p_frame->i_dts < 0 )
+        if( p_frame->i_dts <= 0 && p_frame->i_pts <= 0 )
+        {
             p_frame->i_dts = p_frag->i_dts;
-        if( p_frame->i_pts < 0 )
             p_frame->i_pts = p_frag->i_pts;
+            *pb_used_ts = true;
+        }
     }
     block_ChainLastAppend( &p_sys->pp_last, p_frag );
 
@@ -427,8 +378,8 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
         if( i_ridu > 4 && (ridu[0]&0x80) == 0 ) /* for advanced profile, the first bit is 1 */
         {
             video_format_t *p_v = &p_dec->fmt_in.video;
-            const int i_potential_width  = GetWBE( &ridu[0] );
-            const int i_potential_height = GetWBE( &ridu[2] );
+            const size_t i_potential_width  = GetWBE( &ridu[0] );
+            const size_t i_potential_height = GetWBE( &ridu[2] );
 
             if( i_potential_width >= 2  && i_potential_width <= 8192 &&
                 i_potential_height >= 2 && i_potential_height <= 8192 )
@@ -456,9 +407,9 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
             const int i_level = bs_read( &s, 3 );
 
             /* Advanced profile */
-            p_sys->sh.b_advanced_profile = VLC_TRUE;
-            p_sys->sh.b_range_reduction = VLC_FALSE;
-            p_sys->sh.b_has_bframe = VLC_TRUE;
+            p_sys->sh.b_advanced_profile = true;
+            p_sys->sh.b_range_reduction = false;
+            p_sys->sh.b_has_bframe = true;
 
             bs_skip( &s, 2+3+5+1 ); // chroma format + frame rate Q + bit rate Q + postprocflag
 
@@ -494,7 +445,7 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
                         {64,33}, {160,99},{ 0, 0}, { 0, 0}
                     };
                     int i_ar = bs_read( &s, 4 );
-                    int i_ar_w, i_ar_h;
+                    unsigned i_ar_w, i_ar_h;
 
                     if( i_ar == 15 )
                     {
@@ -551,8 +502,8 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
         else
         {
             /* Simple and main profile */
-            p_sys->sh.b_advanced_profile = VLC_FALSE;
-            p_sys->sh.b_interlaced = VLC_FALSE;
+            p_sys->sh.b_advanced_profile = false;
+            p_sys->sh.b_interlaced = false;
 
             if( !p_sys->b_sequence_header )
                 msg_Dbg( p_dec, "found sequence header for %s profile", i_profile == 0 ? "simple" : "main" );
@@ -562,14 +513,14 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
                          1+1+1+1 );     // variable size transform + reserved + overlap + sync marker
             p_sys->sh.b_range_reduction = bs_read( &s, 1 );
             if( bs_read( &s, 3 ) > 0 )
-                p_sys->sh.b_has_bframe = VLC_TRUE;
+                p_sys->sh.b_has_bframe = true;
             else
-                p_sys->sh.b_has_bframe = VLC_FALSE;
+                p_sys->sh.b_has_bframe = false;
             bs_skip( &s, 2 );           // quantizer
 
             p_sys->sh.b_frame_interpolation = bs_read( &s, 1 );
         }
-        p_sys->b_sequence_header = VLC_TRUE;
+        p_sys->b_sequence_header = true;
         BuildExtraData( p_dec );
     }
     else if( idu == IDU_TYPE_ENTRY_POINT )
@@ -578,7 +529,7 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
             block_Release( p_sys->ep.p_ep );
         p_sys->ep.p_ep = block_Duplicate( p_frag );
 
-        p_sys->b_entry_point = VLC_TRUE;
+        p_sys->b_entry_point = true;
         BuildExtraData( p_dec );
     }
     else if( idu == IDU_TYPE_FRAME )
@@ -660,7 +611,7 @@ static block_t *ParseIDU( decoder_t *p_dec, block_t *p_frag )
             else
                 p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_B;
         }
-        p_sys->b_frame = VLC_TRUE;
+        p_sys->b_frame = true;
     }
     return p_pic;
 }