From 8c8cf8d70718f9ac0647a2d0fcbd2b19f5b366e1 Mon Sep 17 00:00:00 2001 From: "fbarchard@google.com" Date: Thu, 11 Apr 2013 16:34:24 +0000 Subject: [PATCH] Move convert_to_argb and MJPGToARGB to isolated files. Move ValidateJPeg to its own file. Allows jpeg to be not linked in for more applications. BUG=212 TESTED=manual test by removing mjpeg_decode.cc from gyp file and built/ran unittests Review URL: https://webrtc-codereview.appspot.com/1310007 git-svn-id: http://libyuv.googlecode.com/svn/trunk@656 16f28f9a-4ce2-e073-06de-1de4eb20be90 --- README.chromium | 2 +- include/libyuv/version.h | 2 +- libyuv.gyp | 2 + source/convert_argb.cc | 457 -------------------------------------- source/convert_jpeg.cc | 164 ++++++++++++++ source/convert_to_argb.cc | 324 +++++++++++++++++++++++++++ source/mjpeg_validate.cc | 41 ++++ 7 files changed, 533 insertions(+), 459 deletions(-) create mode 100644 source/convert_to_argb.cc create mode 100644 source/mjpeg_validate.cc diff --git a/README.chromium b/README.chromium index 46639ce25..ecca83d1d 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 655 +Version: 656 License: BSD License File: LICENSE diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 525e7d831..f5163d5ed 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -11,6 +11,6 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 655 +#define LIBYUV_VERSION 656 #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT diff --git a/libyuv.gyp b/libyuv.gyp index a8d442d6d..92acd78d5 100644 --- a/libyuv.gyp +++ b/libyuv.gyp @@ -86,10 +86,12 @@ 'source/convert_from.cc', 'source/convert_from_argb.cc', 'source/convert_jpeg.cc', + 'source/convert_to_argb.cc', 'source/convert_to_i420.cc', 'source/cpu_id.cc', 'source/format_conversion.cc', 'source/mjpeg_decoder.cc', + 'source/mjpeg_validate.cc', 'source/planar_functions.cc', 'source/rotate.cc', 'source/rotate_argb.cc', diff --git a/source/convert_argb.cc b/source/convert_argb.cc index 78b508a53..8cb62fcc3 100644 --- a/source/convert_argb.cc +++ b/source/convert_argb.cc @@ -893,463 +893,6 @@ int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, return 0; } -#ifdef HAVE_JPEG -struct ARGBBuffers { - uint8* argb; - int argb_stride; - int w; - int h; -}; - -static void JpegI420ToARGB(void* opaque, - const uint8* const* data, - const int* strides, - int rows) { - ARGBBuffers* dest = static_cast(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* const* data, - const int* strides, - int rows) { - ARGBBuffers* dest = static_cast(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* const* data, - const int* strides, - int rows) { - ARGBBuffers* dest = static_cast(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 JpegI411ToARGB(void* opaque, - const uint8* const* data, - const int* strides, - int rows) { - ARGBBuffers* dest = static_cast(opaque); - I411ToARGB(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* const* data, - const int* strides, - int rows) { - ARGBBuffers* dest = static_cast(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 w and h requirement. dw and dh may be enough. -LIBYUV_API -int MJPGToARGB(const uint8* sample, - size_t sample_size, - uint8* argb, int argb_stride, - int w, int h, - int dw, int dh) { - if (sample_size == kUnknownDataSize) { - // ERROR: MJPEG frame size unknown - return -1; - } - - // TODO(fbarchard): Port MJpeg to C. - MJpegDecoder mjpeg_decoder; - bool ret = mjpeg_decoder.LoadFrame(sample, sample_size); - if (ret && (mjpeg_decoder.GetWidth() != w || - mjpeg_decoder.GetHeight() != h)) { - // ERROR: MJPEG frame has unexpected dimensions - mjpeg_decoder.UnloadFrame(); - return 1; // runtime failure - } - if (ret) { - ARGBBuffers bufs = { argb, argb_stride, dw, dh }; - // 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, dw, dh); - // 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, dw, dh); - // 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, dw, dh); - // YUV411 - } else if (mjpeg_decoder.GetColorSpace() == - MJpegDecoder::kColorSpaceYCbCr && - mjpeg_decoder.GetNumComponents() == 3 && - mjpeg_decoder.GetVertSampFactor(0) == 1 && - mjpeg_decoder.GetHorizSampFactor(0) == 4 && - mjpeg_decoder.GetVertSampFactor(1) == 1 && - mjpeg_decoder.GetHorizSampFactor(1) == 1 && - mjpeg_decoder.GetVertSampFactor(2) == 1 && - mjpeg_decoder.GetHorizSampFactor(2) == 1) { - ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToARGB, &bufs, dw, dh); - // 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, dw, dh); - } else { - // TODO(fbarchard): Implement conversion for any other colorspace/sample - // factors that occur in practice. 411 is supported by libjpeg - // ERROR: Unable to convert MJPEG frame because format is not supported - mjpeg_decoder.UnloadFrame(); - return 1; - } - } - return 0; -} -#endif - -// Convert camera sample to I420 with cropping, rotation and vertical flip. -// src_width is used for source stride computation -// src_height is used to compute location of planes, and indicate inversion -// sample_size is measured in bytes and is the size of the frame. -// With MJPEG it is the compressed size of the frame. -LIBYUV_API -int ConvertToARGB(const uint8* sample, size_t sample_size, - uint8* dst_argb, int argb_stride, - int crop_x, int crop_y, - int src_width, int src_height, - int dst_width, int dst_height, - RotationMode rotation, - uint32 fourcc) { - uint32 format = CanonicalFourCC(fourcc); - if (dst_argb == NULL || sample == NULL || - src_width <= 0 || dst_width <= 0 || - src_height == 0 || dst_height == 0) { - return -1; - } - int aligned_src_width = (src_width + 1) & ~1; - const uint8* src; - const uint8* src_uv; - int abs_src_height = (src_height < 0) ? -src_height : src_height; - int inv_dst_height = (dst_height < 0) ? -dst_height : dst_height; - if (src_height < 0) { - inv_dst_height = -inv_dst_height; - } - int r = 0; - - // One pass rotation is available for some formats. For the rest, convert - // to I420 (with optional vertical flipping) into a temporary I420 buffer, - // and then rotate the I420 to the final destination buffer. - // For in-place conversion, if destination dst_argb is same as source sample, - // also enable temporary buffer. - bool need_buf = (rotation && format != FOURCC_ARGB) || dst_argb == sample; - uint8* tmp_argb = dst_argb; - int tmp_argb_stride = argb_stride; - uint8* buf = NULL; - int abs_dst_height = (dst_height < 0) ? -dst_height : dst_height; - if (need_buf) { - int argb_size = dst_width * abs_dst_height * 4; - buf = new uint8[argb_size]; - if (!buf) { - return 1; // Out of memory runtime error. - } - dst_argb = buf; - argb_stride = dst_width; - } - - switch (format) { - // Single plane formats - case FOURCC_YUY2: - src = sample + (aligned_src_width * crop_y + crop_x) * 2; - r = YUY2ToARGB(src, aligned_src_width * 2, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_UYVY: - src = sample + (aligned_src_width * crop_y + crop_x) * 2; - r = UYVYToARGB(src, aligned_src_width * 2, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_24BG: - src = sample + (src_width * crop_y + crop_x) * 3; - r = RGB24ToARGB(src, src_width * 3, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_RAW: - src = sample + (src_width * crop_y + crop_x) * 3; - r = RAWToARGB(src, src_width * 3, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_ARGB: - src = sample + (src_width * crop_y + crop_x) * 4; - r = ARGBToARGB(src, src_width * 4, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_BGRA: - src = sample + (src_width * crop_y + crop_x) * 4; - r = BGRAToARGB(src, src_width * 4, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_ABGR: - src = sample + (src_width * crop_y + crop_x) * 4; - r = ABGRToARGB(src, src_width * 4, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_RGBA: - src = sample + (src_width * crop_y + crop_x) * 4; - r = RGBAToARGB(src, src_width * 4, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_RGBP: - src = sample + (src_width * crop_y + crop_x) * 2; - r = RGB565ToARGB(src, src_width * 2, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_RGBO: - src = sample + (src_width * crop_y + crop_x) * 2; - r = ARGB1555ToARGB(src, src_width * 2, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_R444: - src = sample + (src_width * crop_y + crop_x) * 2; - r = ARGB4444ToARGB(src, src_width * 2, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - // TODO(fbarchard): Support cropping Bayer by odd numbers - // by adjusting fourcc. - case FOURCC_BGGR: - src = sample + (src_width * crop_y + crop_x); - r = BayerBGGRToARGB(src, src_width, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - - case FOURCC_GBRG: - src = sample + (src_width * crop_y + crop_x); - r = BayerGBRGToARGB(src, src_width, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - - case FOURCC_GRBG: - src = sample + (src_width * crop_y + crop_x); - r = BayerGRBGToARGB(src, src_width, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - - case FOURCC_RGGB: - src = sample + (src_width * crop_y + crop_x); - r = BayerRGGBToARGB(src, src_width, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - - case FOURCC_I400: - src = sample + src_width * crop_y + crop_x; - r = I400ToARGB(src, src_width, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - - // Biplanar formats - case FOURCC_NV12: - src = sample + (src_width * crop_y + crop_x); - src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; - r = NV12ToARGB(src, src_width, - src_uv, aligned_src_width, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_NV21: - src = sample + (src_width * crop_y + crop_x); - src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; - // Call NV12 but with u and v parameters swapped. - r = NV21ToARGB(src, src_width, - src_uv, aligned_src_width, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - case FOURCC_M420: - src = sample + (src_width * crop_y) * 12 / 8 + crop_x; - r = M420ToARGB(src, src_width, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; -// case FOURCC_Q420: -// src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x; -// src_uv = sample + (src_width + aligned_src_width * 2) * crop_y + -// src_width + crop_x * 2; -// r = Q420ToARGB(src, src_width * 3, -// src_uv, src_width * 3, -// dst_argb, argb_stride, -// dst_width, inv_dst_height); -// break; - // Triplanar formats - case FOURCC_I420: - case FOURCC_YU12: - case FOURCC_YV12: { - const uint8* src_y = sample + (src_width * crop_y + crop_x); - const uint8* src_u; - const uint8* src_v; - int halfwidth = (src_width + 1) / 2; - int halfheight = (abs_src_height + 1) / 2; - if (format == FOURCC_YV12) { - src_v = sample + src_width * abs_src_height + - (halfwidth * crop_y + crop_x) / 2; - src_u = sample + src_width * abs_src_height + - halfwidth * (halfheight + crop_y / 2) + crop_x / 2; - } else { - src_u = sample + src_width * abs_src_height + - (halfwidth * crop_y + crop_x) / 2; - src_v = sample + src_width * abs_src_height + - halfwidth * (halfheight + crop_y / 2) + crop_x / 2; - } - r = I420ToARGB(src_y, src_width, - src_u, halfwidth, - src_v, halfwidth, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - } - case FOURCC_I422: - case FOURCC_YV16: { - const uint8* src_y = sample + src_width * crop_y + crop_x; - const uint8* src_u; - const uint8* src_v; - int halfwidth = (src_width + 1) / 2; - if (format == FOURCC_YV16) { - src_v = sample + src_width * abs_src_height + - halfwidth * crop_y + crop_x / 2; - src_u = sample + src_width * abs_src_height + - halfwidth * (abs_src_height + crop_y) + crop_x / 2; - } else { - src_u = sample + src_width * abs_src_height + - halfwidth * crop_y + crop_x / 2; - src_v = sample + src_width * abs_src_height + - halfwidth * (abs_src_height + crop_y) + crop_x / 2; - } - r = I422ToARGB(src_y, src_width, - src_u, halfwidth, - src_v, halfwidth, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - } - case FOURCC_I444: - case FOURCC_YV24: { - const uint8* src_y = sample + src_width * crop_y + crop_x; - const uint8* src_u; - const uint8* src_v; - if (format == FOURCC_YV24) { - src_v = sample + src_width * (abs_src_height + crop_y) + crop_x; - src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; - } else { - src_u = sample + src_width * (abs_src_height + crop_y) + crop_x; - src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; - } - r = I444ToARGB(src_y, src_width, - src_u, src_width, - src_v, src_width, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - } - case FOURCC_I411: { - int quarterwidth = (src_width + 3) / 4; - const uint8* src_y = sample + src_width * crop_y + crop_x; - const uint8* src_u = sample + src_width * abs_src_height + - quarterwidth * crop_y + crop_x / 4; - const uint8* src_v = sample + src_width * abs_src_height + - quarterwidth * (abs_src_height + crop_y) + crop_x / 4; - r = I411ToARGB(src_y, src_width, - src_u, quarterwidth, - src_v, quarterwidth, - dst_argb, argb_stride, - dst_width, inv_dst_height); - break; - } -#ifdef HAVE_JPEG - case FOURCC_MJPG: - r = MJPGToARGB(sample, sample_size, - dst_argb, argb_stride, - src_width, abs_src_height, dst_width, inv_dst_height); - break; -#endif - default: - r = -1; // unknown fourcc - return failure code. - } - - if (need_buf) { - if (!r) { - r = ARGBRotate(dst_argb, argb_stride, - tmp_argb, tmp_argb_stride, - dst_width, abs_dst_height, rotation); - } - delete buf; - } - - return r; -} - #ifdef __cplusplus } // extern "C" } // namespace libyuv diff --git a/source/convert_jpeg.cc b/source/convert_jpeg.cc index 607035de7..3d1ef98cc 100644 --- a/source/convert_jpeg.cc +++ b/source/convert_jpeg.cc @@ -220,6 +220,170 @@ int MJPGToI420(const uint8* sample, } return 0; } + +#ifdef HAVE_JPEG +struct ARGBBuffers { + uint8* argb; + int argb_stride; + int w; + int h; +}; + +static void JpegI420ToARGB(void* opaque, + const uint8* const* data, + const int* strides, + int rows) { + ARGBBuffers* dest = static_cast(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* const* data, + const int* strides, + int rows) { + ARGBBuffers* dest = static_cast(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* const* data, + const int* strides, + int rows) { + ARGBBuffers* dest = static_cast(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 JpegI411ToARGB(void* opaque, + const uint8* const* data, + const int* strides, + int rows) { + ARGBBuffers* dest = static_cast(opaque); + I411ToARGB(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* const* data, + const int* strides, + int rows) { + ARGBBuffers* dest = static_cast(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 w and h requirement. dw and dh may be enough. +LIBYUV_API +int MJPGToARGB(const uint8* sample, + size_t sample_size, + uint8* argb, int argb_stride, + int w, int h, + int dw, int dh) { + if (sample_size == kUnknownDataSize) { + // ERROR: MJPEG frame size unknown + return -1; + } + + // TODO(fbarchard): Port MJpeg to C. + MJpegDecoder mjpeg_decoder; + bool ret = mjpeg_decoder.LoadFrame(sample, sample_size); + if (ret && (mjpeg_decoder.GetWidth() != w || + mjpeg_decoder.GetHeight() != h)) { + // ERROR: MJPEG frame has unexpected dimensions + mjpeg_decoder.UnloadFrame(); + return 1; // runtime failure + } + if (ret) { + ARGBBuffers bufs = { argb, argb_stride, dw, dh }; + // 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, dw, dh); + // 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, dw, dh); + // 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, dw, dh); + // YUV411 + } else if (mjpeg_decoder.GetColorSpace() == + MJpegDecoder::kColorSpaceYCbCr && + mjpeg_decoder.GetNumComponents() == 3 && + mjpeg_decoder.GetVertSampFactor(0) == 1 && + mjpeg_decoder.GetHorizSampFactor(0) == 4 && + mjpeg_decoder.GetVertSampFactor(1) == 1 && + mjpeg_decoder.GetHorizSampFactor(1) == 1 && + mjpeg_decoder.GetVertSampFactor(2) == 1 && + mjpeg_decoder.GetHorizSampFactor(2) == 1) { + ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToARGB, &bufs, dw, dh); + // 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, dw, dh); + } else { + // TODO(fbarchard): Implement conversion for any other colorspace/sample + // factors that occur in practice. 411 is supported by libjpeg + // ERROR: Unable to convert MJPEG frame because format is not supported + mjpeg_decoder.UnloadFrame(); + return 1; + } + } + return 0; +} +#endif + #endif #ifdef __cplusplus diff --git a/source/convert_to_argb.cc b/source/convert_to_argb.cc new file mode 100644 index 000000000..95b6386d7 --- /dev/null +++ b/source/convert_to_argb.cc @@ -0,0 +1,324 @@ +/* + * 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_argb.h" + +#include "libyuv/cpu_id.h" +#include "libyuv/format_conversion.h" +#ifdef HAVE_JPEG +#include "libyuv/mjpeg_decoder.h" +#endif +#include "libyuv/rotate_argb.h" +#include "libyuv/row.h" +#include "libyuv/video_common.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Convert camera sample to I420 with cropping, rotation and vertical flip. +// src_width is used for source stride computation +// src_height is used to compute location of planes, and indicate inversion +// sample_size is measured in bytes and is the size of the frame. +// With MJPEG it is the compressed size of the frame. +LIBYUV_API +int ConvertToARGB(const uint8* sample, size_t sample_size, + uint8* dst_argb, int argb_stride, + int crop_x, int crop_y, + int src_width, int src_height, + int dst_width, int dst_height, + RotationMode rotation, + uint32 fourcc) { + uint32 format = CanonicalFourCC(fourcc); + if (dst_argb == NULL || sample == NULL || + src_width <= 0 || dst_width <= 0 || + src_height == 0 || dst_height == 0) { + return -1; + } + int aligned_src_width = (src_width + 1) & ~1; + const uint8* src; + const uint8* src_uv; + int abs_src_height = (src_height < 0) ? -src_height : src_height; + int inv_dst_height = (dst_height < 0) ? -dst_height : dst_height; + if (src_height < 0) { + inv_dst_height = -inv_dst_height; + } + int r = 0; + + // One pass rotation is available for some formats. For the rest, convert + // to I420 (with optional vertical flipping) into a temporary I420 buffer, + // and then rotate the I420 to the final destination buffer. + // For in-place conversion, if destination dst_argb is same as source sample, + // also enable temporary buffer. + bool need_buf = (rotation && format != FOURCC_ARGB) || dst_argb == sample; + uint8* tmp_argb = dst_argb; + int tmp_argb_stride = argb_stride; + uint8* buf = NULL; + int abs_dst_height = (dst_height < 0) ? -dst_height : dst_height; + if (need_buf) { + int argb_size = dst_width * abs_dst_height * 4; + buf = new uint8[argb_size]; + if (!buf) { + return 1; // Out of memory runtime error. + } + dst_argb = buf; + argb_stride = dst_width; + } + + switch (format) { + // Single plane formats + case FOURCC_YUY2: + src = sample + (aligned_src_width * crop_y + crop_x) * 2; + r = YUY2ToARGB(src, aligned_src_width * 2, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_UYVY: + src = sample + (aligned_src_width * crop_y + crop_x) * 2; + r = UYVYToARGB(src, aligned_src_width * 2, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_24BG: + src = sample + (src_width * crop_y + crop_x) * 3; + r = RGB24ToARGB(src, src_width * 3, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_RAW: + src = sample + (src_width * crop_y + crop_x) * 3; + r = RAWToARGB(src, src_width * 3, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_ARGB: + src = sample + (src_width * crop_y + crop_x) * 4; + r = ARGBToARGB(src, src_width * 4, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_BGRA: + src = sample + (src_width * crop_y + crop_x) * 4; + r = BGRAToARGB(src, src_width * 4, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_ABGR: + src = sample + (src_width * crop_y + crop_x) * 4; + r = ABGRToARGB(src, src_width * 4, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_RGBA: + src = sample + (src_width * crop_y + crop_x) * 4; + r = RGBAToARGB(src, src_width * 4, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_RGBP: + src = sample + (src_width * crop_y + crop_x) * 2; + r = RGB565ToARGB(src, src_width * 2, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_RGBO: + src = sample + (src_width * crop_y + crop_x) * 2; + r = ARGB1555ToARGB(src, src_width * 2, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_R444: + src = sample + (src_width * crop_y + crop_x) * 2; + r = ARGB4444ToARGB(src, src_width * 2, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + // TODO(fbarchard): Support cropping Bayer by odd numbers + // by adjusting fourcc. + case FOURCC_BGGR: + src = sample + (src_width * crop_y + crop_x); + r = BayerBGGRToARGB(src, src_width, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + + case FOURCC_GBRG: + src = sample + (src_width * crop_y + crop_x); + r = BayerGBRGToARGB(src, src_width, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + + case FOURCC_GRBG: + src = sample + (src_width * crop_y + crop_x); + r = BayerGRBGToARGB(src, src_width, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + + case FOURCC_RGGB: + src = sample + (src_width * crop_y + crop_x); + r = BayerRGGBToARGB(src, src_width, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + + case FOURCC_I400: + src = sample + src_width * crop_y + crop_x; + r = I400ToARGB(src, src_width, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + + // Biplanar formats + case FOURCC_NV12: + src = sample + (src_width * crop_y + crop_x); + src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; + r = NV12ToARGB(src, src_width, + src_uv, aligned_src_width, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_NV21: + src = sample + (src_width * crop_y + crop_x); + src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; + // Call NV12 but with u and v parameters swapped. + r = NV21ToARGB(src, src_width, + src_uv, aligned_src_width, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + case FOURCC_M420: + src = sample + (src_width * crop_y) * 12 / 8 + crop_x; + r = M420ToARGB(src, src_width, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; +// case FOURCC_Q420: +// src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x; +// src_uv = sample + (src_width + aligned_src_width * 2) * crop_y + +// src_width + crop_x * 2; +// r = Q420ToARGB(src, src_width * 3, +// src_uv, src_width * 3, +// dst_argb, argb_stride, +// dst_width, inv_dst_height); +// break; + // Triplanar formats + case FOURCC_I420: + case FOURCC_YU12: + case FOURCC_YV12: { + const uint8* src_y = sample + (src_width * crop_y + crop_x); + const uint8* src_u; + const uint8* src_v; + int halfwidth = (src_width + 1) / 2; + int halfheight = (abs_src_height + 1) / 2; + if (format == FOURCC_YV12) { + src_v = sample + src_width * abs_src_height + + (halfwidth * crop_y + crop_x) / 2; + src_u = sample + src_width * abs_src_height + + halfwidth * (halfheight + crop_y / 2) + crop_x / 2; + } else { + src_u = sample + src_width * abs_src_height + + (halfwidth * crop_y + crop_x) / 2; + src_v = sample + src_width * abs_src_height + + halfwidth * (halfheight + crop_y / 2) + crop_x / 2; + } + r = I420ToARGB(src_y, src_width, + src_u, halfwidth, + src_v, halfwidth, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + } + case FOURCC_I422: + case FOURCC_YV16: { + const uint8* src_y = sample + src_width * crop_y + crop_x; + const uint8* src_u; + const uint8* src_v; + int halfwidth = (src_width + 1) / 2; + if (format == FOURCC_YV16) { + src_v = sample + src_width * abs_src_height + + halfwidth * crop_y + crop_x / 2; + src_u = sample + src_width * abs_src_height + + halfwidth * (abs_src_height + crop_y) + crop_x / 2; + } else { + src_u = sample + src_width * abs_src_height + + halfwidth * crop_y + crop_x / 2; + src_v = sample + src_width * abs_src_height + + halfwidth * (abs_src_height + crop_y) + crop_x / 2; + } + r = I422ToARGB(src_y, src_width, + src_u, halfwidth, + src_v, halfwidth, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + } + case FOURCC_I444: + case FOURCC_YV24: { + const uint8* src_y = sample + src_width * crop_y + crop_x; + const uint8* src_u; + const uint8* src_v; + if (format == FOURCC_YV24) { + src_v = sample + src_width * (abs_src_height + crop_y) + crop_x; + src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; + } else { + src_u = sample + src_width * (abs_src_height + crop_y) + crop_x; + src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; + } + r = I444ToARGB(src_y, src_width, + src_u, src_width, + src_v, src_width, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + } + case FOURCC_I411: { + int quarterwidth = (src_width + 3) / 4; + const uint8* src_y = sample + src_width * crop_y + crop_x; + const uint8* src_u = sample + src_width * abs_src_height + + quarterwidth * crop_y + crop_x / 4; + const uint8* src_v = sample + src_width * abs_src_height + + quarterwidth * (abs_src_height + crop_y) + crop_x / 4; + r = I411ToARGB(src_y, src_width, + src_u, quarterwidth, + src_v, quarterwidth, + dst_argb, argb_stride, + dst_width, inv_dst_height); + break; + } +#ifdef HAVE_JPEG + case FOURCC_MJPG: + r = MJPGToARGB(sample, sample_size, + dst_argb, argb_stride, + src_width, abs_src_height, dst_width, inv_dst_height); + break; +#endif + default: + r = -1; // unknown fourcc - return failure code. + } + + if (need_buf) { + if (!r) { + r = ARGBRotate(dst_argb, argb_stride, + tmp_argb, tmp_argb_stride, + dst_width, abs_dst_height, rotation); + } + delete buf; + } + + return r; +} + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif diff --git a/source/mjpeg_validate.cc b/source/mjpeg_validate.cc new file mode 100644 index 000000000..1d0aeebd1 --- /dev/null +++ b/source/mjpeg_validate.cc @@ -0,0 +1,41 @@ +/* + * Copyright 2012 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/mjpeg_decoder.h" + +namespace libyuv { + +// Helper function to validate the jpeg appears intact. +// TODO(fbarchard): Optimize case where SOI is found but EOI is not. +bool ValidateJpeg(const uint8* sample, size_t sample_size) { + if (sample_size < 64) { + // ERROR: Invalid jpeg size: sample_size + return false; + } + if (sample[0] != 0xff || sample[1] != 0xd8) { // Start Of Image + // ERROR: Invalid jpeg initial start code + return false; + } + for (int i = static_cast(sample_size) - 2; i > 1;) { + if (sample[i] != 0xd9) { + if (sample[i] == 0xff && sample[i + 1] == 0xd9) { // End Of Image + return true; + } + --i; + } + --i; + } + // ERROR: Invalid jpeg end code not found. Size sample_size + return false; +} + +} // namespace libyuv + +