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 @@
#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;
......
......@@ -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;
}
/*****************************************************************************
......
......@@ -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
*****************************************************************************/
......
/*****************************************************************************
* 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 @@
#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 )
{
......
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