summaryrefslogtreecommitdiffstats
path: root/HBMpegDemux.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'HBMpegDemux.cpp')
-rw-r--r--HBMpegDemux.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/HBMpegDemux.cpp b/HBMpegDemux.cpp
new file mode 100644
index 000000000..5fda3dde3
--- /dev/null
+++ b/HBMpegDemux.cpp
@@ -0,0 +1,244 @@
+/* $Id: HBMpegDemux.cpp,v 1.13 2003/08/24 19:28:18 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBManager.h"
+#include "HBMpegDemux.h"
+#include "HBFifo.h"
+
+extern "C" {
+#include <a52dec/a52.h>
+}
+
+HBMpegDemux::HBMpegDemux( HBManager * manager, HBTitleInfo * titleInfo,
+ HBAudioInfo * audio1Info, HBAudioInfo * audio2Info )
+ : HBThread( "mpegdemux" )
+{
+ fManager = manager;
+ fTitleInfo = titleInfo;
+ fAudio1Info = audio1Info;
+ fAudio2Info = audio2Info;
+
+ fPSBuffer = NULL;
+ fESBuffer = NULL;
+ fESBufferList = NULL;
+
+ fFirstVideoPTS = -1;
+ fFirstAudio1PTS = -1;
+ fFirstAudio2PTS = -1;
+}
+
+void HBMpegDemux::DoWork()
+{
+ while( !fDie )
+ {
+ /* Get a PS packet */
+ fPSBuffer = fTitleInfo->fPSFifo->Pop();
+
+ if( !fPSBuffer )
+ {
+ continue;
+ }
+
+ /* Get the ES data in it */
+ fESBufferList = PStoES( fPSBuffer );
+
+ if( !fESBufferList )
+ {
+ continue;
+ }
+
+ while( ( fESBuffer = (HBBuffer*) fESBufferList->ItemAt( 0 ) ) )
+ {
+ fESBufferList->RemoveItem( fESBuffer );
+
+ /* Look for a decoder for this ES */
+ if( fESBuffer->fStreamId == 0xE0 )
+ {
+ if( fFirstVideoPTS < 0 )
+ {
+ fFirstVideoPTS = fESBuffer->fPTS;
+ }
+ fTitleInfo->fMpeg2Fifo->Push( fESBuffer );
+ }
+ else if( fESBuffer->fStreamId == fAudio1Info->fId )
+ {
+ /* If the audio track starts later than the video,
+ repeat the first frame as long as needed */
+ if( fFirstAudio1PTS < 0 )
+ {
+ fFirstAudio1PTS = fESBuffer->fPTS;
+
+ if( fFirstAudio1PTS > fFirstVideoPTS )
+ {
+ Log( "HBMpegDemux::DoWork() : audio track %x is late",
+ fAudio1Info->fId );
+ InsertSilence( fFirstAudio1PTS - fFirstVideoPTS,
+ fAudio1Info->fAc3Fifo,
+ fESBuffer );
+ }
+ }
+ fAudio1Info->fAc3Fifo->Push( fESBuffer );
+ }
+ else if( fESBuffer->fStreamId == fAudio2Info->fId )
+ {
+ if( fFirstAudio2PTS < 0 )
+ {
+ fFirstAudio2PTS = fESBuffer->fPTS;
+
+ if( fFirstAudio2PTS > fFirstVideoPTS )
+ {
+ Log( "HBMpegDemux::DoWork() : audio track %x is late",
+ fAudio2Info->fId );
+ InsertSilence( fFirstAudio2PTS - fFirstVideoPTS,
+ fAudio2Info->fAc3Fifo,
+ fESBuffer );
+ }
+ }
+ fAudio2Info->fAc3Fifo->Push( fESBuffer );
+ }
+ else
+ {
+ delete fESBuffer;
+ }
+ }
+ delete fESBufferList;
+ }
+}
+
+void HBMpegDemux::InsertSilence( int64_t time, HBFifo * fifo,
+ HBBuffer * buffer )
+{
+ int flags = 0;
+ int sampleRate = 0;
+ int bitrate = 0;
+ int frameSize = a52_syncinfo( buffer->fData, &flags,
+ &sampleRate, &bitrate );
+
+ if( !frameSize )
+ {
+ Log( "HBMpegDemux::InsertSilence() : a52_syncinfo() failed" );
+ return;
+ }
+
+ uint32_t samples = sampleRate * time / 90000;
+ HBBuffer * buffer2;
+
+ Log( "HBMpegDemux::InsertSilence() : adding %d samples", samples );
+
+ for( uint32_t i = 0; i < samples / ( 6 * 256 ); i++ )
+ {
+ buffer2 = new HBBuffer( frameSize );
+ memcpy( buffer2->fData, buffer->fData, frameSize );
+ fifo->Push( buffer2 );
+ }
+}
+
+BList * PStoES( HBBuffer * psBuffer )
+{
+#define psData (psBuffer->fData)
+
+ BList * esBufferList = new BList();
+ HBBuffer * esBuffer;
+ uint32_t pos = 0;
+
+ /* pack_header */
+ if( psData[pos] != 0 || psData[pos+1] != 0 ||
+ psData[pos+2] != 0x1 || psData[pos+3] != 0xBA )
+ {
+ Log( "PStoES : not a PS packet (%02x%02x%02x%02x)",
+ psData[pos] << 24, psData[pos+1] << 16,
+ psData[pos+2] << 8, psData[pos+3] );
+ delete psBuffer;
+ return NULL;
+ }
+ pos += 4; /* pack_start_code */
+ pos += 9; /* pack_header */
+ pos += 1 + ( psData[pos] & 0x7 ); /* stuffing bytes */
+
+ /* system_header */
+ if( psData[pos] == 0 && psData[pos+1] == 0 &&
+ psData[pos+2] == 0x1 && psData[pos+3] == 0xBB )
+ {
+ uint32_t header_length;
+
+ pos += 4; /* system_header_start_code */
+ header_length = ( psData[pos] << 8 ) + psData[pos+1];
+ pos += 2 + header_length;
+ }
+
+ /* PES */
+ while( pos + 2 < psBuffer->fSize &&
+ psData[pos] == 0 && psData[pos+1] == 0 && psData[pos+2] == 0x1 )
+ {
+ uint32_t streamId;
+ uint32_t PES_packet_length;
+ uint32_t PES_packet_end;
+ uint32_t PES_header_data_length;
+ uint32_t PES_header_end;
+ bool hasPTS;
+ uint64_t PTS = 0;
+
+ pos += 3; /* packet_start_code_prefix */
+ streamId = psData[pos++];
+
+ PES_packet_length = ( psData[pos] << 8 ) + psData[pos+1];
+ pos += 2; /* PES_packet_length */
+ PES_packet_end = pos + PES_packet_length;
+
+ hasPTS = ( ( psData[pos+1] >> 6 ) & 0x2 );
+ pos += 2; /* Required headers */
+
+ PES_header_data_length = psData[pos];
+ pos += 1;
+ PES_header_end = pos + PES_header_data_length;
+
+ if( hasPTS )
+ {
+ PTS = ( ( ( psData[pos] >> 1 ) & 0x7 ) << 30 ) +
+ ( psData[pos+1] << 22 ) +
+ ( ( psData[pos+2] >> 1 ) << 15 ) +
+ ( psData[pos+3] << 7 ) +
+ ( psData[pos+4] >> 1 );
+ }
+
+ pos = PES_header_end;
+
+ if( streamId != 0xE0 && streamId != 0xBD )
+ {
+ /* Not interesting */
+ continue;
+ }
+
+ if( streamId == 0xBD )
+ {
+ /* A52 : don't ask */
+ streamId |= ( psData[pos] << 8 );
+ pos += 4;
+ }
+
+ /* Here we hit we ES payload */
+ esBuffer = new HBBuffer( PES_packet_end - pos );
+
+ esBuffer->fPosition = psBuffer->fPosition;
+ esBuffer->fStreamId = streamId;
+ esBuffer->fPTS = PTS;
+ memcpy( esBuffer->fData, psBuffer->fData + pos,
+ PES_packet_end - pos );
+
+ esBufferList->AddItem( esBuffer );
+
+ pos = PES_packet_end;
+ }
+
+ delete psBuffer;
+
+ if( esBufferList && !esBufferList->CountItems() )
+ {
+ delete esBufferList;
+ return NULL;
+ }
+
+ return esBufferList;
+
+#undef psData
+}