b5427cbd35
Review URL: http://webrtc-codereview.appspot.com/55002 git-svn-id: http://webrtc.googlecode.com/svn/trunk@139 4adac7df-926f-26a2-2b94-8c16560cd09d
363 lines
8.3 KiB
C++
363 lines
8.3 KiB
C++
/*
|
|
* Copyright (c) 2011 The WebRTC 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.
|
|
*/
|
|
|
|
/*
|
|
* jpeg.cc
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "vplib.h"
|
|
#include "jpeg.h"
|
|
#include "data_manager.h"
|
|
#if defined(WIN32)
|
|
#include <basetsd.h>
|
|
#endif
|
|
#ifdef WEBRTC_ANDROID
|
|
extern "C" {
|
|
#endif
|
|
#include "jpeglib.h"
|
|
#ifdef WEBRTC_ANDROID
|
|
}
|
|
#endif
|
|
#include <setjmp.h>
|
|
|
|
|
|
namespace webrtc
|
|
{
|
|
|
|
// Error handler
|
|
struct myErrorMgr {
|
|
|
|
struct jpeg_error_mgr pub;
|
|
jmp_buf setjmp_buffer;
|
|
};
|
|
typedef struct myErrorMgr * myErrorPtr;
|
|
|
|
METHODDEF(void)
|
|
MyErrorExit (j_common_ptr cinfo)
|
|
{
|
|
myErrorPtr myerr = (myErrorPtr) cinfo->err;
|
|
|
|
// Return control to the setjmp point
|
|
longjmp(myerr->setjmp_buffer, 1);
|
|
}
|
|
|
|
JpegEncoder::JpegEncoder()
|
|
{
|
|
_cinfo = new jpeg_compress_struct;
|
|
strcpy(_fileName, "Snapshot.jpg");
|
|
}
|
|
|
|
JpegEncoder::~JpegEncoder()
|
|
{
|
|
if (_cinfo != NULL)
|
|
{
|
|
delete _cinfo;
|
|
_cinfo = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
WebRtc_Word32
|
|
JpegEncoder::SetFileName(const WebRtc_Word8* fileName)
|
|
{
|
|
if (!fileName)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (fileName)
|
|
{
|
|
strncpy(_fileName, fileName, 256);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
WebRtc_Word32
|
|
JpegEncoder::Encode(const RawImage& inputImage)
|
|
{
|
|
if (inputImage._buffer == NULL || inputImage._size == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
if (inputImage._width < 1 || inputImage._height < 1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
FILE* outFile = NULL;
|
|
|
|
const WebRtc_Word32 width = inputImage._width;
|
|
const WebRtc_Word32 height = inputImage._height;
|
|
|
|
// 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 we get here, the JPEG code has signaled an error.
|
|
jpeg_destroy_compress(_cinfo);
|
|
if (outFile != NULL)
|
|
{
|
|
fclose(outFile);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
if ((outFile = fopen(_fileName, "wb")) == NULL)
|
|
{
|
|
return -2;
|
|
}
|
|
// Create a compression object
|
|
jpeg_create_compress(_cinfo);
|
|
|
|
// Setting destination file
|
|
jpeg_stdio_dest(_cinfo, outFile);
|
|
|
|
// Set parameters for compression
|
|
_cinfo->in_color_space = JCS_YCbCr;
|
|
jpeg_set_defaults(_cinfo);
|
|
|
|
_cinfo->image_width = width;
|
|
_cinfo->image_height = height;
|
|
_cinfo->input_components = 3;
|
|
|
|
_cinfo->comp_info[0].h_samp_factor = 2; // Y
|
|
_cinfo->comp_info[0].v_samp_factor = 2;
|
|
_cinfo->comp_info[1].h_samp_factor = 1; // U
|
|
_cinfo->comp_info[1].v_samp_factor = 1;
|
|
_cinfo->comp_info[2].h_samp_factor = 1; // V
|
|
_cinfo->comp_info[2].v_samp_factor = 1;
|
|
_cinfo->raw_data_in = TRUE;
|
|
|
|
jpeg_start_compress(_cinfo, TRUE);
|
|
|
|
JSAMPROW y[16],u[8],v[8];
|
|
JSAMPARRAY data[3];
|
|
|
|
data[0] = y;
|
|
data[1] = u;
|
|
data[2] = v;
|
|
|
|
WebRtc_UWord32 i, j;
|
|
|
|
for (j = 0; j < height; j += 16)
|
|
{
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
y[i] = (JSAMPLE*) inputImage._buffer + width * (i + j);
|
|
|
|
if (i % 2 == 0)
|
|
{
|
|
u[i / 2] = (JSAMPLE*) inputImage._buffer + width * height +
|
|
width / 2 * ((i + j) / 2);
|
|
v[i / 2] = (JSAMPLE*) inputImage._buffer + width * height +
|
|
width * height / 4 + width / 2 * ((i + j) / 2);
|
|
}
|
|
}
|
|
jpeg_write_raw_data(_cinfo, data, 16);
|
|
}
|
|
|
|
jpeg_finish_compress(_cinfo);
|
|
jpeg_destroy_compress(_cinfo);
|
|
|
|
fclose(outFile);
|
|
|
|
return 0;
|
|
}
|
|
|
|
JpegDecoder::JpegDecoder()
|
|
{
|
|
_cinfo = new jpeg_decompress_struct;
|
|
}
|
|
|
|
JpegDecoder::~JpegDecoder()
|
|
{
|
|
if (_cinfo != NULL)
|
|
{
|
|
delete _cinfo;
|
|
_cinfo = NULL;
|
|
}
|
|
}
|
|
|
|
WebRtc_Word32
|
|
JpegDecoder::Decode(const EncodedImage& inputImage,
|
|
RawImage& 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
|
|
if (outputImage._buffer && outputImage._size < requiredSize)
|
|
{
|
|
delete [] outputImage._buffer;
|
|
outputImage._buffer = NULL;
|
|
}
|
|
|
|
if (outputImage._buffer == NULL)
|
|
{
|
|
outputImage._buffer = new WebRtc_UWord8[requiredSize];
|
|
outputImage._size = 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._width = width;
|
|
outputImage._height = height;
|
|
outputImage._length = requiredSize;
|
|
outputImage._timeStamp = inputImage._timeStamp;
|
|
|
|
jpeg_finish_decompress(_cinfo);
|
|
jpeg_destroy_decompress(_cinfo);
|
|
return 0;
|
|
}
|
|
|
|
|
|
}
|