MHEG5  18.9.0
MHEG5 Documentation
stmr_dl.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2010 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 #include <assert.h>
27 #include <string.h>
28 
29 #include "stb_os.h"
30 #include "glue_memory.h"
31 #include "glue_debug.h"
32 #include "glue_queue.h"
33 
34 #include "http_interface.h"
35 #include "stmr_dl.h"
36 #include "stmr_common.h"
37 #include "http_header.h"
38 #include "stmr_header.h"
39 #include "stmr_queue.h"
40 #include "mh5streamer.h"
41 
42 
43 /*---constant definitions for this file--------------------------------------*/
44 
45 #ifdef ICS_THROTTLE
46 #define THROTTLE_BYTES (3 * 1024 * 1024 - 262144)
47 #endif
48 
49 #define INVALID_TIMESTAMP 0xffffffff
50 #define SYNC_BYTE 0x47
51 #define SYNC_COUNT_ACCEPT 20
52 #define SYNC_BUFFER_SIZE (STMR_TS_PACKET_SIZE * SYNC_COUNT_ACCEPT)
53 #define SYNC_COUNT_MIN_ACCEPT (SYNC_COUNT_ACCEPT / 2)
54 
55 #define USE_MAGIC
56 
57 #ifdef USE_MAGIC
58 #define GOOD_MAGIC 0xdeadbeef
59 #define BAD_MAGIC 0xfefefefe
60 #define SET_MAGIC(r) do { r->magic = GOOD_MAGIC; } while (0)
61 #define VERIFY_MAGIC(r) assert(r->magic == GOOD_MAGIC)
62 #define CLEAR_MAGIC(r) do { r->magic = BAD_MAGIC; } while (0)
63 #else
64 #define SET_MAGIC(r)
65 #define VERIFY_MAGIC(r)
66 #define CLEAR_MAGIC(r)
67 #endif
68 
69 #define DBG(x)
70 #define PDBG(x) TRACE(TICS, x)
71 
72 
73 /*---local typedef structs for this file-------------------------------------*/
74 
76 {
80 };
81 
83 {
87 };
88 
89 typedef struct sPsiInfo
90 {
101 } PsiInfo;
102 
103 typedef struct sDownloadRequest
104 {
105  /* Magic */
107 
108  /* Download ID */
110 
111  /* Request ID */
113 
114  /* HTTP or HTTPS */
116 
117  /* HTTP handle */
119 
120  /* Response code and status */
123 
124  /* Request information */
127 
128  /* Last request */
130 
131  /* Download */
135 
138 
141 
142  enum SyncState syncState;
143  U8BIT syncBuffer[SYNC_BUFFER_SIZE];
145 
149 
150  #ifdef ICS_THROTTLE
151  BOOLEAN throttled;
152  U64BIT throttledBytes;
153  U32BIT targetBitrate;
154  #endif
155 
156  /* Partial data to allow buffering of complete packets */
159 
160  /* PSI information */
162 
163  /* Next request */
166 
167 /*---local function definitions----------------------------------------------*/
168 
169 /*---global function definitions---------------------------------------------*/
170 
171 static DownloadRequest* FindRequestById(U32BIT downloadId);
172 static BOOLEAN HeaderCallback(void *userdata, U32BIT downloadId,
173  HttpResponse_t *response);
174 static void HandleHeaderData(DownloadRequest *request, U8BIT *data,
175  U32BIT len);
176 static BOOLEAN ContentCallback(void *userdata, U32BIT downloadId,
177  HttpResponse_t *response);
178 static BOOLEAN HandleStreamData(DownloadRequest *request, U8BIT *data,
179  U32BIT len);
180 static BOOLEAN HandleData(DownloadRequest *request, U8BIT *data, U32BIT len);
181 static BOOLEAN StoreItem(DownloadRequest *request, U8BIT *data, U32BIT len,
182  MHEG5QueueItem **pItem);
183 #ifdef ICS_THROTTLE
184 static void CheckThrottling(DownloadRequest *request);
185 #endif
186 static BOOLEAN ProcessItem(MHEG5QueueItem *item, PsiInfo *psiInfo);
187 static BOOLEAN ProcessPacket(U8BIT *packet, PsiInfo *psiInfo,
188  U32BIT *timestamp);
189 static BOOLEAN BuildSection(U8BIT *packet, U8BIT *section, U16BIT *offset);
190 static void HandlePatSection(PsiInfo *psiInfo);
191 static void HandlePmtSection(PsiInfo *psiInfo);
192 static BOOLEAN HandlePcrPacket(U8BIT *packet, U32BIT *timestamp);
193 static void NotifyHeadersDone(U32BIT downloadId,S32BIT code);
194 static void NotifyDownloadComplete(U32BIT downloadId,E_HttpStatus status,S32BIT code);
195 static BOOLEAN IsValidSection(U8BIT *section);
196 static BOOLEAN IsPositionPartial(DownloadRequest *request);
197 
198 /*---local (static) variable declarations for this file----------------------*/
199 
200 static DownloadRequest *downloadRequestList = NULL;
201 
202 
215 {
216  char rangeBuffer[MHEG5_MAX_RANGE_BUFFER];
217  DownloadRequest *request;
219 
220  downloadId = 0;
221  request = MHEG5getMem(sizeof *request);
222  if (request != NULL)
223  {
224  SET_MAGIC(request);
225 
226  /* Download ID is a unique ID */
227  request->downloadId = MHEG5GetUniqueId();
228 
229  request->requestId = requestId;
230 
231  request->https = FALSE;
232  if (memcmp(url, "https://", 8) == 0)
233  {
234  request->https = TRUE;
235  }
236 
237  request->rangeFrom = rangeFrom;
238  request->rangeTo = rangeTo;
239  request->lastRequest = lastRequest;
240 
241  request->handle = NULL;
242  request->code = 0;
243  request->status = HTTP_STATUS_OTHER_ERROR;
244 
245  ULL_SetInvalid(request->contentLength);
246  ULL_Set32(request->bytesReceived, 0);
247  ULL_SetInvalid(request->bytesExpected);
248 
249  request->processing = FALSE;
250  request->stopped = FALSE;
251 
252  request->keyLocation.len = 0;
253  request->keyLocation.data = NULL;
254  request->keys.num_pids = 0;
255  request->keys.pid_info = 0;
256 
257  request->syncState = SYNC_ACCUM;
258  request->syncBufferPos = 0;
259 
260  request->bytesPerSecond = 0;
261  request->knownBitrate = FALSE;
262  request->timestamp = 0;
263  #ifdef ICS_THROTTLE
264  request->throttled = FALSE;
265  request->targetBitrate = 0;
266  ULL_Set32(request->throttledBytes, 0);
267  #endif
268 
269  request->partialDataLength = 0;
270 
271  request->psiInfo.state = PSI_STATE_PAT;
272  request->psiInfo.offset = 0;
273  request->psiInfo.pmt_pid = 0xffff;
274  request->psiInfo.pcr_pid = 0xffff;
280 
281  request->next = downloadRequestList;
282  downloadRequestList = request;
283 
284  ULL_Itoa(rangeFrom, rangeBuffer);
285  strcat(rangeBuffer, "-");
286  if (ULL_IsValid(rangeTo))
287  {
288  ULL_Itoa(rangeTo, &rangeBuffer[strlen(rangeBuffer)]);
289  }
290 
291  request->handle = httpCreateStreamRequest((U8BIT *)url,
292  (U8BIT *)rangeBuffer,
293  HeaderCallback,
294  ContentCallback,
295  request->downloadId,
296  request);
297  if (request->handle != NULL)
298  {
299  downloadId = request->downloadId;
300  }
301  else
302  {
303  /* Failed to create an HTTP request */
304  MHEG5freeMem(request);
305  request = NULL;
306  }
307  }
308 
309  return downloadId;
310 }
311 
318 {
319  DownloadRequest *request;
320 
321  request = FindRequestById(downloadId);
322  if (request != NULL)
323  {
324  VERIFY_MAGIC(request);
325 
326  assert(request->handle != NULL);
327  httpStartRequest(request->handle);
328  }
329 }
330 
338 {
339  DownloadRequest *request;
340  U8BIT *redirectUrl = NULL;
341 
342  request = FindRequestById(downloadId);
343  if (request != NULL)
344  {
345  VERIFY_MAGIC(request);
346 
347  PDBG(("id=%d",downloadId));
348  redirectUrl = httpGetRequestRedirect(request->handle);
349  }
350  return redirectUrl;
351 }
352 
360 {
361  DownloadRequest *request;
362  BOOLEAN result;
363  request = FindRequestById(downloadId);
364  if (request == NULL)
365  {
366  result = FALSE;
367  }
368  else
369  {
370  result = IsPositionPartial(request);
371  }
372  if (result)
373  {
374  *position = request->rangeFrom;
375  ULL_Add(*position,request->bytesReceived);
376  }
377  else
378  {
379  ULL_Set32((*position),0);
380  }
381  return result;
382 }
383 
395 {
396  DownloadRequest *request;
397 
398  request = FindRequestById(downloadId);
399  if (request != NULL)
400  {
401  VERIFY_MAGIC(request);
402 
403  contentLength = request->contentLength;
404  }
405  return contentLength;
406 }
407 
417 {
418  DownloadRequest *request;
419 
420  request = FindRequestById(downloadId);
421  if (request != NULL)
422  {
423  VERIFY_MAGIC(request);
424 
425  if (request->bytesPerSecond > 0)
426  {
427  *bytesPerSecond = request->bytesPerSecond;
428  }
429  }
430 }
431 
445  S_ICSKeys *keys,
447 {
448  DownloadRequest *request;
449 
450  request = FindRequestById(downloadId);
451  if (request != NULL)
452  {
453  VERIFY_MAGIC(request);
454 
455  if ((request->keys.num_pids > 0) || (request->keyLocation.len > 0))
456  {
457  if (keys->num_pids > 0)
458  {
459  /* Clear caller's keys */
460  MHEG5freeMem(keys->pid_info);
461  keys->num_pids = 0;
462  keys->pid_info = NULL;
463  }
464 
465  if (keyLocation->len > 0)
466  {
467  /* Clear caller's key location */
468  MHEG5stringDestruct(keyLocation);
469  }
470 
471  if (request->keys.num_pids > 0)
472  {
473  /* Pass keys ownership */
474  *keys = request->keys;
475 
476  /* Clear requests's keys */
477  request->keys.num_pids = 0;
478  request->keys.pid_info = NULL;
479  }
480 
481  if (request->keyLocation.len > 0)
482  {
483  /* Pass key location ownership */
484  *keyLocation = request->keyLocation;
485 
486  /* Clear requests's key location */
487  request->keyLocation.len = 0;
488  request->keyLocation.data = NULL;
489  }
490  }
491  }
492 }
493 
502 {
503  DownloadRequest *request;
504  BOOLEAN found = FALSE;
505 
506  request = FindRequestById(downloadId);
507  if (request != NULL)
508  {
509  VERIFY_MAGIC(request);
510 
511  if (request->psiInfo.state == PSI_STATE_PCR)
512  {
513  /* PMT was extracted */
514  memcpy(pmt, request->psiInfo.section, STMR_MAX_PSI_SECTION);
515  found = TRUE;
516  }
517  }
518 
519  return found;
520 }
521 
528 {
529  DownloadRequest *request;
530 
531  request = downloadRequestList;
532  if (request != NULL)
533  {
534  VERIFY_MAGIC(request);
535 
536  if (!request->processing)
537  {
538  DBG(("Download: Resuming connection"));
539  httpResumeRequest(request->handle);
540  }
541  }
542 }
543 
550 {
551  DownloadRequest *request;
552 
553  request = downloadRequestList;
554  if (request != NULL)
555  {
556  VERIFY_MAGIC(request);
557 
558  DBG(("Download: Clearing throttling"));
559  request->timestamp = 0;
560 
561  #ifdef ICS_THROTTLE
562  request->throttled = FALSE;
563  request->targetBitrate = 0;
564  ULL_Set32(request->throttledBytes, 0);
565  #endif
566 
571 
572  if (!request->processing)
573  {
574  httpResumeRequest(request->handle);
575  }
576  }
577 }
578 
585 {
586  DownloadRequest *request;
587 
588  request = FindRequestById(downloadId);
589  if (request != NULL)
590  {
591  VERIFY_MAGIC(request);
592 
593  if (request->handle != NULL)
594  {
595  httpStopRequest(request->handle);
596  }
597  }
598 }
599 
610 {
611  DownloadRequest *request;
612 
613  request = FindRequestById(downloadId);
614  if (request != NULL)
615  {
616  VERIFY_MAGIC(request);
617 
618  request->stopped = TRUE;
619  }
620 }
621 
628 {
629  DownloadRequest **pRequest, *request;
630 
631  pRequest = &downloadRequestList;
632  while (*pRequest != NULL)
633  {
634  request = *pRequest;
635  if (request->downloadId == downloadId)
636  {
637  VERIFY_MAGIC(request);
638 
639  *pRequest = request->next;
640 
641  if (request->handle != NULL)
642  {
643  httpDestroyRequest(request->handle);
644  }
645  if (request->keys.num_pids > 0)
646  {
647  MHEG5freeMem(request->keys.pid_info);
648  }
649  MHEG5stringDestruct(&request->keyLocation);
650 
651  MHEG5freeMem(request);
652 
653  break;
654  }
655  else
656  {
657  pRequest = &request->next;
658  }
659  }
660 }
661 
668 {
669  DownloadRequest *request;
670 
671  request = FindRequestById(downloadId);
672  if (request != NULL)
673  {
674  VERIFY_MAGIC(request);
675 
676  if (request->handle != NULL)
677  {
678  httpStopRequest(request->handle);
679  httpDestroyRequest(request->handle);
680  request->handle = NULL;
681  }
682  if (request->keys.num_pids > 0)
683  {
684  MHEG5freeMem(request->keys.pid_info);
685  request->keys.num_pids = 0;
686  request->keys.pid_info = 0;
687  }
688  MHEG5stringDestruct(&request->keyLocation);
689  }
690 }
691 
698 {
699  char rangeBuffer[MHEG5_MAX_RANGE_BUFFER];
700  DownloadRequest *request;
701 
702  request = FindRequestById(downloadId);
703  if (request != NULL)
704  {
705  VERIFY_MAGIC(request);
706  assert(request->handle == NULL);
707  assert(request->status == HTTP_STATUS_PARTIAL);
708 
709  request->processing = FALSE;
710  request->partialDataLength = 0;
711 
712  ULL_Add(request->rangeFrom, request->bytesReceived);
713  ULL_Set32(request->bytesReceived, 0);
714 
715  ULL_SetInvalid(request->contentLength);
716  ULL_SetInvalid(request->bytesExpected);
717 
718  ULL_Itoa(request->rangeFrom, rangeBuffer);
719  strcat(rangeBuffer, "-");
720  if (ULL_IsValid(request->rangeTo))
721  {
722  ULL_Itoa(request->rangeTo, &rangeBuffer[strlen(rangeBuffer)]);
723  }
724  request->handle = httpCreateStreamRequest((U8BIT *)url, (U8BIT *)rangeBuffer,
725  HeaderCallback, ContentCallback, downloadId, request);
726  }
727 }
728 
729 /*******************
730  * LOCAL FUNCTION *
731  ********************/
732 
733 
739 static DownloadRequest* FindRequestById(U32BIT downloadId)
740 {
741  DownloadRequest *request;
742 
743  request = downloadRequestList;
744  while (request != NULL && request->downloadId != downloadId)
745  {
746  request = request->next;
747  }
748 
749  return request;
750 }
751 
759 static BOOLEAN HeaderCallback(void *userdata, U32BIT downloadId,
760  HttpResponse_t *response)
761 {
762  DownloadRequest *request = userdata;
763 
764  VERIFY_MAGIC(request);
765 
766  if (response->data_len <= 2)
767  {
768  /* Store response code */
769  request->code = response->code;
770 
771  /* Send notification to main task */
772  DBG(("Calling NotifyHeadersDone"));
773  NotifyHeadersDone(downloadId,response->code);
774  }
775  else
776  {
777  HandleHeaderData(request, response->data, response->data_len);
778  }
779 
780  return TRUE;
781 }
782 
792 static void HandleHeaderData(DownloadRequest *request, U8BIT *data,
793  U32BIT len)
794 {
795  E_HTTP_FIELD field;
797 
798  /* Parse field for its name, and beginning of field data */
799  data = httpHdrParseFieldName(data, len, &field);
800  switch (field)
801  {
803  contentLength = httpHdrParseContentLength(data, len);
804  if (ULL_IsValid(contentLength) &&
805  !ULL_IsValid(request->contentLength))
806  {
807  request->contentLength = contentLength;
808  request->bytesExpected = contentLength;
809  PDBG(("expected=%s",ULL_ToString(contentLength)));
810  PDBG(("rangeFrom=%s",ULL_ToString(request->rangeFrom)));
811  ULL_Add(request->contentLength, request->rangeFrom);
812  PDBG(("total contentLength=%s",ULL_ToString(request->contentLength)));
813  }
814  break;
816  contentLength = httpHdrParseContentRange(data, len);
817  if (ULL_IsValid(contentLength) && ULL_Compare(contentLength,request->rangeFrom) > 0)
818  {
819  request->contentLength = contentLength;
820  request->bytesExpected = contentLength;
821  PDBG(("expected=%s",ULL_ToString(contentLength)));
822  PDBG(("rangeFrom=%s",ULL_ToString(request->rangeFrom)));
823  ULL_Sub(request->bytesExpected, request->rangeFrom);
824  PDBG(("expected=%s",ULL_ToString(request->bytesExpected)));
825  }
826  break;
827  case HTTP_FIELD_X_KEYS:
828  if (request->keys.num_pids > 0)
829  {
830  MHEG5freeMem(request->keys.pid_info);
831  request->keys.pid_info = NULL;
832  request->keys.num_pids = 0;
833  }
834  MHEG5ParseXKeys(data, len, &request->keys);
835  break;
837  MHEG5stringDestruct(&request->keyLocation);
838  MHEG5ParseXKeyLocation(data, len, &request->keyLocation);
839  break;
842  &request->knownBitrate);
843  break;
844  default:
845  case HTTP_FIELD_UNKNOWN:
846  break;
847  }
848 }
849 
857 static BOOLEAN ContentCallback(void *userdata, U32BIT downloadId,
858  HttpResponse_t *response)
859 {
860  DownloadRequest *request = userdata;
861  BOOLEAN handled;
862 
863  VERIFY_MAGIC(request);
864  assert(request->downloadId == downloadId);
865 
866 
867  if (response->status == HTTP_STATUS_WAIT)
868  {
869  if (request->code == 200 || request->code == 206)
870  {
871  if (!request->https)
872  {
873  handled = HandleStreamData(request, response->data,
874  response->data_len);
875  if (handled && request->stopped)
876  {
877  PDBG(("Pause, id=%d request has stopped",downloadId));
878  request->status = HTTP_STATUS_OK;
879  NotifyDownloadComplete(downloadId,HTTP_STATUS_OK,request->code);
880  handled = FALSE;
881  }
882  }
883  else
884  {
885  /* The test suite doesn't like streaming from HTTPS, so
886  * we report this as an error.
887  */
888  request->code = 0;
889  request->status = HTTP_STATUS_OTHER_ERROR;
890  NotifyDownloadComplete(downloadId,HTTP_STATUS_OTHER_ERROR,0);
891  handled = TRUE;
892  }
893  }
894  else
895  {
896  /* Just ignore the data */
897  handled = TRUE;
898  }
899  }
900  else
901  {
902  PDBG(("response->status = %s",
903  response->status == HTTP_STATUS_OK ? "HTTP_STATUS_OK" :
904  response->status == HTTP_STATUS_PARTIAL ? "HTTP_STATUS_PARTIAL" :
905  response->status == HTTP_STATUS_SSL_ERROR ? "HTTP_STATUS_SSL_ERROR" :
906  response->status == HTTP_STATUS_NETWORK_ERROR ? "HTTP_STATUS_NETWORK_ERROR" :
907  response->status == HTTP_STATUS_TIMEOUT ? "HTTP_STATUS_TIMEOUT" :
908  response->status == HTTP_STATUS_OTHER_ERROR ? "HTTP_STATUS_OTHER_ERROR" :
909  "UNKNOWN"));
910  PDBG(("Download: request %d: finished, code=%ld len=%ld", downloadId,response->code,response->data_len));
911  if (response->code == 206 &&
912  (response->status == HTTP_STATUS_OK || response->status == HTTP_STATUS_TIMEOUT) &&
913  IsPositionPartial(request) )
914  {
915  response->status = HTTP_STATUS_PARTIAL;
916  }
917  request->status = response->status;
918  NotifyDownloadComplete(downloadId,response->status,response->code);
919  handled = TRUE;
920  }
921  return handled;
922 }
923 
931 static BOOLEAN HandleStreamData(DownloadRequest *request, U8BIT *data,
932  U32BIT len)
933 {
934  BOOLEAN handled = FALSE;
935 #ifdef ICS_THROTTLE
936  U32BIT current;
937  U64BIT bytes;
938  U32BIT bitrate;
939  BOOLEAN queueData = TRUE;
940 
941  if (request->throttled)
942  {
943  queueData = FALSE;
944 
945  /* Check if data can be handled */
946  current = STB_OSGetClockMilliseconds();
947  if (current > request->timestamp)
948  {
949  bytes = request->throttledBytes;
950  ULL_Sub32(bytes, THROTTLE_BYTES);
951  ULL_Add32(bytes, len);
952  /* Over-estimate by 5% */
953  ULL_Mul32(bytes, 1050);
954  ULL_Div32(bytes, (current - request->timestamp));
955  bitrate = ULL_Get32(bytes);
956 
957  /*
958  DBG_PRINTF("%d bytes d/l, ts = %d, ct = %d\n",
959  ULL_Get32(request->throttledBytes) + len,
960  request->timestamp, current);
961  */
962 
963  if (bitrate <= request->targetBitrate)
964  {
965  /*DBG_PRINTF("Data allowed\n");*/
966  /*DBG_PRINTF("%d bytes d/l, ts = %d, ct = %d\n",
967  ULL_Get32(bytes),
968  request->timestamp, current);*/
969  queueData = TRUE;
970  }
971  }
972  }
973 
974  if (queueData)
975  {
976  /* Cannot handle the data - pause the connection */
977  DBG(("Download: Pausing connection"));
978  assert(!handled);
979  }
980  else
981 #endif /* ICS_THROTTLE */
982  {
983  handled = HandleData(request, data, len);
984  if (handled)
985  {
986  #ifdef ICS_THROTTLE
987  ULL_Add32(request->throttledBytes, len);
988  #endif
989  }
990  else
991  {
992  /* Cannot handle the data - pause the connection */
993  DBG(("Download: Pausing connection"));
994  }
995  }
996  request->processing = handled;
997  return handled;
998 }
999 
1000 static BOOLEAN FindSyncOffset( U8BIT *syncBuffer, U16BIT *pOffset )
1001 {
1002  U16BIT offset, i, count, maxCount, bestOffset;
1003  bestOffset = 0;
1004  maxCount = 0;
1005  for (offset = 0; offset != STMR_TS_PACKET_SIZE; offset++)
1006  {
1007  count = 0;
1008  for (i = offset; i != (SYNC_BUFFER_SIZE + offset); i += STMR_TS_PACKET_SIZE)
1009  {
1010  count += (syncBuffer[i] == SYNC_BYTE);
1011  }
1012 
1013  if (count == SYNC_COUNT_ACCEPT)
1014  {
1015  /* Accept immediately */
1016  break;
1017  }
1018 
1019  if (count > maxCount)
1020  {
1021  maxCount = count;
1022  bestOffset = offset;
1023  }
1024  }
1025 
1026  if (maxCount >= SYNC_COUNT_MIN_ACCEPT)
1027  {
1028  DBG(("[sync] Found possible offset %d with count %d\n",
1029  bestOffset, maxCount));
1030  offset = bestOffset;
1031  }
1032  if (offset == STMR_TS_PACKET_SIZE)
1033  {
1034  /* Tried every offset but couldn't find enough sync_bytes,
1035  * so the sync process has failed
1036  */
1037  DBG(("[sync] Could not find sync offset"));
1038  #if 0
1039  {
1040  int i;
1041  for (i = 0; i < SYNC_BUFFER_SIZE; i++)
1042  {
1043  DBG_PRINTF("%02x ", syncBuffer[i]);
1044  if (i % 16 == 15)
1045  {
1046  DBG_PRINTF("\n");
1047  }
1048  }
1049  }
1050  #endif
1051  return FALSE;
1052  }
1053  DBG(("[sync] Found offset %d", offset));
1054  *pOffset = offset;
1055  return TRUE;
1056 }
1057 
1066 static BOOLEAN HandleData( DownloadRequest *request, U8BIT *data, U32BIT len )
1067 {
1068  U16BIT offset, origOffset;
1069  BOOLEAN success;
1070  MHEG5QueueItem *item;
1071 
1072  success = TRUE;
1073 
1074  switch (request->syncState)
1075  {
1076  case SYNC_ACCUM:
1077  origOffset = request->syncBufferPos;
1078 
1079  /* Accumulate data until there is enough for the sync process */
1080  DBG(("[sync] request->syncState == SYNC_ACCUM"));
1081  assert( origOffset < SYNC_BUFFER_SIZE );
1082  offset = SYNC_BUFFER_SIZE - origOffset;
1083  if (offset > len)
1084  {
1085  offset = (U16BIT)len;
1086  }
1087  memcpy(request->syncBuffer + origOffset, data, offset);
1088 
1089  DBG(("[sync] Updated request->syncBufferPos from %d to %d",
1090  request->syncBufferPos, request->syncBufferPos + offset));
1091  request->syncBufferPos += offset;
1092 
1093  if (request->syncBufferPos != SYNC_BUFFER_SIZE)
1094  {
1095  // continue accumulating
1096  break;
1097  }
1098 
1099  /* Perform sync process */
1100  DBG(("[sync] request->SyncState == SYNC_ACCUM and enough data"));
1101  if (!FindSyncOffset( request->syncBuffer, &offset ))
1102  {
1103  request->syncState = SYNC_FAILED;
1104  success = FALSE;
1105  break;
1106  }
1107  request->syncState = SYNC_FOUND;
1108  if (offset != 0)
1109  {
1110  // dropping 'offset' bytes - sync byte not at beginning of buffer
1111  DBG(("[sync] offset = %d", offset));
1112  // still register that these bytes have been received,
1113  // even though they are being ignored
1114  ULL_Add32(request->bytesReceived, offset);
1115  }
1116  if (offset == origOffset)
1117  {
1118  // nothing to drop, and nothing accumulated before this packet
1119  }
1120  else if (offset > origOffset)
1121  {
1122  // sync bye not at beginning of packet
1123  len -= offset - origOffset;
1124  data += offset - origOffset;
1125  }
1126  else //if ( offset < origOffset )
1127  {
1128  // Add data from sync buffer
1129  if (!StoreItem(request, request->syncBuffer + offset, origOffset - offset, &item))
1130  {
1131  success = FALSE;
1132  break;
1133  }
1134  if (item != NULL)
1135  {
1136  (void)ProcessItem(item, &request->psiInfo);
1137  MHEG5QueueInsertItem(item);
1138  }
1139  }
1140  // fallthrough
1141 
1142  case SYNC_FOUND:
1143  if (!StoreItem(request, data, len, &item))
1144  {
1145  success = FALSE;
1146  break;
1147  }
1148  if (item != NULL)
1149  {
1150  if (!ProcessItem(item, &request->psiInfo))
1151  {
1152  request->syncState = SYNC_ACCUM;
1153  origOffset = request->partialDataLength;
1154  request->syncBufferPos = origOffset;
1155  if (origOffset != 0)
1156  {
1157  memcpy(request->syncBuffer, request->partialData, origOffset);
1158  request->partialDataLength = 0;
1159  }
1160  }
1161  MHEG5QueueInsertItem(item);
1162  }
1163  break;
1164 
1165  default:
1166  case SYNC_FAILED:
1167  PDBG(("syncState=%d",request->syncState));
1168  success = FALSE;
1169  break;
1170  }
1171  return success;
1172 }
1173 
1183 static BOOLEAN StoreItem(DownloadRequest *request, U8BIT *data, U32BIT len,
1184  MHEG5QueueItem **pItem)
1185 {
1186  U32BIT totalLen, storeLen, partialLen, remainingLen;
1187  MHEG5QueueItem *item;
1188  BOOLEAN success;
1189 
1190  *pItem = NULL;
1191 
1192  totalLen = len + request->partialDataLength;
1193  storeLen = totalLen - totalLen % STMR_TS_PACKET_SIZE;
1194  if (storeLen >= STMR_TS_PACKET_SIZE)
1195  {
1196  partialLen = storeLen - request->partialDataLength;
1197 
1198  /* partialDataLength bytes from the request and partialLen bytes
1199  * from the new data are stored in the queue (if possible). This
1200  * leaves us with (len - partialLen) bytes to store in
1201  * the request's partialData buffer.
1202  */
1203  item = MHEG5QueueAllocItem(request->requestId, storeLen);
1204  if (item == NULL)
1205  {
1206  DBG(("FAIL Q alloc for %d",storeLen));
1207  success = FALSE;
1208  }
1209  else
1210  {
1211  /* Copy partial data (if any) into item */
1212  if (request->partialDataLength > 0)
1213  {
1214  memcpy(item->data, request->partialData,
1215  request->partialDataLength);
1216  item->len += request->partialDataLength;
1217  }
1218 
1219  /* Copy new data into item */
1220  memcpy(item->data + item->len, data, partialLen);
1221  item->len += partialLen;
1222 
1223  /* Copy remaining data into the request for next time */
1224  remainingLen = len - partialLen;
1225  if (remainingLen > 0)
1226  {
1227  assert(remainingLen < STMR_TS_PACKET_SIZE);
1228  memcpy(request->partialData, data + partialLen,
1229  remainingLen);
1230  }
1231  request->partialDataLength = (U16BIT)remainingLen;
1232 
1233  PDBG(("Download: Inserting item(%d, %u + %u + %u)",
1234  request->downloadId, ULL_Get32(request->rangeFrom),
1235  ULL_Get32(request->bytesReceived),storeLen));
1236 
1237  item->position = request->bytesReceived;
1238  item->base = request->rangeFrom;
1239  item->downloadId = request->downloadId;
1240  item->timestamp = 0;
1241 
1242  ULL_Add32(request->bytesReceived, storeLen);
1243  if ((request->lastRequest) &&
1244  (ULL_IsEqual(request->bytesReceived,
1245  request->bytesExpected)))
1246  {
1247  PDBG(("expected=%s",ULL_ToString(request->bytesExpected)));
1248  item->last = TRUE;
1249  }
1250  else
1251  {
1252  item->last = FALSE;
1253  }
1254 
1255  #ifdef ICS_THROTTLE
1256  if (!request->throttled)
1257  {
1258  CheckThrottling(request);
1259  }
1260  #endif
1261 
1262  *pItem = item;
1263 
1264  success = TRUE;
1265  }
1266  }
1267  else
1268  {
1269  /* Not enough data to store in the buffer */
1270  memcpy(request->partialData + request->partialDataLength,
1271  data, len);
1272  request->partialDataLength += (U16BIT)len;
1273 
1274  success = TRUE;
1275  }
1276 
1277  return success;
1278 }
1279 
1280 #ifdef ICS_THROTTLE
1281 
1286 static void CheckThrottling(DownloadRequest *request)
1287 {
1288  U64BIT bitrate;
1289 
1290  if (!request->throttled)
1291  {
1292  if (ULL_Get32(request->throttledBytes) >= THROTTLE_BYTES &&
1293  request->psiInfo.firstTimestamp != request->psiInfo.lastTimestamp)
1294  {
1295  request->throttled = TRUE;
1296 
1297  bitrate = request->psiInfo.lastPosition;
1298  ULL_Sub(bitrate, request->psiInfo.firstPosition);
1299  ULL_Mul32(bitrate, 1200);
1300  ULL_Div32(bitrate, request->psiInfo.lastTimestamp - request->psiInfo.firstTimestamp);
1301  request->targetBitrate = ULL_Get32(bitrate);
1303  /*ULL_Set32(request->throttledBytes, 0);*/
1304  }
1305  }
1306 }
1307 
1308 #endif /* ICS_THROTTLE */
1309 
1310 
1318 static BOOLEAN ProcessItem(MHEG5QueueItem *item, PsiInfo *psiInfo)
1319 {
1320  U32BIT remaining = item->len;
1321  U8BIT *packet = item->data;
1322  U32BIT timestamp;
1323  BOOLEAN ok;
1324 
1325  ok = TRUE;
1326  assert((remaining % STMR_TS_PACKET_SIZE) == 0);
1327  while (remaining != 0)
1328  {
1329  if (packet[0] != SYNC_BYTE)
1330  {
1331  PDBG(("Need to find sync byte again"))
1332  ok = FALSE;
1333  break;
1334  }
1335  if (ProcessPacket(packet, psiInfo, &timestamp))
1336  {
1337  DBG(("item=%p position=%s timestamp=%lu remaining=%d",item,ULL_ToString(item->position),timestamp,remaining));
1338  if (psiInfo->firstTimestamp == INVALID_TIMESTAMP)
1339  {
1340  psiInfo->firstTimestamp = timestamp;
1341  psiInfo->firstPosition = item->position;
1342  ULL_Add32(psiInfo->firstPosition, item->len);
1343  }
1344 
1345  psiInfo->lastTimestamp = timestamp;
1346  psiInfo->lastPosition = item->position;
1347 
1348  assert(item->timestamp == 0);
1349  if (item->timestamp == 0)
1350  {
1351  item->timestamp = timestamp;
1352 
1353  /* Timestamp is only updated when state=PSI_STATE_PCR, so
1354  * there's no need to stay in this loop.
1355  */
1356  break;
1357  }
1358  }
1359  packet += STMR_TS_PACKET_SIZE;
1360  remaining -= STMR_TS_PACKET_SIZE;
1361  }
1362  if (psiInfo->state == PSI_STATE_PCR && ok)
1363  {
1364  U16BIT pid;
1365  remaining = item->len;
1366  remaining -= remaining % STMR_TS_PACKET_SIZE;
1367  packet = item->data + remaining;
1368  if (item->timestamp == 0)
1369  {
1370  DBG(("item=%p position=%s timestamp=%lu remaining=%d",item,ULL_ToString(item->position),psiInfo->prevTimestamp,remaining));
1371  item->timestamp = psiInfo->prevTimestamp;
1372  }
1373  while (remaining != 0)
1374  {
1375  packet -= STMR_TS_PACKET_SIZE;
1376  remaining -= STMR_TS_PACKET_SIZE;
1377  pid = (packet[1] << 8 | packet[2]) & 0x1fff;
1378  if (pid == psiInfo->pcr_pid &&
1379  HandlePcrPacket(packet,&timestamp))
1380  {
1381  DBG(("item=%p position=%s timestamp=%lu remaining=%d",item,ULL_ToString(item->position),timestamp,remaining));
1382  psiInfo->prevTimestamp = timestamp;
1383  break;
1384  }
1385  }
1386  }
1387  return ok;
1388 }
1389 
1398 static BOOLEAN ProcessPacket(U8BIT *packet, PsiInfo *psiInfo,
1399  U32BIT *timestamp)
1400 {
1401  int pid;
1402  BOOLEAN built;
1403  BOOLEAN found;
1404 
1405  found = FALSE;
1406 
1407  pid = (packet[1] << 8 | packet[2]) & 0x1fff;
1408 
1409  switch (psiInfo->state)
1410  {
1411  case PSI_STATE_PAT:
1412  if (pid == 0x0000)
1413  {
1414  built = BuildSection(packet, psiInfo->section, &psiInfo->offset);
1415  if (built)
1416  {
1417  if (psiInfo->section[0] == 0x00)
1418  {
1419  HandlePatSection(psiInfo);
1420  }
1421  psiInfo->offset = 0;
1422  }
1423  }
1424  break;
1425  case PSI_STATE_PMT:
1426  if (pid == psiInfo->pmt_pid)
1427  {
1428  built = BuildSection(packet, psiInfo->section, &psiInfo->offset);
1429  if (built)
1430  {
1431  if (psiInfo->section[0] == 0x02)
1432  {
1433  HandlePmtSection(psiInfo);
1434  }
1435  psiInfo->offset = 0;
1436  }
1437  }
1438  break;
1439  case PSI_STATE_PCR:
1440  if (pid == psiInfo->pcr_pid)
1441  {
1442  found = HandlePcrPacket(packet, timestamp);
1443  }
1444  break;
1445  }
1446 
1447  return found;
1448 }
1449 
1457 static BOOLEAN BuildSection(U8BIT *packet, U8BIT *section, U16BIT *offset)
1458 {
1459  U32BIT payload_start_indicator;
1460  U32BIT adaptation_field_control;
1461  U32BIT pointer;
1462  U8BIT *payload;
1463  U16BIT payload_length;
1464  BOOLEAN complete;
1465 
1466  complete = FALSE;
1467 
1468  payload_start_indicator = (packet[1] >> 6) & 0x1;
1469  adaptation_field_control = (packet[3] >> 4) & 0x3;
1470  if (adaptation_field_control >= 2)
1471  {
1472  payload = packet + 5 + packet[4];
1473  payload_length = 188 - 5 - packet[4];
1474  }
1475  else
1476  {
1477  payload = packet + 4;
1478  payload_length = 188 - 4;
1479  }
1480 
1481  if (payload_start_indicator)
1482  {
1483  pointer = payload[0];
1484  if (payload_length > 0)
1485  {
1486  memcpy(section, payload + 1 + pointer, payload_length - 1);
1487  *offset = payload_length - 1;
1488  }
1489  else
1490  {
1491  *offset = 0;
1492  }
1493  }
1494  else if (*offset > 0)
1495  {
1496  if (payload_length > 0)
1497  {
1498  if (*offset + payload_length <= STMR_MAX_PSI_SECTION)
1499  {
1500  memcpy(section + *offset, payload, payload_length);
1501  *offset += payload_length;
1502  }
1503  else
1504  {
1505  /* Section too long */
1506  *offset = 0;
1507  }
1508  }
1509  }
1510 
1511  if (*offset > 2)
1512  {
1513  U16BIT section_length;
1514 
1515  section_length = (section[1] << 8 | section[2]) & 0xfff;
1516  if (*offset >= section_length + 3)
1517  {
1518  complete = IsValidSection(section);
1519  if (!complete)
1520  {
1521  /* Invalid data, start again */
1522  *offset = 0;
1523  }
1524  }
1525  }
1526 
1527  return complete;
1528 }
1529 
1535 static void HandlePatSection(PsiInfo *psiInfo)
1536 {
1537  U8BIT *section = psiInfo->section;
1538  U16BIT section_length;
1539  U16BIT offset;
1540  U16BIT program_number;
1541  U16BIT pmt_pid;
1542 
1543  section_length = (section[1] << 8 | section[2]) & 0xfff;
1544  offset = 8;
1545  while (offset + 4 < section_length + 3)
1546  {
1547  program_number = section[offset] << 8 | section[offset + 1];
1548  pmt_pid = (section[offset + 2] << 8 | section[offset + 3]) & 0x1fff;
1549  if (program_number != 0x0000)
1550  {
1551  PDBG(("program_number = %d, program_map_PID = %d",
1552  program_number, pmt_pid));
1553  psiInfo->pmt_pid = pmt_pid;
1554  psiInfo->state = PSI_STATE_PMT;
1555  break;
1556  }
1557 
1558  offset += 4;
1559  }
1560 }
1561 
1567 static void HandlePmtSection(PsiInfo *psiInfo)
1568 {
1569  U8BIT *section = psiInfo->section;
1570 
1571  /* PCR PID */
1572  psiInfo->pcr_pid = (section[8] << 8 | section[9]) & 0x1fff;
1573  PDBG(("PCR PID = %d", psiInfo->pcr_pid));
1574 
1575  psiInfo->state = PSI_STATE_PCR;
1576 }
1577 
1585 static BOOLEAN HandlePcrPacket(U8BIT *packet, U32BIT *timestamp)
1586 {
1587  S32BIT adaptation_field_control;
1588  S32BIT adaptation_field_length;
1589  S32BIT PCR_flag;
1590 
1591  U32BIT pcr_base_x;
1592  U32BIT pcr_base_y;
1593 
1594  BOOLEAN found;
1595 
1596  found = FALSE;
1597  *timestamp = 0;
1598 
1599  adaptation_field_control = (packet[3] >> 4) & 0x3;
1600  if (adaptation_field_control >= 2)
1601  {
1602  adaptation_field_length = packet[4];
1603  if (adaptation_field_length > 0)
1604  {
1605  PCR_flag = (packet[5] >> 4) & 0x1;
1606  if (PCR_flag)
1607  {
1608  /*
1609  * PCR = (packet[6] << 25 | packet[7] << 17 | packet[8] << 9 |
1610  * packet[9] << 1 | packet[10] >> 7)
1611  *
1612  * But we cannot store 33 bit values. So we divide it into
1613  * two parts:
1614  */
1615  pcr_base_x = (packet[6] << 24 |
1616  packet[7] << 16 |
1617  packet[8] << 8 |
1618  packet[9]);
1619  pcr_base_y = packet[10] >> 7;
1620 
1621  /* PCR = (pcr_base_x << 1) | pcr_base_y
1622  *
1623  * To convert PCR to milliseconds, we have to divide it by
1624  * 90:
1625  *
1626  * (2x + y) / 90 = x/45 + y/90 = (x - x%45 + x%45)/45 + y/90
1627  * = (x - x%45)/45 + (2 * x%45 + y)/90
1628  * = x / 45 + (2 * (x % 45) + y) / 90
1629  */
1630 
1631  *timestamp = (pcr_base_x / 45 +
1632  (2 * (pcr_base_x % 45) + pcr_base_y) / 90);
1633  found = TRUE;
1634  }
1635  }
1636  }
1637 
1638  return found;
1639 }
1640 
1647 static void NotifyHeadersDone(U32BIT downloadId,S32BIT code)
1648 {
1649  MHEG5eventMessage_t event;
1650  E_MhegErr cqu_err;
1651 
1653  event.data_type = DT_VALUE;
1654  event.data.streamer.requestId = downloadId;
1655  event.data.streamer.code = code;
1656  event.data.streamer.eventType = MHEG5_STREAMER_EVENT_HTTP_HEADERS_DONE;
1657 
1658  cqu_err = VQ_PutMsg(&event, PRTY_NORMAL);
1659  if (cqu_err != MHERR_OK)
1660  {
1661  PDBG(("NotifyHeaders: Cannot generate event %d", cqu_err));
1662  }
1663 }
1664 
1670 static void NotifyDownloadComplete(U32BIT downloadId,E_HttpStatus status,S32BIT code)
1671 {
1672  MHEG5eventMessage_t event;
1673  E_MhegErr cqu_err;
1674 
1676  event.data_type = DT_VALUE;
1677  event.data.streamer.requestId = downloadId;
1678  event.data.streamer.status = status;
1679  event.data.streamer.code = code;
1680  event.data.streamer.eventType = MHEG5_STREAMER_EVENT_HTTP_DOWNLOAD_DONE;
1681 
1682  cqu_err = VQ_PutMsg(&event, PRTY_NORMAL);
1683  if (cqu_err != MHERR_OK)
1684  {
1685  PDBG(("Download: Cannot send MHEG5_STREAMER_EVENT_HTTP_DOWNLOAD_DONE %d", cqu_err));
1686  }
1687 }
1688 
1689 static U32BIT crc_table[] = {
1690  0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
1691  0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
1692  0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
1693  0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
1694  0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
1695  0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
1696  0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
1697  0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
1698  0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
1699  0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
1700  0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
1701  0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
1702  0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
1703  0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
1704  0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
1705  0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
1706  0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
1707  0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
1708  0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
1709  0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
1710  0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
1711  0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
1712  0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
1713  0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
1714  0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
1715  0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
1716  0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
1717  0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
1718  0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
1719  0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
1720  0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
1721  0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
1722  0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
1723  0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
1724  0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
1725  0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
1726  0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
1727  0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
1728  0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
1729  0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
1730  0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
1731  0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
1732  0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
1733 };
1734 
1735 
1741 static BOOLEAN IsValidSection(U8BIT *section)
1742 {
1743  U16BIT section_length;
1744  U32BIT idx;
1745  U32BIT crc_accum;
1746  U8BIT *limit;
1747  BOOLEAN valid = FALSE;
1748 
1749  section_length = (section[1] << 8 | section[2]) & 0xfff;
1750 
1751  crc_accum = 0xffffffffL;
1752  limit = section + section_length + 3;
1753  while (section < limit)
1754  {
1755  idx = ((crc_accum >> 24) ^ (*section++)) & 0xff;
1756  crc_accum = ((crc_accum << 8) ^ crc_table[idx]) & 0xffffffffL;
1757  }
1758 
1759  if (crc_accum == 0x00000000)
1760  {
1761  valid = TRUE;
1762  }
1763 
1764  return valid;
1765 }
1766 
1767 static BOOLEAN IsPositionPartial(DownloadRequest *request)
1768 {
1769  U64BIT left;
1770  BOOLEAN result = FALSE;
1771  VERIFY_MAGIC(request);
1772  left = request->bytesExpected;
1773  PDBG(("expected=%s received=%s",ULL_ToString(left),ULL_ToString(request->bytesReceived)));
1774  if (ULL_IsValid(left) && ULL_Compare(left,request->bytesReceived) > 0)
1775  {
1776  ULL_Sub(left,request->bytesReceived);
1777  if (ULL_Get32(left) > 262144)
1778  {
1779  PDBG(("******** PARTIAL DOWNLOAD **** id=%d, left=%s",request->downloadId,ULL_ToString(left)));
1780  result = TRUE;
1781  }
1782  }
1783  return result;
1784 }
U32BIT STB_OSGetClockMilliseconds(void)
Get Current Computer Clock Time.
#define SET_MAGIC(r)
Definition: stmr_dl.c:60
E_HttpStatus status
Definition: stmr_dl.c:122
U64BIT MHEG5GetDownloadContentLength(U32BIT downloadId, U64BIT contentLength)
Return content length (in bytes) for download request. The content length may be: ...
Definition: stmr_dl.c:394
E_MhegErr VQ_PutMsg(S_MhegMessage *pMsg, E_PRIORITY priority)
Post event or section message on queue. Copies data into queue.
Definition: glue_queue.c:248
#define ULL_IsValid(variable)
Definition: glue_ulong.h:90
U16BIT partialDataLength
Definition: stmr_dl.c:158
HttpRequest_t handle
Definition: stmr_dl.c:118
F_MSG_PROCESS proc_msg_func
Definition: glue_queue.h:198
IC Streamer http header parser.
#define INVALID_TIMESTAMP
Definition: stmr_dl.c:49
U32BIT MHEG5GetUniqueId(void)
Return a unique ID. The ID is a non-zero 32-bit value. It is guaranteed to be unique for the first 0x...
Definition: stmr_util.c:98
#define DBG(x)
Definition: stmr_dl.c:69
U8BIT syncBuffer[SYNC_BUFFER_SIZE]
Definition: stmr_dl.c:143
void httpStartRequest(HttpRequest_t request)
Start an HTTP request. Everything related to the request is passed through the callback that was regi...
Manages the interface between MHEG5 Engine and the HTTP component.
U32BIT lastTimestamp
Definition: stmr_dl.c:98
E_HttpStatus
Definition: httptype.h:36
#define DBG_PRINTF(...)
Definition: glue_debug.h:127
E_HTTP_FIELD
Definition: http_header.h:39
const char * data
Definition: mh5gate.c:56
#define ULL_Sub(variable, value)
Definition: glue_ulong.h:82
void MHEG5ClearDownloadRequest(U32BIT downloadId)
Clear HTTP download request.
Definition: stmr_dl.c:667
Common header internal to IC streamer.
BOOLEAN lastRequest
Definition: stmr_dl.c:129
void MHEG5CopyDownloadStreamKeyInfo(U32BIT downloadId, S_ICSKeys *keys, MHEG5String *keyLocation)
Copy any keys or key location that were obtained from the headers. If such keys or location exist...
Definition: stmr_dl.c:444
E_HttpStatus status
U64BIT rangeTo
Definition: stmr_dl.c:126
BOOLEAN MHEG5GetDownloadPmt(U32BIT downloadId, U8BIT *pmt)
Return program map table (PMT) for download (if available). The table is provided as a complete secti...
Definition: stmr_dl.c:501
Debug tracing.
#define ULL_IsEqual(variable, value)
Definition: glue_ulong.h:91
MHEG5 queue.
U8BIT * httpHdrParseFieldName(U8BIT *data, U32BIT len, E_HTTP_FIELD *field)
Parse field for its name in an HTTP header.
Definition: http_header.c:78
#define ULL_Sub32(variable, value)
Definition: glue_ulong.h:83
#define MHEG5getMem
Definition: glue_memory.h:93
#define PDBG(x)
Definition: stmr_dl.c:70
#define VERIFY_MAGIC(r)
Definition: stmr_dl.c:61
void MHEG5ClearDownloadThrottling(void)
Clear information about throttling, causing the download to proceed at full speed (until throttling k...
Definition: stmr_dl.c:549
U32BIT requestId
Definition: stmr_dl.c:112
U16BIT pcr_pid
Definition: stmr_dl.c:95
BOOLEAN processing
Definition: stmr_dl.c:136
U32BIT downloadId
Definition: stmr_dl.c:109
E_MhegErr
Definition: mherrors.h:28
void MHEG5stringDestruct(MHEG5String *item)
Destruct a MHEG5String.
Definition: mh5base.c:686
S_ICSPidInfo * pid_info
Definition: stmr_header.h:52
U32BIT firstTimestamp
Definition: stmr_dl.c:97
void(* F_MSG_PROCESS)(void *data)
Function to Process voyager message.
Definition: glue_queue.h:70
U32BIT bytesPerSecond
Definition: stmr_dl.c:146
U32BIT timestamp
Definition: stmr_queue.h:56
uint8_t U8BIT
Definition: techtype.h:82
BOOLEAN MHEG5DownloadPositionPartial(U32BIT downloadId, U64BIT *position)
Return what is current position of download request.
Definition: stmr_dl.c:359
U8BIT section[STMR_MAX_PSI_SECTION]
Definition: stmr_dl.c:92
U64BIT position
Definition: stmr_queue.h:54
#define ULL_Itoa(variable, str)
Definition: glue_ulong.h:97
void MHEG5RenewDownloadRequest(U32BIT downloadId, char *url)
Renew HTTP download request.
Definition: stmr_dl.c:697
void MHEG5StopDownloadRequestAsync(U32BIT downloadId)
Stop HTTP download request asynchronously. This function should be used when the caller wants to stop...
Definition: stmr_dl.c:609
U64BIT rangeFrom
Definition: stmr_dl.c:125
Memory functions.
U16BIT syncBufferPos
Definition: stmr_dl.c:144
void MHEG5ParseXKeys(U8BIT *data, U32BIT len, S_ICSKeys *keys)
Parse "X-Keys" header and return the key information. If the keys cannot be parsed, keys->num_pids will be zero.
Definition: stmr_header.c:237
char * ULL_ToString(U64BIT val)
Convert 64 bit value to string (for debug purposes).
Definition: stmr_util.c:74
#define MHEG5freeMem
Definition: glue_memory.h:94
#define SYNC_COUNT_MIN_ACCEPT
Definition: stmr_dl.c:53
struct sDownloadRequest * next
Definition: stmr_dl.c:164
API for IC streamer.
IC Streamer queue manager.
U8BIT * httpGetRequestRedirect(HttpRequest_t request)
Return the URL that the request is redirected to (valid only for response codes of 3xx)...
void MHEG5StopDownloadRequest(U32BIT downloadId)
Stop HTTP download request.
Definition: stmr_dl.c:584
BOOLEAN stopped
Definition: stmr_dl.c:137
#define SYNC_BUFFER_SIZE
Definition: stmr_dl.c:52
#define ULL_Mul32(variable, value)
Definition: glue_ulong.h:84
PsiState
Definition: stmr_dl.c:82
U64BIT firstPosition
Definition: stmr_dl.c:99
PsiInfo psiInfo
Definition: stmr_dl.c:161
U64BIT bytesReceived
Definition: stmr_dl.c:133
#define ULL_SetInvalid(variable)
Definition: glue_ulong.h:89
U32BIT MHEG5CreateDownloadRequest(U32BIT requestId, char *url, U64BIT rangeFrom, U64BIT rangeTo, BOOLEAN lastRequest)
Create HTTP download request.
Definition: stmr_dl.c:212
void MHEG5ParseXBytesPerSecond(U8BIT *data, U32BIT len, U32BIT *bytesPerSecond, BOOLEAN *knownBitrate)
Parse "X-BytesPerSecond" header and return its value.
Definition: stmr_header.c:277
MHEG5Byte * data
Definition: mh5base.h:85
void MHEG5StartDownloadRequest(U32BIT downloadId)
Start HTTP download request.
Definition: stmr_dl.c:317
void httpStopRequest(HttpRequest_t request)
Stop an HTTP request. This function does not destroy the request; this is done using httpDestroyReque...
int len
Definition: mh5gate.c:57
struct sPsiInfo PsiInfo
void MHEG5QueueInsertItem(MHEG5QueueItem *item)
Insert a queue item into the queue.
Definition: stmr_queue.c:279
BOOLEAN https
Definition: stmr_dl.c:115
int32_t S32BIT
Definition: techtype.h:87
U64BIT httpHdrParseContentRange(U8BIT *data, U32BIT len)
Parse "Content-Range" header and return the content length in bytes.
Definition: http_header.c:177
uint16_t U16BIT
Definition: techtype.h:84
#define ULL_Add(variable, value)
Definition: glue_ulong.h:80
U64BIT lastPosition
Definition: stmr_dl.c:100
BOOLEAN last
Definition: stmr_queue.h:57
void httpResumeRequest(HttpRequest_t request)
Resume an HTTP request. A request can be paused by returning FALSE from the content callback to tell ...
#define SYNC_BYTE
Definition: stmr_dl.c:50
U64BIT bytesExpected
Definition: stmr_dl.c:134
void MHEG5ParseXKeyLocation(U8BIT *data, U32BIT len, MHEG5String *keyLocation)
Parse "X-KeyLocation" header and return the key location.
Definition: stmr_header.c:249
MHEG5QueueItem * MHEG5QueueAllocItem(U32BIT requestId, U32BIT len)
Allocate a new queue item and initialise with request ID and block length.
Definition: stmr_queue.c:241
enum SyncState syncState
Definition: stmr_dl.c:142
#define FALSE
Definition: techtype.h:68
#define ULL_Compare(first, second)
Definition: glue_ulong.h:93
U64BIT httpHdrParseContentLength(U8BIT *data, U32BIT len)
Parse "Content-Length" header and return the content length in bytes.
Definition: http_header.c:147
U32BIT prevTimestamp
Definition: stmr_dl.c:96
void MHEG5CopyDownloadBitrate(U32BIT downloadId, U32BIT *bytesPerSecond)
Copy download bitrate that was obtained from the headers. If the X-BytesPerSecond header were not rec...
Definition: stmr_dl.c:416
enum PsiState state
Definition: stmr_dl.c:91
void httpDestroyRequest(HttpRequest_t request)
Destroy an HTTP request.
U16BIT offset
Definition: stmr_dl.c:93
MHEG5Int len
Definition: mh5base.h:84
void MHEG5StreamerHandle(MHEG5StreamerEventParams_t *params)
Process an MHEG5StreamerEvent message The event is passed onto the streamer module for processing...
#define SYNC_COUNT_ACCEPT
Definition: stmr_dl.c:51
#define ULL_Set32(variable, value)
Definition: glue_ulong.h:88
#define STMR_TS_PACKET_SIZE
Definition: stmr_common.h:35
U8BIT BOOLEAN
Definition: techtype.h:99
#define ULL_Div32(variable, value)
Definition: glue_ulong.h:85
U8BIT * data
Definition: stmr_queue.h:51
U32BIT downloadId
Definition: stmr_queue.h:50
#define TRUE
Definition: techtype.h:69
#define STMR_MAX_PSI_SECTION
Definition: stmr_common.h:36
S_ICSKeys keys
Definition: stmr_dl.c:140
void MHEG5ResumeDownload(void)
Resume download of the active request. Download may or may not have been paused due to the buffer bei...
Definition: stmr_dl.c:527
void MHEG5DestroyDownloadRequest(U32BIT downloadId)
Destroy HTTP download request.
Definition: stmr_dl.c:627
U32BIT timestamp
Definition: stmr_dl.c:148
SyncState
Definition: stmr_dl.c:75
U16BIT num_pids
Definition: stmr_header.h:53
U64BIT contentLength
Definition: stmr_dl.c:132
HttpRequest_t httpCreateStreamRequest(U8BIT *url, U8BIT *range, HttpCallback_t header_callback, HttpCallback_t callback, U32BIT request_id, void *userdata)
Create an HTTP request for stream media.
#define MHEG5_MAX_RANGE_BUFFER
Definition: stmr_util.h:35
BOOLEAN knownBitrate
Definition: stmr_dl.c:147
struct HttpRequest_tag * HttpRequest_t
#define ULL_Get32(variable)
Definition: glue_ulong.h:79
struct sDownloadRequest DownloadRequest
MHEG5String keyLocation
Definition: stmr_dl.c:139
U16BIT pmt_pid
Definition: stmr_dl.c:94
uint32_t U32BIT
Definition: techtype.h:86
U8BIT partialData[STMR_TS_PACKET_SIZE]
Definition: stmr_dl.c:157
IC Streamer download manager.
#define ULL_Add32(variable, value)
Definition: glue_ulong.h:81
U8BIT * MHEG5GetDownloadRedirect(U32BIT downloadId)
Return the redirection URL for a request that was redirected (HTTP status 3xx).
Definition: stmr_dl.c:337
U32BIT magic
Definition: stmr_dl.c:106
Header file - Function prototypes for operating system.