yuv_feeder.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /*
  2. * Copyright (c) 2018, 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 <stdio.h>
  26. #include <string.h>
  27. #include <assert.h>
  28. #include "yuv_feeder.h"
  29. #include "platform.h"
  30. #include "jpulog.h"
  31. #define FB_QUEUE_SIZE 10
  32. typedef struct {
  33. FILE* fp;
  34. Uint32 frameSize;
  35. Uint32 lumaSize;
  36. Uint32 chromaSize;
  37. Uint32 lumaLineWidth;
  38. Uint32 lumaHeight;
  39. Uint32 chromaLineWidth;
  40. Uint32 chromaHeight;
  41. Uint8* pYuv;
  42. Uint32 fbEndian;
  43. Uint32 currentRow;
  44. } IYuvContext;
  45. static void DefaultListener(
  46. YuvFeederListenerArg* arg
  47. )
  48. {
  49. UNREFERENCED_PARAMETER(arg);
  50. }
  51. static void CalcYuvFrameSize(
  52. YuvAttr* attr,
  53. IYuvContext* ctx
  54. )
  55. {
  56. Uint32 lSize = 0, cSize = 0, divc=1;
  57. Uint32 Bpp = (attr->bpp+7)>>3;
  58. Uint32 divw, divh;
  59. divw = divh = 1;
  60. switch (attr->format) {
  61. case FORMAT_400:
  62. /* No chroma data */
  63. divw = divh = 0;
  64. break;
  65. case FORMAT_420:
  66. divw = 2;
  67. divh = 2;
  68. break;
  69. case FORMAT_422:
  70. divw = 2;
  71. divh = 1;
  72. break;
  73. case FORMAT_440:
  74. divw = 1;
  75. divh = 2;
  76. break;
  77. case FORMAT_444:
  78. break;
  79. default:
  80. JLOG(WARN, "%s:%d NOT SUPPORTED YUV FORMAT: %d\n", __FUNCTION__, __LINE__, attr->format);
  81. break;
  82. }
  83. divc = divw * divh;
  84. lSize = attr->width * attr->height * Bpp;
  85. cSize = divc == 0 ? 0 : lSize / divc;
  86. ctx->frameSize = lSize + 2*cSize;
  87. ctx->lumaSize = lSize;
  88. ctx->chromaSize = cSize;
  89. ctx->lumaLineWidth = attr->width * Bpp;
  90. ctx->lumaHeight = attr->height;
  91. ctx->chromaLineWidth = divw == 0 ? 0 : attr->width * Bpp / divw;
  92. ctx->chromaHeight = divh == 0 ? 0 : attr->height / divh;
  93. if (attr->packedFormat != PACKED_FORMAT_NONE) {
  94. if (attr->packedFormat == PACKED_FORMAT_444) {
  95. ctx->lumaLineWidth *= 3;
  96. }
  97. else {
  98. ctx->lumaLineWidth *= 2;
  99. }
  100. ctx->chromaLineWidth = 0;
  101. ctx->chromaHeight = 0;
  102. }
  103. else {
  104. if (attr->chromaInterleaved != CBCR_SEPARATED) {
  105. ctx->chromaLineWidth *= 2;
  106. }
  107. }
  108. }
  109. static void CopyYuvData(PhysicalAddress fbAddr, Uint32 fbStride, Uint8* data, Uint32 dataStride, Uint32 dataHeight, Uint32 endian)
  110. {
  111. PhysicalAddress addr = fbAddr;
  112. Uint8* pData = data;
  113. Uint8* newData = NULL;
  114. Uint32 i;
  115. if (dataStride < fbStride) {
  116. if (NULL == (newData=(Uint8*)malloc(fbStride))) {
  117. JLOG(ERR, "<%s> failed to allocate memory\n", __FUNCTION__);
  118. return;
  119. }
  120. memset(newData, 0x00, fbStride);
  121. }
  122. for (i=0; i<dataHeight; i++) {
  123. if (NULL != newData) {
  124. memcpy(newData, pData, dataStride);
  125. jdi_write_memory(addr, newData, fbStride, endian);
  126. }
  127. else {
  128. jdi_write_memory(addr, pData, fbStride, endian);
  129. }
  130. pData += dataStride;
  131. addr += fbStride;
  132. }
  133. if (newData) free(newData);
  134. }
  135. /* @return height of picture on success, -1 on failure
  136. */
  137. static Int32 LoadFrameFromFile(
  138. IYuvContext* ctx,
  139. FrameBuffer* fb,
  140. YuvAttr attr,
  141. Uint32 endian
  142. )
  143. {
  144. Uint32 nread;
  145. BOOL success = TRUE;
  146. Uint8* pY;
  147. Uint8* pU;
  148. Uint8* pV;
  149. if ((nread=fread(ctx->pYuv, 1, ctx->frameSize, ctx->fp)) != ctx->frameSize) {
  150. JLOG(WARN, "%s:%d INSUFFICIENT FRAME DATA!!!(%d)\n", __FUNCTION__, __LINE__, ctx->frameSize);
  151. success = FALSE;
  152. }
  153. pY = ctx->pYuv;
  154. switch (attr.format) {
  155. case FORMAT_400:
  156. CopyYuvData(fb->bufY, fb->stride, pY, ctx->lumaLineWidth, ctx->lumaHeight, endian);
  157. /* No chroma data */
  158. break;
  159. case FORMAT_420:
  160. case FORMAT_422:
  161. case FORMAT_440:
  162. case FORMAT_444:
  163. if (attr.packedFormat == PACKED_FORMAT_NONE) {
  164. CopyYuvData(fb->bufY, fb->stride, pY, ctx->lumaLineWidth, ctx->lumaHeight, endian);
  165. pU = pY + ctx->lumaSize;
  166. if (attr.chromaInterleaved == CBCR_SEPARATED) {
  167. CopyYuvData(fb->bufCb, fb->strideC, pU, ctx->chromaLineWidth, ctx->chromaHeight, endian);
  168. pV = pU + ctx->chromaSize;
  169. CopyYuvData(fb->bufCr, fb->strideC, pV, ctx->chromaLineWidth, ctx->chromaHeight, endian);
  170. }
  171. else {
  172. CopyYuvData(fb->bufCb, fb->strideC, pU, ctx->chromaLineWidth, ctx->chromaHeight, endian);
  173. }
  174. }
  175. else {
  176. CopyYuvData(fb->bufY, fb->stride, pY, ctx->lumaLineWidth, ctx->lumaHeight, endian);
  177. }
  178. break;
  179. default:
  180. JLOG(ERR, "%s:%d NOT SUPPORTED YUV FORMAT:%d\n", __FUNCTION__, __LINE__, attr.format);
  181. success = FALSE;
  182. break;
  183. }
  184. return success == FALSE ? -1 : attr.height;
  185. }
  186. /* @return It returns the num of rows so far.
  187. */
  188. static Int32 LoadSliceFromFile(
  189. IYuvContext* ctx,
  190. FrameBuffer* fb,
  191. YuvAttr attr,
  192. Uint32 endian
  193. )
  194. {
  195. Uint32 nread;
  196. BOOL success = TRUE;
  197. Uint8* pY;
  198. Uint8* pU;
  199. Uint8* pV;
  200. Uint32 lumaOffset, chromaOffset;
  201. if (ctx->currentRow == attr.height) {
  202. ctx->currentRow = 0;
  203. }
  204. if (ctx->currentRow == 0) {
  205. if ((nread=fread(ctx->pYuv, 1, ctx->frameSize, ctx->fp)) != ctx->frameSize) {
  206. JLOG(WARN, "%s:%d INSUFFICIENT FRAME DATA!!!\n", __FUNCTION__, __LINE__);
  207. success = FALSE;
  208. }
  209. }
  210. lumaOffset = ctx->currentRow * ctx->lumaLineWidth;
  211. pY = ctx->pYuv;
  212. switch (attr.format) {
  213. case FORMAT_400:
  214. jdi_write_memory(fb->bufY+lumaOffset, pY+lumaOffset, ctx->lumaLineWidth, endian);
  215. ctx->currentRow++;
  216. /* No chroma data */
  217. break;
  218. case FORMAT_420:
  219. case FORMAT_422:
  220. case FORMAT_440:
  221. case FORMAT_444:
  222. if (attr.packedFormat == PACKED_FORMAT_NONE) {
  223. Uint32 bytesPerPixel = (attr.format == FORMAT_422) ? 2 : 3;
  224. Uint32 offset = ctx->currentRow * ctx->lumaLineWidth * bytesPerPixel;
  225. Uint32 lineWidth = ctx->lumaLineWidth * bytesPerPixel;
  226. jdi_write_memory(fb->bufY+offset, pY+offset, lineWidth, endian);
  227. ctx->currentRow++;
  228. }
  229. else {
  230. Uint32 currentChromaRow = (attr.format == FORMAT_444) ? ctx->currentRow : ctx->currentRow/2;
  231. jdi_write_memory(fb->bufY+lumaOffset, pY+lumaOffset, ctx->lumaLineWidth, endian);
  232. if (attr.format != FORMAT_444) {
  233. jdi_write_memory(fb->bufY+lumaOffset+ctx->lumaLineWidth, pY+lumaOffset+ctx->lumaLineWidth, ctx->lumaLineWidth, endian);
  234. }
  235. pU = pY + ctx->lumaSize;
  236. if (attr.chromaInterleaved == TRUE) {
  237. chromaOffset = currentChromaRow * ctx->chromaLineWidth * 2;
  238. jdi_write_memory(fb->bufCb+chromaOffset, pU+chromaOffset, 2*ctx->chromaLineWidth, endian);
  239. }
  240. else {
  241. chromaOffset = currentChromaRow * ctx->chromaLineWidth;
  242. jdi_write_memory(fb->bufCb+chromaOffset, pU+chromaOffset, ctx->chromaLineWidth, endian);
  243. pV = pU + ctx->chromaSize;
  244. jdi_write_memory(fb->bufCr+chromaOffset, pV+chromaOffset, ctx->chromaLineWidth, endian);
  245. }
  246. ctx->currentRow += attr.format == FORMAT_444 ? 1 : 2;
  247. }
  248. break;
  249. default:
  250. JLOG(ERR, "%s:%d NOT SUPPORTED YUV YUV_FMT:%d\n", __FUNCTION__, __LINE__);
  251. success = FALSE;
  252. break;
  253. }
  254. return success == FALSE ? -1 : ctx->currentRow;
  255. }
  256. static BOOL IYuvFeeder_Create(
  257. AbstractYuvFeeder* feeder,
  258. const char* path
  259. )
  260. {
  261. IYuvContext* ctx;
  262. FILE* fp;
  263. if ((fp=fopen(path, "rb")) == NULL) {
  264. JLOG(ERR, "%s:%d failed to open yuv file: %s\n", __FUNCTION__, __LINE__, path);
  265. return FALSE;
  266. }
  267. if ((ctx=(IYuvContext*)malloc(sizeof(IYuvContext))) == NULL) {
  268. fclose(fp);
  269. return FALSE;
  270. }
  271. memset(ctx, 0, sizeof(IYuvContext));
  272. ctx->fp = fp;
  273. CalcYuvFrameSize(&feeder->attr, ctx);
  274. ctx->pYuv = malloc(ctx->frameSize);
  275. feeder->impl->context = (void*)ctx;
  276. return TRUE;
  277. }
  278. static BOOL IYuvFeeder_Destroy(
  279. AbstractYuvFeeder* feeder
  280. )
  281. {
  282. IYuvContext* ctx;
  283. if (feeder == NULL) {
  284. return FALSE;
  285. }
  286. ctx = (IYuvContext*)feeder->impl->context;
  287. if (ctx->fp != NULL) {
  288. fclose(ctx->fp); //lint !e482
  289. }
  290. if (ctx->pYuv != NULL) {
  291. free(ctx->pYuv);
  292. }
  293. free(ctx);
  294. return FALSE;
  295. }
  296. static Int32 IYuvFeeder_Feed(
  297. AbstractYuvFeeder* feeder,
  298. FrameBuffer* fb,
  299. Uint32 endian
  300. )
  301. {
  302. if (feeder->sliceHeight > 0) {
  303. return LoadSliceFromFile((IYuvContext*)feeder->impl->context, fb, feeder->attr, endian);
  304. }
  305. else {
  306. return LoadFrameFromFile((IYuvContext*)feeder->impl->context, fb, feeder->attr, endian);
  307. }
  308. }
  309. static BOOL IYuvFeeder_Configure(
  310. AbstractYuvFeeder* feeder,
  311. Uint32 cmd,
  312. void* arg
  313. )
  314. {
  315. UNREFERENCED_PARAMETER(feeder);
  316. UNREFERENCED_PARAMETER(cmd);
  317. UNREFERENCED_PARAMETER(arg);
  318. return FALSE;
  319. }
  320. static YuvFeederImpl IYuvFeederImpl = {
  321. NULL,
  322. IYuvFeeder_Create,
  323. IYuvFeeder_Feed,
  324. IYuvFeeder_Destroy,
  325. IYuvFeeder_Configure
  326. };
  327. static Int32 FeedYuv(
  328. AbstractYuvFeeder* feeder,
  329. FrameBuffer* fb
  330. )
  331. {
  332. YuvFeederImpl* impl = feeder->impl;
  333. return impl->Feed(feeder, fb, feeder->fbEndian);
  334. }
  335. static void NotifyPictureDone(
  336. AbstractYuvFeeder* absFeeder,
  337. Int32 lines
  338. )
  339. {
  340. YuvFeederListenerArg larg;
  341. BOOL doNotify = FALSE;
  342. // Notify to the client when errors occur or slice buffer is filled.
  343. doNotify = (BOOL)(lines <= 0 || (lines%(Int32)absFeeder->sliceHeight) == 0);
  344. if (doNotify) {
  345. larg.currentRow = lines<=0 ? absFeeder->attr.height : lines;
  346. larg.context = absFeeder->sliceNotiCtx;
  347. larg.height = absFeeder->attr.height;
  348. absFeeder->listener(&larg);
  349. }
  350. return;
  351. }
  352. static void YuvFeederThread(
  353. void* arg
  354. )
  355. {
  356. AbstractYuvFeeder* absFeeder = (AbstractYuvFeeder*)arg;
  357. FrameBuffer* fb;
  358. Int32 lines;
  359. BOOL done = FALSE;
  360. while (absFeeder->threadStop == FALSE) {
  361. if ((fb=Queue_Dequeue(absFeeder->fbQueue)) == NULL) {
  362. MSleep(10);
  363. continue;
  364. }
  365. done = FALSE;
  366. while (done == FALSE) {
  367. if ((lines=FeedYuv(absFeeder, fb)) == absFeeder->attr.height) {
  368. done = TRUE;
  369. }
  370. NotifyPictureDone(absFeeder, lines);
  371. if (lines <= 0)
  372. break; // Error
  373. }
  374. }
  375. }
  376. /*lint -esym(438, ap) */
  377. YuvFeeder YuvFeeder_Create(
  378. YuvFeederMode mode,
  379. const char* path,
  380. YuvAttr attr,
  381. Uint32 fbEndian,
  382. YuvFeederListener listener
  383. )
  384. {
  385. AbstractYuvFeeder *feeder;
  386. YuvFeederImpl *impl;
  387. BOOL success = FALSE;
  388. if (path == NULL) {
  389. JLOG(ERR, "%s:%d src path is NULL\n", __FUNCTION__, __LINE__);
  390. return NULL;
  391. }
  392. if ((impl=malloc(sizeof(YuvFeederImpl))) == NULL) {
  393. return NULL;
  394. }
  395. memcpy((void*)impl, (void*)&IYuvFeederImpl, sizeof(YuvFeederImpl));
  396. if ((feeder=(AbstractYuvFeeder*)calloc(1, sizeof(AbstractYuvFeeder))) == NULL) {
  397. free(impl);
  398. return NULL;
  399. }
  400. feeder->impl = impl;
  401. feeder->thread = NULL;
  402. feeder->threadStop = FALSE;
  403. feeder->listener = NULL;
  404. feeder->fbEndian = fbEndian;
  405. feeder->fbQueue = NULL;
  406. feeder->attr = attr;
  407. success = impl->Create(feeder, path);
  408. if (success == FALSE)
  409. return NULL;
  410. if (mode == YUV_FEEDER_MODE_THREAD) {
  411. feeder->thread = (void*)JpuThread_Create((JpuThreadRunner)YuvFeederThread, (void*)feeder);
  412. feeder->listener = (listener == NULL) ? DefaultListener : listener;
  413. feeder->fbQueue = Queue_Create_With_Lock(FB_QUEUE_SIZE, sizeof(FrameBuffer));
  414. }
  415. return feeder;
  416. }
  417. /*lint +esym(438, ap) */
  418. BOOL YuvFeeder_Destroy(
  419. YuvFeeder feeder
  420. )
  421. {
  422. YuvFeederImpl* impl = NULL;
  423. AbstractYuvFeeder* absFeeder = (AbstractYuvFeeder*)feeder;
  424. if (absFeeder == NULL) {
  425. JLOG(ERR, "%s:%d Invalid handle\n", __FUNCTION__, __LINE__);
  426. return FALSE;
  427. }
  428. impl = absFeeder->impl;
  429. if (absFeeder->thread) {
  430. absFeeder->threadStop = TRUE;
  431. JpuThread_Join((JpuThread)absFeeder->thread);
  432. }
  433. impl->Destroy(absFeeder);
  434. free(impl);
  435. free(feeder);
  436. return TRUE;
  437. }
  438. BOOL YuvFeeder_Feed(
  439. YuvFeeder feeder,
  440. FrameBuffer* fb
  441. )
  442. {
  443. AbstractYuvFeeder* absFeeder = (AbstractYuvFeeder*)feeder;
  444. if (absFeeder == NULL) {
  445. JLOG(ERR, "%s:%d Invalid handle\n", __FUNCTION__, __LINE__);
  446. return FALSE;
  447. }
  448. if (absFeeder->thread == NULL) {
  449. return FeedYuv(absFeeder, fb);
  450. }
  451. else {
  452. return Queue_Enqueue(absFeeder->fbQueue, fb);
  453. }
  454. }
  455. BOOL YuvFeeder_Configure(
  456. YuvFeeder feeder,
  457. YuvFeederCmd cmd,
  458. void* arg
  459. )
  460. {
  461. AbstractYuvFeeder* absFeeder = (AbstractYuvFeeder*)feeder;
  462. BOOL success = TRUE;
  463. SliceNotifyParam* sliceParam;
  464. if (absFeeder == NULL) {
  465. JLOG(ERR, "%s:%d Invalid handle\n", __FUNCTION__, __LINE__);
  466. return FALSE;
  467. }
  468. switch (cmd) {
  469. case YUV_FEEDER_CMD_SET_SLICE_NOTIFY:
  470. if (absFeeder->thread == NULL) {
  471. JLOG(ERR, "The YuvFeeder is not thread mode\n");
  472. break;
  473. }
  474. sliceParam = (SliceNotifyParam*)arg;
  475. absFeeder->sliceHeight = sliceParam->rows;
  476. absFeeder->sliceNotiCtx = sliceParam->arg;
  477. break;
  478. default:
  479. success = FALSE;
  480. break;
  481. }
  482. return success;
  483. }