1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libyuv/source/convert_jpeg.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,392 @@ 1.4 +/* 1.5 + * Copyright 2011 The LibYuv Project Authors. All rights reserved. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license 1.8 + * that can be found in the LICENSE file in the root of the source 1.9 + * tree. An additional intellectual property rights grant can be found 1.10 + * in the file PATENTS. All contributing project authors may 1.11 + * be found in the AUTHORS file in the root of the source tree. 1.12 + */ 1.13 + 1.14 +#include "libyuv/convert.h" 1.15 + 1.16 +#ifdef HAVE_JPEG 1.17 +#include "libyuv/mjpeg_decoder.h" 1.18 +#endif 1.19 + 1.20 +#ifdef __cplusplus 1.21 +namespace libyuv { 1.22 +extern "C" { 1.23 +#endif 1.24 + 1.25 +#ifdef HAVE_JPEG 1.26 +struct I420Buffers { 1.27 + uint8* y; 1.28 + int y_stride; 1.29 + uint8* u; 1.30 + int u_stride; 1.31 + uint8* v; 1.32 + int v_stride; 1.33 + int w; 1.34 + int h; 1.35 +}; 1.36 + 1.37 +static void JpegCopyI420(void* opaque, 1.38 + const uint8* const* data, 1.39 + const int* strides, 1.40 + int rows) { 1.41 + I420Buffers* dest = (I420Buffers*)(opaque); 1.42 + I420Copy(data[0], strides[0], 1.43 + data[1], strides[1], 1.44 + data[2], strides[2], 1.45 + dest->y, dest->y_stride, 1.46 + dest->u, dest->u_stride, 1.47 + dest->v, dest->v_stride, 1.48 + dest->w, rows); 1.49 + dest->y += rows * dest->y_stride; 1.50 + dest->u += ((rows + 1) >> 1) * dest->u_stride; 1.51 + dest->v += ((rows + 1) >> 1) * dest->v_stride; 1.52 + dest->h -= rows; 1.53 +} 1.54 + 1.55 +static void JpegI422ToI420(void* opaque, 1.56 + const uint8* const* data, 1.57 + const int* strides, 1.58 + int rows) { 1.59 + I420Buffers* dest = (I420Buffers*)(opaque); 1.60 + I422ToI420(data[0], strides[0], 1.61 + data[1], strides[1], 1.62 + data[2], strides[2], 1.63 + dest->y, dest->y_stride, 1.64 + dest->u, dest->u_stride, 1.65 + dest->v, dest->v_stride, 1.66 + dest->w, rows); 1.67 + dest->y += rows * dest->y_stride; 1.68 + dest->u += ((rows + 1) >> 1) * dest->u_stride; 1.69 + dest->v += ((rows + 1) >> 1) * dest->v_stride; 1.70 + dest->h -= rows; 1.71 +} 1.72 + 1.73 +static void JpegI444ToI420(void* opaque, 1.74 + const uint8* const* data, 1.75 + const int* strides, 1.76 + int rows) { 1.77 + I420Buffers* dest = (I420Buffers*)(opaque); 1.78 + I444ToI420(data[0], strides[0], 1.79 + data[1], strides[1], 1.80 + data[2], strides[2], 1.81 + dest->y, dest->y_stride, 1.82 + dest->u, dest->u_stride, 1.83 + dest->v, dest->v_stride, 1.84 + dest->w, rows); 1.85 + dest->y += rows * dest->y_stride; 1.86 + dest->u += ((rows + 1) >> 1) * dest->u_stride; 1.87 + dest->v += ((rows + 1) >> 1) * dest->v_stride; 1.88 + dest->h -= rows; 1.89 +} 1.90 + 1.91 +static void JpegI411ToI420(void* opaque, 1.92 + const uint8* const* data, 1.93 + const int* strides, 1.94 + int rows) { 1.95 + I420Buffers* dest = (I420Buffers*)(opaque); 1.96 + I411ToI420(data[0], strides[0], 1.97 + data[1], strides[1], 1.98 + data[2], strides[2], 1.99 + dest->y, dest->y_stride, 1.100 + dest->u, dest->u_stride, 1.101 + dest->v, dest->v_stride, 1.102 + dest->w, rows); 1.103 + dest->y += rows * dest->y_stride; 1.104 + dest->u += ((rows + 1) >> 1) * dest->u_stride; 1.105 + dest->v += ((rows + 1) >> 1) * dest->v_stride; 1.106 + dest->h -= rows; 1.107 +} 1.108 + 1.109 +static void JpegI400ToI420(void* opaque, 1.110 + const uint8* const* data, 1.111 + const int* strides, 1.112 + int rows) { 1.113 + I420Buffers* dest = (I420Buffers*)(opaque); 1.114 + I400ToI420(data[0], strides[0], 1.115 + dest->y, dest->y_stride, 1.116 + dest->u, dest->u_stride, 1.117 + dest->v, dest->v_stride, 1.118 + dest->w, rows); 1.119 + dest->y += rows * dest->y_stride; 1.120 + dest->u += ((rows + 1) >> 1) * dest->u_stride; 1.121 + dest->v += ((rows + 1) >> 1) * dest->v_stride; 1.122 + dest->h -= rows; 1.123 +} 1.124 + 1.125 +// Query size of MJPG in pixels. 1.126 +LIBYUV_API 1.127 +int MJPGSize(const uint8* sample, size_t sample_size, 1.128 + int* width, int* height) { 1.129 + MJpegDecoder mjpeg_decoder; 1.130 + LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size); 1.131 + if (ret) { 1.132 + *width = mjpeg_decoder.GetWidth(); 1.133 + *height = mjpeg_decoder.GetHeight(); 1.134 + } 1.135 + mjpeg_decoder.UnloadFrame(); 1.136 + return ret ? 0 : -1; // -1 for runtime failure. 1.137 +} 1.138 + 1.139 +// MJPG (Motion JPeg) to I420 1.140 +// TODO(fbarchard): review w and h requirement. dw and dh may be enough. 1.141 +LIBYUV_API 1.142 +int MJPGToI420(const uint8* sample, 1.143 + size_t sample_size, 1.144 + uint8* y, int y_stride, 1.145 + uint8* u, int u_stride, 1.146 + uint8* v, int v_stride, 1.147 + int w, int h, 1.148 + int dw, int dh) { 1.149 + if (sample_size == kUnknownDataSize) { 1.150 + // ERROR: MJPEG frame size unknown 1.151 + return -1; 1.152 + } 1.153 + 1.154 + // TODO(fbarchard): Port MJpeg to C. 1.155 + MJpegDecoder mjpeg_decoder; 1.156 + LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size); 1.157 + if (ret && (mjpeg_decoder.GetWidth() != w || 1.158 + mjpeg_decoder.GetHeight() != h)) { 1.159 + // ERROR: MJPEG frame has unexpected dimensions 1.160 + mjpeg_decoder.UnloadFrame(); 1.161 + return 1; // runtime failure 1.162 + } 1.163 + if (ret) { 1.164 + I420Buffers bufs = { y, y_stride, u, u_stride, v, v_stride, dw, dh }; 1.165 + // YUV420 1.166 + if (mjpeg_decoder.GetColorSpace() == 1.167 + MJpegDecoder::kColorSpaceYCbCr && 1.168 + mjpeg_decoder.GetNumComponents() == 3 && 1.169 + mjpeg_decoder.GetVertSampFactor(0) == 2 && 1.170 + mjpeg_decoder.GetHorizSampFactor(0) == 2 && 1.171 + mjpeg_decoder.GetVertSampFactor(1) == 1 && 1.172 + mjpeg_decoder.GetHorizSampFactor(1) == 1 && 1.173 + mjpeg_decoder.GetVertSampFactor(2) == 1 && 1.174 + mjpeg_decoder.GetHorizSampFactor(2) == 1) { 1.175 + ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dw, dh); 1.176 + // YUV422 1.177 + } else if (mjpeg_decoder.GetColorSpace() == 1.178 + MJpegDecoder::kColorSpaceYCbCr && 1.179 + mjpeg_decoder.GetNumComponents() == 3 && 1.180 + mjpeg_decoder.GetVertSampFactor(0) == 1 && 1.181 + mjpeg_decoder.GetHorizSampFactor(0) == 2 && 1.182 + mjpeg_decoder.GetVertSampFactor(1) == 1 && 1.183 + mjpeg_decoder.GetHorizSampFactor(1) == 1 && 1.184 + mjpeg_decoder.GetVertSampFactor(2) == 1 && 1.185 + mjpeg_decoder.GetHorizSampFactor(2) == 1) { 1.186 + ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh); 1.187 + // YUV444 1.188 + } else if (mjpeg_decoder.GetColorSpace() == 1.189 + MJpegDecoder::kColorSpaceYCbCr && 1.190 + mjpeg_decoder.GetNumComponents() == 3 && 1.191 + mjpeg_decoder.GetVertSampFactor(0) == 1 && 1.192 + mjpeg_decoder.GetHorizSampFactor(0) == 1 && 1.193 + mjpeg_decoder.GetVertSampFactor(1) == 1 && 1.194 + mjpeg_decoder.GetHorizSampFactor(1) == 1 && 1.195 + mjpeg_decoder.GetVertSampFactor(2) == 1 && 1.196 + mjpeg_decoder.GetHorizSampFactor(2) == 1) { 1.197 + ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh); 1.198 + // YUV411 1.199 + } else if (mjpeg_decoder.GetColorSpace() == 1.200 + MJpegDecoder::kColorSpaceYCbCr && 1.201 + mjpeg_decoder.GetNumComponents() == 3 && 1.202 + mjpeg_decoder.GetVertSampFactor(0) == 1 && 1.203 + mjpeg_decoder.GetHorizSampFactor(0) == 4 && 1.204 + mjpeg_decoder.GetVertSampFactor(1) == 1 && 1.205 + mjpeg_decoder.GetHorizSampFactor(1) == 1 && 1.206 + mjpeg_decoder.GetVertSampFactor(2) == 1 && 1.207 + mjpeg_decoder.GetHorizSampFactor(2) == 1) { 1.208 + ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToI420, &bufs, dw, dh); 1.209 + // YUV400 1.210 + } else if (mjpeg_decoder.GetColorSpace() == 1.211 + MJpegDecoder::kColorSpaceGrayscale && 1.212 + mjpeg_decoder.GetNumComponents() == 1 && 1.213 + mjpeg_decoder.GetVertSampFactor(0) == 1 && 1.214 + mjpeg_decoder.GetHorizSampFactor(0) == 1) { 1.215 + ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh); 1.216 + } else { 1.217 + // TODO(fbarchard): Implement conversion for any other colorspace/sample 1.218 + // factors that occur in practice. 411 is supported by libjpeg 1.219 + // ERROR: Unable to convert MJPEG frame because format is not supported 1.220 + mjpeg_decoder.UnloadFrame(); 1.221 + return 1; 1.222 + } 1.223 + } 1.224 + return 0; 1.225 +} 1.226 + 1.227 +#ifdef HAVE_JPEG 1.228 +struct ARGBBuffers { 1.229 + uint8* argb; 1.230 + int argb_stride; 1.231 + int w; 1.232 + int h; 1.233 +}; 1.234 + 1.235 +static void JpegI420ToARGB(void* opaque, 1.236 + const uint8* const* data, 1.237 + const int* strides, 1.238 + int rows) { 1.239 + ARGBBuffers* dest = (ARGBBuffers*)(opaque); 1.240 + I420ToARGB(data[0], strides[0], 1.241 + data[1], strides[1], 1.242 + data[2], strides[2], 1.243 + dest->argb, dest->argb_stride, 1.244 + dest->w, rows); 1.245 + dest->argb += rows * dest->argb_stride; 1.246 + dest->h -= rows; 1.247 +} 1.248 + 1.249 +static void JpegI422ToARGB(void* opaque, 1.250 + const uint8* const* data, 1.251 + const int* strides, 1.252 + int rows) { 1.253 + ARGBBuffers* dest = (ARGBBuffers*)(opaque); 1.254 + I422ToARGB(data[0], strides[0], 1.255 + data[1], strides[1], 1.256 + data[2], strides[2], 1.257 + dest->argb, dest->argb_stride, 1.258 + dest->w, rows); 1.259 + dest->argb += rows * dest->argb_stride; 1.260 + dest->h -= rows; 1.261 +} 1.262 + 1.263 +static void JpegI444ToARGB(void* opaque, 1.264 + const uint8* const* data, 1.265 + const int* strides, 1.266 + int rows) { 1.267 + ARGBBuffers* dest = (ARGBBuffers*)(opaque); 1.268 + I444ToARGB(data[0], strides[0], 1.269 + data[1], strides[1], 1.270 + data[2], strides[2], 1.271 + dest->argb, dest->argb_stride, 1.272 + dest->w, rows); 1.273 + dest->argb += rows * dest->argb_stride; 1.274 + dest->h -= rows; 1.275 +} 1.276 + 1.277 +static void JpegI411ToARGB(void* opaque, 1.278 + const uint8* const* data, 1.279 + const int* strides, 1.280 + int rows) { 1.281 + ARGBBuffers* dest = (ARGBBuffers*)(opaque); 1.282 + I411ToARGB(data[0], strides[0], 1.283 + data[1], strides[1], 1.284 + data[2], strides[2], 1.285 + dest->argb, dest->argb_stride, 1.286 + dest->w, rows); 1.287 + dest->argb += rows * dest->argb_stride; 1.288 + dest->h -= rows; 1.289 +} 1.290 + 1.291 +static void JpegI400ToARGB(void* opaque, 1.292 + const uint8* const* data, 1.293 + const int* strides, 1.294 + int rows) { 1.295 + ARGBBuffers* dest = (ARGBBuffers*)(opaque); 1.296 + I400ToARGB(data[0], strides[0], 1.297 + dest->argb, dest->argb_stride, 1.298 + dest->w, rows); 1.299 + dest->argb += rows * dest->argb_stride; 1.300 + dest->h -= rows; 1.301 +} 1.302 + 1.303 +// MJPG (Motion JPeg) to ARGB 1.304 +// TODO(fbarchard): review w and h requirement. dw and dh may be enough. 1.305 +LIBYUV_API 1.306 +int MJPGToARGB(const uint8* sample, 1.307 + size_t sample_size, 1.308 + uint8* argb, int argb_stride, 1.309 + int w, int h, 1.310 + int dw, int dh) { 1.311 + if (sample_size == kUnknownDataSize) { 1.312 + // ERROR: MJPEG frame size unknown 1.313 + return -1; 1.314 + } 1.315 + 1.316 + // TODO(fbarchard): Port MJpeg to C. 1.317 + MJpegDecoder mjpeg_decoder; 1.318 + LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size); 1.319 + if (ret && (mjpeg_decoder.GetWidth() != w || 1.320 + mjpeg_decoder.GetHeight() != h)) { 1.321 + // ERROR: MJPEG frame has unexpected dimensions 1.322 + mjpeg_decoder.UnloadFrame(); 1.323 + return 1; // runtime failure 1.324 + } 1.325 + if (ret) { 1.326 + ARGBBuffers bufs = { argb, argb_stride, dw, dh }; 1.327 + // YUV420 1.328 + if (mjpeg_decoder.GetColorSpace() == 1.329 + MJpegDecoder::kColorSpaceYCbCr && 1.330 + mjpeg_decoder.GetNumComponents() == 3 && 1.331 + mjpeg_decoder.GetVertSampFactor(0) == 2 && 1.332 + mjpeg_decoder.GetHorizSampFactor(0) == 2 && 1.333 + mjpeg_decoder.GetVertSampFactor(1) == 1 && 1.334 + mjpeg_decoder.GetHorizSampFactor(1) == 1 && 1.335 + mjpeg_decoder.GetVertSampFactor(2) == 1 && 1.336 + mjpeg_decoder.GetHorizSampFactor(2) == 1) { 1.337 + ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh); 1.338 + // YUV422 1.339 + } else if (mjpeg_decoder.GetColorSpace() == 1.340 + MJpegDecoder::kColorSpaceYCbCr && 1.341 + mjpeg_decoder.GetNumComponents() == 3 && 1.342 + mjpeg_decoder.GetVertSampFactor(0) == 1 && 1.343 + mjpeg_decoder.GetHorizSampFactor(0) == 2 && 1.344 + mjpeg_decoder.GetVertSampFactor(1) == 1 && 1.345 + mjpeg_decoder.GetHorizSampFactor(1) == 1 && 1.346 + mjpeg_decoder.GetVertSampFactor(2) == 1 && 1.347 + mjpeg_decoder.GetHorizSampFactor(2) == 1) { 1.348 + ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh); 1.349 + // YUV444 1.350 + } else if (mjpeg_decoder.GetColorSpace() == 1.351 + MJpegDecoder::kColorSpaceYCbCr && 1.352 + mjpeg_decoder.GetNumComponents() == 3 && 1.353 + mjpeg_decoder.GetVertSampFactor(0) == 1 && 1.354 + mjpeg_decoder.GetHorizSampFactor(0) == 1 && 1.355 + mjpeg_decoder.GetVertSampFactor(1) == 1 && 1.356 + mjpeg_decoder.GetHorizSampFactor(1) == 1 && 1.357 + mjpeg_decoder.GetVertSampFactor(2) == 1 && 1.358 + mjpeg_decoder.GetHorizSampFactor(2) == 1) { 1.359 + ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh); 1.360 + // YUV411 1.361 + } else if (mjpeg_decoder.GetColorSpace() == 1.362 + MJpegDecoder::kColorSpaceYCbCr && 1.363 + mjpeg_decoder.GetNumComponents() == 3 && 1.364 + mjpeg_decoder.GetVertSampFactor(0) == 1 && 1.365 + mjpeg_decoder.GetHorizSampFactor(0) == 4 && 1.366 + mjpeg_decoder.GetVertSampFactor(1) == 1 && 1.367 + mjpeg_decoder.GetHorizSampFactor(1) == 1 && 1.368 + mjpeg_decoder.GetVertSampFactor(2) == 1 && 1.369 + mjpeg_decoder.GetHorizSampFactor(2) == 1) { 1.370 + ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToARGB, &bufs, dw, dh); 1.371 + // YUV400 1.372 + } else if (mjpeg_decoder.GetColorSpace() == 1.373 + MJpegDecoder::kColorSpaceGrayscale && 1.374 + mjpeg_decoder.GetNumComponents() == 1 && 1.375 + mjpeg_decoder.GetVertSampFactor(0) == 1 && 1.376 + mjpeg_decoder.GetHorizSampFactor(0) == 1) { 1.377 + ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh); 1.378 + } else { 1.379 + // TODO(fbarchard): Implement conversion for any other colorspace/sample 1.380 + // factors that occur in practice. 411 is supported by libjpeg 1.381 + // ERROR: Unable to convert MJPEG frame because format is not supported 1.382 + mjpeg_decoder.UnloadFrame(); 1.383 + return 1; 1.384 + } 1.385 + } 1.386 + return 0; 1.387 +} 1.388 +#endif 1.389 + 1.390 +#endif 1.391 + 1.392 +#ifdef __cplusplus 1.393 +} // extern "C" 1.394 +} // namespace libyuv 1.395 +#endif