Updating JPEG Decoder to Use LibYuv

Review URL: https://webrtc-codereview.appspot.com/900004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2947 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/common_video/jpeg/include/jpeg.h b/src/common_video/jpeg/include/jpeg.h
index 10c0461..3bb1093 100644
--- a/src/common_video/jpeg/include/jpeg.h
+++ b/src/common_video/jpeg/include/jpeg.h
@@ -17,11 +17,12 @@
 
 // jpeg forward declaration
 struct jpeg_compress_struct;
-struct jpeg_decompress_struct;
 
 namespace webrtc
 {
 
+// TODO(mikhal): Move this to LibYuv wrappar, when LibYuv will have a JPG
+// Encode.
 class JpegEncoder
 {
 public:
@@ -53,29 +54,19 @@
     char                    _fileName[257];
 };
 
-class JpegDecoder
-{
- public:
-    JpegDecoder();
-    ~JpegDecoder();
-
 // Decodes a JPEG-stream
 // Supports 1 image component. 3 interleaved image components,
 // YCbCr sub-sampling  4:4:4, 4:2:2, 4:2:0.
 //
 // Input:
-//    - inputImage        : encoded image to be decoded.
-//    - outputImage       : VideoFrame to store decoded output.
+//    - input_image        : encoded image to be decoded.
+//    - output_image       : VideoFrame to store decoded output.
 //
 //    Output:
 //    - 0             : OK
 //    - (-1)          : Error
-    WebRtc_Word32 Decode(const EncodedImage& inputImage,
-                         VideoFrame& outputImage);
- private:
-    jpeg_decompress_struct*    _cinfo;
-};
-
-
+//    - (-2)          : Unsupported format
+int ConvertJpegToI420(const EncodedImage& input_image,
+                      VideoFrame* output_image);
 }
 #endif /* WEBRTC_COMMON_VIDEO_JPEG  */
diff --git a/src/common_video/jpeg/jpeg.cc b/src/common_video/jpeg/jpeg.cc
index 93bc251..b0d3a62 100644
--- a/src/common_video/jpeg/jpeg.cc
+++ b/src/common_video/jpeg/jpeg.cc
@@ -18,6 +18,8 @@
 #include "common_video/jpeg/include/jpeg.h"
 #include "common_video/jpeg/data_manager.h"
 #include "common_video/libyuv/include/webrtc_libyuv.h"
+#include "libyuv.h"
+#include "libyuv/mjpeg_decoder.h"
 
 extern "C" {
 #if defined(USE_SYSTEM_LIBJPEG)
@@ -194,172 +196,33 @@
     return 0;
 }
 
