component_dec_feeder.c 14 KB

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