Home | History | Annotate | Download | only in source
      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], data[1], strides[1], data[2], strides[2],
     41            dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v,
     42            dest->v_stride, dest->w, rows);
     43   dest->y += rows * dest->y_stride;
     44   dest->u += ((rows + 1) >> 1) * dest->u_stride;
     45   dest->v += ((rows + 1) >> 1) * dest->v_stride;
     46   dest->h -= rows;
     47 }
     48 
     49 static void JpegI422ToI420(void* opaque,
     50                            const uint8* const* data,
     51                            const int* strides,
     52                            int rows) {
     53   I420Buffers* dest = (I420Buffers*)(opaque);
     54   I422ToI420(data[0], strides[0], data[1], strides[1], data[2], strides[2],
     55              dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v,
     56              dest->v_stride, dest->w, rows);
     57   dest->y += rows * dest->y_stride;
     58   dest->u += ((rows + 1) >> 1) * dest->u_stride;
     59   dest->v += ((rows + 1) >> 1) * dest->v_stride;
     60   dest->h -= rows;
     61 }
     62 
     63 static void JpegI444ToI420(void* opaque,
     64                            const uint8* const* data,
     65                            const int* strides,
     66                            int rows) {
     67   I420Buffers* dest = (I420Buffers*)(opaque);
     68   I444ToI420(data[0], strides[0], data[1], strides[1], data[2], strides[2],
     69              dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v,
     70              dest->v_stride, dest->w, rows);
     71   dest->y += rows * dest->y_stride;
     72   dest->u += ((rows + 1) >> 1) * dest->u_stride;
     73   dest->v += ((rows + 1) >> 1) * dest->v_stride;
     74   dest->h -= rows;
     75 }
     76 
     77 static void JpegI400ToI420(void* opaque,
     78                            const uint8* const* data,
     79                            const int* strides,
     80                            int rows) {
     81   I420Buffers* dest = (I420Buffers*)(opaque);
     82   I400ToI420(data[0], strides[0], dest->y, dest->y_stride, dest->u,
     83              dest->u_stride, dest->v, dest->v_stride, dest->w, rows);
     84   dest->y += rows * dest->y_stride;
     85   dest->u += ((rows + 1) >> 1) * dest->u_stride;
     86   dest->v += ((rows + 1) >> 1) * dest->v_stride;
     87   dest->h -= rows;
     88 }
     89 
     90 // Query size of MJPG in pixels.
     91 LIBYUV_API
     92 int MJPGSize(const uint8* sample, size_t sample_size, int* width, int* height) {
     93   MJpegDecoder mjpeg_decoder;
     94   LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
     95   if (ret) {
     96     *width = mjpeg_decoder.GetWidth();
     97     *height = mjpeg_decoder.GetHeight();
     98   }
     99   mjpeg_decoder.UnloadFrame();
    100   return ret ? 0 : -1;  // -1 for runtime failure.
    101 }
    102 
    103 // MJPG (Motion JPeg) to I420
    104 // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
    105 LIBYUV_API
    106 int MJPGToI420(const uint8* sample,
    107                size_t sample_size,
    108                uint8* y,
    109                int y_stride,
    110                uint8* u,
    111                int u_stride,
    112                uint8* v,
    113                int v_stride,
    114                int w,
    115                int h,
    116                int dw,
    117                int dh) {
    118   if (sample_size == kUnknownDataSize) {
    119     // ERROR: MJPEG frame size unknown
    120     return -1;
    121   }
    122 
    123   // TODO(fbarchard): Port MJpeg to C.
    124   MJpegDecoder mjpeg_decoder;
    125   LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
    126   if (ret &&
    127       (mjpeg_decoder.GetWidth() != w || mjpeg_decoder.GetHeight() != h)) {
    128     // ERROR: MJPEG frame has unexpected dimensions
    129     mjpeg_decoder.UnloadFrame();
    130     return 1;  // runtime failure
    131   }
    132   if (ret) {
    133     I420Buffers bufs = {y, y_stride, u, u_stride, v, v_stride, dw, dh};
    134     // YUV420
    135     if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
    136         mjpeg_decoder.GetNumComponents() == 3 &&
    137         mjpeg_decoder.GetVertSampFactor(0) == 2 &&
    138         mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
    139         mjpeg_decoder.GetVertSampFactor(1) == 1 &&
    140         mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
    141         mjpeg_decoder.GetVertSampFactor(2) == 1 &&
    142         mjpeg_decoder.GetHorizSampFactor(2) == 1) {
    143       ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dw, dh);
    144       // YUV422
    145     } else if (mjpeg_decoder.GetColorSpace() ==
    146                    MJpegDecoder::kColorSpaceYCbCr &&
    147                mjpeg_decoder.GetNumComponents() == 3 &&
    148                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
    149                mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
    150                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
    151                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
    152                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
    153                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
    154       ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh);
    155       // YUV444
    156     } else if (mjpeg_decoder.GetColorSpace() ==
    157                    MJpegDecoder::kColorSpaceYCbCr &&
    158                mjpeg_decoder.GetNumComponents() == 3 &&
    159                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
    160                mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
    161                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
    162                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
    163                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
    164                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
    165       ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh);
    166       // YUV400
    167     } else if (mjpeg_decoder.GetColorSpace() ==
    168                    MJpegDecoder::kColorSpaceGrayscale &&
    169                mjpeg_decoder.GetNumComponents() == 1 &&
    170                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
    171                mjpeg_decoder.GetHorizSampFactor(0) == 1) {
    172       ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh);
    173     } else {
    174       // TODO(fbarchard): Implement conversion for any other colorspace/sample
    175       // factors that occur in practice.
    176       // ERROR: Unable to convert MJPEG frame because format is not supported
    177       mjpeg_decoder.UnloadFrame();
    178       return 1;
    179     }
    180   }
    181   return ret ? 0 : 1;
    182 }
    183 
    184 #ifdef HAVE_JPEG
    185 struct ARGBBuffers {
    186   uint8* argb;
    187   int argb_stride;
    188   int w;
    189   int h;
    190 };
    191 
    192 static void JpegI420ToARGB(void* opaque,
    193                            const uint8* const* data,
    194                            const int* strides,
    195                            int rows) {
    196   ARGBBuffers* dest = (ARGBBuffers*)(opaque);
    197   I420ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
    198              dest->argb, dest->argb_stride, dest->w, rows);
    199   dest->argb += rows * dest->argb_stride;
    200   dest->h -= rows;
    201 }
    202 
    203 static void JpegI422ToARGB(void* opaque,
    204                            const uint8* const* data,
    205                            const int* strides,
    206                            int rows) {
    207   ARGBBuffers* dest = (ARGBBuffers*)(opaque);
    208   I422ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
    209              dest->argb, dest->argb_stride, dest->w, rows);
    210   dest->argb += rows * dest->argb_stride;
    211   dest->h -= rows;
    212 }
    213 
    214 static void JpegI444ToARGB(void* opaque,
    215                            const uint8* const* data,
    216                            const int* strides,
    217                            int rows) {
    218   ARGBBuffers* dest = (ARGBBuffers*)(opaque);
    219   I444ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
    220              dest->argb, dest->argb_stride, dest->w, rows);
    221   dest->argb += rows * dest->argb_stride;
    222   dest->h -= rows;
    223 }
    224 
    225 static void JpegI400ToARGB(void* opaque,
    226                            const uint8* const* data,
    227                            const int* strides,
    228                            int rows) {
    229   ARGBBuffers* dest = (ARGBBuffers*)(opaque);
    230   I400ToARGB(data[0], strides[0], dest->argb, dest->argb_stride, dest->w, rows);
    231   dest->argb += rows * dest->argb_stride;
    232   dest->h -= rows;
    233 }
    234 
    235 // MJPG (Motion JPeg) to ARGB
    236 // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
    237 LIBYUV_API
    238 int MJPGToARGB(const uint8* sample,
    239                size_t sample_size,
    240                uint8* argb,
    241                int argb_stride,
    242                int w,
    243                int h,
    244                int dw,
    245                int dh) {
    246   if (sample_size == kUnknownDataSize) {
    247     // ERROR: MJPEG frame size unknown
    248     return -1;
    249   }
    250 
    251   // TODO(fbarchard): Port MJpeg to C.
    252   MJpegDecoder mjpeg_decoder;
    253   LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
    254   if (ret &&
    255       (mjpeg_decoder.GetWidth() != w || mjpeg_decoder.GetHeight() != h)) {
    256     // ERROR: MJPEG frame has unexpected dimensions
    257     mjpeg_decoder.UnloadFrame();
    258     return 1;  // runtime failure
    259   }
    260   if (ret) {
    261     ARGBBuffers bufs = {argb, argb_stride, dw, dh};
    262     // YUV420
    263     if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
    264         mjpeg_decoder.GetNumComponents() == 3 &&
    265         mjpeg_decoder.GetVertSampFactor(0) == 2 &&
    266         mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
    267         mjpeg_decoder.GetVertSampFactor(1) == 1 &&
    268         mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
    269         mjpeg_decoder.GetVertSampFactor(2) == 1 &&
    270         mjpeg_decoder.GetHorizSampFactor(2) == 1) {
    271       ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh);
    272       // YUV422
    273     } else if (mjpeg_decoder.GetColorSpace() ==
    274                    MJpegDecoder::kColorSpaceYCbCr &&
    275                mjpeg_decoder.GetNumComponents() == 3 &&
    276                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
    277                mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
    278                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
    279                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
    280                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
    281                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
    282       ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh);
    283       // YUV444
    284     } else if (mjpeg_decoder.GetColorSpace() ==
    285                    MJpegDecoder::kColorSpaceYCbCr &&
    286                mjpeg_decoder.GetNumComponents() == 3 &&
    287                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
    288                mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
    289                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
    290                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
    291                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
    292                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
    293       ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh);
    294       // YUV400
    295     } else if (mjpeg_decoder.GetColorSpace() ==
    296                    MJpegDecoder::kColorSpaceGrayscale &&
    297                mjpeg_decoder.GetNumComponents() == 1 &&
    298                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
    299                mjpeg_decoder.GetHorizSampFactor(0) == 1) {
    300       ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh);
    301     } else {
    302       // TODO(fbarchard): Implement conversion for any other colorspace/sample
    303       // factors that occur in practice.
    304       // ERROR: Unable to convert MJPEG frame because format is not supported
    305       mjpeg_decoder.UnloadFrame();
    306       return 1;
    307     }
    308   }
    309   return ret ? 0 : 1;
    310 }
    311 #endif
    312 
    313 #endif
    314 
    315 #ifdef __cplusplus
    316 }  // extern "C"
    317 }  // namespace libyuv
    318 #endif
    319