component_dec_feeder.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /*
  2. * Copyright (c) 2019, Chips&Media
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright notice,
  11. * this list of conditions and the following disclaimer in the documentation
  12. * and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  18. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include <string.h>
  26. #include <time.h>
  27. #include "component.h"
  28. #define STREAM_BUF_SIZE_HEVC (10*1024*1024) // max bitstream size(HEVC:10MB,VP9:not specified)
  29. #define STREAM_BUF_SIZE_VP9 (20*1024*1024) // max bitstream size(HEVC:10MB,VP9:not specified)
  30. #define STREAM_BUF_SIZE 0x700000
  31. #define FEEDING_SIZE 0x20000
  32. typedef struct {
  33. TestDecConfig config;
  34. vpu_buffer_t* bsBuffer;
  35. Uint32 numBuffers;
  36. BSFeeder feeder;
  37. PhysicalAddress nextWrPtr;
  38. Uint32 bsMargin;
  39. Uint32 loopCount;
  40. Uint32 dropCount;
  41. DecHandle handle;
  42. } FeederContext;
  43. static BOOL IsStartCode(Uint8* pData)
  44. {
  45. // find 00 00 00 01
  46. if (pData[0] == 0x00 && pData[1] == 0x00 && pData[2] == 0x00 && pData[3] == 0x01)
  47. return TRUE;
  48. else
  49. return FALSE;
  50. }
  51. static BOOL FindSPSAndPPS(Uint8* pData, Uint32 size)
  52. {
  53. Uint32 k;
  54. Uint32 nalUnitType = 0;
  55. for (k = 0; k < size; k += 4) {
  56. if (IsStartCode((pData + k)) == TRUE) {
  57. nalUnitType = (pData[k+4] >> 1) & 0x3F;
  58. if (nalUnitType == 33 || nalUnitType == 34) {
  59. VLOG(ERR, "Find SPS/PPS : %d\n", nalUnitType);
  60. return TRUE;
  61. }
  62. }
  63. }
  64. return FALSE;
  65. }
  66. static void InjectErrorEvery188(BSFeeder bsf, void* data, Uint32 size, void* arg)
  67. {
  68. Uint8* pData = (Uint8*)data;
  69. Uint8 val;
  70. Uint32 pos;
  71. Uint32 i, nchunk, blockSize;
  72. UNREFERENCED_PARAMETER(bsf);
  73. if (randomSeed == 0) {
  74. randomSeed = (Uint32)time(NULL);
  75. srand(randomSeed);
  76. VLOG(INFO, "RANDOM SEED: %d\n", randomSeed);
  77. }
  78. if (size == 0) {
  79. return;
  80. }
  81. blockSize = (size < 188) ? size : 188;
  82. nchunk = (size + blockSize -1) / blockSize;
  83. for (i=0; i<nchunk; i++) {
  84. pos = GetRandom(0, blockSize-1);
  85. pData = ((Uint8*)data + i*blockSize);
  86. if (FindSPSAndPPS(pData, blockSize) == FALSE) {
  87. /* size is 188 */
  88. val = pData[pos];
  89. val = ~val;
  90. pData[pos] = val;
  91. pos = (pos+1) % blockSize;
  92. }
  93. else {
  94. // if find SPS or PPS, skip current chunk and next chunk.
  95. i++;
  96. }
  97. }
  98. //VLOG(TRACE, "CREATE ERROR BIT!!!\n");
  99. }
  100. static CNMComponentParamRet GetParameterFeeder(ComponentImpl* from, ComponentImpl* com, GetParameterCMD commandType, void* data)
  101. {
  102. FeederContext* ctx = (FeederContext*)com->context;
  103. ParamDecBitstreamBuffer* bsBuf = NULL;
  104. PortContainer* container;
  105. switch(commandType) {
  106. case GET_PARAM_COM_IS_CONTAINER_CONUSUMED:
  107. // This query command is sent from the comonponent core.
  108. // If input data are consumed in sequence, it should return TRUE through PortContainer::consumed.
  109. container = (PortContainer*)data;
  110. container->consumed = TRUE;
  111. break;
  112. case GET_PARAM_FEEDER_BITSTREAM_BUF:
  113. if (ctx->bsBuffer == NULL) return CNM_COMPONENT_PARAM_NOT_READY;
  114. bsBuf = (ParamDecBitstreamBuffer*)data;
  115. bsBuf->num = ctx->numBuffers;
  116. bsBuf->bs = ctx->bsBuffer;
  117. break;
  118. case GET_PARAM_FEEDER_EOS:
  119. if (ctx->feeder == NULL) return CNM_COMPONENT_PARAM_NOT_READY;
  120. *(BOOL*)data = BitstreamFeeder_IsEos(ctx->feeder);
  121. break;
  122. default:
  123. return CNM_COMPONENT_PARAM_NOT_FOUND;
  124. }
  125. return CNM_COMPONENT_PARAM_SUCCESS;
  126. }
  127. static CNMComponentParamRet SetParameterFeeder(ComponentImpl* from, ComponentImpl* com, SetParameterCMD commandType, void* data)
  128. {
  129. CNMComponentParamRet ret = CNM_COMPONENT_PARAM_SUCCESS;
  130. FeederContext* ctx = (FeederContext*)com->context;
  131. switch(commandType) {
  132. case SET_PARAM_COM_PAUSE:
  133. com->pause = *(BOOL*)data;
  134. break;
  135. case SET_PARAM_FEEDER_START_INJECT_ERROR:
  136. BitstreamFeeder_SetHook(ctx->feeder, InjectErrorEvery188, NULL);
  137. break;
  138. case SET_PARAM_FEEDER_STOP_INJECT_ERROR:
  139. BitstreamFeeder_SetHook(ctx->feeder, NULL, NULL);
  140. break;
  141. case SET_PARAM_FEEDER_RESET:
  142. ctx->nextWrPtr = ctx->bsBuffer[0].phys_addr;
  143. ctx->dropCount = 2; /* Drop remaining error injected packets */
  144. break;
  145. default:
  146. ret = CNM_COMPONENT_PARAM_NOT_FOUND;
  147. break;
  148. }
  149. return ret;
  150. }
  151. static BOOL PrepareFeeder(ComponentImpl* com, BOOL *done)
  152. {
  153. FeederContext* ctx = (FeederContext*)com->context;
  154. TestDecConfig* config = &ctx->config;
  155. Uint32 i;
  156. vpu_buffer_t* bsBuffer;
  157. bsBuffer = (vpu_buffer_t*)osal_malloc(com->numSinkPortQueue*sizeof(vpu_buffer_t));
  158. for (i=0; i<ctx->numBuffers; i++) {
  159. bsBuffer[i].size = config->bsSize;
  160. if (vdi_allocate_dma_memory(config->coreIdx, &bsBuffer[i], DEC_BS, 0) < 0) { // can't know instIdx now.
  161. VLOG(ERR, "%s:%d fail to allocate bitstream buffer\n", __FUNCTION__, __LINE__);
  162. return FALSE;
  163. }
  164. }
  165. if (config->bitstreamMode == BS_MODE_INTERRUPT) {
  166. ctx->nextWrPtr = bsBuffer[0].phys_addr;
  167. }
  168. else {
  169. Queue* srcQ = com->sinkPort.inputQ;
  170. Queue* tempQ = Queue_Copy(NULL, srcQ);
  171. PortContainerES* out;
  172. // Flush all data.
  173. Queue_Flush(srcQ);
  174. for (i=0; i<ctx->numBuffers; i++) {
  175. out = (PortContainerES*)Queue_Dequeue(tempQ);
  176. out->buf = bsBuffer[i];
  177. Queue_Enqueue(srcQ, (void*)out);
  178. }
  179. Queue_Destroy(tempQ);
  180. }
  181. ctx->bsBuffer = bsBuffer;
  182. *done = TRUE;
  183. return TRUE;
  184. }
  185. static BOOL ExecuteFeeder(ComponentImpl* com, PortContainer* in, PortContainer* out)
  186. {
  187. FeederContext* ctx = (FeederContext*)com->context;
  188. vpu_buffer_t* bsBuffer = ctx->bsBuffer;
  189. BSFeeder bsFeeder = ctx->feeder;
  190. TestDecConfig* config = &ctx->config;
  191. PortContainerES* container = (PortContainerES*)out;
  192. PhysicalAddress wrPtr;
  193. Int32 room;
  194. BOOL eos = FALSE;
  195. if (com->pause) return TRUE;
  196. #ifdef USE_FEEDING_METHOD_BUFFER
  197. extern void BSFeederBuffer_SetData(
  198. void* feeder,
  199. char* address,
  200. Uint32 size);
  201. extern void* BitstreamFeeder_GetActualFeeder(void *feeder);
  202. extern void BSFeederBuffer_SetEos(void* feeder);
  203. extern BOOL BSFeederBuffer_GetEos(void* feeder);
  204. void *actualFeeder = BitstreamFeeder_GetActualFeeder(bsFeeder);
  205. PortContainerExternal *input = NULL;
  206. if (BSFeederBuffer_GetEos(actualFeeder) == FALSE) {
  207. input = (PortContainerExternal *)ComponentPortPeekData(&com->srcPort);
  208. if (input == NULL) {
  209. return TRUE;
  210. }
  211. BSFeederBuffer_SetData(actualFeeder, (char *)input->pBuffer, input->nFilledLen);
  212. if ((input->nFlags & 0x1) == 0x1)
  213. {
  214. BSFeederBuffer_SetEos(actualFeeder);
  215. }
  216. } else {
  217. BSFeederBuffer_SetData(actualFeeder, 0, 0);
  218. }
  219. #endif
  220. eos = BitstreamFeeder_IsEos(bsFeeder);
  221. if (config->bitstreamMode == BS_MODE_PIC_END) {
  222. bsBuffer = &container->buf;
  223. wrPtr = bsBuffer->phys_addr;
  224. room = bsBuffer->size;
  225. container->size = BitstreamFeeder_Act(bsFeeder, bsBuffer, wrPtr, (Uint32)room, &ctx->nextWrPtr);
  226. #ifdef USE_FEEDING_METHOD_BUFFER
  227. if (input != NULL) {
  228. ComponentPortGetData(&com->srcPort);
  229. ComponentNotifyListeners(com, COMPONENT_EVENT_DEC_EMPTY_BUFFER_DONE, (void *)input);
  230. // do not use input var under next line because this data already be droped.
  231. (void)input;
  232. }
  233. #endif
  234. }
  235. else {
  236. ParamDecBitstreamBufPos bsPos;
  237. BOOL success;
  238. if (eos == FALSE) {
  239. CNMComponentParamRet ret = ComponentGetParameter(com, com->sinkPort.connectedComponent, GET_PARAM_DEC_BITSTREAM_BUF_POS, (void*)&bsPos);
  240. if (ComponentParamReturnTest(ret, &success) == FALSE) {
  241. if (success == FALSE) VLOG(ERR, "%s:%d return FALSE\n", __FUNCTION__, __LINE__);
  242. return success;
  243. }
  244. bsBuffer = &bsBuffer[0];
  245. wrPtr = (ctx->nextWrPtr > 0) ? ctx->nextWrPtr : bsPos.wrPtr;
  246. if (wrPtr >= bsPos.rdPtr) {
  247. room = (bsBuffer->phys_addr + bsBuffer->size) - wrPtr;
  248. room += (bsPos.rdPtr - bsBuffer->phys_addr - 1) - ctx->bsMargin;
  249. }
  250. else {
  251. room = bsPos.rdPtr - wrPtr - ctx->bsMargin - 1;
  252. }
  253. if (room < 0) room = 0;
  254. container->size = BitstreamFeeder_Act(bsFeeder, bsBuffer, wrPtr, (Uint32)room, &ctx->nextWrPtr);
  255. if (ctx->dropCount > 0) {
  256. container->size = 0;
  257. ctx->dropCount--;
  258. ctx->nextWrPtr = wrPtr;
  259. }
  260. #ifdef USE_FEEDING_METHOD_BUFFER
  261. eos = BitstreamFeeder_IsEos(bsFeeder);
  262. if (eos == TRUE) {
  263. ComponentPortGetData(&com->srcPort);
  264. ComponentNotifyListeners(com, COMPONENT_EVENT_DEC_EMPTY_BUFFER_DONE, (void *)input);
  265. // do not use input var under next line because this data already be droped.
  266. (void)input;
  267. }
  268. #endif
  269. }
  270. else {
  271. if (ctx->loopCount > 0) {
  272. eos = FALSE;
  273. BitstreamFeeder_Rewind(bsFeeder);
  274. ctx->loopCount--;
  275. }
  276. container->size = 0;
  277. }
  278. }
  279. container->last = (config->streamEndFlag == TRUE) ? TRUE : eos;
  280. container->buf = *bsBuffer;
  281. container->reuse = (container->size == 0 && container->last == FALSE);
  282. /* To stop sending an element stream.
  283. A user will clear pause state when he gets the stream-end flag form the VPU */
  284. com->pause = config->streamEndFlag;
  285. return TRUE;
  286. }
  287. static void ReleaseFeeder(ComponentImpl* com)
  288. {
  289. FeederContext* ctx = (FeederContext*)com->context;
  290. TestDecConfig* config = &ctx->config;
  291. Uint32 i = 0;
  292. if (NULL != ctx->bsBuffer) {
  293. for (i = 0; i < ctx->numBuffers; i++) {
  294. vdi_free_dma_memory(config->coreIdx, &ctx->bsBuffer[i], DEC_BS, 0);
  295. }
  296. }
  297. }
  298. static BOOL DestroyFeeder(ComponentImpl* com) {
  299. FeederContext* ctx = (FeederContext*)com->context;
  300. if (ctx->bsBuffer != NULL) osal_free(ctx->bsBuffer);
  301. BitstreamFeeder_Destroy(ctx->feeder);
  302. osal_free(ctx);
  303. return TRUE;
  304. }
  305. static Component CreateFeeder(ComponentImpl* com, CNMComponentConfig* comConfig)
  306. {
  307. FeederContext* ctx;
  308. BSFeeder feeder;
  309. TestDecConfig* config;
  310. com->context = osal_malloc(sizeof(FeederContext));
  311. ctx = (FeederContext*)com->context;
  312. osal_memset((void*)ctx, 0, sizeof(FeederContext));
  313. config = &ctx->config;
  314. osal_memcpy((void*)config, (void*)&comConfig->testDecConfig, sizeof(TestDecConfig));
  315. if (PRODUCT_ID_W_SERIES(config->productId)) {
  316. ctx->numBuffers = (config->bitstreamMode == BS_MODE_PIC_END) ? com->numSinkPortQueue: 1;
  317. } else {
  318. ctx->numBuffers = 1;
  319. }
  320. if (config->bsSize == 0) {
  321. if(PRODUCT_ID_W_SERIES(config->productId)) {
  322. config->bsSize = (config->bitFormat == STD_VP9) ? STREAM_BUF_SIZE_VP9 : STREAM_BUF_SIZE_HEVC;
  323. } else {
  324. config->bsSize = STREAM_BUF_SIZE;
  325. }
  326. }
  327. ctx->bsMargin = PRODUCT_ID_W_SERIES(config->productId) ? 0 : 2048; /* 2048 = GBU_SIZE x 2 */
  328. ctx->loopCount = (config->loopCount > 0) ? (config->loopCount-1) : 0;
  329. if (PRODUCT_ID_NOT_W_SERIES(config->productId)) {
  330. if (BS_MODE_PIC_END == config->bitstreamMode || STD_THO == config->bitFormat) {
  331. config->feedingMode = FEEDING_METHOD_FRAME_SIZE;
  332. }
  333. }
  334. if ((feeder=BitstreamFeeder_Create(config->coreIdx, config->inputPath, config->bitFormat, config->feedingMode, config->streamEndian)) == NULL) {
  335. return NULL;
  336. }
  337. BitstreamFeeder_SetFeedingSize(feeder, config->feedingSize);
  338. #ifdef SUPPORT_FFMPEG_DEMUX
  339. #endif /* SUPPORT_FFMPEG_DEMUX */
  340. if (config->streamEndFlag == TRUE) {
  341. BitstreamFeeder_SetFillMode(feeder, BSF_FILLING_RINGBUFFER_WITH_ENDFLAG);
  342. }
  343. else {
  344. BitstreamFeeder_SetFillMode(feeder, (config->bitstreamMode == BS_MODE_PIC_END) ? BSF_FILLING_LINEBUFFER : BSF_FILLING_RINGBUFFER);
  345. }
  346. if (config->errorInject == TRUE) {
  347. BitstreamFeeder_SetHook(feeder, InjectErrorEvery188, NULL);
  348. }
  349. ctx->feeder = feeder;
  350. return (Component)com;
  351. }
  352. ComponentImpl feederComponentImpl = {
  353. "feeder",
  354. NULL,
  355. {0,},
  356. {0,},
  357. sizeof(PortContainerES),
  358. 5,
  359. CreateFeeder,
  360. GetParameterFeeder,
  361. SetParameterFeeder,
  362. PrepareFeeder,
  363. ExecuteFeeder,
  364. ReleaseFeeder,
  365. DestroyFeeder
  366. };