-JpegDecoder::JpegDecoder()
-{
-    _cinfo = new jpeg_decompress_struct;
-}
+int ConvertJpegToI420(const EncodedImage& input_image,
+                      VideoFrame* output_image) {
 
-JpegDecoder::~JpegDecoder()
-{
-    if (_cinfo != NULL)
-    {
-        delete _cinfo;
-        _cinfo = NULL;
-    }
-}
-
-WebRtc_Word32
-JpegDecoder::Decode(const EncodedImage& inputImage,
-                    VideoFrame& outputImage)
-{
-
-    WebRtc_UWord8* tmpBuffer = NULL;
-    // Set error handler
-    myErrorMgr    jerr;
-    _cinfo->err = jpeg_std_error(&jerr.pub);
-    jerr.pub.error_exit = MyErrorExit;
-
-    // Establish the setjmp return context
-    if (setjmp(jerr.setjmp_buffer))
-    {
-        if (_cinfo->is_decompressor)
-        {
-            jpeg_destroy_decompress(_cinfo);
-        }
-        if (tmpBuffer != NULL)
-        {
-            delete [] tmpBuffer;
-        }
-        return -1;
-    }
-
-    _cinfo->out_color_space = JCS_YCbCr;
-
-    // Create decompression object
-    jpeg_create_decompress(_cinfo);
-
-    // Specify data source
-    jpegSetSrcBuffer(_cinfo, (JOCTET*) inputImage._buffer, inputImage._size);
-
-    // Read header data
-    jpeg_read_header(_cinfo, TRUE);
-
-    _cinfo->raw_data_out = TRUE;
-    jpeg_start_decompress(_cinfo);
-
-    // Check header
-    if (_cinfo->num_components == 4)
-    {
-        return -2; // not supported
-    }
-    if (_cinfo->progressive_mode == 1)
-    {
-        return -2; // not supported
-    }
-
-
-    WebRtc_UWord32 height = _cinfo->image_height;
-    WebRtc_UWord32 width = _cinfo->image_width;
-
-    // Making sure width and height are even
-    if (height % 2)
-    {
-        height++;
-    }
-    if (width % 2)
-    {
-         width++;
-    }
-
-    WebRtc_UWord32 height16 = (height + 15) & ~15;
-    WebRtc_UWord32 stride = (width + 15) & ~15;
-    WebRtc_UWord32 uvStride = ((((stride + 1) >> 1) + 15) & ~15);
-
-    WebRtc_UWord32 tmpRequiredSize =  stride * height16 +
-                                      2 * (uvStride * ((height16 + 1) >> 1));
-    WebRtc_UWord32 requiredSize = width * height * 3 >> 1;
-
-    // Verify sufficient buffer size.
-    outputImage.VerifyAndAllocate(requiredSize);
-    WebRtc_UWord8* outPtr = outputImage.Buffer();
-
-    if (tmpRequiredSize > requiredSize)
-    {
-        tmpBuffer = new WebRtc_UWord8[(int) (tmpRequiredSize)];
-        outPtr = tmpBuffer;
-    }
-
-    JSAMPROW y[16],u[8],v[8];
-    JSAMPARRAY data[3];
-    data[0] = y;
-    data[1] = u;
-    data[2] = v;
-
-    WebRtc_UWord32 hInd, i;
-    WebRtc_UWord32 numScanLines = 16;
-    WebRtc_UWord32 numLinesProcessed = 0;
-
-    while (_cinfo->output_scanline < _cinfo->output_height)
-    {
-        hInd = _cinfo->output_scanline;
-        for (i = 0; i < numScanLines; i++)
-        {
-            y[i] = outPtr + stride * (i + hInd);
-
-            if (i % 2 == 0)
-            {
-                 u[i / 2] = outPtr + stride * height16 +
-                            stride / 2 * ((i + hInd) / 2);
-                 v[i / 2] = outPtr + stride * height16 +
-                            stride * height16 / 4 +
-                            stride / 2 * ((i + hInd) / 2);
-            }
-        }
-        // Processes exactly one iMCU row per call
-        numLinesProcessed = jpeg_read_raw_data(_cinfo, data, numScanLines);
-        // Error in read
-        if (numLinesProcessed == 0)
-        {
-            jpeg_abort((j_common_ptr)_cinfo);
-            return -1;
-        }
-    }
-
-    if (tmpRequiredSize > requiredSize)
-    {
-         WebRtc_UWord8* dstFramePtr = outputImage.Buffer();
-         WebRtc_UWord8* tmpPtr = outPtr;
-
-         for (WebRtc_UWord32 p = 0; p < 3; p++)
-         {
-             const WebRtc_UWord32 h = (p == 0) ? height : height >> 1;
-             const WebRtc_UWord32 h16 = (p == 0) ? height16 : height16 >> 1;
-             const WebRtc_UWord32 w = (p == 0) ? width : width >> 1;
-             const WebRtc_UWord32 s = (p == 0) ? stride : stride >> 1;
-
-             for (WebRtc_UWord32 i = 0; i < h; i++)
-             {
-                 memcpy(dstFramePtr, tmpPtr, w);
-                 dstFramePtr += w;
-                 tmpPtr += s;
-             }
-             tmpPtr += (h16 - h) * s;
-         }
-    }
-
-    if (tmpBuffer != NULL)
-    {
-        delete [] tmpBuffer;
-    }
-    // Setting output Image parameter
-    outputImage.SetWidth(width);
-    outputImage.SetHeight(height);
-    outputImage.SetLength(requiredSize);
-    outputImage.SetTimeStamp(inputImage._timeStamp);
-
-    jpeg_finish_decompress(_cinfo);
-    jpeg_destroy_decompress(_cinfo);
-    return 0;
+  if (output_image == NULL)
+    return -1;
+  // TODO(mikhal): Update to use latest API from LibYuv when that becomes
+  // available.
+  libyuv::MJpegDecoder jpeg_decoder;
+  bool ret = jpeg_decoder.LoadFrame(input_image._buffer, input_image._size);
+  if (ret == false)
+    return -1;
+  if (jpeg_decoder.GetNumComponents() == 4)
+    return -2;  // not supported.
+  int width = jpeg_decoder.GetWidth();
+  int height = jpeg_decoder.GetHeight();
+  int req_size = CalcBufferSize(kI420, width, height);
+  output_image->VerifyAndAllocate(req_size);
+  output_image->SetWidth(width);
+  output_image->SetHeight(height);
+  output_image->SetLength(req_size);
+  return ConvertToI420(kMJPG,
+                       input_image._buffer,
+                       0, 0,  // no cropping
+                       width, height,
+                       input_image._size,
+                       kRotateNone,
+                       output_image);
 }
 
 
diff --git a/src/common_video/jpeg/jpeg_unittest.cc b/src/common_video/jpeg/jpeg_unittest.cc
index ee5d0b0..a7c912f 100644
--- a/src/common_video/jpeg/jpeg_unittest.cc
+++ b/src/common_video/jpeg/jpeg_unittest.cc
@@ -34,7 +34,6 @@
 
   void SetUp() {
     encoder_ = new JpegEncoder();
-    decoder_ = new JpegDecoder();
   }
 
   void TearDown() {
@@ -45,7 +44,6 @@
       delete encoded_buffer_;
     }
     delete encoder_;
-    delete decoder_;
   }
 
   // Reads an encoded image. Caller will have to deallocate the memory of this
