1 | #ifndef DVB_H |
---|
2 | #define DVB_H |
---|
3 | |
---|
4 | int dvbwrite(int fd, unsigned char* buf, int count, int tout) |
---|
5 | { |
---|
6 | struct timeval timeout; |
---|
7 | int ret = 0, usec = 0, sec = 0, tmpcount = count; |
---|
8 | unsigned char* buffer = NULL; |
---|
9 | |
---|
10 | if(fd < 0) return -1; |
---|
11 | |
---|
12 | if(tout == -1) tout = 5000 * 1000; |
---|
13 | usec = tout % 1000000; |
---|
14 | sec = (tout - usec) / 1000000; |
---|
15 | |
---|
16 | fd_set wfds; |
---|
17 | |
---|
18 | while (tmpcount > 0) |
---|
19 | { |
---|
20 | buffer = buf + (count - tmpcount); |
---|
21 | ret = write(fd, buffer, tmpcount); |
---|
22 | if(ret < 0) |
---|
23 | { |
---|
24 | if(errno == EINTR || errno == EAGAIN) |
---|
25 | { |
---|
26 | FD_ZERO(&wfds); |
---|
27 | FD_SET(fd, &wfds); |
---|
28 | |
---|
29 | timeout.tv_sec = sec; |
---|
30 | timeout.tv_usec = usec; |
---|
31 | |
---|
32 | ret = TEMP_FAILURE_RETRY(select(fd + 1, NULL, &wfds, NULL, &timeout)); |
---|
33 | } |
---|
34 | |
---|
35 | if(ret == 0) |
---|
36 | { |
---|
37 | perr("dvbwrite timed out fd=%d", fd); |
---|
38 | return -1; |
---|
39 | } |
---|
40 | if(ret < 0) |
---|
41 | { |
---|
42 | perr("can't write fd=%d", fd); |
---|
43 | return errno * -1; |
---|
44 | } |
---|
45 | } |
---|
46 | else |
---|
47 | tmpcount -= ret; |
---|
48 | } |
---|
49 | |
---|
50 | return count; |
---|
51 | } |
---|
52 | |
---|
53 | //flag 0: eof with timeout |
---|
54 | //flag 1: eof without timeout |
---|
55 | int dvbreadfd(int fd, unsigned char *buf, int pos, int count, int tout, int flag) |
---|
56 | { |
---|
57 | struct timeval timeout; |
---|
58 | int ret = 0, usec = 0, sec = 0; |
---|
59 | fd_set rfds; |
---|
60 | |
---|
61 | if(fd < 0) return -1; |
---|
62 | |
---|
63 | if(tout == -1) tout = 5000 * 1000; |
---|
64 | usec = tout % 1000000; |
---|
65 | sec = (tout - usec) / 1000000; |
---|
66 | |
---|
67 | timeout.tv_sec = sec; |
---|
68 | timeout.tv_usec = usec; |
---|
69 | FD_ZERO(&rfds); |
---|
70 | FD_SET(fd, &rfds); |
---|
71 | |
---|
72 | ret = TEMP_FAILURE_RETRY(select(fd + 1, &rfds , NULL, NULL, &timeout)); |
---|
73 | |
---|
74 | if(ret == 1) |
---|
75 | { |
---|
76 | retry: |
---|
77 | ret = TEMP_FAILURE_RETRY(read(fd, buf + pos, count)); |
---|
78 | if(ret > 0) |
---|
79 | return ret; |
---|
80 | else if(ret == 0) |
---|
81 | { |
---|
82 | #ifdef SIMULATE |
---|
83 | tout = tout - 100000; |
---|
84 | usleep(100000); |
---|
85 | #else |
---|
86 | tout = tout - 1000; |
---|
87 | usleep(1000); |
---|
88 | #endif |
---|
89 | if(flag == 0 && tout > 0) goto retry; |
---|
90 | debug(200, "dvb read timeout fd=%d", fd); |
---|
91 | } |
---|
92 | else if(ret < 0) |
---|
93 | { |
---|
94 | if((errno == EAGAIN || errno == EOVERFLOW) && tout > 0) |
---|
95 | { |
---|
96 | if(errno != EAGAIN) perr("dvb read data fd=%d -> retry", fd); |
---|
97 | #ifdef SIMULATE |
---|
98 | tout = tout - 100000; |
---|
99 | usleep(100000); |
---|
100 | #else |
---|
101 | tout = tout - 1000; |
---|
102 | usleep(1000); |
---|
103 | #endif |
---|
104 | goto retry; |
---|
105 | } |
---|
106 | perr("dvb read data fd=%d", fd); |
---|
107 | } |
---|
108 | } |
---|
109 | else if(ret == 0) |
---|
110 | { |
---|
111 | debug(200, "dvb select timeout fd=%d, tout=%d", fd, tout); |
---|
112 | } |
---|
113 | else |
---|
114 | { |
---|
115 | perr("dvb select fd=%d", fd); |
---|
116 | } |
---|
117 | |
---|
118 | return -1; |
---|
119 | } |
---|
120 | |
---|
121 | int dvbread(struct dvbdev* node, unsigned char *buf, int pos, int count, int tout) |
---|
122 | { |
---|
123 | if(node == NULL) return -2; |
---|
124 | return dvbreadfd(node->fd, buf, pos, count, tout, 0); |
---|
125 | } |
---|
126 | |
---|
127 | int dvbfindpmtpid(int fd, int16_t *pmtpid, int *serviceid, int tssize) |
---|
128 | { |
---|
129 | off_t pos = 0; |
---|
130 | int left = 5 * 1024 * 1024; |
---|
131 | |
---|
132 | if(fd < 0) return 1; |
---|
133 | |
---|
134 | while(left >= tssize) |
---|
135 | { |
---|
136 | unsigned char packet[tssize]; |
---|
137 | |
---|
138 | lseek64(fd, pos, SEEK_SET); |
---|
139 | int ret = dvbreadfd(fd, packet, 0, tssize, -1, 0); |
---|
140 | if(ret != tssize) |
---|
141 | { |
---|
142 | err("read error"); |
---|
143 | break; |
---|
144 | } |
---|
145 | left -= tssize; |
---|
146 | pos += tssize; |
---|
147 | |
---|
148 | if(packet[0] != 0x47) |
---|
149 | { |
---|
150 | int i = 0; |
---|
151 | while(i < tssize) |
---|
152 | { |
---|
153 | if(packet[i] == 0x47) break; |
---|
154 | --pos; |
---|
155 | ++i; |
---|
156 | } |
---|
157 | continue; |
---|
158 | } |
---|
159 | |
---|
160 | int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF; |
---|
161 | |
---|
162 | int pusi = !!(packet[1] & 0x40); |
---|
163 | if(!pusi) continue; |
---|
164 | |
---|
165 | // ok, now we have a PES header or section header |
---|
166 | unsigned char *sec; |
---|
167 | |
---|
168 | // check for adaption field |
---|
169 | if(packet[3] & 0x20) |
---|
170 | { |
---|
171 | if(packet[4] >= 183) continue; |
---|
172 | sec = packet + packet[4] + 4 + 1; |
---|
173 | } |
---|
174 | else |
---|
175 | sec = packet + 4; |
---|
176 | |
---|
177 | // table pointer, assumed to be 0 |
---|
178 | if(sec[0]) continue; |
---|
179 | |
---|
180 | // program map section |
---|
181 | if(sec[1] == 0x02) |
---|
182 | { |
---|
183 | *pmtpid = pid; |
---|
184 | *serviceid = (sec[4] << 8) | sec[5]; |
---|
185 | lseek64(fd, 0, SEEK_SET); |
---|
186 | return 0; |
---|
187 | } |
---|
188 | } |
---|
189 | |
---|
190 | lseek64(fd, 0, SEEK_SET); |
---|
191 | return 1; |
---|
192 | } |
---|
193 | |
---|
194 | int dvbgetpmtpid(unsigned char *buf, int serviceid) |
---|
195 | { |
---|
196 | if(buf == NULL) return 1; |
---|
197 | |
---|
198 | int i=0; |
---|
199 | int length = (buf[1] & 0x0F) << 8 | ((buf[2] + 3) & 0xff); |
---|
200 | if(length > MINMALLOC) length = MINMALLOC; |
---|
201 | |
---|
202 | debug(200, "PAT length: %d", length); |
---|
203 | for (i = 8; i < length; i += 4) |
---|
204 | { |
---|
205 | if((((buf[i] & 0xff) << 8) | (buf[i + 1] & 0xff)) > 0) |
---|
206 | { |
---|
207 | if (serviceid == (((buf[i] & 0xff) << 8) | (buf[i + 1] & 0xff))) |
---|
208 | { |
---|
209 | int pmtpid = (((buf[i + 2] & 0x1f) << 8) | (buf[i + 3] & 0xff)); |
---|
210 | debug(200, "PMT pid: 0x%X (%d)", pmtpid, pmtpid); |
---|
211 | return pmtpid; |
---|
212 | } |
---|
213 | } |
---|
214 | } |
---|
215 | return 0; |
---|
216 | } |
---|
217 | |
---|
218 | char* dvbgethbbtvurl(unsigned char* buf) |
---|
219 | { |
---|
220 | //int seclen = 0; |
---|
221 | int pos = 0; |
---|
222 | int pos2 = 0; |
---|
223 | int commondesclen = 0; |
---|
224 | int applooplen = 0; |
---|
225 | int appdesclen = 0; |
---|
226 | int desclen = 0; |
---|
227 | char* url = NULL; |
---|
228 | |
---|
229 | if(buf == NULL) return NULL; |
---|
230 | |
---|
231 | //seclen = ((buf[1] & 0x0F) << 8) + buf[2]; |
---|
232 | commondesclen = ((buf[8] & 0x0F) << 8) + buf[9]; |
---|
233 | pos = 10 + commondesclen; |
---|
234 | |
---|
235 | applooplen = ((buf[pos] & 0x0F) << 8) + buf[pos + 1]; |
---|
236 | pos += 2; |
---|
237 | |
---|
238 | for(; pos < applooplen; pos += appdesclen + 9) |
---|
239 | { |
---|
240 | //long orgid = (buf[pos] << 24) + (buf[pos + 1] << 16) + (buf[pos + 2] << 8) + buf[pos + 3]; |
---|
241 | //int appid = (buf[pos + 4] << 8) + buf[pos + 5]; |
---|
242 | int appcode = buf[pos + 6]; |
---|
243 | appdesclen = ((buf[pos + 7] & 0x0F) << 8) + buf[pos + 8]; |
---|
244 | |
---|
245 | if(appcode != 1) continue; |
---|
246 | |
---|
247 | desclen = 0; |
---|
248 | for(pos2 = pos + 9; pos2 < appdesclen + pos + 9; pos2 += desclen + 2) |
---|
249 | { |
---|
250 | int desctag = buf[pos2]; |
---|
251 | desclen = buf[pos2 + 1]; |
---|
252 | |
---|
253 | switch(desctag) |
---|
254 | { |
---|
255 | case 0x00: //application desc |
---|
256 | break; |
---|
257 | case 0x01: //application name desc |
---|
258 | break; |
---|
259 | case 0x02: //transport protocol desc |
---|
260 | { |
---|
261 | int protocolid = buf[pos2 + 2] + buf[pos2 + 3]; |
---|
262 | switch(protocolid) |
---|
263 | { |
---|
264 | case 1: //object carousel |
---|
265 | break; |
---|
266 | case 2: //ip |
---|
267 | break; |
---|
268 | case 3: //interaction |
---|
269 | { |
---|
270 | free(url); url = NULL; |
---|
271 | url = malloc(desclen - 4); |
---|
272 | if(url != NULL) |
---|
273 | { |
---|
274 | strncpy(url, (char*)&buf[pos2 + 6], desclen - 5); |
---|
275 | url[desclen - 5]='\0'; |
---|
276 | } |
---|
277 | break; |
---|
278 | } |
---|
279 | } |
---|
280 | break; |
---|
281 | } |
---|
282 | case 0x14: //graphics constraints desc |
---|
283 | break; |
---|
284 | case 0x15: //simple application location desc |
---|
285 | { |
---|
286 | if(url != NULL) |
---|
287 | { |
---|
288 | char* tmpurl = NULL; |
---|
289 | tmpurl = malloc(desclen + 1); |
---|
290 | strncpy(tmpurl, (char*)&buf[pos2 + 2], desclen); |
---|
291 | tmpurl[desclen]='\0'; |
---|
292 | url = ostrcat(url, tmpurl, 1, 1); |
---|
293 | } |
---|
294 | break; |
---|
295 | } |
---|
296 | case 0x16: //application usage desc |
---|
297 | break; |
---|
298 | case 0x17: //simple application boundary desc |
---|
299 | break; |
---|
300 | } |
---|
301 | } |
---|
302 | } |
---|
303 | |
---|
304 | return url; |
---|
305 | } |
---|
306 | |
---|
307 | unsigned char* dvbget(struct dvbdev* fenode, int pid, int type, int secnr, int timeout) |
---|
308 | { |
---|
309 | int length = -1; |
---|
310 | struct dvbdev* dmxnode = NULL; |
---|
311 | unsigned char* buf = NULL; |
---|
312 | |
---|
313 | buf = malloc(MINMALLOC); |
---|
314 | if(buf == NULL) |
---|
315 | { |
---|
316 | err("no memory"); |
---|
317 | return NULL; |
---|
318 | } |
---|
319 | |
---|
320 | if(fenode == NULL) |
---|
321 | { |
---|
322 | err("no frontend dev"); |
---|
323 | free(buf); |
---|
324 | return NULL; |
---|
325 | } |
---|
326 | |
---|
327 | dmxnode = dmxopen(fenode, 1); |
---|
328 | if(dmxnode == NULL) |
---|
329 | { |
---|
330 | err("open demux dev"); |
---|
331 | free(buf); |
---|
332 | return NULL; |
---|
333 | } |
---|
334 | |
---|
335 | dmxsetsource(dmxnode, fenode->fedmxsource); |
---|
336 | dmxsetfilter(dmxnode, pid, secnr, type); |
---|
337 | |
---|
338 | length = dvbread(dmxnode, buf, 0, MINMALLOC, timeout); |
---|
339 | if(length < 0) |
---|
340 | { |
---|
341 | dmxclose(dmxnode, -1); |
---|
342 | free(buf); |
---|
343 | err("read"); |
---|
344 | return NULL; |
---|
345 | } |
---|
346 | |
---|
347 | dmxclose(dmxnode, -1); |
---|
348 | return buf; |
---|
349 | } |
---|
350 | |
---|
351 | unsigned char* dvbgetait(struct dvbdev* fenode, int pid, int secnr, int timeout) |
---|
352 | { |
---|
353 | return dvbget(fenode, pid, 14, secnr, timeout); |
---|
354 | } |
---|
355 | |
---|
356 | unsigned char* dvbgetsdt(struct dvbdev* fenode, int secnr, int timeout) |
---|
357 | { |
---|
358 | return dvbget(fenode, 0x11, 11, secnr, timeout); |
---|
359 | } |
---|
360 | |
---|
361 | unsigned char* dvbgetpat(struct dvbdev* fenode, int timeout) |
---|
362 | { |
---|
363 | return dvbget(fenode, 0, 1, 0, timeout); |
---|
364 | } |
---|
365 | |
---|
366 | unsigned char* dvbgetnit(struct dvbdev* fenode, int secnr, int timeout) |
---|
367 | { |
---|
368 | return dvbget(fenode, 0x10, 4, secnr, timeout); |
---|
369 | } |
---|
370 | |
---|
371 | //flag 0: with pat |
---|
372 | //flag 1: don't use patbuf |
---|
373 | unsigned char* dvbgetpmt(struct dvbdev* fenode, unsigned char* patbuf, int serviceid, int16_t* pmtpid, int* pmtlen, int timeout, int flag) |
---|
374 | { |
---|
375 | int length = -1, i; |
---|
376 | struct dvbdev* dmxnode = NULL; |
---|
377 | unsigned char* buf = NULL; |
---|
378 | |
---|
379 | #ifdef SIMULATE |
---|
380 | FILE* fd = NULL; |
---|
381 | |
---|
382 | buf = malloc(MINMALLOC); |
---|
383 | |
---|
384 | fd = fopen("simulate/pmt.tmp", "rb"); |
---|
385 | if(fd == NULL) |
---|
386 | { |
---|
387 | err("open simulate/pmt.tmp"); |
---|
388 | } |
---|
389 | else |
---|
390 | fread(buf, sizeof(unsigned char), MINMALLOC, fd); |
---|
391 | |
---|
392 | if(fd != NULL) fclose(fd); |
---|
393 | if(buf != NULL) return buf; |
---|
394 | #endif |
---|
395 | |
---|
396 | if(flag == 0) |
---|
397 | { |
---|
398 | if(patbuf == NULL) return NULL; |
---|
399 | *pmtpid = dvbgetpmtpid(patbuf, serviceid); |
---|
400 | } |
---|
401 | |
---|
402 | if(*pmtpid < 1) |
---|
403 | { |
---|
404 | err("pmt pid not found sid=%d, pmtpid=%d", serviceid, *pmtpid); |
---|
405 | return NULL; |
---|
406 | } |
---|
407 | |
---|
408 | buf = malloc(MINMALLOC); |
---|
409 | if(buf == NULL) |
---|
410 | { |
---|
411 | err("no memory"); |
---|
412 | return NULL; |
---|
413 | } |
---|
414 | |
---|
415 | if(fenode == NULL) |
---|
416 | { |
---|
417 | err("no frontend dev"); |
---|
418 | return NULL; |
---|
419 | } |
---|
420 | |
---|
421 | dmxnode = dmxopen(fenode, 1); |
---|
422 | if(dmxnode == NULL) |
---|
423 | { |
---|
424 | err("open demux dev"); |
---|
425 | free(buf); |
---|
426 | return NULL; |
---|
427 | } |
---|
428 | // error |
---|
429 | // if(checkbox("ATEMIO-NEMESIS") != 1) |
---|
430 | dmxsetsource(dmxnode, fenode->fedmxsource); |
---|
431 | |
---|
432 | dmxsetfilter(dmxnode, *pmtpid, 0, 2); |
---|
433 | |
---|
434 | for (i = 0; i < 64; i++) |
---|
435 | { |
---|
436 | if((length = dvbread(dmxnode, buf, 0, MINMALLOC, timeout)) < 0) |
---|
437 | { |
---|
438 | err("read pmt pid=%d", *pmtpid); |
---|
439 | break; |
---|
440 | } |
---|
441 | if(serviceid == (((buf[3] & 0xff) << 8) + (buf[4] & 0xff))) |
---|
442 | { |
---|
443 | debug(200, "sid: %d = buf", serviceid); |
---|
444 | dmxclose(dmxnode, -1); |
---|
445 | if(pmtlen != NULL) |
---|
446 | { |
---|
447 | *pmtlen =((buf[1] & 0xf) << 8) + ((buf[2] + 3) & 0xff); |
---|
448 | debug(200, "pmtlen=%d", *pmtlen); |
---|
449 | buf = realloc(buf, *pmtlen); |
---|
450 | } |
---|
451 | return buf; |
---|
452 | } |
---|
453 | } |
---|
454 | |
---|
455 | err("find pmt"); |
---|
456 | dmxclose(dmxnode, -1); |
---|
457 | free(buf); |
---|
458 | if(flag == 0) *pmtpid = 0; |
---|
459 | return NULL; |
---|
460 | } |
---|
461 | |
---|
462 | int dvbgetinfo(unsigned char* pmtbuf, struct channel* chnode) |
---|
463 | { |
---|
464 | int i, sectionlength, programinfolength, esinfolength, ret = 0; |
---|
465 | unsigned short pos, descriptortag, descriptorlength; |
---|
466 | int isac3 = 0, isdts = 0, isaac = 0 isddp = 0; |
---|
467 | int audiocodec = 0, videocodec = 0; |
---|
468 | int firstaudiopid = -1, firstaudiocodec = -1, audiochange = 1; |
---|
469 | int streamtype, pid, tsid, onid, pcrpid; |
---|
470 | unsigned char *tmpbuf = NULL; |
---|
471 | struct audiotrack* prevaudio = NULL; |
---|
472 | |
---|
473 | if(pmtbuf == NULL || chnode == NULL) |
---|
474 | { |
---|
475 | err("NULL detect"); |
---|
476 | return -1; |
---|
477 | } |
---|
478 | |
---|
479 | sectionlength = ((pmtbuf[1] & 0x0F) << 8) + (pmtbuf[2] & 0xff); |
---|
480 | if(sectionlength > MINMALLOC) sectionlength = MINMALLOC; |
---|
481 | programinfolength = ((pmtbuf[10] & 0x0F) << 8) | (pmtbuf[11] & 0xff); |
---|
482 | if(programinfolength > MINMALLOC) programinfolength = MINMALLOC; |
---|
483 | |
---|
484 | pcrpid = chnode->pcrpid; |
---|
485 | chnode->pcrpid = ((pmtbuf[8] & 0x1F) << 8) + pmtbuf[9]; |
---|
486 | debug(200, "add pcrpid %d", chnode->pcrpid); |
---|
487 | if(chnode->pcrpid != pcrpid) status.writechannel = 1; |
---|
488 | |
---|
489 | // pmt |
---|
490 | int programnumber = (pmtbuf[3] << 8) + pmtbuf[4]; |
---|
491 | int versionnumber = (pmtbuf[5] >> 1) & 0x1F; |
---|
492 | int currentnextindicator = pmtbuf[5] & 0x01; |
---|
493 | addpmt(chnode, programnumber, versionnumber, currentnextindicator); |
---|
494 | |
---|
495 | if(programinfolength) |
---|
496 | { |
---|
497 | for(i = 12; i < 12 + programinfolength; i += pmtbuf[i + 1] + 2) |
---|
498 | { |
---|
499 | switch (pmtbuf[i]) |
---|
500 | { |
---|
501 | case 0x09: |
---|
502 | chnode->crypt = 1; |
---|
503 | addcadesc(chnode, 0, &pmtbuf[i], NULL); |
---|
504 | break; |
---|
505 | } |
---|
506 | } |
---|
507 | } |
---|
508 | |
---|
509 | for(i = 12 + programinfolength; i < sectionlength - 1; i += esinfolength + 5) |
---|
510 | { |
---|
511 | tmpbuf = pmtbuf + i; |
---|
512 | if(tmpbuf > pmtbuf + MINMALLOC) break; |
---|
513 | streamtype = (tmpbuf[0] & 0xff); |
---|
514 | pid = ((tmpbuf[1] & 0x1F) << 8) | (tmpbuf[2] & 0xff); |
---|
515 | esinfolength = ((tmpbuf[3] & 0x0F) << 8) | (tmpbuf[4] & 0xff); |
---|
516 | isac3 = 0; isdts = 0; isaac = 0; isddp = 0, audiocodec = 0, videocodec = 0; |
---|
517 | char langdesc[4] = "---"; |
---|
518 | int y = 0, descriptorcount = 0; |
---|
519 | |
---|
520 | addesinfo(chnode, streamtype, pid, NULL); |
---|
521 | |
---|
522 | for(pos = 5; pos < esinfolength + 5; pos += descriptorlength + 2) |
---|
523 | { |
---|
524 | descriptorcount++; |
---|
525 | descriptortag = tmpbuf[pos]; |
---|
526 | descriptorlength = tmpbuf[pos + 1]; |
---|
527 | switch (descriptortag) |
---|
528 | { |
---|
529 | case 0x6f: //get aitpid for hbbtv |
---|
530 | if(streamtype == 0x05) |
---|
531 | { |
---|
532 | chnode->aitpid = pid; |
---|
533 | debug(200, "add aitpid %d", pid); |
---|
534 | } |
---|
535 | break; |
---|
536 | case 0x05: |
---|
537 | if(descriptorlength >= 3) |
---|
538 | if(!ostrncmp((char*)&tmpbuf[pos + 2], "DTS", 3)) |
---|
539 | isdts = 1; |
---|
540 | break; |
---|
541 | case 0x81: |
---|
542 | // private descr: dvb namespace |
---|
543 | tsid = tmpbuf[pos + 6] << 8 | tmpbuf[pos + 7]; |
---|
544 | onid = (tmpbuf[pos + 8]) << 8 | tmpbuf[pos + 9]; |
---|
545 | break; |
---|
546 | case 0x09: |
---|
547 | chnode->crypt = 1; |
---|
548 | addcadesc(chnode, pid, &tmpbuf[pos], NULL); |
---|
549 | break; |
---|
550 | case 0x0A: |
---|
551 | langdesc[0] = toupper(tmpbuf[pos + 2]); |
---|
552 | langdesc[1] = toupper(tmpbuf[pos + 3]); |
---|
553 | langdesc[2] = toupper(tmpbuf[pos + 4]); |
---|
554 | langdesc[3] = '\0'; |
---|
555 | break; |
---|
556 | case 0x6A: |
---|
557 | isac3 = 1; |
---|
558 | break; |
---|
559 | case 0x7C: |
---|
560 | isaac = 1; |
---|
561 | break; |
---|
562 | case 0x7B: |
---|
563 | isdts = 1; |
---|
564 | break; |
---|
565 | // case 0x??; ToDo |
---|
566 | // isddp = 1; |
---|
567 | // break; |
---|
568 | case 0x56: //teletext |
---|
569 | for (y = 0; y < descriptorlength / 5; y++) |
---|
570 | { |
---|
571 | langdesc[0] = toupper(tmpbuf[pos + 5 * y + 2]); |
---|
572 | langdesc[1] = toupper(tmpbuf[pos + 5 * y + 3]); |
---|
573 | langdesc[2] = toupper(tmpbuf[pos + 5 * y + 4]); |
---|
574 | langdesc[3] = '\0'; |
---|
575 | unsigned char txttype = tmpbuf[pos + 5 * y + 5] >> 3; |
---|
576 | unsigned short txtmagazinenr = tmpbuf[pos + 5 * y + 5] & 7; |
---|
577 | unsigned short txtpagenr = tmpbuf[pos + 5 * y + 6]; |
---|
578 | if(txttype == 0x02 || txttype == 0x05) |
---|
579 | addsubtitle(chnode, 1, langdesc , pid, txttype, txtmagazinenr, txtpagenr, NULL); |
---|
580 | |
---|
581 | } |
---|
582 | chnode->txtpid = pid; |
---|
583 | debug(200, "add txtpid %d", pid); |
---|
584 | break; |
---|
585 | case 0x59: //subtitle |
---|
586 | if(streamtype == 0x06) |
---|
587 | { |
---|
588 | for (y = 0; y < descriptorlength / 8; y++) |
---|
589 | { |
---|
590 | langdesc[0] = toupper(tmpbuf[pos + 8 * y + 2]); |
---|
591 | langdesc[1] = toupper(tmpbuf[pos + 8 * y + 3]); |
---|
592 | langdesc[2] = toupper(tmpbuf[pos + 8 * y + 4]); |
---|
593 | langdesc[3] = '\0'; |
---|
594 | unsigned char subtype = tmpbuf[pos + 8 * y + 5]; |
---|
595 | unsigned short subpageid = (tmpbuf[(pos + 8 * y + 6) + 1] << 8) | tmpbuf[pos + 8 * y + 6]; |
---|
596 | endianswapshort(&subpageid); |
---|
597 | unsigned short subancillarypageid = (tmpbuf[(pos + 8 * y + 8) + 1] << 8) | tmpbuf[pos + 8 * y + 8]; |
---|
598 | endianswapshort(&subancillarypageid); |
---|
599 | addsubtitle(chnode, 2, langdesc , pid, subtype, subpageid, subancillarypageid, NULL); |
---|
600 | } |
---|
601 | debug(200, "add subtile pid %d", pid); |
---|
602 | } |
---|
603 | break; |
---|
604 | //case 0x53: //ca identifier |
---|
605 | } |
---|
606 | } |
---|
607 | |
---|
608 | switch (streamtype) |
---|
609 | { |
---|
610 | case 0x01: // Mpeg1 Video (6) |
---|
611 | case 0x02: // Mpeg2 Video (0) |
---|
612 | case 0x10: // Mpeg4 Part2 Video (4) |
---|
613 | case 0x1b: // H264 (1) |
---|
614 | case 0x24: // H265_HEVC |
---|
615 | case 0xea: // vc1 (10) |
---|
616 | if(streamtype == 0x1b) |
---|
617 | videocodec = H264; |
---|
618 | else if(streamtype == 0x24) |
---|
619 | videocodec = H265; |
---|
620 | else if(streamtype == 0x10) |
---|
621 | videocodec = MPEG4V; |
---|
622 | else if(streamtype == 0xea) |
---|
623 | videocodec = VC1; |
---|
624 | else |
---|
625 | videocodec = MPEGV; |
---|
626 | |
---|
627 | if(chnode->videopid != pid || chnode->videocodec != videocodec) |
---|
628 | { |
---|
629 | chnode->videopid = pid; |
---|
630 | chnode->videocodec = videocodec; |
---|
631 | status.writechannel = 1; |
---|
632 | ret = 1; |
---|
633 | |
---|
634 | debug(200, "set videopid to %d", pid); |
---|
635 | debug(200, "set videocode to %d (pid=%d)", videocodec, pid); |
---|
636 | } |
---|
637 | break; |
---|
638 | case 0x03: // Mpeg1 Audio (1) |
---|
639 | case 0x04: // Mpeg2 Audio (1) |
---|
640 | case 0x0f: // Mpeg2 AAC (8) |
---|
641 | case 0x11: // Mpeg4 AACHE (9) |
---|
642 | case 0x80: // LPCM (6) |
---|
643 | case 0xA0: // LPCM (6) |
---|
644 | case 0x81: // AC3 (0) |
---|
645 | case 0xA1: // AC3 (0) |
---|
646 | case 0x82: // DTS (2) |
---|
647 | case 0xA2: // DTS (2) |
---|
648 | case 0x85: // DTS-HD HRA |
---|
649 | case 0x86: // DTS-HD MA |
---|
650 | case 0xA6: // DTS-HD |
---|
651 | case 0x06: |
---|
652 | if(descriptorcount == 0 && streamtype == 0x06 && prevaudio != NULL) |
---|
653 | { |
---|
654 | prevaudio->rdspid = pid; |
---|
655 | debug(200, "set rdspid to %d", pid); |
---|
656 | } |
---|
657 | prevaudio = NULL; |
---|
658 | //if(streamtype == 0x81) esInfo->stream_type = 0x6; |
---|
659 | if(streamtype == 0x06 && !isac3 && !isdts && !isaac && !isddp) |
---|
660 | continue; |
---|
661 | |
---|
662 | if(streamtype == 0x06) |
---|
663 | { |
---|
664 | if(isac3) |
---|
665 | audiocodec = AC3; |
---|
666 | else if(isdts) |
---|
667 | audiocodec = DTS; |
---|
668 | else if(isaac) |
---|
669 | audiocodec = AAC; |
---|
670 | else if(isddp) |
---|
671 | audiocodec = DDP; |
---|
672 | } |
---|
673 | else if(streamtype == 0x0F) |
---|
674 | audiocodec = AAC; |
---|
675 | else if(streamtype == 0x11) |
---|
676 | audiocodec = AACHE; |
---|
677 | else if(streamtype == 0x80 || streamtype == 0xA0) |
---|
678 | audiocodec = LPCM; |
---|
679 | else if(streamtype == 0x81 || streamtype == 0xA1) |
---|
680 | audiocodec = AC3; |
---|
681 | else if(streamtype == 0x82 || streamtype == 0xA2) |
---|
682 | audiocodec = DTS; |
---|
683 | else if(streamtype == 0x85 || (streamtype == 0x86 || streamtype == 0xA6) |
---|
684 | audiocodec = DTSHD; |
---|
685 | else |
---|
686 | audiocodec = MPEGA; |
---|
687 | |
---|
688 | if(firstaudiopid == -1 || firstaudiocodec == -1) |
---|
689 | { |
---|
690 | firstaudiopid = pid; |
---|
691 | firstaudiocodec = audiocodec; |
---|
692 | } |
---|
693 | |
---|
694 | if(getconfigint("av_ac3default", NULL) == YES && audiocodec == AC3 && chnode->audiocodec != AC3) |
---|
695 | { |
---|
696 | chnode->audiopid = pid; |
---|
697 | chnode->audiocodec = audiocodec; |
---|
698 | status.writechannel = 1; |
---|
699 | debug(200, "ac3default -> set audiopid to %d", pid); |
---|
700 | debug(200, "ac3default -> set audiocode to %d (pid=%d)", chnode->audiocodec, pid); |
---|
701 | } |
---|
702 | |
---|
703 | if(chnode->audiopid == pid && chnode->audiocodec == audiocodec) |
---|
704 | audiochange = 0; |
---|
705 | |
---|
706 | prevaudio = addaudiotrack(chnode, langdesc, pid, audiocodec, NULL); |
---|
707 | break; |
---|
708 | } |
---|
709 | } |
---|
710 | |
---|
711 | if(audiochange == 1 && firstaudiopid != -1 && firstaudiocodec != -1) |
---|
712 | { |
---|
713 | chnode->audiopid = firstaudiopid; |
---|
714 | chnode->audiocodec = firstaudiocodec; |
---|
715 | status.writechannel = 1; |
---|
716 | ret = 1; |
---|
717 | |
---|
718 | debug(200, "set audiopid to %d", firstaudiopid); |
---|
719 | debug(200, "set audiocode to %d (pid=%d)", firstaudiocodec, firstaudiopid); |
---|
720 | } |
---|
721 | |
---|
722 | if(chnode->crypt != 0) debug(200, "stream is crypted"); |
---|
723 | return ret; |
---|
724 | } |
---|
725 | |
---|
726 | //check dynamic change of pmt |
---|
727 | void dvbgetpmtthread() |
---|
728 | { |
---|
729 | int len = 0, change = 0; |
---|
730 | unsigned char* pmtbuf = NULL; |
---|
731 | |
---|
732 | //play activ? |
---|
733 | if(status.play != 0 || status.playspeed != 0) return; |
---|
734 | |
---|
735 | if(status.aktservice->type != CHANNEL || status.aktservice->channel == NULL) return; |
---|
736 | |
---|
737 | debug(200, "dvbgetpmtthread started"); |
---|
738 | |
---|
739 | int serviceid = status.aktservice->channel->serviceid; |
---|
740 | uint64_t transponderid = status.aktservice->channel->transponderid; |
---|
741 | int16_t pmtpid = status.aktservice->channel->pmtpid; |
---|
742 | int16_t audiopid = status.aktservice->channel->audiopid; |
---|
743 | int16_t videopid = status.aktservice->channel->videopid; |
---|
744 | uint8_t crypt = status.aktservice->channel->crypt; |
---|
745 | int oldpmtlen = status.aktservice->pmtlen; |
---|
746 | |
---|
747 | if(pmtpid < 1) return; |
---|
748 | |
---|
749 | //outside of lock, can block a little |
---|
750 | pmtbuf = dvbgetpmt(status.aktservice->fedev, NULL, serviceid, &pmtpid, &len, -1, 1); |
---|
751 | if(pmtbuf == NULL) return; |
---|
752 | |
---|
753 | m_lock(&status.servicemutex, 2); |
---|
754 | |
---|
755 | //check if threre was a change from start funktion to lock |
---|
756 | if(status.aktservice->type != CHANNEL || status.aktservice->channel == NULL || status.aktservice->channel->serviceid != serviceid || status.aktservice->channel->transponderid != transponderid) |
---|
757 | { |
---|
758 | debug(200, "change from start"); |
---|
759 | m_unlock(&status.servicemutex, 2); |
---|
760 | free(pmtbuf); |
---|
761 | return; |
---|
762 | } |
---|
763 | |
---|
764 | if(len != status.aktservice->pmtlen || memcmp(status.aktservice->pmtbuf, pmtbuf, len) != 0) |
---|
765 | { |
---|
766 | serviceresetchannelinfo(status.aktservice->channel); |
---|
767 | status.aktservice->channel->audiopid = -1; |
---|
768 | status.aktservice->channel->audiocodec = -1; |
---|
769 | status.aktservice->channel->videopid = -1; |
---|
770 | status.aktservice->channel->videocodec = -1; |
---|
771 | status.aktservice->channel->pmtpid = pmtpid; |
---|
772 | status.aktservice->channel->crypt = 0; |
---|
773 | dvbgetinfo(pmtbuf, status.aktservice->channel); |
---|
774 | |
---|
775 | debug(200, "pmt dynamic change oldapid=%d apid=%d oldvpid=%d vpid=%d oldcrypt=%d crypt=%d oldpmtlen=%d\n", audiopid, status.aktservice->channel->audiopid, videopid, status.aktservice->channel->videopid, status.aktservice->channel->crypt, crypt, oldpmtlen); |
---|
776 | |
---|
777 | if(status.aktservice->channel->audiopid != audiopid || status.aktservice->channel->videopid != videopid || oldpmtlen == -1 || status.aktservice->channel->crypt != crypt) |
---|
778 | change = 1; |
---|
779 | } |
---|
780 | |
---|
781 | m_unlock(&status.servicemutex, 2); |
---|
782 | free(pmtbuf); |
---|
783 | |
---|
784 | if(change == 1) |
---|
785 | servicestart(status.aktservice->channel, NULL, NULL, 3); |
---|
786 | |
---|
787 | debug(200, "dvbgetpmtthread ended... change=%i", change); |
---|
788 | } |
---|
789 | |
---|
790 | time_t dvbconvertdate(unsigned char *buf, int flag) |
---|
791 | { |
---|
792 | int i = 0; |
---|
793 | long mjd; |
---|
794 | struct tm *time = NULL; |
---|
795 | time_t gmttime = 0; |
---|
796 | |
---|
797 | time = (struct tm*)malloc(sizeof(struct tm)); |
---|
798 | if(time == NULL) |
---|
799 | { |
---|
800 | err("no mem"); |
---|
801 | return 0; |
---|
802 | } |
---|
803 | |
---|
804 | memset(time, 0, sizeof(struct tm)); |
---|
805 | |
---|
806 | mjd = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff); |
---|
807 | time->tm_hour = bcdtoint(buf[2] & 0xff); |
---|
808 | time->tm_min = bcdtoint(buf[3] & 0xff); |
---|
809 | time->tm_sec = bcdtoint(buf[4] & 0xff); |
---|
810 | |
---|
811 | time->tm_year = (int) ((mjd - 15078.2) / 365.25); |
---|
812 | time->tm_mon = (int) ((mjd - 14956.1 - (int) (time->tm_year * 365.25)) / 30.6001); |
---|
813 | time->tm_mday = (int) mjd - 14956 - (int) (time->tm_year * 365.25) - (int) (time->tm_mon * 30.6001); |
---|
814 | if(time->tm_mon == 14 || time->tm_mon == 15) i = 1; |
---|
815 | time->tm_year += i; |
---|
816 | time->tm_mon = time->tm_mon - 2 - i * 12; |
---|
817 | |
---|
818 | time->tm_isdst = 0; |
---|
819 | time->tm_gmtoff = 0; |
---|
820 | |
---|
821 | if(flag == 0) |
---|
822 | gmttime = timegm(time); |
---|
823 | else |
---|
824 | gmttime = mktime(time); |
---|
825 | |
---|
826 | free(time); |
---|
827 | return gmttime; |
---|
828 | } |
---|
829 | |
---|
830 | int dvbgetdate(time_t* time, int timeout) |
---|
831 | { |
---|
832 | int length = -1, sectionlength; |
---|
833 | struct dvbdev* dmxnode = NULL; |
---|
834 | unsigned char *buf = NULL; |
---|
835 | |
---|
836 | buf = malloc(MINMALLOC); |
---|
837 | if(buf == NULL) |
---|
838 | { |
---|
839 | err("no memory"); |
---|
840 | return 1; |
---|
841 | } |
---|
842 | |
---|
843 | if(status.aktservice->fedev == NULL) |
---|
844 | { |
---|
845 | err("no frontend dev in aktservice"); |
---|
846 | free(buf); |
---|
847 | return 1; |
---|
848 | } |
---|
849 | |
---|
850 | dmxnode = dmxopen(status.aktservice->fedev, 1); |
---|
851 | if(dmxnode == NULL) |
---|
852 | { |
---|
853 | err("open demux dev"); |
---|
854 | free(buf); |
---|
855 | return 1; |
---|
856 | } |
---|
857 | |
---|
858 | dmxsetsource(dmxnode, status.aktservice->fedev->fedmxsource); |
---|
859 | dmxsetfilter(dmxnode, 0x14, 0, 3); |
---|
860 | |
---|
861 | if((length = dvbread(dmxnode, buf, 0, MINMALLOC, timeout)) < 0) |
---|
862 | if(length < 3) |
---|
863 | { |
---|
864 | dmxclose(dmxnode, -1); |
---|
865 | free(buf); |
---|
866 | err("read dvb date"); |
---|
867 | return 1; |
---|
868 | } |
---|
869 | |
---|
870 | sectionlength = ((buf[1] & 0x0f) << 8) | (buf[2] & 0xff); |
---|
871 | if(length == sectionlength + 3) |
---|
872 | *time = dvbconvertdate(&(buf[3]), 0); |
---|
873 | else |
---|
874 | { |
---|
875 | dmxclose(dmxnode, -1); |
---|
876 | free(buf); |
---|
877 | err("read dvb date"); |
---|
878 | return 1; |
---|
879 | } |
---|
880 | |
---|
881 | setrtctime(*time); |
---|
882 | |
---|
883 | dmxclose(dmxnode, -1); |
---|
884 | free(buf); |
---|
885 | return 0; |
---|
886 | } |
---|
887 | |
---|
888 | // getPTS extracts a pts value from any PID at a given offset. |
---|
889 | int getpts(int fd, off64_t offset, int spid, int left, unsigned long long *pts, off64_t *findpos, int dir, int tssize) |
---|
890 | { |
---|
891 | int first = 1; |
---|
892 | |
---|
893 | offset -= offset % tssize; |
---|
894 | if(dir < 0 && offset < tssize) offset = tssize * 2; |
---|
895 | if(dir < 0) offset *= -1; |
---|
896 | while(left >= tssize) |
---|
897 | { |
---|
898 | unsigned char packet[tssize]; |
---|
899 | |
---|
900 | if(dir > -1) |
---|
901 | *findpos = lseek64(fd, offset, SEEK_SET); |
---|
902 | else |
---|
903 | { |
---|
904 | if(dir == -2) |
---|
905 | { |
---|
906 | if(first == 1) |
---|
907 | { |
---|
908 | first = 0; |
---|
909 | offset *= -1; |
---|
910 | *findpos = lseek64(fd, offset, SEEK_SET); |
---|
911 | offset = -tssize; |
---|
912 | } |
---|
913 | else |
---|
914 | { |
---|
915 | if(offset % tssize != 0) |
---|
916 | { |
---|
917 | *findpos = lseek64(fd, (offset % tssize) - tssize, SEEK_CUR); |
---|
918 | offset = -tssize; |
---|
919 | } |
---|
920 | else |
---|
921 | *findpos = lseek64(fd, -tssize * 2, SEEK_CUR); |
---|
922 | } |
---|
923 | } |
---|
924 | else |
---|
925 | *findpos = lseek64(fd, offset, SEEK_END); |
---|
926 | } |
---|
927 | |
---|
928 | int ret = dvbreadfd(fd, packet, 0, tssize, -1, 0); |
---|
929 | if(ret != tssize && ret != 188) |
---|
930 | { |
---|
931 | err("read error"); |
---|
932 | break; |
---|
933 | } |
---|
934 | |
---|
935 | if(packet[0] != 0x47) |
---|
936 | { |
---|
937 | debug(200, "resync"); |
---|
938 | int i = 0; |
---|
939 | while(i < tssize) |
---|
940 | { |
---|
941 | if(packet[i] == 0x47) break; |
---|
942 | i++; |
---|
943 | offset++; |
---|
944 | } |
---|
945 | continue; |
---|
946 | } |
---|
947 | |
---|
948 | left -= tssize; |
---|
949 | if(dir > -1) |
---|
950 | offset += tssize; |
---|
951 | else |
---|
952 | offset -= tssize; |
---|
953 | |
---|
954 | int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF; |
---|
955 | int pusi = !!(packet[1] & 0x40); |
---|
956 | |
---|
957 | // printf("PID %04x, PUSI %d\n", pid, pusi); |
---|
958 | |
---|
959 | unsigned char *payload; |
---|
960 | |
---|
961 | //check for adaption field |
---|
962 | if(packet[3] & 0x20) |
---|
963 | { |
---|
964 | if(packet[4] >= 183) continue; |
---|
965 | if(packet[4]) |
---|
966 | { |
---|
967 | if(packet[5] & 0x10) //PCR present |
---|
968 | { |
---|
969 | *pts = ((unsigned long long)(packet[6] & 0xFF)) << 25; |
---|
970 | *pts |= ((unsigned long long)(packet[7] & 0xFF)) << 17; |
---|
971 | *pts |= ((unsigned long long)(packet[8] & 0xFE)) << 9; |
---|
972 | *pts |= ((unsigned long long)(packet[9] & 0xFF)) << 1; |
---|
973 | *pts |= ((unsigned long long)(packet[10] & 0x80)) >> 7; |
---|
974 | if(dir > -1) |
---|
975 | { |
---|
976 | offset -= tssize; |
---|
977 | *findpos -= tssize; |
---|
978 | } |
---|
979 | debug(200, "PCR %16llx found at %lld pid %02x (%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x)", *pts, offset, pid, packet[0], packet[1], packet[2], packet[3], packet[4], packet[5], packet[10], packet[9], packet[8], packet[7], packet[6]); |
---|
980 | return 0; |
---|
981 | } |
---|
982 | } |
---|
983 | payload = packet + packet[4] + 4 + 1; |
---|
984 | } else |
---|
985 | payload = packet + 4; |
---|
986 | |
---|
987 | //if(spid >= 0 && pid != spid) continue; |
---|
988 | if(!pusi) continue; |
---|
989 | |
---|
990 | //somehow not a startcode. (this is invalid, since pusi was set.) ignore it. |
---|
991 | if (payload[0] || payload[1] || (payload[2] != 1)) |
---|
992 | continue; |
---|
993 | |
---|
994 | //stream use extension mechanism def in ISO 13818-1 Amendment 2 |
---|
995 | if(payload[3] == 0xFD) |
---|
996 | { |
---|
997 | if(payload[7] & 1) //PES extension flag |
---|
998 | { |
---|
999 | int offs = 0; |
---|
1000 | if(payload[7] & 0x80) offs += 5; //pts avail |
---|
1001 | if(payload[7] & 0x40) offs += 5; //dts avail |
---|
1002 | if(payload[7] & 0x20) offs += 6; //escr avail |
---|
1003 | if(payload[7] & 0x10) offs += 3; //es rate |
---|
1004 | if(payload[7] & 0x8) offs += 1; //dsm trickmode |
---|
1005 | if(payload[7] & 0x4) offs += 1; //additional copy info |
---|
1006 | if(payload[7] & 0x2) offs += 2; //crc |
---|
1007 | if(payload[8] < offs) continue; |
---|
1008 | |
---|
1009 | uint8_t pef = payload[9 + offs++]; //pes extension field |
---|
1010 | if(pef & 1) //pes extension flag 2 |
---|
1011 | { |
---|
1012 | if(pef & 0x80) offs += 16; //private data flag |
---|
1013 | if(pef & 0x40) offs += 1; //pack header field flag |
---|
1014 | if(pef & 0x20) offs += 2; //program packet sequence counter flag |
---|
1015 | if(pef & 0x10) offs += 2; //P-STD buffer flag |
---|
1016 | if(payload[8] < offs) continue; |
---|
1017 | |
---|
1018 | uint8_t stream_id_extension_len = payload[9 + offs++] & 0x7F; |
---|
1019 | if(stream_id_extension_len >= 1) |
---|
1020 | { |
---|
1021 | if(payload[8] < (offs + stream_id_extension_len)) continue; |
---|
1022 | //stream_id_extension_bit (should not set) |
---|
1023 | if(payload[9 + offs] & 0x80) continue; |
---|
1024 | switch(payload[9 + offs]) |
---|
1025 | { |
---|
1026 | case 0x55 ... 0x5f: break; //VC-1 |
---|
1027 | case 0x71: break; //AC3 / DTS |
---|
1028 | case 0x72: break; //DTS - HD |
---|
1029 | default: |
---|
1030 | debug(200, "skip unknwn stream_id_extension %02x\n", payload[9 + offs]); |
---|
1031 | continue; |
---|
1032 | } |
---|
1033 | } |
---|
1034 | else |
---|
1035 | continue; |
---|
1036 | } |
---|
1037 | else |
---|
1038 | continue; |
---|
1039 | } |
---|
1040 | else |
---|
1041 | continue; |
---|
1042 | } |
---|
1043 | //drop non-audio, non-video packets because other streams |
---|
1044 | //can be non-compliant. |
---|
1045 | //0xC0 = audio, 0xE0 = video |
---|
1046 | else if(((payload[3] & 0xE0) != 0xC0) && ((payload[3] & 0xF0) != 0xE0)) |
---|
1047 | continue; |
---|
1048 | |
---|
1049 | if(payload[7] & 0x80) //PTS |
---|
1050 | { |
---|
1051 | *pts = ((unsigned long long)(payload[9] & 0xE)) << 29; |
---|
1052 | *pts |= ((unsigned long long)(payload[10] & 0xFF)) << 22; |
---|
1053 | *pts |= ((unsigned long long)(payload[11] & 0xFE)) << 14; |
---|
1054 | *pts |= ((unsigned long long)(payload[12] & 0xFF)) << 7; |
---|
1055 | *pts |= ((unsigned long long)(payload[13] & 0xFE)) >> 1; |
---|
1056 | |
---|
1057 | if(dir > -1) |
---|
1058 | { |
---|
1059 | offset -= tssize; |
---|
1060 | *findpos -= tssize; |
---|
1061 | } |
---|
1062 | debug(200, "PTS %16llx found at %lld pid %02x stream: %02x", *pts, offset, pid, payload[3]); |
---|
1063 | |
---|
1064 | return 0; |
---|
1065 | } |
---|
1066 | } |
---|
1067 | |
---|
1068 | return 1; |
---|
1069 | } |
---|
1070 | |
---|
1071 | unsigned long long fixuppts(unsigned long long start, unsigned long long end) |
---|
1072 | { |
---|
1073 | //pts can wrap to 0 in the middle |
---|
1074 | if(end < start) |
---|
1075 | end = end + 0x200000000LL; |
---|
1076 | return end; |
---|
1077 | } |
---|
1078 | |
---|
1079 | unsigned long long gettsbitrate(unsigned long long start, unsigned long long end, off64_t startfindpos, off64_t endfindpos) |
---|
1080 | { |
---|
1081 | unsigned long long bitrate = 0; |
---|
1082 | unsigned long long diff = 0; |
---|
1083 | |
---|
1084 | diff = end - start; |
---|
1085 | if(diff <= 0) return 0; |
---|
1086 | |
---|
1087 | bitrate = (endfindpos - startfindpos) * 90000 * 8 / diff; |
---|
1088 | if(bitrate < 10000 || bitrate > 100000000) |
---|
1089 | return 0; |
---|
1090 | else |
---|
1091 | return bitrate; |
---|
1092 | } |
---|
1093 | |
---|
1094 | int gettsinfo(int fd, unsigned long long* lenpts, unsigned long long* startpts, unsigned long long* endpts, unsigned long long* bitrate, int tssize) |
---|
1095 | { |
---|
1096 | int ret = 0; |
---|
1097 | unsigned long long start = 0, end = 0; |
---|
1098 | off64_t startfindpos = 0, endfindpos = 0; |
---|
1099 | |
---|
1100 | if(startpts != NULL && *startpts > 0) start = *startpts; |
---|
1101 | if(endpts != NULL && *endpts > 0) end = *endpts; |
---|
1102 | |
---|
1103 | if(start == 0 || (bitrate != NULL && bitrate == 0)) |
---|
1104 | ret = getpts(fd, 0, 0, 256 * 1024, &start, &startfindpos, 1, tssize); |
---|
1105 | |
---|
1106 | if((ret == 0 && end == 0) || (bitrate != NULL && bitrate == 0)) |
---|
1107 | ret = getpts(fd, 0, 0, 256 * 1024, &end, &endfindpos, -1, tssize); |
---|
1108 | |
---|
1109 | if(ret == 0) |
---|
1110 | { |
---|
1111 | end = fixuppts(start, end); |
---|
1112 | if(lenpts != NULL) *lenpts = end - start; |
---|
1113 | if(startpts != NULL) *startpts = start; |
---|
1114 | if(endpts != NULL) *endpts = end; |
---|
1115 | if(bitrate != NULL && *bitrate == 0) *bitrate = gettsbitrate(start, end, startfindpos, endfindpos); |
---|
1116 | } |
---|
1117 | |
---|
1118 | if(lenpts != NULL && *lenpts < 0) *lenpts = 0; |
---|
1119 | if(startpts != NULL && *startpts < 0) *startpts = 0; |
---|
1120 | if(endpts != NULL && *endpts < 0) *endpts = 0; |
---|
1121 | return ret; |
---|
1122 | } |
---|
1123 | |
---|
1124 | int getptspos(int fd, off64_t startfind, unsigned long long* pts, off64_t* findpos, int dir, int tssize) |
---|
1125 | { |
---|
1126 | int ret = 0; |
---|
1127 | unsigned long long pts1 = 0; |
---|
1128 | off64_t findpos1 = 0; |
---|
1129 | |
---|
1130 | ret = getpts(fd, startfind, 0, 256 * 1024, &pts1, &findpos1, dir, tssize); |
---|
1131 | if(pts != NULL) *pts = pts1; |
---|
1132 | if(findpos != NULL) *findpos = findpos1; |
---|
1133 | |
---|
1134 | return ret; |
---|
1135 | } |
---|
1136 | |
---|
1137 | |
---|
1138 | //rc = 1 --> mpeg |
---|
1139 | //rc = 2 --> h.264 |
---|
1140 | int findcodec(unsigned char* buf, int len, int tssize) |
---|
1141 | { |
---|
1142 | int i,i1; |
---|
1143 | int rc = 2; |
---|
1144 | |
---|
1145 | for(i = 0; i < len-tssize; i = i + tssize) |
---|
1146 | { |
---|
1147 | if((buf[i+1]&0x40)>>6 == 0x01) |
---|
1148 | { |
---|
1149 | for(i1 = i+4; i1 < i + tssize-4; i1 = i1 + 1) |
---|
1150 | { |
---|
1151 | if (buf[i1] == 0x00 && buf[i1+1] == 0x00 && buf[i1+2] == 0x01 && buf[i1+3] == 0xB3) |
---|
1152 | { |
---|
1153 | return 1; |
---|
1154 | } |
---|
1155 | } |
---|
1156 | } |
---|
1157 | } |
---|
1158 | return rc; |
---|
1159 | } |
---|
1160 | |
---|
1161 | //flag=0 -> future use |
---|
1162 | //flag=1 -> I-Slice |
---|
1163 | //flag=2 -> ende Frame |
---|
1164 | int findframeHD(unsigned char* buf, int len, int start, int tssize, int flag) |
---|
1165 | { |
---|
1166 | int position = -1; |
---|
1167 | int i = 0; |
---|
1168 | int i1 = 0; |
---|
1169 | |
---|
1170 | len = start + len; |
---|
1171 | |
---|
1172 | while(1) |
---|
1173 | { |
---|
1174 | for(i = start; i < len-3; i = i + 1) |
---|
1175 | { |
---|
1176 | //Picture header ? |
---|
1177 | if (buf[i] == 0x00 && buf[i+1] == 0x00 && buf[i+2] == 0x01) |
---|
1178 | { |
---|
1179 | //SPS (Sequence Parameter Set)? |
---|
1180 | if(buf[i+3] == 0x67 && flag == 1) |
---|
1181 | { |
---|
1182 | //PPS (Picture Parameter Set) ? |
---|
1183 | for(i1 = i + 4; i1 < (i % tssize) + i; i1 = i1 + 1) |
---|
1184 | { |
---|
1185 | if (buf[i1] == 0x00 && buf[i1+1] == 0x00 && buf[i1+2] == 0x01 && buf[i1+3] == 0x68) |
---|
1186 | { |
---|
1187 | position = i1; |
---|
1188 | break; |
---|
1189 | } |
---|
1190 | } |
---|
1191 | if(position != -1) |
---|
1192 | { |
---|
1193 | for(i1 = position + 4; i1 < (position % tssize) + position; i1 = i1 + 1) |
---|
1194 | { |
---|
1195 | if (buf[i1] == 0x00 && buf[i1+1] == 0x00 && buf[i1+2] == 0x01) |
---|
1196 | { |
---|
1197 | if(buf[i1+3] == 0x01 || buf[i1+3] == 0x21 || buf[i1+3] == 0x41 || buf[i1+3] == 0x61) |
---|
1198 | { |
---|
1199 | i = i1+4; |
---|
1200 | position = -1; |
---|
1201 | break; |
---|
1202 | } |
---|
1203 | } |
---|
1204 | } |
---|
1205 | } |
---|
1206 | if(position != -1) |
---|
1207 | break; |
---|
1208 | } |
---|
1209 | //I-P-Slice oder I-P-B-Slice oder oder .....? |
---|
1210 | else if((buf[i+3] == 0x01 || buf[i+3] == 0x21 || buf[i+3] == 0x41 || buf[i+3] == 0x61) && flag == 2 ) |
---|
1211 | { |
---|
1212 | position = i; |
---|
1213 | break; |
---|
1214 | } |
---|
1215 | } |
---|
1216 | } |
---|
1217 | return position; |
---|
1218 | } |
---|
1219 | } |
---|
1220 | |
---|
1221 | |
---|
1222 | //flag=0 -> Sequence header |
---|
1223 | //flag=1 -> I-Fame |
---|
1224 | //flag=2 -> ende Frame |
---|
1225 | int findframe(unsigned char* buf, int len, int start, int tssize, int flag) |
---|
1226 | { |
---|
1227 | //#define SEQ_START_CODE 0x000001b3 |
---|
1228 | //#define GOP_START_CODE 0x000001b8 |
---|
1229 | //#define PICTURE_START_CODE 0x00000100 |
---|
1230 | //#define SLICE_START_CODE 0x00000101 |
---|
1231 | //#define PACK_START_CODE 0x000001ba |
---|
1232 | //#define VIDEO_ID 0x000001e0 |
---|
1233 | //#define AUDIO_ID 0x000001c0 |
---|
1234 | |
---|
1235 | |
---|
1236 | int position = -1; |
---|
1237 | int i = 0; |
---|
1238 | |
---|
1239 | len = start + len; |
---|
1240 | |
---|
1241 | while(1) { |
---|
1242 | |
---|
1243 | for(i = start; i < len-3; i = i + 1) |
---|
1244 | { |
---|
1245 | |
---|
1246 | //Picture header ? |
---|
1247 | if (buf[i] == 0x00 && buf[i+1] == 0x00 && buf[i+2] == 0x01) |
---|
1248 | { |
---|
1249 | |
---|
1250 | //Sequence header |
---|
1251 | if(buf[i+3] == 0xB3 && flag == 0) |
---|
1252 | { |
---|
1253 | position = i; |
---|
1254 | break; |
---|
1255 | } |
---|
1256 | |
---|
1257 | //Picture-Frame ? |
---|
1258 | else if(buf[i+3] == 0x00) |
---|
1259 | { |
---|
1260 | |
---|
1261 | //I-Frame ? |
---|
1262 | if((buf[i+5] & 0x38)>>3 == 0x01 && flag == 1) |
---|
1263 | { |
---|
1264 | position = i; |
---|
1265 | break; |
---|
1266 | } |
---|
1267 | |
---|
1268 | //other Frame ? |
---|
1269 | else if((buf[i+5] & 0x38)>>3 != 0x00 && flag == 2) |
---|
1270 | { |
---|
1271 | position = i; |
---|
1272 | break; |
---|
1273 | } |
---|
1274 | } |
---|
1275 | } |
---|
1276 | } |
---|
1277 | return position; |
---|
1278 | } |
---|
1279 | } |
---|
1280 | |
---|
1281 | int findandposrew(int fd, int tssize, int skip) |
---|
1282 | { |
---|
1283 | int i; |
---|
1284 | int ret = 0; |
---|
1285 | int framelen = -1; |
---|
1286 | off64_t endframe = -1; |
---|
1287 | off64_t startframe = -1; |
---|
1288 | int readret = 0; |
---|
1289 | int codec = 0; |
---|
1290 | int buflen = tssize * 15000; |
---|
1291 | unsigned char* buf = malloc(buflen); |
---|
1292 | off64_t currentpos; |
---|
1293 | off64_t skippos; |
---|
1294 | |
---|
1295 | //ret = videostop(status.aktservice->videodev,0); |
---|
1296 | //ret = videoclearbuffer(status.aktservice->videodev); |
---|
1297 | //ret = audioclearbuffer(status.aktservice->audiodev); |
---|
1298 | //ret = audiosetavsync(status.aktservice->audiodev, 0); |
---|
1299 | //ret = audiosetmute(status.aktservice->audiodev, 1); |
---|
1300 | |
---|
1301 | currentpos = lseek64(fd, 0, SEEK_CUR); |
---|
1302 | skippos = currentpos; |
---|
1303 | |
---|
1304 | while(1) |
---|
1305 | { |
---|
1306 | skippos = skippos - buflen; |
---|
1307 | if(skippos < 0) |
---|
1308 | { |
---|
1309 | currentpos = lseek64(fd, currentpos, SEEK_SET); |
---|
1310 | free(buf); |
---|
1311 | return -1; |
---|
1312 | } |
---|
1313 | skippos = lseek64(fd, skippos, SEEK_SET); |
---|
1314 | readret = dvbreadfd(fd, buf, 0, buflen, 5000000, 1); |
---|
1315 | if(readret > 0) |
---|
1316 | { |
---|
1317 | codec = findcodec(buf, buflen, tssize); |
---|
1318 | for(i = readret - tssize; i >= 0; i = i - tssize) |
---|
1319 | { |
---|
1320 | if(codec == 1) |
---|
1321 | ret = findframe(buf, tssize, i, tssize, 0); |
---|
1322 | else |
---|
1323 | ret = findframeHD(buf, tssize, i, tssize, 1); |
---|
1324 | if(ret > -1) |
---|
1325 | { |
---|
1326 | if(endframe == -1) |
---|
1327 | { |
---|
1328 | if(skip != 0) |
---|
1329 | skip = skip - 1; |
---|
1330 | else |
---|
1331 | endframe = skippos + i; |
---|
1332 | } |
---|
1333 | else |
---|
1334 | { |
---|
1335 | startframe = skippos + i; |
---|
1336 | framelen = endframe - startframe; |
---|
1337 | currentpos = lseek64(fd, startframe, SEEK_SET); |
---|
1338 | //readret = dvbreadfd(servicenode->recsrcfd, buf, 0, buflen, 5000000, 1); |
---|
1339 | free(buf); |
---|
1340 | return framelen; |
---|
1341 | } |
---|
1342 | } |
---|
1343 | } |
---|
1344 | } |
---|
1345 | else |
---|
1346 | { |
---|
1347 | currentpos = lseek64(fd, currentpos, SEEK_SET); |
---|
1348 | free(buf); |
---|
1349 | return -1; |
---|
1350 | } |
---|
1351 | } |
---|
1352 | } |
---|
1353 | |
---|
1354 | #endif |
---|