1 #include "../libzmpeg3.h"
22 font_size = fsz_normal;
23 video->reset_subtitles();
24 int sid = video->subtitle_track+1;
25 if( sid <= 0 || sid > MX_SVC ) sid = 1;
30 get_atsc_data(zbits_t *s)
32 /* xfer data to data[0], first byte = total size */
33 /* <dat[1]=isz,dat[2..isz+1]=input, ...,0> */
34 int b = s->get_bits(8) & 0x1f;
36 uint8_t *dat = &data[0][0];
40 //zmsgs(" len=%d\n",len);
41 s->get_bits(8); /* rsvd */
43 for( int i=0; i<len; ++i ) {
44 int typ = s->get_bits(8);
45 if( (typ & 0xf8) != 0xf8 ) return;
46 int valid = typ & 0x04;
47 int ch1 = s->get_bits(8);
48 int ch2 = s->get_bits(8);
49 //zmsgs("*** typ %02x %02x %02x\n",typ,ch1,ch2);
51 switch( typ &= 0x03 ) {
52 case 0x02: /* dvb_data */
53 if( isz == 0 ) continue; /* missed start */
55 case 0x03: /* dvb_start */
56 if( isz > 0 ) { *bp = isz; bp = cp++; }
58 case 0x00: /* ntsc_f1 */
59 case 0x01: /* ntsc_f2 */
62 if( !valid ) continue;
63 if( cp-dat+2 > 128 ) {
64 zerr("closed caption data ovfl\n");
70 /* terminate last recd */
71 if( (*bp = cp-bp - 1) > 0 ) *cp++ = 0;
72 /* dat[0] = total size */
74 //zmsgs("***** size %d\n",dat[0]);
75 if( s->get_bits(8) == 0xff ) decode();
82 //zmsgs("seq %d, isz=%d, pict_type %c, pict_struct %3.3s %d\n",
83 // data[0][1]>>6,isz," IPBD"[video->pict_type],
84 // &" TOP BTM FRM "[4*video->pict_struct],video->framenum);
85 switch( video->pict_type ) {
88 switch( video->pict_struct ) {
90 if( (frs_history & (frs_tf1 | frs_frm)) ) {
92 frs_history &= ~(frs_tf1 | frs_frm);
94 memcpy(&data[1],&data[0],isz);
95 frs_history |= frs_tf1;
97 case pics_BOTTOM_FIELD:
98 if( (frs_history & frs_frm) ) {
100 frs_history &= ~frs_frm;
102 else if( (frs_history & frs_bf2) ) {
104 frs_history &= ~frs_bf2;
106 memcpy(&data[2],&data[1],isz);
107 frs_history |= frs_bf2;
109 case pics_FRAME_PICTURE:
110 if( (frs_history & (frs_tf1 | frs_frm)) ) {
112 frs_history &= ~(frs_tf1 | frs_frm);
114 if( frs_history & frs_bf2 ) {
116 frs_history &= ~frs_bf2;
118 memcpy(&data[1],&data[0],isz);
119 frs_history = frs_frm;
124 if( frs_history == frs_tf1 || frs_history == frs_bf2 )
129 frs_history |= frs_prc;
137 if( !(frs_history & frs_prc) )
139 frs_history &= ~frs_prc;
147 uint8_t *dat = &data[k][1];
148 while( (isz = *dat++) > 0 ) {
151 int sz = 2 * (b & 0x03f);
154 zmsgs("cc decode seq %d size %d/%d -",seq,isz,sz);
156 for( int i=0; i<n; ++i ) printf(" %02x",dat[i]);
158 for( int i=0; i<n; ++i ) printf(" %c",dat[i]>=0x20&&dat[i]<0x7f?dat[i]:'.');
161 if( sz > isz ) return;
162 uint8_t *ep = sz + bp++;
166 int svc_nr = b >> 5, blksz = b & 0x1f;
167 if( svc_nr == 0x07 ) {
168 if( bp >= ep ) break;
170 if( svc_nr < 7 || svc_nr > 63 ) break;
172 if( svc_nr == svc.id() && bp+blksz <= ep )
173 svc.append(bp,blksz);
197 reset(int sid, zcc_t *cc)
199 //zmsgs(" svc %d\n",sid);
203 if( ctrk < 0 ) ctrk = MX_SVC-1;
206 for( int sid=0; sid<MX_WIN; ++sid )
207 win[sid].reset(sid, this);
208 for( chr_t *bfr; (bfr=get_bfr()); ) delete [] bfr;
209 // win[0].default_window();
218 if( bfr ) bfrs = *(chr_t **)bfr;
226 *(chr_t **)bfr = bfrs;
232 append(uint8_t *bp, int len)
235 if( n > isizeof(data) ) n = isizeof(data);
236 for( int i=size; i<n; data[i++]=*bp++);
243 if( size == 0 ) return;
244 bp = data; ep = bp+size; size = 0;
245 //zmsgs(" size=%d,sid=%d\n",(int)(ep-bp),sid);
248 if( (b&0x7f) >= 0x20 ) { // group G0/G1 ascii/latin chars
249 if( curw && curw->st > st_unmap ) curw->store(b);
252 if( b < 0x10 || b >= 0x80 ) { // group C0/C1
253 if( command(b) ) break;
256 if( b == 0x10 ) { // ETX1 escape C2/C3, G2/G3
257 if( bp >= ep ) break;
258 b = *bp++; // no valid codes, just skip rsvd bytes
259 if( b < 0x08 ) continue; // 0x00-0x07 C2
260 if( b < 0x10 ) { bp += 1; continue; } // 0x08-0x0f C2
261 if( b < 0x18 ) { bp += 2; continue; } // 0x10-0x17 C2
262 if( b < 0x20 ) { bp += 3; continue; } // 0x18-0x1f C2
263 if( b < 0x80 ) continue; /* misc */ // 0x20-0x7f G2
264 if( b < 0x88 ) { bp += 4; continue; } // 0x80-0x87 C3
265 if( b < 0x90 ) { bp += 5; continue; } // 0x88-0x8f C3
268 int bb = b & 0x07; // one byte >ETX1 0x11-0x17
269 if( bp >= ep ) break;
270 bb = (bb << 8) | *bp++;
271 if( b >= 0x18 ) { // two byte >=P16 0x18-0x20
272 if( bp >= ep ) break;
273 bb = (bb << 8) | *bp++;
275 if( curw && curw->st > st_unmap ) curw->store(bb);
283 /* render dirty windows */
284 for( int iw=0; iw<MX_WIN; ++iw ) {
285 win_t *wp = &win[iw];
297 if( cmd == 0x00 || cmd == 0x03 || // nuisance
298 cmd == 0x8d || cmd == 0x8e ) return 0;
299 #define CMD(fn,args...) return fn(args)
300 //zmsgs("cmd %02x svc %d ",cmd,sid);
301 //#define CMD(fn,args...) printf("%s\n",#fn); return fn(args)
303 case 0x03: CMD(ETX); /* End of text, render */
304 case 0x08: CMD(BS); /* Backspace */
305 case 0x0C: CMD(FF); /* Form Feed */
306 case 0x0D: CMD(CR); /* Carriage Return */
307 case 0x0E: CMD(HCR); /* Horizontal Carriage Return */
309 CMD(CWx,cmd & 0x07); /* SetCurrentWindow */
310 case 0x88: CMD(CLW); /* ClearWindows */
311 case 0x89: CMD(DSW); /* DisplayWindows */
312 case 0x8A: CMD(HDW); /* HideWindows */
313 case 0x8B: CMD(TGW); /* ToggleWindows */
314 case 0x8C: CMD(DLW); /* DeleteWindows */
315 case 0x8D: CMD(DLY); /* Delay */
316 case 0x8E: CMD(DLC); /* Delay Cancel */
317 case 0x8F: CMD(RST); /* Reset */
318 case 0x90: CMD(SPA); /* SetPenAttributes */
319 case 0x91: CMD(SPC); /* SetPenColor */
320 case 0x92: CMD(SPL); /* SetPenLocation */
322 CMD(RSVD); /* reserved */
323 case 0x97: CMD(SWA); /* SetWindowAttributes */
325 CMD(DFx,cmd & 0x07); /* DFx DefineWindow */
327 zerrs("unkn %02x\n",cmd);
331 static inline int RGB2Y(int r,int g,int b)
333 return ( 257*r+504*g+ 98*b+ 16500)/1000;
336 static inline int RGB2Cr(int r,int g,int b)
338 return ( 439*r-368*g- 71*b+128500)/1000;
341 static inline int RGB2Cb(int r,int g,int b)
343 return (-148*r-291*g+439*b+128500)/1000;
347 pen_yuva(int color, int opacity)
349 int r, g, b, y, u, v, a;
350 r = ((color>>4) & 0x03) * 255 / 3;
351 g = ((color>>2) & 0x03) * 255 / 3;
352 b = ((color>>0) & 0x03) * 255 / 3;
355 case oty_transparent: a = 0; break;
356 case oty_translucent: a = 128; break;
357 case oty_flash: a = 208; break;
358 case oty_solid: a = 255; break;
363 return (y<<24) | (u<<16) | (v<<8) | (a<<0);
366 static inline int put_utf8(unsigned int v, uint8_t *cp, int n)
369 int l = v < 0x0800 ? 2 : v < 0x00010000 ? 3 :
370 v < 0x00200000 ? 4 : v < 0x04000000 ? 5 : 6;
371 if( l > n ) return -1;
372 int m = 0xff00 >> l, i = l;
373 *cp++ = (v>>(6*--i)) | m;
374 for( ; --i>=0; ++cp ) *cp = ((v>>(6*i)) & 0x3f) | 0x80;
377 if( n < 1 ) return -1;
400 if( st < st_visible ) return;
401 end_frame = svc->cc->video->framenum;
402 if( !svc->cc->text_cb ) return;
405 uint8_t *cp = (uint8_t *)txt, *ep = cp + sizeof(txt)-1;
406 for( int iy=0; iy<ch; ++iy ) {
407 if( iy && cp < ep ) *cp++ = '|';
408 chr_t *bp = &bfr[iy * MX_CX];
409 for( int ix=0; ix<cw && cp<ep; ++ix,++bp ) {
410 if( !bp->glyph ) continue;
411 int n = put_utf8(bp->glyph, cp, ep-cp);
417 svc->cc->text_cb(svc->sid, id, start_frame, end_frame, txt);
418 start_frame = end_frame;
424 if( this->st == st ) return;
425 //zmsgs("win %d was %d, now %d %s\n", id, this->st, st,
426 // st==st_unmap ? "unmapped" : st==st_hidden ? "hidden" :
427 // st==st_visible ? "visible" : "err");
429 if( this->st < st_visible && st >= st_visible )
430 start_frame = svc->cc->video->framenum;
436 reset(int i, zsvc_t *svc)
440 //zmsgs("win %d\n",id);
442 cx = cy = cw = ch = 0;
453 return b == ' ' || b == '-' || b == '\r';
461 chr_t line[MX_CX]; int ix = cx-1;
462 chr_t *cp = &line[ix], *sp = cp;
464 chr_t *bp = &bfr[cy*MX_CX + ix];
465 if( is_breakable(bp->glyph) ) break;
466 *cp-- = *bp; bp->glyph = 0; --ix;
469 for( ; cx<cw && cp<sp; ++cx )
470 bfr[cy*MX_CX + cx] = *++cp;
475 chr_t line[MX_CX]; int ix = cx+1;
476 chr_t *cp = &line[ix], *sp = cp;
478 chr_t *bp = &bfr[cy*MX_CX + ix];
479 if( is_breakable(bp->glyph) ) break;
480 *cp++ = *bp; bp->glyph = 0; ++ix;
483 for( ; cx>=0 && cp>sp; --cx )
484 bfr[cy*MX_CX + cx] = *--cp;
489 chr_t line[MX_CY]; int iy = cy-1;
490 chr_t *cp = &line[iy], *sp = cp;
492 chr_t *bp = &bfr[iy*MX_CX + cx];
493 if( is_breakable(bp->glyph) ) break;
494 *cp-- = *bp; bp->glyph = 0; --iy;
497 for( ; cy<ch && cp<sp; ++cy )
498 bfr[cy*MX_CX + cx] = *++cp;
503 chr_t line[MX_CY]; int iy = cy+1;
504 chr_t *cp = &line[iy], *sp = cp;
506 chr_t *bp = &bfr[iy*MX_CX + cx];
507 if( is_breakable(bp->glyph) ) break;
508 *cp++ = *bp; bp->glyph = 0; ++iy;
511 for( ; cy>=0 && cp>sp; --cy )
512 bfr[cy*MX_CX + cx] = *--cp;
523 if( !col_lock && !resize(cx+1, ch) ) return 0;
524 if( !row_lock ) return 1;
525 if( wordwrap ) return wrap();
532 //zmsgs("%02x ** \"%c\" at %d,%d win %d\n",
533 // b, b>=0x20 && b<0x7f ? b : '.',cx,cy,id);
536 case dir_rt: if( cx >= cw && ovfl() ) return 1; break;
537 case dir_lt: if( cx < 0 && ovfl() ) return 1; break;
538 case dir_dn: if( cy >= ch && ovfl() ) return 1; break;
539 case dir_up: if( cy < 0 && ovfl() ) return 1; break;
541 if( cx >= 0 && cx < cw && cy >= 0 && cy < ch ) {
542 chr_t *chr = &bfr[cy*MX_CX + cx];
544 chr->fg_opacity = fg_opacity;
545 chr->fg_color = fg_color;
546 chr->bg_opacity = bg_opacity;
547 chr->bg_color = bg_color;
548 chr->pen_size = pen_size;
549 chr->edge_color = edge_color;
550 chr->italics = italics;
551 chr->edge_type = edge_type;
552 chr->underline = underline;
553 chr->font_style = font_style;
554 chr->font_size = svc->cc->font_size;
555 chr->offset = offset;
556 chr->text_tag = text_tag;
560 case dir_rt: ++cx; break;
561 case dir_lt: --cx; break;
562 case dir_dn: ++cy; break;
563 case dir_up: --cy; break;
569 ETX() /* end of text */
571 //zmsgs("svc %d,win %d\n",sid, curw ? curw->id : -1);
572 // if( curw ) curw->render();
580 case dir_rt: if( cx > 0 ) --cx; break;
581 case dir_lt: if( cx < cw-1 ) ++cx; break;
582 case dir_dn: if( cy > 0 ) --cy; break;
583 case dir_up: if( cy < ch-1 ) ++cy; break;
591 if( !curw || curw->st == st_unmap ) return 0;
592 //zmsgs("svc %d,win %d\n",sid,curw->id);
599 int n = cw*sizeof(*bfr);
600 for( int iy=0; iy<ch; ++iy )
601 memset(&bfr[iy*MX_CX],0,n);
610 if( !curw || curw->st == st_unmap ) return 0;
611 //zmsgs("svc %d,win %d\n",sid,curw->id);
616 CR() /* Carriage Return */
618 int n = (cw-1)*sizeof(*bfr);
619 int m = cw*sizeof(*bfr);
624 if( cx > 0 ) { --cx; break; }
625 for( int i=0; i<ch; ++i ) {
626 memmove(&bfr[i*MX_CX+1],&bfr[i*MX_CX],n);
627 memset(&bfr[i*MX_CX],0,sizeof(*bfr));
634 if( cx+1 < cw ) { ++cx; break; }
635 for( int i=0; i<ch; ++i ) {
636 memmove(&bfr[i*MX_CX],&bfr[i*MX_CX+1],n);
637 memset(&bfr[i*MX_CX+cw-1],0,sizeof(*bfr));
644 if( cy > 0 ) { --cy; break; }
645 for( int i=ch; --i>0; )
646 memmove(&bfr[i*MX_CX],&bfr[(i-1)*MX_CX],m);
653 if( cy+1 < ch ) { ++cy; break; }
654 for( int i=1; i<ch; ++i )
655 memmove(&bfr[(i-1)*MX_CX],&bfr[i*MX_CX],m);
656 memset(&bfr[(ch-1)*MX_CX],0,m);
669 CR() /* Carriage Return */
671 if( !curw || curw->st == st_unmap ) return 0;
672 //zmsgs("svc %d,win %d\n",sid,curw->id);
677 HCR() /* Horizontal Carriage Return */
682 memset(&bfr[cy*MX_CX],0,cw*sizeof(*bfr));
683 cy = pdir == dir_rt ? 0 : cw-1;
688 for( int i=0; i<ch; ++i ) memset(&bfr[i*MX_CX+cx],0,sizeof(*bfr));
689 cx = pdir == dir_dn ? 0 : ch-1;
697 HCR() /* Horizontal Carriage Return */
699 if( !curw || curw->st == st_unmap ) return 0;
700 //zmsgs("svc %d,win %d\n",sid,curw->id);
705 CLW() /* ClearWindows */
707 if( bp >= ep ) return 1;
708 int map = *bp++; // 1
709 //zmsgs("map %02x svc %d\n",map,sid);
710 for( int iw=0; iw<MX_WIN; ++iw ) {
711 if( !(map & (1<<iw)) ) continue;
712 win_t *wp = &win[iw];
713 if( wp->st > st_unmap ) {
715 //zmsgs(" clear win %d\n",wp->id);
716 int n = wp->cw*sizeof(*wp->bfr);
717 for( int iy=0; iy<wp->ch; ++iy )
718 memset(&wp->bfr[iy*MX_CX],0,n);
726 DSW() /* DisplayWindows */
728 if( bp >= ep ) return 1;
729 int map = *bp++; // 1
730 //zmsgs("map %02x svc %d\n",map,sid);
731 for( int iw=0; iw<MX_WIN; ++iw ) {
732 if( !(map & (1<<iw)) ) continue;
733 win_t *wp = &win[iw];
734 if( wp->st > st_unmap ) {
735 wp->set_state(st_visible);
742 HDW() /* HideWindows */
744 if( bp >= ep ) return 1;
745 int map = *bp++; // 1
746 //zmsgs("map %02x svc %d\n",map,sid);
747 for( int iw=0; iw<MX_WIN; ++iw ) {
748 if( !(map & (1<<iw)) ) continue;
749 win_t *wp = &win[iw];
750 if( wp->st > st_unmap ) {
751 wp->set_state(st_hidden);
758 TGW() /* ToggleWindows */
760 if( bp >= ep ) return 1;
761 int map = *bp++; // 1
762 //zmsgs("map %02x svc %d\n",map,sid);
763 for( int iw=0; iw<MX_WIN; ++iw ) {
764 if( !(map & (1<<iw)) ) continue;
765 win_t *wp = &win[iw];
766 if( wp->st > st_unmap ) {
767 int8_t st = wp->st == st_visible ? st_hidden : st_visible;
775 DLW() /* DeleteWindows */
777 if( bp >= ep ) return 1;
778 int map = *bp++; // 1
779 //zmsgs("map %02x svc %d\n",map,sid);
780 for( int iw=0; iw<MX_WIN; ++iw ) {
781 if( !(map & (1<<iw)) ) continue;
782 win_t *wp = &win[iw];
783 if( wp->st == st_unmap ) continue;
784 //zmsgs(" delete %d\n",wp->id);
785 wp->set_state(st_unmap);
786 if( wp == curw ) curw = 0;
795 if( bp >= ep ) return 1;
796 //zmsgs(" svc %d (%d)\n",sid, *bp);
802 DLC() /* delay cancel */
811 //zmsgs("svc %d\n",sid);
817 SPA() /* SetPenAttributes */
819 if( bp+2 > ep ) return 1;
822 int offset = (b>>2) & 0x03;
823 int pen_size = b & 0x03;
826 int underline = (b>>6) & 0x01;
827 int edge_type = (b>>3) & 0x07;
828 int font_style = b & 0x07;
829 if( pen_size >= 3 ) return 0;
830 if( offset >= 3 ) return 0;
831 if( edge_type >= 6 ) return 0;
833 if( wp && wp->st > st_unmap ) {
834 wp->text_tag = text_tag;
836 wp->pen_size = pen_size;
837 wp->italics = italics;
838 wp->underline = underline;
839 wp->edge_type = edge_type;
840 wp->font_style = font_style;
841 //zmsgs("txttag=%d,offset=%d,pen_size=%d,ital=%d,undl=%d,"
842 // "edge=%d,ftstyl=%d,win %d,svc %d\n",text_tag,offset,
843 // pen_size,italics,underline,edge_type,font_style,wp->id,sid);
849 SPC() /* SetPenColor */
851 if( bp+3 > ep ) return 1;
853 int fg_opacity = b >> 6;
854 int fg_color = b & 0x3f;
856 int bg_opacity = b >> 6;
857 int bg_color = b & 0x3f;
861 if( wp && wp->st > st_unmap ) {
862 wp->fg_opacity = fg_opacity;
863 wp->fg_color = fg_color;
864 wp->edge_color = edge_color;
865 wp->bg_opacity = bg_opacity;
866 wp->bg_color = bg_color;
867 wp->fg_yuva = pen_yuva(fg_color,fg_opacity);
868 wp->edge_yuva = pen_yuva(edge_color,fg_opacity);
869 wp->bg_yuva = pen_yuva(bg_color,bg_opacity);
870 //zmsgs("fgopc=%d,fgclr=%02x,bgopc=%d,bgclr=%02x,egclr=%02x,"
871 // "win %d,svc %d\n",fg_opacity,fg_color,bg_opacity,bg_color,
872 // edge_color,wp->id,sid);
878 SPL() /* SetPenLocation */
880 if( bp+2 > ep ) return 1;
885 if( row >= MX_CY ) return 0;
886 if( column >= MX_CX ) return 0;
888 if( wp && wp->st > st_unmap ) {
889 if( column >= wp->cw || row >= wp->ch ) return 1;
890 wp->cx = column; wp->cy = row;
891 //zmsgs("row=%d,col=%d,win %d,svc %d\n",row,column,wp->id,sid);
897 RSVD() /* reserved */
899 //zmsgs("sid %d\n",sid);
904 SWA() /* SetWindowAttributes */
906 if( bp+4 > ep ) return 1;
908 int fill_opacity = b>>6;
909 int fill_color = b & 0x3f;
911 int border_color = b & 0x3f;
912 int border_type = b>>6;
914 int wordwrap = (b>>6) & 0x01;
915 border_type |= (b>>5) & 0x04;
916 int print_direction = (b>>4) & 0x03;
917 int scroll_direction = (b>>2) & 0x03;
918 int justify = b & 0x03;
920 int effect_speed = b>>4;
921 int effect_direction = (b>>2) & 0x3;
922 int display_effect = b & 0x03;
923 if( border_type >= 6 ) return 0;
924 if( display_effect >= 3 ) return 0;
927 if( wp && wp->st > st_unmap ) {
928 wp->fill_opacity = fill_opacity;
929 wp->fill_color = fill_color;
930 wp->border_color = border_color;
931 wp->fill_yuva = pen_yuva(fill_color,fill_opacity);
932 wp->border_yuva = pen_yuva(border_color,fill_opacity);
933 wp->wordwrap = wordwrap;
934 wp->pdir = print_direction;
935 wp->sdir = scroll_direction;
936 wp->justify = justify;
937 wp->effect_speed = effect_speed;
938 wp->effect_direction = effect_direction;
939 wp->display_effect = display_effect;
941 //zmsgs("fopc=%d,fclr=%02x,bclr=%02x,wrap=%d,pdir=%d,sdir=%d,just=%d"
942 // "espd=%d,edir=%d,deft=%d,win %d,svc %d\n",fill_opacity,fill_color,
943 // border_color,wordwrap,print_direction,scroll_direction,justify,
944 // effect_speed,effect_direction,display_effect,wp->id,sid);
950 CWx(int id) /* SetCurrentWindow */
952 win_t *wp = &win[id];
953 curw = wp->st == st_unmap ? 0 : wp;
954 //zmsgs("== win %d,svc %d\n",wp->id,sid);
959 DFz(int id) /* DFx DefineWindow */
961 if( bp+6 > ep ) return 1;
962 win_t *wp = &win[id];
964 int visible = (b>>5) & 0x01;
965 int row_lock = (b>>4) & 0x01;
966 int col_lock = (b>>3) & 0x01;
967 int priority = b & 0x07;
969 int anchor_relative = (b>>7) & 0x01;
970 int anchor_vertical = b & 0x7f;
972 int anchor_horizontal = b;
974 int anchor_point = b>>4;
975 int ch = (b & 0x0f) + 1;
979 int window_style = (b>>3) & 0x07;
980 int pen_style = b & 0x07;
981 //zmsgs("%dx%d vis=%d,rowlk=%d,collk=%d,pri=%d,an_rel=%d,\n"
982 // "an_hor=%d,an_vert=%d,an_pnt=%d,wsty=%d,psty=%d,win %d,svc %d\n",
983 // cw,ch,visible,row_lock,col_lock,priority,anchor_relative,
984 // anchor_horizontal,anchor_vertical,anchor_point,window_style,
985 // pen_style,wp->id,sid);
986 if( anchor_relative ) {
987 if( anchor_vertical >= 75 ) return -1;
988 if( anchor_horizontal >= 210 ) return -1;
991 if( anchor_vertical >= 100 ) return -1;
992 if( anchor_horizontal >= 100 ) return -1;
994 if( anchor_point >= 9 ) return -1;
995 if( cw > MX_CX ) return -1;
996 if( ch > MX_CY ) return -1;
998 wp->row_lock = row_lock;
999 wp->col_lock = col_lock;
1000 wp->priority = priority;
1001 wp->anchor_relative = anchor_relative;
1002 wp->anchor_vertical = anchor_vertical;
1003 wp->anchor_horizontal = anchor_horizontal;
1004 wp->anchor_point = anchor_point;
1005 if( wp->st == st_unmap )
1006 wp->set_window_style(window_style);
1007 if( wp->st == st_unmap )
1008 wp->set_pen_style(pen_style);
1009 int bw = wp->border_type != edg_none ? bdr_width : 0;
1010 wp->bw = (bw+3) & ~4; // yuv 422 macro pixels
1011 if( wp->st == st_unmap )
1015 wp->set_state(visible ? st_visible : st_hidden);
1018 int scale = cc->video->coded_picture_height/360;
1019 if( scale < 1 ) scale = 1;
1025 DFx(int id) /* DFx DefineWindow wrapper */
1029 zmsgs("failed to validate cc win %d\n",id);
1036 init(int ncw, int nch)
1038 //zmsgs(" init %d, %dx%d\n", id, ncw, nch);
1039 if( ncw > MX_CX ) return 1;
1040 if( nch > MX_CY ) return 1;
1041 bfr = svc->get_bfr();
1043 bfr = new chr_t[MX_CX*MX_CY];
1045 int n = cw*sizeof(*bfr);
1046 for( int iy=0; iy<ch; ++iy )
1047 memset(&bfr[iy*MX_CX],0,n);
1055 resize(int ncw, int nch)
1057 //zmsgs(" resize %d, %dx%d %s\n", id, ncw, nch, cw!=ncw || ch!=nch ? "*" : "");
1058 if( ncw > MX_CX ) return 1;
1059 if( nch > MX_CY ) return 1;
1060 int dx = ncw-cw, dy = nch-ch;
1061 if( !dx && !dy ) return 0;
1062 int n = cw*sizeof(*bfr);
1065 if( dx > 0 ) { // scroll right, expanding
1066 int m = dx*sizeof(*bfr);
1067 for( int iy=0; iy<ch; ++iy ) {
1068 chr_t *bp = &bfr[iy*MX_CX], *cp = bp+dx;
1076 if( dx < 0 ) { // scroll left, contracting
1077 for( int iy=0; iy<ch; ++iy ) {
1078 chr_t *bp = &bfr[iy*MX_CX], *cp = bp-dx;
1085 if( dy > 0 ) { // scroll down, expanding
1086 for( int iy=ch; --iy>=dy; ) {
1087 chr_t *bp = &bfr[iy*MX_CX], *cp = bp-dy*MX_CX;
1090 memset(&bfr[0],0,dy*n);
1095 if( dy < 0 ) { // scroll up, contracting
1096 for( int iy=dy; iy>ch; ++iy ) {
1097 chr_t *bp = &bfr[iy*MX_CX], *cp = bp+dy*MX_CX;
1106 int m = dx*sizeof(*bfr);
1107 for( int iy=0; iy<ch; ++iy ) {
1108 chr_t *bp = &bfr[iy*MX_CX] + cw;
1113 n = ncw*sizeof(*bfr);
1114 for( int iy=ch; iy<nch; ++iy ) {
1115 chr_t *bp = &bfr[iy*MX_CX];
1124 set_pen_style(int i)
1126 pen_style = i > 0 ? i : 1;
1127 pen_size = psz_standard;
1128 font_style = pen_style <= 5 ? pen_style-1 : pen_style-3;
1129 offset = ofs_normal;
1130 italics = underline = 0;
1131 fg_opacity = oty_solid;
1133 edge_type = pen_style <= 5 ? edg_none : edg_uniform;
1135 bg_opacity = pen_style <= 5 ? oty_solid : oty_transparent;
1137 fg_yuva = pen_yuva(fg_color,fg_opacity);
1138 edge_yuva = pen_yuva(edge_color,fg_opacity);
1139 bg_yuva = pen_yuva(bg_color,bg_opacity);
1140 text_tag = tag_dialog;
1144 set_window_style(int i)
1146 window_style = i > 0 ? i : 1;
1147 justify = ((0x48>>window_style) & 1) ? jfy_center : jfy_left;
1148 pdir = window_style < 7 ? dir_rt : dir_dn;
1149 sdir = window_style < 7 ? dir_up : dir_lt;
1150 wordwrap = (0x70>>window_style) & 1;
1151 display_effect = eft_snap;
1153 effect_direction = dir_rt;
1154 fill_opacity = oty_solid;
1156 border_type = edg_none;
1157 border_color = 0x00;
1158 fill_yuva = pen_yuva(fill_color,fill_opacity);
1159 border_yuva = pen_yuva(border_color,fill_opacity);
1167 row_lock = col_lock = 0;
1169 anchor_relative = 0;
1170 anchor_vertical = 24;
1171 anchor_horizontal = 12;
1173 set_window_style(1);
1177 int n = cw*sizeof(*bfr);
1178 for( int iy=0; iy<ch; ++iy)
1179 memset(&bfr[iy*MX_CX],0,n);
1189 zmsgs("bfr %d\n",id);
1190 for( int iy=0; iy<ch; ++iy ) {
1192 for( int ix=0; ix<cw; ++ix ) {
1193 int b = bfr[ofs++].glyph;
1194 printf("%c", b>=0x20 && b<0x7f ? b : '.');
1203 if( !subtitle ) return;
1204 uint16_t bb = chr->glyph;
1205 bitfont_t *font = chr_font(chr, scale);
1206 if( bb >= font->nch ) return;
1207 //zmsgs("%02x \"%c\" at %d,%d in %d\n",bb,bb>=0x20&&bb<0x7f?bb:'.',x,y,id);
1208 int ww = subtitle->w - 2*bw;
1209 int hh = subtitle->h - 2*bw;
1211 bitfont_t::bitchar_t *cp = &font->chrs[bb];
1212 uint8_t *bmap = cp->bitmap;
1213 if( bmap || cp->ch == ' ' ) {
1214 /* cell origin = (x,y) addressed (0,0) to (x2,y2) */
1215 /* char data box (x0,y0) to (x1,y1), may exceed cell box */
1216 int x0, ix0, y0, iy0;
1218 x0 = ix0 = cp->left;
1219 y0 = iy0 = font->imy - cp->ascent;
1221 y1 = font->imy + cp->decent;
1222 x2 = font->idx; y2 = font->idy;
1225 case dir_rt: x2 = dx = cp->right; break;
1226 case dir_lt: x2 = dx = cp->left; break;
1227 case dir_dn: y2 = dy = cp->decent; break;
1228 case dir_up: y2 = dy = cp->ascent; break;
1233 case dir_rt: case dir_lt: dx = font->idx; break;
1234 case dir_dn: case dir_up: dy = font->idy; break;
1237 if( x+x0 < 0 ) x0 = -x;
1238 if( y+y0 < 0 ) y0 = -y;
1240 if( x0 > mx ) x0 = mx;
1241 if( x1 > mx ) x1 = mx;
1242 if( x2 > mx ) x2 = mx;
1244 if( y0 > my ) y0 = my;
1245 if( y1 > my ) y1 = my;
1246 if( y2 > my ) y2 = my;
1248 class pix_t { /* address char cell */
1249 uint8_t *image_y, *image_u, *image_v, *image_a;
1250 uint8_t *img_y, *img_u, *img_v, *img_a; int w;
1252 void set_line(int n) {
1254 img_y = image_y + ofs;
1255 img_u = image_u + ofs;
1256 img_v = image_v + ofs;
1257 img_a = image_a + ofs;
1259 pix_t(subtitle_t *subtitle, int x, int y) {
1262 image_y = subtitle->image_y + ofs;
1263 image_u = subtitle->image_u + ofs;
1264 image_v = subtitle->image_v + ofs;
1265 image_a = subtitle->image_a + ofs;
1267 void write(int i, uint32_t yuva) {
1268 img_y[i] = yuva >> 24;
1269 img_u[i] = yuva >> 16;
1270 img_v[i] = yuva >> 8;
1271 img_a[i] = yuva >> 0;
1273 void fill_box(uint32_t yuva, int x0,int y0, int x1,int y1) {
1274 if( x0 >= x1 ) return;
1277 for( int ix=x0; ix<x1; ++ix ) write(ix,yuva);
1280 } pix(subtitle, x+bw, y+bw); /* origin inside border */
1281 /* dont fill left of cell */
1282 pix.fill_box(bg_yuva, 0, 0, x2,y0); /* fill top */
1283 pix.fill_box(bg_yuva, 0,y0, x0,y1); /* fill left */
1284 pix.fill_box(bg_yuva, x1,y0, x2,y1); /* fill right */
1285 pix.fill_box(bg_yuva, 0,y1, x2,y2); /* fill bottom */
1287 int wsz = (cp->right-cp->left+7) / 8;
1290 /* render char box */
1291 for( int iy=y0; iy<y1; ++iy,++ry ) {
1293 uint8_t *row = &bmap[ry*wsz];
1294 int i = rx, ix = x0;
1295 /* dont render bg left of cell */
1297 if( ((row[i>>3] >> (i&7)) & 1) ) pix.write(ix, fg_yuva);
1300 /* render fg/bg inside of cell */
1302 pix.write(ix, ((row[i>>3] >> (i&7)) & 1) ? fg_yuva : bg_yuva);
1306 if( chr->underline ) {
1307 int uy0 = font->imy;
1309 int uy1 = uy0 + (y2+23)/24;
1310 if( uy1 > y2 ) uy1 = y2;
1311 pix.fill_box(fg_yuva, 0,uy0, x2,uy1);
1316 /* no bitmap and not blank */
1318 case dir_rt: dx = font->idx; dy = 0; break;
1319 case dir_lt: dx = font->idy; dy = 0; break;
1320 case dir_dn: dx = 0; dy = font->idy; break;
1321 case dir_up: dx = 0; dy = font->idy; break;
1328 hbar(int x, int y, int ww, int hh, int lm, int rm, int clr)
1330 /* w,h = widget dims, ww,hh = bar dims */
1331 /* x,y = widget coord, lm,rm = lt/rt miter, clr = color */
1332 int w = subtitle->w;
1333 int h = subtitle->h;
1334 if( y < 0 ) { hh += y; y = 0; }
1335 if( y+hh > h ) hh = h - y;
1336 uint32_t yuva = border_yuva;
1337 for( int ih=hh; --ih>=0; ++y ) {
1338 int iw = ww, ix = x;
1339 if( ix < 0 ) { iw += ix; ix = 0; }
1340 if( ix+iw > w ) iw = w - ix;
1342 uint8_t *img_y = &subtitle->image_y[ofs];
1343 uint8_t *img_u = &subtitle->image_u[ofs];
1344 uint8_t *img_v = &subtitle->image_v[ofs];
1345 uint8_t *img_a = &subtitle->image_a[ofs];
1346 while( --iw >= 0 ) {
1347 *img_y = clr; ++img_y;
1348 *img_u = yuva >> 16; ++img_u;
1349 *img_v = yuva >> 8; ++img_v;
1350 *img_a = yuva >> 0; ++img_a;
1352 x += lm; ww -= lm-rm;
1357 vbar(int x, int y, int ww, int hh, int tm, int bm, int clr)
1359 /* w,h = widget dims, ww,hh = bar dims */
1360 /* x,y = widget coord, lm,rm = lt/rt miter, clr = color */
1361 int w = subtitle->w;
1362 int h = subtitle->h;
1363 if( x < 0 ) { ww += x; x = 0; }
1364 if( x+ww > w ) ww = w - x;
1365 uint32_t yuva = border_yuva;
1366 for( int iw=ww; --iw>=0; ++x ) {
1367 int ih = hh, iy = y;
1368 if( iy < 0 ) { ih += iy; iy = 0; }
1369 if( iy+ih > h ) ih = h - iy;
1371 uint8_t *img_y = &subtitle->image_y[ofs];
1372 uint8_t *img_u = &subtitle->image_u[ofs];
1373 uint8_t *img_v = &subtitle->image_v[ofs];
1374 uint8_t *img_a = &subtitle->image_a[ofs];
1375 while( --ih >= 0 ) {
1376 *img_y = clr; img_y += w;
1377 *img_u = yuva >> 16; img_u += w;
1378 *img_v = yuva >> 8; img_v += w;
1379 *img_a = yuva >> 0; img_a += w;
1381 y += tm; hh -= tm-bm;
1386 border(int ilt, int olt, int irt, int ort,
1387 int iup, int oup, int idn, int odn)
1389 /* i/o = inside/outside + lt/rt/up/dn = colors */
1390 if( !bw || !subtitle ) return;
1391 int w = subtitle->w;
1392 int h = subtitle->h;
1393 int sbw = bw * scale;
1394 int zo = sbw / 2; // outside width
1395 int zi = sbw - zo; // inside width
1396 hbar(0,0,w,zo,1,-1,oup);
1397 hbar(zo,zo,w-2*zo,zi,1,-1,iup);
1398 hbar(sbw-1,h-sbw,w-2*sbw+2,zi,-1,1,idn);
1399 hbar(zo-1,h-zo,w-2*zo+2,zo,-1,1,odn);
1400 vbar(0,1,zo,h-2,1,-1,olt);
1401 vbar(zo,zo+1,zi,h-2*zo-2,1,-1,ilt);
1402 vbar(w-sbw,sbw,zi,h-2*sbw,-1,1,irt);
1403 vbar(w-zo,zo,zo,h-2*zo,-1,1,ort);
1409 if( st < st_visible || !bfr ) {
1410 if( subtitle ) subtitle->draw = -1;
1413 /* get bounding box */
1416 int fw = 0, fh = 0, zz = 0;
1420 for( int iy=0; iy<ch; ++iy ) {
1422 for( int ix=0; ix<cw; ++ix ) {
1423 chr_t *chr = &bfr[iy*MX_CX + ix];
1424 bitfont_t *font = chr_font(chr, scale);
1425 if( font->idy > fh ) fh = font->idy;
1427 if( b >= font->nch ) continue;
1428 bitfont_t::bitchar_t *cp = &font->chrs[b];
1429 int sz = !cp->bitmap ? font->idx :
1430 pdir == dir_rt ? cp->right : cp->left;
1433 if( ww > zz ) zz = ww;
1440 for( int ix=0; ix<cw; ++ix ) {
1442 for( int iy=0; iy<ch; ++iy ) {
1443 chr_t *chr = &bfr[iy*MX_CX + ix];
1444 bitfont_t *font = chr_font(chr, scale);
1445 if( font->idx > fw ) fw = font->idx;
1447 if( b >= font->nch ) continue;
1448 bitfont_t::bitchar_t *cp = &font->chrs[b];
1449 int sz = !cp->bitmap ? font->idy :
1450 pdir == dir_dn ? cp->decent : cp->ascent;
1453 if( hh > zz ) zz = hh;
1459 video_t *video = svc->cc->video;
1460 //zmsgs(" an_horz=%d, an_vert=%d, an_rela=%d, %dx%d\n",
1461 // anchor_horizontal, anchor_vertical, anchor_relative,
1462 // video->coded_picture_width, video->coded_picture_height);
1463 int ax = ((anchor_horizontal+10) * video->coded_picture_width) / 200;
1464 int ay = ((anchor_vertical+10) * video->coded_picture_height) / 100;
1465 if( anchor_relative ) { ax += ax; ay += ay; }
1466 switch( anchor_point ) {
1467 case 0x00: break; /* nw */
1468 case 0x01: ax -= wd/2; break; /* n */
1469 case 0x02: ax -= wd; break; /* ne */
1470 case 0x03: ax -= wd; ay -= ht/2; break; /* e */
1471 case 0x04: ax -= wd; ay -= ht; break; /* se */
1472 case 0x05: ax -= wd/2; ay -= ht; break; /* s */
1473 case 0x06: ay -= ht; break; /* sw */
1474 case 0x07: ay -= ht/2; break; /* w */
1475 case 0x08: ax -= wd/2; ay -= ht/2; break; /* center */
1478 zmpeg3_t *src = video->src;
1479 strack_t *strack = src->create_strack(svc->ctrk, video);
1481 subtitle = new subtitle_t(id, wd, ht);
1482 if( subtitle->done < 0 ) {
1483 if( strack->append_subtitle(subtitle,0) ) {
1484 delete subtitle; subtitle = 0;
1488 subtitle->set_image_size(wd, ht);
1489 subtitle->x1 = ax; subtitle->x2 = ax + wd;
1490 subtitle->y1 = ay; subtitle->y2 = ay + ht;
1492 subtitle->frame_time = video->frame_time;
1494 uint8_t yy = fill_yuva >> 24;
1495 uint8_t uu = fill_yuva >> 16;
1496 uint8_t vv = fill_yuva >> 8;
1497 uint8_t aa = fill_yuva >> 0;
1498 aa = 0xff - aa; // this is probably wrong
1499 int w = subtitle->w;
1500 int h = subtitle->h;
1502 memset(subtitle->image_y, yy, sz);
1503 memset(subtitle->image_u, uu, sz);
1504 memset(subtitle->image_v, vv, sz);
1505 memset(subtitle->image_a, aa, sz);
1506 yy = border_yuva >> 24;
1508 if( (hi_y = yy + 0x60) > 0xff ) hi_y = 0xff;
1509 if( (lo_y = yy - 0x60) < 0x10 ) lo_y = 0x10;
1510 switch( border_type ) {
1511 case 0x01: /* raised */
1512 border(hi_y, yy, hi_y, yy, hi_y, yy, hi_y, yy);
1514 case 0x02: /* depressed */
1515 border(lo_y, yy, lo_y, yy, lo_y, yy, lo_y, yy);
1517 case 0x03: /* uniform */
1518 border(yy, yy, yy, yy, yy, yy, yy, yy);
1520 case 0x04: /* shadowl */
1521 border(lo_y, lo_y, hi_y, hi_y, hi_y, lo_y, hi_y, lo_y);
1523 case 0x05: /* shadowr */
1524 border(hi_y, hi_y, lo_y, lo_y, hi_y, lo_y, hi_y, lo_y);
1527 case 0x00: /* none */
1530 /* render character data */
1533 for( int iy=0; iy<ch; ++iy ) {
1535 chr_t *bp = &bfr[iy * MX_CX];
1536 for( int ix=0; ix<cw; ++ix, ++bp ) {
1542 for( int iy=0; iy<ch; ++iy ) {
1544 chr_t *bp = &bfr[iy*MX_CX + cw];
1545 for( int ix=cw; --ix>=0; )
1550 for( int ix=0; ix<cw; ++ix ) {
1552 chr_t *bp = &bfr[ix];
1553 for( int iy=0; iy<ch; ++iy, bp+=MX_CX )
1558 for( int ix=0; ix<cw; ++ix ) {
1560 chr_t *bp = &bfr[ch*MX_CX - cw + ix];
1561 for( int iy=ch; --iy>=0; ) {
1562 put_chr(bp -= MX_CX);