1/*
2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
3 *
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:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
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.
23 */
24
25#include <stdio.h>
26#include <fcntl.h>
27#include <unistd.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "TransportStreamDemux.h"
32#include "Packet.h"
33#include "PacketQueue.h"
34
35#define TRACE_TS_DEMUX
36#ifdef TRACE_TS_DEMUX
37  #define TRACE printf
38#else
39  #define TRACE(a...)
40#endif
41
42#define CLOCK_TO_USEC(clck)		(bigtime_t((clck) + 13) / 27)
43#define USEC_TO_CLOCK(usec)		(bigtime_t((usec) * 27))
44
45
46TransportStreamDemux::TransportStreamDemux(
47	PacketQueue *vid_queue, PacketQueue *aud_queue,
48	PacketQueue *vid_queue2, PacketQueue *aud_queue2,
49	PacketQueue *mpeg_ts_queue)
50 :	fCount(0)
51 ,	fSystemTime(0)
52 ,	fPerformanceTime(0)
53 ,	fLastEndTime(0)
54 ,	fVidPid(-1)
55 ,	fAudPid(-1)
56 ,	fPcrPid(-1)
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)
66{
67}
68
69
70TransportStreamDemux::~TransportStreamDemux()
71{
72	delete fVidPacket;
73	delete fAudPacket;
74}
75
76
77void
78TransportStreamDemux::SetPIDs(int vid_pid, int aud_pid, int pcr_pid)
79{
80	fVidPacket->MakeEmpty();
81	fAudPacket->MakeEmpty();
82	fVidPacketValid = false;
83	fAudPacketValid = false;
84	fVidPid = vid_pid;
85	fAudPid = aud_pid;
86	fPcrPid = pcr_pid;
87}
88
89
90void
91TransportStreamDemux::ProcessPacket(const mpeg_ts_packet *pkt, bigtime_t start_time)
92{
93	fCount++;
94
95//	printf("ProcessPacket %lld\n", fCount);
96
97	if (pkt->SyncByte() != 0x47) {
98//		fCountInvalid++;
99		printf("packet %lld 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]);
106		return;
107	}
108
109//	if (pkt->TransportError()) {
110//		fCountInvalid++;
111//		printf("invalid packet %lld (transport_error_indicator)\n", fCount);
112//		return;
113//	}
114
115    int pid = pkt->PID();
116
117    if (pid == 0) {
118    	ProcessPAT(pkt);
119    	return;
120    }
121
122    if (pid == fPcrPid) {
123    	ProcessPCR(pkt, start_time);
124    }
125
126    if (pid == fAudPid) {
127    	ProcessAUD(pkt);
128    }
129
130    if (pid == fVidPid) {
131    	ProcessVID(pkt);
132    }
133}
134
135
136void
137TransportStreamDemux::ProcessPAT(const mpeg_ts_packet *pkt)
138{
139}
140
141
142void
143TransportStreamDemux::ProcessPCR(const mpeg_ts_packet *pkt, bigtime_t start_time)
144{
145	if (!(pkt->AdaptationFieldControl() & 0x2)) // adaptation field present?
146		return;
147	if (pkt->data[0] < 7) // long enough?
148		return;
149	if (!(pkt->data[1] & 0x10)) // PCR present?
150		return;
151	int64 pcr;
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);
157	pcr *= 300;
158	pcr += (pkt->data[6] & 1) | pkt->data[7];
159//	printf("    pcr = %lld\n", pcr);
160
161//	bigtime_t now = system_time();
162//	printf("system_time %.3f, PCR-time %.3f, delta %.06f, PCR %lld\n", now / 1e6, CLOCK_TO_USEC(pcr) / 1e6, (CLOCK_TO_USEC(pcr) - now) / 1e6, pcr);
163
164//	atomic_set64(&fCurrentTime, CLOCK_TO_USEC(pcr));
165
166	fTimeSourceLocker.Lock();
167	fSystemTime = start_time;
168 	fPerformanceTime = CLOCK_TO_USEC(pcr);
169	fTimeSourceLocker.Unlock();
170}
171
172
173void
174TransportStreamDemux::ProcessAUD(const mpeg_ts_packet *pkt)
175{
176	// flush old packet
177	if (pkt->PayloadUnitStart()) {
178		if (fAudPacketValid) {
179			Packet *clone = new Packet(*fAudPacket);
180			status_t err = fAudQueue->Insert(fAudPacket);
181			if (err != B_OK) {
182				delete fAudPacket;
183				if (err == B_WOULD_BLOCK) {
184					printf("fAudQueue->Insert failed (would block)\n");
185				}
186			}
187			err = fAudQueue2->Insert(clone);
188			if (err != B_OK) {
189				delete clone;
190				if (err == B_WOULD_BLOCK) {
191					printf("fAudQueue2->Insert failed (would block)\n");
192				}
193			}
194			fAudPacket = new Packet;
195		} else {
196			fAudPacket->MakeEmpty();
197			fAudPacketValid = true;
198		}
199	}
200
201	int skip;
202	switch (pkt->AdaptationFieldControl()) {
203		case 0:	// illegal
204			skip = 184;
205			break;
206		case 1: // payload only
207			skip = 0;
208			break;
209		case 2:	// adaptation field only
210			skip = 184;
211			break;
212		case 3: // adaptation field followed by payload
213			skip = pkt->data[0] + 1;
214			if (skip > 184)
215				skip = 184;
216			break;
217		default:
218			skip = 0; // stupid compiler, impossible case
219	}
220
221	const uint8 *data = pkt->data + skip;
222	int size = 184 - skip;
223
224//	if (skip != 0)
225//		printf("aud skip %d\n", skip);
226
227	if (pkt->PayloadUnitStart()) {
228
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;
232			return;
233		}
234
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;
238			return;
239		}
240
241		if (data[7] & 0x80) { // PTS
242			int64 pts;
243			int64 dts;
244
245			pts = (uint64((data[9] >> 1) & 0x7) << 30)
246				| (data[10] << 22) | ((data[11] >> 1) << 15)
247				| (data[12] << 7) | (data[13] >> 1);
248			pts *= 300;
249
250//		    printf("vid pts = %lld\n", pts);
251
252			if (data[7] & 0x40) { // DTS
253
254				dts = (uint64((data[14] >> 1) & 0x7) << 30)
255					| (data[15] << 22) | ((data[16] >> 1) << 15)
256					| (data[17] << 7) | (data[18] >> 1);
257				dts *= 300;
258
259//				printf("aud dts = %lld\n", dts);
260			} else {
261				dts = pts;
262			}
263
264			fAudPacket->SetTimeStamp(CLOCK_TO_USEC(dts));
265		}
266
267
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]);
271	}
272
273	fAudPacket->AddData(data, size);
274}
275
276
277void
278TransportStreamDemux::ProcessVID(const mpeg_ts_packet *pkt)
279{
280	// flush old packet
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);
286			if (err != B_OK) {
287				delete fVidPacket;
288				if (err == B_WOULD_BLOCK) {
289					printf("fVidQueue->Insert failed (would block)\n");
290				}
291			}
292			err = fVidQueue2->Insert(clone);
293			if (err != B_OK) {
294				delete clone;
295				if (err == B_WOULD_BLOCK) {
296					printf("fVidQueue2->Insert failed (would block)\n");
297				}
298			}
299			fVidPacket = new Packet;
300		} else {
301			fVidPacket->MakeEmpty();
302			fVidPacketValid = true;
303		}
304	}
305
306//	if (pkt->TransportError()) {
307//		printf("transport error\n");
308//		fVidPacketValid = false;
309//		return;
310//	}
311
312	int skip;
313	switch (pkt->AdaptationFieldControl()) {
314		case 0:	// illegal
315			skip = 184;
316			break;
317		case 1: // payload only
318			skip = 0;
319			break;
320		case 2:	// adaptation field only
321			skip = 184;
322			break;
323		case 3: // adaptation field followed by payload
324			skip = pkt->data[0] + 1;
325			if (skip > 184)
326				skip = 184;
327			break;
328		default:
329			skip = 0; // stupid compiler, impossible case
330	}
331
332	const uint8 *data = pkt->data + skip;
333	int size = 184 - skip;
334
335//	if (skip != 0)
336//		printf("vid skip %d\n", skip);
337
338	if (pkt->PayloadUnitStart()) {
339
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;
343			return;
344		}
345
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;
349			return;
350		}
351
352		if (data[7] & 0x80) { // PTS
353			int64 pts;
354			int64 dts;
355
356			pts = (uint64((data[9] >> 1) & 0x7) << 30)
357				| (data[10] << 22) | ((data[11] >> 1) << 15)
358				| (data[12] << 7) | (data[13] >> 1);
359			pts *= 300;
360
361//		    printf("vid pts = %lld\n", pts);
362
363			if (data[7] & 0x40) { // DTS
364
365				dts = (uint64((data[14] >> 1) & 0x7) << 30)
366					| (data[15] << 22) | ((data[16] >> 1) << 15)
367					| (data[17] << 7) | (data[18] >> 1);
368				dts *= 300;
369
370//				printf("vid dts = %lld\n", dts);
371//				printf("dts = %lld, pts = %lld, delta %lld ### dts = %lld, pts = %lld, delta %lld\n",
372//						dts, pts, pts - dts, CLOCK_TO_USEC(dts), CLOCK_TO_USEC(pts), CLOCK_TO_USEC(pts - dts));
373			} else {
374				dts = pts;
375			}
376
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));
379
380			fVidPacket->SetTimeStamp(CLOCK_TO_USEC(dts));
381		}
382
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]);
386	}
387
388	fVidPacket->AddData(data, size);
389}
390
391
392inline void
393TransportStreamDemux::ProcessData(const void *data, int size, bigtime_t start_time, bigtime_t delta)
394{
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]);
402		return;
403	}
404
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);
409	}
410}
411
412
413void
414TransportStreamDemux::AddData(Packet *packet)
415{
416	bigtime_t end_time = packet->TimeStamp();
417
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;
423	}
424
425	bigtime_t delta = end_time - fLastEndTime;
426
427	// sanity check
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;
432	}
433
434	ProcessData(packet->Data(), packet->Size(), fLastEndTime, delta);
435
436	packet->SetTimeStamp(fLastEndTime);
437
438	fLastEndTime = end_time;
439
440	status_t err = fMpegTsQueue->Insert(packet);
441	if (err != B_OK) {
442		delete packet;
443		if (err == B_WOULD_BLOCK) {
444			printf("fMpegTsQueue->Insert failed (would block)\n");
445		}
446	}
447}
448
449