vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / media-add-ons / dvb / TransportStreamDemux.cpp
blobd2c99a90d0ed2f4e01254f5a9e52b0e6d00e8ad8
1 /*
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.
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <string.h>
31 #include "TransportStreamDemux.h"
32 #include "Packet.h"
33 #include "PacketQueue.h"
35 #define TRACE_TS_DEMUX
36 #ifdef TRACE_TS_DEMUX
37 #define TRACE printf
38 #else
39 #define TRACE(a...)
40 #endif
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)
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)
70 TransportStreamDemux::~TransportStreamDemux()
72 delete fVidPacket;
73 delete fAudPacket;
77 void
78 TransportStreamDemux::SetPIDs(int vid_pid, int aud_pid, int pcr_pid)
80 fVidPacket->MakeEmpty();
81 fAudPacket->MakeEmpty();
82 fVidPacketValid = false;
83 fAudPacketValid = false;
84 fVidPid = vid_pid;
85 fAudPid = aud_pid;
86 fPcrPid = pcr_pid;
90 void
91 TransportStreamDemux::ProcessPacket(const mpeg_ts_packet *pkt, bigtime_t start_time)
93 fCount++;
95 // printf("ProcessPacket %Ld\n", fCount);
97 if (pkt->SyncByte() != 0x47) {
98 // fCountInvalid++;
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]);
106 return;
109 // if (pkt->TransportError()) {
110 // fCountInvalid++;
111 // printf("invalid packet %Ld (transport_error_indicator)\n", fCount);
112 // return;
113 // }
115 int pid = pkt->PID();
117 if (pid == 0) {
118 ProcessPAT(pkt);
119 return;
122 if (pid == fPcrPid) {
123 ProcessPCR(pkt, start_time);
126 if (pid == fAudPid) {
127 ProcessAUD(pkt);
130 if (pid == fVidPid) {
131 ProcessVID(pkt);
136 void
137 TransportStreamDemux::ProcessPAT(const mpeg_ts_packet *pkt)
142 void
143 TransportStreamDemux::ProcessPCR(const mpeg_ts_packet *pkt, bigtime_t start_time)
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 = %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();
173 void
174 TransportStreamDemux::ProcessAUD(const mpeg_ts_packet *pkt)
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");
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");
194 fAudPacket = new Packet;
195 } else {
196 fAudPacket->MakeEmpty();
197 fAudPacketValid = true;
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
221 const uint8 *data = pkt->data + skip;
222 int size = 184 - skip;
224 // if (skip != 0)
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;
232 return;
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;
241 if (data[7] & 0x80) { // PTS
242 int64 pts;
243 int64 dts;
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;
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);
257 dts *= 300;
259 // printf("aud dts = %Ld\n", dts);
260 } else {
261 dts = pts;
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);
277 void
278 TransportStreamDemux::ProcessVID(const mpeg_ts_packet *pkt)
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");
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");
299 fVidPacket = new Packet;
300 } else {
301 fVidPacket->MakeEmpty();
302 fVidPacketValid = true;
306 // if (pkt->TransportError()) {
307 // printf("transport error\n");
308 // fVidPacketValid = false;
309 // return;
310 // }
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
332 const uint8 *data = pkt->data + skip;
333 int size = 184 - skip;
335 // if (skip != 0)
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;
343 return;
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;
352 if (data[7] & 0x80) { // PTS
353 int64 pts;
354 int64 dts;
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;
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);
368 dts *= 300;
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));
373 } else {
374 dts = pts;
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);
392 inline void
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]);
402 return;
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);
413 void
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;
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;
434 ProcessData(packet->Data(), packet->Size(), fLastEndTime, delta);
436 packet->SetTimeStamp(fLastEndTime);
438 fLastEndTime = end_time;
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");