Commit 2c51255f authored by Rafaël Carré's avatar Rafaël Carré Committed by Rémi Denis-Courmont

asf demux: rewrite DemuxPacket

Split it in several functions

(cherry picked from commit 6eddafe741954803ec2928d26fb7566bd07a3601)
Signed-off-by: default avatarRémi Denis-Courmont <remi@remlab.net>
parent f0fd1cbe
...@@ -408,289 +408,279 @@ static inline int GetValue2b(int *var, const uint8_t *p, int *skip, int left, in ...@@ -408,289 +408,279 @@ static inline int GetValue2b(int *var, const uint8_t *p, int *skip, int left, in
} }
} }
static int DemuxPacket( demux_t *p_demux ) struct asf_packet_t
{ {
demux_sys_t *p_sys = p_demux->p_sys; int property;
int length;
int i_data_packet_min = p_sys->p_fp->i_min_data_packet_size; int padding_length;
const uint8_t *p_peek; uint32_t send_time;
bool multiple;
int length_type;
/* buffer handling for this ASF packet */
int i_skip; int i_skip;
int peek_size; const uint8_t *p_peek;
int left;
if( stream_Peek( p_demux->s, &p_peek,i_data_packet_min)<i_data_packet_min ) };
{
msg_Warn( p_demux, "cannot peek while getting new packet, EOF ?" );
return 0;
}
peek_size = i_data_packet_min;
i_skip = 0;
/* *** parse error correction if present *** */ static void SendPacket(demux_t *p_demux, asf_track_t *tk)
if( p_peek[0]&0x80 ) {
{ demux_sys_t *p_sys = p_demux->p_sys;
unsigned int i_error_correction_data_length = p_peek[0] & 0x0f;
unsigned int i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;
unsigned int i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03;
i_skip += 1; // skip error correction flags
if( i_error_correction_length_type != 0x00 || block_t *p_gather = block_ChainGather( tk->p_frame );
i_opaque_data_present != 0 ||
i_error_correction_data_length != 0x02 )
{
goto loop_error_recovery;
}
i_skip += i_error_correction_data_length; if( p_gather->i_dts > VLC_TS_INVALID )
} tk->i_time = p_gather->i_dts - VLC_TS_0;
else
{
msg_Warn( p_demux, "p_peek[0]&0x80 != 0x80" );
}
/* sanity check */ if( p_sys->i_time < 0 )
if( i_skip + 2 >= i_data_packet_min ) es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_gather->i_dts );
{
goto loop_error_recovery;
}
int i_packet_flags = p_peek[i_skip]; i_skip++; es_out_Send( p_demux->out, tk->p_es, p_gather );
int i_packet_property = p_peek[i_skip]; i_skip++;
int b_packet_multiple_payload = i_packet_flags&0x01;
int i_packet_length = i_data_packet_min; tk->p_frame = NULL;
int i_packet_sequence = 0; }
int i_packet_padding_length = 0;
if (GetValue2b(&i_packet_length, p_peek, &i_skip, peek_size - i_skip, i_packet_flags >> 5) < 0) static int DemuxSubPayload(demux_t *p_demux, asf_track_t *tk,
goto loop_error_recovery; int i_sub_payload_data_length, mtime_t i_pts, int i_media_object_offset)
if (GetValue2b(&i_packet_sequence, p_peek, &i_skip, peek_size - i_skip, i_packet_flags >> 1) < 0) {
goto loop_error_recovery; /* FIXME I don't use i_media_object_number, sould I ? */
if (GetValue2b(&i_packet_padding_length, p_peek, &i_skip, peek_size - i_skip, i_packet_flags >> 3) < 0) if( tk->p_frame && i_media_object_offset == 0 )
goto loop_error_recovery; SendPacket(p_demux, tk);
if( i_packet_padding_length > i_packet_length ) block_t *p_frag = stream_Block( p_demux->s, i_sub_payload_data_length );
{ if( p_frag == NULL ) {
msg_Warn( p_demux, "Too large padding: %d", i_packet_padding_length ); msg_Warn( p_demux, "cannot read data" );
goto loop_error_recovery; return -1;
} }
if( i_packet_length < i_data_packet_min ) if( tk->p_frame == NULL ) {
{ p_frag->i_pts = VLC_TS_0 + i_pts;
/* if packet length too short, there is extra padding */ p_frag->i_dts = VLC_TS_0 + p_frag->i_pts; //FIXME: VLC_TS_0 * 2 ?
i_packet_padding_length += i_data_packet_min - i_packet_length; if( tk->i_cat == VIDEO_ES )
i_packet_length = i_data_packet_min; p_frag->i_pts = VLC_TS_INVALID;
} }
uint32_t i_packet_send_time = GetDWLE( p_peek + i_skip ); i_skip += 4; block_ChainAppend( &tk->p_frame, p_frag );
/* uint16_t i_packet_duration = GetWLE( p_peek + i_skip ); */ i_skip += 2;
int i_packet_size_left = i_packet_length; return 0;
}
int i_payload_count = 1; static int DemuxPayload(demux_t *p_demux, struct asf_packet_t *pkt, int i_payload)
int i_payload_length_type = 0x02; //unused {
if( b_packet_multiple_payload ) demux_sys_t *p_sys = p_demux->p_sys;
{
i_payload_count = p_peek[i_skip] & 0x3f; if( pkt->i_skip >= pkt->left )
i_payload_length_type = ( p_peek[i_skip] >> 6 )&0x03; return -1;
i_skip++;
} int i_packet_keyframe = pkt->p_peek[pkt->i_skip] >> 7;
unsigned int i_stream_number = pkt->p_peek[pkt->i_skip++] & 0x7f;
for( int i_payload = 0; i_payload < i_payload_count ; i_payload++ )
{
int i_media_object_number = 0; int i_media_object_number = 0;
int i_media_object_offset; if (GetValue2b(&i_media_object_number, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 4) < 0)
return -1;
int i_media_object_offset = 0;
if (GetValue2b(&i_media_object_offset, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 2) < 0)
return -1;
int i_replicated_data_length = 0; int i_replicated_data_length = 0;
int i_payload_data_length = 0; if (GetValue2b(&i_replicated_data_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property) < 0)
int i_sub_payload_data_length; return -1;
int i_tmp = 0;
mtime_t i_pts; mtime_t i_pts;
mtime_t i_pts_delta;
if( i_skip >= i_packet_size_left )
{
/* prevent some segfault with invalid file */
break;
}
int i_packet_keyframe = p_peek[i_skip] >> 7;
unsigned int i_stream_number = p_peek[i_skip++] & 0x7f;
if (GetValue2b(&i_media_object_number, p_peek, &i_skip, peek_size - i_skip, i_packet_property >> 4) < 0)
break;
if (GetValue2b(&i_tmp, p_peek, &i_skip, peek_size - i_skip, i_packet_property >> 2) < 0)
break;
if (GetValue2b(&i_replicated_data_length, p_peek, &i_skip, peek_size - i_skip, i_packet_property) < 0)
break;
if( i_replicated_data_length > 1 ) // should be at least 8 bytes if( i_replicated_data_length > 1 ) // should be at least 8 bytes
{ {
i_pts = (mtime_t)GetDWLE( p_peek + i_skip + 4 ) * 1000; i_pts = (mtime_t)GetDWLE( pkt->p_peek + pkt->i_skip + 4 );
i_skip += i_replicated_data_length; pkt->i_skip += i_replicated_data_length;
i_pts_delta = 0;
i_media_object_offset = i_tmp; if( pkt->i_skip >= pkt->left )
return -1;
if( i_skip >= i_packet_size_left )
{
break;
}
} }
else if( i_replicated_data_length == 1 ) else if( i_replicated_data_length == 1 )
{ {
/* msg_Dbg( p_demux, "found compressed payload" ); */ i_pts = (mtime_t)i_media_object_offset + (mtime_t)pkt->p_peek[pkt->i_skip] * i_payload;
pkt->i_skip++;
i_pts = (mtime_t)i_tmp * 1000;
i_pts_delta = (mtime_t)p_peek[i_skip] * 1000; i_skip++;
i_media_object_offset = 0; i_media_object_offset = 0;
} }
else else
{ {
i_pts = (mtime_t)i_packet_send_time * 1000; i_pts = (mtime_t)pkt->send_time * 1000;
i_pts_delta = 0;
i_media_object_offset = i_tmp;
} }
i_pts = __MAX( i_pts - p_sys->p_fp->i_preroll * 1000, 0 ); i_pts -= p_sys->p_fp->i_preroll;
if( b_packet_multiple_payload ) if (i_pts < 0) i_pts = 0; // FIXME?
{ i_pts *= 1000; // FIXME ?
i_payload_data_length = 0;
if (GetValue2b(&i_payload_data_length, p_peek, &i_skip, peek_size - i_skip, i_payload_length_type) < 0) int i_payload_data_length = 0;
break; if( pkt->multiple ) {
} if (GetValue2b(&i_payload_data_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->length_type) < 0)
else return -1;
{ } else
i_payload_data_length = i_packet_length - i_payload_data_length = pkt->length - pkt->padding_length - pkt->i_skip;
i_packet_padding_length - i_skip;
} if( i_payload_data_length < 0 || i_payload_data_length > pkt->left )
return -1;
if( i_payload_data_length < 0 || i_payload_data_length > i_packet_size_left )
{
break;
}
#ifdef ASF_DEBUG #ifdef ASF_DEBUG
msg_Dbg( p_demux, msg_Dbg( p_demux,
"payload(%d/%d) stream_number:%d media_object_number:%d media_object_offset:%d replicated_data_length:%d payload_data_length %d", "payload(%d) stream_number:%d media_object_number:%d media_object_offset:%d replicated_data_length:%d payload_data_length %d",
i_payload + 1, i_payload_count, i_stream_number, i_media_object_number, i_payload + 1, i_stream_number, i_media_object_number,
i_media_object_offset, i_replicated_data_length, i_payload_data_length ); i_media_object_offset, i_replicated_data_length, i_payload_data_length );
#endif #endif
asf_track_t *tk = p_sys->track[i_stream_number]; asf_track_t *tk = p_sys->track[i_stream_number];
if( tk == NULL ) if( tk == NULL )
{ {
msg_Warn( p_demux, msg_Warn( p_demux, "undeclared stream[Id 0x%x]", i_stream_number );
"undeclared stream[Id 0x%x]", i_stream_number ); goto skip;
i_skip += i_payload_data_length;
continue; // over payload
} }
if( p_sys->i_wait_keyframe && if( p_sys->i_wait_keyframe && !i_media_object_offset &&
!(i_stream_number == p_sys->i_seek_track && i_packet_keyframe && (i_stream_number != p_sys->i_seek_track || !i_packet_keyframe) )
!i_media_object_offset) )
{ {
i_skip += i_payload_data_length;
p_sys->i_wait_keyframe--; p_sys->i_wait_keyframe--;
continue; // over payload goto skip;
} }
p_sys->i_wait_keyframe = 0; p_sys->i_wait_keyframe = 0;
if( !tk->p_es ) if( !tk->p_es )
goto skip;
while (i_payload_data_length)
{ {
i_skip += i_payload_data_length; int i_sub_payload_data_length = i_payload_data_length;
continue; if( i_replicated_data_length == 1 )
} i_sub_payload_data_length = pkt->p_peek[pkt->i_skip++];
stream_Read(p_demux->s, NULL, pkt->i_skip);
for( int i_payload_data_pos = 0; if (DemuxSubPayload(p_demux, tk, i_sub_payload_data_length, i_pts,
i_payload_data_pos < i_payload_data_length && i_media_object_offset) < 0)
i_packet_size_left > 0; return -1;
i_payload_data_pos += i_sub_payload_data_length )
{
block_t *p_frag;
int i_read;
// read sub payload length pkt->left -= pkt->i_skip + i_sub_payload_data_length;
if( i_replicated_data_length == 1 ) pkt->i_skip = 0;
{ if( pkt->left > 0 && stream_Peek( p_demux->s, &pkt->p_peek, pkt->left ) < pkt->left ) {
i_sub_payload_data_length = p_peek[i_skip]; i_skip++; msg_Warn( p_demux, "cannot peek, EOF ?" );
i_payload_data_pos++; return -1;
}
else
{
i_sub_payload_data_length = i_payload_data_length;
} }
/* FIXME I don't use i_media_object_number, sould I ? */ i_payload_data_length -= i_sub_payload_data_length;
if( tk->p_frame && i_media_object_offset == 0 ) }
{
/* send complete packet to decoder */
block_t *p_gather = block_ChainGather( tk->p_frame );
if( p_gather->i_dts > VLC_TS_INVALID ) return 0;
tk->i_time = p_gather->i_dts - VLC_TS_0;
if( p_sys->i_time < 0 ) skip:
es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + tk->i_time ); pkt->i_skip += i_payload_data_length;
return 0;
}
es_out_Send( p_demux->out, tk->p_es, p_gather ); static int DemuxPacket( demux_t *p_demux )
{
demux_sys_t *p_sys = p_demux->p_sys;
tk->p_frame = NULL; int i_data_packet_min = p_sys->p_fp->i_min_data_packet_size;
}
i_read = i_sub_payload_data_length + i_skip; const uint8_t *p_peek;
if( ( p_frag = stream_Block( p_demux->s, i_read ) ) == NULL ) if( stream_Peek( p_demux->s, &p_peek,i_data_packet_min)<i_data_packet_min )
{ {
msg_Warn( p_demux, "cannot read data" ); msg_Warn( p_demux, "cannot peek while getting new packet, EOF ?" );
return 0; return 0;
} }
i_packet_size_left -= i_read; int i_skip = 0;
peek_size = 0;
p_frag->p_buffer += i_skip; /* *** parse error correction if present *** */
p_frag->i_buffer -= i_skip; if( p_peek[0]&0x80 )
{
unsigned int i_error_correction_data_length = p_peek[0] & 0x0f;
unsigned int i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;
unsigned int i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03;
i_skip += 1; // skip error correction flags
if( tk->p_frame == NULL ) if( i_error_correction_length_type != 0x00 ||
i_opaque_data_present != 0 ||
i_error_correction_data_length != 0x02 )
{ {
p_frag->i_pts = VLC_TS_0 + i_pts + i_payload * (mtime_t)i_pts_delta; goto loop_error_recovery;
if( tk->i_cat != VIDEO_ES ) }
p_frag->i_dts = VLC_TS_0 + p_frag->i_pts;
i_skip += i_error_correction_data_length;
}
else else
msg_Warn( p_demux, "no error correction" );
/* sanity check */
if( i_skip + 2 >= i_data_packet_min )
goto loop_error_recovery;
struct asf_packet_t pkt;
int i_packet_flags = p_peek[i_skip]; i_skip++;
pkt.property = p_peek[i_skip]; i_skip++;
pkt.multiple = !!(i_packet_flags&0x01);
pkt.length = i_data_packet_min;
pkt.padding_length = 0;
if (GetValue2b(&pkt.length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 5) < 0)
goto loop_error_recovery;
int i_packet_sequence;
if (GetValue2b(&i_packet_sequence, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 1) < 0)
goto loop_error_recovery;
if (GetValue2b(&pkt.padding_length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 3) < 0)
goto loop_error_recovery;
if( pkt.padding_length > pkt.length )
{ {
p_frag->i_dts = VLC_TS_0 + p_frag->i_pts; msg_Warn( p_demux, "Too large padding: %d", pkt.padding_length );
p_frag->i_pts = VLC_TS_INVALID; goto loop_error_recovery;
} }
if( pkt.length < i_data_packet_min )
{
/* if packet length too short, there is extra padding */
pkt.padding_length += i_data_packet_min - pkt.length;
pkt.length = i_data_packet_min;
} }
block_ChainAppend( &tk->p_frame, p_frag ); pkt.send_time = GetDWLE( p_peek + i_skip ); i_skip += 4;
/* uint16_t i_packet_duration = GetWLE( p_peek + i_skip ); */ i_skip += 2;
i_skip = 0; if( pkt.length <= 0 || stream_Peek( p_demux->s, &p_peek, pkt.length ) < pkt.length)
if( i_packet_size_left > 0 )
{
if( stream_Peek( p_demux->s, &p_peek, i_packet_size_left )
< i_packet_size_left )
{ {
msg_Warn( p_demux, "cannot peek, EOF ?" ); msg_Warn( p_demux, "cannot peek, EOF ?" );
return 0; return 0;
} }
peek_size = i_packet_size_left;
} int i_payload_count = 1;
} pkt.length_type = 0x02; //unused
if( pkt.multiple )
{
i_payload_count = p_peek[i_skip] & 0x3f;
pkt.length_type = ( p_peek[i_skip] >> 6 )&0x03;
i_skip++;
} }
if( i_packet_size_left > 0 ) #ifdef ASF_DEBUG
msg_Dbg(p_demux, "%d payloads", i_payload_count);
#endif
pkt.i_skip = i_skip;
pkt.p_peek = p_peek;
pkt.left = pkt.length;
for( int i_payload = 0; i_payload < i_payload_count ; i_payload++ )
if (DemuxPayload(p_demux, &pkt, i_payload) < 0)
return 0;
if( pkt.left > 0 )
{ {
#ifdef ASF_DEBUG #ifdef ASF_DEBUG
if( i_packet_size_left > i_packet_padding_length ) if( pkt.left > pkt.padding_length )
msg_Warn( p_demux, "Didn't read %d bytes in the packet", msg_Warn( p_demux, "Didn't read %d bytes in the packet",
i_packet_size_left - i_packet_padding_length ); pkt.left - pkt.padding_length );
else if( i_packet_size_left < i_packet_padding_length ) else if( pkt.left < pkt.padding_length )
msg_Warn( p_demux, "Read %d too much bytes in the packet", msg_Warn( p_demux, "Read %d too much bytes in the packet",
i_packet_padding_length - i_packet_size_left ); pkt.padding_length - pkt.left );
#endif #endif
if( stream_Read( p_demux->s, NULL, i_packet_size_left ) if( stream_Read( p_demux->s, NULL, pkt.left ) < pkt.left )
< i_packet_size_left )
{ {
msg_Err( p_demux, "cannot skip data, EOF ?" ); msg_Err( p_demux, "cannot skip data, EOF ?" );
return 0; return 0;
......
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