convert_jpeg.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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* y;
  22. int y_stride;
  23. uint8* u;
  24. int u_stride;
  25. uint8* v;
  26. int v_stride;
  27. int w;
  28. int h;
  29. };
  30. static void JpegCopyI420(void* opaque,
  31. const uint8* const* data,
  32. const int* strides,
  33. int rows) {
  34. I420Buffers* dest = (I420Buffers*)(opaque);
  35. I420Copy(data[0], strides[0],
  36. data[1], strides[1],
  37. data[2], strides[2],
  38. dest->y, dest->y_stride,
  39. dest->u, dest->u_stride,
  40. dest->v, dest->v_stride,
  41. dest->w, rows);
  42. dest->y += rows * dest->y_stride;
  43. dest->u += ((rows + 1) >> 1) * dest->u_stride;
  44. dest->v += ((rows + 1) >> 1) * dest->v_stride;
  45. dest->h -= rows;
  46. }
  47. static void JpegI422ToI420(void* opaque,
  48. const uint8* const* data,
  49. const int* strides,
  50. int rows) {
  51. I420Buffers* dest = (I420Buffers*)(opaque);
  52. I422ToI420(data[0], strides[0],
  53. data[1], strides[1],
  54. data[2], strides[2],
  55. dest->y, dest->y_stride,
  56. dest->u, dest->u_stride,
  57. dest->v, dest->v_stride,
  58. dest->w, rows);
  59. dest->y += rows * dest->y_stride;
  60. dest->u += ((rows + 1) >> 1) * dest->u_stride;
  61. dest->v += ((rows + 1) >> 1) * dest->v_stride;
  62. dest->h -= rows;
  63. }
  64. static void JpegI444ToI420(void* opaque,
  65. const uint8* const* data,
  66. const int* strides,
  67. int rows) {
  68. I420Buffers* dest = (I420Buffers*)(opaque);
  69. I444ToI420(data[0], strides[0],
  70. data[1], strides[1],
  71. data[2], strides[2],
  72. dest->y, dest->y_stride,
  73. dest->u, dest->u_stride,
  74. dest->v, dest->v_stride,
  75. 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. static void JpegI411ToI420(void* opaque,
  82. const uint8* const* data,
  83. const int* strides,
  84. int rows) {
  85. I420Buffers* dest = (I420Buffers*)(opaque);
  86. I411ToI420(data[0], strides[0],
  87. data[1], strides[1],
  88. data[2], strides[2],
  89. dest->y, dest->y_stride,
  90. dest->u, dest->u_stride,
  91. dest->v, dest->v_stride,
  92. dest->w, rows);
  93. dest->y += rows * dest->y_stride;
  94. dest->u += ((rows + 1) >> 1) * dest->u_stride;
  95. dest->v += ((rows + 1) >> 1) * dest->v_stride;
  96. dest->h -= rows;
  97. }
  98. static void JpegI400ToI420(void* opaque,
  99. const uint8* const* data,
  100. const int* strides,
  101. int rows) {
  102. I420Buffers* dest = (I420Buffers*)(opaque);
  103. I400ToI420(data[0], strides[0],
  104. dest->y, dest->y_stride,
  105. dest->u, dest->u_stride,
  106. dest->v, dest->v_stride,
  107. dest->w, rows);
  108. dest->y += rows * dest->y_stride;
  109. dest->u += ((rows + 1) >> 1) * dest->u_stride;
  110. dest->v += ((rows + 1) >> 1) * dest->v_stride;
  111. dest->h -= rows;
  112. }
  113. // Query size of MJPG in pixels.
  114. LIBYUV_API
  115. int MJPGSize(const uint8* sample, size_t sample_size,
  116. int* width, int* height) {
  117. MJpegDecoder mjpeg_decoder;
  118. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
  119. if (ret) {
  120. *width = mjpeg_decoder.GetWidth();
  121. *height = mjpeg_decoder.GetHeight();
  122. }
  123. mjpeg_decoder.UnloadFrame();
  124. return ret ? 0 : -1; // -1 for runtime failure.
  125. }
  126. // MJPG (Motion JPeg) to I420
  127. // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
  128. LIBYUV_API
  129. int MJPGToI420(const uint8* sample,
  130. size_t sample_size,
  131. uint8* y, int y_stride,
  132. uint8* u, int u_stride,
  133. uint8* v, int v_stride,
  134. int w, int h,
  135. int dw, int dh) {
  136. if (sample_size == kUnknownDataSize) {
  137. // ERROR: MJPEG frame size unknown
  138. return -1;
  139. }
  140. // TODO(fbarchard): Port MJpeg to C.
  141. MJpegDecoder mjpeg_decoder;
  142. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
  143. if (ret && (mjpeg_decoder.GetWidth() != w ||
  144. mjpeg_decoder.GetHeight() != h)) {
  145. // ERROR: MJPEG frame has unexpected dimensions
  146. mjpeg_decoder.UnloadFrame();
  147. return 1; // runtime failure
  148. }
  149. if (ret) {
  150. I420Buffers bufs = { y, y_stride, u, u_stride, v, v_stride, dw, dh };
  151. // YUV420
  152. if (mjpeg_decoder.GetColorSpace() ==
  153. MJpegDecoder::kColorSpaceYCbCr &&
  154. mjpeg_decoder.GetNumComponents() == 3 &&
  155. mjpeg_decoder.GetVertSampFactor(0) == 2 &&
  156. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  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(&JpegCopyI420, &bufs, dw, dh);
  162. // YUV422
  163. } else if (mjpeg_decoder.GetColorSpace() ==
  164. MJpegDecoder::kColorSpaceYCbCr &&
  165. mjpeg_decoder.GetNumComponents() == 3 &&
  166. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  167. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  168. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  169. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  170. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  171. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  172. ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh);
  173. // YUV444
  174. } else if (mjpeg_decoder.GetColorSpace() ==
  175. MJpegDecoder::kColorSpaceYCbCr &&
  176. mjpeg_decoder.GetNumComponents() == 3 &&
  177. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  178. mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
  179. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  180. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  181. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  182. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  183. ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh);
  184. // YUV411
  185. } else if (mjpeg_decoder.GetColorSpace() ==
  186. MJpegDecoder::kColorSpaceYCbCr &&
  187. mjpeg_decoder.GetNumComponents() == 3 &&
  188. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  189. mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
  190. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  191. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  192. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  193. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  194. ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToI420, &bufs, dw, dh);
  195. // YUV400
  196. } else if (mjpeg_decoder.GetColorSpace() ==
  197. MJpegDecoder::kColorSpaceGrayscale &&
  198. mjpeg_decoder.GetNumComponents() == 1 &&
  199. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  200. mjpeg_decoder.GetHorizSampFactor(0) == 1) {
  201. ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh);
  202. } else {
  203. // TODO(fbarchard): Implement conversion for any other colorspace/sample
  204. // factors that occur in practice. 411 is supported by libjpeg
  205. // ERROR: Unable to convert MJPEG frame because format is not supported
  206. mjpeg_decoder.UnloadFrame();
  207. return 1;
  208. }
  209. }
  210. return ret ? 0 : 1;
  211. }
  212. #ifdef HAVE_JPEG
  213. struct ARGBBuffers {
  214. uint8* argb;
  215. int argb_stride;
  216. int w;
  217. int h;
  218. };
  219. static void JpegI420ToARGB(void* opaque,
  220. const uint8* const* data,
  221. const int* strides,
  222. int rows) {
  223. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  224. I420ToARGB(data[0], strides[0],
  225. data[1], strides[1],
  226. data[2], strides[2],
  227. dest->argb, dest->argb_stride,
  228. dest->w, rows);
  229. dest->argb += rows * dest->argb_stride;
  230. dest->h -= rows;
  231. }
  232. static void JpegI422ToARGB(void* opaque,
  233. const uint8* const* data,
  234. const int* strides,
  235. int rows) {
  236. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  237. I422ToARGB(data[0], strides[0],
  238. data[1], strides[1],
  239. data[2], strides[2],
  240. dest->argb, dest->argb_stride,
  241. dest->w, rows);
  242. dest->argb += rows * dest->argb_stride;
  243. dest->h -= rows;
  244. }
  245. static void JpegI444ToARGB(void* opaque,
  246. const uint8* const* data,
  247. const int* strides,
  248. int rows) {
  249. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  250. I444ToARGB(data[0], strides[0],
  251. data[1], strides[1],
  252. data[2], strides[2],
  253. dest->argb, dest->argb_stride,
  254. dest->w, rows);
  255. dest->argb += rows * dest->argb_stride;
  256. dest->h -= rows;
  257. }
  258. static void JpegI411ToARGB(void* opaque,
  259. const uint8* const* data,
  260. const int* strides,
  261. int rows) {
  262. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  263. I411ToARGB(data[0], strides[0],
  264. data[1], strides[1],
  265. data[2], strides[2],
  266. dest->argb, dest->argb_stride,
  267. dest->w, rows);
  268. dest->argb += rows * dest->argb_stride;
  269. dest->h -= rows;
  270. }
  271. static void JpegI400ToARGB(void* opaque,
  272. const uint8* const* data,
  273. const int* strides,
  274. int rows) {
  275. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  276. I400ToARGB(data[0], strides[0],
  277. dest->argb, dest->argb_stride,
  278. dest->w, rows);
  279. dest->argb += rows * dest->argb_stride;
  280. dest->h -= rows;
  281. }
  282. // MJPG (Motion JPeg) to ARGB
  283. // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
  284. LIBYUV_API
  285. int MJPGToARGB(const uint8* sample,
  286. size_t sample_size,
  287. uint8* argb, int argb_stride,
  288. int w, int h,
  289. int dw, int dh) {
  290. if (sample_size == kUnknownDataSize) {
  291. // ERROR: MJPEG frame size unknown
  292. return -1;
  293. }
  294. // TODO(fbarchard): Port MJpeg to C.
  295. MJpegDecoder mjpeg_decoder;
  296. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
  297. if (ret && (mjpeg_decoder.GetWidth() != w ||
  298. mjpeg_decoder.GetHeight() != h)) {
  299. // ERROR: MJPEG frame has unexpected dimensions
  300. mjpeg_decoder.UnloadFrame();
  301. return 1; // runtime failure
  302. }
  303. if (ret) {
  304. ARGBBuffers bufs = { argb, argb_stride, dw, dh };
  305. // YUV420
  306. if (mjpeg_decoder.GetColorSpace() ==
  307. MJpegDecoder::kColorSpaceYCbCr &&
  308. mjpeg_decoder.GetNumComponents() == 3 &&
  309. mjpeg_decoder.GetVertSampFactor(0) == 2 &&
  310. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  311. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  312. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  313. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  314. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  315. ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh);
  316. // YUV422
  317. } else if (mjpeg_decoder.GetColorSpace() ==
  318. MJpegDecoder::kColorSpaceYCbCr &&
  319. mjpeg_decoder.GetNumComponents() == 3 &&
  320. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  321. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  322. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  323. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  324. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  325. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  326. ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh);
  327. // YUV444
  328. } else if (mjpeg_decoder.GetColorSpace() ==
  329. MJpegDecoder::kColorSpaceYCbCr &&
  330. mjpeg_decoder.GetNumComponents() == 3 &&
  331. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  332. mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
  333. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  334. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  335. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  336. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  337. ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh);
  338. // YUV411
  339. } else if (mjpeg_decoder.GetColorSpace() ==
  340. MJpegDecoder::kColorSpaceYCbCr &&
  341. mjpeg_decoder.GetNumComponents() == 3 &&
  342. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  343. mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
  344. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  345. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  346. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  347. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  348. ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToARGB, &bufs, dw, dh);
  349. // YUV400
  350. } else if (mjpeg_decoder.GetColorSpace() ==
  351. MJpegDecoder::kColorSpaceGrayscale &&
  352. mjpeg_decoder.GetNumComponents() == 1 &&
  353. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  354. mjpeg_decoder.GetHorizSampFactor(0) == 1) {
  355. ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh);
  356. } else {
  357. // TODO(fbarchard): Implement conversion for any other colorspace/sample
  358. // factors that occur in practice. 411 is supported by libjpeg
  359. // ERROR: Unable to convert MJPEG frame because format is not supported
  360. mjpeg_decoder.UnloadFrame();
  361. return 1;
  362. }
  363. }
  364. return ret ? 0 : 1;
  365. }
  366. #endif
  367. #endif
  368. #ifdef __cplusplus
  369. } // extern "C"
  370. } // namespace libyuv
  371. #endif