1 | #ifndef SUBTITLE_H |
---|
2 | #define SUBTITLE_H |
---|
3 | |
---|
4 | int subdisplaywidth = 720; |
---|
5 | int subdisplayheight = 576; |
---|
6 | |
---|
7 | static int map2to4bit[4]; |
---|
8 | static int map2to8bit[4]; |
---|
9 | static int map4to8bit[16]; |
---|
10 | |
---|
11 | //flag 0 = free oldsubpage |
---|
12 | //flag 1 = free subpage |
---|
13 | void subfree(int flag) |
---|
14 | { |
---|
15 | struct subpage* page = NULL; |
---|
16 | struct subpage* tmppage = NULL; |
---|
17 | |
---|
18 | if(flag == 0) page = oldsubpage; |
---|
19 | if(flag == 1) page = subpage; |
---|
20 | |
---|
21 | while(page != NULL) |
---|
22 | { |
---|
23 | while(page->pageregions != NULL) |
---|
24 | { |
---|
25 | struct subpagereg *p = page->pageregions->next; |
---|
26 | free(page->pageregions); |
---|
27 | page->pageregions = p; |
---|
28 | } |
---|
29 | while(page->regions != NULL) |
---|
30 | { |
---|
31 | struct subreg *reg = page->regions; |
---|
32 | |
---|
33 | while(reg->objects != NULL) |
---|
34 | { |
---|
35 | struct subregobj *obj = reg->objects; |
---|
36 | reg->objects = obj->next; |
---|
37 | free(obj); |
---|
38 | } |
---|
39 | |
---|
40 | free(reg->buf); |
---|
41 | reg->buf = NULL; |
---|
42 | free(reg->palette); |
---|
43 | reg->palette = NULL; |
---|
44 | |
---|
45 | page->regions = reg->next; |
---|
46 | free(reg); |
---|
47 | } |
---|
48 | while(page->cluts != NULL) |
---|
49 | { |
---|
50 | struct subclut *clut = page->cluts; |
---|
51 | page->cluts = clut->next; |
---|
52 | free(clut); |
---|
53 | } |
---|
54 | |
---|
55 | tmppage = page->next; |
---|
56 | free(page); |
---|
57 | if(flag == 0) oldsubpage = NULL; |
---|
58 | if(flag == 1) subpage = NULL; |
---|
59 | page = tmppage; |
---|
60 | } |
---|
61 | } |
---|
62 | |
---|
63 | void subclear(int ontimeout) |
---|
64 | { |
---|
65 | struct subpage* subnode = oldsubpage; |
---|
66 | struct subpagereg* pageregnode = NULL; |
---|
67 | time_t sec = 0; |
---|
68 | int stat = 0; |
---|
69 | |
---|
70 | if(subnode != NULL) |
---|
71 | { |
---|
72 | if(ontimeout == 1) |
---|
73 | { |
---|
74 | if(subnode->pagetimeout == 0) return; |
---|
75 | sec = time(NULL); |
---|
76 | if(subnode->pagetimeout >= sec) return; |
---|
77 | } |
---|
78 | |
---|
79 | pageregnode = subnode->pageregions; |
---|
80 | while(pageregnode != NULL) |
---|
81 | { |
---|
82 | struct subreg *regnode = subnode->regions; |
---|
83 | while(regnode != NULL) |
---|
84 | { |
---|
85 | if(regnode->regid == pageregnode->regid) break; |
---|
86 | regnode = regnode->next; |
---|
87 | } |
---|
88 | if(regnode != NULL) |
---|
89 | { |
---|
90 | stat = 1; |
---|
91 | int posx = pageregnode->scaleposx; |
---|
92 | int posy = pageregnode->scaleposy; |
---|
93 | |
---|
94 | if(posx < 0 || posy < 0) continue; |
---|
95 | clearrect(posx, posy, regnode->scalewidth, regnode->scaleheight); |
---|
96 | } |
---|
97 | pageregnode = pageregnode->next; |
---|
98 | } |
---|
99 | |
---|
100 | if(stat == 1) blitfb(0); |
---|
101 | subfree(0); |
---|
102 | } |
---|
103 | } |
---|
104 | |
---|
105 | void subdraw(unsigned long long subpts, struct subpage* page) |
---|
106 | { |
---|
107 | debug(300, "subtitle draw"); |
---|
108 | struct subpagereg* pageregnode = NULL; |
---|
109 | int y, x, stat = 0; |
---|
110 | uint64_t pts = 0; |
---|
111 | unsigned char* scalebuf = NULL; |
---|
112 | |
---|
113 | if(page == NULL) return; |
---|
114 | |
---|
115 | //wait for subtitle to display |
---|
116 | #ifndef SIMULATE |
---|
117 | videogetpts(status.aktservice->videodev, &pts); |
---|
118 | #else |
---|
119 | pts = 8275201296; |
---|
120 | #endif |
---|
121 | debug(300, "pts = %lld, subpts = %lld", pts, subpts); |
---|
122 | while(status.subthreadaktion != STOP && status.subthreadaktion != PAUSE && subpts >= pts) |
---|
123 | { |
---|
124 | subclear(1); |
---|
125 | usleep(100000); |
---|
126 | #ifndef SIMULATE |
---|
127 | videogetpts(status.aktservice->videodev, &pts); |
---|
128 | #else |
---|
129 | pts += 100000; |
---|
130 | #endif |
---|
131 | } |
---|
132 | if(status.subthreadaktion == STOP || status.subthreadaktion == PAUSE) |
---|
133 | return; |
---|
134 | debug(300, "pts = %lld, subpts = %lld", pts, subpts); |
---|
135 | |
---|
136 | subclear(0); |
---|
137 | |
---|
138 | pageregnode = page->pageregions; |
---|
139 | while(pageregnode != NULL) |
---|
140 | { |
---|
141 | |
---|
142 | struct subreg *regnode = page->regions; |
---|
143 | while(regnode != NULL) |
---|
144 | { |
---|
145 | if(regnode->regid == pageregnode->regid) break; |
---|
146 | regnode = regnode->next; |
---|
147 | } |
---|
148 | if(regnode != NULL && regnode->buf != NULL) |
---|
149 | { |
---|
150 | |
---|
151 | stat = 1; |
---|
152 | int posx = pageregnode->reghorizontaladdress * skinfb->width / subdisplaywidth; |
---|
153 | int posy = pageregnode->regverticaladdress * skinfb->height / subdisplayheight; |
---|
154 | unsigned long *palette = (unsigned long*)regnode->palette; |
---|
155 | |
---|
156 | pageregnode->scaleposx = posx; |
---|
157 | pageregnode->scaleposy = posy; |
---|
158 | |
---|
159 | //scale |
---|
160 | regnode->scalewidth = regnode->width * skinfb->width / subdisplaywidth; |
---|
161 | regnode->scaleheight = regnode->height * skinfb->height / subdisplayheight; |
---|
162 | |
---|
163 | if(accelfb != NULL && accelfb->varfbsize >= regnode->width * regnode->height * 4) |
---|
164 | { |
---|
165 | |
---|
166 | m_lock(&status.accelfbmutex, 16); |
---|
167 | for(y = 0; y < regnode->height; y++) |
---|
168 | { |
---|
169 | for(x = 0; x < regnode->width; x++) |
---|
170 | { |
---|
171 | if(regnode->buf[y * regnode->width + x] != 0) |
---|
172 | drawpixelfb(accelfb, (regnode->width * y) + x, 0, palette[regnode->buf[y * regnode->width + x]]); |
---|
173 | else |
---|
174 | drawpixelfb(accelfb, (regnode->width * y) + x, 0, 0); |
---|
175 | } |
---|
176 | } |
---|
177 | blitscale(posx, posy, regnode->width, regnode->height, regnode->scalewidth, regnode->scaleheight, 0); |
---|
178 | m_unlock(&status.accelfbmutex, 16); |
---|
179 | } |
---|
180 | else |
---|
181 | { |
---|
182 | if(regnode->scalewidth != regnode->width || regnode->scaleheight != regnode->height) |
---|
183 | { |
---|
184 | scalebuf = scale(regnode->buf, regnode->width, regnode->height, 1, regnode->scalewidth, regnode->scaleheight, 1); |
---|
185 | if(scalebuf != NULL) regnode->buf = scalebuf; |
---|
186 | } |
---|
187 | else |
---|
188 | scalebuf = regnode->buf; |
---|
189 | /* |
---|
190 | //only for test no scale |
---|
191 | posx = pageregnode->reghorizontaladdress; |
---|
192 | posy = pageregnode->regverticaladdress; |
---|
193 | pageregnode->scaleposx = posx; |
---|
194 | pageregnode->scaleposy = posy; |
---|
195 | regnode->scalewidth = regnode->width; |
---|
196 | regnode->scaleheight = regnode->height; |
---|
197 | */ |
---|
198 | |
---|
199 | for(y = 0; y < regnode->scaleheight; y++) |
---|
200 | { |
---|
201 | for(x = 0; x < regnode->scalewidth; x++) |
---|
202 | { |
---|
203 | if(regnode->buf[y * regnode->scalewidth + x] != 0) |
---|
204 | { |
---|
205 | drawpixel(posx + x, posy + y, palette[regnode->buf[y * regnode->scalewidth + x]]); |
---|
206 | } |
---|
207 | } |
---|
208 | } |
---|
209 | } |
---|
210 | } |
---|
211 | pageregnode = pageregnode->next; |
---|
212 | } |
---|
213 | if(stat == 1) blitfb(0); |
---|
214 | } |
---|
215 | |
---|
216 | void subcalc(int pageid, unsigned long long pts) |
---|
217 | { |
---|
218 | int i, clutsize = 0; |
---|
219 | struct subpage *page = subpage; |
---|
220 | |
---|
221 | while(page != NULL) |
---|
222 | { |
---|
223 | if(page->pageid == pageid) break; |
---|
224 | page = page->next; |
---|
225 | } |
---|
226 | |
---|
227 | if(page == NULL) return; |
---|
228 | |
---|
229 | struct subpagereg *pagereg = page->pageregions; |
---|
230 | |
---|
231 | for(; pagereg; pagereg = pagereg->next) |
---|
232 | { |
---|
233 | struct subreg *reg = page->regions; |
---|
234 | while(reg != NULL) |
---|
235 | { |
---|
236 | if(reg->regid == pagereg->regid) break; |
---|
237 | reg = reg->next; |
---|
238 | } |
---|
239 | if(reg != NULL) |
---|
240 | { |
---|
241 | if(reg->committed) continue; |
---|
242 | |
---|
243 | int posx = pagereg->reghorizontaladdress; |
---|
244 | int posy = pagereg->regverticaladdress; |
---|
245 | |
---|
246 | if(posx < 0 || posy < 0) continue; |
---|
247 | |
---|
248 | /* find corresponding clut */ |
---|
249 | struct subclut *clut = page->cluts; |
---|
250 | while(clut != NULL) |
---|
251 | { |
---|
252 | if(clut->clutid == reg->clutid) break; |
---|
253 | clut = clut->next; |
---|
254 | } |
---|
255 | |
---|
256 | if(reg->depth == 1) |
---|
257 | { |
---|
258 | clutsize = 4; |
---|
259 | reg->palette = (struct rgba*)malloc(clutsize * sizeof(struct rgba)); |
---|
260 | } |
---|
261 | if(reg->depth == 2) |
---|
262 | { |
---|
263 | clutsize = 16; |
---|
264 | reg->palette = (struct rgba*)malloc(clutsize * sizeof(struct rgba)); |
---|
265 | } |
---|
266 | if(reg->depth == 3) |
---|
267 | { |
---|
268 | clutsize = 256; |
---|
269 | reg->palette = (struct rgba*)malloc(clutsize * sizeof(struct rgba)); |
---|
270 | } |
---|
271 | |
---|
272 | struct subclutentry *entries = NULL; |
---|
273 | switch(reg->depth) |
---|
274 | { |
---|
275 | case 1: |
---|
276 | { |
---|
277 | if(clut != NULL) |
---|
278 | entries = clut->entries2bit; |
---|
279 | memset(reg->palette, 0, 4 * sizeof(struct rgba)); |
---|
280 | reg->palette[0].a = 0xFF; |
---|
281 | reg->palette[2].r = reg->palette[2].g = reg->palette[2].b = 0xFF; |
---|
282 | reg->palette[3].r = reg->palette[3].g = reg->palette[3].b = 0x80; |
---|
283 | break; |
---|
284 | } |
---|
285 | case 2: |
---|
286 | { |
---|
287 | if(clut != NULL) |
---|
288 | entries = clut->entries4bit; |
---|
289 | memset(reg->palette, 0, 16 * sizeof(struct rgba)); |
---|
290 | for(i = 0; i < 16; ++i) |
---|
291 | { |
---|
292 | if(!i) |
---|
293 | reg->palette[i].a = 0xFF; |
---|
294 | else if(i & 8) |
---|
295 | { |
---|
296 | if(i & 1) reg->palette[i].r = 0x80; |
---|
297 | if(i & 2) reg->palette[i].g = 0x80; |
---|
298 | if(i & 4) reg->palette[i].b = 0x80; |
---|
299 | } |
---|
300 | else |
---|
301 | { |
---|
302 | if(i & 1) reg->palette[i].r = 0xFF; |
---|
303 | if(i & 2) reg->palette[i].g = 0xFF; |
---|
304 | if(i & 4) reg->palette[i].b = 0xFF; |
---|
305 | } |
---|
306 | } |
---|
307 | break; |
---|
308 | } |
---|
309 | case 3: |
---|
310 | { |
---|
311 | if(clut != NULL) |
---|
312 | entries = clut->entries8bit; |
---|
313 | memset(reg->palette, 0, 256 * sizeof(struct rgba)); |
---|
314 | for(i = 0; i < 256; ++i) |
---|
315 | { |
---|
316 | switch(i & 17) |
---|
317 | { |
---|
318 | case 0: |
---|
319 | { |
---|
320 | if(!(i & 14)) |
---|
321 | { |
---|
322 | if(!(i & 224)) |
---|
323 | reg->palette[i].a = 0xFF; |
---|
324 | else |
---|
325 | { |
---|
326 | if(i & 128) reg->palette[i].r = 0xFF; |
---|
327 | if (i & 64) reg->palette[i].g = 0xFF; |
---|
328 | if(i & 32) reg->palette[i].b = 0xFF; |
---|
329 | reg->palette[i].a = 0xBF; |
---|
330 | } |
---|
331 | break; |
---|
332 | } |
---|
333 | } |
---|
334 | case 16: |
---|
335 | { |
---|
336 | if(i & 128) reg->palette[i].r = 0x55; |
---|
337 | if(i & 64) reg->palette[i].g = 0x55; |
---|
338 | if(i & 32) reg->palette[i].b = 0x55; |
---|
339 | if(i & 8) reg->palette[i].r += 0xAA; |
---|
340 | if(i & 4) reg->palette[i].g += 0xAA; |
---|
341 | if(i & 2) reg->palette[i].b += 0xAA; |
---|
342 | if(i & 16) reg->palette[i].a = 0x80; |
---|
343 | break; |
---|
344 | } |
---|
345 | case 1: |
---|
346 | { |
---|
347 | reg->palette[i].r = 0x80; |
---|
348 | reg->palette[i].g = 0x80; |
---|
349 | reg->palette[i].b = 0x80; |
---|
350 | } |
---|
351 | case 17: |
---|
352 | { |
---|
353 | if(i & 128) reg->palette[i].r += 0x2A; |
---|
354 | if(i & 64) reg->palette[i].g += 0x2A; |
---|
355 | if(i & 32) reg->palette[i].b += 0x2A; |
---|
356 | if(i & 8) reg->palette[i].r += 0x55; |
---|
357 | if(i & 4) reg->palette[i].g += 0x55; |
---|
358 | if(i & 2) reg->palette[i].b += 0x55; |
---|
359 | break; |
---|
360 | } |
---|
361 | |
---|
362 | } |
---|
363 | break; |
---|
364 | } |
---|
365 | } |
---|
366 | } |
---|
367 | |
---|
368 | for(i = 0; i < clutsize; ++i) |
---|
369 | { |
---|
370 | if(entries && entries[i].valid) |
---|
371 | { |
---|
372 | int y = entries[i].Y; |
---|
373 | int cr = entries[i].Cr; |
---|
374 | int cb = entries[i].Cb; |
---|
375 | |
---|
376 | if(y > 0) |
---|
377 | { |
---|
378 | y -= 16; |
---|
379 | cr -= 128; |
---|
380 | cb -= 128; |
---|
381 | reg->palette[i].r = OMAX(OMIN(((298 * y + 460 * cr) / 256), 255), 0); |
---|
382 | reg->palette[i].g = OMAX(OMIN(((298 * y - 55 * cb - 137 * cr) / 256), 255), 0); |
---|
383 | reg->palette[i].b = OMAX(OMIN(((298 * y + 543 * cb ) / 256), 255), 0); |
---|
384 | //reg->palette[i].a = (entries[i].T) & 0xFF; |
---|
385 | reg->palette[i].a = 0xFF; |
---|
386 | } |
---|
387 | else |
---|
388 | { |
---|
389 | reg->palette[i].r = 0; |
---|
390 | reg->palette[i].g = 0; |
---|
391 | reg->palette[i].b = 0; |
---|
392 | reg->palette[i].a = 0xFF; |
---|
393 | } |
---|
394 | } |
---|
395 | } |
---|
396 | |
---|
397 | reg->committed = 1; |
---|
398 | } |
---|
399 | } |
---|
400 | page->pagetimeout += time(NULL); |
---|
401 | subdraw(pts, page); |
---|
402 | subfree(0); |
---|
403 | oldsubpage = subpage; |
---|
404 | subpage = NULL; |
---|
405 | } |
---|
406 | |
---|
407 | void subcalcall(unsigned long long pts) |
---|
408 | { |
---|
409 | #if 1 |
---|
410 | struct subpage *page = subpage; |
---|
411 | |
---|
412 | while(page != NULL) |
---|
413 | { |
---|
414 | if(page->state != 0) |
---|
415 | subcalc(page->pageid, pts); |
---|
416 | page = page->next; |
---|
417 | } |
---|
418 | #else |
---|
419 | struct subpage *page = subpage; |
---|
420 | |
---|
421 | debug(300, "end of display set"); |
---|
422 | debug(300, "active pages:"); |
---|
423 | while(page != NULL) |
---|
424 | { |
---|
425 | debug(300, "page_id %02x", page->pageid); |
---|
426 | debug(300, "page_version_number: %d", page->pageversionnumber); |
---|
427 | debug(300, "active regions:"); |
---|
428 | { |
---|
429 | subpagereg *reg = page->pageregions; |
---|
430 | while(reg != NULL) |
---|
431 | { |
---|
432 | debug(300, "region_id: %04x", reg->regid); |
---|
433 | debug(300, "region_horizontal_address: %d", reg->reghorizontaladdress); |
---|
434 | debug(300, "region_vertical_address: %d", reg->regverticaladdress); |
---|
435 | |
---|
436 | reg = reg->next; |
---|
437 | } |
---|
438 | } |
---|
439 | |
---|
440 | subcalc(page->pageid); |
---|
441 | |
---|
442 | debug(300, "defined regions:"); |
---|
443 | struct subregion *reg = page->regions; |
---|
444 | while(reg != NULL) |
---|
445 | { |
---|
446 | debug("region_id %04x, version %d, %dx%d", reg->regid, reg->versionnumber, reg->width, reg->height); |
---|
447 | |
---|
448 | struct subregobj *obj = reg->objects; |
---|
449 | while(object != NULL) |
---|
450 | { |
---|
451 | debug(300, "object %02x, type %d, %d:%d", obj->objid, obj->objtype, obj->objhorizontalpos, obj->objverticalpos); |
---|
452 | obj = obj->next; |
---|
453 | } |
---|
454 | reg = reg->next; |
---|
455 | } |
---|
456 | page = page->next; |
---|
457 | } |
---|
458 | #endif |
---|
459 | } |
---|
460 | |
---|
461 | void bitstreaminit(struct bitstream *bit, const void *buf, int size) |
---|
462 | { |
---|
463 | bit->data = (unsigned char*) buf; |
---|
464 | bit->size = size; |
---|
465 | bit->avail = 8; |
---|
466 | bit->consumed = 0; |
---|
467 | } |
---|
468 | |
---|
469 | int bitstreamget(struct bitstream *bit) |
---|
470 | { |
---|
471 | int val; |
---|
472 | bit->avail -= bit->size; |
---|
473 | val = ((*bit->data) >> bit->avail) & ((1 << bit->size) - 1); |
---|
474 | if(!bit->avail) |
---|
475 | { |
---|
476 | bit->data++; |
---|
477 | bit->consumed++; |
---|
478 | bit->avail = 8; |
---|
479 | } |
---|
480 | return val; |
---|
481 | } |
---|
482 | |
---|
483 | int verifysubpes(unsigned char* pkt) |
---|
484 | { |
---|
485 | int substart, pktlen; |
---|
486 | |
---|
487 | if(pkt == NULL) |
---|
488 | { |
---|
489 | debug(300, "NULL Paket"); |
---|
490 | return 1; |
---|
491 | } |
---|
492 | |
---|
493 | /* Packet header == 0x000001 */ |
---|
494 | if(pkt[0] != 0x00 || pkt[1] != 0x00 || pkt[2] != 0x01) |
---|
495 | { |
---|
496 | debug(300, "Invalid header"); |
---|
497 | return 1; |
---|
498 | } |
---|
499 | |
---|
500 | /* stream_id == private_stream_1 */ |
---|
501 | if(pkt[3] != 0xbd) |
---|
502 | { |
---|
503 | debug(300, "Not a private_stream_1 stream (%x)\n", pkt[3]); |
---|
504 | return 1; |
---|
505 | } |
---|
506 | |
---|
507 | /* data_alignment_indicator == 1 */ |
---|
508 | if((pkt[6] & 0x04) == 0) |
---|
509 | { |
---|
510 | debug(300, "Data alignment indicator == 0"); |
---|
511 | return 1; |
---|
512 | } |
---|
513 | |
---|
514 | /* PTS is present */ |
---|
515 | if((pkt[7] & 0x80) == 0) |
---|
516 | { |
---|
517 | debug(300, "No PTS"); |
---|
518 | return 1; |
---|
519 | } |
---|
520 | |
---|
521 | substart = 9 + pkt[8]; |
---|
522 | pktlen = ((uint16_t)pkt[4] << 8) + pkt[5] + 6; |
---|
523 | |
---|
524 | /* data_identifier == 0x20, subtitle_stream_id == 0x00, |
---|
525 | end_of_PES_data_field_marker == 0xff */ |
---|
526 | if(pkt[substart] != 0x20) |
---|
527 | { |
---|
528 | debug(300, "Data identifier != 0x20"); |
---|
529 | return 1; |
---|
530 | } |
---|
531 | |
---|
532 | if(pkt[substart + 1] != 0x00) |
---|
533 | { |
---|
534 | debug(300, "Subtitle stream ID %x != 0x00\n", pkt[substart + 1]); |
---|
535 | return 1; |
---|
536 | } |
---|
537 | |
---|
538 | if(pkt[pktlen - 1] != 0xff) |
---|
539 | { |
---|
540 | debug(300, "Wrong packet length"); |
---|
541 | return 1; |
---|
542 | } |
---|
543 | |
---|
544 | return 0; |
---|
545 | } |
---|
546 | |
---|
547 | int subgetpts(unsigned long long *pts, unsigned char *pkt) |
---|
548 | { |
---|
549 | pkt += 7; |
---|
550 | int flags = *pkt++; |
---|
551 | |
---|
552 | pkt++; // header length |
---|
553 | |
---|
554 | if(flags & 0x80) /* PTS present? */ |
---|
555 | { |
---|
556 | *pts = ((unsigned long long)(((pkt[0] >> 1) & 7))) << 30; |
---|
557 | *pts |= pkt[1] << 22; |
---|
558 | *pts |= (pkt[2] >> 1) << 15; |
---|
559 | *pts |= pkt[3] << 7; |
---|
560 | *pts |= (pkt[5] >> 1); |
---|
561 | |
---|
562 | return 0; |
---|
563 | } else |
---|
564 | return 1; |
---|
565 | } |
---|
566 | |
---|
567 | void subline(struct subreg *reg, struct subregobj *obj, int line, unsigned char *data, int len) |
---|
568 | { |
---|
569 | int x = obj->objhorizontalpos; |
---|
570 | int y = obj->objverticalpos + line; |
---|
571 | |
---|
572 | if(x + len > reg->width) len = reg->width - x; |
---|
573 | if(len < 0) return; |
---|
574 | if(y >= reg->height) return; |
---|
575 | |
---|
576 | memcpy(reg->buf + reg->width * y + x, data, len); |
---|
577 | } |
---|
578 | |
---|
579 | int subpixeldata(struct subreg *reg, struct subregobj *obj, int *linenr, int *linep, unsigned char *data) |
---|
580 | { |
---|
581 | int datatype = *data++, i = 0; |
---|
582 | static unsigned char line[1920]; |
---|
583 | struct bitstream bit; |
---|
584 | |
---|
585 | bit.size = 0; |
---|
586 | switch(datatype) |
---|
587 | { |
---|
588 | case 0x10: // 2bit pixel data |
---|
589 | { |
---|
590 | bitstreaminit(&bit, data, 2); |
---|
591 | while(1) |
---|
592 | { |
---|
593 | int len = 0, col = 0; |
---|
594 | int code = bitstreamget(&bit); |
---|
595 | |
---|
596 | if(code) |
---|
597 | { |
---|
598 | col = code; |
---|
599 | len = 1; |
---|
600 | } |
---|
601 | else |
---|
602 | { |
---|
603 | code = bitstreamget(&bit); |
---|
604 | if(!code) |
---|
605 | { |
---|
606 | code = bitstreamget(&bit); |
---|
607 | if(code == 1) |
---|
608 | { |
---|
609 | col = 0; |
---|
610 | len = 2; |
---|
611 | } |
---|
612 | else if(code == 2) |
---|
613 | { |
---|
614 | len = bitstreamget(&bit) << 2; |
---|
615 | len |= bitstreamget(&bit); |
---|
616 | len += 12; |
---|
617 | col = bitstreamget(&bit); |
---|
618 | } |
---|
619 | else if(code == 3) |
---|
620 | { |
---|
621 | len = bitstreamget(&bit) << 6; |
---|
622 | len |= bitstreamget(&bit) << 4; |
---|
623 | len |= bitstreamget(&bit) << 2; |
---|
624 | len |= bitstreamget(&bit); |
---|
625 | len += 29; |
---|
626 | col = bitstreamget(&bit); |
---|
627 | } |
---|
628 | else |
---|
629 | break; |
---|
630 | } |
---|
631 | else if(code==1) |
---|
632 | { |
---|
633 | col = 0; |
---|
634 | len = 1; |
---|
635 | } |
---|
636 | else if(code & 2) |
---|
637 | { |
---|
638 | if(code & 1) |
---|
639 | len = 3 + 4 + bitstreamget(&bit); |
---|
640 | else |
---|
641 | len = 3 + bitstreamget(&bit); |
---|
642 | col = bitstreamget(&bit); |
---|
643 | } |
---|
644 | } |
---|
645 | |
---|
646 | uint8_t c = reg->depth == 1 ? map2to4bit[col] : reg->depth == 2 ? map2to8bit[col] : col; |
---|
647 | while(len && ((*linep) < subdisplaywidth)) |
---|
648 | { |
---|
649 | line[(*linep)++] = c; |
---|
650 | len--; |
---|
651 | } |
---|
652 | } |
---|
653 | while(bit.avail != 8) |
---|
654 | bitstreamget(&bit); |
---|
655 | return bit.consumed + 1; |
---|
656 | } |
---|
657 | case 0x11: // 4bit pixel data |
---|
658 | { |
---|
659 | bitstreaminit(&bit, data, 4); |
---|
660 | while(1) |
---|
661 | { |
---|
662 | int len = 0, col = 0; |
---|
663 | int code = bitstreamget(&bit); |
---|
664 | if(code) |
---|
665 | { |
---|
666 | col = code; |
---|
667 | len = 1; |
---|
668 | } |
---|
669 | else |
---|
670 | { |
---|
671 | code = bitstreamget(&bit); |
---|
672 | if(!code) |
---|
673 | break; |
---|
674 | else if(code == 0xC) |
---|
675 | { |
---|
676 | col = 0; |
---|
677 | len = 1; |
---|
678 | } |
---|
679 | else if(code == 0xD) |
---|
680 | { |
---|
681 | col = 0; |
---|
682 | len = 2; |
---|
683 | } |
---|
684 | else if(code < 8) |
---|
685 | { |
---|
686 | col = 0; |
---|
687 | len = (code & 7) + 2; |
---|
688 | } |
---|
689 | else if((code & 0xC) == 0x8) |
---|
690 | { |
---|
691 | col = bitstreamget(&bit); |
---|
692 | len = (code & 3) + 4; |
---|
693 | } |
---|
694 | else if(code == 0xE) |
---|
695 | { |
---|
696 | len = bitstreamget(&bit) + 9; |
---|
697 | col = bitstreamget(&bit); |
---|
698 | } |
---|
699 | else if(code == 0xF) |
---|
700 | { |
---|
701 | len = bitstreamget(&bit) << 4; |
---|
702 | len |= bitstreamget(&bit); |
---|
703 | len += 25; |
---|
704 | col = bitstreamget(&bit); |
---|
705 | } |
---|
706 | } |
---|
707 | uint8_t c = reg->depth == 3 ? map4to8bit[col] : col; |
---|
708 | while(len && ((*linep) < subdisplaywidth)) |
---|
709 | { |
---|
710 | line[(*linep)++] = c; |
---|
711 | len--; |
---|
712 | } |
---|
713 | } |
---|
714 | while(bit.avail != 8) |
---|
715 | bitstreamget(&bit); |
---|
716 | return bit.consumed + 1; |
---|
717 | } |
---|
718 | case 0x12: // 8bit pixel data |
---|
719 | { |
---|
720 | bitstreaminit(&bit, data, 8); |
---|
721 | while(1) |
---|
722 | { |
---|
723 | int len = 0, col = 0; |
---|
724 | int code = bitstreamget(&bit); |
---|
725 | if(code) |
---|
726 | { |
---|
727 | col = code; |
---|
728 | len = 1; |
---|
729 | } |
---|
730 | else |
---|
731 | { |
---|
732 | code = bitstreamget(&bit); |
---|
733 | if((code & 0x80) == 0x80) |
---|
734 | { |
---|
735 | len = code & 0x7F; |
---|
736 | col = bitstreamget(&bit); |
---|
737 | } |
---|
738 | else if(code & 0x7F) |
---|
739 | { |
---|
740 | len = code & 0x7F; |
---|
741 | col = 0; |
---|
742 | } |
---|
743 | else |
---|
744 | break; |
---|
745 | } |
---|
746 | while(len && ((*linep) < subdisplaywidth)) |
---|
747 | { |
---|
748 | line[(*linep)++] = col; |
---|
749 | len--; |
---|
750 | } |
---|
751 | } |
---|
752 | return bit.consumed + 1; |
---|
753 | } |
---|
754 | case 0x20: |
---|
755 | { |
---|
756 | bitstreaminit(&bit, data, 4); |
---|
757 | for(i = 0; i < 4; ++i) |
---|
758 | map2to4bit[i] = bitstreamget(&bit); |
---|
759 | return bit.consumed + 1; |
---|
760 | } |
---|
761 | case 0x21: |
---|
762 | { |
---|
763 | bitstreaminit(&bit, data, 8); |
---|
764 | for(i = 0; i < 4; ++i) |
---|
765 | map2to8bit[i] = bitstreamget(&bit); |
---|
766 | return bit.consumed + 1; |
---|
767 | } |
---|
768 | case 0x22: |
---|
769 | { |
---|
770 | bitstreaminit(&bit, data, 8); |
---|
771 | for(i = 0; i < 16; ++i) |
---|
772 | map4to8bit[i] = bitstreamget(&bit); |
---|
773 | return bit.consumed + 1; |
---|
774 | } |
---|
775 | case 0xF0: |
---|
776 | { |
---|
777 | subline(reg, obj, *linenr, line, *linep); |
---|
778 | (*linenr) += 2; // interlaced |
---|
779 | *linep = 0; |
---|
780 | return 1; |
---|
781 | } |
---|
782 | default: |
---|
783 | { |
---|
784 | debug(300, "subtitle_process_pixel_data: invalid data_type %02x", datatype); |
---|
785 | return -1; |
---|
786 | } |
---|
787 | } |
---|
788 | return 0; |
---|
789 | } |
---|
790 | |
---|
791 | int subsegment(unsigned char *seg, int id1, int id2, unsigned long long pts) |
---|
792 | { |
---|
793 | int segtype, pageid, seglen, proclen; |
---|
794 | |
---|
795 | if(*seg++ != 0x0F) |
---|
796 | { |
---|
797 | debug(300, "segment out of sync"); |
---|
798 | return -1; |
---|
799 | } |
---|
800 | |
---|
801 | segtype = *seg++; |
---|
802 | pageid = *seg++ << 8; |
---|
803 | pageid |= *seg++; |
---|
804 | seglen = *seg++ << 8; |
---|
805 | seglen |= *seg++; |
---|
806 | |
---|
807 | if(segtype == 0xFF) return seglen + 6; |
---|
808 | |
---|
809 | if(pageid != id1 && pageid != id2) |
---|
810 | return seglen + 6; |
---|
811 | |
---|
812 | struct subpage *page = subpage, **ppage = &subpage; |
---|
813 | |
---|
814 | while(page != NULL) |
---|
815 | { |
---|
816 | if(page->pageid == pageid) break; |
---|
817 | page = page->next; |
---|
818 | } |
---|
819 | |
---|
820 | proclen = 0; |
---|
821 | |
---|
822 | switch(segtype) |
---|
823 | { |
---|
824 | case 0x10: // page composition segment |
---|
825 | { |
---|
826 | int pagetimeout = *seg++; proclen++; |
---|
827 | int pageversionnumber = *seg >> 4; |
---|
828 | int pagestate = (*seg >> 2) & 0x3; |
---|
829 | seg++; |
---|
830 | proclen++; |
---|
831 | |
---|
832 | if(page == NULL) |
---|
833 | { |
---|
834 | page = malloc(sizeof(struct subpage)); |
---|
835 | if(page == NULL) |
---|
836 | { |
---|
837 | err("no mem"); |
---|
838 | break; |
---|
839 | } |
---|
840 | memset(page, 0, sizeof(struct subpage)); |
---|
841 | page->pageid = pageid; |
---|
842 | *ppage = page; |
---|
843 | } |
---|
844 | else |
---|
845 | { |
---|
846 | if(page->pcssize != seglen) |
---|
847 | page->pageversionnumber = -1; |
---|
848 | // if no update, just skip this data. |
---|
849 | if(page->pageversionnumber == pageversionnumber) |
---|
850 | break; |
---|
851 | } |
---|
852 | |
---|
853 | page->state = pagestate; |
---|
854 | |
---|
855 | if((pagestate == 1) || (pagestate == 2)) |
---|
856 | { |
---|
857 | while(page->pageregions != NULL) |
---|
858 | { |
---|
859 | struct subpagereg *p = page->pageregions->next; |
---|
860 | free(page->pageregions); |
---|
861 | page->regions = NULL; |
---|
862 | page->pageregions = p; |
---|
863 | } |
---|
864 | while(page->regions) |
---|
865 | { |
---|
866 | struct subreg *p = page->regions->next; |
---|
867 | while(page->regions->objects) |
---|
868 | { |
---|
869 | struct subregobj *obj = page->regions->objects->next; |
---|
870 | free(page->regions->objects); |
---|
871 | page->regions->objects = NULL; |
---|
872 | page->regions->objects = obj; |
---|
873 | } |
---|
874 | free(page->regions); |
---|
875 | page->regions = NULL; |
---|
876 | page->regions = p; |
---|
877 | } |
---|
878 | |
---|
879 | } |
---|
880 | |
---|
881 | page->pagetimeout = pagetimeout; |
---|
882 | page->pageversionnumber = pageversionnumber; |
---|
883 | |
---|
884 | struct subpagereg **reg = &page->pageregions; |
---|
885 | |
---|
886 | while(*reg != NULL) reg = &(*reg)->next; |
---|
887 | |
---|
888 | if(proclen == seglen && !page->pageregions) |
---|
889 | { |
---|
890 | debug(300, "no regions in page.. clear screen!!"); |
---|
891 | //TODO: ?? |
---|
892 | //subcalc(page->pageid); |
---|
893 | } |
---|
894 | |
---|
895 | while(proclen < seglen) |
---|
896 | { |
---|
897 | struct subpagereg *preg; |
---|
898 | |
---|
899 | // append new entry to list |
---|
900 | preg = malloc(sizeof(struct subpagereg)); |
---|
901 | if(preg == NULL) |
---|
902 | { |
---|
903 | err("no mem"); |
---|
904 | proclen += 6; |
---|
905 | continue; |
---|
906 | } |
---|
907 | memset(preg, 0, sizeof(struct subpagereg)); |
---|
908 | *reg = preg; |
---|
909 | reg = &preg->next; |
---|
910 | |
---|
911 | preg->regid = *seg++; proclen++; |
---|
912 | seg++; proclen++; |
---|
913 | |
---|
914 | preg->reghorizontaladdress = *seg++ << 8; |
---|
915 | preg->reghorizontaladdress |= *seg++; |
---|
916 | proclen += 2; |
---|
917 | |
---|
918 | preg->regverticaladdress = *seg++ << 8; |
---|
919 | preg->regverticaladdress |= *seg++; |
---|
920 | proclen += 2; |
---|
921 | } |
---|
922 | |
---|
923 | if(proclen != seglen) |
---|
924 | debug(300, "proclen %d != seglen %d", proclen, seglen); |
---|
925 | break; |
---|
926 | } |
---|
927 | case 0x11: // region composition segment |
---|
928 | { |
---|
929 | int regid = *seg++; proclen++; |
---|
930 | int versionnumber = *seg >> 4; |
---|
931 | int regfillflag = (*seg >> 3) & 1; |
---|
932 | seg++; proclen++; |
---|
933 | |
---|
934 | if(page == NULL) |
---|
935 | { |
---|
936 | debug(300, "ignoring region %x, since page %02x doesn't yet exist.", regid, pageid); |
---|
937 | break; |
---|
938 | } |
---|
939 | |
---|
940 | struct subreg *reg = page->regions, **preg = &page->regions; |
---|
941 | |
---|
942 | while(reg != NULL) |
---|
943 | { |
---|
944 | if(reg->regid == regid) break; |
---|
945 | preg = ®->next; |
---|
946 | reg = reg->next; |
---|
947 | } |
---|
948 | |
---|
949 | if(reg == NULL) |
---|
950 | { |
---|
951 | *preg = reg = malloc(sizeof(struct subreg)); |
---|
952 | if(reg == NULL) |
---|
953 | { |
---|
954 | err("no mem"); |
---|
955 | break; |
---|
956 | } |
---|
957 | memset(reg, 0, sizeof(struct subreg)); |
---|
958 | reg->committed = 0; |
---|
959 | } |
---|
960 | else if(reg->versionnumber != versionnumber) |
---|
961 | { |
---|
962 | struct subregobj *obj = reg->objects; |
---|
963 | while(obj != NULL) |
---|
964 | { |
---|
965 | struct subregobj *n = obj->next; |
---|
966 | free(obj); obj = NULL; |
---|
967 | obj = n; |
---|
968 | } |
---|
969 | free(reg->buf); |
---|
970 | reg->buf = NULL; |
---|
971 | free(reg->palette); |
---|
972 | reg->palette = NULL; |
---|
973 | |
---|
974 | reg->committed = 0; |
---|
975 | } |
---|
976 | else |
---|
977 | break; |
---|
978 | |
---|
979 | reg->regid = regid; |
---|
980 | reg->versionnumber = versionnumber; |
---|
981 | |
---|
982 | reg->width = *seg++ << 8; |
---|
983 | reg->width |= *seg++; |
---|
984 | proclen += 2; |
---|
985 | |
---|
986 | reg->height = *seg++ << 8; |
---|
987 | reg->height |= *seg++; |
---|
988 | proclen += 2; |
---|
989 | |
---|
990 | reg->buf = malloc(reg->width * reg->height); |
---|
991 | if(reg->buf == NULL) |
---|
992 | { |
---|
993 | err("no mem"); |
---|
994 | break; |
---|
995 | } |
---|
996 | memset(reg->buf, 0, reg->width * reg->height); |
---|
997 | |
---|
998 | //int reglevelofcompatibility = (*seg >> 5) & 7; |
---|
999 | |
---|
1000 | reg->depth = (*seg++ >> 2) & 7; |
---|
1001 | proclen++; |
---|
1002 | |
---|
1003 | reg->clutid = *seg++; proclen++; |
---|
1004 | |
---|
1005 | int reg8bitpixel = *seg++; proclen++; |
---|
1006 | int reg4bitpixel = *seg >> 4; |
---|
1007 | int reg2bitpixel = (*seg++ >> 2) & 3; |
---|
1008 | proclen++; |
---|
1009 | |
---|
1010 | if(regfillflag == 0) |
---|
1011 | { |
---|
1012 | reg2bitpixel = reg4bitpixel = reg8bitpixel = 0; |
---|
1013 | regfillflag = 1; |
---|
1014 | } |
---|
1015 | |
---|
1016 | if(regfillflag != 0) |
---|
1017 | { |
---|
1018 | if(reg->depth == 1) |
---|
1019 | memset(reg->buf, reg2bitpixel, reg->height * reg->width); |
---|
1020 | else if(reg->depth == 2) |
---|
1021 | memset(reg->buf, reg4bitpixel, reg->height * reg->width); |
---|
1022 | else if(reg->depth == 3) |
---|
1023 | memset(reg->buf, reg8bitpixel, reg->height * reg->width); |
---|
1024 | else |
---|
1025 | debug(300, "invalid depth"); |
---|
1026 | } |
---|
1027 | |
---|
1028 | reg->objects = 0; |
---|
1029 | struct subregobj **pobj = ®->objects; |
---|
1030 | |
---|
1031 | while(proclen < seglen) |
---|
1032 | { |
---|
1033 | struct subregobj *obj; |
---|
1034 | |
---|
1035 | obj = malloc(sizeof(struct subregobj)); |
---|
1036 | if(obj == NULL) |
---|
1037 | { |
---|
1038 | err("no mem"); |
---|
1039 | proclen += 8; |
---|
1040 | continue; |
---|
1041 | } |
---|
1042 | memset(obj, 0, sizeof(struct subregobj)); |
---|
1043 | |
---|
1044 | *pobj = obj; |
---|
1045 | pobj = &obj->next; |
---|
1046 | |
---|
1047 | obj->objid = *seg++ << 8; |
---|
1048 | obj->objid |= *seg++; proclen += 2; |
---|
1049 | |
---|
1050 | obj->objtype = *seg >> 6; |
---|
1051 | obj->objproviderflag = (*seg >> 4) & 3; |
---|
1052 | obj->objhorizontalpos = (*seg++ & 0xF) << 8; |
---|
1053 | obj->objhorizontalpos |= *seg++; |
---|
1054 | proclen += 2; |
---|
1055 | |
---|
1056 | obj->objverticalpos = *seg++ << 8; |
---|
1057 | obj->objverticalpos |= *seg++ ; |
---|
1058 | proclen += 2; |
---|
1059 | |
---|
1060 | if((obj->objtype == 1) || (obj->objtype == 2)) |
---|
1061 | { |
---|
1062 | obj->foregroundpixel = *seg++; |
---|
1063 | obj->backgroundpixel = *seg++; |
---|
1064 | proclen += 2; |
---|
1065 | } |
---|
1066 | } |
---|
1067 | |
---|
1068 | if(proclen != seglen) |
---|
1069 | debug(300, "too less data! (%d < %d)", seglen, proclen); |
---|
1070 | |
---|
1071 | break; |
---|
1072 | } |
---|
1073 | case 0x12: // CLUT definition segment |
---|
1074 | { |
---|
1075 | int clutid, clutversionnumber; |
---|
1076 | struct subclut *clut, **pclut; |
---|
1077 | |
---|
1078 | if(page == NULL) break; |
---|
1079 | |
---|
1080 | clutid = *seg++; |
---|
1081 | clutversionnumber = *seg++ >> 4; |
---|
1082 | proclen += 2; |
---|
1083 | |
---|
1084 | clut = page->cluts; pclut = &page->cluts; |
---|
1085 | |
---|
1086 | while(clut != NULL) |
---|
1087 | { |
---|
1088 | if(clut->clutid == clutid) break; |
---|
1089 | pclut = &clut->next; |
---|
1090 | clut = clut->next; |
---|
1091 | } |
---|
1092 | |
---|
1093 | if(clut == NULL) |
---|
1094 | { |
---|
1095 | *pclut = clut = malloc(sizeof(struct subclut)); |
---|
1096 | if(clut == NULL) |
---|
1097 | { |
---|
1098 | err("no mem"); |
---|
1099 | break; |
---|
1100 | } |
---|
1101 | memset(clut, 0, sizeof(struct subclut)); |
---|
1102 | clut->clutid = clutid; |
---|
1103 | } |
---|
1104 | else if(clut->clutversionnumber == clutversionnumber) |
---|
1105 | break; |
---|
1106 | |
---|
1107 | clut->clutversionnumber = clutversionnumber; |
---|
1108 | |
---|
1109 | memset(clut->entries2bit, 0, sizeof(clut->entries2bit)); |
---|
1110 | memset(clut->entries4bit, 0, sizeof(clut->entries4bit)); |
---|
1111 | memset(clut->entries8bit, 0, sizeof(clut->entries8bit)); |
---|
1112 | |
---|
1113 | while(proclen < seglen) |
---|
1114 | { |
---|
1115 | int clutentryid, entryclutflag, fullrange; |
---|
1116 | int Y, Cr, Cb, T; |
---|
1117 | |
---|
1118 | clutentryid = *seg++; |
---|
1119 | fullrange = *seg & 1; |
---|
1120 | entryclutflag = (*seg++ & 0xE0) >> 5; |
---|
1121 | proclen += 2; |
---|
1122 | |
---|
1123 | if(fullrange) |
---|
1124 | { |
---|
1125 | Y = *seg++; |
---|
1126 | Cr = *seg++; |
---|
1127 | Cb = *seg++; |
---|
1128 | T = *seg++; |
---|
1129 | proclen += 4; |
---|
1130 | } |
---|
1131 | else |
---|
1132 | { |
---|
1133 | Y = *seg & 0xFC; |
---|
1134 | Cr = (*seg++ & 3) << 6; |
---|
1135 | Cr |= (*seg & 0xC0) >> 2; |
---|
1136 | Cb = (*seg & 0x3C) << 2; |
---|
1137 | T = (*seg++ & 3) << 6; |
---|
1138 | proclen += 2; |
---|
1139 | } |
---|
1140 | |
---|
1141 | if(entryclutflag & 1) // 8bit |
---|
1142 | { |
---|
1143 | clut->entries8bit[clutentryid].Y = Y; |
---|
1144 | clut->entries8bit[clutentryid].Cr = Cr; |
---|
1145 | clut->entries8bit[clutentryid].Cb = Cb; |
---|
1146 | clut->entries8bit[clutentryid].T = T; |
---|
1147 | clut->entries8bit[clutentryid].valid = 1; |
---|
1148 | } |
---|
1149 | if(entryclutflag & 2) // 4bit |
---|
1150 | { |
---|
1151 | if(clutentryid < 16) |
---|
1152 | { |
---|
1153 | clut->entries4bit[clutentryid].Y = Y; |
---|
1154 | clut->entries4bit[clutentryid].Cr = Cr; |
---|
1155 | clut->entries4bit[clutentryid].Cb = Cb; |
---|
1156 | clut->entries4bit[clutentryid].T = T; |
---|
1157 | clut->entries4bit[clutentryid].valid = 1; |
---|
1158 | } |
---|
1159 | else |
---|
1160 | debug(300, "CLUT entry marked as 4 bit with id %d (>15)", clutentryid); |
---|
1161 | } |
---|
1162 | if(entryclutflag & 4) // 2bit |
---|
1163 | { |
---|
1164 | if(clutentryid < 4) |
---|
1165 | { |
---|
1166 | clut->entries2bit[clutentryid].Y = Y; |
---|
1167 | clut->entries2bit[clutentryid].Cr = Cr; |
---|
1168 | clut->entries2bit[clutentryid].Cb = Cb; |
---|
1169 | clut->entries2bit[clutentryid].T = T; |
---|
1170 | clut->entries2bit[clutentryid].valid = 1; |
---|
1171 | } |
---|
1172 | else |
---|
1173 | debug(300, "CLUT entry marked as 2 bit with id %d (>3)", clutentryid); |
---|
1174 | } |
---|
1175 | } |
---|
1176 | break; |
---|
1177 | } |
---|
1178 | case 0x13: // object data segment |
---|
1179 | { |
---|
1180 | int objid, objversionnumber, objcodingmethod, nonmodifyingcolorflag; |
---|
1181 | |
---|
1182 | if(page == NULL) |
---|
1183 | { |
---|
1184 | debug(300, "no page for object data found"); |
---|
1185 | break; |
---|
1186 | } |
---|
1187 | |
---|
1188 | objid = *seg++ << 8; |
---|
1189 | objid |= *seg++; |
---|
1190 | proclen += 2; |
---|
1191 | |
---|
1192 | objversionnumber = *seg >> 4; |
---|
1193 | objcodingmethod = (*seg >> 2) & 3; |
---|
1194 | nonmodifyingcolorflag = (*seg++ >> 1) & 1; |
---|
1195 | proclen++; |
---|
1196 | |
---|
1197 | struct subreg *reg = page->regions; |
---|
1198 | while(reg != NULL) |
---|
1199 | { |
---|
1200 | struct subregobj *obj = reg->objects; |
---|
1201 | while(obj != NULL) |
---|
1202 | { |
---|
1203 | if(obj->objid == objid) |
---|
1204 | { |
---|
1205 | if(objcodingmethod == 0) |
---|
1206 | { |
---|
1207 | int topfielddatablocklen, bottomfielddatablocklen; |
---|
1208 | int i = 1, line, linep; |
---|
1209 | |
---|
1210 | topfielddatablocklen = *seg++ << 8; |
---|
1211 | topfielddatablocklen |= *seg++; |
---|
1212 | bottomfielddatablocklen = *seg++ << 8; |
---|
1213 | bottomfielddatablocklen |= *seg++; |
---|
1214 | proclen += 4; |
---|
1215 | |
---|
1216 | map2to4bit[0] = 0; |
---|
1217 | map2to4bit[1] = 8; |
---|
1218 | map2to4bit[2] = 7; |
---|
1219 | map2to4bit[3] = 15; |
---|
1220 | |
---|
1221 | // this map is realy untested... |
---|
1222 | map2to8bit[0] = 0; |
---|
1223 | map2to8bit[1] = 0x88; |
---|
1224 | map2to8bit[2] = 0x77; |
---|
1225 | map2to8bit[3] = 0xff; |
---|
1226 | |
---|
1227 | map4to8bit[0] = 0; |
---|
1228 | for(; i < 16; ++i) |
---|
1229 | map4to8bit[i] = i * 0x11; |
---|
1230 | |
---|
1231 | i = 0; line = 0; linep = 0; |
---|
1232 | while(i < topfielddatablocklen) |
---|
1233 | { |
---|
1234 | int len; |
---|
1235 | len = subpixeldata(reg, obj, &line, &linep, seg); |
---|
1236 | if(len < 0) return -1; |
---|
1237 | seg += len; |
---|
1238 | proclen += len; |
---|
1239 | i += len; |
---|
1240 | } |
---|
1241 | |
---|
1242 | line = 1; linep = 0; |
---|
1243 | if(bottomfielddatablocklen) |
---|
1244 | { |
---|
1245 | i = 0; |
---|
1246 | while(i < bottomfielddatablocklen) |
---|
1247 | { |
---|
1248 | int len; |
---|
1249 | len = subpixeldata(reg, obj, &line, &linep, seg); |
---|
1250 | if(len < 0) return -1; |
---|
1251 | seg += len; |
---|
1252 | proclen += len; |
---|
1253 | i += len; |
---|
1254 | } |
---|
1255 | } |
---|
1256 | else if(topfielddatablocklen) |
---|
1257 | debug(300, "unimplemented: no bottom field! (%d : %d)", topfielddatablocklen, bottomfielddatablocklen); |
---|
1258 | |
---|
1259 | if((topfielddatablocklen + bottomfielddatablocklen) & 1) |
---|
1260 | { |
---|
1261 | seg++; proclen++; |
---|
1262 | } |
---|
1263 | } |
---|
1264 | else if(objcodingmethod == 1) |
---|
1265 | debug(300, "object_coding_method 1 unsupported!"); |
---|
1266 | } |
---|
1267 | obj = obj->next; |
---|
1268 | } |
---|
1269 | reg = reg->next; |
---|
1270 | } |
---|
1271 | break; |
---|
1272 | } |
---|
1273 | case 0x14: // display definition segment |
---|
1274 | { |
---|
1275 | if(seglen > 4) |
---|
1276 | { |
---|
1277 | //int ddsversionnumber = seg[0] >> 4; |
---|
1278 | int displaywindowflag = (seg[0] >> 3) & 1; |
---|
1279 | int displaywidth = (seg[1] << 8) | (seg[2]); |
---|
1280 | int displayheight = (seg[3] << 8) | (seg[4]); |
---|
1281 | |
---|
1282 | proclen += 5; |
---|
1283 | subdisplaywidth = displaywidth + 1; |
---|
1284 | subdisplayheight = displayheight +1; |
---|
1285 | |
---|
1286 | if(displaywindowflag) |
---|
1287 | { |
---|
1288 | if(seglen > 12) |
---|
1289 | { |
---|
1290 | //int displaywindowhorizontalposmin = (seg[4] << 8) | seg[5]; |
---|
1291 | //int displaywindowhorizontalposmax = (seg[6] << 8) | seg[7]; |
---|
1292 | //int displaywindowverticalposmin = (seg[8] << 8) | seg[9]; |
---|
1293 | //int displaywindowverticalposmax = (seg[10] << 8) | seg[11]; |
---|
1294 | proclen += 8; |
---|
1295 | } |
---|
1296 | else |
---|
1297 | debug(300, "display window flag set but display definition segment to short %d!", seglen); |
---|
1298 | } |
---|
1299 | } |
---|
1300 | else |
---|
1301 | debug(300, "display definition segment to short %d!", seglen); |
---|
1302 | break; |
---|
1303 | } |
---|
1304 | case 0x80: // end of display set segment |
---|
1305 | { |
---|
1306 | subcalcall(pts); |
---|
1307 | } |
---|
1308 | case 0xFF: // stuffing |
---|
1309 | break; |
---|
1310 | default: |
---|
1311 | debug(300, "unhandled segment type %02x", segtype); |
---|
1312 | } |
---|
1313 | |
---|
1314 | return seglen + 6; |
---|
1315 | } |
---|
1316 | |
---|
1317 | void subpes(unsigned char *pkt, int len, int id1, int id2) |
---|
1318 | { |
---|
1319 | int ret = 0; |
---|
1320 | unsigned long long pts = 0; |
---|
1321 | |
---|
1322 | ret = verifysubpes(pkt); |
---|
1323 | if(ret != 0) return; |
---|
1324 | |
---|
1325 | ret = subgetpts(&pts, pkt); |
---|
1326 | if(ret == 0) |
---|
1327 | { |
---|
1328 | pkt += 6; len -= 6; |
---|
1329 | // skip PES header |
---|
1330 | pkt++; len--; |
---|
1331 | pkt++; len--; |
---|
1332 | |
---|
1333 | int hdrlen = *pkt++; len--; |
---|
1334 | pkt += hdrlen; len -= hdrlen; |
---|
1335 | |
---|
1336 | pkt++; len--; // data identifier |
---|
1337 | pkt++; len--; // stream id; |
---|
1338 | |
---|
1339 | if(len <= 0) return; |
---|
1340 | |
---|
1341 | while(len && *pkt == 0x0F) |
---|
1342 | { |
---|
1343 | int l = subsegment(pkt, id1, id2, pts); |
---|
1344 | if(l < 0) break; |
---|
1345 | pkt += l; |
---|
1346 | len -= l; |
---|
1347 | } |
---|
1348 | |
---|
1349 | if(len && *pkt != 0xFF) debug(300, "strange data at the end"); |
---|
1350 | |
---|
1351 | subcalcall(pts); |
---|
1352 | } |
---|
1353 | } |
---|
1354 | |
---|
1355 | void* subthreadfunc(void *param) |
---|
1356 | { |
---|
1357 | struct dvbdev* dmxsubnode = NULL; |
---|
1358 | int count = 0, len = 0, packlen = 0; |
---|
1359 | unsigned char* buf = NULL; |
---|
1360 | |
---|
1361 | struct subtitle* subnode = (struct subtitle*)param; |
---|
1362 | |
---|
1363 | if(subnode == NULL || subnode->pid < 1) |
---|
1364 | { |
---|
1365 | err("NULL detect"); |
---|
1366 | pthread_exit(NULL); |
---|
1367 | } |
---|
1368 | |
---|
1369 | dmxsubnode = dmxopen(status.aktservice->fedev); |
---|
1370 | if(dmxsubnode == NULL) |
---|
1371 | { |
---|
1372 | err("no demux dev"); |
---|
1373 | pthread_exit(NULL); |
---|
1374 | } |
---|
1375 | dmxsetbuffersize(dmxsubnode, 128 * 1024); |
---|
1376 | if(status.aktservice->fedev != NULL) |
---|
1377 | dmxsetsource(dmxsubnode, status.aktservice->fedev->fedmxsource); |
---|
1378 | else |
---|
1379 | err("NULL detect"); |
---|
1380 | dmxsetpesfilter(dmxsubnode, subnode->pid, -1, DMX_OUT_TAP, DMX_PES_OTHER, 0); |
---|
1381 | |
---|
1382 | #ifdef SIMULATE |
---|
1383 | int fd = open("simulate/dvbsubtitle.ts", O_RDONLY); |
---|
1384 | if(fd == -1) |
---|
1385 | { |
---|
1386 | perr("open simulate/dvbsubtitle.ts"); |
---|
1387 | pthread_exit(NULL); |
---|
1388 | } |
---|
1389 | #endif |
---|
1390 | |
---|
1391 | buf = malloc(16); |
---|
1392 | if(buf == NULL) |
---|
1393 | { |
---|
1394 | err("no mem"); |
---|
1395 | pthread_exit(NULL); |
---|
1396 | } |
---|
1397 | |
---|
1398 | status.aktservice->dmxsubtitledev = dmxsubnode; |
---|
1399 | |
---|
1400 | debug(300, "start subtitle thread"); |
---|
1401 | status.subthreadstatus = ACTIVE; |
---|
1402 | while(status.subthreadaktion != STOP) |
---|
1403 | { |
---|
1404 | if(status.subthreadaktion == PAUSE) |
---|
1405 | { |
---|
1406 | status.subthreadstatus = INPAUSE; |
---|
1407 | usleep(100000); |
---|
1408 | continue; |
---|
1409 | } |
---|
1410 | status.subthreadstatus = ACTIVE; |
---|
1411 | count = 0; |
---|
1412 | while(status.subthreadaktion != STOP && status.subthreadaktion != PAUSE) |
---|
1413 | { |
---|
1414 | debug(300, "sync subtitle"); |
---|
1415 | #ifdef SIMULATE |
---|
1416 | len = TEMP_FAILURE_RETRY(read(fd, &buf[count], 3 - count)); |
---|
1417 | #else |
---|
1418 | len = dvbread(dmxsubnode, &buf[count], 0, 3 - count, 100 * 1000); |
---|
1419 | #endif |
---|
1420 | subclear(1); |
---|
1421 | if(len < 0) continue; |
---|
1422 | if(len == 3 - count) |
---|
1423 | { |
---|
1424 | if(buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) |
---|
1425 | { |
---|
1426 | count = 3; |
---|
1427 | break; |
---|
1428 | } |
---|
1429 | buf[0] = buf[1]; |
---|
1430 | buf[1] = buf[2]; |
---|
1431 | count = 2; |
---|
1432 | continue; |
---|
1433 | } |
---|
1434 | count = count + len; |
---|
1435 | } |
---|
1436 | |
---|
1437 | while(status.subthreadaktion != STOP && status.subthreadaktion != PAUSE && count < 6) |
---|
1438 | { |
---|
1439 | #ifdef SIMULATE |
---|
1440 | len = TEMP_FAILURE_RETRY(read(fd, &buf[count], 6 - count)); |
---|
1441 | #else |
---|
1442 | len = dvbread(dmxsubnode, &buf[count], 0, 6 - count, 100 * 1000); |
---|
1443 | #endif |
---|
1444 | subclear(1); |
---|
1445 | if(len < 0) continue; |
---|
1446 | count = count + len; |
---|
1447 | } |
---|
1448 | debug(300, "subtitle read peslen len=%d", len); |
---|
1449 | |
---|
1450 | packlen = (((uint16_t)buf[4] << 8) | buf[5]) + 6; |
---|
1451 | buf = realloc(buf, packlen); |
---|
1452 | |
---|
1453 | while(status.subthreadaktion != STOP && status.subthreadaktion != PAUSE && count < packlen) |
---|
1454 | { |
---|
1455 | #ifdef SIMULATE |
---|
1456 | len = TEMP_FAILURE_RETRY(read(fd, &buf[count], packlen - count)); |
---|
1457 | #else |
---|
1458 | len = dvbread(dmxsubnode, &buf[count], 0, packlen - count, 100 * 1000); |
---|
1459 | #endif |
---|
1460 | subclear(1); |
---|
1461 | if(len <= 0) continue; |
---|
1462 | count = count + len; |
---|
1463 | |
---|
1464 | if(count == packlen) |
---|
1465 | { |
---|
1466 | debug(300, "decode subtile len=%d", count); |
---|
1467 | subpes(buf, count, subnode->id1, subnode->id2); |
---|
1468 | } |
---|
1469 | } |
---|
1470 | } |
---|
1471 | |
---|
1472 | debug(300, "end subtitle thread"); |
---|
1473 | |
---|
1474 | dmxclose(status.aktservice->dmxsubtitledev, -1); |
---|
1475 | status.aktservice->dmxsubtitledev = NULL; |
---|
1476 | |
---|
1477 | free(buf); |
---|
1478 | |
---|
1479 | #ifdef SIMULATE |
---|
1480 | close(fd); |
---|
1481 | #endif |
---|
1482 | |
---|
1483 | status.subthreadstatus = DEACTIVE; |
---|
1484 | subfree(0); |
---|
1485 | subfree(1); |
---|
1486 | |
---|
1487 | pthread_exit(NULL); |
---|
1488 | } |
---|
1489 | |
---|
1490 | int subtitlestart(struct subtitle* node) |
---|
1491 | { |
---|
1492 | int ret; |
---|
1493 | |
---|
1494 | if(status.subthreadstatus != DEACTIVE) |
---|
1495 | { |
---|
1496 | err("subtitle thread in use"); |
---|
1497 | return 1; |
---|
1498 | } |
---|
1499 | |
---|
1500 | status.subthreadaktion = START; |
---|
1501 | pthread_attr_destroy(&status.subthreadattr); |
---|
1502 | pthread_attr_init(&status.subthreadattr); |
---|
1503 | pthread_attr_setstacksize(&status.subthreadattr, 50000); |
---|
1504 | pthread_attr_setdetachstate(&status.subthreadattr, PTHREAD_CREATE_JOINABLE); |
---|
1505 | ret = pthread_create(&status.subthread, &status.subthreadattr, subthreadfunc, node); |
---|
1506 | if(ret) |
---|
1507 | { |
---|
1508 | err("create subtitle thread"); |
---|
1509 | return 1; |
---|
1510 | } |
---|
1511 | |
---|
1512 | return 0; |
---|
1513 | } |
---|
1514 | |
---|
1515 | int subtitlepause(int flag) |
---|
1516 | { |
---|
1517 | int i = 0; |
---|
1518 | |
---|
1519 | if(flag == 0) |
---|
1520 | { |
---|
1521 | if(status.subthreadstatus == INPAUSE) |
---|
1522 | status.subthreadaktion = START; |
---|
1523 | } |
---|
1524 | else if(status.subthreadstatus == ACTIVE) |
---|
1525 | { |
---|
1526 | status.subthreadaktion = PAUSE; |
---|
1527 | while(status.subthreadstatus != INPAUSE) |
---|
1528 | { |
---|
1529 | usleep(100000); |
---|
1530 | i++; if(i > 20) break; |
---|
1531 | } |
---|
1532 | if(i > 20) |
---|
1533 | err("detect hanging subthread"); |
---|
1534 | subclear(0); |
---|
1535 | } |
---|
1536 | |
---|
1537 | return 0; |
---|
1538 | } |
---|
1539 | |
---|
1540 | int subtitlestop(int flag) |
---|
1541 | { |
---|
1542 | void* threadstatus; |
---|
1543 | int i = 0; |
---|
1544 | |
---|
1545 | status.subthreadaktion = STOP; |
---|
1546 | while(status.subthreadstatus != DEACTIVE) |
---|
1547 | { |
---|
1548 | usleep(100000); |
---|
1549 | i++; if(i > 20) break; |
---|
1550 | } |
---|
1551 | subclear(0); |
---|
1552 | |
---|
1553 | if(i > 20) |
---|
1554 | { |
---|
1555 | err("detect hanging subthread"); |
---|
1556 | } |
---|
1557 | else if(status.subthread != 0) |
---|
1558 | pthread_join(status.subthread, &threadstatus); |
---|
1559 | |
---|
1560 | status.subthread = 0; |
---|
1561 | pthread_attr_destroy(&status.subthreadattr); |
---|
1562 | if(flag == 0) |
---|
1563 | { |
---|
1564 | status.subthreadpid = 0; |
---|
1565 | status.subthreadid2 = 0; |
---|
1566 | } |
---|
1567 | |
---|
1568 | return 0; |
---|
1569 | } |
---|
1570 | |
---|
1571 | struct subtitle* checksubtitle(struct channel* chnode, struct subtitle* strack) |
---|
1572 | { |
---|
1573 | struct subtitle* node = NULL; |
---|
1574 | |
---|
1575 | if(chnode != NULL) |
---|
1576 | { |
---|
1577 | node = chnode->subtitle; |
---|
1578 | while(node != NULL) |
---|
1579 | { |
---|
1580 | if(node == strack) |
---|
1581 | return node; |
---|
1582 | node = node->next; |
---|
1583 | } |
---|
1584 | } |
---|
1585 | return NULL; |
---|
1586 | } |
---|
1587 | |
---|
1588 | void screensubtitle() |
---|
1589 | { |
---|
1590 | int rcret = 0, treffer = 0; |
---|
1591 | struct skin* subtitle = getscreen("subtitle"); |
---|
1592 | struct skin* listbox = getscreennode(subtitle, "listbox"); |
---|
1593 | struct skin* tmp = NULL; |
---|
1594 | struct subtitle* node = NULL; |
---|
1595 | struct lastsubtitle* lsnode = NULL; |
---|
1596 | |
---|
1597 | listbox->aktline = 1; |
---|
1598 | listbox->aktpage = -1; |
---|
1599 | |
---|
1600 | if(status.aktservice->channel != NULL) |
---|
1601 | { |
---|
1602 | m_lock(&status.subtitlemutex, 8); |
---|
1603 | node = status.aktservice->channel->subtitle; |
---|
1604 | while(node != NULL) |
---|
1605 | { |
---|
1606 | tmp = addlistbox(subtitle, listbox, tmp, 1); |
---|
1607 | if(tmp != NULL) |
---|
1608 | { |
---|
1609 | changetext(tmp, _(node->name)); |
---|
1610 | tmp->type = CHOICEBOX; |
---|
1611 | tmp->del = 1; |
---|
1612 | tmp->handle = (char*)node; |
---|
1613 | |
---|
1614 | if(node->pid == status.subthreadpid) |
---|
1615 | { |
---|
1616 | if(node->subtype == 2 || (node->subtype == 1 && node->id2 == status.subthreadid2)) |
---|
1617 | changeinput(tmp, _("running")); |
---|
1618 | treffer = 1; |
---|
1619 | } |
---|
1620 | else |
---|
1621 | changeinput(tmp, ""); |
---|
1622 | |
---|
1623 | if(treffer == 0) listbox->aktline++; |
---|
1624 | } |
---|
1625 | node = node->next; |
---|
1626 | } |
---|
1627 | m_unlock(&status.subtitlemutex, 8); |
---|
1628 | } |
---|
1629 | |
---|
1630 | if(treffer == 0) listbox->aktline = 1; |
---|
1631 | |
---|
1632 | drawscreen(subtitle, 0, 0); |
---|
1633 | addscreenrc(subtitle, listbox); |
---|
1634 | |
---|
1635 | while(1) |
---|
1636 | { |
---|
1637 | rcret = waitrc(subtitle, 0, 0); |
---|
1638 | |
---|
1639 | if(rcret == getrcconfigint("rcexit", NULL)) break; |
---|
1640 | if(rcret == getrcconfigint("rcok", NULL)) |
---|
1641 | { |
---|
1642 | if(listbox->select != NULL && listbox->select->handle != NULL) |
---|
1643 | { |
---|
1644 | subtitlestop(1); |
---|
1645 | m_lock(&status.subtitlemutex, 8); |
---|
1646 | |
---|
1647 | if(status.autosubtitle == 1 && status.aktservice->channel != NULL) |
---|
1648 | { |
---|
1649 | lsnode = getlastsubtitle(status.aktservice->channel->transponderid, status.aktservice->channel->serviceid); |
---|
1650 | dellastsubtitle(lsnode); |
---|
1651 | lsnode = NULL; |
---|
1652 | } |
---|
1653 | |
---|
1654 | if(checksubtitle(status.aktservice->channel, (struct subtitle*)listbox->select->handle) != NULL) |
---|
1655 | { |
---|
1656 | if(((struct subtitle*)listbox->select->handle)->pid != status.subthreadpid || ((struct subtitle*)listbox->select->handle)->id2 != status.subthreadid2) |
---|
1657 | { |
---|
1658 | clearscreen(subtitle); |
---|
1659 | drawscreen(skin, 0, 0); |
---|
1660 | if(subtitlestart((struct subtitle*)listbox->select->handle) == 0) |
---|
1661 | { |
---|
1662 | status.subthreadpid = ((struct subtitle*)listbox->select->handle)->pid; |
---|
1663 | status.subthreadid2 = ((struct subtitle*)listbox->select->handle)->id2; |
---|
1664 | } |
---|
1665 | |
---|
1666 | if(status.autosubtitle == 1 && status.aktservice->channel != NULL) |
---|
1667 | { |
---|
1668 | lsnode = getlastsubtitle(status.aktservice->channel->transponderid, status.aktservice->channel->serviceid); |
---|
1669 | if(lsnode == NULL) |
---|
1670 | { |
---|
1671 | char* tmpstr = NULL; |
---|
1672 | tmpstr = ostrcat(ollutoa(status.aktservice->channel->transponderid), "#", 1, 0); |
---|
1673 | tmpstr = ostrcat(tmpstr, oitoa(status.aktservice->channel->serviceid), 1, 1); |
---|
1674 | tmpstr = ostrcat(tmpstr, "#", 1, 0); |
---|
1675 | tmpstr = ostrcat(tmpstr, oitoa(((struct subtitle*)listbox->select->handle)->pid), 1, 1); |
---|
1676 | tmpstr = ostrcat(tmpstr, "#", 1, 0); |
---|
1677 | tmpstr = ostrcat(tmpstr, oitoa(((struct subtitle*)listbox->select->handle)->id2), 1, 1); |
---|
1678 | addlastsubtitle(tmpstr, 1, NULL); |
---|
1679 | free(tmpstr); tmpstr = NULL; |
---|
1680 | } |
---|
1681 | else |
---|
1682 | changelastsubtitle(lsnode, ((struct subtitle*)listbox->select->handle)->pid, ((struct subtitle*)listbox->select->handle)->id2); |
---|
1683 | } |
---|
1684 | |
---|
1685 | } |
---|
1686 | else |
---|
1687 | { |
---|
1688 | status.subthreadpid = 0; |
---|
1689 | status.subthreadid2 = 0; |
---|
1690 | } |
---|
1691 | } |
---|
1692 | else |
---|
1693 | { |
---|
1694 | status.subthreadpid = 0; |
---|
1695 | status.subthreadid2 = 0; |
---|
1696 | } |
---|
1697 | m_unlock(&status.subtitlemutex, 8); |
---|
1698 | } |
---|
1699 | break; |
---|
1700 | } |
---|
1701 | } |
---|
1702 | |
---|
1703 | delmarkedscreennodes(subtitle, 1); |
---|
1704 | delownerrc(subtitle); |
---|
1705 | clearscreen(subtitle); |
---|
1706 | } |
---|
1707 | |
---|
1708 | struct subtitle* addsubtitle(struct channel* chnode, int subtype, char* langdesc, int pid, int type, int id1, int id2, struct subtitle* last) |
---|
1709 | { |
---|
1710 | struct subtitle *newnode = NULL, *prev = NULL, *node = NULL; |
---|
1711 | char *tmpstr = NULL, *tmpnr = NULL; |
---|
1712 | |
---|
1713 | if(chnode == NULL) |
---|
1714 | { |
---|
1715 | err("NULL detect"); |
---|
1716 | return NULL; |
---|
1717 | } |
---|
1718 | |
---|
1719 | newnode = (struct subtitle*)malloc(sizeof(struct subtitle)); |
---|
1720 | if(newnode == NULL) |
---|
1721 | { |
---|
1722 | err("no memory"); |
---|
1723 | return NULL; |
---|
1724 | } |
---|
1725 | |
---|
1726 | memset(newnode, 0, sizeof(struct subtitle)); |
---|
1727 | |
---|
1728 | newnode->subtype = subtype; |
---|
1729 | newnode->pid = pid; |
---|
1730 | newnode->type = type; |
---|
1731 | newnode->id1 = id1; |
---|
1732 | newnode->id2 = id2; |
---|
1733 | |
---|
1734 | if(ostrcmp(langdesc, "und") == 0) |
---|
1735 | tmpstr = ostrcat(tmpstr, _("undefined"), 1, 0); |
---|
1736 | else |
---|
1737 | tmpstr = ostrcat(tmpstr, _(langdesc), 1, 0); |
---|
1738 | if(subtype == 1) |
---|
1739 | { |
---|
1740 | tmpstr = ostrcat(tmpstr, " (", 1, 0); |
---|
1741 | tmpstr = ostrcat(tmpstr, "TXT Subtitle", 1, 0); |
---|
1742 | tmpstr = ostrcat(tmpstr, " - ", 1, 0); |
---|
1743 | tmpnr = oitoa(id2); |
---|
1744 | tmpstr = ostrcat(tmpstr, tmpnr, 1, 1); |
---|
1745 | tmpstr = ostrcat(tmpstr, ")", 1, 0); |
---|
1746 | } |
---|
1747 | if(subtype == 2) |
---|
1748 | { |
---|
1749 | tmpstr = ostrcat(tmpstr, " (", 1, 0); |
---|
1750 | tmpstr = ostrcat(tmpstr, "DVB Subtitle", 1, 0); |
---|
1751 | tmpstr = ostrcat(tmpstr, ")", 1, 0); |
---|
1752 | } |
---|
1753 | newnode->name = tmpstr; |
---|
1754 | |
---|
1755 | m_lock(&status.subtitlemutex, 8); |
---|
1756 | node = chnode->subtitle; |
---|
1757 | if(last == NULL) |
---|
1758 | { |
---|
1759 | while(node != NULL) |
---|
1760 | { |
---|
1761 | prev = node; |
---|
1762 | node = node->next; |
---|
1763 | } |
---|
1764 | } |
---|
1765 | else |
---|
1766 | { |
---|
1767 | prev = last; |
---|
1768 | node = last->next; |
---|
1769 | } |
---|
1770 | |
---|
1771 | if(prev == NULL) |
---|
1772 | chnode->subtitle = newnode; |
---|
1773 | else |
---|
1774 | prev->next = newnode; |
---|
1775 | |
---|
1776 | newnode->next = node; |
---|
1777 | |
---|
1778 | m_unlock(&status.subtitlemutex, 8); |
---|
1779 | return newnode; |
---|
1780 | } |
---|
1781 | |
---|
1782 | void freesubtitle(struct channel* chnode) |
---|
1783 | { |
---|
1784 | struct subtitle *node = NULL, *prev = NULL; |
---|
1785 | |
---|
1786 | if(chnode == NULL) |
---|
1787 | { |
---|
1788 | err("NULL detect"); |
---|
1789 | return; |
---|
1790 | } |
---|
1791 | |
---|
1792 | m_lock(&status.subtitlemutex, 8); |
---|
1793 | node = chnode->subtitle; |
---|
1794 | prev = chnode->subtitle; |
---|
1795 | |
---|
1796 | while(node != NULL) |
---|
1797 | { |
---|
1798 | prev = node; |
---|
1799 | node = node->next; |
---|
1800 | chnode->subtitle = node; |
---|
1801 | |
---|
1802 | free(prev->name); |
---|
1803 | prev->name = NULL; |
---|
1804 | |
---|
1805 | free(prev); |
---|
1806 | prev = NULL; |
---|
1807 | |
---|
1808 | } |
---|
1809 | m_unlock(&status.subtitlemutex, 8); |
---|
1810 | } |
---|
1811 | |
---|
1812 | int subtitlestartlast() |
---|
1813 | { |
---|
1814 | int ret = 1; |
---|
1815 | struct subtitle* node = NULL; |
---|
1816 | struct lastsubtitle* lsnode = NULL; |
---|
1817 | |
---|
1818 | if(status.aktservice->channel != NULL) |
---|
1819 | { |
---|
1820 | m_lock(&status.subtitlemutex, 8); |
---|
1821 | node = status.aktservice->channel->subtitle; |
---|
1822 | lsnode = getlastsubtitle(status.aktservice->channel->transponderid, status.aktservice->channel->serviceid); |
---|
1823 | |
---|
1824 | if(lsnode != NULL) |
---|
1825 | { |
---|
1826 | while(node != NULL) |
---|
1827 | { |
---|
1828 | if(node->pid == lsnode->subtitlepid && node->id2 == lsnode->subtitleid2) |
---|
1829 | break; |
---|
1830 | node = node->next; |
---|
1831 | } |
---|
1832 | |
---|
1833 | if(node != NULL) |
---|
1834 | { |
---|
1835 | if(subtitlestart(node) == 0) |
---|
1836 | { |
---|
1837 | status.subthreadaktion = PAUSE; |
---|
1838 | status.subthreadpid = node->pid; |
---|
1839 | status.subthreadid2 = node->id2; |
---|
1840 | ret = 0; |
---|
1841 | } |
---|
1842 | } |
---|
1843 | } |
---|
1844 | m_unlock(&status.subtitlemutex, 8); |
---|
1845 | } |
---|
1846 | return ret; |
---|
1847 | } |
---|
1848 | |
---|
1849 | void changelastsubtitle(struct lastsubtitle* lsnode, int pid, int id2) |
---|
1850 | { |
---|
1851 | if(lsnode == NULL) return; |
---|
1852 | |
---|
1853 | if(lsnode->subtitlepid != pid || lsnode->subtitleid2 != id2) |
---|
1854 | { |
---|
1855 | lsnode->subtitlepid = pid; |
---|
1856 | lsnode->subtitleid2 = id2; |
---|
1857 | status.writelastsubtitle = 1; |
---|
1858 | } |
---|
1859 | } |
---|
1860 | |
---|
1861 | struct lastsubtitle* getlastsubtitle(uint64_t transponderid, int serviceid) |
---|
1862 | { |
---|
1863 | struct lastsubtitle *node = lastsubtitle; |
---|
1864 | |
---|
1865 | while(node != NULL) |
---|
1866 | { |
---|
1867 | if(node->transponderid == transponderid && node->serviceid == serviceid) |
---|
1868 | break; |
---|
1869 | node = node->next; |
---|
1870 | } |
---|
1871 | |
---|
1872 | return node; |
---|
1873 | } |
---|
1874 | |
---|
1875 | struct lastsubtitle* addlastsubtitle(char* line, int count, struct lastsubtitle* last) |
---|
1876 | { |
---|
1877 | struct lastsubtitle *newnode = NULL, *prev = NULL, *node = lastsubtitle; |
---|
1878 | int ret = 0; |
---|
1879 | |
---|
1880 | if(line == NULL) return NULL; |
---|
1881 | |
---|
1882 | newnode = (struct lastsubtitle*)calloc(1, sizeof(struct lastsubtitle)); |
---|
1883 | if(newnode == NULL) |
---|
1884 | { |
---|
1885 | err("no memory"); |
---|
1886 | return NULL; |
---|
1887 | } |
---|
1888 | |
---|
1889 | ret = sscanf(line, "%llu#%d#%"SCNu16"#%"SCNu16"", &newnode->transponderid, &newnode->serviceid, &newnode->subtitlepid, &newnode->subtitleid2); |
---|
1890 | if(ret != 4) |
---|
1891 | { |
---|
1892 | if(count > 0) |
---|
1893 | { |
---|
1894 | err("lastsubtitle line %d not ok", count); |
---|
1895 | } |
---|
1896 | else |
---|
1897 | { |
---|
1898 | err("add lastsubtitle"); |
---|
1899 | } |
---|
1900 | free(newnode); |
---|
1901 | return NULL; |
---|
1902 | } |
---|
1903 | |
---|
1904 | status.writelastsubtitle = 1; |
---|
1905 | |
---|
1906 | if(last == NULL) |
---|
1907 | { |
---|
1908 | while(node != NULL) |
---|
1909 | { |
---|
1910 | prev = node; |
---|
1911 | node = node->next; |
---|
1912 | } |
---|
1913 | } |
---|
1914 | else |
---|
1915 | { |
---|
1916 | prev = last; |
---|
1917 | node = last->next; |
---|
1918 | } |
---|
1919 | |
---|
1920 | if(prev == NULL) |
---|
1921 | lastsubtitle = newnode; |
---|
1922 | else |
---|
1923 | prev->next = newnode; |
---|
1924 | newnode->next = node; |
---|
1925 | |
---|
1926 | return newnode; |
---|
1927 | } |
---|
1928 | |
---|
1929 | int readlastsubtitle(const char* filename) |
---|
1930 | { |
---|
1931 | FILE *fd = NULL; |
---|
1932 | char *fileline = NULL; |
---|
1933 | int linecount = 0, len = 0; |
---|
1934 | struct lastsubtitle* last = NULL, *tmplast = NULL; |
---|
1935 | |
---|
1936 | fileline = malloc(MINMALLOC); |
---|
1937 | if(fileline == NULL) |
---|
1938 | { |
---|
1939 | err("no memory"); |
---|
1940 | return 1; |
---|
1941 | } |
---|
1942 | |
---|
1943 | fd = fopen(filename, "r"); |
---|
1944 | if(fd == NULL) |
---|
1945 | { |
---|
1946 | perr("can't open %s", filename); |
---|
1947 | free(fileline); |
---|
1948 | return 1; |
---|
1949 | } |
---|
1950 | |
---|
1951 | while(fgets(fileline, MINMALLOC, fd) != NULL) |
---|
1952 | { |
---|
1953 | if(fileline[0] == '#' || fileline[0] == '\n') |
---|
1954 | continue; |
---|
1955 | len = strlen(fileline) - 1; |
---|
1956 | if(len >= 0 && fileline[len] == '\n') |
---|
1957 | fileline[len] = '\0'; |
---|
1958 | len--; |
---|
1959 | if(len >= 0 && fileline[len] == '\r') |
---|
1960 | fileline[len] = '\0'; |
---|
1961 | |
---|
1962 | linecount++; |
---|
1963 | |
---|
1964 | if(last == NULL) last = tmplast; |
---|
1965 | last = addlastsubtitle(fileline, linecount, last); |
---|
1966 | if(last != NULL) tmplast = last; |
---|
1967 | } |
---|
1968 | |
---|
1969 | status.writelastsubtitle = 0; |
---|
1970 | free(fileline); |
---|
1971 | fclose(fd); |
---|
1972 | return 0; |
---|
1973 | } |
---|
1974 | |
---|
1975 | void dellastsubtitle(struct lastsubtitle* lsnode) |
---|
1976 | { |
---|
1977 | struct lastsubtitle *node = lastsubtitle, *prev = lastsubtitle; |
---|
1978 | |
---|
1979 | while(node != NULL) |
---|
1980 | { |
---|
1981 | if(node == lsnode) |
---|
1982 | { |
---|
1983 | status.writelastsubtitle = 1; |
---|
1984 | if(node == lastsubtitle) |
---|
1985 | lastsubtitle = node->next; |
---|
1986 | else |
---|
1987 | prev->next = node->next; |
---|
1988 | |
---|
1989 | free(node); |
---|
1990 | node = NULL; |
---|
1991 | break; |
---|
1992 | } |
---|
1993 | |
---|
1994 | prev = node; |
---|
1995 | node = node->next; |
---|
1996 | } |
---|
1997 | } |
---|
1998 | |
---|
1999 | void freelastsubtitle() |
---|
2000 | { |
---|
2001 | struct lastsubtitle *node = lastsubtitle, *prev = lastsubtitle; |
---|
2002 | |
---|
2003 | while(node != NULL) |
---|
2004 | { |
---|
2005 | prev = node; |
---|
2006 | node = node->next; |
---|
2007 | if(prev != NULL) |
---|
2008 | dellastsubtitle(prev); |
---|
2009 | } |
---|
2010 | } |
---|
2011 | |
---|
2012 | int writelastsubtitle(const char *filename) |
---|
2013 | { |
---|
2014 | FILE *fd = NULL; |
---|
2015 | struct lastsubtitle *node = lastsubtitle; |
---|
2016 | int ret = 0; |
---|
2017 | |
---|
2018 | fd = fopen(filename, "w"); |
---|
2019 | if(fd == NULL) |
---|
2020 | { |
---|
2021 | perr("can't open %s", filename); |
---|
2022 | return 1; |
---|
2023 | } |
---|
2024 | |
---|
2025 | while(node != NULL) |
---|
2026 | { |
---|
2027 | ret = fprintf(fd, "%llu#%d#%d#%d\n", node->transponderid, node->serviceid, node->subtitlepid, node->subtitleid2); |
---|
2028 | if(ret < 0) |
---|
2029 | { |
---|
2030 | perr("writting file %s", filename); |
---|
2031 | } |
---|
2032 | node = node->next; |
---|
2033 | } |
---|
2034 | |
---|
2035 | fclose(fd); |
---|
2036 | return 0; |
---|
2037 | } |
---|
2038 | |
---|
2039 | #endif |
---|