source: svn/newcon3bcm2_21bu/BSEAV/lib/scte_27/scte_27.c

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 30.2 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2009, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile:  $
11 * $brcm_Revision:  $
12 * $brcm_Date: $
13 *
14 * Module Description:
15 *
16 * Revision History:
17 *
18 * $brcm_Log:  $
19 *
20 ***************************************************************************/
21#include "scte_27.h"
22#include "bstd.h"
23#include "getbits.h"
24#include "bapp.h"
25#include "gist.h"
26#include "bxpt_pcr.h"
27#include "bapp_task_priorities.h"
28#include "bapp_palette.h"
29#include "bgfx_types.h"
30
31BDBG_MODULE(scte_27);
32
33/* function prototype */
34void scte_27_handler(void *data);
35static bool scte_27_render_subtitle(pscte_27_handle pscte_27, scte_27_data *imme_pdata);
36
37//#define       SUBTITLE_DRAW_TEST              1
38
39#define SCTE_27_EVENT_TIME              25                      /* 10 ms */
40#define SCTE_27_MUTEX_TIME              100
41
42#define BITMAP_BUFFER_SIZE              25920           /* (720 * 576 / 8 / 2) half of screen should be enough */
43
44static scte_27_handle   s_scte_27;
45static subtitle_message scte_27_msg[MAX_SUBTITLE_MESSAGE];
46static scte_27_data             scte_27_data_array[MAX_SUBTITLE_MESSAGE];
47
48#define CLUT_MAX_ENTRIES        16
49#define CLUT_BG_INDEX                   12
50#define CLUT_FG_INDEX                   13
51#define CLUT_OUTLINE_INDEX              14
52#define CLUT_FRAME_INDEX                15
53
54#define abs(n)          __builtin_abs ((n))
55
56static uint32_t clut_color_entries[CLUT_MAX_ENTRIES] = { 0 };
57/* display standard */
58static uint8_t display_standard_array[4] = {
59        30,             /* DS_720_480_30 */
60    25,         /* DS_720_576_25 */
61    60,         /* DS_1280_720_60 */
62    60          /* DS_1920_1080_60 */
63};
64
65#ifndef SCTE_ASSERT
66#define SCTE_ASSERT(expr) {                                         \
67    if (!expr)                                                      \
68        printf("%s failed at %s:%d\n",#expr, __FILE__, __LINE__);   \
69    }
70#endif
71
72#define insert_list(list, data)         \
73        flags = bos_enter_critical();   \
74    inslt(&list, data);                         \
75    bos_exit_critical(flags)
76
77#define insert_list_head(list, data)\
78    flags = bos_enter_critical();   \
79    inslh(&list, data);             \
80    bos_exit_critical(flags)
81
82#define remove_list(list)               \
83    flags = bos_enter_critical();   \
84    pdata = remlh(&list);                       \
85    bos_exit_critical(flags)
86
87/*
88 * compare given PTS against currrent stc clock
89 *
90 * Parameters:
91 *  pscte_27    pointer to scte_27 handle
92 *      Tp                      pts for in-cue
93 *
94 * Returns:
95 *  0   if (Tp = Tc)
96 *  < 0 past
97 *      > 0 future
98 */
99static int scte_27_pts_stc_diff(pscte_27_handle pscte_27, uint32_t Tp)
100{
101        BXPT_PCR_Handle hPcr;
102        uint32_t Tc = 0, lo;
103
104        hPcr = GetDPCR();
105        if (NULL == hPcr) {
106                return 0;
107        }
108        BXPT_PCR_GetStc(hPcr, &Tc, &lo);
109        Tc += PCRS_PER_MSEC * 800;
110        if (Tp == Tc)
111                return 0;
112
113        /* 4.11 */
114        if (Tp < Tc) 
115                Tp = (uint32_t)Tp + 0xffffffff;         /* 0x100000000 */
116
117        if ((Tp - Tc) >= 0x80000000) {
118                return -1;              /* past */
119        }
120        else {
121                if (Tp >= Tc) {
122                        if ((Tp - Tc) <= (PCRS_PER_MSEC * (PCRS_PER_MSEC + 5)))
123                                return 0;
124                }       
125                return 1;               /* future */
126        }
127}
128
129/*
130 * This function is used to reset given list (which should be discard)
131 *
132 * Parameters:
133 *  pscte_27    pointer to scte_27 handle
134 *  which               which list.
135 *
136 * Returns:
137 *      1 if success
138 *      0 otherwise
139 */
140static bool scte_27_reset_list(pscte_27_handle pscte_27, int which)
141{
142    unsigned int    flags;
143    scte_27_data    *pdata = NULL;
144
145    BDBG_MSG(("%s: enter", __func__));
146
147#ifdef  DEBUG
148    if (NULL == pscte_27) {
149        BDBG_WRN(("%s: null pointer", __func__));
150        return false;
151    }
152#endif
153
154        if (SC_RENDER == which) {
155                while (pscte_27->render_list.count > 0) {
156                        remove_list(pscte_27->render_list);
157                        if (pdata) {
158                                if (pdata->msg->bitmap_data) {
159                                        free(pdata->msg->bitmap_data);
160                                        pdata->msg->bitmap_data = NULL;
161                                        pdata->msg->bitmap_size = 0;
162                                }
163                                /* put it back to free list */
164                                insert_list(pscte_27->free_list, pdata);
165                        }
166                }
167        }
168        if (SC_CLEAR == which) {
169        while (pscte_27->clear_list.count > 0) {
170            remove_list(pscte_27->clear_list);
171            if (pdata) {
172                /* put it back to free list */
173                insert_list(pscte_27->free_list, pdata);
174            }
175        }
176        }
177
178        BDBG_MSG(("%s: leave", __func__));
179        return true;
180}
181
182/*
183 * This function is used to reset scte 27.
184 *
185 * Parameters:
186 *  pscte_27    pointer to scte_27 handle
187 *
188 * Returns:
189 *      1 if success
190 *      0 otherwise
191 */
192bool scte_27_reset(pscte_27_handle pscte_27)
193{
194        BDBG_MSG(("%s: enter", __func__));
195
196#ifdef  DEBUG
197        if (NULL == pscte_27) {
198                BDBG_WRN(("%s: null pointer", __func__));
199                return false;
200        }
201#endif
202
203        scte_27_reset_list(pscte_27, SC_RENDER);
204        scte_27_reset_list(pscte_27, SC_CLEAR);
205
206        /* free segmented data buffer if any */
207        if (pscte_27->segment_data) {
208                free(pscte_27->segment_data);
209                pscte_27->segment_data = NULL;
210                pscte_27->segment_data_size = 0;
211        }
212        pscte_27->pdata = NULL;
213        pscte_27->segmented = false;
214
215        BDBG_MSG(("%s: leave", __func__));
216        return true;
217}
218
219/*
220 * This function is used to initialize scte 27 object
221 *
222 * Parameters:
223 *      v_app           pointer to application structure
224 *
225 * Returns:
226 *      pointer to scte_27_handle if success
227 *      NULL otherwise
228 */
229pscte_27_handle scte_27_init(void *v_app)
230{
231        pscte_27_handle pscte_27 = &s_scte_27;
232        unsigned int *palette, palette_size;            /* palette pointer */
233        b_task_params   params;
234        int i;
235        scte_27_data    *pdata = NULL;
236
237        BDBG_MSG(("%s: enter", __func__));
238#ifdef  DEBUG
239        if (!p_app) {
240                BDBG_ERR(("%s: null ptr", __func__));
241                return NULL;
242        }
243#endif
244
245        memset(pscte_27, 0, sizeof(scte_27_handle));
246        /* keep application pointer to later use */
247        pscte_27->v_app = v_app;
248
249        SCTE_ASSERT(b_ok == bos_create_mutex(&pscte_27->mutex));
250        pscte_27->bitmap = malloc(BITMAP_BUFFER_SIZE);
251        SCTE_ASSERT(pscte_27->bitmap);
252        SCTE_ASSERT(b_ok == bos_create_queue(&pscte_27->queue, pscte_27->event, MAX_SUBTITLE_EVENTS));
253
254        bapp_palette_get(ePALETTE_APP,(unsigned int **)&palette, &palette_size);
255
256        /* last 4 in CLUT entried are used for subtitle, but we just set the values for all entries */
257        for (i = 0; i <= CLUT_FRAME_INDEX; i++) {
258                clut_color_entries[i] = *(palette + i);
259        }
260        /* initialize all the list  */
261        initl(&pscte_27->free_list);
262        initl(&pscte_27->render_list);
263        initl(&pscte_27->clear_list);
264
265    /* free list */
266    for (i = 0; i < MAX_SUBTITLE_MESSAGE; i++) {
267        pdata = &scte_27_data_array[i];
268        pdata->msg = &scte_27_msg[i];
269                inslt(&pscte_27->free_list, pdata);
270    }
271        scte_27_reset(pscte_27);
272
273        pscte_27->cmd_array[SC_RENDER] = SC_RENDER;
274        pscte_27->cmd_array[SC_CLEAR] = SC_CLEAR;
275
276        params.priority = SCTE_27_PRIORITY;
277        params.stack = pscte_27->stack;
278        params.name = "scte_27_task";
279        params.stack_size = SCTE_27_STK_SIZE;
280        /* enable scte 27 task */
281        bos_start_task(&pscte_27->task, &params, scte_27_handler, pscte_27);
282
283        BDBG_MSG(("%s: leave", __func__));
284        return pscte_27;
285}
286
287/*
288 * This function is used to de-initialize scte 27 object initialized before
289 *
290 * Parameters:
291 *      pointer to scte 27 handle
292 *
293 * Returns:
294 *      NONE
295 */
296void scte_27_deinit(pscte_27_handle pscte_27)
297{
298        BDBG_MSG(("%s: enter", __func__));
299
300        if (!pscte_27) {
301                BDBG_MSG(("%s: null pointer", __func__));
302                return;
303        }
304        if (pscte_27->bitmap)
305                free(pscte_27->bitmap);
306        scte_27_reset(pscte_27);
307        if (&pscte_27->mutex)
308                bos_delete_mutex(&pscte_27->mutex);
309        if (pscte_27->stack)
310                free(pscte_27->stack);
311        //free(pscte_27);
312        BDBG_MSG(("%s: leave", __func__));
313}
314
315/*
316 * enable/disable SCTE 27 subtitle
317 *
318 * Parameters:
319 *  pscte_27    pointer to scte_27 handle
320 *  enable      enable/disable SCTE 27 module
321 *
322 * Returns:
323 *      NONE
324 */
325void scte_27_enable(pscte_27_handle pscte_27, int enable)
326{
327        if (bos_acquire_mutex(&pscte_27->mutex, 0) != b_ok) {
328                BDBG_ERR(("%s bos_acquire_mutex failed (enable = %d)\n",__func__,enable));
329                return;
330        }
331
332        if (pscte_27->enabled == enable) {
333                bos_release_mutex(&pscte_27->mutex);
334                return;
335        }
336        pscte_27->enabled = enable;
337        bos_release_mutex(&pscte_27->mutex);
338}
339
340/*
341 * SCTE 27 subtitle message parser
342 *
343 * Parameters:
344 *  pscte_27    pointer to scte_27 handle
345 *  data                pointer to scte_27 message data buffer
346 *      length          data bufer length
347 *      hdr                     pointer to header that will hold the message header parsed
348 *
349 * Returns:
350 *      true            if parse the data correctly
351 *      false           if anything is wrong
352 */
353
354bool scte_27_parse_subtitle(pscte_27_handle pscte_27, unsigned char *data, int length, scte_27_data *pdata)
355{
356        struct bit_state_t bits, *bs;
357        subtitle_message    *hdr;
358        uint32_t flags;
359        BXPT_PCR_Handle hPcr = NULL;
360        uint32_t hi, lo;
361
362        bs = &bits;
363        bits.data = data;
364        bits.bindex = 0;
365
366#ifdef  DEBUG
367        if (!pscte_27 || !data || (length < 10) || !pdata) {
368                BDBG_WRN(("%s: null ptr or zero data", __func__));
369                return false;
370        }
371#endif
372        hdr = pdata->msg;
373
374        hdr->table_ID = get_bits(8, bs);
375        if (SUBTITLE_SECTION_ID != hdr->table_ID) {
376                BDBG_WRN(("%s: invalid subtitle message", __func__));
377                return false;
378        }
379
380        get_bits(4, bs);                /* skip zero and ISO reserved bits */
381        hdr->section_length = get_bits(12, bs);
382        if (hdr->section_length > (length - 3)) {
383                BDBG_WRN(("%s: section_length out of range", __func__));
384                return false;
385        }
386
387        get_bits(1, bs);
388        hdr->segmentation_overlay_included = get_bits(1, bs);
389        /* protocol version */
390        if (0 != get_bits(6, bs)) {
391                BDBG_WRN(("%s: protocol version not zero", __func__));
392                return false;
393        }
394
395        if (hdr->segmentation_overlay_included) {
396                hdr->table_extension = get_bits(16, bs);
397                hdr->last_segment_number = get_bits(12, bs);
398                hdr->segment_number = get_bits(12, bs);
399
400                /* following packets of same table extension */
401                if (pscte_27->segmented) {
402                        if ((hdr->table_extension != pscte_27->table_extension) || ((pscte_27->segment_number + 1) != hdr->segment_number) ||
403                                (hdr->segment_number > pscte_27->last_segment_number) || (pscte_27->segment_data_size != (hdr->section_length - 10))) {
404                                BDBG_WRN(("%s: segmented data not match. table=(0x%04x,0x%04x),sn=(%d,%d),lsn=(%d,%d),slen=(%d,%d)", __func__,
405                                        pscte_27->table_extension,pscte_27->table_extension, hdr->segment_number, pscte_27->segment_number, 
406                                        pscte_27->last_segment_number, hdr->last_segment_number, pscte_27->segment_data_size, hdr->section_length - 10));
407                                goto EXIT_PARSER;
408                        }
409                        bs->data = bs->data + (bs->bindex >> 3);                /* should be data byte 9 */
410                        memcpy(pscte_27->segment_data + (pscte_27->segment_data_size * hdr->segment_number), bs->data, pscte_27->segment_data_size);
411                        /* if last segment */
412                        if (hdr->segment_number == pscte_27->last_segment_number) {
413                                BDBG_WRN(("%s: packets assembled and ready to render!", __func__));
414                                pscte_27->segmented = false;
415                                pscte_27->pdata = NULL;
416                                /* ready to process subtitle body assembled */
417                                bits.data = pscte_27->segment_data;
418                                bits.bindex = 0;
419                        } else {
420                                pscte_27->segment_number = hdr->segment_number;
421                                return true;
422                        }
423                } else {
424                        int size;
425
426                        /* validate for first of segment packet */
427                        if (0 != hdr->segment_number || (hdr->last_segment_number < 1)) {
428                                BDBG_WRN(("%s: not a valid segment packet. Discard!", __func__));
429                                return false;
430                        }
431                        /* all coming message will have same size of body */
432                        pscte_27->segment_data_size = (hdr->section_length - 10);
433                        /* allow buffer to hold all message body */
434                        size = pscte_27->segment_data_size * (hdr->last_segment_number + 1); 
435                        pscte_27->segment_data = malloc(size); 
436                        if (!pscte_27->segment_data) {
437                                BDBG_WRN(("%s: out of memory. Discard all %d segmented packets", __func__, hdr->last_segment_number + 1));
438                                goto EXIT_PARSER;
439                        }
440                        bs->data = bs->data + (bs->bindex >> 3);                /* should be data byte 9 */
441                        memcpy(pscte_27->segment_data, bs->data, pscte_27->segment_data_size);
442                        /* remember current segment for validating coming packets of same table extension */
443                        pscte_27->table_extension = hdr->table_extension;
444                        pscte_27->last_segment_number = hdr->last_segment_number;
445                        pscte_27->segment_number = hdr->segment_number;
446                        pscte_27->segmented = true;
447                        /* need to reuse same data structure for coming packets of same table extension */
448                        pscte_27->pdata = pdata;
449                        return true;
450                }
451        }
452
453        /* should we check language match here? */
454        hdr->ISO_639_language_code = get_bits_aligned(24, bs);
455        /* display modes */
456        hdr->pre_clear_display = get_bits(1, bs);
457        hdr->immediate = get_bits(1, bs);
458#ifdef  SUBTITLE_DRAW_TEST
459        hdr->immediate = true;
460#endif
461
462        get_bits(1, bs);        /* skip reserved */
463        /* display stardards */
464        hdr->display_standard = get_bits(5, bs);
465        if (hdr->display_standard >= 2) {
466                BDBG_WRN(("%s: don't support given display format %d", __func__, hdr->display_standard));
467                goto EXIT_PARSER;
468        }
469        /* in-cue time */
470        hdr->display_in_PTS = get_bits_aligned(32, bs);
471        hdr->display_in_PTS = (hdr->display_in_PTS >> 1);       /* convert to 45KHz clock */
472        hdr->subtitle_type = get_bits(4, bs);
473    if (SUBTITLE_TYPE_SIMPLE_BITMAP != hdr->subtitle_type) {
474        BDBG_WRN(("%s: bitmap type %d is not simple bitmap", __func__, hdr->subtitle_type));
475        goto EXIT_PARSER;
476    }
477        get_bits(1, bs);        /* skip reserved */
478        hdr->display_duration = get_bits(11, bs);
479        hdr->block_length = get_bits(16, bs);
480
481        /* simple bitmap, continue parse */
482        get_bits(5, bs);
483        hdr->background_style = get_bits(1, bs);
484        hdr->outline_style = get_bits(2, bs);
485
486        hdr->Y_component = get_bits(5, bs);
487        hdr->opaque_enable = get_bits(1, bs);
488        hdr->Cr_component = get_bits(5, bs);
489        hdr->Cb_component = get_bits(5, bs);
490
491        /* character color */
492        hdr->bitmap_top_H_coordinate = get_bits(12, bs);
493        hdr->bitmap_top_V_coordinate = get_bits(12, bs);
494        hdr->bitmap_bottom_H_coordinate = get_bits(12, bs);
495        hdr->bitmap_bottom_V_coordinate = get_bits(12, bs);
496
497        /* Calculate the height and width from top and bottom coordinates */
498        if ((hdr->bitmap_bottom_V_coordinate < hdr->bitmap_top_V_coordinate) ||
499                (hdr->bitmap_bottom_H_coordinate < hdr->bitmap_top_H_coordinate)) {
500                BDBG_WRN(("%s: bad bitmap coordinate", __func__));
501                goto EXIT_PARSER;
502        }
503
504        /* if framed background style */
505        if (hdr->background_style) {
506                hdr->frame_top_H_coordinate = get_bits(12, bs);
507                hdr->frame_top_V_coordinate = get_bits(12, bs);
508                hdr->frame_bottom_H_coordinate = get_bits(12, bs);
509                hdr->frame_bottom_V_coordinate = get_bits(12, bs);
510                hdr->frame_Y_component = get_bits(5, bs);
511                hdr->frame_opaque_enable = get_bits(1, bs);
512                hdr->frame_Cr_component = get_bits(5, bs);
513                hdr->frame_Cb_component = get_bits(5, bs);
514        }
515
516        /* if outlined outline style */
517        if (OS_OUTLINE == hdr->outline_style) {
518                get_bits(4, bs);        /* skip reserved */
519                hdr->outline_thickness = get_bits(4, bs);
520                hdr->outline_Y_component = get_bits(5, bs);
521                hdr->outline_opaque_enable = get_bits(1, bs);
522                hdr->outline_Cr_component = get_bits(5, bs);
523                hdr->outline_Cb_component = get_bits(5, bs);
524        } else if (OS_DROP_SHADOW == hdr->outline_style) {
525                hdr->shadow_right = get_bits(4, bs);
526                hdr->shadow_bottom = get_bits(4, bs);
527                hdr->shadow_Y_component = get_bits(5, bs);
528                hdr->shadow_opaque_enable = get_bits(1, bs);
529                hdr->shadow_Cr_component = get_bits(5, bs);
530                hdr->shadow_Cb_component = get_bits(5, bs);
531        } else if (OS_RESERVED == hdr->outline_style) {
532                /* what should we do */
533                get_bits_aligned(24, bs);
534        } else {
535                BDBG_WRN(("%s: unsupported outline style %d", __func__, hdr->background_style));
536                goto EXIT_PARSER;
537        }
538
539        hdr->bitmap_length = get_bits(16, bs);
540
541        if (hdr->bitmap_data) {
542                BDBG_WRN(("%s: bitmap_data allocated?", __func__));
543                free(hdr->bitmap_data);
544        }
545        hdr->bitmap_data = malloc(hdr->bitmap_length); 
546        if (!hdr->bitmap_data) {
547                BDBG_WRN(("%s: out of memory, %d", __func__, hdr->bitmap_length));
548                goto EXIT_PARSER;
549        }
550
551        /* position pointer to compressed data */
552        bs->data = bs->data + (bs->bindex >> 3);
553        /* copy compressed data for later process */
554        memcpy(hdr->bitmap_data, bs->data, hdr->bitmap_length);
555
556        hPcr = GetDPCR();
557        if (NULL == hPcr) {
558                hi = 0;
559        }
560        else
561                BXPT_PCR_GetStc(hPcr, &hi, &lo);
562
563        /* if rendering immediaterly */
564        if (hdr->immediate) {
565                /* discard any pending render subtitle if any per section 4.1 */
566                if (pscte_27->render_list.count)
567                        scte_27_reset_list(pscte_27, SC_RENDER);
568                /* if subtitle already rendered, clear screen first */
569                if (pscte_27->clear_list.count) {
570                        scte_27_reset_list(pscte_27, SC_CLEAR);
571                        hdr->pre_clear_display = true;
572                }
573#ifndef SUBTITLE_DRAW_TEST
574                hdr->display_in_PTS = hi;
575#endif
576        }
577        hdr->display_out_PTS = hdr->display_in_PTS + 
578                ((hdr->display_duration * PCRS_PER_SEC) / display_standard_array[hdr->display_standard]);   
579        BDBG_MSG(("####### in=%lx, out=%lx, stc=%x, diff(out-in)=%d\n", hdr->display_in_PTS, hdr->display_out_PTS, hi, (hdr->display_out_PTS - hdr->display_in_PTS)));
580        if (hdr->immediate) {
581                scte_27_render_subtitle(pscte_27, pdata);
582        }
583        else {
584                insert_list(pscte_27->render_list, pdata);
585                /* post render event */
586                bos_post_event(pscte_27->queue, (b_event_t*)&pscte_27->cmd_array[SC_RENDER]);
587        }
588       
589        /* free segment data buffer if any */
590        if (pscte_27->segment_data) {
591                free(pscte_27->segment_data);
592                pscte_27->segment_data = NULL;
593                pscte_27->pdata = NULL;
594        }
595        return true;
596
597EXIT_PARSER:
598        if (pscte_27->segment_data) {
599                free(pscte_27->segment_data);
600                pscte_27->segment_data = NULL;
601        }
602        if (hdr->bitmap_data) {
603                free(hdr->bitmap_data);
604                hdr->bitmap_data = NULL;
605        }
606        return false;
607}
608
609/*
610 * Create an 32 bit AYUV color using the 5 bit yuv components and opaque
611 */
612static uint32_t scte_27_create_color(uint8_t y, uint8_t u, uint8_t v,bool opaque)
613{
614        uint32_t a;
615
616        y = y << 3;
617        u = u << 3;
618        v = v << 3;
619
620        a = opaque ? 0xff : 0x80;
621        a = (a << 24) | (y << 16) | (u << 8) | v;
622
623        return a;
624}
625
626/*
627 * Check given color against given CLUT index for the match
628 */ 
629static bool scte_27_check_color(int index, uint32_t color)
630{
631        if (index < 0 || index > CLUT_MAX_ENTRIES) {
632                BDBG_WRN(("%s index is out of range", __func__));
633                return false;
634        }
635        return(clut_color_entries[index] != color) ? true : false;
636}
637
638/*
639 * fill block area of subtitle
640 */
641static void scte_27_block_fill(
642        pscte_27_handle pscte_27,
643        uint16_t x,        /* x */
644        uint16_t y,        /* y */
645        uint16_t width,   /* width in pixels   */
646        uint16_t height,           /* height */
647        uint32_t color)   /* color to fill, index for CLUT */
648{
649        bapp_t *p_app = (bapp_t*)pscte_27->v_app;
650
651        bgfx_fill_rect(&p_app->surf,x,y,width,height,color);
652        bapp_sync(p_app);
653        bapp_flush_screen(p_app);
654}
655
656/*
657 * draw subtitle
658 */
659static void scte_27_draw_subtitle(
660        pscte_27_handle pscte_27, 
661        uint16_t x, 
662        uint16_t y, 
663        uint16_t width, 
664        uint16_t height, 
665        uint16_t spacing,
666        uint32_t bg, 
667        uint32_t fg, 
668        bool flush, 
669        bool update_bg)
670{
671        bapp_t *p_app = (bapp_t*)pscte_27->v_app;
672
673        /* make sure that the parse function do range check, so if we are here, all the data are valid */
674        bgfx_fill_box_subtitle(&p_app->surf, x, y, width, height, pscte_27->bitmap, pscte_27->bitmap_size, bg, fg, update_bg);
675        if (flush) {
676                bapp_sync(p_app);
677                bapp_flush_screen(p_app);
678        }
679}
680
681#define CHECKCOLOR(index, clr)                                  \
682        if (scte_27_check_color(index, clr)) {          \
683                changed = true;                                                 \
684                clut_color_entries[index] = clr;                \
685                *(palette + index) = clr;                               \
686        }                                                                                       \
687        clr = index;                                                           
688
689/*
690 * subtitle message render
691 *
692 * Parameters:
693 *  pscte_27    pointer to scte_27 handle
694 *  imme_pdata  pointer to scte_27_data if immediately draw is requested
695 *
696 * Returns:
697 *  true        if parse the data correctly
698 *  false       if anything is wrong
699 */
700
701static bool scte_27_render_subtitle(pscte_27_handle pscte_27, scte_27_data *imme_pdata)
702{
703        bapp_t *p_app = (bapp_t*)pscte_27->v_app;
704        scte_27_data    *pdata = NULL;
705        subtitle_message    *hdr = NULL;
706        unsigned int *palette, palette_size;    /* palette pointer */
707        int i, j, width, height, maxbytes, size = 0;
708        bool ret = true, changed = false;
709        uint8_t *bitmap_data = NULL, on, off;
710        uint32_t flags, bitmap_length, bit_offset = 0, bit_offset_current = 0;
711        uint32_t bitmapFgColor, bitmapBgColor, shadowColor, outlineColor;
712    struct bit_state_t bits, *bs;
713
714#ifdef  DEBUG
715        if (!pscte_27) {
716                BDBG_WRN(("%s: null ptr or zero data", __func__));
717                return false;
718        }
719#endif
720
721        if (!imme_pdata) {
722                remove_list(pscte_27->render_list);
723                if (!pdata) {
724                        /* since currently we poll it to check a) if has data, b) if it is time to render, so it is normal if no data */
725                        BDBG_MSG(("%s: no data to render", __func__));
726                        return false;
727                }
728        }
729        else
730                pdata = imme_pdata;
731
732        /* now get subtitle data */
733        hdr = pdata->msg;
734        if (!hdr) {
735                BDBG_ERR(("%s: null hdr ptr, pdata=%p. Something is wrong\n", pdata));
736                return false;
737        }
738
739        /* check time for rendering */
740        if (!hdr->immediate) {
741                i = scte_27_pts_stc_diff(pscte_27, hdr->display_in_PTS);
742                /* if past, discard it */
743                if (i < 0) {
744                        BDBG_WRN(("%s: render time passed. Discard it", __func__));
745                        ret = false;
746                        goto EXIT_RENDER;
747                }
748                if (i > 0) {
749                        /* if furture, requeue it and try later */
750                        insert_list_head(pscte_27->render_list, pdata);
751                        /* post render event */
752                        bos_post_event(pscte_27->queue, (b_event_t*)&pscte_27->cmd_array[SC_RENDER]);
753                        return true;
754                }
755        }
756        if (!pscte_27->enabled) {
757                BDBG_WRN(("%s: render is disabled", __func__));
758                ret = false;
759                goto EXIT_RENDER;
760        }
761
762        width = hdr->bitmap_bottom_H_coordinate - hdr->bitmap_top_H_coordinate + 1;
763        height = hdr->bitmap_bottom_V_coordinate - hdr->bitmap_top_V_coordinate + 1;
764        maxbytes = width * height;
765        size = (maxbytes + 7) >> 3;
766
767        /* TODO will reallcate? */
768        if (size > BITMAP_BUFFER_SIZE) {
769                BDBG_WRN(("%s: bitmap buffer is too big ", __func__));
770                ret = false;
771                goto EXIT_RENDER;
772        }
773
774        if (size < hdr->bitmap_length) {
775                BDBG_WRN(("%s: uncompress bitmap (%d) < compressed bitmap (%d)", __func__, size, hdr->bitmap_length));
776                ret = false;
777                goto EXIT_RENDER;
778        }
779
780        /* clear bitmap buffer to all off */
781        memset(pscte_27->bitmap, 0, size);
782        pscte_27->bitmap_size = size;
783
784        /* prepare to decompress */
785        bitmap_data = hdr->bitmap_data;
786        bitmap_length = hdr->bitmap_length;
787
788        /* decompress data */
789    bs = &bits;
790    bs->data = bitmap_data;
791    bs->bindex = 0;
792
793    /* decompress data */
794    while ((bs->bindex >> 3) < bitmap_length) {
795        on = off = 0;
796        i = get_bits(1, bs);
797        if (1 == i) {                   /* 1xxxYYYYY */
798            on = get_bits(3, bs);
799            if (0 == on)
800                on = 8;
801            off = get_bits(5, bs);
802            if (0 == off)
803                off = 32;
804        }
805        else {
806            i = get_bits(1, bs);
807            if (1 == i) {               /* 01YYYYYY */
808                off = get_bits(6, bs);
809                if (0 == off)
810                    off = 64;
811            }
812            else {
813                i = get_bits(1, bs);    /* 001XXXX */
814                if (1 == i) {
815                    on = get_bits(4, bs);
816                    if (0 == on)
817                        on = 16;
818                }
819                else {
820                    i = get_bits(2, bs);    /* cmd */
821                    if (1 == i) {
822                        /* end of line */
823                        bit_offset = bit_offset_current + width;
824                                                bit_offset_current = bit_offset;
825                        continue;
826                    }
827                    else {
828                        BDBG_MSG(("cmd=%d, bs->bindex=%d, offset=%d\n", i, bs->bindex, bit_offset));
829                        if (0 == i)
830                            break;
831                        continue;
832                    }
833                }
834            }
835        }
836
837        if ((bit_offset >> 3) + (on + off) <= maxbytes) {
838            while (on) {
839                uint8_t  *uncompress_byte = (uint8_t *)(pscte_27->bitmap + (bit_offset >> 3));
840                *uncompress_byte |= (1 << (7 - (bit_offset & 0x7)));
841                bit_offset++;
842                on--;
843            }
844            bit_offset += off;
845        } else {
846            BDBG_ERR(("%s: uncompress bitmap out of range, offset=%d, maxbytes=%d", __func__, (bit_offset >> 3) + (on + off), maxbytes));
847            ret = false;
848            goto EXIT_RENDER;
849        }
850    }
851    if ((bs->bindex >> 3) != bitmap_length) {
852        BDBG_ERR(("s: uncompressed data not match", __func__));
853        ret = false;
854        goto EXIT_RENDER;
855    }
856
857        hdr->top_H = hdr->bitmap_top_H_coordinate;
858        hdr->top_V = hdr->bitmap_top_V_coordinate;
859        hdr->bottom_H = hdr->bitmap_bottom_H_coordinate; 
860        hdr->bottom_V = hdr->bitmap_bottom_V_coordinate; 
861
862        bapp_palette_get(ePALETTE_APP,(unsigned int **)&palette, &palette_size);
863
864        /* FG color */
865        bitmapFgColor = scte_27_create_color(hdr->Y_component, hdr->Cr_component, hdr->Cb_component, hdr->opaque_enable);
866        CHECKCOLOR(CLUT_FG_INDEX, bitmapFgColor);
867
868        /* BG color */
869        if (hdr->background_style) {
870                if (hdr->frame_top_H_coordinate < hdr->top_H) {
871                        hdr->top_H = hdr->frame_top_H_coordinate;
872                }
873                if (hdr->frame_top_V_coordinate < hdr->top_V) {
874                        hdr->top_V = hdr->frame_top_V_coordinate;
875                }
876                if (hdr->frame_bottom_H_coordinate > hdr->bottom_H) {
877                        hdr->bottom_H = hdr->frame_bottom_H_coordinate;
878                }
879                if (hdr->frame_bottom_V_coordinate > hdr->bottom_V) {
880                        hdr->bottom_V = hdr->frame_bottom_V_coordinate;
881                }
882                bitmapBgColor = scte_27_create_color(hdr->frame_Y_component, 
883                        hdr->frame_Cr_component, hdr->frame_Cb_component, hdr->opaque_enable);
884                CHECKCOLOR(CLUT_BG_INDEX, bitmapBgColor);
885        } else
886                bitmapBgColor = eCOLOR_CLEAR;
887
888        outlineColor = CLUT_OUTLINE_INDEX;
889        shadowColor = CLUT_FRAME_INDEX;
890
891        switch (hdr->outline_style) {
892        case OS_OUTLINE:
893                hdr->bottom_H += hdr->outline_thickness * 2;
894                hdr->bottom_V += hdr->outline_thickness * 2;
895                outlineColor = scte_27_create_color(hdr->outline_Y_component,
896                        hdr->outline_Cr_component, hdr->outline_Cb_component, hdr->outline_opaque_enable);
897                CHECKCOLOR(CLUT_OUTLINE_INDEX, outlineColor);
898                break;
899
900        case OS_DROP_SHADOW:
901                hdr->bottom_H += hdr->shadow_right;
902                hdr->bottom_V += hdr->shadow_bottom;
903                shadowColor = scte_27_create_color(hdr->shadow_Y_component,
904                        hdr->shadow_Cr_component, hdr->shadow_Cb_component, hdr->opaque_enable);
905                CHECKCOLOR(CLUT_FRAME_INDEX, shadowColor);
906                break;
907        }
908
909        if (changed) {
910                /* update CLUT's last four entries which corresponding to subtitle */
911                bgraphics_load_palette(p_app->graphics);
912        }
913
914        if (pscte_27->clear_list.count > 0) {
915        hdr->pre_clear_display = true;
916                scte_27_reset_list(pscte_27, SC_CLEAR);
917        }
918        /* Draw the frame first */
919        if (hdr->pre_clear_display) {
920#if DISPLAY_PAL
921                scte_27_block_fill(pscte_27, 0, 0, BFMT_PAL_WIDTH, BFMT_PAL_HEIGHT - 2, eCOLOR_CLEAR);
922#else
923                scte_27_block_fill(pscte_27, 0, 0, BFMT_NTSC_WIDTH, BFMT_NTSC_HEIGHT - 2, eCOLOR_CLEAR);
924#endif
925        } 
926        if (hdr->background_style) {
927                scte_27_block_fill(pscte_27, hdr->frame_top_H_coordinate, hdr->frame_top_V_coordinate, hdr->frame_bottom_H_coordinate - hdr->frame_top_H_coordinate + 1, 
928                        hdr->frame_bottom_V_coordinate - hdr->frame_top_V_coordinate + 1, bitmapBgColor);
929        }
930
931        switch (hdr->outline_style) {
932        case OS_OUTLINE:
933                hdr->bottom_H += hdr->outline_thickness;
934                hdr->bottom_H += hdr->outline_thickness;
935
936                for (i = -hdr->outline_thickness; i <= hdr->outline_thickness; i += 2) {
937                        for (j = -hdr->outline_thickness; j <= hdr->outline_thickness; j += 2) {
938                                if (i && j) {
939                                        scte_27_draw_subtitle(pscte_27, hdr->top_H + i, hdr->top_V + j, 
940                                                width, height, 0, 0, outlineColor, false, false);
941                                }
942                        }
943                }
944                break;
945
946        case OS_DROP_SHADOW:
947                scte_27_draw_subtitle(pscte_27, hdr->top_H + hdr->shadow_right, hdr->top_V + hdr->shadow_bottom, 
948                        width, height, 0, 0, shadowColor, false, false);
949                break;
950        }
951
952        scte_27_draw_subtitle(pscte_27, hdr->top_H, hdr->top_V, width, height, 0, bitmapBgColor, bitmapFgColor, true, false);
953    BDBG_MSG(("%s: pdata=%p", __func__, pdata));
954    BDBG_MSG(("subtitle x=%d, y=%d, w=%d, h=%d", hdr->top_H, hdr->top_V, width, height));
955    BDBG_MSG(("clear x=%d, y=%d, w=%d, h=%d", hdr->top_H, hdr->top_V, hdr->bottom_H - hdr->top_H, hdr->bottom_V - hdr->top_V));
956        /* passing through */
957
958EXIT_RENDER:
959        /* to free allocated memory */
960        if (hdr->bitmap_data) {
961                free(hdr->bitmap_data);
962                hdr->bitmap_data = NULL;
963                hdr->bitmap_size = 0; 
964        }
965        /* if rendering successfull, put it to the clear_list list */
966        if (pdata) {
967                if (true == ret) {
968#ifdef  SUBTITLE_DRAW_TEST
969                        insert_list(pscte_27->free_list, pdata);
970#else
971                        insert_list(pscte_27->clear_list, pdata);
972                        /* post render event */
973                        bos_post_event(pscte_27->queue, (b_event_t*)&pscte_27->cmd_array[SC_CLEAR]);
974#endif
975                } 
976                else {
977                        insert_list(pscte_27->free_list, pdata);
978                }
979        }
980        return ret;
981}
982
983/*
984 * clear subtitle
985 *
986 * Parameters:
987 *  pscte_27    pointer to scte_27 handle
988 *
989 * Returns:
990 *  true        if parse the data correctly
991 *  false       if anything is wrong
992 */
993static bool scte_27_clear_subtitle(pscte_27_handle pscte_27)
994{
995        uint32_t flags;
996        scte_27_data    *pdata;
997
998        if (bos_acquire_mutex(&pscte_27->mutex, SCTE_27_MUTEX_TIME) != b_ok) {
999                return false;
1000        }
1001        remove_list(pscte_27->clear_list);
1002        bos_release_mutex(&pscte_27->mutex);
1003        if (pdata) {
1004                subtitle_message *hdr = pdata->msg;
1005                int i;
1006
1007                i = scte_27_pts_stc_diff(pscte_27, hdr->display_out_PTS);
1008                /* if furture, requeue it and try later */
1009                if (i > 0) {
1010                        /* furture */
1011                        insert_list_head(pscte_27->clear_list, pdata);
1012                        /* post render event */
1013                        bos_post_event(pscte_27->queue, (b_event_t*)&pscte_27->cmd_array[SC_CLEAR]);
1014                } else {
1015                        BDBG_MSG(("%s: clear subtitle, pdata=%p, x=%d, y=%d, w=%d, h=%d\n", __func__, pdata, hdr->top_H, hdr->top_V,
1016                hdr->bottom_H - hdr->top_H + 1, hdr->bottom_V - hdr->top_V + 1));
1017                        if (pscte_27->enabled) {
1018                                scte_27_block_fill(pscte_27, hdr->top_H, hdr->top_V, 
1019                                        hdr->bottom_H - hdr->top_H + 1, hdr->bottom_V - hdr->top_V + 1, eCOLOR_CLEAR);
1020                        }
1021                        /* put it back to free list */
1022                        insert_list(pscte_27->free_list, pdata);
1023                }
1024                return true;
1025        }
1026        return false;
1027}
1028
1029/*
1030 * scte 27 event handler
1031 *
1032 * Parameters:
1033 *  data        pointer to scte_27 handle
1034 *
1035 * Returns:
1036 *  NONE
1037 */
1038void scte_27_handler(void *data)
1039{
1040        b_event_t orig_event, *cur_event;
1041        pscte_27_handle pscte_27 = (pscte_27_handle)data;
1042
1043        while (true) {
1044                orig_event = pscte_27->cmd_array[0];
1045                switch (pscte_27->cmd_array[0]) {
1046                default:
1047                case SC_NONE:
1048                        cur_event = (b_event_t *)bos_pend_event(pscte_27->queue, SCTE_27_EVENT_TIME);
1049                        /* if no pending event */
1050                        if (NULL == cur_event) {
1051                                if (pscte_27->render_list.count)
1052                                        scte_27_render_subtitle(pscte_27, (pscte_27_data)NULL);
1053                                if (pscte_27->clear_list.count)
1054                                        scte_27_clear_subtitle(pscte_27);
1055                                break;
1056                        }
1057                        pscte_27->cmd_array[0] = *cur_event;
1058                        break;
1059
1060                case SC_RENDER:
1061                        scte_27_render_subtitle(pscte_27, (pscte_27_data)NULL);
1062                        if (pscte_27->clear_list.count)
1063                                scte_27_clear_subtitle(pscte_27);
1064                        break;
1065
1066                case SC_CLEAR:
1067                        /* to clear subtitle */
1068                        scte_27_clear_subtitle(pscte_27);
1069                        if (pscte_27->render_list.count)
1070                                scte_27_render_subtitle(pscte_27, (pscte_27_data)NULL);
1071                        break;
1072
1073                case SC_IDLE:
1074                        /* if idle, wait for longer time */
1075                        orig_event = SC_NONE;
1076                        bos_sleep(SCTE_27_EVENT_TIME * 10);
1077                        break;
1078                }
1079        }
1080}
1081
Note: See TracBrowser for help on using the repository browser.