Moved and fixed all common code from video packetizers into packetizer_helper.h
authorLaurent Aimar <fenrir@videolan.org>
Tue, 28 Apr 2009 17:27:16 +0000 (19:27 +0200)
committerLaurent Aimar <fenrir@videolan.org>
Tue, 28 Apr 2009 19:23:56 +0000 (21:23 +0200)
There are some risks of regression (in case of typo), but it was
a nightmare to maintain.
Also by using the right model (h264.c) it fixes some timing issues in
vc1 and mpeg2 packetizer.

modules/packetizer/h264.c
modules/packetizer/mpeg4video.c
modules/packetizer/mpegvideo.c
modules/packetizer/packetizer_helper.h [new file with mode: 0644]
modules/packetizer/vc1.c

index 175643e..d1f7f88 100644 (file)
@@ -41,6 +41,7 @@
 #include "vlc_block_helper.h"
 #include "vlc_bits.h"
 #include "../codec/cc.h"
+#include "packetizer_helper.h"
 
 /*****************************************************************************
  * Module descriptor
@@ -60,10 +61,6 @@ vlc_module_end ()
 /****************************************************************************
  * Local prototypes
  ****************************************************************************/
-static block_t *Packetize( decoder_t *, block_t ** );
-static block_t *PacketizeAVC1( decoder_t *, block_t ** );
-static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] );
-
 typedef struct
 {
     int i_nal_type;
@@ -89,12 +86,10 @@ typedef struct
 #define PPS_MAX (256)
 struct decoder_sys_t
 {
-    block_bytestream_t bytestream;
-
-    int     i_state;
-    size_t  i_offset;
-    uint8_t startcode[4];
+    /* */
+    packetizer_t packetizer;
 
+    /* */
     bool    b_slice;
     block_t *p_frame;
 
@@ -133,12 +128,6 @@ struct decoder_sys_t
     cc_data_t cc_next;
 };
 
-enum
-{
-    STATE_NOSYNC,
-    STATE_NEXT_SYNC,
-};
-
 enum nal_unit_type_e
 {
     NAL_UNKNOWN = 0,
@@ -162,8 +151,15 @@ enum nal_priority_e
     NAL_PRIORITY_HIGHEST    = 3,
 };
 
-static block_t *ParseNALBlock( decoder_t *, bool *pb_used_ts, block_t * );
+static block_t *Packetize( decoder_t *, block_t ** );
+static block_t *PacketizeAVC1( decoder_t *, block_t ** );
+static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] );
 
+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 *ParseNALBlock( decoder_t *, bool *pb_used_ts, block_t * );
 static block_t *CreateAnnexbNAL( decoder_t *, const uint8_t *p, int );
 
 static block_t *OutputPicture( decoder_t *p_dec );
