xref: /haiku/src/add-ons/media/media-add-ons/dvb/TransportStreamDemux.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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 
46 TransportStreamDemux::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 
70 TransportStreamDemux::~TransportStreamDemux()
71 {
72 	delete fVidPacket;
73 	delete fAudPacket;
74 }
75 
76 
77 void
78 TransportStreamDemux::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 
90 void
91 TransportStreamDemux::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 
136 void
137 TransportStreamDemux::ProcessPAT(const mpeg_ts_packet *pkt)
138 {
139 }
140 
141 
142 void
143 TransportStreamDemux::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 
173 void
174 TransportStreamDemux::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 
277 void
278 TransportStreamDemux::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 
392 inline void
393 TransportStreamDemux::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 
413 void
414 TransportStreamDemux::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