OSDN Git Service

HandBrake 0.2
[handbrake-jp/handbrake-jp-git.git] / HBMpegDemux.cpp
1 /* $Id: HBMpegDemux.cpp,v 1.13 2003/08/24 19:28:18 titer Exp $ */
2
3 #include "HBCommon.h"
4 #include "HBManager.h"
5 #include "HBMpegDemux.h"
6 #include "HBFifo.h"
7
8 extern "C" {
9 #include <a52dec/a52.h>
10 }
11
12 HBMpegDemux::HBMpegDemux( HBManager * manager, HBTitleInfo * titleInfo,
13                           HBAudioInfo * audio1Info, HBAudioInfo * audio2Info )
14     : HBThread( "mpegdemux" )
15 {
16     fManager        = manager;
17     fTitleInfo      = titleInfo;
18     fAudio1Info     = audio1Info;
19     fAudio2Info     = audio2Info;
20     
21     fPSBuffer       = NULL;
22     fESBuffer       = NULL;
23     fESBufferList   = NULL;
24     
25     fFirstVideoPTS  = -1;
26     fFirstAudio1PTS = -1;
27     fFirstAudio2PTS = -1;
28 }
29
30 void HBMpegDemux::DoWork()
31 {
32     while( !fDie )
33     {
34         /* Get a PS packet */
35         fPSBuffer = fTitleInfo->fPSFifo->Pop();
36         
37         if( !fPSBuffer )
38         {
39             continue;
40         }
41         
42         /* Get the ES data in it */
43         fESBufferList = PStoES( fPSBuffer );
44         
45         if( !fESBufferList )
46         {
47             continue;
48         }
49         
50         while( ( fESBuffer = (HBBuffer*) fESBufferList->ItemAt( 0 ) ) )
51         {
52             fESBufferList->RemoveItem( fESBuffer );
53         
54             /* Look for a decoder for this ES */
55             if( fESBuffer->fStreamId == 0xE0 )
56             {
57                 if( fFirstVideoPTS < 0 )
58                 {
59                     fFirstVideoPTS = fESBuffer->fPTS;
60                 }
61                 fTitleInfo->fMpeg2Fifo->Push( fESBuffer );
62             }
63             else if( fESBuffer->fStreamId == fAudio1Info->fId )
64             {
65                 /* If the audio track starts later than the video,
66                    repeat the first frame as long as needed  */
67                 if( fFirstAudio1PTS < 0 )
68                 {
69                     fFirstAudio1PTS = fESBuffer->fPTS;
70                     
71                     if( fFirstAudio1PTS > fFirstVideoPTS )
72                     {
73                         Log( "HBMpegDemux::DoWork() : audio track %x is late",
74                              fAudio1Info->fId );
75                         InsertSilence( fFirstAudio1PTS - fFirstVideoPTS,
76                                        fAudio1Info->fAc3Fifo,
77                                        fESBuffer );
78                     }
79                 }
80                 fAudio1Info->fAc3Fifo->Push( fESBuffer );
81             }
82             else if( fESBuffer->fStreamId == fAudio2Info->fId )
83             {
84                 if( fFirstAudio2PTS < 0 )
85                 {
86                     fFirstAudio2PTS = fESBuffer->fPTS;
87                     
88                     if( fFirstAudio2PTS > fFirstVideoPTS )
89                     {
90                         Log( "HBMpegDemux::DoWork() : audio track %x is late",
91                              fAudio2Info->fId );
92                         InsertSilence( fFirstAudio2PTS - fFirstVideoPTS,
93                                        fAudio2Info->fAc3Fifo,
94                                        fESBuffer );
95                     }
96                 }
97                 fAudio2Info->fAc3Fifo->Push( fESBuffer );
98             }
99             else
100             {
101                 delete fESBuffer;
102             }
103         }
104         delete fESBufferList;
105     }
106 }
107
108 void HBMpegDemux::InsertSilence( int64_t time, HBFifo * fifo,
109                                  HBBuffer * buffer )
110 {
111     int        flags      = 0;
112     int        sampleRate = 0;
113     int        bitrate    = 0;
114     int        frameSize  = a52_syncinfo( buffer->fData, &flags,
115                                           &sampleRate, &bitrate );
116     
117     if( !frameSize )
118     {
119         Log( "HBMpegDemux::InsertSilence() : a52_syncinfo() failed" );
120         return;
121     }
122      
123     uint32_t   samples      = sampleRate * time / 90000;
124     HBBuffer * buffer2;
125     
126     Log( "HBMpegDemux::InsertSilence() : adding %d samples", samples );
127     
128     for( uint32_t i = 0; i < samples / ( 6 * 256 ); i++ )
129     {
130         buffer2 = new HBBuffer( frameSize );
131         memcpy( buffer2->fData, buffer->fData, frameSize );
132         fifo->Push( buffer2 );
133     }
134 }
135
136 BList * PStoES( HBBuffer * psBuffer )
137 {
138 #define psData (psBuffer->fData)
139
140     BList    * esBufferList = new BList();
141     HBBuffer * esBuffer;
142     uint32_t   pos = 0;
143
144     /* pack_header */
145     if( psData[pos] != 0 || psData[pos+1] != 0 ||
146         psData[pos+2] != 0x1 || psData[pos+3] != 0xBA )
147     {
148         Log( "PStoES : not a PS packet (%02x%02x%02x%02x)",
149              psData[pos] << 24, psData[pos+1] << 16,
150              psData[pos+2] << 8, psData[pos+3] );
151         delete psBuffer;
152         return NULL;
153     }
154     pos += 4;                         /* pack_start_code */
155     pos += 9;                         /* pack_header */
156     pos += 1 + ( psData[pos] & 0x7 ); /* stuffing bytes */
157         
158     /* system_header */
159     if( psData[pos] == 0 && psData[pos+1] == 0 &&
160         psData[pos+2] == 0x1 && psData[pos+3] == 0xBB )
161     {
162         uint32_t header_length;
163     
164         pos           += 4; /* system_header_start_code */
165         header_length  = ( psData[pos] << 8 ) + psData[pos+1];
166         pos           += 2 + header_length;
167     }
168     
169     /* PES */
170     while( pos + 2 < psBuffer->fSize &&
171            psData[pos] == 0 && psData[pos+1] == 0 && psData[pos+2] == 0x1 )
172     {
173         uint32_t streamId;
174         uint32_t PES_packet_length;
175         uint32_t PES_packet_end;
176         uint32_t PES_header_data_length;
177         uint32_t PES_header_end;
178         bool     hasPTS;
179         uint64_t PTS = 0;
180     
181         pos               += 3;               /* packet_start_code_prefix */
182         streamId           = psData[pos++];
183
184         PES_packet_length  = ( psData[pos] << 8 ) + psData[pos+1];
185         pos               += 2;               /* PES_packet_length */
186         PES_packet_end     = pos + PES_packet_length;
187
188         hasPTS             = ( ( psData[pos+1] >> 6 ) & 0x2 );
189         pos               += 2;               /* Required headers */
190         
191         PES_header_data_length  = psData[pos];
192         pos                    += 1;
193         PES_header_end          = pos + PES_header_data_length;
194         
195         if( hasPTS )
196         {
197             PTS = ( ( ( psData[pos] >> 1 ) & 0x7 ) << 30 ) +
198                   ( psData[pos+1] << 22 ) +
199                   ( ( psData[pos+2] >> 1 ) << 15 ) +
200                   ( psData[pos+3] << 7 ) +
201                   ( psData[pos+4] >> 1 );
202         }
203         
204         pos = PES_header_end;
205     
206         if( streamId != 0xE0 && streamId != 0xBD )
207         {
208             /* Not interesting */
209             continue;
210         }
211     
212         if( streamId == 0xBD )
213         {
214             /* A52 : don't ask */
215             streamId |= ( psData[pos] << 8 );
216             pos += 4;
217         }
218         
219         /* Here we hit we ES payload */
220         esBuffer = new HBBuffer( PES_packet_end - pos );
221         
222         esBuffer->fPosition = psBuffer->fPosition;
223         esBuffer->fStreamId = streamId;
224         esBuffer->fPTS      = PTS;
225         memcpy( esBuffer->fData, psBuffer->fData + pos,
226                 PES_packet_end - pos );
227         
228         esBufferList->AddItem( esBuffer );
229     
230         pos = PES_packet_end;
231     }
232     
233     delete psBuffer;
234     
235     if( esBufferList && !esBufferList->CountItems() )
236     {
237         delete esBufferList;
238         return NULL;
239     }
240
241     return esBufferList;
242
243 #undef psData
244 }