media/libyuv/source/convert_jpeg.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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  */
    11 #include "libyuv/convert.h"
    13 #ifdef HAVE_JPEG
    14 #include "libyuv/mjpeg_decoder.h"
    15 #endif
    17 #ifdef __cplusplus
    18 namespace libyuv {
    19 extern "C" {
    20 #endif
    22 #ifdef HAVE_JPEG
    23 struct I420Buffers {
    24   uint8* y;
    25   int y_stride;
    26   uint8* u;
    27   int u_stride;
    28   uint8* v;
    29   int v_stride;
    30   int w;
    31   int h;
    32 };
    34 static void JpegCopyI420(void* opaque,
    35                          const uint8* const* data,
    36                          const int* strides,
    37                          int rows) {
    38   I420Buffers* dest = (I420Buffers*)(opaque);
    39   I420Copy(data[0], strides[0],
    40            data[1], strides[1],
    41            data[2], strides[2],
    42            dest->y, dest->y_stride,
    43            dest->u, dest->u_stride,
    44            dest->v, dest->v_stride,
    45            dest->w, rows);
    46   dest->y += rows * dest->y_stride;
    47   dest->u += ((rows + 1) >> 1) * dest->u_stride;
    48   dest->v += ((rows + 1) >> 1) * dest->v_stride;
    49   dest->h -= rows;
    50 }
    52 static void JpegI422ToI420(void* opaque,
    53                            const uint8* const* data,
    54                            const int* strides,
    55                            int rows) {
    56   I420Buffers* dest = (I420Buffers*)(opaque);
    57   I422ToI420(data[0], strides[0],
    58              data[1], strides[1],
    59              data[2], strides[2],
    60              dest->y, dest->y_stride,
    61              dest->u, dest->u_stride,
    62              dest->v, dest->v_stride,
    63              dest->w, rows);
    64   dest->y += rows * dest->y_stride;
    65   dest->u += ((rows + 1) >> 1) * dest->u_stride;
    66   dest->v += ((rows + 1) >> 1) * dest->v_stride;
    67   dest->h -= rows;
    68 }
    70 static void JpegI444ToI420(void* opaque,
    71                            const uint8* const* data,
    72                            const int* strides,
    73                            int rows) {
    74   I420Buffers* dest = (I420Buffers*)(opaque);
    75   I444ToI420(data[0], strides[0],
    76              data[1], strides[1],
    77              data[2], strides[2],
    78              dest->y, dest->y_stride,
    79              dest->u, dest->u_stride,
    80              dest->v, dest->v_stride,
    81              dest->w, rows);
    82   dest->y += rows * dest->y_stride;
    83   dest->u += ((rows + 1) >> 1) * dest->u_stride;
    84   dest->v += ((rows + 1) >> 1) * dest->v_stride;
    85   dest->h -= rows;
    86 }
    88 static void JpegI411ToI420(void* opaque,
    89                            const uint8* const* data,
    90                            const int* strides,
    91                            int rows) {
    92   I420Buffers* dest = (I420Buffers*)(opaque);
    93   I411ToI420(data[0], strides[0],
    94              data[1], strides[1],
    95              data[2], strides[2],
    96              dest->y, dest->y_stride,
    97              dest->u, dest->u_stride,
    98              dest->v, dest->v_stride,
    99              dest->w, rows);
   100   dest->y += rows * dest->y_stride;
   101   dest->u += ((rows + 1) >> 1) * dest->u_stride;
   102   dest->v += ((rows + 1) >> 1) * dest->v_stride;
   103   dest->h -= rows;
   104 }
   106 static void JpegI400ToI420(void* opaque,
   107                            const uint8* const* data,
   108                            const int* strides,
   109                            int rows) {
   110   I420Buffers* dest = (I420Buffers*)(opaque);
   111   I400ToI420(data[0], strides[0],
   112              dest->y, dest->y_stride,
   113              dest->u, dest->u_stride,
   114              dest->v, dest->v_stride,
   115              dest->w, rows);
   116   dest->y += rows * dest->y_stride;
   117   dest->u += ((rows + 1) >> 1) * dest->u_stride;
   118   dest->v += ((rows + 1) >> 1) * dest->v_stride;
   119   dest->h -= rows;
   120 }
   122 // Query size of MJPG in pixels.
   123 LIBYUV_API
   124 int MJPGSize(const uint8* sample, size_t sample_size,
   125              int* width, int* height) {
   126   MJpegDecoder mjpeg_decoder;
   127   LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
   128   if (ret) {
   129     *width = mjpeg_decoder.GetWidth();
   130     *height = mjpeg_decoder.GetHeight();
   131   }
   132   mjpeg_decoder.UnloadFrame();
   133   return ret ? 0 : -1;  // -1 for runtime failure.
   134 }
   136 // MJPG (Motion JPeg) to I420
   137 // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
   138 LIBYUV_API
   139 int MJPGToI420(const uint8* sample,
   140                size_t sample_size,
   141                uint8* y, int y_stride,
   142                uint8* u, int u_stride,
   143                uint8* v, int v_stride,
   144                int w, int h,
   145                int dw, int dh) {
   146   if (sample_size == kUnknownDataSize) {
   147     // ERROR: MJPEG frame size unknown
   148     return -1;
   149   }
   151   // TODO(fbarchard): Port MJpeg to C.
   152   MJpegDecoder mjpeg_decoder;
   153   LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
   154   if (ret && (mjpeg_decoder.GetWidth() != w ||
   155               mjpeg_decoder.GetHeight() != h)) {
   156     // ERROR: MJPEG frame has unexpected dimensions
   157     mjpeg_decoder.UnloadFrame();
   158     return 1;  // runtime failure
   159   }
   160   if (ret) {
   161     I420Buffers bufs = { y, y_stride, u, u_stride, v, v_stride, dw, dh };
   162     // YUV420
   163     if (mjpeg_decoder.GetColorSpace() ==
   164             MJpegDecoder::kColorSpaceYCbCr &&
   165         mjpeg_decoder.GetNumComponents() == 3 &&
   166         mjpeg_decoder.GetVertSampFactor(0) == 2 &&
   167         mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
   168         mjpeg_decoder.GetVertSampFactor(1) == 1 &&
   169         mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
   170         mjpeg_decoder.GetVertSampFactor(2) == 1 &&
   171         mjpeg_decoder.GetHorizSampFactor(2) == 1) {
   172       ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dw, dh);
   173     // YUV422
   174     } else if (mjpeg_decoder.GetColorSpace() ==
   175                    MJpegDecoder::kColorSpaceYCbCr &&
   176                mjpeg_decoder.GetNumComponents() == 3 &&
   177                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
   178                mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
   179                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
   180                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
   181                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
   182                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
   183       ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh);
   184     // YUV444
   185     } else if (mjpeg_decoder.GetColorSpace() ==
   186                    MJpegDecoder::kColorSpaceYCbCr &&
   187                mjpeg_decoder.GetNumComponents() == 3 &&
   188                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
   189                mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
   190                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
   191                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
   192                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
   193                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
   194       ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh);
   195     // YUV411
   196     } else if (mjpeg_decoder.GetColorSpace() ==
   197                    MJpegDecoder::kColorSpaceYCbCr &&
   198                mjpeg_decoder.GetNumComponents() == 3 &&
   199                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
   200                mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
   201                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
   202                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
   203                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
   204                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
   205       ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToI420, &bufs, dw, dh);
   206     // YUV400
   207     } else if (mjpeg_decoder.GetColorSpace() ==
   208                    MJpegDecoder::kColorSpaceGrayscale &&
   209                mjpeg_decoder.GetNumComponents() == 1 &&
   210                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
   211                mjpeg_decoder.GetHorizSampFactor(0) == 1) {
   212       ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh);
   213     } else {
   214       // TODO(fbarchard): Implement conversion for any other colorspace/sample
   215       // factors that occur in practice. 411 is supported by libjpeg
   216       // ERROR: Unable to convert MJPEG frame because format is not supported
   217       mjpeg_decoder.UnloadFrame();
   218       return 1;
   219     }
   220   }
   221   return 0;
   222 }
   224 #ifdef HAVE_JPEG
   225 struct ARGBBuffers {
   226   uint8* argb;
   227   int argb_stride;
   228   int w;
   229   int h;
   230 };
   232 static void JpegI420ToARGB(void* opaque,
   233                          const uint8* const* data,
   234                          const int* strides,
   235                          int rows) {
   236   ARGBBuffers* dest = (ARGBBuffers*)(opaque);
   237   I420ToARGB(data[0], strides[0],
   238              data[1], strides[1],
   239              data[2], strides[2],
   240              dest->argb, dest->argb_stride,
   241              dest->w, rows);
   242   dest->argb += rows * dest->argb_stride;
   243   dest->h -= rows;
   244 }
   246 static void JpegI422ToARGB(void* opaque,
   247                            const uint8* const* data,
   248                            const int* strides,
   249                            int rows) {
   250   ARGBBuffers* dest = (ARGBBuffers*)(opaque);
   251   I422ToARGB(data[0], strides[0],
   252              data[1], strides[1],
   253              data[2], strides[2],
   254              dest->argb, dest->argb_stride,
   255              dest->w, rows);
   256   dest->argb += rows * dest->argb_stride;
   257   dest->h -= rows;
   258 }
   260 static void JpegI444ToARGB(void* opaque,
   261                            const uint8* const* data,
   262                            const int* strides,
   263                            int rows) {
   264   ARGBBuffers* dest = (ARGBBuffers*)(opaque);
   265   I444ToARGB(data[0], strides[0],
   266              data[1], strides[1],
   267              data[2], strides[2],
   268              dest->argb, dest->argb_stride,
   269              dest->w, rows);
   270   dest->argb += rows * dest->argb_stride;
   271   dest->h -= rows;
   272 }
   274 static void JpegI411ToARGB(void* opaque,
   275                            const uint8* const* data,
   276                            const int* strides,
   277                            int rows) {
   278   ARGBBuffers* dest = (ARGBBuffers*)(opaque);
   279   I411ToARGB(data[0], strides[0],
   280              data[1], strides[1],
   281              data[2], strides[2],
   282              dest->argb, dest->argb_stride,
   283              dest->w, rows);
   284   dest->argb += rows * dest->argb_stride;
   285   dest->h -= rows;
   286 }
   288 static void JpegI400ToARGB(void* opaque,
   289                            const uint8* const* data,
   290                            const int* strides,
   291                            int rows) {
   292   ARGBBuffers* dest = (ARGBBuffers*)(opaque);
   293   I400ToARGB(data[0], strides[0],
   294              dest->argb, dest->argb_stride,
   295              dest->w, rows);
   296   dest->argb += rows * dest->argb_stride;
   297   dest->h -= rows;
   298 }
   300 // MJPG (Motion JPeg) to ARGB
   301 // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
   302 LIBYUV_API
   303 int MJPGToARGB(const uint8* sample,
   304                size_t sample_size,
   305                uint8* argb, int argb_stride,
   306                int w, int h,
   307                int dw, int dh) {
   308   if (sample_size == kUnknownDataSize) {
   309     // ERROR: MJPEG frame size unknown
   310     return -1;
   311   }
   313   // TODO(fbarchard): Port MJpeg to C.
   314   MJpegDecoder mjpeg_decoder;
   315   LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
   316   if (ret && (mjpeg_decoder.GetWidth() != w ||
   317               mjpeg_decoder.GetHeight() != h)) {
   318     // ERROR: MJPEG frame has unexpected dimensions
   319     mjpeg_decoder.UnloadFrame();
   320     return 1;  // runtime failure
   321   }
   322   if (ret) {
   323     ARGBBuffers bufs = { argb, argb_stride, dw, dh };
   324     // YUV420
   325     if (mjpeg_decoder.GetColorSpace() ==
   326             MJpegDecoder::kColorSpaceYCbCr &&
   327         mjpeg_decoder.GetNumComponents() == 3 &&
   328         mjpeg_decoder.GetVertSampFactor(0) == 2 &&
   329         mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
   330         mjpeg_decoder.GetVertSampFactor(1) == 1 &&
   331         mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
   332         mjpeg_decoder.GetVertSampFactor(2) == 1 &&
   333         mjpeg_decoder.GetHorizSampFactor(2) == 1) {
   334       ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh);
   335     // YUV422
   336     } else if (mjpeg_decoder.GetColorSpace() ==
   337                    MJpegDecoder::kColorSpaceYCbCr &&
   338                mjpeg_decoder.GetNumComponents() == 3 &&
   339                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
   340                mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
   341                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
   342                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
   343                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
   344                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
   345       ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh);
   346     // YUV444
   347     } else if (mjpeg_decoder.GetColorSpace() ==
   348                    MJpegDecoder::kColorSpaceYCbCr &&
   349                mjpeg_decoder.GetNumComponents() == 3 &&
   350                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
   351                mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
   352                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
   353                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
   354                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
   355                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
   356       ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh);
   357     // YUV411
   358     } else if (mjpeg_decoder.GetColorSpace() ==
   359                    MJpegDecoder::kColorSpaceYCbCr &&
   360                mjpeg_decoder.GetNumComponents() == 3 &&
   361                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
   362                mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
   363                mjpeg_decoder.GetVertSampFactor(1) == 1 &&
   364                mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
   365                mjpeg_decoder.GetVertSampFactor(2) == 1 &&
   366                mjpeg_decoder.GetHorizSampFactor(2) == 1) {
   367       ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToARGB, &bufs, dw, dh);
   368     // YUV400
   369     } else if (mjpeg_decoder.GetColorSpace() ==
   370                    MJpegDecoder::kColorSpaceGrayscale &&
   371                mjpeg_decoder.GetNumComponents() == 1 &&
   372                mjpeg_decoder.GetVertSampFactor(0) == 1 &&
   373                mjpeg_decoder.GetHorizSampFactor(0) == 1) {
   374       ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh);
   375     } else {
   376       // TODO(fbarchard): Implement conversion for any other colorspace/sample
   377       // factors that occur in practice. 411 is supported by libjpeg
   378       // ERROR: Unable to convert MJPEG frame because format is not supported
   379       mjpeg_decoder.UnloadFrame();
   380       return 1;
   381     }
   382   }
   383   return 0;
   384 }
   385 #endif
   387 #endif
   389 #ifdef __cplusplus
   390 }  // extern "C"
   391 }  // namespace libyuv
   392 #endif

mercurial