@@ -174,6 +170,8 @@ static void ParseSlice( decoder_t *p_dec, bool *pb_new_picture, slice_t *p_slice
 static void ParseSei( decoder_t *, block_t * );
 
 
+static const uint8_t p_h264_startcode[3] = { 0x00, 0x00, 0x01 };
+
 /*****************************************************************************
  * Open: probe the packetizer and return score
  * When opening after demux, the packetizer is only loaded AFTER the decoder
@@ -203,13 +201,12 @@ static int Open( vlc_object_t *p_this )
     {
         return VLC_ENOMEM;
     }
-    p_sys->i_state = STATE_NOSYNC;
-    p_sys->i_offset = 0;
-    p_sys->startcode[0] = 0;
-    p_sys->startcode[1] = 0;
-    p_sys->startcode[2] = 0;
-    p_sys->startcode[3] = 1;
-    p_sys->bytestream = block_BytestreamInit();
+
+    packetizer_Init( &p_sys->packetizer,
+                     p_h264_startcode, sizeof(p_h264_startcode),
+                     p_h264_startcode, 1,
+                     PacketizeReset, PacketizeParse, PacketizeValidate, p_dec );
+
     p_sys->b_slice = false;
     p_sys->p_frame = NULL;
     p_sys->b_header= false;
@@ -397,7 +394,8 @@ static void Close( vlc_object_t *p_this )
         if( p_sys->pp_pps[i] )
             block_Release( p_sys->pp_pps[i] );
     }
-    block_BytestreamRelease( &p_sys->bytestream );
+    packetizer_Clean( &p_sys->packetizer );
+
     if( p_dec->pf_get_cc )
     {
          cc_Exit( &p_sys->cc_next );
@@ -415,117 +413,8 @@ static void Close( vlc_object_t *p_this )
 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 || !*pp_block )
-        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_BytestreamEmpty( &p_sys->bytestream );
-
-            if( p_sys->p_frame )
-                block_ChainRelease( p_sys->p_frame );
-            p_sys->p_frame = NULL;
-            p_sys->slice.i_frame_type = 0;
-            p_sys->b_slice = false;
-        }
-        p_sys->i_frame_pts = -1;
-        p_sys->i_frame_dts = -1;
-
-        block_Release( *pp_block );
-        return NULL;
-    }
-
-    block_BytestreamPush( &p_sys->bytestream, *pp_block );
-
-    for( ;; )
-    {
-        bool b_used_ts;
-
-        switch( p_sys->i_state )
-        {
-            case STATE_NOSYNC:
-                /* Skip until 3 byte startcode 0 0 1 */
-                if( block_FindStartcodeFromOffset( &p_sys->bytestream,
-                      &p_sys->i_offset, p_sys->startcode+1, 3 ) == VLC_SUCCESS)
-                {
-                    p_sys->i_state = STATE_NEXT_SYNC;
-                }
-
-                if( p_sys->i_offset )
-                {
-                    /* skip the data */
-                    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 )
-                {
-                    /* Need more data */
-                    return NULL;
-                }
-
-                p_sys->i_offset = 1; /* To find next startcode */
-
-            case STATE_NEXT_SYNC:
-                /* Find the next 3 byte startcode 0 0 1*/
-                if( block_FindStartcodeFromOffset( &p_sys->bytestream,
-                      &p_sys->i_offset, p_sys->startcode+1, 3 ) != VLC_SUCCESS)
-                {
-                    /* Need more data */
-                    return NULL;
-                }
-                block_BytestreamFlush( &p_sys->bytestream );
-
-                /* Get the new fragment and set the pts/dts */
-                block_t *p_block_bytestream = p_sys->bytestream.p_block;
-
-                p_pic = block_New( p_dec, p_sys->i_offset +1 );
-                p_pic->i_pts = p_block_bytestream->i_pts;
-                p_pic->i_dts = p_block_bytestream->i_dts;
-
-                /* Force 4 byte startcode 0 0 0 1 */
-                p_pic->p_buffer[0] = 0;
-
-                block_GetBytes( &p_sys->bytestream, &p_pic->p_buffer[1],
-                                p_pic->i_buffer-1 );
-
-                /* Remove trailing 0 bytes */
-                while( p_pic->i_buffer && (!p_pic->p_buffer[p_pic->i_buffer-1] ) )
-                    p_pic->i_buffer--;
-                p_sys->i_offset = 0;
-
-                /* Parse the NAL */
-                p_pic = ParseNALBlock( p_dec, &b_used_ts, p_pic );
-                if( b_used_ts )
-                {
-                    p_block_bytestream->i_dts = -1;
-                    p_block_bytestream->i_pts = -1;
-                }
-
-                if( !p_pic )
-                {
-                    p_sys->i_state = STATE_NOSYNC;
-                    break;
-                }
-#if 0
-                msg_Dbg( p_dec, "pts=%"PRId64" dts=%"PRId64,
-                         p_pic->i_pts, p_pic->i_dts );
-#endif
-
-                /* So p_block doesn't get re-added several times */
-                *pp_block = block_BytestreamPop( &p_sys->bytestream );
-
-                p_sys->i_state = STATE_NOSYNC;
-
-                return p_pic;
-        }
-    }
+    return packetizer_Packetize( &p_sys->packetizer, pp_block );
 }
 
 /****************************************************************************
@@ -618,6 +507,39 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] )
 /****************************************************************************
  * Helpers
  ****************************************************************************/
