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 )