Commit 55441fa5 authored by Laurent Aimar's avatar Laurent Aimar

Moved and fixed all common code from video packetizers into packetizer_helper.h

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.
parent 7aa5ac93
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "vlc_block_helper.h" #include "vlc_block_helper.h"
#include "vlc_bits.h" #include "vlc_bits.h"
#include "../codec/cc.h" #include "../codec/cc.h"
#include "packetizer_helper.h"
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
...@@ -60,10 +61,6 @@ vlc_module_end () ...@@ -60,10 +61,6 @@ vlc_module_end ()
/**************************************************************************** /****************************************************************************
* Local prototypes * 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 typedef struct
{ {
int i_nal_type; int i_nal_type;
...@@ -89,12 +86,10 @@ typedef struct ...@@ -89,12 +86,10 @@ typedef struct
#define PPS_MAX (256) #define PPS_MAX (256)
struct decoder_sys_t struct decoder_sys_t
{ {
block_bytestream_t bytestream; /* */
packetizer_t packetizer;
int i_state;
size_t i_offset;
uint8_t startcode[4];
/* */
bool b_slice; bool b_slice;
block_t *p_frame; block_t *p_frame;
...@@ -133,12 +128,6 @@ struct decoder_sys_t ...@@ -133,12 +128,6 @@ struct decoder_sys_t
cc_data_t cc_next; cc_data_t cc_next;
}; };
enum
{
STATE_NOSYNC,
STATE_NEXT_SYNC,
};
enum nal_unit_type_e enum nal_unit_type_e
{ {
NAL_UNKNOWN = 0, NAL_UNKNOWN = 0,
...@@ -162,8 +151,15 @@ enum nal_priority_e ...@@ -162,8 +151,15 @@ enum nal_priority_e
NAL_PRIORITY_HIGHEST = 3, 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 *CreateAnnexbNAL( decoder_t *, const uint8_t *p, int );
static block_t *OutputPicture( decoder_t *p_dec ); 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 ...@@ -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 void ParseSei( decoder_t *, block_t * );
static const uint8_t p_h264_startcode[3] = { 0x00, 0x00, 0x01 };
/***************************************************************************** /*****************************************************************************
* Open: probe the packetizer and return score * Open: probe the packetizer and return score
* When opening after demux, the packetizer is only loaded AFTER the decoder * When opening after demux, the packetizer is only loaded AFTER the decoder
...@@ -203,13 +201,12 @@ static int Open( vlc_object_t *p_this ) ...@@ -203,13 +201,12 @@ static int Open( vlc_object_t *p_this )
{ {
return VLC_ENOMEM; return VLC_ENOMEM;
} }
p_sys->i_state = STATE_NOSYNC;
p_sys->i_offset = 0; packetizer_Init( &p_sys->packetizer,
p_sys->startcode[0] = 0; p_h264_startcode, sizeof(p_h264_startcode),
p_sys->startcode[1] = 0; p_h264_startcode, 1,
p_sys->startcode[2] = 0; PacketizeReset, PacketizeParse, PacketizeValidate, p_dec );
p_sys->startcode[3] = 1;
p_sys->bytestream = block_BytestreamInit();
p_sys->b_slice = false; p_sys->b_slice = false;
p_sys->p_frame = NULL; p_sys->p_frame = NULL;
p_sys->b_header= false; p_sys->b_header= false;
...@@ -397,7 +394,8 @@ static void Close( vlc_object_t *p_this ) ...@@ -397,7 +394,8 @@ static void Close( vlc_object_t *p_this )
if( p_sys->pp_pps[i] ) if( p_sys->pp_pps[i] )
block_Release( 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 ) if( p_dec->pf_get_cc )
{ {
cc_Exit( &p_sys->cc_next ); cc_Exit( &p_sys->cc_next );
...@@ -415,117 +413,8 @@ static void Close( vlc_object_t *p_this ) ...@@ -415,117 +413,8 @@ static void Close( vlc_object_t *p_this )
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
{ {
decoder_sys_t *p_sys = p_dec->p_sys; 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 ) return packetizer_Packetize( &p_sys->packetizer, pp_block );
{
/* 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;
}
}
} }
/**************************************************************************** /****************************************************************************
...@@ -618,6 +507,39 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] ) ...@@ -618,6 +507,39 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] )
/**************************************************************************** /****************************************************************************
* Helpers * 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 ) static block_t *CreateAnnexbNAL( decoder_t *p_dec, const uint8_t *p, int i_size )
{ {
block_t *p_nal; block_t *p_nal;
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "vlc_bits.h" #include "vlc_bits.h"
#include "vlc_block_helper.h" #include "vlc_block_helper.h"
#include "packetizer_helper.h"
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
...@@ -57,17 +58,12 @@ vlc_module_end () ...@@ -57,17 +58,12 @@ vlc_module_end ()
/**************************************************************************** /****************************************************************************
* Local prototypes * Local prototypes
****************************************************************************/ ****************************************************************************/
static block_t *Packetize( decoder_t *, block_t ** );
struct decoder_sys_t struct decoder_sys_t
{ {
/* /*
* Input properties * Input properties
*/ */
block_bytestream_t bytestream; packetizer_t packetizer;
int i_state;
size_t i_offset;
uint8_t p_startcode[3];
/* /*
* Common properties * Common properties
...@@ -94,10 +90,11 @@ struct decoder_sys_t ...@@ -94,10 +90,11 @@ struct decoder_sys_t
block_t **pp_last; block_t **pp_last;
}; };
enum { static block_t *Packetize( decoder_t *, block_t ** );
STATE_NOSYNC,
STATE_NEXT_SYNC 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 block_t *ParseMPEGBlock( decoder_t *, block_t * );
static int ParseVOL( decoder_t *, es_format_t *, uint8_t *, int ); static int ParseVOL( decoder_t *, es_format_t *, uint8_t *, int );
...@@ -124,6 +121,8 @@ static int vlc_log2( unsigned int ); ...@@ -124,6 +121,8 @@ static int vlc_log2( unsigned int );
#define TEXTURE_SPATIAL_LAYER_START_CODE 0x1bf #define TEXTURE_SPATIAL_LAYER_START_CODE 0x1bf
#define TEXTURE_SNR_LAYER_START_CODE 0x1c0 #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 * Open: probe the packetizer and return score
*****************************************************************************/ *****************************************************************************/
...@@ -163,12 +162,11 @@ static int Open( vlc_object_t *p_this ) ...@@ -163,12 +162,11 @@ static int Open( vlc_object_t *p_this )
memset( p_sys, 0, sizeof(decoder_sys_t) ); memset( p_sys, 0, sizeof(decoder_sys_t) );
/* Misc init */ /* Misc init */
p_sys->i_state = STATE_NOSYNC; packetizer_Init( &p_sys->packetizer,
p_sys->bytestream = block_BytestreamInit(); p_mp4v_startcode, sizeof(p_mp4v_startcode),
p_sys->p_startcode[0] = 0; NULL, 0,
p_sys->p_startcode[1] = 0; PacketizeReset, PacketizeParse, PacketizeValidate, p_dec );
p_sys->p_startcode[2] = 1;
p_sys->i_offset = 0;
p_sys->p_frame = NULL; p_sys->p_frame = NULL;
p_sys->pp_last = &p_sys->p_frame; p_sys->pp_last = &p_sys->p_frame;
...@@ -207,10 +205,12 @@ static int Open( vlc_object_t *p_this ) ...@@ -207,10 +205,12 @@ static int Open( vlc_object_t *p_this )
static void Close( vlc_object_t *p_this ) static void Close( vlc_object_t *p_this )
{ {
decoder_t *p_dec = (decoder_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 ); packetizer_Clean( &p_sys->packetizer );
if( p_dec->p_sys->p_frame ) block_ChainRelease( p_dec->p_sys->p_frame ); if( p_sys->p_frame )
free( p_dec->p_sys ); block_ChainRelease( p_sys->p_frame );
free( p_sys );
} }
/**************************************************************************** /****************************************************************************
...@@ -219,125 +219,68 @@ static void Close( vlc_object_t *p_this ) ...@@ -219,125 +219,68 @@ static void Close( vlc_object_t *p_this )
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
{ {
decoder_sys_t *p_sys = p_dec->p_sys; 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 ) if( p_sys->p_frame )
{ block_ChainRelease( p_sys->p_frame );
p_sys->i_state = STATE_NOSYNC; p_sys->p_frame = NULL;
block_BytestreamEmpty( &p_sys->bytestream ); p_sys->pp_last = &p_sys->p_frame;
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;
} }
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 ) static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block )
{ {
switch( p_sys->i_state ) 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: block_t *p_au = ParseMPEGBlock( p_dec, p_block );
if( block_FindStartcodeFromOffset( &p_sys->bytestream,
&p_sys->i_offset, p_sys->p_startcode, 3 ) == VLC_SUCCESS ) *pb_ts_used = p_au && p_au->i_dts == i_dts && p_au->i_pts == i_pts;
{
p_sys->i_state = STATE_NEXT_SYNC; return p_au;
} }
if( p_sys->i_offset )
{ static int PacketizeValidate( void *p_private, block_t *p_au )
block_SkipBytes( &p_sys->bytestream, p_sys->i_offset ); {
p_sys->i_offset = 0; decoder_t *p_dec = p_private;
block_BytestreamFlush( &p_sys->bytestream ); decoder_sys_t *p_sys = p_dec->p_sys;
}
/* We've just started the stream, wait for the first PTS.
if( p_sys->i_state != STATE_NEXT_SYNC ) * We discard here so we can still get the sequence header. */
{ if( p_sys->i_interpolated_pts <= 0 &&
/* Need more data */ p_sys->i_interpolated_dts <= 0 )
return NULL; {
} msg_Dbg( p_dec, "need a starting pts/dts" );
return VLC_EGENERIC;
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;
}
} }
/* 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;
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include <vlc_codec.h> #include <vlc_codec.h>
#include <vlc_block_helper.h> #include <vlc_block_helper.h>
#include "../codec/cc.h" #include "../codec/cc.h"
#include "packetizer_helper.h"
#define SYNC_INTRAFRAME_TEXT N_("Sync on Intra Frame") #define SYNC_INTRAFRAME_TEXT N_("Sync on Intra Frame")
#define SYNC_INTRAFRAME_LONGTEXT N_("Normally the packetizer would " \ #define SYNC_INTRAFRAME_LONGTEXT N_("Normally the packetizer would " \
...@@ -79,19 +80,12 @@ vlc_module_end () ...@@ -79,19 +80,12 @@ vlc_module_end ()
/***************************************************************************** /*****************************************************************************
* Local prototypes * 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 struct decoder_sys_t
{ {
/* /*
* Input properties * Input properties
*/ */
block_bytestream_t bytestream; packetizer_t packetizer;
int i_state;
size_t i_offset;
uint8_t p_startcode[3];
/* Sequence header and extension */ /* Sequence header and extension */
block_t *p_seq; block_t *p_seq;
...@@ -140,10 +134,16 @@ struct decoder_sys_t ...@@ -140,10 +134,16 @@ struct decoder_sys_t
cc_data_t cc; cc_data_t cc;
}; };
enum { static block_t *Packetize( decoder_t *, block_t ** );
STATE_NOSYNC, static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] );
STATE_NEXT_SYNC
}; 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: * Open:
...@@ -170,12 +170,10 @@ static int Open( vlc_object_t *p_this ) ...@@ -170,12 +170,10 @@ static int Open( vlc_object_t *p_this )
memset( p_dec->p_sys, 0, sizeof( decoder_sys_t ) ); memset( p_dec->p_sys, 0, sizeof( decoder_sys_t ) );
/* Misc init */ /* Misc init */
p_sys->i_state = STATE_NOSYNC; packetizer_Init( &p_sys->packetizer,
p_sys->bytestream = block_BytestreamInit(); p_mp2v_startcode, sizeof(p_mp2v_startcode),
p_sys->p_startcode[0] = 0; NULL, 0,
p_sys->p_startcode[1] = 0; PacketizeReset, PacketizeParse, PacketizeValidate, p_dec );
p_sys->p_startcode[2] = 1;
p_sys->i_offset = 0;
p_sys->p_seq = NULL; p_sys->p_seq = NULL;
p_sys->p_ext = NULL; p_sys->p_ext = NULL;
...@@ -225,8 +223,6 @@ static void Close( vlc_object_t *p_this ) ...@@ -225,8 +223,6 @@ static void Close( vlc_object_t *p_this )
decoder_t *p_dec = (decoder_t*)p_this; decoder_t *p_dec = (decoder_t*)p_this;
decoder_sys_t *p_sys = p_dec->p_sys; decoder_sys_t *p_sys = p_dec->p_sys;
block_BytestreamRelease( &p_sys->bytestream );
if( p_sys->p_seq ) if( p_sys->p_seq )
{ {
block_Release( p_sys->p_seq ); block_Release( p_sys->p_seq );
...@@ -239,6 +235,7 @@ static void Close( vlc_object_t *p_this ) ...@@ -239,6 +235,7 @@ static void Close( vlc_object_t *p_this )
{ {
block_ChainRelease( p_sys->p_frame ); block_ChainRelease( p_sys->p_frame );
} }
packetizer_Clean( &p_sys->packetizer );
var_Destroy( p_dec, "packetizer-mpegvideo-sync-iframe" ); var_Destroy( p_dec, "packetizer-mpegvideo-sync-iframe" );
...@@ -251,147 +248,8 @@ static void Close( vlc_object_t *p_this ) ...@@ -251,147 +248,8 @@ static void Close( vlc_object_t *p_this )
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
{ {
decoder_sys_t *p_sys = p_dec->p_sys; 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 return packetizer_Packetize( &p_sys->packetizer, pp_block );
* 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;
}
}
} }
/***************************************************************************** /*****************************************************************************
...@@ -421,6 +279,76 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] ) ...@@ -421,6 +279,76 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] )
return p_cc; 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 * ParseMPEGBlock: Re-assemble fragments into a block containing a picture
*****************************************************************************/ *****************************************************************************/
......
/*****************************************************************************
* 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
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "vlc_bits.h" #include "vlc_bits.h"
#include "vlc_block_helper.h" #include "vlc_block_helper.h"
#include "packetizer_helper.h"
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
...@@ -60,10 +61,7 @@ struct decoder_sys_t ...@@ -60,10 +61,7 @@ struct decoder_sys_t
/* /*
* Input properties * Input properties
*/ */
block_bytestream_t bytestream; packetizer_t packetizer;
int i_state;
size_t i_offset;
uint8_t p_startcode[3];
/* Current sequence header */ /* Current sequence header */
bool b_sequence_header; bool b_sequence_header;
...@@ -93,12 +91,6 @@ struct decoder_sys_t ...@@ -93,12 +91,6 @@ struct decoder_sys_t
mtime_t i_interpolated_dts; mtime_t i_interpolated_dts;
}; };
enum
{
STATE_NOSYNC,
STATE_NEXT_SYNC
};
typedef enum typedef enum
{ {
IDU_TYPE_SEQUENCE_HEADER = 0x0f, IDU_TYPE_SEQUENCE_HEADER = 0x0f,
...@@ -117,6 +109,13 @@ typedef enum ...@@ -117,6 +109,13 @@ typedef enum
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ); 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 * Open: probe the packetizer and return score
***************************************************************************** *****************************************************************************
...@@ -137,12 +136,10 @@ static int Open( vlc_object_t *p_this ) ...@@ -137,12 +136,10 @@ static int Open( vlc_object_t *p_this )
es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) ); p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
p_sys->i_state = STATE_NOSYNC; packetizer_Init( &p_sys->packetizer,
p_sys->bytestream = block_BytestreamInit(); p_vc1_startcode, sizeof(p_vc1_startcode),
p_sys->p_startcode[0] = 0x00; NULL, 0,
p_sys->p_startcode[1] = 0x00; PacketizeReset, PacketizeParse, PacketizeValidate, p_dec );
p_sys->p_startcode[2] = 0x01;
p_sys->i_offset = 0;
p_sys->b_sequence_header = false; p_sys->b_sequence_header = false;
p_sys->sh.p_sh = NULL; p_sys->sh.p_sh = NULL;
...@@ -155,7 +152,6 @@ static int Open( vlc_object_t *p_this ) ...@@ -155,7 +152,6 @@ static int Open( vlc_object_t *p_this )
p_sys->i_interpolated_dts = -1; p_sys->i_interpolated_dts = -1;
/* */
if( p_dec->fmt_out.i_extra > 0 ) if( p_dec->fmt_out.i_extra > 0 )
{ {
uint8_t *p_extra = p_dec->fmt_out.p_extra; uint8_t *p_extra = p_dec->fmt_out.p_extra;
...@@ -192,7 +188,7 @@ static void Close( vlc_object_t *p_this ) ...@@ -192,7 +188,7 @@ static void Close( vlc_object_t *p_this )
decoder_t *p_dec = (decoder_t*)p_this; decoder_t *p_dec = (decoder_t*)p_this;
decoder_sys_t *p_sys = p_dec->p_sys; decoder_sys_t *p_sys = p_dec->p_sys;
block_BytestreamRelease( &p_sys->bytestream ); packetizer_Clean( &p_sys->packetizer );
if( p_sys->p_frame ) if( p_sys->p_frame )
block_Release( p_sys->p_frame ); block_Release( p_sys->p_frame );
free( p_sys ); free( p_sys );
...@@ -201,112 +197,50 @@ static void Close( vlc_object_t *p_this ) ...@@ -201,112 +197,50 @@ static void Close( vlc_object_t *p_this )
/***************************************************************************** /*****************************************************************************
* Packetize: packetize an access unit * 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 ) static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
{ {
decoder_sys_t *p_sys = p_dec->p_sys; 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) ) return packetizer_Packetize( &p_sys->packetizer, pp_block );
{ }
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;
}
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; if( p_sys->p_frame )
block_ChainRelease( p_sys->p_frame );
switch( p_sys->i_state ) p_sys->p_frame = NULL;
{ p_sys->pp_last = &p_sys->p_frame;
p_sys->b_frame = false;
case STATE_NOSYNC: }
if( block_FindStartcodeFromOffset( &p_sys->bytestream, &p_sys->i_offset, p_sys->p_startcode, 3 ) == VLC_SUCCESS ) p_sys->i_interpolated_dts = 0;
p_sys->i_state = STATE_NEXT_SYNC; }
static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block )
if( p_sys->i_offset ) {
{ decoder_t *p_dec = p_private;
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;
}
/* So p_block doesn't get re-added several times */ return ParseIDU( p_dec, pb_ts_used, p_block );
*pp_block = block_BytestreamPop( &p_sys->bytestream ); }
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) */ /* 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 ) static void DecodeRIDU( uint8_t *p_ret, int *pi_ret, uint8_t *src, int i_src )
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment