diff options
Diffstat (limited to 'libmediafork/demuxmpeg.c')
-rw-r--r-- | libmediafork/demuxmpeg.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/libmediafork/demuxmpeg.c b/libmediafork/demuxmpeg.c new file mode 100644 index 000000000..54bef2b47 --- /dev/null +++ b/libmediafork/demuxmpeg.c @@ -0,0 +1,125 @@ +/* $Id: demuxmpeg.c,v 1.4 2004/10/19 23:11:36 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "mediafork.h" + +/* Basic MPEG demuxer, only works with DVDs (2048 bytes packets) */ + +int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es ) +{ + hb_buffer_t * buf_es; + int pos; + + pos = 0; + +#define d (buf_ps->data) + + /* pack_header */ + if( d[pos] != 0 || d[pos+1] != 0 || + d[pos+2] != 0x1 || d[pos+3] != 0xBA ) + { + hb_log( "hb_demux_ps: not a PS packet (%02x%02x%02x%02x)", + d[pos], d[pos+1], d[pos+2], d[pos+3] ); + return 0; + } + pos += 4; /* pack_start_code */ + pos += 9; /* pack_header */ + pos += 1 + ( d[pos] & 0x7 ); /* stuffing bytes */ + + /* system_header */ + if( d[pos] == 0 && d[pos+1] == 0 && + d[pos+2] == 0x1 && d[pos+3] == 0xBB ) + { + int header_length; + + pos += 4; /* system_header_start_code */ + header_length = ( d[pos] << 8 ) + d[pos+1]; + pos += 2 + header_length; + } + + /* pes */ + while( pos + 6 < buf_ps->size && + d[pos] == 0 && d[pos+1] == 0 && d[pos+2] == 0x1 ) + { + int id; + int pes_packet_length; + int pes_packet_end; + int pes_header_d_length; + int pes_header_end; + int has_pts; + int64_t pts = -1; + + pos += 3; /* packet_start_code_prefix */ + id = d[pos]; + pos += 1; + + pes_packet_length = ( d[pos] << 8 ) + d[pos+1]; + pos += 2; /* pes_packet_length */ + pes_packet_end = pos + pes_packet_length; + + if( id != 0xE0 && id != 0xBD && + ( id & 0xC0 ) != 0xC0 ) + { + /* Not interesting */ + pos = pes_packet_end; + continue; + } + + has_pts = ( ( d[pos+1] >> 6 ) & 0x2 ) ? 1 : 0; + pos += 2; /* Required headers */ + + pes_header_d_length = d[pos]; + pos += 1; + pes_header_end = pos + pes_header_d_length; + + if( has_pts ) + { + pts = ( ( ( (uint64_t) d[pos] >> 1 ) & 0x7 ) << 30 ) + + ( d[pos+1] << 22 ) + + ( ( d[pos+2] >> 1 ) << 15 ) + + ( d[pos+3] << 7 ) + + ( d[pos+4] >> 1 ); + } + + pos = pes_header_end; + + if( id == 0xBD ) + { + id |= ( d[pos] << 8 ); + if( ( id & 0xF0FF ) == 0x80BD ) /* A52 */ + { + pos += 4; + } + else if( ( id & 0xE0FF ) == 0x20BD || /* SPU */ + ( id & 0xF0FF ) == 0xA0BD ) /* LPCM */ + { + pos += 1; + } + } + + /* Sanity check */ + if( pos >= pes_packet_end ) + { + pos = pes_packet_end; + continue; + } + + /* Here we hit we ES payload */ + buf_es = hb_buffer_init( pes_packet_end - pos ); + + buf_es->id = id; + buf_es->start = pts; + memcpy( buf_es->data, d + pos, pes_packet_end - pos ); + + hb_list_add( list_es, buf_es ); + + pos = pes_packet_end; + } + +#undef d + + return 1; +} |