+static void PacketizeReset( void *p_private, bool b_broken )
+{
+    decoder_t *p_dec = p_private;
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    if( b_broken )
+    {
+        if( p_sys->p_frame )
+            block_ChainRelease( p_sys->p_frame );
+        p_sys->p_frame = NULL;
+        p_sys->slice.i_frame_type = 0;
+        p_sys->b_slice = false;
+    }
+    p_sys->i_frame_pts = -1;
+    p_sys->i_frame_dts = -1;
+}
+static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block )
+{
+    decoder_t *p_dec = p_private;
+
+    /* Remove trailing 0 bytes */
+    while( p_block->i_buffer && p_block->p_buffer[p_block->i_buffer-1] == 0x00 )
+        p_block->i_buffer--;
+
+    return ParseNALBlock( p_dec, pb_ts_used, p_block );
+}
+static int PacketizeValidate( void *p_private, block_t *p_au )
+{
+    VLC_UNUSED(p_private);
+    VLC_UNUSED(p_au);
+    return VLC_SUCCESS;
+}
+
 static block_t *CreateAnnexbNAL( decoder_t *p_dec, const uint8_t *p, int i_size )
 {
     block_t *p_nal;
index 06e5f4e..018846c 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "vlc_bits.h"
 #include "vlc_block_helper.h"
+#include "packetizer_helper.h"
 
 /*****************************************************************************
  * Module descriptor
@@ -57,17 +58,12 @@ vlc_module_end ()
 /****************************************************************************
  * Local prototypes
  ****************************************************************************/
-static block_t *Packetize( decoder_t *, block_t ** );
-
 struct decoder_sys_t
 {
     /*
      * Input properties
      */
-    block_bytestream_t bytestream;
-    int i_state;
-    size_t i_offset;
-    uint8_t p_startcode[3];
+    packetizer_t packetizer;
 
     /*
      * Common properties
@@ -94,10 +90,11 @@ struct decoder_sys_t
     block_t    **pp_last;
 };
 
-enum {
-    STATE_NOSYNC,
-    STATE_NEXT_SYNC
-};
+static block_t *Packetize( decoder_t *, block_t ** );
+
+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 *ParseMPEGBlock( decoder_t *, block_t * );
 static int ParseVOL( decoder_t *, es_format_t *, uint8_t *, int );
@@ -124,6 +121,8 @@ static int vlc_log2( unsigned int );
 #define TEXTURE_SPATIAL_LAYER_START_CODE        0x1bf
 #define TEXTURE_SNR_LAYER_START_CODE            0x1c0
 
+static const uint8_t p_mp4v_startcode[3] = { 0x00, 0x00, 0x01 };
+
 /*****************************************************************************
  * Open: probe the packetizer and return score
  *****************************************************************************/
@@ -163,12 +162,11 @@ static int Open( vlc_object_t *p_this )
     memset( p_sys, 0, sizeof(decoder_sys_t) );
 
     /* Misc init */
-    p_sys->i_state = STATE_NOSYNC;
-    p_sys->bytestream = block_BytestreamInit();
-    p_sys->p_startcode[0] = 0;
-    p_sys->p_startcode[1] = 0;
-    p_sys->p_startcode[2] = 1;
-    p_sys->i_offset = 0;
+    packetizer_Init( &p_sys->packetizer,
+                     p_mp4v_startcode, sizeof(p_mp4v_startcode),
+                     NULL, 0,
+                     PacketizeReset, PacketizeParse, PacketizeValidate, p_dec );
+
     p_sys->p_frame = NULL;
     p_sys->pp_last = &p_sys->p_frame;
 
@@ -207,10 +205,12 @@ static int Open( vlc_object_t *p_this )
 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_dec->p_sys->bytestream );
-    if( p_dec->p_sys->p_frame ) block_ChainRelease( p_dec->p_sys->p_frame );
-    free( p_dec->p_sys );
+    packetizer_Clean( &p_sys->packetizer );
+    if( p_sys->p_frame )
+        block_ChainRelease( p_sys->p_frame );
+    free( p_sys );
 }
 
 /****************************************************************************
@@ -219,125 +219,68 @@ static void Close( vlc_object_t *p_this )
 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;
-    mtime_t       i_pts, i_dts;
 
-    if( pp_block == NULL || *pp_block == NULL ) return NULL;
+    return packetizer_Packetize( &p_sys->packetizer, pp_block );
+}
+
+/*****************************************************************************
+ * Helpers:
+ *****************************************************************************/
+static void PacketizeReset( void *p_private, bool b_broken )
+{
+    decoder_t *p_dec = p_private;
+    decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
+    if( b_broken )
     {
-        if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED )
-        {
-            p_sys->i_state = STATE_NOSYNC;
-            block_BytestreamEmpty( &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->i_interpolated_pts =
-        p_sys->i_interpolated_dts =
-        p_sys->i_last_ref_pts =
-        p_sys->i_last_time_ref =
-        p_sys->i_time_ref =
-        p_sys->i_last_time =
-        p_sys->i_last_timeincr = 0;
-
-        block_Release( *pp_block );
-        return NULL;
+        if( p_sys->p_frame )
+            block_ChainRelease( p_sys->p_frame );
+        p_sys->p_frame = NULL;
+        p_sys->pp_last = &p_sys->p_frame;
     }
 
-    block_BytestreamPush( &p_sys->bytestream, *pp_block );
+    p_sys->i_interpolated_pts =
+    p_sys->i_interpolated_dts =
+    p_sys->i_last_ref_pts =
+    p_sys->i_last_time_ref =
+    p_sys->i_time_ref =
+    p_sys->i_last_time =
+    p_sys->i_last_timeincr = 0;
+}
 
-    while( 1 )
-    {
-        switch( p_sys->i_state )
-        {
+static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block )
+{
+    decoder_t *p_dec = p_private;
+    const mtime_t i_dts = p_block->i_dts;
+    const mtime_t i_pts = p_block->i_pts;
 
-        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 )
-            {
-                /* Need more data */
-                return NULL;
-            }
-
-            p_sys->i_offset = 1; /* 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 )
-            {
-                /* Need more data */
-                return NULL;
-            }
-
-            /* 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 = i_pts = p_sys->bytestream.p_block->i_pts;
-            p_pic->i_dts = i_dts = p_sys->bytestream.p_block->i_dts;
-
-            block_GetBytes( &p_sys->bytestream, p_pic->p_buffer,
-                            p_pic->i_buffer );
-
-            p_sys->i_offset = 0;
-
-            /* Get picture if any */
-            if( !( p_pic = ParseMPEGBlock( p_dec, p_pic ) ) )
-            {
-                p_sys->i_state = STATE_NOSYNC;
-                break;
-            }
-
-            /* don't reuse the same timestamps several times */
-            if( i_pts == p_sys->bytestream.p_block->i_pts &&
-                i_dts == p_sys->bytestream.p_block->i_dts )
-            {
-                p_sys->bytestream.p_block->i_pts = 0;
-                p_sys->bytestream.p_block->i_dts = 0;
-            }
-
-            /* We've just started the stream, wait for the first PTS.
-             * We discard here so we can still get the sequence header. */
-            if( p_sys->i_interpolated_pts <= 0 &&
-                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;
-            }
-
-            /* When starting the stream we can have the first frame with
-             * a null DTS (i_interpolated_pts is initialized to 0) */
-            if( !p_pic->i_dts ) p_pic->i_dts = p_pic->i_pts;
-
-            /* So p_block doesn't get re-added several times */
-            *pp_block = block_BytestreamPop( &p_sys->bytestream );
-
-            p_sys->i_state = STATE_NOSYNC;
-
-            return p_pic;
-        }
+    block_t *p_au = ParseMPEGBlock( p_dec, p_block );
+
+    *pb_ts_used = p_au &&  p_au->i_dts == i_dts && p_au->i_pts == i_pts;
+
+    return p_au;
+}
+
+
+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;
+
+    /* We've just started the stream, wait for the first PTS.
+     * We discard here so we can still get the sequence header. */
+    if( p_sys->i_interpolated_pts <= 0 &&
+        p_sys->i_interpolated_dts <= 0 )
+    {
+        msg_Dbg( p_dec, "need a starting pts/dts" );
+        return VLC_EGENERIC;
     }
