| /* |
| * Copyright 2011 The LibYuv Project Authors. All rights reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "libyuv/convert.h" |
| #include "libyuv/convert_argb.h" |
| |
| #ifdef HAVE_JPEG |
| #include "libyuv/mjpeg_decoder.h" |
| #endif |
| |
| #ifdef __cplusplus |
| namespace libyuv { |
| extern "C" { |
| #endif |
| |
| #ifdef HAVE_JPEG |
| struct I420Buffers { |
| uint8_t* y; |
| int y_stride; |
| uint8_t* u; |
| int u_stride; |
| uint8_t* v; |
| int v_stride; |
| int w; |
| int h; |
| }; |
| |
| static void JpegCopyI420(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| I420Buffers* dest = (I420Buffers*)(opaque); |
| I420Copy(data[0], strides[0], data[1], strides[1], data[2], strides[2], |
| dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v, |
| dest->v_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->u += ((rows + 1) >> 1) * dest->u_stride; |
| dest->v += ((rows + 1) >> 1) * dest->v_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI422ToI420(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| I420Buffers* dest = (I420Buffers*)(opaque); |
| I422ToI420(data[0], strides[0], data[1], strides[1], data[2], strides[2], |
| dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v, |
| dest->v_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->u += ((rows + 1) >> 1) * dest->u_stride; |
| dest->v += ((rows + 1) >> 1) * dest->v_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI444ToI420(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| I420Buffers* dest = (I420Buffers*)(opaque); |
| I444ToI420(data[0], strides[0], data[1], strides[1], data[2], strides[2], |
| dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v, |
| dest->v_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->u += ((rows + 1) >> 1) * dest->u_stride; |
| dest->v += ((rows + 1) >> 1) * dest->v_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI400ToI420(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| I420Buffers* dest = (I420Buffers*)(opaque); |
| I400ToI420(data[0], strides[0], dest->y, dest->y_stride, dest->u, |
| dest->u_stride, dest->v, dest->v_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->u += ((rows + 1) >> 1) * dest->u_stride; |
| dest->v += ((rows + 1) >> 1) * dest->v_stride; |
| dest->h -= rows; |
| } |
| |
| // Query size of MJPG in pixels. |
| LIBYUV_API |
| int MJPGSize(const uint8_t* src_mjpg, |
| size_t src_size_mjpg, |
| int* width, |
| int* height) { |
| MJpegDecoder mjpeg_decoder; |
| LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(src_mjpg, src_size_mjpg); |
| if (ret) { |
| *width = mjpeg_decoder.GetWidth(); |
| *height = mjpeg_decoder.GetHeight(); |
| } |
| mjpeg_decoder.UnloadFrame(); |
| return ret ? 0 : -1; // -1 for runtime failure. |
| } |
| |
| // MJPG (Motion JPeg) to I420 |
| // TODO(fbarchard): review src_width and src_height requirement. dst_width and |
| // dst_height may be enough. |
| LIBYUV_API |
| int MJPGToI420(const uint8_t* src_mjpg, |
| size_t src_size_mjpg, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| uint8_t* dst_u, |
| int dst_stride_u, |
| uint8_t* dst_v, |
| int dst_stride_v, |
| int src_width, |
| int src_height, |
| int dst_width, |
| int dst_height) { |
| if (src_size_mjpg == kUnknownDataSize) { |
| // ERROR: MJPEG frame size unknown |
| return -1; |
| } |
| |
| // TODO(fbarchard): Port MJpeg to C. |
| MJpegDecoder mjpeg_decoder; |
| LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(src_mjpg, src_size_mjpg); |
| if (ret && (mjpeg_decoder.GetWidth() != src_width || |
| mjpeg_decoder.GetHeight() != src_height)) { |
| // ERROR: MJPEG frame has unexpected dimensions |
| mjpeg_decoder.UnloadFrame(); |
| return 1; // runtime failure |
| } |
| if (ret) { |
| I420Buffers bufs = {dst_y, dst_stride_y, dst_u, dst_stride_u, |
| dst_v, dst_stride_v, dst_width, dst_height}; |
| // YUV420 |
| if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 2 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 2 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dst_width, |
| dst_height); |
| // YUV422 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 2 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dst_width, |
| dst_height); |
| // YUV444 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 1 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dst_width, |
| dst_height); |
| // YUV400 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceGrayscale && |
| mjpeg_decoder.GetNumComponents() == 1 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dst_width, |
| dst_height); |
| } else { |
| // TODO(fbarchard): Implement conversion for any other |
| // colorspace/subsample factors that occur in practice. ERROR: Unable to |
| // convert MJPEG frame because format is not supported |
| mjpeg_decoder.UnloadFrame(); |
| return 1; |
| } |
| } |
| return ret ? 0 : 1; |
| } |
| |
| struct NV21Buffers { |
| uint8_t* y; |
| int y_stride; |
| uint8_t* vu; |
| int vu_stride; |
| int w; |
| int h; |
| }; |
| |
| static void JpegI420ToNV21(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| NV21Buffers* dest = (NV21Buffers*)(opaque); |
| I420ToNV21(data[0], strides[0], data[1], strides[1], data[2], strides[2], |
| dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->vu += ((rows + 1) >> 1) * dest->vu_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI422ToNV21(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| NV21Buffers* dest = (NV21Buffers*)(opaque); |
| I422ToNV21(data[0], strides[0], data[1], strides[1], data[2], strides[2], |
| dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->vu += ((rows + 1) >> 1) * dest->vu_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI444ToNV21(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| NV21Buffers* dest = (NV21Buffers*)(opaque); |
| I444ToNV21(data[0], strides[0], data[1], strides[1], data[2], strides[2], |
| dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->vu += ((rows + 1) >> 1) * dest->vu_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI400ToNV21(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| NV21Buffers* dest = (NV21Buffers*)(opaque); |
| I400ToNV21(data[0], strides[0], dest->y, dest->y_stride, dest->vu, |
| dest->vu_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->vu += ((rows + 1) >> 1) * dest->vu_stride; |
| dest->h -= rows; |
| } |
| |
| // MJPG (Motion JPeg) to NV21 |
| LIBYUV_API |
| int MJPGToNV21(const uint8_t* src_mjpg, |
| size_t src_size_mjpg, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| uint8_t* dst_vu, |
| int dst_stride_vu, |
| int src_width, |
| int src_height, |
| int dst_width, |
| int dst_height) { |
| if (src_size_mjpg == kUnknownDataSize) { |
| // ERROR: MJPEG frame size unknown |
| return -1; |
| } |
| |
| // TODO(fbarchard): Port MJpeg to C. |
| MJpegDecoder mjpeg_decoder; |
| LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(src_mjpg, src_size_mjpg); |
| if (ret && (mjpeg_decoder.GetWidth() != src_width || |
| mjpeg_decoder.GetHeight() != src_height)) { |
| // ERROR: MJPEG frame has unexpected dimensions |
| mjpeg_decoder.UnloadFrame(); |
| return 1; // runtime failure |
| } |
| if (ret) { |
| NV21Buffers bufs = {dst_y, dst_stride_y, dst_vu, |
| dst_stride_vu, dst_width, dst_height}; |
| // YUV420 |
| if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 2 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 2 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToNV21, &bufs, dst_width, |
| dst_height); |
| // YUV422 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 2 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToNV21, &bufs, dst_width, |
| dst_height); |
| // YUV444 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 1 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToNV21, &bufs, dst_width, |
| dst_height); |
| // YUV400 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceGrayscale && |
| mjpeg_decoder.GetNumComponents() == 1 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToNV21, &bufs, dst_width, |
| dst_height); |
| } else { |
| // Unknown colorspace. |
| mjpeg_decoder.UnloadFrame(); |
| return 1; |
| } |
| } |
| return ret ? 0 : 1; |
| } |
| |
| static void JpegI420ToNV12(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| NV21Buffers* dest = (NV21Buffers*)(opaque); |
| // Use NV21 with VU swapped. |
| I420ToNV21(data[0], strides[0], data[2], strides[2], data[1], strides[1], |
| dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->vu += ((rows + 1) >> 1) * dest->vu_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI422ToNV12(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| NV21Buffers* dest = (NV21Buffers*)(opaque); |
| // Use NV21 with VU swapped. |
| I422ToNV21(data[0], strides[0], data[2], strides[2], data[1], strides[1], |
| dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->vu += ((rows + 1) >> 1) * dest->vu_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI444ToNV12(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| NV21Buffers* dest = (NV21Buffers*)(opaque); |
| // Use NV21 with VU swapped. |
| I444ToNV21(data[0], strides[0], data[2], strides[2], data[1], strides[1], |
| dest->y, dest->y_stride, dest->vu, dest->vu_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->vu += ((rows + 1) >> 1) * dest->vu_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI400ToNV12(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| NV21Buffers* dest = (NV21Buffers*)(opaque); |
| // Use NV21 since there is no UV plane. |
| I400ToNV21(data[0], strides[0], dest->y, dest->y_stride, dest->vu, |
| dest->vu_stride, dest->w, rows); |
| dest->y += rows * dest->y_stride; |
| dest->vu += ((rows + 1) >> 1) * dest->vu_stride; |
| dest->h -= rows; |
| } |
| |
| // MJPG (Motion JPEG) to NV12. |
| LIBYUV_API |
| int MJPGToNV12(const uint8_t* sample, |
| size_t sample_size, |
| uint8_t* dst_y, |
| int dst_stride_y, |
| uint8_t* dst_uv, |
| int dst_stride_uv, |
| int src_width, |
| int src_height, |
| int dst_width, |
| int dst_height) { |
| if (sample_size == kUnknownDataSize) { |
| // ERROR: MJPEG frame size unknown |
| return -1; |
| } |
| |
| // TODO(fbarchard): Port MJpeg to C. |
| MJpegDecoder mjpeg_decoder; |
| LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size); |
| if (ret && (mjpeg_decoder.GetWidth() != src_width || |
| mjpeg_decoder.GetHeight() != src_height)) { |
| // ERROR: MJPEG frame has unexpected dimensions |
| mjpeg_decoder.UnloadFrame(); |
| return 1; // runtime failure |
| } |
| if (ret) { |
| // Use NV21Buffers but with UV instead of VU. |
| NV21Buffers bufs = {dst_y, dst_stride_y, dst_uv, |
| dst_stride_uv, dst_width, dst_height}; |
| // YUV420 |
| if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 2 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 2 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToNV12, &bufs, dst_width, |
| dst_height); |
| // YUV422 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 2 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToNV12, &bufs, dst_width, |
| dst_height); |
| // YUV444 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 1 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToNV12, &bufs, dst_width, |
| dst_height); |
| // YUV400 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceGrayscale && |
| mjpeg_decoder.GetNumComponents() == 1 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToNV12, &bufs, dst_width, |
| dst_height); |
| } else { |
| // Unknown colorspace. |
| mjpeg_decoder.UnloadFrame(); |
| return 1; |
| } |
| } |
| return ret ? 0 : 1; |
| } |
| |
| struct ARGBBuffers { |
| uint8_t* argb; |
| int argb_stride; |
| int w; |
| int h; |
| }; |
| |
| static void JpegI420ToARGB(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| ARGBBuffers* dest = (ARGBBuffers*)(opaque); |
| I420ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2], |
| dest->argb, dest->argb_stride, dest->w, rows); |
| dest->argb += rows * dest->argb_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI422ToARGB(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| ARGBBuffers* dest = (ARGBBuffers*)(opaque); |
| I422ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2], |
| dest->argb, dest->argb_stride, dest->w, rows); |
| dest->argb += rows * dest->argb_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI444ToARGB(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| ARGBBuffers* dest = (ARGBBuffers*)(opaque); |
| I444ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2], |
| dest->argb, dest->argb_stride, dest->w, rows); |
| dest->argb += rows * dest->argb_stride; |
| dest->h -= rows; |
| } |
| |
| static void JpegI400ToARGB(void* opaque, |
| const uint8_t* const* data, |
| const int* strides, |
| int rows) { |
| ARGBBuffers* dest = (ARGBBuffers*)(opaque); |
| I400ToARGB(data[0], strides[0], dest->argb, dest->argb_stride, dest->w, rows); |
| dest->argb += rows * dest->argb_stride; |
| dest->h -= rows; |
| } |
| |
| // MJPG (Motion JPeg) to ARGB |
| // TODO(fbarchard): review src_width and src_height requirement. dst_width and |
| // dst_height may be enough. |
| LIBYUV_API |
| int MJPGToARGB(const uint8_t* src_mjpg, |
| size_t src_size_mjpg, |
| uint8_t* dst_argb, |
| int dst_stride_argb, |
| int src_width, |
| int src_height, |
| int dst_width, |
| int dst_height) { |
| if (src_size_mjpg == kUnknownDataSize) { |
| // ERROR: MJPEG frame size unknown |
| return -1; |
| } |
| |
| // TODO(fbarchard): Port MJpeg to C. |
| MJpegDecoder mjpeg_decoder; |
| LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(src_mjpg, src_size_mjpg); |
| if (ret && (mjpeg_decoder.GetWidth() != src_width || |
| mjpeg_decoder.GetHeight() != src_height)) { |
| // ERROR: MJPEG frame has unexpected dimensions |
| mjpeg_decoder.UnloadFrame(); |
| return 1; // runtime failure |
| } |
| if (ret) { |
| ARGBBuffers bufs = {dst_argb, dst_stride_argb, dst_width, dst_height}; |
| // YUV420 |
| if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 2 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 2 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dst_width, |
| dst_height); |
| // YUV422 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 2 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dst_width, |
| dst_height); |
| // YUV444 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceYCbCr && |
| mjpeg_decoder.GetNumComponents() == 3 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 1 && |
| mjpeg_decoder.GetVertSampFactor(1) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(1) == 1 && |
| mjpeg_decoder.GetVertSampFactor(2) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(2) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dst_width, |
| dst_height); |
| // YUV400 |
| } else if (mjpeg_decoder.GetColorSpace() == |
| MJpegDecoder::kColorSpaceGrayscale && |
| mjpeg_decoder.GetNumComponents() == 1 && |
| mjpeg_decoder.GetVertSampFactor(0) == 1 && |
| mjpeg_decoder.GetHorizSampFactor(0) == 1) { |
| ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dst_width, |
| dst_height); |
| } else { |
| // TODO(fbarchard): Implement conversion for any other |
| // colorspace/subsample factors that occur in practice. ERROR: Unable to |
| // convert MJPEG frame because format is not supported |
| mjpeg_decoder.UnloadFrame(); |
| return 1; |
| } |
| } |
| return ret ? 0 : 1; |
| } |
| |
| #endif // HAVE_JPEG |
| |
| #ifdef __cplusplus |
| } // extern "C" |
| } // namespace libyuv |
| #endif |