Ticket #668: ccdecoder-r7892.patch

File ccdecoder-r7892.patch, 49.9 KB (added by gtgj@…, 14 years ago)
  • libs/libmythtv/vbitext/cc.cpp

     
    194194    cc->code1 = -1;
    195195    cc->code2 = -1;
    196196
    197     for (int i = 0; i < 2; i++)
    198     {
    199         cc->badvbi[i] = 0;
    200         cc->lasttc[i] = 0;
    201         cc->lastcode[i] = -1;
    202         cc->lastcodetc[i] = 0;
    203         cc->ccmode[i] = -1;
    204         cc->txtmode[i*2 + 0] = 0;
    205         cc->txtmode[i*2 + 1] = 0;
    206         cc->xds[i] = 0;
    207     }
    208 
    209     for (int i = 0; i < 8; i++)
    210     {
    211         cc->lastrow[i] = 0;
    212         cc->newrow[i] = 0;
    213         cc->newcol[i] = 0;
    214         cc->timecode[i] = 0;
    215         cc->row[i] = 0;
    216         cc->col[i] = 0;
    217         cc->rowcount[i] = 0;
    218         cc->style[i] = 0;
    219         cc->linecont[i] = 0;
    220         cc->resumetext[i] = 0;
    221         cc->lastclr[i] = 0;
    222         cc->ccbuf[i] = "";
    223     }
    224 
    225197    return cc;
    226198}
    227199
  • libs/libmythtv/vbitext/cc.h

     
    11#ifndef CC_H
    22#define CC_H
    33
    4 #include <qstring.h>
    5 
    64#define CC_VBIBUFSIZE 65536
    75
    86//cc is 32 columns per row, this allows for extra characters
     
    1412    char buffer[CC_VBIBUFSIZE];
    1513    int code1;
    1614    int code2;
    17 
    18     // per-field
    19     int badvbi[2];
    20     int lasttc[2];
    21     int lastcode[2];
    22     int lastcodetc[2];
    23     int ccmode[2];      // 0=cc1/txt1, 1=cc2/txt2
    24     int txtmode[4];
    25     int xds[2];
    26 
    27     // per-mode state
    28     int lastrow[8];
    29     int newrow[8];
    30     int newcol[8];
    31     int timecode[8];
    32     int row[8];
    33     int col[8];
    34     int rowcount[8];
    35     int style[8];
    36     int linecont[8];
    37     int resumetext[8];
    38     int lastclr[8];
    39     QString ccbuf[8];
    4015};
    4116
    4217int cc_decode(unsigned char *vbiline);
  • libs/libmythtv/NuppelVideoRecorder.cpp

     
    169169    prev_bframe_save_pos = -1;
    170170
    171171    volume = 100;
     172
     173    ccd = new CCDecoder(this);
     174
    172175    go7007 = false;
    173176}
    174177
     
    228231        delete videoFilters;
    229232    if (FiltMan)
    230233        delete FiltMan;
     234
     235    delete ccd;
    231236}
    232237
    233238void NuppelVideoRecorder::deleteLater(void)
     
    24632468    int tc = (tnow.tv_sec - stm.tv_sec) * 1000 +
    24642469             tnow.tv_usec / 1000 - stm.tv_usec / 1000;
    24652470
    2466     for (int field = 0; field < 2; field++)
    2467         FormatCCField(cc, tc, field);
     2471    ccd->FormatCC(tc, cc->code1, cc->code2);
    24682472}
    24692473
    2470 void NuppelVideoRecorder::FormatCCField(struct cc *cc, int tc, int field)
     2474void NuppelVideoRecorder::AddTextData(unsigned char *buf, int len,
     2475                                      long long timecode, char type)
    24712476{
    2472     const int rowdata[] = { 11, -1, 1, 2, 3, 4, 12, 13,
    2473                             14, 15, 5, 6, 7, 8, 9, 10 };
    2474     const QChar specialchar[] =
    2475     { '®', '°', 'œ', '¿', 0x2122 /* TM */, '¢', '£', 0x266A /* 1/8 note */,
    2476       'à', ' ', 'è', 'â', 'ê', 'î', 'ô', 'û'
    2477     };
    2478     const QChar extendedchar2[] =
    2479     { 'Á', 'É', 'Ó', 'Ú', 'Ü', 'ü', '`', '¡',
    2480       '*', '\'', 0x2014 /* dash */, '©', 0x2120 /* SM */, '·', 0x201C, 0x201D /* dquotes */,
    2481       'À', 'Â', 'Ç', 'È', 'Ê', 'Ë', 'ë', 'Î',
    2482       'Ï', 'ï', 'Ô', 'Ù', 'ù', 'Û', '«', '»'
    2483     };
    2484     const QChar extendedchar3[] =
    2485     { 'Ã', 'ã', 'Í', 'Ì', 'ì', 'Ò', 'ò', 'Õ',
    2486       'õ', '{', '}', '\\', '^', '_', 'Š', '~',
    2487       'Ä', 'ä', 'Ö', 'ö', 'ß', '¥', '€', '|',
    2488       'Å', 'å', 'Ø', 'ø', 0x250C, 0x2510, 0x2514, 0x2518 /* box drawing */
    2489     };
    2490     int b1, b2, len, x;
    2491     int mode;
    2492     int data;
    2493 
    2494     if (field == 0)
    2495         data = cc->code1;
    2496     else
    2497         data = cc->code2;
    2498 
    2499     if (data == -1)              // invalid data. flush buffers to be safe.
    2500     {
    2501         // TODO: write textbuffer[act]
    2502         //printf (" TODO: write textbuffer[act]\n");
    2503         if (cc->ccmode[field] != -1)
    2504         {
    2505             for (mode = field*4; mode < (field*4 + 4); mode++)
    2506                 ResetCC(cc, mode);
    2507             cc->xds[field] = 0;
    2508             cc->badvbi[field] = 0;
    2509             cc->ccmode[field] = -1;
    2510             cc->txtmode[field*2] = 0;
    2511             cc->txtmode[field*2 + 1] = 0;
    2512         }
    2513         return;
    2514     }
    2515 
    2516     b1 = data & 0x7f;
    2517     b2 = (data >> 8) & 0x7f;
    2518     if (cc->ccmode[field] >= 0)
    2519     {
    2520         mode = field << 2 |
    2521                (cc->txtmode[field*2 + cc->ccmode[field]] << 1) |
    2522                cc->ccmode[field];
    2523         len = cc->ccbuf[mode].length();
    2524     }
    2525     else
    2526     {
    2527         mode = -1;
    2528         len = 0;
    2529     }
    2530 
    2531     // bttv-0.9 VBI reads are pretty reliable (1 read/33367us).
    2532     // bttv-0.7 reads don't seem to work as well so if read intervals
    2533     // vary from this, be more conservative in detecting duplicate
    2534     // CC codes.
    2535     int dup_text_fudge, dup_ctrl_fudge;
    2536     if (cc->badvbi[field] < 100 && b1 != 0 && b2 != 0)
    2537     {
    2538         int d = tc - cc->lasttc[field];
    2539         if (d < 25 || d > 42)
    2540             cc->badvbi[field]++;
    2541         else if (cc->badvbi[field] > 0)
    2542             cc->badvbi[field]--;
    2543     }
    2544     if (cc->badvbi[field] < 4)
    2545     {
    2546         dup_text_fudge = -2;  // should pick up all codes
    2547         dup_ctrl_fudge = 33 - 4;  // should pick up 1st, 4th, 6th, 8th, ... codes
    2548     }
    2549     else
    2550     {
    2551         dup_text_fudge = 4;
    2552         dup_ctrl_fudge = 33 - 4;
    2553     }
    2554 
    2555     if (data == cc->lastcode[field])
    2556     {
    2557         int false_dup = 1;
    2558         if ((b1 & 0x70) == 0x10)
    2559         {
    2560             if (tc > (cc->lastcodetc[field] + 67 + dup_ctrl_fudge))
    2561                 false_dup = 0;
    2562         }
    2563         else if (b1)
    2564         {
    2565             // text, XDS
    2566             if (tc > (cc->lastcodetc[field] + 33 + dup_text_fudge))
    2567                 false_dup = 0;
    2568         }
    2569 
    2570         if (false_dup)
    2571             goto skip;
    2572     }
    2573 
    2574     if ((field == 1) &&
    2575         (cc->xds[field] || b1 && ((b1 & 0x70) == 0x00)))
    2576         // 0x01 <= b1 <= 0x0F
    2577         // start XDS
    2578         // or inside XDS packet
    2579     {
    2580         int xds_packet = 1;
    2581 
    2582         // TODO: process XDS packets
    2583         if (b1 == 0x0F)
    2584         {
    2585             // end XDS
    2586             cc->xds[field] = 0;
    2587             xds_packet = 1;
    2588         }
    2589         else if ((b1 & 0x70) == 0x10)
    2590         {
    2591             // ctrl code -- interrupt XDS
    2592             cc->xds[field] = 0;
    2593             xds_packet = 0;
    2594         }
    2595         else
    2596         {
    2597             cc->xds[field] = 1;
    2598             xds_packet = 1;
    2599         }
    2600 
    2601         if (xds_packet)
    2602             goto skip;
    2603     }
    2604 
    2605     if (b1 & 0x60)
    2606         // 0x20 <= b1 <= 0x7F
    2607         // text codes
    2608     {
    2609         if (mode >= 0)
    2610         {
    2611             cc->lastcodetc[field] += 33;
    2612             cc->timecode[mode] = tc;
    2613 
    2614             // commit row number only when first text code
    2615             // comes in
    2616             if (cc->newrow[mode])
    2617                 len = NewRowCC(cc, mode, len);
    2618 
    2619             cc->ccbuf[mode] += CharCC(b1);
    2620             len++;
    2621             cc->col[mode]++;
    2622             if (b2 & 0x60)
    2623             {
    2624                 cc->ccbuf[mode] += CharCC(b2);
    2625                 len++;
    2626                 cc->col[mode]++;
    2627             }
    2628         }
    2629     }
    2630 
    2631     else if ((b1 & 0x10) && (b2 > 0x1F))
    2632         // 0x10 <= b1 <= 0x1F
    2633         // control codes
    2634     {
    2635         cc->lastcodetc[field] += 67;
    2636 
    2637         int newccmode = (b1 >> 3) & 1;
    2638         int newtxtmode = cc->txtmode[field*2 + newccmode];
    2639         if ((b1 & 0x06) == 0x04)
    2640         {
    2641             switch (b2)
    2642             {
    2643             case 0x29:
    2644             case 0x2C:
    2645             case 0x20:
    2646             case 0x2F:
    2647             case 0x25:
    2648             case 0x26:
    2649             case 0x27:
    2650                 // CC1,2
    2651                 newtxtmode = 0;
    2652                 break;
    2653             case 0x2A:
    2654             case 0x2B:
    2655                 // TXT1,2
    2656                 newtxtmode = 1;
    2657                 break;
    2658             }
    2659         }
    2660         cc->ccmode[field] = newccmode;
    2661         cc->txtmode[field*2 + newccmode] = newtxtmode;
    2662         mode = (field << 2) | (newtxtmode << 1) | cc->ccmode[field];
    2663 
    2664         cc->timecode[mode] = tc;
    2665         len = cc->ccbuf[mode].length();
    2666 
    2667         if (b2 & 0x40)           //preamble address code (row & indent)
    2668         {
    2669             if (newtxtmode)
    2670                 // no address codes in TXT mode?
    2671                 goto skip;
    2672 
    2673             cc->newrow[mode] = rowdata[((b1 << 1) & 14) | ((b2 >> 5) & 1)];
    2674             if (cc->newrow[mode] == -1)
    2675                 // bogus code?
    2676                 cc->newrow[mode] = cc->lastrow[mode] + 1;
    2677 
    2678             if (b2 & 0x10)        //row contains indent flag
    2679                 cc->newcol[mode] = (b2 & 0x0E) << 1;
    2680             else
    2681                 cc->newcol[mode] = 0;
    2682 
    2683             // row, indent settings are not final
    2684             // until text code arrives
    2685         }
    2686         else
    2687         {
    2688             switch (b1 & 0x07)
    2689             {
    2690                case 0x00:          //attribute
    2691                   /*
    2692                    printf ("<ATTRIBUTE %d %d>\n", b1, b2);
    2693                    fflush (stdout);
    2694                    */
    2695                    break;
    2696                case 0x01:          //midrow or char
    2697                    if (cc->newrow[mode])
    2698                        len = NewRowCC(cc, mode, len);
    2699 
    2700                    switch (b2 & 0x70)
    2701                    {
    2702                        case 0x20:      //midrow attribute change
    2703                            // TODO: we _do_ want colors, is that an attribute?
    2704                            cc->ccbuf[mode] += ' ';
    2705                            len = cc->ccbuf[mode].length();
    2706                            cc->col[mode]++;
    2707                            break;
    2708                        case 0x30:      //special character..
    2709                            cc->ccbuf[mode] += specialchar[b2 & 0x0f];
    2710                            len++;
    2711                            cc->col[mode]++;
    2712                            break;
    2713                    }
    2714                    break;
    2715                case 0x02:          //extended char
    2716                    // extended char is preceded by alternate char
    2717                    // - if there's no alternate, it could be noise
    2718                    if (!len)
    2719                        break;
    2720 
    2721                    if (b2 & 0x30)
    2722                    {
    2723                        cc->ccbuf[mode].remove(len - 1, 1);
    2724                        cc->ccbuf[mode] += extendedchar2[b2 - 0x20];
    2725                        len = cc->ccbuf[mode].length();
    2726                        break;
    2727                    }
    2728                    break;
    2729                case 0x03:          //extended char
    2730                    // extended char is preceded by alternate char
    2731                    // - if there's no alternate, it could be noise
    2732                    if (!len)
    2733                        break;
    2734 
    2735                    if (b2 & 0x30)
    2736                    {
    2737                        cc->ccbuf[mode].remove(len - 1, 1);
    2738                        cc->ccbuf[mode] += extendedchar3[b2 - 0x20];
    2739                        len = cc->ccbuf[mode].length();
    2740                        break;
    2741                    }
    2742                    break;
    2743                case 0x04:          //misc
    2744                case 0x05:          //misc + F
    2745 //                 printf("ccmode %d cmd %02x\n",ccmode,b2);
    2746                    switch (b2)
    2747                    {
    2748                        case 0x21:      //backspace
    2749                            // add backspace if line has been encoded already
    2750                            if (cc->newrow[mode])
    2751                                len = NewRowCC(cc, mode, len);
    2752 
    2753                            if (len == 0 ||
    2754                                cc->ccbuf[mode].left(1) == "\b")
    2755                            {
    2756                                cc->ccbuf[mode] += (char)'\b';
    2757                                len++;
    2758                                cc->col[mode]--;
    2759                            }
    2760                            else
    2761                            {
    2762                                cc->ccbuf[mode].remove(len - 1, 1);
    2763                                len = cc->ccbuf[mode].length();
    2764                                cc->col[mode]--;
    2765                            }
    2766                            break;
    2767                        case 0x25:      //2 row caption
    2768                        case 0x26:      //3 row caption
    2769                        case 0x27:      //4 row caption
    2770                            if (cc->style[mode] == CC_STYLE_PAINT && len)
    2771                            {
    2772                                // flush
    2773                                BufferCC(cc, mode, len, 0);
    2774                                cc->ccbuf[mode] = "";
    2775                                cc->row[mode] = 0;
    2776                                cc->col[mode] = 0;
    2777                            }
    2778                            else if (cc->style[mode] == CC_STYLE_POPUP)
    2779                                ResetCC(cc, mode);
    2780 
    2781                            cc->rowcount[mode] = b2 - 0x25 + 2;
    2782                            cc->style[mode] = CC_STYLE_ROLLUP;
    2783                            break;
    2784                        case 0x2D:      //carriage return
    2785                            if (cc->style[mode] != CC_STYLE_ROLLUP)
    2786                                break;
    2787 
    2788                            if (cc->newrow[mode])
    2789                                cc->row[mode] = cc->newrow[mode];
    2790 
    2791                            // flush if there is text or need to scroll
    2792                            // TODO:  decode ITV (WebTV) link in TXT2
    2793                            if (len ||
    2794                                cc->row[mode] != 0 &&
    2795                                !cc->linecont[mode] &&
    2796                                (!newtxtmode || cc->row[mode] >= 16))
    2797                                BufferCC(cc, mode, len, 0);
    2798 
    2799                            if (newtxtmode)
    2800                            {
    2801                                if (cc->row[mode] < 16)
    2802                                    cc->newrow[mode] = cc->row[mode] + 1;
    2803                                else
    2804                                    // scroll up previous lines
    2805                                    cc->newrow[mode] = 16;
    2806                            }
    2807 
    2808                            cc->ccbuf[mode] = "";
    2809                            cc->col[mode] = 0;
    2810                            cc->linecont[mode] = 0;
    2811                            break;
    2812 
    2813                        case 0x29:      //resume direct caption (paint-on style)
    2814                            if (cc->style[mode] == CC_STYLE_ROLLUP && len)
    2815                            {
    2816                                // flush
    2817                                BufferCC(cc, mode, len, 0);
    2818                                cc->ccbuf[mode] = "";
    2819                                cc->row[mode] = 0;
    2820                                cc->col[mode] = 0;
    2821                            }
    2822                            else if (cc->style[mode] == CC_STYLE_POPUP)
    2823                                ResetCC(cc, mode);
    2824 
    2825                            cc->style[mode] = CC_STYLE_PAINT;
    2826                            cc->rowcount[mode] = 0;
    2827                            cc->linecont[mode] = 0;
    2828                            break;
    2829 
    2830                        case 0x2B:      //resume text display
    2831                            cc->resumetext[mode] = 1;
    2832                            if (cc->row[mode] == 0)
    2833                            {
    2834                                cc->newrow[mode] = 1;
    2835                                cc->newcol[mode] = 0;
    2836                            }
    2837                            cc->style[mode] = CC_STYLE_ROLLUP;
    2838                            break;
    2839                        case 0x2C:      //erase displayed memory
    2840                            if ((tc - cc->lastclr[mode]) > 5000 ||
    2841                                cc->lastclr[mode] == 0)
    2842                                // don't overflow the frontend with
    2843                                // too many redundant erase codes
    2844                                BufferCC(cc, mode, 0, 1);
    2845                            if (cc->style[mode] != CC_STYLE_POPUP)
    2846                            {
    2847                                cc->row[mode] = 0;
    2848                                cc->col[mode] = 0;
    2849                            }
    2850                            cc->linecont[mode] = 0;
    2851                            break;
    2852 
    2853                        case 0x20:      //resume caption (pop-up style)
    2854                            if (cc->style[mode] != CC_STYLE_POPUP)
    2855                            {
    2856                                if (len)
    2857                                    // flush
    2858                                    BufferCC(cc, mode, len, 0);
    2859                                cc->ccbuf[mode] = "";
    2860                                cc->row[mode] = 0;
    2861                                cc->col[mode] = 0;
    2862                            }
    2863                            cc->style[mode] = CC_STYLE_POPUP;
    2864                            cc->rowcount[mode] = 0;
    2865                            cc->linecont[mode] = 0;
    2866                            break;
    2867                        case 0x2F:      //end caption + swap memory
    2868                            if (cc->style[mode] != CC_STYLE_POPUP)
    2869                            {
    2870                                if (len)
    2871                                    // flush
    2872                                    BufferCC(cc, mode, len, 0);
    2873                            }
    2874                            else if ((tc - cc->lastclr[mode]) > 5000 ||
    2875                                     cc->lastclr[mode] == 0)
    2876                                // clear and flush
    2877                                BufferCC(cc, mode, len, 1);
    2878                            else if (len)
    2879                                // flush
    2880                                BufferCC(cc, mode, len, 0);
    2881                            cc->ccbuf[mode] = "";
    2882                            cc->row[mode] = 0;
    2883                            cc->col[mode] = 0;
    2884                            cc->style[mode] = CC_STYLE_POPUP;
    2885                            cc->rowcount[mode] = 0;
    2886                            cc->linecont[mode] = 0;
    2887                            break;
    2888 
    2889                        case 0x2A:      //text restart
    2890                            // clear display
    2891                            BufferCC(cc, mode, 0, 1);
    2892                            ResetCC(cc, mode);
    2893                            // TXT starts at row 1
    2894                            cc->newrow[mode] = 1;
    2895                            cc->newcol[mode] = 0;
    2896                            cc->style[mode] = CC_STYLE_ROLLUP;
    2897                            break;
    2898 
    2899                        case 0x2E:      //erase non-displayed memory
    2900                            ResetCC(cc, mode);
    2901                            break;
    2902                    }
    2903                    break;
    2904                case 0x07:          //misc (TAB)
    2905                    if (cc->newrow[mode])
    2906                    {
    2907                        cc->newcol[mode] += (b2 & 0x03);
    2908                        len = NewRowCC(cc, mode, len);
    2909                    }
    2910                    else
    2911                        // illegal?
    2912                        for (x = 0; x < (b2 & 0x03); x++)
    2913                        {
    2914                            cc->ccbuf[mode] += ' ';
    2915                            len++;
    2916                            cc->col[mode]++;
    2917                        }
    2918                    break;
    2919             }
    2920         }
    2921     }
    2922 
    2923 skip:
    2924     for (mode = field*4; mode < (field*4 + 4); mode++)
    2925     {
    2926         len = cc->ccbuf[mode].length();
    2927         if (((tc - cc->timecode[mode]) > 100) &&
    2928             (cc->style[mode] != CC_STYLE_POPUP) && len)
    2929         {
    2930             // flush unfinished line if waiting too long
    2931             // in paint-on or scroll-up mode
    2932             cc->timecode[mode] = tc;
    2933             BufferCC(cc, mode, len, 0);
    2934             cc->ccbuf[mode] = "";
    2935             cc->row[mode] = cc->lastrow[mode];
    2936             cc->linecont[mode] = 1;
    2937         }
    2938     }
    2939 
    2940     if (data != cc->lastcode[field])
    2941     {
    2942         cc->lastcode[field] = data;
    2943         cc->lastcodetc[field] = tc;
    2944     }
    2945     cc->lasttc[field] = tc;
    2946 }
    2947 
    2948 QChar NuppelVideoRecorder::CharCC(int code)
    2949 {
    2950     switch (code)
    2951     {
    2952     case 42:  return 'á';
    2953     case 92:  return 'é';
    2954     case 94:  return 'í';
    2955     case 95:  return 'ó';
    2956     case 96:  return 'ú';
    2957     case 123: return 'ç';
    2958     case 124: return '÷';
    2959     case 125: return 'Ñ';
    2960     case 126: return 'ñ';
    2961     case 127: return 0x2588; /* full block */
    2962     default : return QChar(code);
    2963     }
    2964 }
    2965 
    2966 void NuppelVideoRecorder::ResetCC(struct cc *cc, int mode)
    2967 {
    2968 //    cc->lastrow[mode] = 0;
    2969 //    cc->newrow[mode] = 0;
    2970 //    cc->newcol[mode] = 0;
    2971 //    cc->timecode[mode] = 0;
    2972     cc->row[mode] = 0;
    2973     cc->col[mode] = 0;
    2974     cc->rowcount[mode] = 0;
    2975 //    cc->style[mode] = CC_STYLE_POPUP;
    2976     cc->linecont[mode] = 0;
    2977     cc->resumetext[mode] = 0;
    2978     cc->lastclr[mode] = 0;
    2979     cc->ccbuf[mode] = "";
    2980 }
    2981 
    2982 void NuppelVideoRecorder::BufferCC(struct cc *cc, int mode, int len, int clr)
    2983 {
    29842477    int act = act_text_buffer;
    29852478    if (!textbuffer[act]->freeToBuffer)
    29862479    {
     
    29882481        return;
    29892482    }
    29902483
    2991     textbuffer[act]->timecode = cc->timecode[mode];
     2484    textbuffer[act]->timecode = timecode;
     2485    memcpy(textbuffer[act]->buffer, buf, len);
     2486    textbuffer[act]->bufferlen = len + sizeof(ccsubtitle);
    29922487
    2993     // NOTE:  text_buffer_size happens to be > (sizeof(ccsubtitle)+255)
    2994     QCString tmpbuf;
    2995     if (len)
    2996     {
    2997         // calculate UTF-8 encoding length
    2998         tmpbuf = cc->ccbuf[mode].utf8();
    2999         len = tmpbuf.length();
    3000         if (len > 255)
    3001             len = 255;
    3002     }
    3003 
    3004     unsigned char f;
    3005     unsigned char *bp = textbuffer[act]->buffer;
    3006     *(bp++) = cc->row[mode];
    3007     *(bp++) = cc->rowcount[mode];
    3008     *(bp++) = cc->style[mode];
    3009     // overload resumetext field
    3010     f = cc->resumetext[mode];
    3011     f |= mode << 4;
    3012     if (cc->linecont[mode])
    3013         f |= CC_LINE_CONT;
    3014     *(bp++) = f;
    3015     *(bp++) = clr;
    3016     *(bp++) = len;
    3017     if (len)
    3018     {
    3019         memcpy(bp,
    3020                tmpbuf,
    3021                len);
    3022         textbuffer[act]->bufferlen = len + sizeof(ccsubtitle);
    3023     }
    3024     else
    3025         textbuffer[act]->bufferlen = sizeof(ccsubtitle);
    3026 
    30272488    textbuffer[act]->freeToBuffer = 0;
    30282489    act_text_buffer++;
    30292490    if (act_text_buffer >= text_buffer_count)
    30302491        act_text_buffer = 0;
    30312492    textbuffer[act]->freeToEncode = 1;
    3032 
    3033     cc->resumetext[mode] = 0;
    3034     if (clr && !len)
    3035         cc->lastclr[mode] = cc->timecode[mode];
    3036     else if (len)
    3037         cc->lastclr[mode] = 0;
    30382493}
    30392494
    3040 int NuppelVideoRecorder::NewRowCC(struct cc *cc, int mode, int len)
    3041 {
    3042     if (cc->style[mode] == CC_STYLE_ROLLUP)
    3043     {
    3044         // previous line was likely missing a carriage return
    3045         cc->row[mode] = cc->newrow[mode];
    3046         if (len)
    3047         {
    3048             BufferCC(cc, mode, len, 0);
    3049             cc->ccbuf[mode] = "";
    3050             len = 0;
    3051         }
    3052         cc->col[mode] = 0;
    3053         cc->linecont[mode] = 0;
    3054     }
    3055     else
    3056     {
    3057         // popup/paint style
    3058 
    3059         if (cc->row[mode] == 0)
    3060         {
    3061             if (len == 0)
    3062                 cc->row[mode] = cc->newrow[mode];
    3063             else
    3064             {
    3065                 // previous line was missing a row address
    3066                 // - assume it was one row up
    3067                 cc->ccbuf[mode] += (char)'\n';
    3068                 len++;
    3069                 if (cc->row[mode] == 0)
    3070                     cc->row[mode] = cc->newrow[mode] - 1;
    3071                 else
    3072                     cc->row[mode]--;
    3073             }
    3074         }
    3075         else if (cc->newrow[mode] > cc->lastrow[mode])
    3076         {
    3077             // next line can be more than one row away
    3078             for (int i = 0; i < (cc->newrow[mode] - cc->lastrow[mode]); i++)
    3079             {
    3080                 cc->ccbuf[mode] += (char)'\n';
    3081                 len++;
    3082             }
    3083             cc->col[mode] = 0;
    3084         }
    3085         else if (cc->newrow[mode] == cc->lastrow[mode])
    3086         {
    3087             // same row
    3088             if (cc->newcol[mode] >= cc->col[mode])
    3089                 // new line appends to current line
    3090                 cc->newcol[mode] -= cc->col[mode];
    3091             else
    3092             {
    3093                 // new line overwrites current line;
    3094                 // could be legal (overwrite spaces?) but
    3095                 // more likely we have bad address codes
    3096                 // - just move to next line; may exceed row 15
    3097                 // but frontend will adjust
    3098                 cc->ccbuf[mode] += (char)'\n';
    3099                 len++;
    3100                 cc->col[mode] = 0;
    3101             }
    3102         }
    3103         else
    3104         {
    3105             // next line goes upwards (not legal?)
    3106             // - flush
    3107             BufferCC(cc, mode, len, 0);
    3108             cc->ccbuf[mode] = "";
    3109             cc->row[mode] = cc->newrow[mode];
    3110             cc->col[mode] = 0;
    3111             cc->linecont[mode] = 0;
    3112             len = 0;
    3113         }
    3114     }
    3115 
    3116     cc->lastrow[mode] = cc->newrow[mode];
    3117     cc->newrow[mode] = 0;
    3118 
    3119     for (int x = 0; x < cc->newcol[mode]; x++)
    3120     {
    3121         cc->ccbuf[mode] += ' ';
    3122         len++;
    3123         cc->col[mode]++;
    3124     }
    3125     cc->newcol[mode] = 0;
    3126 
    3127     return len;
    3128 }
    3129 
    31302495static void vbi_event(struct VBIData *data, struct vt_event *ev)
    31312496{
    31322497    switch (ev->type)
  • libs/libmythtv/libmythtv.pro

     
    9090HEADERS += recordingtypes.h         jobqueue.h
    9191HEADERS += filtermanager.h          recordingprofile.h
    9292HEADERS += remoteencoder.h          videosource.h
     93HEADERS += ccdecoder.h
    9394HEADERS += sr_dialog.h              sr_root.h
    9495HEADERS += sr_items.h               scheduledrecording.h
    9596HEADERS += signalmonitorvalue.h
     
    104105SOURCES += recordingtypes.cpp       jobqueue.cpp
    105106SOURCES += filtermanager.cpp        recordingprofile.cpp
    106107SOURCES += remoteencoder.cpp        videosource.cpp
     108SOURCES += ccdecoder.cpp
    107109SOURCES += sr_dialog.cpp            sr_root.cpp
    108110SOURCES += sr_items.cpp             scheduledrecording.cpp
    109111SOURCES += signalmonitorvalue.cpp
  • libs/libmythtv/ccdecoder.h

     
     1#ifndef CCDECODER_H_
     2#define CCDECODER_H_
     3
     4#include <qstringlist.h>
     5
     6#include "format.h"
     7
     8class CCReader
     9{
     10  public:
     11    virtual ~CCReader() { }
     12    virtual void AddTextData(unsigned char *buf, int len, long long timecode, char type) = 0;
     13};
     14
     15class CCDecoder
     16{
     17  public:
     18    CCDecoder(CCReader *ccr);
     19    ~CCDecoder();
     20
     21    void FormatCC(int tc, int code1, int code2);
     22    void FormatCCField(int tc, int field, int data);
     23                                                         
     24  private:
     25    QChar CharCC(int code) { return stdchar[code]; }
     26    void ResetCC(int mode);
     27    void BufferCC(int mode, int len, int clr);
     28    int NewRowCC(int mode, int len);
     29
     30    CCReader *reader;
     31
     32    // per-field
     33    int badvbi[2];
     34    int lasttc[2];
     35    int lastcode[2];
     36    int lastcodetc[2];
     37    int ccmode[2];      // 0=cc1/txt1, 1=cc2/txt2
     38    int txtmode[4];
     39    int xds[2];
     40
     41    // per-mode state
     42    int lastrow[8];
     43    int newrow[8];
     44    int newcol[8];
     45    int timecode[8];
     46    int row[8];
     47    int col[8];
     48    int rowcount[8];
     49    int style[8];
     50    int linecont[8];
     51    int resumetext[8];
     52    int lastclr[8];
     53    QString ccbuf[8];
     54
     55    // translation table
     56    QChar stdchar[128];
     57
     58    // temporary buffer
     59    unsigned char *rbuf;
     60};
     61
     62#endif
  • libs/libmythtv/ccdecoder.cpp

     
     1#include <qstringlist.h>
     2#include <iostream>
     3using namespace std;
     4
     5#include "format.h"
     6#include "ccdecoder.h"
     7
     8CCDecoder::CCDecoder(CCReader *ccr)
     9{
     10    reader = ccr;
     11
     12    for (int i = 0; i < 2; i++)
     13    {
     14        badvbi[i] = 0;
     15        lasttc[i] = 0;
     16        lastcode[i] = -1;
     17        lastcodetc[i] = 0;
     18        ccmode[i] = -1;
     19        txtmode[i*2 + 0] = 0;
     20        txtmode[i*2 + 1] = 0;
     21        xds[i] = 0;
     22    }
     23
     24    for (int i = 0; i < 8; i++)
     25    {
     26        lastrow[i] = 0;
     27        newrow[i] = 0;
     28        newcol[i] = 0;
     29        timecode[i] = 0;
     30        row[i] = 0;
     31        col[i] = 0;
     32        rowcount[i] = 0;
     33        style[i] = 0;
     34        linecont[i] = 0;
     35        resumetext[i] = 0;
     36        lastclr[i] = 0;
     37        ccbuf[i] = "";
     38    }
     39
     40    // fill translation table
     41    for (int i = 0; i < 128; i++)
     42        stdchar[i] = QChar(i);
     43
     44    // exceptions
     45    stdchar[42] = 'á';
     46    stdchar[92] = 'é';
     47    stdchar[94] = 'í';
     48    stdchar[95] = 'ó';
     49    stdchar[96] = 'ú';
     50    stdchar[123] = 'ç';
     51    stdchar[124] = '÷';
     52    stdchar[125] = 'Ñ';
     53    stdchar[126] = 'ñ';
     54    stdchar[127] = 0x2588; /* full block */
     55
     56    rbuf = new unsigned char[sizeof(ccsubtitle)+255];
     57}
     58
     59CCDecoder::~CCDecoder(void)
     60{
     61    delete rbuf;
     62}
     63
     64void CCDecoder::FormatCC(int tc, int code1, int code2)
     65{
     66    FormatCCField(tc, 0, code1);
     67    FormatCCField(tc, 1, code2);
     68}
     69
     70void CCDecoder::FormatCCField(int tc, int field, int data)
     71{
     72    const int rowdata[] = { 11, -1, 1, 2, 3, 4, 12, 13,
     73                            14, 15, 5, 6, 7, 8, 9, 10 };
     74    const QChar specialchar[] =
     75    { '®', '°', 'œ', '¿', 0x2122 /* TM */, '¢', '£', 0x266A /* 1/8 note */,
     76      'à', ' ', 'è', 'â', 'ê', 'î', 'ô', 'û'
     77    };
     78    const QChar extendedchar2[] =
     79    { 'Á', 'É', 'Ó', 'Ú', 'Ü', 'ü', '`', '¡',
     80      '*', '\'', 0x2014 /* dash */, '©', 0x2120 /* SM */, '·', 0x201C, 0x201D /* dquotes */,
     81      'À', 'Â', 'Ç', 'È', 'Ê', 'Ë', 'ë', 'Î',
     82      'Ï', 'ï', 'Ô', 'Ù', 'ù', 'Û', '«', '»'
     83    };
     84    const QChar extendedchar3[] =
     85    { 'Ã', 'ã', 'Í', 'Ì', 'ì', 'Ò', 'ò', 'Õ',
     86      'õ', '{', '}', '\\', '^', '_', 'Š', '~',
     87      'Ä', 'ä', 'Ö', 'ö', 'ß', '¥', '€', '|',
     88      'Å', 'å', 'Ø', 'ø', 0x250C, 0x2510, 0x2514, 0x2518 /* box drawing */
     89    };
     90    int b1, b2, len, x;
     91    int mode;
     92
     93    if (data == -1)              // invalid data. flush buffers to be safe.
     94    {
     95        // TODO:  flush reader buffer
     96        if (ccmode[field] != -1)
     97        {
     98            for (mode = field*4; mode < (field*4 + 4); mode++)
     99                ResetCC(mode);
     100            xds[field] = 0;
     101            badvbi[field] = 0;
     102            ccmode[field] = -1;
     103            txtmode[field*2] = 0;
     104            txtmode[field*2 + 1] = 0;
     105        }
     106        return;
     107    }
     108
     109    b1 = data & 0x7f;
     110    b2 = (data >> 8) & 0x7f;
     111//    printf("%10d:  %02x %02x\n", tc, b1, b2);
     112    if (ccmode[field] >= 0)
     113    {
     114        mode = field << 2 |
     115               (txtmode[field*2 + ccmode[field]] << 1) |
     116               ccmode[field];
     117        len = ccbuf[mode].length();
     118    }
     119    else
     120    {
     121        mode = -1;
     122        len = 0;
     123    }
     124
     125    // bttv-0.9 VBI reads are pretty reliable (1 read/33367us).
     126    // bttv-0.7 reads don't seem to work as well so if read intervals
     127    // vary from this, be more conservative in detecting duplicate
     128    // CC codes.
     129    int dup_text_fudge, dup_ctrl_fudge;
     130    if (badvbi[field] < 100 && b1 != 0 && b2 != 0)
     131    {
     132        int d = tc - lasttc[field];
     133        if (d < 25 || d > 42)
     134            badvbi[field]++;
     135        else if (badvbi[field] > 0)
     136            badvbi[field]--;
     137    }
     138    if (badvbi[field] < 4)
     139    {
     140        dup_text_fudge = -2;  // should pick up all codes
     141        dup_ctrl_fudge = 33 - 4;  // should pick up 1st, 4th, 6th, 8th, ... codes
     142    }
     143    else
     144    {
     145        dup_text_fudge = 4;
     146        dup_ctrl_fudge = 33 - 4;
     147    }
     148
     149    if (data == lastcode[field])
     150    {
     151        int false_dup = 1;
     152        if ((b1 & 0x70) == 0x10)
     153        {
     154            if (tc > (lastcodetc[field] + 67 + dup_ctrl_fudge))
     155                false_dup = 0;
     156        }
     157        else if (b1)
     158        {
     159            // text, XDS
     160            if (tc > (lastcodetc[field] + 33 + dup_text_fudge))
     161                false_dup = 0;
     162        }
     163
     164        if (false_dup)
     165            goto skip;
     166    }
     167
     168    if ((field == 1) &&
     169        (xds[field] || b1 && ((b1 & 0x70) == 0x00)))
     170        // 0x01 <= b1 <= 0x0F
     171        // start XDS
     172        // or inside XDS packet
     173    {
     174        int xds_packet = 1;
     175
     176        // TODO: process XDS packets
     177        if (b1 == 0x0F)
     178        {
     179            // end XDS
     180            xds[field] = 0;
     181            xds_packet = 1;
     182        }
     183        else if ((b1 & 0x70) == 0x10)
     184        {
     185            // ctrl code -- interrupt XDS
     186            xds[field] = 0;
     187            xds_packet = 0;
     188        }
     189        else
     190        {
     191            xds[field] = 1;
     192            xds_packet = 1;
     193        }
     194
     195        if (xds_packet)
     196            goto skip;
     197    }
     198
     199    if (b1 & 0x60)
     200        // 0x20 <= b1 <= 0x7F
     201        // text codes
     202    {
     203        if (mode >= 0)
     204        {
     205            lastcodetc[field] += 33;
     206            timecode[mode] = tc;
     207
     208            // commit row number only when first text code
     209            // comes in
     210            if (newrow[mode])
     211                len = NewRowCC(mode, len);
     212
     213            ccbuf[mode] += CharCC(b1);
     214            len++;
     215            col[mode]++;
     216            if (b2 & 0x60)
     217            {
     218                ccbuf[mode] += CharCC(b2);
     219                len++;
     220                col[mode]++;
     221            }
     222        }
     223    }
     224
     225    else if ((b1 & 0x10) && (b2 > 0x1F))
     226        // 0x10 <= b1 <= 0x1F
     227        // control codes
     228    {
     229        lastcodetc[field] += 67;
     230
     231        int newccmode = (b1 >> 3) & 1;
     232        int newtxtmode = txtmode[field*2 + newccmode];
     233        if ((b1 & 0x06) == 0x04)
     234        {
     235            switch (b2)
     236            {
     237            case 0x29:
     238            case 0x2C:
     239            case 0x20:
     240            case 0x2F:
     241            case 0x25:
     242            case 0x26:
     243            case 0x27:
     244                // CC1,2
     245                newtxtmode = 0;
     246                break;
     247            case 0x2A:
     248            case 0x2B:
     249                // TXT1,2
     250                newtxtmode = 1;
     251                break;
     252            }
     253        }
     254        ccmode[field] = newccmode;
     255        txtmode[field*2 + newccmode] = newtxtmode;
     256        mode = (field << 2) | (newtxtmode << 1) | ccmode[field];
     257
     258        timecode[mode] = tc;
     259        len = ccbuf[mode].length();
     260
     261        if (b2 & 0x40)           //preamble address code (row & indent)
     262        {
     263            if (newtxtmode)
     264                // no address codes in TXT mode?
     265                goto skip;
     266
     267            newrow[mode] = rowdata[((b1 << 1) & 14) | ((b2 >> 5) & 1)];
     268            if (newrow[mode] == -1)
     269                // bogus code?
     270                newrow[mode] = lastrow[mode] + 1;
     271
     272            if (b2 & 0x10)        //row contains indent flag
     273                newcol[mode] = (b2 & 0x0E) << 1;
     274            else
     275                newcol[mode] = 0;
     276
     277            // row, indent settings are not final
     278            // until text code arrives
     279        }
     280        else
     281        {
     282            switch (b1 & 0x07)
     283            {
     284               case 0x00:          //attribute
     285                  /*
     286                   printf ("<ATTRIBUTE %d %d>\n", b1, b2);
     287                   fflush (stdout);
     288                   */
     289                   break;
     290               case 0x01:          //midrow or char
     291                   if (newrow[mode])
     292                       len = NewRowCC(mode, len);
     293
     294                   switch (b2 & 0x70)
     295                   {
     296                       case 0x20:      //midrow attribute change
     297                           // TODO: we _do_ want colors, is that an attribute?
     298                           ccbuf[mode] += ' ';
     299                           len = ccbuf[mode].length();
     300                           col[mode]++;
     301                           break;
     302                       case 0x30:      //special character..
     303                           ccbuf[mode] += specialchar[b2 & 0x0f];
     304                           len++;
     305                           col[mode]++;
     306                           break;
     307                   }
     308                   break;
     309               case 0x02:          //extended char
     310                   // extended char is preceded by alternate char
     311                   // - if there's no alternate, it could be noise
     312                   if (!len)
     313                       break;
     314
     315                   if (b2 & 0x30)
     316                   {
     317                       ccbuf[mode].remove(len - 1, 1);
     318                       ccbuf[mode] += extendedchar2[b2 - 0x20];
     319                       len = ccbuf[mode].length();
     320                       break;
     321                   }
     322                   break;
     323               case 0x03:          //extended char
     324                   // extended char is preceded by alternate char
     325                   // - if there's no alternate, it could be noise
     326                   if (!len)
     327                       break;
     328
     329                   if (b2 & 0x30)
     330                   {
     331                       ccbuf[mode].remove(len - 1, 1);
     332                       ccbuf[mode] += extendedchar3[b2 - 0x20];
     333                       len = ccbuf[mode].length();
     334                       break;
     335                   }
     336                   break;
     337               case 0x04:          //misc
     338               case 0x05:          //misc + F
     339//                 printf("ccmode %d cmd %02x\n",ccmode,b2);
     340                   switch (b2)
     341                   {
     342                       case 0x21:      //backspace
     343                           // add backspace if line has been encoded already
     344                           if (newrow[mode])
     345                               len = NewRowCC(mode, len);
     346
     347                           if (len == 0 ||
     348                               ccbuf[mode].left(1) == "\b")
     349                           {
     350                               ccbuf[mode] += (char)'\b';
     351                               len++;
     352                               col[mode]--;
     353                           }
     354                           else
     355                           {
     356                               ccbuf[mode].remove(len - 1, 1);
     357                               len = ccbuf[mode].length();
     358                               col[mode]--;
     359                           }
     360                           break;
     361                       case 0x25:      //2 row caption
     362                       case 0x26:      //3 row caption
     363                       case 0x27:      //4 row caption
     364                           if (style[mode] == CC_STYLE_PAINT && len)
     365                           {
     366                               // flush
     367                               BufferCC(mode, len, 0);
     368                               ccbuf[mode] = "";
     369                               row[mode] = 0;
     370                               col[mode] = 0;
     371                           }
     372                           else if (style[mode] == CC_STYLE_POPUP)
     373                               ResetCC(mode);
     374
     375                           rowcount[mode] = b2 - 0x25 + 2;
     376                           style[mode] = CC_STYLE_ROLLUP;
     377                           break;
     378                       case 0x2D:      //carriage return
     379                           if (style[mode] != CC_STYLE_ROLLUP)
     380                               break;
     381
     382                           if (newrow[mode])
     383                               row[mode] = newrow[mode];
     384
     385                           // flush if there is text or need to scroll
     386                           // TODO:  decode ITV (WebTV) link in TXT2
     387                           if (len ||
     388                               row[mode] != 0 &&
     389                               !linecont[mode] &&
     390                               (!newtxtmode || row[mode] >= 16))
     391                               BufferCC(mode, len, 0);
     392
     393                           if (newtxtmode)
     394                           {
     395                               if (row[mode] < 16)
     396                                   newrow[mode] = row[mode] + 1;
     397                               else
     398                                   // scroll up previous lines
     399                                   newrow[mode] = 16;
     400                           }
     401
     402                           ccbuf[mode] = "";
     403                           col[mode] = 0;
     404                           linecont[mode] = 0;
     405                           break;
     406
     407                       case 0x29:      //resume direct caption (paint-on style)
     408                           if (style[mode] == CC_STYLE_ROLLUP && len)
     409                           {
     410                               // flush
     411                               BufferCC(mode, len, 0);
     412                               ccbuf[mode] = "";
     413                               row[mode] = 0;
     414                               col[mode] = 0;
     415                           }
     416                           else if (style[mode] == CC_STYLE_POPUP)
     417                               ResetCC(mode);
     418
     419                           style[mode] = CC_STYLE_PAINT;
     420                           rowcount[mode] = 0;
     421                           linecont[mode] = 0;
     422                           break;
     423
     424                       case 0x2B:      //resume text display
     425                           resumetext[mode] = 1;
     426                           if (row[mode] == 0)
     427                           {
     428                               newrow[mode] = 1;
     429                               newcol[mode] = 0;
     430                           }
     431                           style[mode] = CC_STYLE_ROLLUP;
     432                           break;
     433                       case 0x2C:      //erase displayed memory
     434                           if ((tc - lastclr[mode]) > 5000 ||
     435                               lastclr[mode] == 0)
     436                               // don't overflow the frontend with
     437                               // too many redundant erase codes
     438                               BufferCC(mode, 0, 1);
     439                           if (style[mode] != CC_STYLE_POPUP)
     440                           {
     441                               row[mode] = 0;
     442                               col[mode] = 0;
     443                           }
     444                           linecont[mode] = 0;
     445                           break;
     446
     447                       case 0x20:      //resume caption (pop-up style)
     448                           if (style[mode] != CC_STYLE_POPUP)
     449                           {
     450                               if (len)
     451                                   // flush
     452                                   BufferCC(mode, len, 0);
     453                               ccbuf[mode] = "";
     454                               row[mode] = 0;
     455                               col[mode] = 0;
     456                           }
     457                           style[mode] = CC_STYLE_POPUP;
     458                           rowcount[mode] = 0;
     459                           linecont[mode] = 0;
     460                           break;
     461                       case 0x2F:      //end caption + swap memory
     462                           if (style[mode] != CC_STYLE_POPUP)
     463                           {
     464                               if (len)
     465                                   // flush
     466                                   BufferCC(mode, len, 0);
     467                           }
     468                           else if ((tc - lastclr[mode]) > 5000 ||
     469                                    lastclr[mode] == 0)
     470                               // clear and flush
     471                               BufferCC(mode, len, 1);
     472                           else if (len)
     473                               // flush
     474                               BufferCC(mode, len, 0);
     475                           ccbuf[mode] = "";
     476                           row[mode] = 0;
     477                           col[mode] = 0;
     478                           style[mode] = CC_STYLE_POPUP;
     479                           rowcount[mode] = 0;
     480                           linecont[mode] = 0;
     481                           break;
     482
     483                       case 0x2A:      //text restart
     484                           // clear display
     485                           BufferCC(mode, 0, 1);
     486                           ResetCC(mode);
     487                           // TXT starts at row 1
     488                           newrow[mode] = 1;
     489                           newcol[mode] = 0;
     490                           style[mode] = CC_STYLE_ROLLUP;
     491                           break;
     492
     493                       case 0x2E:      //erase non-displayed memory
     494                           ResetCC(mode);
     495                           break;
     496                   }
     497                   break;
     498               case 0x07:          //misc (TAB)
     499                   if (newrow[mode])
     500                   {
     501                       newcol[mode] += (b2 & 0x03);
     502                       len = NewRowCC(mode, len);
     503                   }
     504                   else
     505                       // illegal?
     506                       for (x = 0; x < (b2 & 0x03); x++)
     507                       {
     508                           ccbuf[mode] += ' ';
     509                           len++;
     510                           col[mode]++;
     511                       }
     512                   break;
     513            }
     514        }
     515    }
     516
     517skip:
     518    for (mode = field*4; mode < (field*4 + 4); mode++)
     519    {
     520        len = ccbuf[mode].length();
     521        if (((tc - timecode[mode]) > 100) &&
     522            (style[mode] != CC_STYLE_POPUP) && len)
     523        {
     524            // flush unfinished line if waiting too long
     525            // in paint-on or scroll-up mode
     526            timecode[mode] = tc;
     527            BufferCC(mode, len, 0);
     528            ccbuf[mode] = "";
     529            row[mode] = lastrow[mode];
     530            linecont[mode] = 1;
     531        }
     532    }
     533
     534    if (data != lastcode[field])
     535    {
     536        lastcode[field] = data;
     537        lastcodetc[field] = tc;
     538    }
     539    lasttc[field] = tc;
     540}
     541
     542void CCDecoder::ResetCC(int mode)
     543{
     544//    lastrow[mode] = 0;
     545//    newrow[mode] = 0;
     546//    newcol[mode] = 0;
     547//    timecode[mode] = 0;
     548    row[mode] = 0;
     549    col[mode] = 0;
     550    rowcount[mode] = 0;
     551//    style[mode] = CC_STYLE_POPUP;
     552    linecont[mode] = 0;
     553    resumetext[mode] = 0;
     554    lastclr[mode] = 0;
     555    ccbuf[mode] = "";
     556}
     557
     558void CCDecoder::BufferCC(int mode, int len, int clr)
     559{
     560    QCString tmpbuf;
     561    if (len)
     562    {
     563        // calculate UTF-8 encoding length
     564        tmpbuf = ccbuf[mode].utf8();
     565        len = tmpbuf.length();
     566        if (len > 255)
     567            len = 255;
     568    }
     569
     570    unsigned char f;
     571    unsigned char *bp = rbuf;
     572    *(bp++) = row[mode];
     573    *(bp++) = rowcount[mode];
     574    *(bp++) = style[mode];
     575    // overload resumetext field
     576    f = resumetext[mode];
     577    f |= mode << 4;
     578    if (linecont[mode])
     579        f |= CC_LINE_CONT;
     580    *(bp++) = f;
     581    *(bp++) = clr;
     582    *(bp++) = len;
     583    if (len)
     584    {
     585        memcpy(bp,
     586               tmpbuf,
     587               len);
     588        len += sizeof(ccsubtitle);
     589    }
     590    else
     591        len = sizeof(ccsubtitle);
     592
     593    reader->AddTextData(rbuf, len, timecode[mode], 'C');
     594
     595    resumetext[mode] = 0;
     596    if (clr && !len)
     597        lastclr[mode] = timecode[mode];
     598    else if (len)
     599        lastclr[mode] = 0;
     600}
     601
     602int CCDecoder::NewRowCC(int mode, int len)
     603{
     604    if (style[mode] == CC_STYLE_ROLLUP)
     605    {
     606        // previous line was likely missing a carriage return
     607        row[mode] = newrow[mode];
     608        if (len)
     609        {
     610            BufferCC(mode, len, 0);
     611            ccbuf[mode] = "";
     612            len = 0;
     613        }
     614        col[mode] = 0;
     615        linecont[mode] = 0;
     616    }
     617    else
     618    {
     619        // popup/paint style
     620
     621        if (row[mode] == 0)
     622        {
     623            if (len == 0)
     624                row[mode] = newrow[mode];
     625            else
     626            {
     627                // previous line was missing a row address
     628                // - assume it was one row up
     629                ccbuf[mode] += (char)'\n';
     630                len++;
     631                if (row[mode] == 0)
     632                    row[mode] = newrow[mode] - 1;
     633                else
     634                    row[mode]--;
     635            }
     636        }
     637        else if (newrow[mode] > lastrow[mode])
     638        {
     639            // next line can be more than one row away
     640            for (int i = 0; i < (newrow[mode] - lastrow[mode]); i++)
     641            {
     642                ccbuf[mode] += (char)'\n';
     643                len++;
     644            }
     645            col[mode] = 0;
     646        }
     647        else if (newrow[mode] == lastrow[mode])
     648        {
     649            // same row
     650            if (newcol[mode] >= col[mode])
     651                // new line appends to current line
     652                newcol[mode] -= col[mode];
     653            else
     654            {
     655                // new line overwrites current line;
     656                // could be legal (overwrite spaces?) but
     657                // more likely we have bad address codes
     658                // - just move to next line; may exceed row 15
     659                // but frontend will adjust
     660                ccbuf[mode] += (char)'\n';
     661                len++;
     662                col[mode] = 0;
     663            }
     664        }
     665        else
     666        {
     667            // next line goes upwards (not legal?)
     668            // - flush
     669            BufferCC(mode, len, 0);
     670            ccbuf[mode] = "";
     671            row[mode] = newrow[mode];
     672            col[mode] = 0;
     673            linecont[mode] = 0;
     674            len = 0;
     675        }
     676    }
     677
     678    lastrow[mode] = newrow[mode];
     679    newrow[mode] = 0;
     680
     681    for (int x = 0; x < newcol[mode]; x++)
     682    {
     683        ccbuf[mode] += ' ';
     684        len++;
     685        col[mode]++;
     686    }
     687    newcol[mode] = 0;
     688
     689    return len;
     690}
     691
  • libs/libmythtv/NuppelVideoRecorder.h

     
    3030// MythTV headers
    3131#include "recorderbase.h"
    3232#include "format.h"
     33#include "ccdecoder.h"
    3334
    3435struct video_audio;
    3536struct VBIData;
     
    4041class FilterManager;
    4142class FilterChain;
    4243
    43 class NuppelVideoRecorder : public RecorderBase
     44class NuppelVideoRecorder : public RecorderBase, public CCReader
    4445{
    4546 public:
    4647    NuppelVideoRecorder(TVRec *rec, ChannelBase *channel);
     
    131132
    132133    void FormatTeletextSubtitles(struct VBIData *vbidata);
    133134    void FormatCC(struct cc *cc);
    134     void FormatCCField(struct cc *cc, int tc, int field);
    135     QChar CharCC(int code);
    136     void ResetCC(struct cc *cc, int mode);
    137     void BufferCC(struct cc *cc, int mode, int len, int clr);
    138     int NewRowCC(struct cc *cc, int mode, int len);
     135    void AddTextData(unsigned char *buf, int len, long long timecode, char type);
    139136   
    140137    bool encoding;
    141138   
     
    281278    bool correct_bttv;
    282279
    283280    int volume;
     281
     282    CCDecoder *ccd;
     283
    284284    bool go7007;
    285285};
    286286