+
+    /* When starting the stream we can have the first frame with
+     * a null DTS (i_interpolated_pts is initialized to 0) */
+    if( !p_au->i_dts )
+        p_au->i_dts = p_au->i_pts;
+    return VLC_SUCCESS;
 }
 
 /*****************************************************************************
index e841928..a3a4020 100644 (file)
@@ -52,6 +52,7 @@
 #include <vlc_codec.h>
 #include <vlc_block_helper.h>
 #include "../codec/cc.h"
+#include "packetizer_helper.h"
 
 #define SYNC_INTRAFRAME_TEXT N_("Sync on Intra Frame")
 #define SYNC_INTRAFRAME_LONGTEXT N_("Normally the packetizer would " \
@@ -79,19 +80,12 @@ vlc_module_end ()
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static block_t *Packetize( decoder_t *, block_t ** );
-static block_t *ParseMPEGBlock( decoder_t *, block_t * );
-static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] );
-
 struct decoder_sys_t
 {
     /*
      * Input properties
      */
-    block_bytestream_t bytestream;
-    int i_state;
-    size_t i_offset;
-    uint8_t p_startcode[3];
+    packetizer_t packetizer;
 
     /* Sequence header and extension */
     block_t *p_seq;
@@ -140,10 +134,16 @@ struct decoder_sys_t
     cc_data_t cc;
 };
 
