convert_jpeg.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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], 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* 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* 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* 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* sample, size_t sample_size, int* width, int* height) {
  84. MJpegDecoder mjpeg_decoder;
  85. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
  86. if (ret) {
  87. *width = mjpeg_decoder.GetWidth();
  88. *height = mjpeg_decoder.GetHeight();
  89. }
  90. mjpeg_decoder.UnloadFrame();
  91. return ret ? 0 : -1; // -1 for runtime failure.
  92. }
  93. // MJPG (Motion JPeg) to I420
  94. // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
  95. LIBYUV_API
  96. int MJPGToI420(const uint8* sample,
  97. size_t sample_size,
  98. uint8* y,
  99. int y_stride,
  100. uint8* u,
  101. int u_stride,
  102. uint8* v,
  103. int v_stride,
  104. int w,
  105. int h,
  106. int dw,
  107. int dh) {
  108. if (sample_size == kUnknownDataSize) {
  109. // ERROR: MJPEG frame size unknown
  110. return -1;
  111. }
  112. // TODO(fbarchard): Port MJpeg to C.
  113. MJpegDecoder mjpeg_decoder;
  114. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
  115. if (ret &&
  116. (mjpeg_decoder.GetWidth() != w || mjpeg_decoder.GetHeight() != h)) {
  117. // ERROR: MJPEG frame has unexpected dimensions
  118. mjpeg_decoder.UnloadFrame();
  119. return 1; // runtime failure
  120. }
  121. if (ret) {
  122. I420Buffers bufs = {y, y_stride, u, u_stride, v, v_stride, dw, dh};
  123. // YUV420
  124. if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
  125. mjpeg_decoder.GetNumComponents() == 3 &&
  126. mjpeg_decoder.GetVertSampFactor(0) == 2 &&
  127. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  128. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  129. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  130. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  131. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  132. ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dw, dh);
  133. // YUV422
  134. } else if (mjpeg_decoder.GetColorSpace() ==
  135. MJpegDecoder::kColorSpaceYCbCr &&
  136. mjpeg_decoder.GetNumComponents() == 3 &&
  137. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  138. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  139. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  140. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  141. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  142. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  143. ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh);
  144. // YUV444
  145. } else if (mjpeg_decoder.GetColorSpace() ==
  146. MJpegDecoder::kColorSpaceYCbCr &&
  147. mjpeg_decoder.GetNumComponents() == 3 &&
  148. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  149. mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
  150. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  151. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  152. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  153. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  154. ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh);
  155. // YUV400
  156. } else if (mjpeg_decoder.GetColorSpace() ==
  157. MJpegDecoder::kColorSpaceGrayscale &&
  158. mjpeg_decoder.GetNumComponents() == 1 &&
  159. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  160. mjpeg_decoder.GetHorizSampFactor(0) == 1) {
  161. ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh);
  162. } else {
  163. // TODO(fbarchard): Implement conversion for any other colorspace/sample
  164. // factors that occur in practice.
  165. // ERROR: Unable to convert MJPEG frame because format is not supported
  166. mjpeg_decoder.UnloadFrame();
  167. return 1;
  168. }
  169. }
  170. return ret ? 0 : 1;
  171. }
  172. #ifdef HAVE_JPEG
  173. struct ARGBBuffers {
  174. uint8* argb;
  175. int argb_stride;
  176. int w;
  177. int h;
  178. };
  179. static void JpegI420ToARGB(void* opaque,
  180. const uint8* const* data,
  181. const int* strides,
  182. int rows) {
  183. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  184. I420ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  185. dest->argb, dest->argb_stride, dest->w, rows);
  186. dest->argb += rows * dest->argb_stride;
  187. dest->h -= rows;
  188. }
  189. static void JpegI422ToARGB(void* opaque,
  190. const uint8* const* data,
  191. const int* strides,
  192. int rows) {
  193. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  194. I422ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  195. dest->argb, dest->argb_stride, dest->w, rows);
  196. dest->argb += rows * dest->argb_stride;
  197. dest->h -= rows;
  198. }
  199. static void JpegI444ToARGB(void* opaque,
  200. const uint8* const* data,
  201. const int* strides,
  202. int rows) {
  203. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  204. I444ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
  205. dest->argb, dest->argb_stride, dest->w, rows);
  206. dest->argb += rows * dest->argb_stride;
  207. dest->h -= rows;
  208. }
  209. static void JpegI400ToARGB(void* opaque,
  210. const uint8* const* data,
  211. const int* strides,
  212. int rows) {
  213. ARGBBuffers* dest = (ARGBBuffers*)(opaque);
  214. I400ToARGB(data[0], strides[0], dest->argb, dest->argb_stride, dest->w, rows);
  215. dest->argb += rows * dest->argb_stride;
  216. dest->h -= rows;
  217. }
  218. // MJPG (Motion JPeg) to ARGB
  219. // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
  220. LIBYUV_API
  221. int MJPGToARGB(const uint8* sample,
  222. size_t sample_size,
  223. uint8* argb,
  224. int argb_stride,
  225. int w,
  226. int h,
  227. int dw,
  228. int dh) {
  229. if (sample_size == kUnknownDataSize) {
  230. // ERROR: MJPEG frame size unknown
  231. return -1;
  232. }
  233. // TODO(fbarchard): Port MJpeg to C.
  234. MJpegDecoder mjpeg_decoder;
  235. LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
  236. if (ret &&
  237. (mjpeg_decoder.GetWidth() != w || mjpeg_decoder.GetHeight() != h)) {
  238. // ERROR: MJPEG frame has unexpected dimensions
  239. mjpeg_decoder.UnloadFrame();
  240. return 1; // runtime failure
  241. }
  242. if (ret) {
  243. ARGBBuffers bufs = {argb, argb_stride, dw, dh};
  244. // YUV420
  245. if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
  246. mjpeg_decoder.GetNumComponents() == 3 &&
  247. mjpeg_decoder.GetVertSampFactor(0) == 2 &&
  248. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  249. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  250. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  251. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  252. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  253. ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh);
  254. // YUV422
  255. } else if (mjpeg_decoder.GetColorSpace() ==
  256. MJpegDecoder::kColorSpaceYCbCr &&
  257. mjpeg_decoder.GetNumComponents() == 3 &&
  258. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  259. mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
  260. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  261. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  262. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  263. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  264. ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh);
  265. // YUV444
  266. } else if (mjpeg_decoder.GetColorSpace() ==
  267. MJpegDecoder::kColorSpaceYCbCr &&
  268. mjpeg_decoder.GetNumComponents() == 3 &&
  269. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  270. mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
  271. mjpeg_decoder.GetVertSampFactor(1) == 1 &&
  272. mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
  273. mjpeg_decoder.GetVertSampFactor(2) == 1 &&
  274. mjpeg_decoder.GetHorizSampFactor(2) == 1) {
  275. ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh);
  276. // YUV400
  277. } else if (mjpeg_decoder.GetColorSpace() ==
  278. MJpegDecoder::kColorSpaceGrayscale &&
  279. mjpeg_decoder.GetNumComponents() == 1 &&
  280. mjpeg_decoder.GetVertSampFactor(0) == 1 &&
  281. mjpeg_decoder.GetHorizSampFactor(0) == 1) {
  282. ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh);
  283. } else {
  284. // TODO(fbarchard): Implement conversion for any other colorspace/sample
  285. // factors that occur in practice.
  286. // ERROR: Unable to convert MJPEG frame because format is not supported
  287. mjpeg_decoder.UnloadFrame();
  288. return 1;
  289. }
  290. }
  291. return ret ? 0 : 1;
  292. }
  293. #endif
  294. #endif
  295. #ifdef __cplusplus
  296. } // extern "C"
  297. } // namespace libyuv
  298. #endif