2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify,
8 * merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
31 #include "TransportStreamDemux.h"
33 #include "PacketQueue.h"
35 #define TRACE_TS_DEMUX
42 #define CLOCK_TO_USEC(clck) (bigtime_t((clck) + 13) / 27)
43 #define USEC_TO_CLOCK(usec) (bigtime_t((usec) * 27))
46 TransportStreamDemux::TransportStreamDemux(
47 PacketQueue
*vid_queue
, PacketQueue
*aud_queue
,
48 PacketQueue
*vid_queue2
, PacketQueue
*aud_queue2
,
49 PacketQueue
*mpeg_ts_queue
)
57 , fVidQueue(vid_queue
)
58 , fVidQueue2(vid_queue2
)
59 , fAudQueue(aud_queue
)
60 , fAudQueue2(aud_queue2
)
61 , fMpegTsQueue(mpeg_ts_queue
)
62 , fVidPacket(new Packet
)
63 , fAudPacket(new Packet
)
64 , fVidPacketValid(false)
65 , fAudPacketValid(false)
70 TransportStreamDemux::~TransportStreamDemux()
78 TransportStreamDemux::SetPIDs(int vid_pid
, int aud_pid
, int pcr_pid
)
80 fVidPacket
->MakeEmpty();
81 fAudPacket
->MakeEmpty();
82 fVidPacketValid
= false;
83 fAudPacketValid
= false;
91 TransportStreamDemux::ProcessPacket(const mpeg_ts_packet
*pkt
, bigtime_t start_time
)
95 // printf("ProcessPacket %Ld\n", fCount);
97 if (pkt
->SyncByte() != 0x47) {
99 printf("packet %Ld sync byte error "
100 "%02x %02x %02x %02x %02x %02x %02x %02x "
101 "%02x %02x %02x %02x %02x %02x %02x %02x\n", fCount
,
102 pkt
->header
[0], pkt
->header
[1], pkt
->header
[2], pkt
->header
[3],
103 pkt
->data
[0], pkt
->data
[1], pkt
->data
[2], pkt
->data
[3],
104 pkt
->data
[4], pkt
->data
[5], pkt
->data
[6], pkt
->data
[7],
105 pkt
->data
[8], pkt
->data
[9], pkt
->data
[10], pkt
->data
[11]);
109 // if (pkt->TransportError()) {
111 // printf("invalid packet %Ld (transport_error_indicator)\n", fCount);
115 int pid
= pkt
->PID();
122 if (pid
== fPcrPid
) {
123 ProcessPCR(pkt
, start_time
);
126 if (pid
== fAudPid
) {
130 if (pid
== fVidPid
) {
137 TransportStreamDemux::ProcessPAT(const mpeg_ts_packet
*pkt
)
143 TransportStreamDemux::ProcessPCR(const mpeg_ts_packet
*pkt
, bigtime_t start_time
)
145 if (!(pkt
->AdaptationFieldControl() & 0x2)) // adaptation field present?
147 if (pkt
->data
[0] < 7) // long enough?
149 if (!(pkt
->data
[1] & 0x10)) // PCR present?
152 pcr
= (uint64(pkt
->data
[2]) << 25)
153 | (uint32(pkt
->data
[3]) << 17)
154 | (uint32(pkt
->data
[4]) << 9)
155 | (uint32(pkt
->data
[5]) << 1)
156 | (pkt
->data
[6] >> 7);
158 pcr
+= (pkt
->data
[6] & 1) | pkt
->data
[7];
159 // printf(" pcr = %Ld\n", pcr);
161 // bigtime_t now = system_time();
162 // printf("system_time %.3f, PCR-time %.3f, delta %.06f, PCR %Ld\n", now / 1e6, CLOCK_TO_USEC(pcr) / 1e6, (CLOCK_TO_USEC(pcr) - now) / 1e6, pcr);
164 // atomic_set64(&fCurrentTime, CLOCK_TO_USEC(pcr));
166 fTimeSourceLocker
.Lock();
167 fSystemTime
= start_time
;
168 fPerformanceTime
= CLOCK_TO_USEC(pcr
);
169 fTimeSourceLocker
.Unlock();
174 TransportStreamDemux::ProcessAUD(const mpeg_ts_packet
*pkt
)
177 if (pkt
->PayloadUnitStart()) {
178 if (fAudPacketValid
) {
179 Packet
*clone
= new Packet(*fAudPacket
);
180 status_t err
= fAudQueue
->Insert(fAudPacket
);
183 if (err
== B_WOULD_BLOCK
) {
184 printf("fAudQueue->Insert failed (would block)\n");
187 err
= fAudQueue2
->Insert(clone
);
190 if (err
== B_WOULD_BLOCK
) {
191 printf("fAudQueue2->Insert failed (would block)\n");
194 fAudPacket
= new Packet
;
196 fAudPacket
->MakeEmpty();
197 fAudPacketValid
= true;
202 switch (pkt
->AdaptationFieldControl()) {
206 case 1: // payload only
209 case 2: // adaptation field only
212 case 3: // adaptation field followed by payload
213 skip
= pkt
->data
[0] + 1;
218 skip
= 0; // stupid compiler, impossible case
221 const uint8
*data
= pkt
->data
+ skip
;
222 int size
= 184 - skip
;
225 // printf("aud skip %d\n", skip);
227 if (pkt
->PayloadUnitStart()) {
229 if (pkt
->TransportError()) {
230 printf("error in audio packet %02x %02x %02x %02x\n", data
[0], data
[1], data
[2], data
[3]);
231 fAudPacketValid
= false;
235 if (data
[0] || data
[1] || data
[2] != 0x01 || data
[3] <= 0xbf || data
[3] >= 0xf0) {
236 printf("invalid audio packet %02x %02x %02x %02x\n", data
[0], data
[1], data
[2], data
[3]);
237 fAudPacketValid
= false;
241 if (data
[7] & 0x80) { // PTS
245 pts
= (uint64((data
[9] >> 1) & 0x7) << 30)
246 | (data
[10] << 22) | ((data
[11] >> 1) << 15)
247 | (data
[12] << 7) | (data
[13] >> 1);
250 // printf("vid pts = %Ld\n", pts);
252 if (data
[7] & 0x40) { // DTS
254 dts
= (uint64((data
[14] >> 1) & 0x7) << 30)
255 | (data
[15] << 22) | ((data
[16] >> 1) << 15)
256 | (data
[17] << 7) | (data
[18] >> 1);
259 // printf("aud dts = %Ld\n", dts);
264 fAudPacket
->SetTimeStamp(CLOCK_TO_USEC(dts
));
268 // printf("aud %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
269 // data[0], data[1], data[2], data[3], data[4],
270 // data[5], data[6], data[7], data[8], data[9]);
273 fAudPacket
->AddData(data
, size
);
278 TransportStreamDemux::ProcessVID(const mpeg_ts_packet
*pkt
)
281 // if (pkt->PayloadUnitStart() || pkt->TransportError()) {
282 if (pkt
->PayloadUnitStart()) {
283 if (fVidPacketValid
) {
284 Packet
*clone
= new Packet(*fVidPacket
);
285 status_t err
= fVidQueue
->Insert(fVidPacket
);
288 if (err
== B_WOULD_BLOCK
) {
289 printf("fVidQueue->Insert failed (would block)\n");
292 err
= fVidQueue2
->Insert(clone
);
295 if (err
== B_WOULD_BLOCK
) {
296 printf("fVidQueue2->Insert failed (would block)\n");
299 fVidPacket
= new Packet
;
301 fVidPacket
->MakeEmpty();
302 fVidPacketValid
= true;
306 // if (pkt->TransportError()) {
307 // printf("transport error\n");
308 // fVidPacketValid = false;
313 switch (pkt
->AdaptationFieldControl()) {
317 case 1: // payload only
320 case 2: // adaptation field only
323 case 3: // adaptation field followed by payload
324 skip
= pkt
->data
[0] + 1;
329 skip
= 0; // stupid compiler, impossible case
332 const uint8
*data
= pkt
->data
+ skip
;
333 int size
= 184 - skip
;
336 // printf("vid skip %d\n", skip);
338 if (pkt
->PayloadUnitStart()) {
340 if (pkt
->TransportError()) {
341 printf("error in video packet %02x %02x %02x %02x\n", data
[0], data
[1], data
[2], data
[3]);
342 fVidPacketValid
= false;
346 if (data
[0] || data
[1] || data
[2] != 0x01 || data
[3] <= 0xbf || data
[3] >= 0xf0) {
347 printf("invalid video packet %02x %02x %02x %02x\n", data
[0], data
[1], data
[2], data
[3]);
348 fVidPacketValid
= false;
352 if (data
[7] & 0x80) { // PTS
356 pts
= (uint64((data
[9] >> 1) & 0x7) << 30)
357 | (data
[10] << 22) | ((data
[11] >> 1) << 15)
358 | (data
[12] << 7) | (data
[13] >> 1);
361 // printf("vid pts = %Ld\n", pts);
363 if (data
[7] & 0x40) { // DTS
365 dts
= (uint64((data
[14] >> 1) & 0x7) << 30)
366 | (data
[15] << 22) | ((data
[16] >> 1) << 15)
367 | (data
[17] << 7) | (data
[18] >> 1);
370 // printf("vid dts = %Ld\n", dts);
371 // printf("dts = %Ld, pts = %Ld, delta %Ld ### dts = %Ld, pts = %Ld, delta %Ld\n",
372 // dts, pts, pts - dts, CLOCK_TO_USEC(dts), CLOCK_TO_USEC(pts), CLOCK_TO_USEC(pts - dts));
377 // printf("clocks: dts = %14Ld, pts = %14Ld, delta %8Ld ### usec: dts = %14Ld, pts = %14Ld, delta %8Ld\n",
378 // dts, pts, pts - dts, CLOCK_TO_USEC(dts), CLOCK_TO_USEC(pts), CLOCK_TO_USEC(pts - dts));
380 fVidPacket
->SetTimeStamp(CLOCK_TO_USEC(dts
));
383 // printf("vid %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
384 // data[0], data[1], data[2], data[3], data[4],
385 // data[5], data[6], data[7], data[8], data[9]);
388 fVidPacket
->AddData(data
, size
);
393 TransportStreamDemux::ProcessData(const void *data
, int size
, bigtime_t start_time
, bigtime_t delta
)
395 const uint8
*d
= (const uint8
*)data
;
396 if (d
[0] != 0x47 && size
> 376 && d
[188] != 0x47 && d
[376] != 0x47) {
397 printf("TransportStreamDemux::ProcessData: input sync error: "
398 "%02x %02x %02x %02x %02x %02x %02x %02x "
399 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
400 d
[0], d
[1], d
[2], d
[3], d
[4], d
[5], d
[6], d
[7],
401 d
[8], d
[9], d
[10], d
[11], d
[12], d
[13], d
[14], d
[15]);
405 const mpeg_ts_packet
*pkt
= (const mpeg_ts_packet
*)data
;
406 int count
= size
/ 188;
407 for (int i
= 0; i
< count
; i
++) {
408 ProcessPacket(pkt
++, start_time
+ (i
* delta
) / count
);
414 TransportStreamDemux::AddData(Packet
*packet
)
416 bigtime_t end_time
= packet
->TimeStamp();
418 if (fLastEndTime
== 0) {
419 #define DEFAULT_DELTA 36270
420 // need something at the start, 36270 usec is the packet length
421 // in Germany, and should be ok for other countries, too
422 fLastEndTime
= end_time
- DEFAULT_DELTA
;
425 bigtime_t delta
= end_time
- fLastEndTime
;
428 if (delta
> (3 * DEFAULT_DELTA
)) {
429 printf("TransportStreamDemux::ProcessData: delta %.6f is too large\n", delta
/ 1E6
);
430 fLastEndTime
= end_time
- DEFAULT_DELTA
;
431 delta
= DEFAULT_DELTA
;
434 ProcessData(packet
->Data(), packet
->Size(), fLastEndTime
, delta
);
436 packet
->SetTimeStamp(fLastEndTime
);
438 fLastEndTime
= end_time
;
440 status_t err
= fMpegTsQueue
->Insert(packet
);
443 if (err
== B_WOULD_BLOCK
) {
444 printf("fMpegTsQueue->Insert failed (would block)\n");