-enum {
-    STATE_NOSYNC,
-    STATE_NEXT_SYNC
-};
+static block_t *Packetize( decoder_t *, block_t ** );
+static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] );
+
+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 *ParseMPEGBlock( decoder_t *, block_t * );
+
+static const uint8_t p_mp2v_startcode[3] = { 0x00, 0x00, 0x01 };
 
 /*****************************************************************************
  * Open:
@@ -170,12 +170,10 @@ static int Open( vlc_object_t *p_this )
     memset( p_dec->p_sys, 0, sizeof( decoder_sys_t ) );
 
     /* Misc init */
-    p_sys->i_state = STATE_NOSYNC;
-    p_sys->bytestream = block_BytestreamInit();
-    p_sys->p_startcode[0] = 0;
-    p_sys->p_startcode[1] = 0;
-    p_sys->p_startcode[2] = 1;
-    p_sys->i_offset = 0;
+    packetizer_Init( &p_sys->packetizer,
+                     p_mp2v_startcode, sizeof(p_mp2v_startcode),
+                     NULL, 0,
+                     PacketizeReset, PacketizeParse, PacketizeValidate, p_dec );
 
     p_sys->p_seq = NULL;
     p_sys->p_ext = NULL;
@@ -225,8 +223,6 @@ 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 );
-
     if( p_sys->p_seq )
     {
         block_Release( p_sys->p_seq );
@@ -239,6 +235,7 @@ static void Close( vlc_object_t *p_this )
     {
         block_ChainRelease( p_sys->p_frame );
     }
+    packetizer_Clean( &p_sys->packetizer );
 
     var_Destroy( p_dec, "packetizer-mpegvideo-sync-iframe" );
 
@@ -251,147 +248,8 @@ static void Close( vlc_object_t *p_this )
 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_BytestreamEmpty( &p_sys->bytestream );
-
-            p_sys->b_discontinuity = true;
-            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_slice = false;
-        }
-        p_sys->i_dts = 0;
-        p_sys->i_pts = 0;
-        p_sys->i_interpolated_dts = 0;
-        p_sys->i_last_ref_pts = 0;
-
-        block_Release( *pp_block );
-        return NULL;
-    }
-
-
-    block_BytestreamPush( &p_sys->bytestream, *pp_block );
-
-    while( 1 )
-    {
-        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 )
-            {
-                /* Need more data */
-                return NULL;
-            }
-
-            p_sys->i_offset = 1; /* 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 )
-            {
-                /* Need more data */
-                return NULL;
-            }
-
-            /* 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;
-
-            block_GetBytes( &p_sys->bytestream, p_pic->p_buffer,
-                            p_pic->i_buffer );
-
-            /* don't reuse the same timestamps several times */
-            if( p_pic->i_buffer >= 4 && p_pic->p_buffer[3] == 0x00 )
-            {
-                /* We have a picture start code */
-                p_sys->bytestream.p_block->i_pts = 0;
-                p_sys->bytestream.p_block->i_dts = 0;
-            }
-
-            p_sys->i_offset = 0;
-
-            /* Get picture if any */
-            if( !( p_pic = ParseMPEGBlock( p_dec, p_pic ) ) )
-            {
-                p_sys->i_state = STATE_NOSYNC;
-                break;
-            }
 
