2
0

convert_jpeg.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. * Copyright 2011 The LibYuv Project Authors. All rights reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #include "libyuv/convert.h"
  11. #include "libyuv/convert_argb.h"
  12. #ifdef HAVE_JPEG
  13. #include "libyuv/mjpeg_decoder.h"
  14. #endif
  15. #ifdef __cplusplus
  16. namespace libyuv {
  17. extern "C" {
  18. #endif
  19. #ifdef HAVE_JPEG
  20. struct I420Buffers {
  21. uint8_t* y;
  22. int y_stride;
  23. uint8_t* u;
  24. int u_stride;
  25. uint8_t* v;
  26. int v_stride;
  27. int w;
  28. int h;
  29. };
  30. static void JpegCopyI420(void* opaque,
  31. const uint8_t* const* data,
  32. const int* strides,
  33. int rows) {
  34. I420Buffers* dest = (I420Buffers*)(opaque);
  35. I420Copy(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  36. dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v,
  37. dest->v_stride, dest->w, rows);
  38. dest->y += rows * dest->y_stride;
  39. dest->u += ((rows + 1) >> 1) * dest->u_stride;
  40. dest->v += ((rows + 1) >> 1) * dest->v_stride;
  41. dest->h -= rows;
  42. }
  43. static void JpegI422ToI420(void* opaque,
  44. const uint8_t* const* data,
  45. const int* strides,
  46. int rows) {
  47. I420Buffers* dest = (I420Buffers*)(opaque);
  48. I422ToI420(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  49. dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v,
  50. dest->v_stride, dest->w, rows);
  51. dest->y += rows * dest->y_stride;
  52. dest->u += ((rows + 1) >> 1) * dest->u_stride;
  53. dest->v += ((rows + 1) >> 1) * dest->v_stride;
  54. dest->h -= rows;
  55. }
  56. static void JpegI444ToI420(void* opaque,
  57. const uint8_t* const* data,
  58. const int* strides,
  59. int rows) {
  60. I420Buffers* dest = (I420Buffers*)(opaque);
  61. I444ToI420(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  62. dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v,
  63. dest->v_stride, dest->w, rows);
  64. dest->y += rows * dest->y_stride;
  65. dest->u += ((rows + 1) >> 1) * dest->u_stride;
  66. dest->v += ((rows + 1) >> 1) * dest->v_stride;
  67. dest->h -= rows;
  68. }
  69. static void JpegI400ToI420(void* opaque,
  70. const uint8_t* const* data,
  71. const int* strides,
  72. int rows) {
  73. I420Buffers* dest = (I420Buffers*)(opaque);
  74. I400ToI420(data[0], strides[0], dest->y, dest->y_stride, dest->u,
  75. dest->u_stride, dest->v, dest->v_stride, dest->w, rows);
  76. dest->y += rows * dest->y_stride;
  77. dest->u += ((rows + 1) >> 1) * dest->u_stride;
  78. dest->v += ((rows + 1) >> 1) * dest->v_stride;
  79. dest->h -= rows;
  80. }
  81. // Query size of MJPG in pixels.
  82. LIBYUV_API
  83. int MJPGSize(const uint8_t* src_mjpg,
  84. size_t src_size_mjpg,
  85. int* width,
  86. int* height) {
  87. MJpegDecoder mjpeg_decoder;
  88. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(src_mjpg, src_size_mjpg);
  89. if (ret) {
  90. *width = mjpeg_decoder.GetWidth();
  91. *height = mjpeg_decoder.GetHeight();
  92. }
  93. mjpeg_decoder.UnloadFrame();
  94. return ret ? 0 : -1; // -1 for runtime failure.
  95. }
  96. // MJPG (Motion JPeg) to I420
  97. // TODO(fbarchard): review src_width and src_height requirement. dst_width and
  98. // dst_height may be enough.
  99. LIBYUV_API
  100. int MJPGToI420(const uint8_t* src_mjpg,
  101. size_t src_size_mjpg,
  102. uint8_t* dst_y,
  103. int dst_stride_y,
  104. uint8_t* dst_u,
  105. int dst_stride_u,
  106. uint8_t* dst_v,
  107. int dst_stride_v,
  108. int src_width,
  109. int src_height,
  110. int dst_width,
  111. int dst_height) {
  112. if (src_size_mjpg == kUnknownDataSize) {
  113. // ERROR: MJPEG frame size unknown
  114. return -1;
  115. }
  116. // TODO(fbarchard): Port MJpeg to C.
  117. MJpegDecoder mjpeg_decoder;
  118. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(src_mjpg, src_size_mjpg);
  119. if (ret && (mjpeg_decoder.GetWidth() != src_width ||
  120. mjpeg_decoder.GetHeight() != src_height)) {
  121. // ERROR: MJPEG frame has unexpected dimensions
  122. mjpeg_decoder.UnloadFrame();
  123. return 1; // runtime failure
  124. }
  125. if (ret) {
  126. I420Buffers bufs = {dst_y, dst_stride_y, dst_u, dst_stride_u,
  127. dst_v, dst_stride_v, dst_width, dst_height};
  128. // YUV420
  129. if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
  130. mjpeg_decoder.GetNumComponents() == 3 &&
  131. mjpeg_decoder.GetVertSampFactor(0) == 2 &&
  132. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  133. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  134. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  135. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  136. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  137. ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dst_width,
  138. dst_height);
  139. // YUV422
  140. } else if (mjpeg_decoder.GetColorSpace() ==
  141. MJpegDecoder::kColorSpaceYCbCr &&
  142. mjpeg_decoder.GetNumComponents() == 3 &&
  143. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  144. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  145. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  146. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  147. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  148. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  149. ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dst_width,
  150. dst_height);
  151. // YUV444
  152. } else if (mjpeg_decoder.GetColorSpace() ==
  153. MJpegDecoder::kColorSpaceYCbCr &&
  154. mjpeg_decoder.GetNumComponents() == 3 &&
  155. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  156. mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
  157. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  158. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  159. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  160. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  161. ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dst_width,
  162. dst_height);
  163. // YUV400
  164. } else if (mjpeg_decoder.GetColorSpace() ==
  165. MJpegDecoder::kColorSpaceGrayscale &&
  166. mjpeg_decoder.GetNumComponents() == 1 &&
  167. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  168. mjpeg_decoder.GetHorizSampFactor(0) == 1) {
  169. ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dst_width,
  170. dst_height);
  171. } else {
  172. // TODO(fbarchard): Implement conversion for any other
  173. // colorspace/subsample factors that occur in practice. ERROR: Unable to
  174. // convert MJPEG frame because format is not supported
  175. mjpeg_decoder.UnloadFrame();
  176. return 1;
  177. }
  178. }
  179. return ret ? 0 : 1;
  180. }
  181. struct NV21Buffers {
  182. uint8_t* y;
  183. int y_stride;
  184. uint8_t* vu;
  185. int vu_stride;
  186. int w;
  187. int h;
  188. };
  189. static void JpegI420ToNV21(void* opaque,
  190. const uint8_t* const* data,
  191. const int* strides,
  192. int rows) {
  193. NV21Buffers* dest = (NV21Buffers*)(opaque);
  194. I420ToNV21(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  195. dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows);
  196. dest->y += rows * dest->y_stride;
  197. dest->vu += ((rows + 1) >> 1) * dest->vu_stride;
  198. dest->h -= rows;
  199. }
  200. static void JpegI422ToNV21(void* opaque,
  201. const uint8_t* const* data,
  202. const int* strides,
  203. int rows) {
  204. NV21Buffers* dest = (NV21Buffers*)(opaque);
  205. I422ToNV21(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  206. dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows);
  207. dest->y += rows * dest->y_stride;
  208. dest->vu += ((rows + 1) >> 1) * dest->vu_stride;
  209. dest->h -= rows;
  210. }
  211. static void JpegI444ToNV21(void* opaque,
  212. const uint8_t* const* data,
  213. const int* strides,
  214. int rows) {
  215. NV21Buffers* dest = (NV21Buffers*)(opaque);
  216. I444ToNV21(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  217. dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows);
  218. dest->y += rows * dest->y_stride;
  219. dest->vu += ((rows + 1) >> 1) * dest->vu_stride;
  220. dest->h -= rows;
  221. }
  222. static void JpegI400ToNV21(void* opaque,
  223. const uint8_t* const* data,
  224. const int* strides,
  225. int rows) {
  226. NV21Buffers* dest = (NV21Buffers*)(opaque);
  227. I400ToNV21(data[0], strides[0], dest->y, dest->y_stride, dest->vu,
  228. dest->vu_stride, dest->w, rows);
  229. dest->y += rows * dest->y_stride;
  230. dest->vu += ((rows + 1) >> 1) * dest->vu_stride;
  231. dest->h -= rows;
  232. }
  233. // MJPG (Motion JPeg) to NV21
  234. LIBYUV_API
  235. int MJPGToNV21(const uint8_t* src_mjpg,
  236. size_t src_size_mjpg,
  237. uint8_t* dst_y,
  238. int dst_stride_y,
  239. uint8_t* dst_vu,
  240. int dst_stride_vu,
  241. int src_width,
  242. int src_height,
  243. int dst_width,
  244. int dst_height) {
  245. if (src_size_mjpg == kUnknownDataSize) {
  246. // ERROR: MJPEG frame size unknown
  247. return -1;
  248. }
  249. // TODO(fbarchard): Port MJpeg to C.
  250. MJpegDecoder mjpeg_decoder;
  251. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(src_mjpg, src_size_mjpg);
  252. if (ret && (mjpeg_decoder.GetWidth() != src_width ||
  253. mjpeg_decoder.GetHeight() != src_height)) {
  254. // ERROR: MJPEG frame has unexpected dimensions
  255. mjpeg_decoder.UnloadFrame();
  256. return 1; // runtime failure
  257. }
  258. if (ret) {
  259. NV21Buffers bufs = {dst_y, dst_stride_y, dst_vu,
  260. dst_stride_vu, dst_width, dst_height};
  261. // YUV420
  262. if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
  263. mjpeg_decoder.GetNumComponents() == 3 &&
  264. mjpeg_decoder.GetVertSampFactor(0) == 2 &&
  265. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  266. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  267. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  268. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  269. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  270. ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToNV21, &bufs, dst_width,
  271. dst_height);
  272. // YUV422
  273. } else if (mjpeg_decoder.GetColorSpace() ==
  274. MJpegDecoder::kColorSpaceYCbCr &&
  275. mjpeg_decoder.GetNumComponents() == 3 &&
  276. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  277. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  278. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  279. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  280. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  281. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  282. ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToNV21, &bufs, dst_width,
  283. dst_height);
  284. // YUV444
  285. } else if (mjpeg_decoder.GetColorSpace() ==
  286. MJpegDecoder::kColorSpaceYCbCr &&
  287. mjpeg_decoder.GetNumComponents() == 3 &&
  288. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  289. mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
  290. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  291. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  292. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  293. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  294. ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToNV21, &bufs, dst_width,
  295. dst_height);
  296. // YUV400
  297. } else if (mjpeg_decoder.GetColorSpace() ==
  298. MJpegDecoder::kColorSpaceGrayscale &&
  299. mjpeg_decoder.GetNumComponents() == 1 &&
  300. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  301. mjpeg_decoder.GetHorizSampFactor(0) == 1) {
  302. ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToNV21, &bufs, dst_width,
  303. dst_height);
  304. } else {
  305. // Unknown colorspace.
  306. mjpeg_decoder.UnloadFrame();
  307. return 1;
  308. }
  309. }
  310. return ret ? 0 : 1;
  311. }
  312. struct ARGBBuffers {
  313. uint8_t* argb;
  314. int argb_stride;
  315. int w;
  316. int h;
  317. };
  318. static void JpegI420ToARGB(void* opaque,
  319. const uint8_t* const* data,
  320. const int* strides,
  321. int rows) {
  322. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  323. I420ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  324. dest->argb, dest->argb_stride, dest->w, rows);
  325. dest->argb += rows * dest->argb_stride;
  326. dest->h -= rows;
  327. }
  328. static void JpegI422ToARGB(void* opaque,
  329. const uint8_t* const* data,
  330. const int* strides,
  331. int rows) {
  332. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  333. I422ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  334. dest->argb, dest->argb_stride, dest->w, rows);
  335. dest->argb += rows * dest->argb_stride;
  336. dest->h -= rows;
  337. }
  338. static void JpegI444ToARGB(void* opaque,
  339. const uint8_t* const* data,
  340. const int* strides,
  341. int rows) {
  342. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  343. I444ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  344. dest->argb, dest->argb_stride, dest->w, rows);
  345. dest->argb += rows * dest->argb_stride;
  346. dest->h -= rows;
  347. }
  348. static void JpegI400ToARGB(void* opaque,
  349. const uint8_t* const* data,
  350. const int* strides,
  351. int rows) {
  352. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  353. I400ToARGB(data[0], strides[0], dest->argb, dest->argb_stride, dest->w, rows);
  354. dest->argb += rows * dest->argb_stride;
  355. dest->h -= rows;
  356. }
  357. // MJPG (Motion JPeg) to ARGB
  358. // TODO(fbarchard): review src_width and src_height requirement. dst_width and
  359. // dst_height may be enough.
  360. LIBYUV_API
  361. int MJPGToARGB(const uint8_t* src_mjpg,
  362. size_t src_size_mjpg,
  363. uint8_t* dst_argb,
  364. int dst_stride_argb,
  365. int src_width,
  366. int src_height,
  367. int dst_width,
  368. int dst_height) {
  369. if (src_size_mjpg == kUnknownDataSize) {
  370. // ERROR: MJPEG frame size unknown
  371. return -1;
  372. }
  373. // TODO(fbarchard): Port MJpeg to C.
  374. MJpegDecoder mjpeg_decoder;
  375. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(src_mjpg, src_size_mjpg);
  376. if (ret && (mjpeg_decoder.GetWidth() != src_width ||
  377. mjpeg_decoder.GetHeight() != src_height)) {
  378. // ERROR: MJPEG frame has unexpected dimensions
  379. mjpeg_decoder.UnloadFrame();
  380. return 1; // runtime failure
  381. }
  382. if (ret) {
  383. ARGBBuffers bufs = {dst_argb, dst_stride_argb, dst_width, dst_height};
  384. // YUV420
  385. if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
  386. mjpeg_decoder.GetNumComponents() == 3 &&
  387. mjpeg_decoder.GetVertSampFactor(0) == 2 &&
  388. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  389. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  390. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  391. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  392. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  393. ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dst_width,
  394. dst_height);
  395. // YUV422
  396. } else if (mjpeg_decoder.GetColorSpace() ==
  397. MJpegDecoder::kColorSpaceYCbCr &&
  398. mjpeg_decoder.GetNumComponents() == 3 &&
  399. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  400. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  401. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  402. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  403. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  404. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  405. ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dst_width,
  406. dst_height);
  407. // YUV444
  408. } else if (mjpeg_decoder.GetColorSpace() ==
  409. MJpegDecoder::kColorSpaceYCbCr &&
  410. mjpeg_decoder.GetNumComponents() == 3 &&
  411. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  412. mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
  413. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  414. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  415. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  416. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  417. ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dst_width,
  418. dst_height);
  419. // YUV400
  420. } else if (mjpeg_decoder.GetColorSpace() ==
  421. MJpegDecoder::kColorSpaceGrayscale &&
  422. mjpeg_decoder.GetNumComponents() == 1 &&
  423. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  424. mjpeg_decoder.GetHorizSampFactor(0) == 1) {
  425. ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dst_width,
  426. dst_height);
  427. } else {
  428. // TODO(fbarchard): Implement conversion for any other
  429. // colorspace/subsample factors that occur in practice. ERROR: Unable to
  430. // convert MJPEG frame because format is not supported
  431. mjpeg_decoder.UnloadFrame();
  432. return 1;
  433. }
  434. }
  435. return ret ? 0 : 1;
  436. }
  437. #endif // HAVE_JPEG
  438. #ifdef __cplusplus
  439. } // extern "C"
  440. } // namespace libyuv
  441. #endif