convert_jpeg.cc 14 KB

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