-            /* If a discontinuity has been encountered, then wait till
-             * the next Intra frame before continuing with packetizing */
-            if( p_sys->b_discontinuity &&
-                p_sys->b_sync_on_intra_frame )
-            {
-                if( p_pic->i_flags & BLOCK_FLAG_TYPE_I )
-                {
-                    msg_Dbg( p_dec, "synced on intra frame" );
-                    p_sys->b_discontinuity = false;
-                    p_pic->i_flags |= BLOCK_FLAG_DISCONTINUITY;
-                }
-                else
-                {
-                    msg_Dbg( p_dec, "waiting on intra frame" );
-                    p_sys->i_state = STATE_NOSYNC;
-                    block_Release( p_pic );
-                    break;
-                }
-            }
-
-            /* We've just started the stream, wait for the first PTS.
-             * We discard here so we can still get the sequence header. */
-            if( p_sys->i_dts <= 0 && p_sys->i_pts <= 0 &&
-                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;
-            }
-
-            /* When starting the stream we can have the first frame with
-             * a null DTS (i_interpolated_pts is initialized to 0) */
-            if( !p_pic->i_dts ) p_pic->i_dts = p_pic->i_pts;
-
-            /* So p_block doesn't get re-added several times */
-            *pp_block = block_BytestreamPop( &p_sys->bytestream );
-
-            p_sys->i_state = STATE_NOSYNC;
-
-            return p_pic;
-        }
-    }
+    return packetizer_Packetize( &p_sys->packetizer, pp_block );
 }
 
 /*****************************************************************************
@@ -421,6 +279,76 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] )
     return p_cc;
 }
 
+/*****************************************************************************
+ * Helpers:
+ *****************************************************************************/
+static void PacketizeReset( void *p_private, bool b_broken )
+{
+    decoder_t *p_dec = p_private;
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    if( b_broken )
+    {
+        p_sys->b_discontinuity = true;
+        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_slice = false;
+    }
+    p_sys->i_dts = 0;
+    p_sys->i_pts = 0;
+    p_sys->i_interpolated_dts = 0;
+    p_sys->i_last_ref_pts = 0;
+}
+
+static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block )
+{
+    decoder_t *p_dec = p_private;
+
+    /* Check if we have a picture start code */
+    *pb_ts_used = p_block->i_buffer >= 4 && p_block->p_buffer[3] == 0x00;
+
+    return ParseMPEGBlock( p_dec, p_block );
+}
+
+
+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;
+
+    /* If a discontinuity has been encountered, then wait till
+     * the next Intra frame before continuing with packetizing */
+    if( p_sys->b_discontinuity &&
+        p_sys->b_sync_on_intra_frame )
+    {
+        if( (p_au->i_flags & BLOCK_FLAG_TYPE_I) == 0 )
+        {
+            msg_Dbg( p_dec, "waiting on intra frame" );
+            return VLC_EGENERIC;
+        }
+        msg_Dbg( p_dec, "synced on intra frame" );
+        p_sys->b_discontinuity = false;
+        p_au->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+    }
+
+    /* We've just started the stream, wait for the first PTS.
+     * We discard here so we can still get the sequence header. */
+    if( p_sys->i_dts <= 0 && p_sys->i_pts <= 0 &&
+        p_sys->i_interpolated_dts <= 0 )
+    {
+        msg_Dbg( p_dec, "need a starting pts/dts" );
+        return VLC_EGENERIC;
+    }
+
+    /* When starting the stream we can have the first frame with
+     * a null DTS (i_interpolated_pts is initialized to 0) */
+    if( !p_au->i_dts )
+        p_au->i_dts = p_au->i_pts;
+
+    return VLC_SUCCESS;
+}
 /*****************************************************************************
  * ParseMPEGBlock: Re-assemble fragments into a block containing a picture
  *****************************************************************************/
