DVBCore  20.3.0
DVBCore Documentation
stbpes.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  *******************************************************************************/
26 /* #define STB_PES_COLLECTION_PRINT_REQUIRED */
27 
28 //---includes for this file----------------------------------------------------
29 // compiler library header files
30 
31 #include <string.h>
32 
33 // third party header files
34 
35 // Ocean Blue Software header files
36 
37 #include <techtype.h>
38 #include <dbgfuncs.h>
39 
40 #include "stbhwos.h"
41 #include "stbhwdmx.h"
42 #include "stbheap.h"
43 #include "stbpes.h"
44 #include "stbdpc.h"
45 
46 
47 //---constant definitions for this file----------------------------------------
48 
49 #define PES_COLL_TASK_STACK_SIZE 1024 * 4
50 #define PES_COLLECTION_PRIORITY STB_TPID_CBUFF_PRIORITY - 1
51 
52 // pes_hdr_data_len byte location withinthe PES packet structure
53 #define PES_HDR_DATA_LEN_BYTE 0x08
54 
55 typedef enum e_pes_state
56 {
57  LOOKING_PREFIX_BYTE_ONE,
58  LOOKING_PREFIX_BYTE_TWO,
59  LOOKING_PREFIX_CODE_THREE,
60  LOOKING_STREAM_ID,
61 
62  LOOKING_LENGTH_BYTE_ONE,
63  LOOKING_LENGTH_BYTE_TWO,
64 
65  LOOKING_FOR_END
66 } E_PES_STATE;
67 
68 #define FIXED_BUFFER_LENGTH 8192L
69 
70 // Debug message macros
71 
72 #ifdef STB_PES_COLLECTION_PRINT_REQUIRED
73  #define STB_PRINT_PES_ERROR
74  #ifdef STB_PES_COLLECTION_CHANNEL_DEBUG_REQUIRED
75  #define STB_PES_COLLECTION_PRINT(x) DEBUG_PRINTX_CONDITIONAL(DEBUG_STB_OSD) x
76  #else
77  #define STB_PES_COLLECTION_PRINT(x) STB_SPDebugWrite x
78  #endif
79 #else
80  #define STB_PES_COLLECTION_PRINT(x)
81 #endif
82 
83 //---local typedef structs for this file---------------------------------------
84 
85 typedef struct s_pes_request
86 {
87  U32BIT handle;
88  U8BIT lowest_data_identifier;
89  U8BIT highest_data_identifier;
90  void (*callback_function)(U32BIT, U8BIT, void *, U32BIT); // (handle, data_identifier, pes_data_ptr, pes_data_length)
91 
92  struct s_pes_request *next_ptr;
94 
95 //---local (static) variable declarations for this file------------------------
96 // (internal variables declared static to make them local)
97 
98 static BOOLEAN initialised;
99 
100 static void *pes_collection_task;
101 
102 static U8BIT pes_collection_path = INVALID_RES_ID;
103 static BOOLEAN reset_pes_collection_task;
104 
105 static S_PES_REQUEST *pes_request_link_list;
106 static void *pes_request_semaphore;
107 
108 static U32BIT next_avaialable_handle;
109 
110 static U8BIT *pes_fixed_buffer;
111 static BOOLEAN task_running;
112 
113 //---local function prototypes for this file-----------------------------------
114 // (internal functions declared static to make them local)
115 
116 static void PesCollectionTask(void *unused);
117 
118 //---local function definitions------------------------------------------------
119 
132 static void PesCollectionTask(void *unused)
133 {
134  U8BIT data_identifier;
135  U32BIT m_buf_size, pes_len, num_bytes_obtained;
136  U32BIT nbytes, available_bytes, remaining_bytes, i;
137  E_PES_STATE state;
138  U8BIT *malloc_buf;
139  U8BIT *buffer;
140  S_PES_REQUEST *pes_request_ptr;
141  U8BIT demux;
142 #ifdef STB_PRINT_PES_ERROR
143  BOOLEAN pes_error;
144 #endif
145 
146  FUNCTION_START(PesCollectionTask);
147 
148  USE_UNWANTED_PARAM(unused);
149 
150  malloc_buf = NULL;
151  pes_len = 0;
152 
153  state = LOOKING_PREFIX_BYTE_ONE;
154  num_bytes_obtained = 0;
155 #ifdef STB_PRINT_PES_ERROR
156  pes_error = FALSE;
157 #endif
158  demux = INVALID_RES_ID;
159 
160  while (1)
161  {
162  if (reset_pes_collection_task)
163  {
164  reset_pes_collection_task = FALSE;
165  state = LOOKING_PREFIX_BYTE_ONE;
166 
167  if (pes_collection_path != INVALID_RES_ID)
168  {
169  demux = STB_DPGetPathDemux(pes_collection_path);
170  }
171  else
172  {
173  demux = INVALID_RES_ID;
174  }
175  }
176 
177  if (demux != INVALID_RES_ID)
178  {
179  STB_DMXReadTextPES(demux, &buffer, &nbytes);
180  STB_PES_COLLECTION_PRINT(("DMX PES returns %d", nbytes));
181  if (nbytes == 0)
182  {
183  /* Give the OS a chance to deschedule task */
184  STB_OSTaskDelay(25);
185  }
186  }
187  else
188  {
189  /* Give the OS a chance to deschedule task */
190  STB_OSTaskDelay(25);
191  nbytes = 0;
192  }
193 
194  // Find begin of a PES; PES Prefix 0x00 0x00 0x01 Then Stream ID 0xbd
195  i = 0;
196  while (i < nbytes)
197  {
198  switch (state)
199  {
200  case LOOKING_PREFIX_BYTE_ONE:
201  {
202  if (buffer[i] == 0x00)
203  {
204  state = LOOKING_PREFIX_BYTE_TWO;
205  num_bytes_obtained = 0;
206 
207  #ifdef STB_PRINT_PES_ERROR
208  if (pes_error)
209  {
210  STB_SPDebugWrite("pes err@ %d", num_bytes_obtained);
211  }
212  pes_error = TRUE;
213  #endif
214  }
215  #ifdef STB_PES_COLLECTION_PRINT_REQUIRED
216  else
217  {
218  STB_PES_COLLECTION_PRINT(("PES %d: %u=0x%02x", __LINE__, i, buffer[i]));
219  }
220  #endif
221  break;
222  }
223 
224  case LOOKING_PREFIX_BYTE_TWO:
225  {
226  if (buffer[i] == 0x00)
227  {
228  state = LOOKING_PREFIX_CODE_THREE;
229  }
230  else
231  {
232  state = LOOKING_PREFIX_BYTE_ONE;
233  STB_PES_COLLECTION_PRINT(("PES %d: %u=0x%02x\n", __LINE__, i, buffer[i]));
234  }
235  break;
236  }
237 
238  case LOOKING_PREFIX_CODE_THREE:
239  {
240  if (buffer[i] == 0x01)
241  {
242  state = LOOKING_STREAM_ID;
243  }
244  else
245  {
246  if (!(buffer[i] == 0x00))
247  {
248  state = LOOKING_PREFIX_BYTE_ONE;
249  STB_PES_COLLECTION_PRINT(("PES %d: %u=0x%02x", __LINE__, i, buffer[i]));
250  }
251  }
252  break;
253  }
254 
255  case LOOKING_STREAM_ID:
256  {
257  if (buffer[i] == 0xbd)
258  {
259  state = LOOKING_LENGTH_BYTE_ONE;
260  }
261  else
262  {
263  state = LOOKING_PREFIX_BYTE_ONE;
264  STB_PES_COLLECTION_PRINT(("PES %d: %u=0x%02x", __LINE__, i, buffer[i]));
265  }
266  break;
267  }
268 
269  case LOOKING_LENGTH_BYTE_ONE:
270  {
271  // Plus six because length values are form the length bytes onward.
272  m_buf_size = (buffer[i] << 8) + 0xff + 6;
273 
274  if (malloc_buf != NULL)
275  {
276  if (malloc_buf != pes_fixed_buffer)
277  {
278  STB_FreeMemory(malloc_buf);
279  }
280  malloc_buf = NULL;
281  }
282 
283  if ((m_buf_size <= FIXED_BUFFER_LENGTH) && (pes_fixed_buffer != NULL))
284  {
285  malloc_buf = pes_fixed_buffer;
286  }
287  else
288  {
289  malloc_buf = (U8BIT *)STB_GetMemory((U32BIT)m_buf_size);
290  }
291 
292  if (malloc_buf == NULL)
293  {
294  state = LOOKING_PREFIX_BYTE_ONE;
295  }
296  else
297  {
298  malloc_buf[0] = 0x00;
299  malloc_buf[1] = 0x00;
300  malloc_buf[2] = 0x01;
301  malloc_buf[3] = 0xbd;
302  malloc_buf[4] = buffer[i];
303  pes_len = (buffer[i] << 8);
304  state = LOOKING_LENGTH_BYTE_TWO;
305  }
306  break;
307  }
308 
309  case LOOKING_LENGTH_BYTE_TWO:
310  {
311  malloc_buf[5] = buffer[i];
312  pes_len += buffer[i];
313 
314  state = LOOKING_FOR_END;
315 
316  // Six because length values are form the length bytes onward.
317  num_bytes_obtained = 6;
318  break;
319  }
320 
321  case LOOKING_FOR_END:
322  {
323  // PES continues into this buffer
324  // Plus six because length values are form the length bytes onward.
325  remaining_bytes = (pes_len + 6) - num_bytes_obtained;
326 
327  if (remaining_bytes <= (nbytes - i))
328  {
329  // Remainder of PES present in this buffer
330  #ifdef STB_PRINT_PES_ERROR
331  pes_error = FALSE;
332  #endif
333  memcpy((void *)&malloc_buf[num_bytes_obtained], (void *)&buffer[i], (size_t)remaining_bytes);
334 
335  data_identifier = malloc_buf[PES_HDR_DATA_LEN_BYTE + malloc_buf[PES_HDR_DATA_LEN_BYTE] + 1];
336 
337  if (!reset_pes_collection_task)
338  {
339  STB_PES_COLLECTION_PRINT(("PES size %d", pes_len + 6));
340 
341  // We are going to traverse a link-list wich can be altered by other threads.
342  STB_OSSemaphoreWait(pes_request_semaphore);
343 
344  pes_request_ptr = pes_request_link_list;
345 
346  while (pes_request_ptr != NULL)
347  {
348  if ((data_identifier >= pes_request_ptr->lowest_data_identifier) &&
349  (data_identifier <= pes_request_ptr->highest_data_identifier))
350  {
351  (*pes_request_ptr->callback_function)(pes_request_ptr->handle,
352  data_identifier,
353  (void *)malloc_buf,
354  num_bytes_obtained + remaining_bytes);
355  }
356 
357  pes_request_ptr = pes_request_ptr->next_ptr;
358  }
359 
360  STB_OSSemaphoreSignal(pes_request_semaphore);
361 
362  if (malloc_buf != pes_fixed_buffer)
363  {
364  STB_FreeMemory(malloc_buf);
365  }
366  malloc_buf = NULL;
367  }
368 
369  state = LOOKING_PREFIX_BYTE_ONE;
370 
371  // Because the remainder of this PES is in this buffer, there may be another PES
372  // starting at the end of this buffer.
373  // NB. added minus one because of the i++ later.
374  i += remaining_bytes - 1;
375  }
376  else
377  {
378  // PES continues into another buffer
379  available_bytes = nbytes - i;
380  memcpy((void *)&malloc_buf[num_bytes_obtained], (void *)&buffer[i], (size_t)available_bytes);
381  num_bytes_obtained += available_bytes;
382  i += available_bytes;
383  }
384  break;
385  }
386 
387  default:
388  {
389  state = LOOKING_PREFIX_BYTE_ONE;
390  STB_PES_COLLECTION_PRINT(("PES %d: %u=0x%02x", __LINE__, i, buffer[i]));
391  break;
392  }
393  }
394  i++;
395  }
396  }
397 
398  STB_PES_COLLECTION_PRINT(("PesCollectionTask Terminated"));
399 
400  FUNCTION_FINISH(PesCollectionTask);
401 }
402 
403 //---global function definitions-----------------------------------------------
404 
417 {
418  FUNCTION_START(STB_PesCollectionTaskInitialise);
419 
420  if (!initialised)
421  {
422  pes_fixed_buffer = (U8BIT *)STB_GetMemory(FIXED_BUFFER_LENGTH);
423 
424  pes_request_semaphore = STB_OSCreateSemaphore();
425 
426  pes_collection_task = STB_OSCreateTask(PesCollectionTask, NULL, PES_COLL_TASK_STACK_SIZE,
427  PES_COLLECTION_PRIORITY, (U8BIT *)"PesColl");
428 
429  reset_pes_collection_task = FALSE;
430  initialised = TRUE;
431  }
432 
433  FUNCTION_FINISH(STB_PesCollectionTaskInitialise);
434 }
435 
448 {
449  FUNCTION_START(STB_FlushPesCollectionTask);
450 
451  reset_pes_collection_task = TRUE;
452 
453  FUNCTION_FINISH(STB_FlushPesCollectionTask);
454 }
455 
467 void STB_ChangePesCollectionPID(U8BIT path, U16BIT text_pid)
468 {
469  FUNCTION_START(STB_ChangePesCollectionPID);
470 
471  if ((text_pid != STB_DPGetTextPID(path)) || (path != pes_collection_path))
472  {
473  if ((pes_collection_path != INVALID_RES_ID) && (pes_collection_path != path))
474  {
475  /* Stop the current PES collection */
476  STB_DPSetTextPID(pes_collection_path, 0);
477  }
478 
479  /* Set the new PID */
480  STB_DPSetTextPID(path, text_pid);
481 
482  reset_pes_collection_task = TRUE;
483 
484  if (text_pid == 0)
485  {
486  /* PES collection has been stopped */
487  pes_collection_path = INVALID_RES_ID;
488  }
489  else
490  {
491  pes_collection_path = path;
492  task_running = TRUE;
493  }
494  }
495 
496  FUNCTION_FINISH(STB_ChangePesCollectionPID);
497 }
498 
537 U32BIT STB_RegisterPesCollectionCallback(void (*callback_function)(U32BIT, U8BIT, void *, U32BIT),
538  U8BIT lowest_data_identifier, U8BIT highest_data_identifier)
539 {
540  U32BIT retval;
541  S_PES_REQUEST *pes_request_ptr;
542 
543  FUNCTION_START(STB_RegisterPesCollectionCallback);
544 
545  retval = 0L;
546 
547  if (initialised == TRUE)
548  {
549  // If we have valid parameters....
550  if ((callback_function) &&
551  (lowest_data_identifier <= highest_data_identifier))
552  {
553  // ...and we can add allocate a PES reqyest structure
554  pes_request_ptr = (S_PES_REQUEST *)STB_GetMemory(sizeof(S_PES_REQUEST));
555  if (pes_request_ptr != NULL)
556  {
557  // Contrive a unique handle to be returned - can be used to cancel the callback request,
558  next_avaialable_handle++;
559  pes_request_ptr->handle = next_avaialable_handle;
560 
561  // Make record of PES request details.
562  pes_request_ptr->callback_function = callback_function;
563  pes_request_ptr->lowest_data_identifier = lowest_data_identifier;
564  pes_request_ptr->highest_data_identifier = highest_data_identifier;
565 
566  // We are going to alter a link-list traversed by several threads.
567  STB_OSSemaphoreWait(pes_request_semaphore);
568 
569  // Attach PES request record to head of lin-list.
570  pes_request_ptr->next_ptr = pes_request_link_list;
571  pes_request_link_list = pes_request_ptr;
572 
573  // Return value is request record handle.
574  retval = pes_request_ptr->handle;
575 
576  STB_OSSemaphoreSignal(pes_request_semaphore);
577  }
578  }
579  }
580 
581  FUNCTION_FINISH(STB_RegisterPesCollectionCallback);
582 
583  return(retval);
584 }
585 
603 {
604  S_PES_REQUEST *pes_request_ptr;
605  S_PES_REQUEST *prev_pes_request_ptr;
606 
607  FUNCTION_START(STB_UnregisterPesCollectionCallback);
608 
609  if (initialised == TRUE)
610  {
611  // We are going to alter a link-list traversed by several threads.
612  STB_OSSemaphoreWait(pes_request_semaphore);
613 
614  // Initialise pointers used to traverse the link-list.
615  pes_request_ptr = pes_request_link_list;
616  prev_pes_request_ptr = NULL;
617 
618  // Go through link-list looking for handle match
619  while (pes_request_ptr != NULL)
620  {
621  if (handle == pes_request_ptr->handle)
622  {
623  // If this is the first record on the link list...
624  if (prev_pes_request_ptr == NULL)
625  {
626  // ... then just modify the link-list header pointer.
627  pes_request_link_list = pes_request_link_list->next_ptr;
628  }
629  else
630  {
631  // ... then modify the previos link-list record to point to the next.
632  prev_pes_request_ptr->next_ptr = pes_request_ptr->next_ptr;
633  }
634 
635  // The record has now been removed from the link-list, so can be safely freed.
636  STB_FreeMemory(pes_request_ptr);
637 
638  // Once matching handle has been delat with, quit.
639  break;
640  }
641 
642  // Move to next link-list item
643  prev_pes_request_ptr = pes_request_ptr;
644  pes_request_ptr = pes_request_ptr->next_ptr;
645  }
646 
647  STB_OSSemaphoreSignal(pes_request_semaphore);
648  }
649 
650  FUNCTION_FINISH(STB_UnregisterPesCollectionCallback);
651 }
652 
653 //*****************************************************************************
654 // End of file
655 //*****************************************************************************
656 
void * STB_GetMemory(U32BIT bytes)
Attempts to allocate memory from the heap.
Definition: stbheap.c:221
void STB_PesCollectionTaskInitialise(void)
Initialises the PES collection task.
Definition: stbpes.c:416
void STB_FlushPesCollectionTask(void)
Flushes the PES collection task.
Definition: stbpes.c:447
Header file - macros and function prototypes for public use.
void * STB_OSCreateSemaphore(void)
Create a Semaphore.
void STB_ChangePesCollectionPID(U8BIT path, U16BIT text_pid)
Changes the PID that the DMX is using to gather data on.
Definition: stbpes.c:467
void STB_OSSemaphoreSignal(void *semaphore)
Signal a Semaphore to Release it by decrementing its counter.
void STB_OSSemaphoreWait(void *semaphore)
Wait on Semaphore Indefinity or Until Released.
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
void STB_FreeMemory(void *addr)
Releases previously allocated heap memory.
Definition: stbheap.c:336
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.
void STB_DMXReadTextPES(U8BIT path, U8BIT **buffer, U32BIT *num_bytes)
Reads Teletext PES data from the demux.
Header file - Function prototypes for operating system.
System Wide Global Technical Data Type Definitions.
void STB_UnregisterPesCollectionCallback(U32BIT handle)
Used to un-register a callback function that will receive specific PES data packets.
Definition: stbpes.c:602
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...
Header file - Function prototypes for heap memory.
void STB_DPSetTextPID(U8BIT path, U16BIT pid)
Writes teletext PID value into decode path store.
Definition: stbdpc.c:7288
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.
U8BIT STB_DPGetPathDemux(U8BIT path)
Returns the demux path ID acquired by the given decode path.
Definition: stbdpc.c:1711
U16BIT STB_DPGetTextPID(U8BIT path)
Reads the teletext PID value from decode path store.
Definition: stbdpc.c:7323