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