diff --git a/modules/packetizer/packetizer_helper.h b/modules/packetizer/packetizer_helper.h
new file mode 100644 (file)
index 0000000..33e9c77
--- /dev/null
@@ -0,0 +1,186 @@
+/*****************************************************************************
+ * packetizer.h: Packetizer helpers
+ *****************************************************************************
+ * Copyright (C) 2009 Laurent Aimar
+ * $Id$
+ *
+ * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef _PACKETIZER_H
+#define _PACKETIZER_H 1
+
+#include <vlc_block.h>
+
+enum
+{
+    STATE_NOSYNC,
+    STATE_NEXT_SYNC
+};
+
+typedef void (*packetizer_reset_t)( void *p_private, bool b_broken );
+typedef block_t *(*packetizer_parse_t)( void *p_private, bool *pb_ts_used, block_t * );
+typedef int (*packetizer_validate_t)( void *p_private, block_t * );
+
+typedef struct
+{
+    int i_state;
+    block_bytestream_t bytestream;
+    size_t i_offset;
+
+    int i_startcode;
+    const uint8_t *p_startcode;
+
+    int i_au_prepend;
+    const uint8_t *p_au_prepend;
+
+    void *p_private;
+    packetizer_reset_t    pf_reset;
+    packetizer_parse_t    pf_parse;
+    packetizer_validate_t pf_validate;
+
+} packetizer_t;
+
+static inline void packetizer_Init( packetizer_t *p_pack,
+                                    const uint8_t *p_startcode, int i_startcode,
+                                    const uint8_t *p_au_prepend, int i_au_prepend,
+                                    packetizer_reset_t pf_reset,
+                                    packetizer_parse_t pf_parse,
+                                    packetizer_validate_t pf_validate,
+                                    void *p_private )
+{
+    p_pack->i_state = STATE_NOSYNC;
+    p_pack->bytestream = block_BytestreamInit();
+    p_pack->i_offset = 0;
+
+    p_pack->i_au_prepend = i_au_prepend;
+    p_pack->p_au_prepend = p_au_prepend;
+
+    p_pack->i_startcode = i_startcode;
+    p_pack->p_startcode = p_startcode;
+    p_pack->pf_reset = pf_reset;
+    p_pack->pf_parse = pf_parse;
+    p_pack->pf_validate = pf_validate;
+    p_pack->p_private = p_private;
+}
+
+static inline void packetizer_Clean( packetizer_t *p_pack )
+{
+    block_BytestreamRelease( &p_pack->bytestream );
+}
+
+static inline block_t *packetizer_Packetize( packetizer_t *p_pack, block_t **pp_block )
+{
+    if( !pp_block || !*pp_block )
+        return NULL;
+
+    if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
+    {
+        const bool b_broken = ( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) != 0;
+        if( b_broken )
+        {
+            p_pack->i_state = STATE_NOSYNC;
+            block_BytestreamEmpty( &p_pack->bytestream );
+            p_pack->i_offset = 0;
+        }
+        p_pack->pf_reset( p_pack->p_private, b_broken );
+
+        block_Release( *pp_block );
+        return NULL;
+    }
+
+    block_BytestreamPush( &p_pack->bytestream, *pp_block );
+
+    for( ;; )
+    {
+        bool b_used_ts;
+        block_t *p_pic;
+
+        switch( p_pack->i_state )
+        {
+        case STATE_NOSYNC:
+            /* Find a startcode */
+            if( !block_FindStartcodeFromOffset( &p_pack->bytestream, &p_pack->i_offset,
+                                                p_pack->p_startcode, p_pack->i_startcode ) )
+                p_pack->i_state = STATE_NEXT_SYNC;
+
+            if( p_pack->i_offset )
+            {
+                block_SkipBytes( &p_pack->bytestream, p_pack->i_offset );
+                p_pack->i_offset = 0;
+                block_BytestreamFlush( &p_pack->bytestream );
+            }
+
+            if( p_pack->i_state != STATE_NEXT_SYNC )
+                return NULL; /* Need more data */
+
+            p_pack->i_offset = 1; /* To find next startcode */
+
+        case STATE_NEXT_SYNC:
+            /* Find the next startcode */
+            if( block_FindStartcodeFromOffset( &p_pack->bytestream, &p_pack->i_offset,
+                                               p_pack->p_startcode, p_pack->i_startcode ) )
+                return NULL; /* Need more data */
+
+            block_BytestreamFlush( &p_pack->bytestream );
+
+            /* Get the new fragment and set the pts/dts */
+            block_t *p_block_bytestream = p_pack->bytestream.p_block;
+
+            p_pic = block_New( p_dec, p_pack->i_offset + p_pack->i_au_prepend );
+            p_pic->i_pts = p_block_bytestream->i_pts;
+            p_pic->i_dts = p_block_bytestream->i_dts;
+
+            block_GetBytes( &p_pack->bytestream, &p_pic->p_buffer[p_pack->i_au_prepend],
+                            p_pic->i_buffer - p_pack->i_au_prepend );
+            if( p_pack->i_au_prepend > 0 )
+                memcpy( p_pic->p_buffer, p_pack->p_au_prepend, p_pack->i_au_prepend );
+
+            p_pack->i_offset = 0;
+
+            /* Parse the NAL */
+            p_pic = p_pack->pf_parse( p_pack->p_private, &b_used_ts, p_pic );
+            if( b_used_ts )
+            {
+                p_block_bytestream->i_dts = -1;
+                p_block_bytestream->i_pts = -1;
+            }
+
+            if( !p_pic )
+            {
+                p_pack->i_state = STATE_NOSYNC;
+                break;
+            }
+            if( p_pack->pf_validate( p_pack->p_private, p_pic ) )
+            {
+                p_pack->i_state = STATE_NOSYNC;
+                block_Release( p_pic );
+                break;
+            }
+
+            /* So p_block doesn't get re-added several times */
+            *pp_block = block_BytestreamPop( &p_pack->bytestream );
+
+            p_pack->i_state = STATE_NOSYNC;
+
+            return p_pic;
+        }
+    }
+}
+
+#endif
+
index e628940..2cd4bc8 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "vlc_bits.h"
 #include "vlc_block_helper.h"
