DVBCore  20.3.0
DVBCore Documentation
stbdsc.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2004 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
25 //---includes for this file----------------------------------------------------
26 // compiler library header files
27 
28 #include <string.h>
29 #include <stdio.h>
30 
31 // third party header files
32 
33 // Ocean Blue Software header files
34 
35 #include <techtype.h>
36 #include <dbgfuncs.h>
37 
38 #include "stbhwos.h"
39 #include "stbhwosd.h"
40 #include "stbhwdmx.h"
41 #include "stbheap.h"
42 #include "stbds.h"
43 #include "stbdsapi.h"
44 #include "stbdpc.h"
45 #include "stbpes.h"
46 
47 //---constant definitions for this file----------------------------------------
48 
49 #define DVB_SUBT_TASK_STACK_SIZE 1024 * 5
50 #define DVB_SUBT_TASK_PRIORITY 9
51 
52 // Debug message macros
53 
54 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
55  #ifdef STB_CONTROL_TASK_CHANNEL_DEBUG_REQUIRED
56  #define STB_CONTROL_TASK_PRINT(x) DEBUG_PRINTX_CONDITIONAL(DEBUG_STB_OSD) x
57  #else
58  #define STB_CONTROL_TASK_PRINT(x) STB_SPDebugWrite x
59  #endif
60 #else
61  #define STB_CONTROL_TASK_PRINT(x)
62 #endif
63 
64 //**************************************************************************************************
65 // DVB subtitle segment macros
66 //**************************************************************************************************
67 
68 #define PCS 0x10 // Page Composition Segment
69 #define RCS 0x11 // Region Composition Segment
70 #define CDS 0x12 // CLUT Definition Segment
71 #define ODS 0x13 // Object Data Segment
72 #define DDS 0x14 // Display Definition Segment
73 
74 // values 0x40 - 0x7f reserved for future use
75 
76 // values 0x80 - 0xef reserved for future use
77 #define EDS 0x80 // End of Display set Segment - DTG Subtitling:
78  // 28 August 1998: Version: 3.0 Clause 5.7.1
79 
80 // ETS 300 743 7.1
81 #define END_OF_PES_DATA_FIELD_MARKER 0xff
82 
83 // all other values reserved for future use
84 
85 //**************************************************************************************************
86 // end DVB subtitle segment macros
87 //**************************************************************************************************
88 
89 #define SYNC_BYTE 0x0f
90 
91 // For use with the memcmp function, ease of reading code only
92 #define MATCH 0x00
93 
94 // pes_hdr_data_len byte location withinthe PES packet structure
95 #define PES_HDR_DATA_LEN_BYTE 0x08
96 
97 // Represents the max value of a 16bit number and the prefix code, stream id and the length bytes.
98 #define MAX_PES_SIZE (0xffff + 0x06)
99 
100 #ifdef DS_HEAP_USAGE
101  #define STB_GetMemory(x) STB_DSGetMemory(x)
102  #define STB_FreeMemory(x) STB_DSFreeMemory(x)
103 #endif
104 
105 //---local typedef structs for this file---------------------------------------
106 
107 typedef struct stream
108 {
109  BOOLEAN started;
110  BOOLEAN stopped;
111  BOOLEAN enabled;
112 
113  U8BIT decode_path;
114  U16BIT subtitle_pid;
115  U16BIT composition_page_id;
116  U16BIT ancillary_page_id;
117 } S_STREAM;
118 
119 //---local (static) variable declarations for this file------------------------
120 // (internal variables declared static to make them local)
121 
122 static BOOLEAN initialised = FALSE;
123 
124 //Assuming that we are best able to work out whether we should use the next acquisition point
125 //as a mode change point (unless mode change occurs first).
126 //Used to tell lower level that we suspect they need to synchronise at next opportunity.
127 static BOOLEAN force_acquisition = TRUE;
128 
129 static S_STREAM subtitle_status;
130 static void *dvb_subtitle_queue;
131 static void *dvb_subtitle_ptr;
132 static void *dvb_decoder_sem;
133 static void *dvb_display_sem;
134 static void *set_stream_sem;
135 
136 static U8BIT last_pts[5] = {0xff, 0xff, 0xff, 0xff, 0xff};
137 static U8BIT curr_pts[5] = {0xff, 0xff, 0xff, 0xff, 0xff};
138 
139 static U8BIT *next_pes;
140 
141 static U32BIT pes_collection_callback_handle;
142 
143 #ifdef DS_HEAP_USAGE
144 static U32BIT malloc_array[2][MAX_ARRAY_INDEX];
145 static U32BIT hi_water_allocations;
146 static S16BIT num_allocations;
147 static U32BIT hi_water_mem_alloc;
148 static U32BIT mem_allocation;
149 static U8BIT i;
150 static BOOLEAN found;
151 static BOOLEAN done_one_malloc_report;
152 #endif
153 
154 //---local function prototypes for this file-----------------------------------
155 // (internal functions declared static to make them local)
156 
157 static void DVBSubtitlePesCallback(U32BIT handle, U8BIT data_identifier, void *buffer_ptr, U32BIT buffer_size);
158 static void DelayIfRequired(void);
159 static void FlushQueue(void);
160 static BOOLEAN ParseSegment(U8BIT path, U8BIT *data, U16BIT *processed_bytes, U16BIT pes_length);
161 static void DVBSubtTask(void *unwanted_p);
162 
163 //---local function definitions------------------------------------------------
164 
180 static void DVBSubtitlePesCallback(U32BIT handle, U8BIT data_identifier, void *buffer_ptr, U32BIT buffer_size)
181 {
182  void *buffer;
183  BOOLEAN success;
184 
185  FUNCTION_START(DVBSubtitlePesCallback);
186 
187  USE_UNWANTED_PARAM(handle);
188  USE_UNWANTED_PARAM(data_identifier);
189 
190  buffer = STB_GetMemory(buffer_size);
191  if (buffer != NULL)
192  {
193  memcpy(buffer, buffer_ptr, buffer_size);
194 
195  success = STB_OSWriteQueue(dvb_subtitle_queue, (void *)&buffer, sizeof(U8BIT *), TIMEOUT_NOW);
196  if (!success)
197  {
198  DBGPRINT("DVBSubtitlePesCallback: Failed to add pes buffer to subtitle queue");
199  STB_FreeMemory(buffer);
200  }
201  }
202 
203  FUNCTION_FINISH(DVBSubtitlePesCallback);
204 }
205 
219 static void DelayIfRequired(void)
220 {
221  static U32BIT timestamp;
222  U32BIT diff;
223 
224 
225  FUNCTION_START(DelayIfRequired);
226 
227  diff = (STB_OSGetClockDiff(timestamp));
228 
229  if (diff > 250)
230  {
231  STB_OSTaskDelay(10);
232  timestamp = STB_OSGetClockMilliseconds();
233  }
234 
235  FUNCTION_FINISH(DelayIfRequired);
236 }
237 
250 static void FlushQueue(void)
251 {
252  U8BIT *pes_ptr;
253  BOOLEAN read_pes_from_queue;
254 
255 
256  FUNCTION_START(FlushQueue);
257  DBGPRINT("FlushQueue");
258 
259  if (next_pes != NULL)
260  {
261  STB_FreeMemory(next_pes);
262  next_pes = NULL;
263  }
264 
265  do
266  {
267  read_pes_from_queue = STB_OSReadQueue(dvb_subtitle_queue, &pes_ptr, sizeof(U8BIT *), TIMEOUT_NOW);
268  if (read_pes_from_queue == TRUE)
269  {
270  STB_FreeMemory(pes_ptr);
271  }
272  }
273  while (read_pes_from_queue);
274 
275  FUNCTION_FINISH(FlushQueue);
276 }
277 
292 static BOOLEAN ParseSegment(U8BIT path, U8BIT *data, U16BIT *processed_bytes, U16BIT pes_length)
293 {
294  U16BIT segment_length;
295  U16BIT page_id;
296  U8BIT segment_type;
297  BOOLEAN parsed_ok = FALSE;
298  BOOLEAN ancillary_pg_present;
299 
300  // Stores whether we're currently happy with Page composition state
301  static BOOLEAN page_okay = FALSE;
302  static BOOLEAN comp_cds_allowed;
303  static BOOLEAN comp_ods_allowed;
304  // Have we processed subtitle data, which we haven't yet displayed?
305  static BOOLEAN undisplayed_data = FALSE;
306 
307 
308  FUNCTION_START(ParseSegment);
309 
310  // sync_byte = data[0];
311  segment_type = data[1];
312 
313  page_id = (data[2] << 8) + data[3];
314 
315  // EN 300 468 version 1.3.1 clause 6.2.30 Subtitling descriptor
316  // The values in the ancillary_page_id and the composition_page_id fields
317  // shall be the same if no ancillary page is provided.
318 
319  // NB. the second clause where pages do not match and the ancillary page is zero
320  // is for Channel 4, but strictly speaking this is wrong.
321  if ((subtitle_status.composition_page_id == subtitle_status.ancillary_page_id) ||
322  (subtitle_status.ancillary_page_id == 0))
323  {
324  ancillary_pg_present = FALSE;
325  }
326  else
327  {
328  ancillary_pg_present = TRUE;
329  }
330 
331  segment_length = (data[4] << 8) + data[5] + 6;
332 
333  /* Check length segment len is sensible */
334  if ((*processed_bytes + segment_length) >= pes_length)
335  {
336  STB_CONTROL_TASK_PRINT(("ERR LENGTH wrong! peslen=%d,seglen=%d, prc=%d",
337  pes_length, segment_length, *processed_bytes));
338 
339  segment_length = pes_length - *processed_bytes;
340  }
341  /* Check we're not about to lose sync with segment data / pes data */
342  else if ((data[segment_length] == SYNC_BYTE) ||
343  (data[segment_length] == END_OF_PES_DATA_FIELD_MARKER))
344  {
345  switch (segment_type)
346  {
347  case DDS:
348  {
349  if (page_id == subtitle_status.composition_page_id)
350  {
351  STB_CONTROL_TASK_PRINT(("\nDDS"));
352 
353  STB_OSSemaphoreWait(dvb_display_sem);
354  parsed_ok = STB_DSSegmentDDS(data, pes_length, *processed_bytes);
355  STB_OSSemaphoreSignal(dvb_display_sem);
356 
357 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
358  if (!parsed_ok)
359  {
360  STB_CONTROL_TASK_PRINT(("DDS parse error"));
361  }
362 #endif
363  }
364 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
365  else
366  {
367  STB_CONTROL_TASK_PRINT(("\nDDS - not composing page %d", page_id));
368  }
369 #endif
370  break;
371  }
372 
373  case PCS:
374  {
375  STB_CONTROL_TASK_PRINT(("\nPCS - mode %d - %s",
376  ((data[7] & 0x0c) >> 2),
377  (force_acquisition ? "FORCE MODE CHANGE" : "")));
378 
379  // Check that PCS describes the page that we wish to compose
380  if (page_id == subtitle_status.composition_page_id)
381  {
382  // Remember PTS
383  memcpy((void *)last_pts, (void *)curr_pts, (size_t)5);
384 
385  /* If there's undisplayed data, then no EDS segment was found.
386  * Any existing data should be discarded, which should happen when the next
387  * acquisition point is detected */
388  if (undisplayed_data)
389  {
390  undisplayed_data = FALSE;
391  }
392 
393  // Until we parse PCS succesfully we need to inhibit any further processing
394  page_okay = FALSE;
395 
396  STB_CONTROL_TASK_PRINT(("PCS composing page %d", page_id));
397 
398  //Process the PCS segment.
399  //force_acquisition == TRUE signals that lower level should treat the first acquisition
400  //point as a mode change (unless a mode_change occurs first)
401  STB_OSSemaphoreWait(dvb_display_sem);
402  parsed_ok = STB_DSSegmentPCS(data, pes_length, *processed_bytes, force_acquisition);
403  STB_OSSemaphoreSignal(dvb_display_sem);
404 
405  if (!parsed_ok)
406  {
407  force_acquisition = TRUE;
408  STB_CONTROL_TASK_PRINT(("PCS parse error in STB_DSSegmentPCS!!"));
409  }
410  else
411  {
412  //Lower level remembers this signal, we don't send again, until we think we need
413  //to re-acquire again
414  force_acquisition = FALSE;
415 
416  // Allow processing of following segments within page
417  page_okay = TRUE;
418  }
419 
420  if (parsed_ok)
421  {
422  STB_DSSetDisplaySetPts(path, curr_pts);
423  // Remember that we have started defining a page which has yet to be displayed
424  undisplayed_data = TRUE;
425  comp_cds_allowed = TRUE;
426  comp_ods_allowed = TRUE;
427  }
428  }
429 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
430  else
431  {
432  STB_CONTROL_TASK_PRINT(("PCS - not composing page %d", page_id));
433  }
434 #endif
435  break;
436  }
437 
438  case RCS:
439  {
440 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
441  if (page_okay)
442  {
443  STB_CONTROL_TASK_PRINT(("+RCS: page=%d", page_id));
444  }
445  else
446  {
447  STB_CONTROL_TASK_PRINT(("-rcs: page=%d", page_id));
448  }
449 #endif
450 
451  if (page_okay &&
452  ((page_id == subtitle_status.composition_page_id) ||
453  ((page_id == subtitle_status.ancillary_page_id) && ancillary_pg_present)))
454  {
455  STB_OSSemaphoreWait(dvb_display_sem);
456  parsed_ok = STB_DSSegmentRCS(data, pes_length, *processed_bytes);
457  STB_OSSemaphoreSignal(dvb_display_sem);
458 
459  if (!parsed_ok)
460  {
461  STB_CONTROL_TASK_PRINT(("RCS parse error"));
462  }
463  }
464 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
465  else if (page_okay)
466  {
467  STB_CONTROL_TASK_PRINT(("RCS - not composing page %d", page_id));
468  }
469 #endif
470  break;
471  }
472 
473  case CDS:
474  {
475 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
476  if (page_okay && comp_cds_allowed)
477  {
478  STB_CONTROL_TASK_PRINT(("+CDS: page=%d", page_id));
479  }
480  else
481  {
482  STB_CONTROL_TASK_PRINT(("-cds: page=%d", page_id));
483  }
484 #endif
485 
486  if (page_okay &&
487  ((page_id == subtitle_status.composition_page_id) ||
488  (page_id == subtitle_status.ancillary_page_id)))
489  {
490  if ((page_id == subtitle_status.ancillary_page_id) && (ancillary_pg_present))
491  {
492  comp_cds_allowed = FALSE;
493  }
494  if ((page_id == subtitle_status.composition_page_id) && (comp_cds_allowed))
495  {
496  parsed_ok = STB_DSSegmentCDS(data, pes_length, *processed_bytes);
497  if (!parsed_ok)
498  {
499  STB_CONTROL_TASK_PRINT(("CDS parse error"));
500  }
501  }
502  }
503 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
504  else if (page_okay)
505  {
506  STB_CONTROL_TASK_PRINT(("CDS - not composing page %d", page_id));
507  }
508 #endif
509 
510  break;
511  }
512 
513  case ODS:
514  {
515 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
516  if (page_okay && comp_ods_allowed)
517  {
518  STB_CONTROL_TASK_PRINT(("+ODS: page=%d", page_id));
519  }
520  else
521  {
522  STB_CONTROL_TASK_PRINT(("-ods: page=%d", page_id));
523  }
524 #endif
525 
526  if (page_okay &&
527  ((page_id == subtitle_status.composition_page_id) ||
528  (page_id == subtitle_status.ancillary_page_id)))
529  {
530  if ((page_id == subtitle_status.ancillary_page_id) && (ancillary_pg_present))
531  {
532  comp_ods_allowed = FALSE;
533  comp_cds_allowed = FALSE;
534  }
535  if ((page_id == subtitle_status.composition_page_id) && (comp_ods_allowed))
536  {
537  STB_OSSemaphoreWait(dvb_display_sem);
538  parsed_ok = STB_DSSegmentODS(data, pes_length, *processed_bytes);
539  STB_OSSemaphoreSignal(dvb_display_sem);
540  if (!parsed_ok)
541  {
542  STB_CONTROL_TASK_PRINT(("ODS parse error"));
543  }
544  }
545  }
546 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
547  else if (page_okay)
548  {
549  STB_CONTROL_TASK_PRINT(("ODS - not composing page %d", page_id));
550  }
551 #endif
552 
553  break;
554  }
555 
556  case EDS:
557  {
558 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
559  if (page_okay)
560  {
561  STB_CONTROL_TASK_PRINT(("+EDS: page=%d", page_id));
562  }
563  else
564  {
565  STB_CONTROL_TASK_PRINT(("-eds: page=%d", page_id));
566  }
567 #endif
568 
569  if (page_okay &&
570  ((page_id == subtitle_status.composition_page_id) ||
571  ((page_id == subtitle_status.ancillary_page_id) && ancillary_pg_present)))
572  {
573  parsed_ok = STB_DSSegmentEDS(data, pes_length, *processed_bytes);
574 
575  if (parsed_ok)
576  {
577  STB_OSSemaphoreWait(dvb_display_sem);
579  STB_OSSemaphoreSignal(dvb_display_sem);
580  undisplayed_data = FALSE;
581  }
582  else
583  {
584  STB_CONTROL_TASK_PRINT(("EDS parse error"));
585  }
586  }
587 #ifdef STB_CONTROL_TASK_PRINT_REQUIRED
588  else if (page_okay)
589  {
590  STB_CONTROL_TASK_PRINT(("EDS - not composing page %d", page_id));
591  }
592 #endif
593 
594  break;
595  }
596 
597  default:
598  {
599  STB_CONTROL_TASK_PRINT(("Unknown segment code 0x%02x", segment_type));
600  break;
601  }
602  }
603  }
604  else
605  {
606  STB_CONTROL_TASK_PRINT(("LOST sync with segments; PESlen=%d, prc_posn=%d, seglen=%d, dseg=%x",
607  pes_length, *processed_bytes, segment_length, data[segment_length]));
608  }
609 
610  (*processed_bytes) += segment_length;
611 
612  FUNCTION_FINISH(ParseSegment);
613 
614  return(parsed_ok);
615 }
616 
629 static void DVBSubtTask(void *unwanted_p)
630 {
631  U8BIT *pes_ptr;
632  U8BIT *data;
633 
634  U16BIT data_id_stream_id;
635  U16BIT pes_length;
636  U16BIT processed_bytes;
637 
638  U8BIT pts_dts_flags;
639  U8BIT pes_hdr_data_len;
640  U8BIT segment_data;
641 
642  BOOLEAN data_alignment_indicator;
643  BOOLEAN pts_present;
644  BOOLEAN read_pes_from_queue;
645  BOOLEAN terminate;
646 
647  FUNCTION_START(DVBSubtTask);
648 
649  USE_UNWANTED_PARAM(unwanted_p);
650 
651  subtitle_status.decode_path = INVALID_RES_ID;
652  subtitle_status.subtitle_pid = 0;
653  subtitle_status.composition_page_id = 0;
654  subtitle_status.ancillary_page_id = 0;
655 
656  subtitle_status.stopped = FALSE;
657  subtitle_status.started = FALSE;
658  subtitle_status.enabled = FALSE;
659 
660  pes_ptr = NULL;
661  data = NULL;
662 
663  data_id_stream_id = 0;
664  pes_length = 0;
665  processed_bytes = 0;
666 
667  pts_dts_flags = 0;
668  pes_hdr_data_len = 0;
669  segment_data = 0;
670 
671  data_alignment_indicator = FALSE;
672  pts_present = FALSE;
673  read_pes_from_queue = FALSE;
674 
675  while (1)
676  {
677  read_pes_from_queue = STB_OSReadQueue(dvb_subtitle_queue, &pes_ptr, sizeof(U8BIT *), 250);
678 
679  if (subtitle_status.decode_path != INVALID_RES_ID)
680  {
681  STB_OSSemaphoreWait(dvb_display_sem);
683  STB_OSSemaphoreSignal(dvb_display_sem);
684  }
685 
686  if (read_pes_from_queue)
687  {
688  // Got PES check packet_start_code_prefix 24bit value 0x000001
689  if ((pes_ptr[0] == 0x00) && (pes_ptr[1] == 0x00) && (pes_ptr[2] == 0x01))
690  {
691  // Check stream_id
692  if (pes_ptr[3] == 0xbd)
693  {
694  // private_stream_1
695  // This value is from this point forward, the size of the entire PES packet
696  // is (pes_length + 6); as the bytes before and the length bytes are not included.
697  pes_length = (pes_ptr[4] << 8) + pes_ptr[5] + 6;
698 
699  data_alignment_indicator = (pes_ptr[6] >> 2) & 0x01;
700 
701  pts_dts_flags = (pes_ptr[7] & 0xc0) >> 6;
702  pts_present = ((pts_dts_flags & 0x2) >> 1);
703 
704  // PES_header_data_length - An 8bit field specifying the total number of bytes
705  // occupied by the optional fields and any stuffing bytes in this PES packet header.
706  pes_hdr_data_len = pes_ptr[PES_HDR_DATA_LEN_BYTE];
707 
708  if (pts_present)
709  {
710  // PTS_DTS_flags when set either pts present[10] or pts & dts present[11]
711  // neither present[00], and no pts and a dts[01] not allowed; as dts is
712  // listed after pts, the pts is in the same location.
713  if (STB_DSGetPesPts(&pes_ptr[9], curr_pts) == FALSE)
714  {
715  // One or more of the 3 marker_bits' are not set correctly.
716  memset(curr_pts, 0x00, 5);
717  STB_CONTROL_TASK_PRINT(("PTS error"));
718  }
719  }
720  else
721  {
722  // No PTS; but this value has the effect of displaying immediately.
723  memset(curr_pts, 0x00, 5);
724  STB_CONTROL_TASK_PRINT(("No PTS"));
725  }
726 
727  // This should place data ptr at the beginning of the PES_packet_data_byte area
728  segment_data = PES_HDR_DATA_LEN_BYTE + pes_hdr_data_len + 1;
729  data = &pes_ptr[segment_data];
730 
731  data_id_stream_id = (data[0] << 8) + data[1];
732  data += 2;
733  processed_bytes = segment_data + 2;
734 
735  if (subtitle_status.decode_path != INVALID_RES_ID)
736  {
737  // ETS 300 743 5.1.2 - In summary, all of the segments of a single display set
738  // shall be carried in one (or more) PES packets that have the same PTS value.
739  if (memcmp(last_pts, curr_pts, 5) != MATCH)
740  {
741  STB_OSSemaphoreWait(dvb_display_sem);
743  STB_OSSemaphoreSignal(dvb_display_sem);
744  }
745  }
746 
747  if ((data_id_stream_id == 0x2000) &&
748  (data_alignment_indicator))
749  {
750  terminate = FALSE;
751 
752  while (processed_bytes < pes_length)
753  {
754  switch (data[0])
755  {
756  case SYNC_BYTE:
757  {
758  ParseSegment(subtitle_status.decode_path, data,
759  &processed_bytes, pes_length);
760  break;
761  }
762 
763  case END_OF_PES_DATA_FIELD_MARKER:
764  {
765  processed_bytes++;
766  break;
767  }
768 
769  default:
770  {
771  processed_bytes++;
772  STB_CONTROL_TASK_PRINT(("Not a sync byte, PES len=%u, processed %u bytes, value=0x%02x",
773  pes_length, processed_bytes, data[0]));
774  terminate = TRUE;
775  break;
776  }
777  }
778 
779  if (terminate)
780  {
781  break;
782  }
783 
784  // Move data to next segment
785  data = &pes_ptr[processed_bytes];
786  DelayIfRequired();
787  }
788  }
789  }
790  }
791  }
792 
793  if (pes_ptr != NULL)
794  {
795  STB_FreeMemory(pes_ptr);
796  pes_ptr = NULL;
797  }
798  } //loop
799 
800  /* Execution never gets here! */
801 #if 0
802  STB_UnregisterPesCollectionCallback(pes_collection_callback_handle);
803  STB_SUBStop();
804 #endif
805 
806  FUNCTION_FINISH(DVBSubtTask);
807 }
808 
809 //---global function definitions-----------------------------------------------
810 
811 #ifdef DS_HEAP_USAGE
812 
823 void* STB_DSGetMemory(U32BIT bytes)
824 {
825  void *temp;
826  BOOLEAN hi_water;
827 
828  temp = STB_GetMemory(bytes);
829  if (temp != NULL)
830  {
831  num_allocations++;
832  mem_allocation += bytes;
833  found = FALSE;
834  hi_water = FALSE;
835 
836  for (i = 0; i < MAX_ARRAY_INDEX; i++)
837  {
838  if (malloc_array[0][i] == 0)
839  {
840  found = TRUE;
841  break;
842  }
843  }
844  if (found)
845  {
846  malloc_array[0][i] = temp;
847  malloc_array[1][i] = bytes;
848  }
849  else
850  {
851  STB_SPDebugWrite("Malloc trace array exceeded");
852  }
853 
854  if (num_allocations > hi_water_allocations)
855  {
856  hi_water_allocations = num_allocations;
857  hi_water = TRUE;
858  }
859  if (mem_allocation > hi_water_mem_alloc)
860  {
861  hi_water_mem_alloc = mem_allocation;
862  hi_water = TRUE;
863  }
864 
865  if (hi_water)
866  {
867  STB_SPDebugWrite("Malloc: HiNum %02d; Hisize %02d",
868  hi_water_allocations, hi_water_mem_alloc);
869  }
870  if ((done_one_malloc_report) && (num_allocations > 2))
871  {
872  done_one_malloc_report = FALSE;
873  }
874  }
875  return(temp);
876 }
877 
889 void STB_DSFreeMemory(void *addr)
890 {
891  if (addr != NULL)
892  {
893  found = FALSE;
894  STB_FreeMemory(addr);
895  num_allocations--;
896 
897  for (i = 0; i < MAX_ARRAY_INDEX; i++)
898  {
899  if (malloc_array[0][i] == (U32BIT)addr)
900  {
901  found = TRUE;
902  break;
903  }
904  }
905 
906  if (found)
907  {
908  mem_allocation -= malloc_array[1][i];
909  malloc_array[0][i] = 0;
910  malloc_array[1][i] = 0;
911  }
912  else
913  {
914  STB_SPDebugWrite("NO record of malloc!!!");
915  }
916 
917  if ((num_allocations == 1) && (!done_one_malloc_report))
918  {
919  STB_SPDebugWrite("One malloc, scratch pad");
920  done_one_malloc_report = TRUE;
921  }
922  if (num_allocations < 0)
923  {
924  STB_SPDebugWrite("Minus Frees!");
925  }
926  }
927 }
928 
929 #endif
930 
943 {
944  FUNCTION_START(STB_SUBInitialise);
945 
946  if (!initialised)
947  {
948  subtitle_status.started = FALSE;
949  subtitle_status.stopped = TRUE;
950  subtitle_status.enabled = FALSE;
951 
952  subtitle_status.decode_path = INVALID_RES_ID;
953  subtitle_status.subtitle_pid = 0;
954  subtitle_status.composition_page_id = 0;
955  subtitle_status.ancillary_page_id = 0;
956 
957  dvb_subtitle_queue = (void *)STB_OSCreateQueue(sizeof(U8BIT *), 50);
958 
959  dvb_decoder_sem = STB_OSCreateSemaphore();
960  dvb_display_sem = STB_OSCreateSemaphore();
961  set_stream_sem = STB_OSCreateSemaphore();
962 
963  STB_OSSemaphoreWait(dvb_decoder_sem);
964 
966  dvb_subtitle_ptr = STB_OSCreateTask(DVBSubtTask, NULL, DVB_SUBT_TASK_STACK_SIZE,
967  DVB_SUBT_TASK_PRIORITY, (U8BIT *)"DStask");
968 
969  if ((dvb_subtitle_ptr != NULL) && (dvb_decoder_sem != NULL) &&
970  (dvb_display_sem != NULL) && (set_stream_sem != NULL))
971  {
972  STB_CONTROL_TASK_PRINT(("\nDVB subtitle task, bitmaps rendered directly into region, double buffered"));
973 
974  pes_collection_callback_handle = STB_RegisterPesCollectionCallback(DVBSubtitlePesCallback, 0x20, 0x20);
975 
976  STB_OSDEnable(FALSE);
977  initialised = TRUE;
978  }
979  }
980 
981  FUNCTION_FINISH(STB_SUBInitialise);
982 }
983 
995 void STB_SUBEnable(U8BIT path, BOOLEAN enable)
996 {
997  FUNCTION_START(STB_SUBEnable);
998  USE_UNWANTED_PARAM(path);
999 
1000  if (initialised)
1001  {
1002  DBGPRINT("STB_SUBEnable(%d): enable=%u", path, enable);
1003 
1004  // Show or Hide the subtitling display
1005  if (enable == TRUE)
1006  {
1007  STB_DSShow();
1008  }
1009  else
1010  {
1011  STB_OSSemaphoreWait(set_stream_sem);
1013  STB_OSSemaphoreSignal(set_stream_sem);
1014 
1015  STB_DSHide();
1016  STB_OSSemaphoreWait(dvb_display_sem);
1018  STB_OSSemaphoreSignal(dvb_display_sem);
1019  }
1020 
1021  subtitle_status.enabled = enable;
1022  }
1023  else
1024  {
1025  DBGPRINT("STB_SUBEnable called before initialisation -- IGNORING ");
1026  }
1027 
1028  FUNCTION_FINISH(STB_SUBEnable);
1029 }
1030 
1044 void STB_SUBStart(U8BIT path, U16BIT pid, U16BIT composition_id, U16BIT ancillary_id)
1045 {
1046  FUNCTION_START(STB_SUBStart);
1047 
1048  if (initialised)
1049  {
1050  DBGPRINT("STB_SUBStart(%d): PID %d comp pg %d anc pg %d", path, pid, composition_id, ancillary_id);
1051 
1052  STB_SUBSetStream(path, pid, composition_id, ancillary_id);
1053  }
1054 
1055  FUNCTION_FINISH(STB_SUBStart);
1056 }
1057 
1069 void STB_SUBStop(U8BIT path)
1070 {
1071  FUNCTION_START(STB_SUBStop);
1072 
1073  if (initialised)
1074  {
1075  DBGPRINT(">>>>>>>>>>>>>>>>>>STB_SUBStop(%d)", path);
1076  STB_SUBSetStream(path, 0, 0, 0);
1077 
1078  STB_OSSemaphoreWait(dvb_display_sem);
1079  subtitle_status.decode_path = INVALID_RES_ID;
1080  STB_OSSemaphoreSignal(dvb_display_sem);
1081  DBGPRINT("<<<<<<<<<<<<<<<STB_SUBStop()");
1082  }
1083 
1084  FUNCTION_FINISH(STB_SUBStop);
1085 }
1086 
1104 void STB_SUBSetStream(U8BIT path, U16BIT pid, U16BIT composition_id, U16BIT ancillary_id)
1105 {
1106  FUNCTION_START(STB_SUBSetStream);
1107 
1108  if (initialised)
1109  {
1110  DBGPRINT("STB_SUBSetStream(%d): %d %d %d", path, pid, composition_id, ancillary_id);
1111 
1112  STB_OSSemaphoreWait(set_stream_sem);
1114  if (subtitle_status.started == TRUE)
1115  {
1116  STB_OSSemaphoreWait(dvb_decoder_sem);
1117  subtitle_status.started = FALSE;
1118  }
1119  STB_OSSemaphoreSignal(set_stream_sem);
1120 
1121  /* STB_SUBEnable can wait for a timeout on the next display set, but calling
1122  * STB_DSTerminateDisplayCycle will make it drop out of the wait loop, so
1123  * this must be called before STB_SUBEnable */
1124  STB_SUBEnable(path, FALSE);
1125 
1126  //Make sure that if we see an Acquisition Point before the next Mode Change, we treat it
1127  //as a Mode Change
1128  force_acquisition = TRUE;
1129  DBGPRINT("STB_SUBSetStream 2");
1130  STB_OSSemaphoreWait(dvb_display_sem);
1131 
1134 
1135  if ((pid != STB_DPGetTextPID(path)) || (pid != subtitle_status.subtitle_pid))
1136  {
1137  DBGPRINT("STB_SUBSetStream 3a");
1139 
1140  // Flush PES collection task & queue
1141  STB_ChangePesCollectionPID(path, pid);
1142 // STB_FlushPesCollectionTask();
1143  FlushQueue();
1144  }
1145  else
1146  {
1147  DBGPRINT("STB_SUBSetStream 3b");
1148  if ((composition_id != subtitle_status.composition_page_id) ||
1149  (ancillary_id != subtitle_status.ancillary_page_id))
1150  {
1152  }
1153  }
1154 
1155  STB_OSSemaphoreSignal(dvb_display_sem);
1156 
1157  // Set the new stream parameters
1158  subtitle_status.decode_path = path;
1159  subtitle_status.subtitle_pid = pid;
1160  subtitle_status.composition_page_id = composition_id;
1161  subtitle_status.ancillary_page_id = ancillary_id;
1162 
1163  // Start the subtitling decoder
1164  subtitle_status.started = TRUE;
1165  STB_OSSemaphoreSignal(dvb_decoder_sem);
1166 
1167  // Do not show yet.
1168  STB_SUBEnable(path, FALSE);
1169  }
1170  else
1171  {
1172  DBGPRINT("STB_SUBSetStream called before initialisation -- IGNORING");
1173  }
1174 
1175  FUNCTION_FINISH(STB_SUBSetStream);
1176 }
1177 
1189 void STB_SUBStatus(BOOLEAN *started, BOOLEAN *shown)
1190 {
1191  FUNCTION_START(STB_SUBStatus);
1192 
1193  *started = subtitle_status.started;
1194  *shown = subtitle_status.enabled;
1195 
1196  FUNCTION_FINISH(STB_SUBStatus);
1197 }
1198 
1214 void STB_SUBReadSettings(BOOLEAN *started, U16BIT *pid, U16BIT *comp_id, U16BIT *anc_id, BOOLEAN *enabled)
1215 {
1216  FUNCTION_START(STB_SUBReadSettings);
1217 
1218  *started = subtitle_status.started;
1219  *pid = subtitle_status.subtitle_pid;
1220  *comp_id = subtitle_status.composition_page_id;
1221  *anc_id = subtitle_status.ancillary_page_id;
1222  *enabled = subtitle_status.enabled;
1223 
1224  FUNCTION_FINISH(STB_SUBReadSettings);
1225 }
1226 
1239 BOOLEAN STB_DSGetNextPesPts(U8BIT *next_pts)
1240 {
1241  U8BIT *pes_ptr;
1242  BOOLEAN read_pes_from_queue;
1243 
1244  FUNCTION_START(STB_DSGetNextPesPts);
1245 
1246  next_pts[0] = 0;
1247  next_pts[1] = 0;
1248  next_pts[2] = 0;
1249  next_pts[3] = 0;
1250  next_pts[4] = 0;
1251 
1252  pes_ptr = NULL;
1253 
1254  if (next_pes == NULL)
1255  {
1256  read_pes_from_queue = STB_OSReadQueue(dvb_subtitle_queue, &pes_ptr, sizeof(U8BIT *), 0);
1257  next_pes = pes_ptr;
1258  }
1259  else
1260  {
1261  pes_ptr = next_pes;
1262  read_pes_from_queue = TRUE;
1263  }
1264 
1265  if (next_pes != NULL)
1266  {
1267  if (STB_DSGetPesPts(&pes_ptr[9], next_pts) == FALSE)
1268  {
1269  next_pts[0] = 0;
1270  next_pts[1] = 0;
1271  next_pts[2] = 0;
1272  next_pts[3] = 0;
1273  next_pts[4] = 0;
1274  }
1275  }
1276 
1277  FUNCTION_FINISH(STB_DSGetNextPesPts);
1278 
1279  return(read_pes_from_queue);
1280 }
1281 
1282 //*****************************************************************************
1283 // End of file
1284 //*****************************************************************************
1285 
void STB_DSHide(void)
Prevents subtitles to display what it has decoded.
Definition: stbdsdis.c:1299
void * STB_GetMemory(U32BIT bytes)
Attempts to allocate memory from the heap.
Definition: stbheap.c:221
void STB_DSResetPhysicalDisplayRegions(void)
Deletes all regions and clears serice_aquired flag.
Definition: stbdsdis.c:1321
BOOLEAN STB_DSInitialiseDVBSubtitlesProcessing(void)
Initilises DVB subtitles, allocates a temporary buffer for use as a scratchpad and zero&#39;s the display...
Definition: stbdsfn.c:1760
S_DISPLAY_SET * STB_DSGetDetails(void)
Gets a pointer to the display set structure.
Definition: stbdsfn.c:2897
void STB_DSDisplay(U8BIT path, S_DISPLAY_SET *subtitle_display_set)
The subtitle display function. Provides timing of display and clean up when necessary.
Definition: stbdsdis.c:1216
U32BIT STB_OSGetClockDiff(U32BIT timestamp)
Get Difference between Given Time and Current Time.
Header file - macros and function prototypes for public use.
void * STB_OSCreateSemaphore(void)
Create a Semaphore.
Header file - Function prototypes for OSD control.
void STB_SUBInitialise(void)
Initialises subtitling control.
Definition: stbdsc.c:942
void STB_OSSemaphoreSignal(void *semaphore)
Signal a Semaphore to Release it by decrementing its counter.
void STB_ChangePesCollectionPID(U8BIT path, U16BIT text_pid)
Changes the PID that the DMX is using to gather data on.
Definition: stbpes.c:467
U32BIT STB_RegisterPesCollectionCallback(void(*callback_function)(U32BIT, U8BIT, void *, U32BIT), U8BIT lowest_data_identifier, U8BIT highest_data_identifier)
Used to register a callback function that will receive specific PES data packets. In theory...
Definition: stbpes.c:537
BOOLEAN STB_DSSegmentDDS(U8BIT *data, U16BIT pes_len, U16BIT processed_bytes)
Processes the Display Definition segment in accordance with ETSI document ETS 300 743...
Definition: stbdsfn.c:1877
Header file - Function prototypes for DVB subtitles.
void STB_OSSemaphoreWait(void *semaphore)
Wait on Semaphore Indefinity or Until Released.
BOOLEAN STB_DSSegmentODS(U8BIT *data, U16BIT pes_len, U16BIT processed_bytes)
Processes the Object Data segment in accordance with ETSI document ETS 300 743.
Definition: stbdsfn.c:2625
BOOLEAN STB_DSSegmentPCS(U8BIT *data, U16BIT pes_len, U16BIT processed_bytes, BOOLEAN force_acquisition)
Processes the Page Composition segment in accordance with ETSI document ETS 300 743.
Definition: stbdsfn.c:1972
BOOLEAN STB_DSSetDisplaySetPts(U8BIT path, U8BIT *pts)
Copies the passed PTS into the display set structure.
Definition: stbdsfn.c:2844
BOOLEAN STB_DSSegmentCDS(U8BIT *data, U16BIT pes_len, U16BIT processed_bytes)
Processes the CLUT Definition segment in accordance with ETSI document ETS 300 743.
Definition: stbdsfn.c:2475
void STB_FreeMemory(void *addr)
Releases previously allocated heap memory.
Definition: stbheap.c:336
void STB_DSCheckDisplaySetTimeout(S_DISPLAY_SET *subtitle_display_set, BOOLEAN timeout_override)
It checks the timeout of the current display set, and removes if/when necessary.
Definition: stbdsdis.c:1177
void STB_DSTerminateDisplayCycle(void)
Sets flag to exit display wait while loop.
Definition: stbdsdis.c:1387
BOOLEAN STB_DSSegmentRCS(U8BIT *data, U16BIT pes_len, U16BIT processed_bytes)
Processes the Region Composition segment in accordance with ETSI document ETS 300 743...
Definition: stbdsfn.c:2204
void STB_SUBStop(U8BIT path)
Stops subtitling display.
Definition: stbdsc.c:1069
void STB_SPDebugWrite(const char *format,...)
Write debug string to serial/debug port. <CR><LF> characters will be automatically added to the end o...
Debug functions header file.
BOOLEAN STB_DSGetNextPesPts(U8BIT *next_pts)
Get the PTS of the next PES packet, does not process next PES, but places on the next PES pointer...
Definition: stbdsc.c:1239
BOOLEAN STB_DSGetPesPts(U8BIT *data, U8BIT *pts)
Extracts the PTS from the PES packet header.
Definition: stbdsfn.c:2813
void STB_SUBStatus(BOOLEAN *started, BOOLEAN *shown)
returns the current status information
Definition: stbdsc.c:1189
BOOLEAN STB_OSDEnable(BOOLEAN enable)
Enable/Disable the OSD.
Definition: stbdsc.c:107
void STB_SUBSetStream(U8BIT path, U16BIT pid, U16BIT composition_id, U16BIT ancillary_id)
Sets the stream IDs to be decoded.
Definition: stbdsc.c:1104
void STB_DSClearDisplaySetStruct(void)
Clears all information from the display set structure.
Definition: stbdsfn.c:2915
BOOLEAN STB_OSWriteQueue(void *queue, void *msg, U16BIT msg_size, U16BIT timeout)
Write a message to the queue.
Header file - Function prototypes for operating system.
System Wide Global Technical Data Type Definitions.
void STB_DSResetPhysicalCompositionRegions(void)
Deletes all regions and clears serice_aquired flag.
Definition: stbdsdis.c:1354
void * STB_OSCreateTask(void(*function)(void *), void *param, U32BIT stack, U8BIT priority, U8BIT *name)
Create a New Task to the calling process. Upon success, the created task runs on its own stack...
void * STB_OSCreateQueue(U16BIT msg_size, U16BIT msg_max)
Create Queue of given number of messages and size of message.
void STB_DSShow(void)
Allows subtitles to display what it has decoded.
Definition: stbdsdis.c:1277
Header file - Function prototypes for DVB subtitles api.
Header file - Function prototypes for heap memory.
BOOLEAN STB_OSReadQueue(void *queue, void *msg, U16BIT msg_size, U16BIT timeout)
Read a message from a queue.
void STB_UnregisterPesCollectionCallback(U32BIT handle)
Used to un-register a callback function that will receive specific PES data packets.
Definition: stbpes.c:602
BOOLEAN STB_DSSegmentEDS(U8BIT *data, U16BIT pes_len, U16BIT processed_bytes)
DTG - Digital Terrestrial Television Requirements for Interoperability Subtitling: 28 August 1998: Ve...
Definition: stbdsfn.c:2760
void STB_OSTaskDelay(U16BIT timeout)
Delay Task for Specifed Time Period.
Header file - Function prototypes for Demux control.
Header file - Function prototypes for PES collection task.
U32BIT STB_OSGetClockMilliseconds(void)
Get Current Computer Clock Time.
void STB_SUBReadSettings(BOOLEAN *started, U16BIT *pid, U16BIT *comp_id, U16BIT *anc_id, BOOLEAN *enabled)
returns the current status information
Definition: stbdsc.c:1214
#define DBGPRINT(...)
Definition: dbgfuncs.h:74
U16BIT STB_DPGetTextPID(U8BIT path)
Reads the teletext PID value from decode path store.
Definition: stbdpc.c:7323
void STB_SUBEnable(U8BIT path, BOOLEAN enable)
Enables or disables subtitling display.
Definition: stbdsc.c:995
void STB_SUBStart(U8BIT path, U16BIT pid, U16BIT composition_id, U16BIT ancillary_id)
Starts subtitling display.
Definition: stbdsc.c:1044