@@ -70,13 +68,12 @@
   std::string encoded_filename_;
   EncodedImage* encoded_buffer_;
   JpegEncoder* encoder_;
-  JpegDecoder* decoder_;
 };
 
 TEST_F(JpegTest, Decode) {
   encoded_buffer_ = ReadEncodedImage(input_filename_);
   VideoFrame image_buffer;
-  EXPECT_EQ(0, decoder_->Decode(*encoded_buffer_, image_buffer));
+  EXPECT_EQ(0, ConvertJpegToI420(*encoded_buffer_, &image_buffer));
   EXPECT_GT(image_buffer.Length(), 0u);
   EXPECT_EQ(kImageWidth, image_buffer.Width());
   EXPECT_EQ(kImageHeight, image_buffer.Height());
@@ -107,7 +104,7 @@
   // Decode our input image then encode it again to a new file:
   encoded_buffer_ = ReadEncodedImage(input_filename_);
   VideoFrame image_buffer;
-  EXPECT_EQ(0, decoder_->Decode(*encoded_buffer_, image_buffer));
+  EXPECT_EQ(0, ConvertJpegToI420(*encoded_buffer_, &image_buffer));
 
   EXPECT_EQ(0, encoder_->SetFileName(encoded_filename_.c_str()));
   EXPECT_EQ(0, encoder_->Encode(image_buffer));
diff --git a/src/video_engine/vie_file_image.cc b/src/video_engine/vie_file_image.cc
index 772642c..1f224fe 100644
--- a/src/video_engine/vie_file_image.cc
+++ b/src/video_engine/vie_file_image.cc
@@ -69,8 +69,7 @@
   }
   fclose(image_file);
 
-  JpegDecoder decoder;
-  int ret = decoder.Decode(image_buffer, *video_frame);
+  int ret = ConvertJpegToI420(image_buffer, video_frame);
 
   delete [] image_buffer._buffer;
   image_buffer._buffer = NULL;