+#include "packetizer_helper.h"
 
 /*****************************************************************************
  * Module descriptor
@@ -60,10 +61,7 @@ struct decoder_sys_t
     /*
      * Input properties
      */
-    block_bytestream_t bytestream;
-    int i_state;
-    size_t i_offset;
-    uint8_t p_startcode[3];
+    packetizer_t packetizer;
 
     /* Current sequence header */
     bool b_sequence_header;
@@ -93,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,
@@ -117,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
  *****************************************************************************
@@ -137,12 +136,10 @@ 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_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 = false;
     p_sys->sh.p_sh = NULL;
@@ -155,7 +152,6 @@ static int Open( vlc_object_t *p_this )
 
     p_sys->i_interpolated_dts = -1;
 
-    /* */
     if( p_dec->fmt_out.i_extra > 0 )
     {
         uint8_t *p_extra = p_dec->fmt_out.p_extra;
@@ -192,7 +188,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 );
@@ -201,112 +197,50 @@ static void Close( vlc_object_t *p_this )
 /*****************************************************************************
  * Packetize: packetize an access unit
  *****************************************************************************/
-static block_t *ParseIDU( decoder_t *p_dec, bool *pb_used_ts, 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_BytestreamEmpty( &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 = 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 )
     {
-        bool b_used_ts;
-
-        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;
-
-            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, &b_used_ts, p_pic );
-
-            /* Don't reuse the same timestamps several times */
-            if( b_used_ts )
-            {
-                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 )
 {