332 lines · 12.3 KB · C++
RawDownload
/* *  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 __cplusplusnamespace libyuv {extern "C" {#endif #ifdef HAVE_JPEGstruct 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_APIint MJPGSize(const uint8_t* sample,             size_t sample_size,             int* width,             int* height) {  MJpegDecoder mjpeg_decoder;  LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);  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_APIint MJPGToI420(const uint8_t* sample,               size_t sample_size,               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 (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) {    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/sample      // 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;} #ifdef HAVE_JPEGstruct 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_APIint MJPGToARGB(const uint8_t* sample,               size_t sample_size,               uint8_t* dst_argb,               int dst_stride_argb,               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) {    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/sample      // 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 #endif #ifdef __cplusplus}  // extern "C"}  // namespace libyuv#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t