git-svn-id: http://webrtc.googlecode.com/svn/trunk@3 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/common_video/OWNERS b/common_video/OWNERS
new file mode 100644
index 0000000..30eee35
--- /dev/null
+++ b/common_video/OWNERS
@@ -0,0 +1,4 @@
+holmer@google.com
+mikhal@google.com
+marpan@google.com
+hlundin@google.com
diff --git a/common_video/jpeg/main/interface/jpeg.h b/common_video/jpeg/main/interface/jpeg.h
new file mode 100644
index 0000000..6f092b8
--- /dev/null
+++ b/common_video/jpeg/main/interface/jpeg.h
@@ -0,0 +1,96 @@
+/*
+ * 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 wrapper
+ */
+
+#ifndef WEBRTC_COMMON_VIDEO_JPEG
+#define WEBRTC_COMMON_VIDEO_JPEG
+
+#include "typedefs.h"
+
+// jpeg forward declaration
+struct jpeg_compress_struct;
+struct jpeg_decompress_struct;
+
+namespace webrtc
+{
+
+class JpegEncoder
+{
+public:
+ JpegEncoder();
+ ~JpegEncoder();
+
+// SetFileName
+// Input:
+// - fileName - Pointer to input vector (should be less than 256) to which the
+// compressed file will be written to
+// Output:
+// - 0 : OK
+// - (-1) : Error
+ WebRtc_Word32 SetFileName(const WebRtc_Word8* fileName);
+
+// Encode an I420 image. The encoded image is saved to a file
+//
+// Input:
+// - inputImage : Image to be encoded
+//
+// Output:
+// - 0 : OK
+// - (-1) : Error
+ WebRtc_Word32 Encode(const WebRtc_UWord8* imageBuffer,
+ const WebRtc_UWord32 imageBufferSize,
+ const WebRtc_UWord32 width,
+ const WebRtc_UWord32 height);
+
+private:
+ WebRtc_Word32 Encode(const WebRtc_UWord8* imageBuffer,
+ const WebRtc_UWord32 imageBufferSize);
+
+ jpeg_compress_struct* _cinfo;
+ WebRtc_Word8 _fileName[256];
+ WebRtc_UWord32 _width;
+ WebRtc_UWord32 _height;
+};
+
+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:
+// - encodedBuffer : Pointer to the encoded stream to be decoded.
+// - encodedBufferSize : Size of the data to be decoded
+// - decodedBuffer : Reference to the destination of the decoded I420-image.
+// - width : Reference returning width of decoded image.
+// - height : Reference returning height of decoded image.
+//
+// Output:
+// - 0 : OK
+// - (-1) : Error
+//Note: decodedBuffer should be freed by user
+ WebRtc_Word32 Decode(const WebRtc_UWord8* encodedBuffer,
+ const WebRtc_UWord32 encodedBufferSize,
+ WebRtc_UWord8*& decodedBuffer,
+ WebRtc_UWord32& width,
+ WebRtc_UWord32& height);
+ private:
+ jpeg_decompress_struct* _cinfo;
+};
+
+
+}
+#endif /* WEBRTC_COMMON_VIDEO_JPEG */
diff --git a/common_video/jpeg/main/source/data_manager.cc b/common_video/jpeg/main/source/data_manager.cc
new file mode 100644
index 0000000..2e2a870
--- /dev/null
+++ b/common_video/jpeg/main/source/data_manager.cc
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+/*
+ * data_manager.cc
+ */
+
+#include "data_manager.h"
+
+#ifdef WEBRTC_ANDROID
+extern "C" {
+#endif
+#include "jpeglib.h"
+#ifdef WEBRTC_ANDROID
+}
+#endif
+#include "jmorecfg.h"
+
+
+namespace webrtc
+{
+
+typedef struct
+{
+ jpeg_source_mgr mgr;
+ JOCTET* next_input_byte;
+ size_t bytes_in_buffer; /* # of byte spaces remaining in buffer */
+} DataSrcMgr;
+
+void
+jpegSetSrcBuffer(j_decompress_ptr cinfo, JOCTET* srcBuffer, size_t bufferSize)
+{
+ DataSrcMgr* src;
+ if (cinfo->src == NULL)
+ { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,
+ JPOOL_PERMANENT, sizeof(DataSrcMgr));
+ }
+
+ // Setting required functionality
+ src = (DataSrcMgr*) cinfo->src;
+ src->mgr.init_source = initSrc;;
+ src->mgr.fill_input_buffer = fillInputBuffer;
+ src->mgr.skip_input_data = skipInputData;
+ src->mgr.resync_to_restart = jpeg_resync_to_restart; // use default
+ src->mgr.term_source = termSource;
+ // setting buffer/src
+ src->bytes_in_buffer = bufferSize;
+ src->next_input_byte = srcBuffer;
+
+}
+
+
+void
+initSrc(j_decompress_ptr cinfo)
+{
+ DataSrcMgr *src = (DataSrcMgr*)cinfo->src;
+ src->mgr.next_input_byte = src->next_input_byte;
+ src->mgr.bytes_in_buffer = src->bytes_in_buffer;
+}
+
+boolean
+fillInputBuffer(j_decompress_ptr cinfo)
+{
+ return false;
+}
+
+
+void
+skipInputData(j_decompress_ptr cinfo, long num_bytes)
+{
+ DataSrcMgr* src = (DataSrcMgr*)cinfo->src;
+ if (num_bytes > 0)
+ {
+ if ((unsigned long)num_bytes > src->mgr.bytes_in_buffer)
+ src->mgr.bytes_in_buffer = 0;
+ else
+ {
+ src->mgr.next_input_byte += num_bytes;
+ src->mgr.bytes_in_buffer -= num_bytes;
+ }
+ }
+}
+
+
+void
+termSource (j_decompress_ptr cinfo)
+{
+ //
+}
+
+} // end of namespace webrtc
diff --git a/common_video/jpeg/main/source/data_manager.h b/common_video/jpeg/main/source/data_manager.h
new file mode 100644
index 0000000..56fdb2d
--- /dev/null
+++ b/common_video/jpeg/main/source/data_manager.h
@@ -0,0 +1,68 @@
+/*
+ * 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 source data manager
+ */
+
+#ifndef WEBRTC_COMMON_VIDEO_JPEG_DATA_MANAGER
+#define WEBRTC_COMMON_VIDEO_JPEG_DATA_MANAGER
+
+#include <stdio.h>
+
+// jpeg forward declaration
+struct jpeg_source_mgr;
+typedef unsigned char JOCTET;
+typedef int boolean;
+typedef struct jpeg_decompress_struct* j_decompress_ptr;
+typedef struct jpeg_compress_struct* j_compress_ptr;
+
+namespace webrtc
+{
+
+// Source manager:
+
+
+// a general function that will set these values
+void
+jpegSetSrcBuffer(j_decompress_ptr cinfo, JOCTET* srcBuffer, size_t bufferSize);
+
+
+// Initialize source. This is called by jpeg_read_header() before any
+// data is actually read.
+
+void
+initSrc(j_decompress_ptr cinfo);
+
+
+// Fill input buffer
+// This is called whenever bytes_in_buffer has reached zero and more
+// data is wanted.
+
+boolean
+fillInputBuffer(j_decompress_ptr cinfo);
+
+// Skip input data
+// Skip num_bytes worth of data.
+
+void
+skipInputData(j_decompress_ptr cinfo, long num_bytes);
+
+
+
+
+// Terminate source
+void
+termSource (j_decompress_ptr cinfo);
+
+} // end of namespace webrtc
+
+
+#endif /* WEBRTC_COMMON_VIDEO_JPEG_DATA_MANAGER */
diff --git a/common_video/jpeg/main/source/jpeg.cc b/common_video/jpeg/main/source/jpeg.cc
new file mode 100644
index 0000000..9fffedd
--- /dev/null
+++ b/common_video/jpeg/main/source/jpeg.cc
@@ -0,0 +1,345 @@
+/*
+ * 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():
+_width(0),
+_height(0)
+{
+ _cinfo = new jpeg_compress_struct;
+ strcpy(_fileName, "Snapshot.jpg");
+}
+
+JpegEncoder::~JpegEncoder()
+{
+ 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 WebRtc_UWord8* imageBuffer,
+ const WebRtc_UWord32 imageBufferSize,
+ const WebRtc_UWord32 width,
+ const WebRtc_UWord32 height)
+{
+ if ((imageBuffer == NULL) || (imageBufferSize == 0))
+ {
+ return -1;
+ }
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ FILE* outFile = NULL;
+
+ _width = width;
+ _height = 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)
+ {
+ fprintf(stderr, "can't open %s\n", _fileName);
+ return -2;
+ }
+ // Create a compression object
+ jpeg_create_compress(_cinfo);
+
+ // Setting destination file
+ jpeg_stdio_dest(_cinfo, outFile);
+
+ WebRtc_Word32 ret = 0;
+
+ // Height of image buffer should be a multiple of 16
+ if (_height % 16 == 0)
+ {
+ ret = Encode(imageBuffer, imageBufferSize);
+ }
+ else
+ {
+ WebRtc_UWord32 height16 = ((_height + 15) - 16) & - 16;
+ height16 = (height16 < _height) ? height16 + 16 : height16;
+
+ // Copy image to an adequate size buffer
+ WebRtc_UWord32 requiredSize = height16 * _width * 3 >> 1;
+ WebRtc_UWord8* origImagePtr = new WebRtc_UWord8[requiredSize];
+ if (origImagePtr == NULL)
+ {
+ return -1;
+ }
+ memset(origImagePtr, 0, requiredSize);
+ memcpy(origImagePtr, imageBuffer, imageBufferSize);
+
+ ret = Encode(origImagePtr, requiredSize);
+
+ // delete allocated buffer
+ delete [] origImagePtr;
+ origImagePtr = NULL;
+ }
+
+
+ fclose(outFile);
+
+ return ret;
+}
+
+WebRtc_Word32
+JpegEncoder::Encode(const WebRtc_UWord8* imageBuffer,
+ const WebRtc_UWord32 imageBufferSize)
+{
+ // 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*) imageBuffer + _width * (i + j);
+
+ if (i % 2 == 0)
+ {
+ u[i / 2] = (JSAMPLE*) imageBuffer + _width * _height +
+ _width / 2 * ((i + j) / 2);
+ v[i / 2] = (JSAMPLE*) imageBuffer + _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);
+
+ return 0;
+}
+
+
+JpegDecoder::JpegDecoder()
+{
+ _cinfo = new jpeg_decompress_struct;
+}
+
+JpegDecoder::~JpegDecoder()
+{
+ delete _cinfo;
+ _cinfo = NULL;
+}
+
+WebRtc_Word32
+JpegDecoder::Decode(const WebRtc_UWord8* encodedBuffer,
+ const WebRtc_UWord32 encodedBufferSize,
+ WebRtc_UWord8*& decodedBuffer,
+ WebRtc_UWord32& width,
+ WebRtc_UWord32& 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 (_cinfo->is_decompressor)
+ {
+ jpeg_destroy_decompress(_cinfo);
+ }
+ return -1;
+ }
+
+ _cinfo->out_color_space = JCS_YCbCr;
+
+ // Create decompression object
+ jpeg_create_decompress(_cinfo);
+
+ // Specify data source
+ jpegSetSrcBuffer(_cinfo, (JOCTET*) encodedBuffer, encodedBufferSize);
+
+ // 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
+ }
+
+ height = _cinfo->image_height;
+ width = _cinfo->image_width;
+
+ // Making sure width and height are even
+ if (height % 2)
+ height++;
+ if (width % 2)
+ width++;
+
+ WebRtc_UWord32 height16 = ((height + 15) - 16) & - 16;
+ height16 = (height16 < height) ? height16 + 16 : height16;
+
+ // allocate buffer to output
+ if (decodedBuffer != NULL)
+ {
+ delete [] decodedBuffer;
+ decodedBuffer = NULL;
+ }
+ decodedBuffer = new WebRtc_UWord8[width * height16 * 3 >> 1];
+ if (decodedBuffer == NULL)
+ {
+ return -1;
+ }
+
+ 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] = decodedBuffer + width * (i + hInd);
+
+ if (i % 2 == 0)
+ {
+ u[i / 2] = decodedBuffer + width * height +
+ width / 2 * ((i + hInd) / 2);
+ v[i / 2] = decodedBuffer + width * height +
+ width * height / 4 + width / 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)
+ {
+ delete [] decodedBuffer;
+ jpeg_abort((j_common_ptr)_cinfo);
+ return -1;
+ }
+ }
+
+ jpeg_finish_decompress(_cinfo);
+ jpeg_destroy_decompress(_cinfo);
+ return 0;
+}
+
+
+}
diff --git a/common_video/jpeg/main/source/jpeg.gyp b/common_video/jpeg/main/source/jpeg.gyp
new file mode 100644
index 0000000..ad5419e
--- /dev/null
+++ b/common_video/jpeg/main/source/jpeg.gyp
@@ -0,0 +1,98 @@
+# 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.
+
+{
+ 'includes': [
+ '../../../../common_settings.gypi', # Common settings
+ ],
+ 'targets': [
+ {
+ 'target_name': 'webrtc_jpeg',
+ 'type': '<(library)',
+ 'dependencies': [
+ '../../../vplib/main/source/vplib.gyp:webrtc_vplib',
+ ],
+ 'include_dirs': [
+ '../interface',
+ '../../../../../../',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../interface',
+ ],
+ },
+ 'conditions': [
+ ['build_with_chromium==1', {
+ 'dependencies': [
+ '../../../../../libjpeg_turbo/libjpeg.gyp:libjpeg',
+ ],
+ 'include_dirs': [
+ '../../../../../libjpeg_turbo',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../../../../../libjpeg_turbo',
+ ],
+ },
+ },{
+ 'dependencies': [
+ '../../../../../third_party/libjpeg_turbo/libjpeg.gyp:libjpeg',
+ ],
+ 'include_dirs': [
+ '../../../../third_party/libjpeg_turbo',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../../../../third_party/libjpeg_turbo',
+ ],
+ },
+ }],
+ ],
+ 'sources': [
+ # interfaces
+ '../interface/jpeg.h',
+
+ # headers
+ 'data_manager.h',
+
+ # sources
+ 'jpeg.cc',
+ 'data_manager.cc',
+ ],
+ },
+ {
+ 'target_name': 'jpeg_test',
+ 'type': 'executable',
+ 'dependencies': [
+ 'webrtc_jpeg',
+ ],
+ 'include_dirs': [
+ '../interface',
+ '../../../vplib/main/interface',
+ '../source',
+ ],
+ 'sources': [
+
+ # headers
+ '../test/test_buffer.h',
+
+
+ # sources
+ '../test/test_buffer.cc',
+ '../test/test_jpeg.cc',
+
+ ], # source
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/common_video/jpeg/main/test/test_buffer.cc b/common_video/jpeg/main/test/test_buffer.cc
new file mode 100644
index 0000000..98468f2
--- /dev/null
+++ b/common_video/jpeg/main/test/test_buffer.cc
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+// system includes
+#include <assert.h>
+#include <string.h> // memcpy
+
+#include "test_buffer.h"
+#include "vplib.h"
+
+TestBuffer::TestBuffer():
+_buffer(0),
+_bufferSize(0),
+_bufferLength(0),
+_width(0),
+_height(0)
+{
+ //
+}
+
+TestBuffer::~TestBuffer()
+{
+ _bufferLength = 0;
+ _bufferSize = 0;
+ if(_buffer)
+ {
+ delete [] _buffer;
+ _buffer = 0;
+ }
+}
+
+TestBuffer::TestBuffer(const TestBuffer& rhs)
+:
+_bufferLength(rhs._bufferLength),
+_bufferSize(rhs._bufferSize),
+_height(rhs._height),
+_width(rhs._width),
+_buffer(0)
+{
+ // make sure that our buffer is big enough
+ _buffer = new WebRtc_UWord8[_bufferSize];
+ // only copy required length
+ memcpy(_buffer, rhs._buffer, _bufferLength);
+}
+
+WebRtc_UWord32
+TestBuffer::GetWidth() const
+{
+ return _width;
+}
+
+WebRtc_UWord32
+TestBuffer::GetHeight() const
+{
+ return _height;
+}
+
+void
+TestBuffer::SetWidth(WebRtc_UWord32 width)
+{
+ _width = width;
+}
+
+void
+TestBuffer::SetHeight(WebRtc_UWord32 height)
+{
+ _height = height;
+}
+
+void
+TestBuffer::Free()
+{
+ _bufferLength = 0;
+ _bufferSize = 0;
+ _height = 0;
+ _width = 0;
+ if(_buffer)
+ {
+ delete [] _buffer;
+ _buffer = 0;
+ }
+}
+
+void
+TestBuffer::VerifyAndAllocate(WebRtc_UWord32 minimumSize)
+{
+ if(minimumSize > _bufferSize)
+ {
+ // make sure that our buffer is big enough
+ WebRtc_UWord8 * newBufferBuffer = new WebRtc_UWord8[minimumSize];
+ if(_buffer)
+ {
+ // copy the old data
+ memcpy(newBufferBuffer, _buffer, _bufferSize);
+ delete [] _buffer;
+ }
+ _buffer = newBufferBuffer;
+ _bufferSize = minimumSize;
+ }
+}
+
+void
+TestBuffer::UpdateLength(WebRtc_UWord32 newLength)
+{
+ assert(newLength <= _bufferSize);
+ _bufferLength = newLength;
+}
+
+void
+TestBuffer::CopyBuffer(WebRtc_UWord32 length, const WebRtc_UWord8* buffer)
+{
+ assert(length <= _bufferSize);
+ memcpy(_buffer, buffer, length);
+ _bufferLength = length;
+}
+
+void
+TestBuffer::CopyBuffer(TestBuffer& fromVideoBuffer)
+{
+ assert(fromVideoBuffer.GetLength() <= _bufferSize);
+ assert(fromVideoBuffer.GetSize() <= _bufferSize);
+ _bufferLength = fromVideoBuffer.GetLength();
+ _height = fromVideoBuffer.GetHeight();
+ _width = fromVideoBuffer.GetWidth();
+ memcpy(_buffer, fromVideoBuffer.GetBuffer(), fromVideoBuffer.GetLength());
+}
+
+void
+TestBuffer::Set(WebRtc_UWord8* tempBuffer,WebRtc_UWord32 tempSize, WebRtc_UWord32 tempLength)
+{
+ _buffer = tempBuffer;
+ _bufferSize = tempSize;
+ _bufferLength = tempLength;
+
+}
+
+WebRtc_UWord8*
+TestBuffer::GetBuffer() const
+{
+ return _buffer;
+}
+
+WebRtc_UWord32
+TestBuffer::GetSize() const
+{
+ return _bufferSize;
+}
+
+WebRtc_UWord32
+TestBuffer::GetLength() const
+{
+ return _bufferLength;
+}
+
diff --git a/common_video/jpeg/main/test/test_buffer.h b/common_video/jpeg/main/test/test_buffer.h
new file mode 100644
index 0000000..757fae3
--- /dev/null
+++ b/common_video/jpeg/main/test/test_buffer.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+
+#ifndef WEBRTC_COMMON_VIDEO_JPEG_TEST_BUFFER_H
+#define WEBRTC_COMMON_VIDEO_JPEG_TEST_BUFFER_H
+
+#include "typedefs.h"
+
+class TestBuffer
+{
+public:
+ TestBuffer();
+
+ virtual ~TestBuffer();
+
+ TestBuffer(const TestBuffer& rhs);
+
+ /**
+ * Verifies that current allocated buffer size is larger than or equal to the input size.
+ * If the current buffer size is smaller, a new allocation is made and the old buffer data is copied to the new buffer.
+ */
+ void VerifyAndAllocate(WebRtc_UWord32 minimumSize);
+
+ void UpdateLength(WebRtc_UWord32 newLength);
+
+
+
+ void CopyBuffer(WebRtc_UWord32 length, const WebRtc_UWord8* fromBuffer);
+
+ void CopyBuffer(TestBuffer& fromBuffer);
+
+ void Free(); // Deletes frame buffer and resets members to zero
+
+ /**
+ * Gets pointer to frame buffer
+ */
+ WebRtc_UWord8* GetBuffer() const;
+
+ /**
+ * Gets allocated buffer size
+ */
+ WebRtc_UWord32 GetSize() const;
+
+ /**
+ * Gets length of frame
+ */
+ WebRtc_UWord32 GetLength() const;
+
+
+ WebRtc_UWord32 GetWidth() const;
+ WebRtc_UWord32 GetHeight() const;
+
+ void SetWidth(WebRtc_UWord32 width);
+ void SetHeight(WebRtc_UWord32 height);
+
+private:
+ // TestBuffer& operator=(const TestBuffer& inBuffer);
+
+private:
+ void Set(WebRtc_UWord8* buffer,WebRtc_UWord32 size,WebRtc_UWord32 length);
+
+ WebRtc_UWord8* _buffer; // Pointer to frame buffer
+ WebRtc_UWord32 _bufferSize; // Allocated buffer size
+ WebRtc_UWord32 _bufferLength; // Length (in bytes) of frame
+ WebRtc_UWord32 _width;
+ WebRtc_UWord32 _height;
+};
+
+#endif
diff --git a/common_video/jpeg/main/test/test_jpeg.cc b/common_video/jpeg/main/test/test_jpeg.cc
new file mode 100644
index 0000000..a947dbd
--- /dev/null
+++ b/common_video/jpeg/main/test/test_jpeg.cc
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+/*
+ * test_jpeg.cc
+ */
+
+#include <cassert>
+#include <iostream>
+#include <cmath>
+#include <string>
+#include <stdio.h>
+
+
+#include "test_buffer.h"
+#include "jpeg.h"
+
+using namespace webrtc;
+
+#define PRINT_LINE std::cout << "-------------------------------" << std::endl;
+
+int
+main(int argc, char **argv)
+{
+ if (argc < 1)
+ {
+ return -1;
+ }
+ std::string fileName = argv[1];
+ const char* fileNameDec = "TestJpegDec.yuv";
+ const char* fileNameEnc = "TestJpegEnc.jpg";
+
+ std::string str;
+ std::cout << "---------------------" << std::endl;
+ std::cout << "----- Test JPEG -----" << std::endl;
+ std::cout << "---------------------" << std::endl;
+ std::cout << " " << std::endl;
+
+
+ JpegDecoder* JpgDecPtr = new JpegDecoder( );
+
+ // Open input file
+ FILE* openFile = fopen(fileName.c_str(), "rb");
+ assert(openFile != NULL);
+
+ // Get file length
+ fseek(openFile, 0, SEEK_END);
+ int length = ftell(openFile);
+ fseek(openFile, 0, SEEK_SET);
+
+ // Read input file to buffer
+ TestBuffer encodedBuffer;
+ encodedBuffer.VerifyAndAllocate(length);
+ encodedBuffer.UpdateLength(length);
+ fread(encodedBuffer.GetBuffer(), 1, length, openFile);
+ fclose(openFile);
+
+ // ------------------
+ // Decode
+ // ------------------
+
+ TestBuffer imageBuffer;
+ WebRtc_UWord32 width = 0;
+ WebRtc_UWord32 height = 0;
+ WebRtc_UWord8* tmp = NULL;
+ int error = JpgDecPtr->Decode(encodedBuffer.GetBuffer(),
+ encodedBuffer.GetSize(), tmp, width, height);
+
+ std::cout << error << " = Decode(" << fileName.c_str() << ", (" << width <<
+ "x" << height << "))" << std::endl;
+ PRINT_LINE;
+
+ if (error == 0)
+ {
+ int imageBufferSize = width*height*3/2;
+ //update buffer info
+ imageBuffer.VerifyAndAllocate( imageBufferSize);
+ imageBuffer.CopyBuffer(imageBufferSize, tmp);
+ delete [] tmp;
+ // Save decoded image to file
+ FILE* saveFile = fopen(fileNameDec, "wb");
+ fwrite(imageBuffer.GetBuffer(), 1, imageBuffer.GetLength(), saveFile);
+ fclose(saveFile);
+
+ // ------------------
+ // Encode
+ // ------------------
+
+ JpegEncoder* JpegEncoderPtr = new JpegEncoder();
+
+ // Test invalid inputs
+
+ // Test buffer
+ TestBuffer empty;
+
+ int error = JpegEncoderPtr->SetFileName(0);
+ assert(error == -1);
+ error = JpegEncoderPtr->Encode(empty.GetBuffer(), empty.GetSize(),
+ 164, 164);
+ assert(error == -1);
+ error = JpegEncoderPtr->Encode(empty.GetBuffer(), empty.GetSize(),
+ 0, height);
+ assert(error == -1);
+ error = JpegEncoderPtr->Encode(empty.GetBuffer(), empty.GetSize(),
+ width, 0);
+ assert(error == -1);
+
+ error = JpegEncoderPtr->SetFileName(fileNameEnc);
+ assert(error == 0);
+
+ // Actual Encode
+ error = JpegEncoderPtr->Encode(imageBuffer.GetBuffer(),
+ imageBuffer.GetSize(), width, height);
+ assert(error == 0);
+
+ std::cout << error << " = Encode(" << fileNameDec << ")" << std::endl;
+
+ PRINT_LINE;
+
+ delete JpegEncoderPtr;
+ }
+
+ imageBuffer.Free();
+ encodedBuffer.Free();
+ delete JpgDecPtr;
+
+ std::cout << "Verify that the encoded and decoded images look correct."
+ << std::endl;
+ std::cout << "Press enter to quit test...";
+ std::getline(std::cin, str);
+
+ return 0;
+}
+
diff --git a/common_video/vplib/main/interface/interpolator.h b/common_video/vplib/main/interface/interpolator.h
new file mode 100644
index 0000000..70ec4fa
--- /dev/null
+++ b/common_video/vplib/main/interface/interpolator.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/*
+ * interpolator.h
+ * Interface to the WebRTC's interpolation functionality
+ */
+
+#ifndef WEBRTC_COMMON_VIDEO_INTERFACE_INTERPOLATOR_H
+#define WEBRTC_COMMON_VIDEO_INTERFACE_INTERPOLATOR_H
+
+#include "typedefs.h"
+#include "vplib.h"
+
+namespace webrtc
+{
+
+// supported interpolation types
+enum interpolatorType
+{
+ kBilinear
+};
+
+
+class interpolator
+{
+public:
+ interpolator();
+ ~interpolator();
+
+ // Set interpolation properties:
+ //
+ // Return value : 0 if OK,
+ // : -1 - parameter error
+ // : -2 - general error
+ WebRtc_Word32 Set(WebRtc_UWord32 srcWidth, WebRtc_UWord32 srcHeight,
+ WebRtc_UWord32 dstWidth, WebRtc_UWord32 dstHeight,
+ VideoType srcVideoType, VideoType dstVideoType,
+ interpolatorType type);
+
+ // Interpolate frame
+ //
+ // Return value : Height of interpolated frame if OK,
+ // : -1 - parameter error
+ // : -2 - general error
+ WebRtc_Word32 Interpolate(const WebRtc_UWord8* srcFrame,
+ WebRtc_UWord8*& dstFrame);
+
+private:
+
+ // Extract computation method given actual type
+ WebRtc_Word32 Method(interpolatorType type);
+
+ // Determine if the VideoTypes are currently supported
+ WebRtc_Word32 SupportedVideoType(VideoType srcVideoType,
+ VideoType dstVideoType);
+
+ interpolatorType _method;
+ WebRtc_UWord32 _srcWidth;
+ WebRtc_UWord32 _srcHeight;
+ WebRtc_UWord32 _dstWidth;
+ WebRtc_UWord32 _dstHeight;
+};
+
+
+} // namespace webrtc
+
+
+#endif // WEBRTC_COMMON_VIDEO_INTERFACE_INTERPOLATOR_H
diff --git a/common_video/vplib/main/interface/vplib.h b/common_video/vplib/main/interface/vplib.h
new file mode 100644
index 0000000..79f96be
--- /dev/null
+++ b/common_video/vplib/main/interface/vplib.h
@@ -0,0 +1,356 @@
+/*
+ * 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.
+ */
+
+
+#ifndef WEBRTC_COMMON_VIDEO_INTERFACE_VPLIB_H
+#define WEBRTC_COMMON_VIDEO_INTERFACE_VPLIB_H
+
+
+#include "typedefs.h"
+
+namespace webrtc
+{
+
+// Supported video types
+enum VideoType
+{
+ kUnknown,
+ kI420,
+ kIYUV,
+ kRGB24,
+ kARGB,
+ kARGB4444,
+ kRGB565,
+ kARGB1555,
+ kYUY2,
+ kYV12,
+ kUYVY,
+ kMJPG,
+ kNV21,
+ kNV12,
+ kARGBMac,
+ kRGBAMac,
+
+ kNumberOfVideoTypes
+};
+
+
+// Supported rotation
+enum VideoRotationMode
+{
+ kRotateNone = 0,
+ kRotateClockwise = 90,
+ kRotateAntiClockwise = -90,
+ kRotate180 = 180,
+};
+
+
+ // Calculate the required buffer size
+ // Input
+ // - type - The type of the designated video frame
+ // - width - frame width in pixels
+ // - height - frame height in pixels
+ // Output
+ // - The required size in bytes to accommodate the specified video frame
+ //
+ WebRtc_UWord32 CalcBufferSize(VideoType type, WebRtc_UWord32 width, WebRtc_UWord32 height);
+
+
+ // Calculate the required buffer size when converting from one type to another
+ // Input
+ // - incomingVideoType - The type of the existing video frame
+ // - convertedVideoType - width of the designated video frame
+ // - length - length in bytes of the data
+ // Output
+ // - The required size in bytes to accommodate the specified converted video frame
+ //
+ WebRtc_UWord32 CalcBufferSize(VideoType incomingVideoType, VideoType convertedVideoType,
+ WebRtc_UWord32 length);
+
+ //
+ // Convert To/From I420
+ //
+ // The following 2 functions convert an image to/from a I420 type to/from a specified
+ // format.
+ //
+ // Input:
+ // - incomingVideoType : Type of input video
+ // - incomingBuffer : Pointer to an input image.
+ // - width : Image width in pixels.
+ // - height : Image height in pixels.
+ // - outgoingBuffer : Pointer to converted image.
+ // - interlaced : Flag indicating if interlaced I420 output
+ // - rotate : Rotation mode of output image
+ // Return value : Size of converted image if OK, otherwise, the following error
+ // codes:
+ // -1 : Parameter error
+ // -2 : Unsupported command (parameter request)
+ //
+ // Note: the following functions includes the most common usage cases; for a more general
+ // usage, refer to explicit function
+ WebRtc_Word32 ConvertToI420(VideoType incomingVideoType,
+ const WebRtc_UWord8* incomingBuffer,
+ WebRtc_UWord32 width,
+ WebRtc_UWord32 height,
+ WebRtc_UWord8* outgoingBuffer,
+ bool interlaced = false ,
+ VideoRotationMode rotate = kRotateNone
+ );
+
+ WebRtc_Word32 ConvertFromI420(VideoType outgoingVideoType,
+ const WebRtc_UWord8* incomingBuffer,
+ WebRtc_UWord32 width,
+ WebRtc_UWord32 height,
+ WebRtc_UWord8* outgoingBuffer,
+ bool interlaced = false ,
+ VideoRotationMode rotate = kRotateNone
+ );
+
+ // Designated Convert Functions
+ // The following list describes the designated conversion function which are called by the
+ // 2 prior general conversion function.
+ // Input and output descriptions match the above descriptions, and are therefore omitted.
+ WebRtc_Word32 ConvertI420ToRGB24(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertI420ToARGB(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut);
+ WebRtc_Word32 ConvertI420ToARGB4444(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut);
+ WebRtc_Word32 ConvertI420ToRGB565(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertI420ToRGB565Android(const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertI420ToARGB1555(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut);
+ WebRtc_Word32 ConvertI420ToARGBMac(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut);
+ WebRtc_Word32 ConvertI420ToRGBAMac(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut);
+ WebRtc_Word32 ConvertI420ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut = 0);
+ WebRtc_Word32 ConvertI420ToUYVY(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut = 0);
+ WebRtc_Word32 ConvertI420ToYUY2(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut = 0);
+ WebRtc_Word32 ConvertI420ToYV12(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut);
+ WebRtc_Word32 ConvertYUY2ToI420interlaced(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth,
+ WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight);
+ WebRtc_Word32 ConvertYV12ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height, WebRtc_UWord8* outFrame);
+ WebRtc_Word32 ConvertRGB24ToARGB(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut);
+ WebRtc_Word32 ConvertRGB24ToI420(WebRtc_Word32 width, WebRtc_Word32 height,
+ const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame);
+ WebRtc_Word32 ConvertRGB565ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height, WebRtc_UWord8* outFrame);
+ WebRtc_Word32 ConvertARGBMacToI420(WebRtc_UWord32 width, WebRtc_UWord32 height,
+ const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame);
+ WebRtc_Word32 ConvertUYVYToI420(WebRtc_UWord32 width, WebRtc_UWord32 height,
+ const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame);
+
+ // pad cut and convert
+ WebRtc_Word32 ConvertYUY2ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth,
+ WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight);
+ WebRtc_Word32 ConvertUYVYToI420interlaced(const WebRtc_UWord8* inFrame,
+ WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight,
+ WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth,
+ WebRtc_UWord32 outHeight);
+ WebRtc_Word32 ConvertRGB24ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth,
+ WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight);
+ WebRtc_Word32 ConvertI420ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth,
+ WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight);
+
+ //NV12 Conversion/Rotation
+ WebRtc_Word32 ConvertNV12ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertNV12ToI420AndRotate180(const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertNV12ToI420AndRotateAntiClockwise(const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width,
+ WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertNV12ToI420AndRotateClockwise(const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width,
+ WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertNV12ToRGB565(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height);
+
+ //NV21 Conversion/Rotation
+ WebRtc_Word32 ConvertNV21ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertNV21ToI420AndRotate180(const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertNV21ToI420AndRotateAntiClockwise(const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width,
+ WebRtc_UWord32 height);
+ WebRtc_Word32 ConvertNV21ToI420AndRotateClockwise(const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width,
+ WebRtc_UWord32 height);
+
+ //IPhone
+ WebRtc_Word32 ConvertI420ToRGBAIPhone(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord32 strideOut);
+
+ // I420 Cut and Pad - make a center cut
+ WebRtc_Word32 CutI420Frame(WebRtc_UWord8* frame, WebRtc_UWord32 fromWidth,
+ WebRtc_UWord32 fromHeight, WebRtc_UWord32 toWidth,
+ WebRtc_UWord32 toHeight);
+
+ // Pad an I420 frame
+ // Input:
+ // - inBuffer : Pointer to the input image component to be padded.
+ // - outBuffer : Pointer to the output padded image component.
+ // - fromWidth : Width in pixels of the inBuffer component.
+ // - fromHeight : Height in pixels of the inBuffer component.
+ // - toWidth : Width in pixels of the outBuffer component.
+ // - toHeight : Height in pixels of the outBuffer component.
+ // Return Value:
+ // - Length of the output component.
+ WebRtc_Word32 PadI420Frame(const WebRtc_UWord8* inBuffer, WebRtc_UWord8* outBuffer,
+ WebRtc_UWord32 fromWidth, WebRtc_UWord32 fromHeight,
+ WebRtc_UWord32 toWidth, WebRtc_UWord32 toHeight);
+ WebRtc_Word32 PadI420BottomRows(WebRtc_UWord8* buffer, WebRtc_UWord32 size,
+ WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_Word32 nrRows, WebRtc_UWord32& newLength);
+
+ // I420 Scale
+ // Scale an I420 frame:Half frame, quarter frame
+ // Input:
+ // - inFrame : Pointer to the image component to be scaled
+ // - width : Width in pixels of the output frame.
+ // - height : Height in pixels of the out frame.
+ // Return Value:
+ // - Length of the output component.
+ WebRtc_Word32 ScaleI420FrameQuarter(WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord8* inFrame);
+ WebRtc_Word32 ScaleI420DownHalfFrame(WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord8* inFrame);
+ WebRtc_Word32 ScaleI420UpHalfFrame(WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord8* inFrame);
+
+ // Scales up an I420-frame to twice its width and height. Interpolates by using mean value
+ // of neighboring pixels.
+ // The following two function allow up-scaling by either twice or 3/2 of the original
+ // the width and height
+ // Input:
+ // - width : Width of input frame in pixels.
+ // - height : Height of input frame in pixels.
+ // - buffer : Reference to a buffer containing the frame.
+ // - size :Size of allocated buffer
+ // - scaledWidth : Reference to the width of scaled frame in pixels.
+ // - scaledHeight : Reference to the height of scaled frame in pixels.
+ // Return value:
+ // - (length) : Length of scaled frame.
+ // - (-1) : Error.
+ WebRtc_Word32 ScaleI420Up2(WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord8*& buffer, WebRtc_UWord32 size,
+ WebRtc_UWord32 &scaledWidth, WebRtc_UWord32 &scaledHeight);
+ WebRtc_Word32 ScaleI420Up3_2(WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord8*& buffer, WebRtc_UWord32 size,
+ WebRtc_UWord32 &scaledWidth, WebRtc_UWord32 &scaledHeight);
+
+ // Scales down an I420-frame to one third its width and height.
+ // Input:
+ // - width : Width of frame in pixels.
+ // - height : Height of frame in pixels.
+ // - videoBuffer : Reference to a buffer containing the frame.
+ // - scaledWidth : Width of scaled frame in pixels.
+ // - scaledHeight : Height of scaled frame in pixels.
+ // Return value:
+ // - (length) : Length of scaled frame.
+ // - (-1) : Error.
+ WebRtc_Word32 ScaleI420Down1_3(WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord8*& buffer, WebRtc_UWord32 size,
+ WebRtc_UWord32 &scaledWidth, WebRtc_UWord32 &scaledHeight);
+
+ // Convert From I420/YV12 to I420 and Rotate clockwise
+ // Input:
+ // - srcBuffer : Reference to a buffer containing the source frame.
+ // - srcWidth : Width of source frame in pixels.
+ // - srcHeight : Height of source frame in pixels.
+ // - dstBuffer : Reference to a buffer containing the destination frame.
+ // - dstWidth : Width of destination frame in pixels.
+ // - dstHeight : Height of destination frame in pixels.
+ // - colorSpaceIn : Input color space
+ // Return value:
+ // - (length) : Length of scaled frame.
+ // - (-1) : Error.
+ WebRtc_Word32 ConvertToI420AndRotateClockwise(const WebRtc_UWord8* srcBuffer,
+ WebRtc_UWord32 srcWidth,
+ WebRtc_UWord32 srcHeight,
+ WebRtc_UWord8* dstBuffer,
+ WebRtc_UWord32 dstWidth,
+ WebRtc_UWord32 dstHeight,
+ VideoType colorSpaceIn);
+
+ // Convert From I420/YV12 to I420 and Rotate anti clockwise
+ // Inputs/outputs as the above function
+ WebRtc_Word32 ConvertToI420AndRotateAntiClockwise(const WebRtc_UWord8* srcBuffer,
+ WebRtc_UWord32 srcWidth,
+ WebRtc_UWord32 srcHeight,
+ WebRtc_UWord8* dstBuffer,
+ WebRtc_UWord32 dstWidth,
+ WebRtc_UWord32 dstHeight,
+ VideoType colorSpaceIn);
+
+ // Mirror functions
+ // The following 2 functions perform mirroring on a given image (LeftRight/UpDown)
+ // Input:
+ // - width : Image width in pixels.
+ // - height : Image height in pixels.
+ // - inFrame : Reference to input image.
+ // - outFrame : Reference to converted image.
+ // Return value: 0 if OK, < 0 otherwise.
+ WebRtc_Word32 MirrorI420LeftRight(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height);
+ WebRtc_Word32 MirrorI420UpDown(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height);
+
+ // Mirror functions - Don't work in place (srcBuffer == dstBuffer),
+ // and are therefore faster. Also combine mirroring with conversion to speed things up.
+ // Input:
+ // - srcBuffer : Pointer to source image.
+ // - dstBuffer : Pointer to destination image.
+ // - srcWidth : Width of input buffer.
+ // - srcHeight : Height of input buffer.
+ // - colorSpaceIn : Color space to convert from, I420 if no conversion should be done
+ // - dstBuffer : Pointer to converted/rotated image.
+ // Return value: 0 if OK, < 0 otherwise.
+ WebRtc_Word32 ConvertToI420AndMirrorUpDown(const WebRtc_UWord8* srcBuffer,
+ WebRtc_UWord8* dstBuffer,
+ WebRtc_UWord32 srcWidth,
+ WebRtc_UWord32 srcHeight,
+ VideoType colorSpaceIn = kI420);
+
+}
+
+#endif
diff --git a/common_video/vplib/main/source/conversion_tables.h b/common_video/vplib/main/source/conversion_tables.h
new file mode 100644
index 0000000..4f3b1ec
--- /dev/null
+++ b/common_video/vplib/main/source/conversion_tables.h
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+/**************************************************************
+* conversion_tables.h
+*
+* Pre-compiled definitions of the conversion equations: YUV -> RGB.
+*
+***************************************************************/
+
+#ifndef WEBRTC_COMMON_VIDEO_VPLIB_CONVERSION_TABLES
+#define WEBRTC_COMMON_VIDEO_VPLIB_CONVERSION_TABLES
+
+#include "typedefs.h"
+namespace webrtc
+{
+/*********************************************************************************************
+* YUV TO RGB approximation
+*
+* R = clip( (298 * (Y - 16) + 409 * (V - 128) + 128 ) >> 8 )
+* G = clip( (298 * (Y - 16) - 100 * (U - 128) - 208 * (V - 128) + 128 ) >> 8 )
+* B = clip( (298 * (Y - 16) + 516 * (U - 128) + 128 ) >> 8 )
+**********************************************************************************************/
+
+ #define Yc(i) static_cast<WebRtc_Word32> ( 298 * ( i - 16 )) // Y contribution
+ #define Ucg(i) static_cast<WebRtc_Word32> ( -100 * ( i - 128 )) // U contribution to G
+ #define Ucb(i) static_cast<WebRtc_Word32> ( 516 * ( i - 128 )) // U contribution to B
+ #define Vcr(i) static_cast<WebRtc_Word32> ( 409 * ( i - 128 )) // V contribution to R
+ #define Vcg(i) static_cast<WebRtc_Word32> ( -208 * ( i - 128 )) // V contribution to G
+
+ static const WebRtc_Word32 mapYc[256] = {
+ Yc(0),Yc(1),Yc(2),Yc(3),Yc(4),Yc(5),Yc(6),Yc(7),Yc(8),Yc(9),
+ Yc(10),Yc(11),Yc(12),Yc(13),Yc(14),Yc(15),Yc(16),Yc(17),Yc(18),Yc(19),
+ Yc(20),Yc(21),Yc(22),Yc(23),Yc(24),Yc(25),Yc(26),Yc(27),Yc(28),Yc(29),
+ Yc(30),Yc(31),Yc(32),Yc(33),Yc(34),Yc(35),Yc(36),Yc(37),Yc(38),Yc(39),
+ Yc(40),Yc(41),Yc(42),Yc(43),Yc(44),Yc(45),Yc(46),Yc(47),Yc(48),Yc(49),
+ Yc(50),Yc(51),Yc(52),Yc(53),Yc(54),Yc(55),Yc(56),Yc(57),Yc(58),Yc(59),
+ Yc(60),Yc(61),Yc(62),Yc(63),Yc(64),Yc(65),Yc(66),Yc(67),Yc(68),Yc(69),
+ Yc(70),Yc(71),Yc(72),Yc(73),Yc(74),Yc(75),Yc(76),Yc(77),Yc(78),Yc(79),
+ Yc(80),Yc(81),Yc(82),Yc(83),Yc(84),Yc(85),Yc(86),Yc(87),Yc(88),Yc(89),
+ Yc(90),Yc(91),Yc(92),Yc(93),Yc(94),Yc(95),Yc(96),Yc(97),Yc(98),Yc(99),
+ Yc(100),Yc(101),Yc(102),Yc(103),Yc(104),Yc(105),Yc(106),Yc(107),Yc(108),Yc(109),
+ Yc(110),Yc(111),Yc(112),Yc(113),Yc(114),Yc(115),Yc(116),Yc(117),Yc(118),Yc(119),
+ Yc(120),Yc(121),Yc(122),Yc(123),Yc(124),Yc(125),Yc(126),Yc(127),Yc(128),Yc(129),
+ Yc(130),Yc(131),Yc(132),Yc(133),Yc(134),Yc(135),Yc(136),Yc(137),Yc(138),Yc(139),
+ Yc(140),Yc(141),Yc(142),Yc(143),Yc(144),Yc(145),Yc(146),Yc(147),Yc(148),Yc(149),
+ Yc(150),Yc(151),Yc(152),Yc(153),Yc(154),Yc(155),Yc(156),Yc(157),Yc(158),Yc(159),
+ Yc(160),Yc(161),Yc(162),Yc(163),Yc(164),Yc(165),Yc(166),Yc(167),Yc(168),Yc(169),
+ Yc(170),Yc(171),Yc(172),Yc(173),Yc(174),Yc(175),Yc(176),Yc(177),Yc(178),Yc(179),
+ Yc(180),Yc(181),Yc(182),Yc(183),Yc(184),Yc(185),Yc(186),Yc(187),Yc(188),Yc(189),
+ Yc(190),Yc(191),Yc(192),Yc(193),Yc(194),Yc(195),Yc(196),Yc(197),Yc(198),Yc(199),
+ Yc(200),Yc(201),Yc(202),Yc(203),Yc(204),Yc(205),Yc(206),Yc(207),Yc(208),Yc(209),
+ Yc(210),Yc(211),Yc(212),Yc(213),Yc(214),Yc(215),Yc(216),Yc(217),Yc(218),Yc(219),
+ Yc(220),Yc(221),Yc(222),Yc(223),Yc(224),Yc(225),Yc(226),Yc(227),Yc(228),Yc(229),
+ Yc(230),Yc(231),Yc(232),Yc(233),Yc(234),Yc(235),Yc(236),Yc(237),Yc(238),Yc(239),
+ Yc(240),Yc(241),Yc(242),Yc(243),Yc(244),Yc(245),Yc(246),Yc(247),Yc(248),Yc(249),
+ Yc(250),Yc(251),Yc(252),Yc(253),Yc(254),Yc(255)};
+
+ static const WebRtc_Word32 mapUcg[256] = {
+ Ucg(0),Ucg(1),Ucg(2),Ucg(3),Ucg(4),Ucg(5),Ucg(6),Ucg(7),Ucg(8),Ucg(9),
+ Ucg(10),Ucg(11),Ucg(12),Ucg(13),Ucg(14),Ucg(15),Ucg(16),Ucg(17),Ucg(18),Ucg(19),
+ Ucg(20),Ucg(21),Ucg(22),Ucg(23),Ucg(24),Ucg(25),Ucg(26),Ucg(27),Ucg(28),Ucg(29),
+ Ucg(30),Ucg(31),Ucg(32),Ucg(33),Ucg(34),Ucg(35),Ucg(36),Ucg(37),Ucg(38),Ucg(39),
+ Ucg(40),Ucg(41),Ucg(42),Ucg(43),Ucg(44),Ucg(45),Ucg(46),Ucg(47),Ucg(48),Ucg(49),
+ Ucg(50),Ucg(51),Ucg(52),Ucg(53),Ucg(54),Ucg(55),Ucg(56),Ucg(57),Ucg(58),Ucg(59),
+ Ucg(60),Ucg(61),Ucg(62),Ucg(63),Ucg(64),Ucg(65),Ucg(66),Ucg(67),Ucg(68),Ucg(69),
+ Ucg(70),Ucg(71),Ucg(72),Ucg(73),Ucg(74),Ucg(75),Ucg(76),Ucg(77),Ucg(78),Ucg(79),
+ Ucg(80),Ucg(81),Ucg(82),Ucg(83),Ucg(84),Ucg(85),Ucg(86),Ucg(87),Ucg(88),Ucg(89),
+ Ucg(90),Ucg(91),Ucg(92),Ucg(93),Ucg(94),Ucg(95),Ucg(96),Ucg(97),Ucg(98),Ucg(99),
+ Ucg(100),Ucg(101),Ucg(102),Ucg(103),Ucg(104),Ucg(105),Ucg(106),Ucg(107),Ucg(108),Ucg(109),
+ Ucg(110),Ucg(111),Ucg(112),Ucg(113),Ucg(114),Ucg(115),Ucg(116),Ucg(117),Ucg(118),Ucg(119),
+ Ucg(120),Ucg(121),Ucg(122),Ucg(123),Ucg(124),Ucg(125),Ucg(126),Ucg(127),Ucg(128),Ucg(129),
+ Ucg(130),Ucg(131),Ucg(132),Ucg(133),Ucg(134),Ucg(135),Ucg(136),Ucg(137),Ucg(138),Ucg(139),
+ Ucg(140),Ucg(141),Ucg(142),Ucg(143),Ucg(144),Ucg(145),Ucg(146),Ucg(147),Ucg(148),Ucg(149),
+ Ucg(150),Ucg(151),Ucg(152),Ucg(153),Ucg(154),Ucg(155),Ucg(156),Ucg(157),Ucg(158),Ucg(159),
+ Ucg(160),Ucg(161),Ucg(162),Ucg(163),Ucg(164),Ucg(165),Ucg(166),Ucg(167),Ucg(168),Ucg(169),
+ Ucg(170),Ucg(171),Ucg(172),Ucg(173),Ucg(174),Ucg(175),Ucg(176),Ucg(177),Ucg(178),Ucg(179),
+ Ucg(180),Ucg(181),Ucg(182),Ucg(183),Ucg(184),Ucg(185),Ucg(186),Ucg(187),Ucg(188),Ucg(189),
+ Ucg(190),Ucg(191),Ucg(192),Ucg(193),Ucg(194),Ucg(195),Ucg(196),Ucg(197),Ucg(198),Ucg(199),
+ Ucg(200),Ucg(201),Ucg(202),Ucg(203),Ucg(204),Ucg(205),Ucg(206),Ucg(207),Ucg(208),Ucg(209),
+ Ucg(210),Ucg(211),Ucg(212),Ucg(213),Ucg(214),Ucg(215),Ucg(216),Ucg(217),Ucg(218),Ucg(219),
+ Ucg(220),Ucg(221),Ucg(222),Ucg(223),Ucg(224),Ucg(225),Ucg(226),Ucg(227),Ucg(228),Ucg(229),
+ Ucg(230),Ucg(231),Ucg(232),Ucg(233),Ucg(234),Ucg(235),Ucg(236),Ucg(237),Ucg(238),Ucg(239),
+ Ucg(240),Ucg(241),Ucg(242),Ucg(243),Ucg(244),Ucg(245),Ucg(246),Ucg(247),Ucg(248),Ucg(249),
+ Ucg(250),Ucg(251),Ucg(252),Ucg(253),Ucg(254),Ucg(255)};
+
+
+ static const WebRtc_Word32 mapUcb[256] = {
+ Ucb(0),Ucb(1),Ucb(2),Ucb(3),Ucb(4),Ucb(5),Ucb(6),Ucb(7),Ucb(8),Ucb(9),
+ Ucb(10),Ucb(11),Ucb(12),Ucb(13),Ucb(14),Ucb(15),Ucb(16),Ucb(17),Ucb(18),Ucb(19),
+ Ucb(20),Ucb(21),Ucb(22),Ucb(23),Ucb(24),Ucb(25),Ucb(26),Ucb(27),Ucb(28),Ucb(29),
+ Ucb(30),Ucb(31),Ucb(32),Ucb(33),Ucb(34),Ucb(35),Ucb(36),Ucb(37),Ucb(38),Ucb(39),
+ Ucb(40),Ucb(41),Ucb(42),Ucb(43),Ucb(44),Ucb(45),Ucb(46),Ucb(47),Ucb(48),Ucb(49),
+ Ucb(50),Ucb(51),Ucb(52),Ucb(53),Ucb(54),Ucb(55),Ucb(56),Ucb(57),Ucb(58),Ucb(59),
+ Ucb(60),Ucb(61),Ucb(62),Ucb(63),Ucb(64),Ucb(65),Ucb(66),Ucb(67),Ucb(68),Ucb(69),
+ Ucb(70),Ucb(71),Ucb(72),Ucb(73),Ucb(74),Ucb(75),Ucb(76),Ucb(77),Ucb(78),Ucb(79),
+ Ucb(80),Ucb(81),Ucb(82),Ucb(83),Ucb(84),Ucb(85),Ucb(86),Ucb(87),Ucb(88),Ucb(89),
+ Ucb(90),Ucb(91),Ucb(92),Ucb(93),Ucb(94),Ucb(95),Ucb(96),Ucb(97),Ucb(98),Ucb(99),
+ Ucb(100),Ucb(101),Ucb(102),Ucb(103),Ucb(104),Ucb(105),Ucb(106),Ucb(107),Ucb(108),Ucb(109),
+ Ucb(110),Ucb(111),Ucb(112),Ucb(113),Ucb(114),Ucb(115),Ucb(116),Ucb(117),Ucb(118),Ucb(119),
+ Ucb(120),Ucb(121),Ucb(122),Ucb(123),Ucb(124),Ucb(125),Ucb(126),Ucb(127),Ucb(128),Ucb(129),
+ Ucb(130),Ucb(131),Ucb(132),Ucb(133),Ucb(134),Ucb(135),Ucb(136),Ucb(137),Ucb(138),Ucb(139),
+ Ucb(140),Ucb(141),Ucb(142),Ucb(143),Ucb(144),Ucb(145),Ucb(146),Ucb(147),Ucb(148),Ucb(149),
+ Ucb(150),Ucb(151),Ucb(152),Ucb(153),Ucb(154),Ucb(155),Ucb(156),Ucb(157),Ucb(158),Ucb(159),
+ Ucb(160),Ucb(161),Ucb(162),Ucb(163),Ucb(164),Ucb(165),Ucb(166),Ucb(167),Ucb(168),Ucb(169),
+ Ucb(170),Ucb(171),Ucb(172),Ucb(173),Ucb(174),Ucb(175),Ucb(176),Ucb(177),Ucb(178),Ucb(179),
+ Ucb(180),Ucb(181),Ucb(182),Ucb(183),Ucb(184),Ucb(185),Ucb(186),Ucb(187),Ucb(188),Ucb(189),
+ Ucb(190),Ucb(191),Ucb(192),Ucb(193),Ucb(194),Ucb(195),Ucb(196),Ucb(197),Ucb(198),Ucb(199),
+ Ucb(200),Ucb(201),Ucb(202),Ucb(203),Ucb(204),Ucb(205),Ucb(206),Ucb(207),Ucb(208),Ucb(209),
+ Ucb(210),Ucb(211),Ucb(212),Ucb(213),Ucb(214),Ucb(215),Ucb(216),Ucb(217),Ucb(218),Ucb(219),
+ Ucb(220),Ucb(221),Ucb(222),Ucb(223),Ucb(224),Ucb(225),Ucb(226),Ucb(227),Ucb(228),Ucb(229),
+ Ucb(230),Ucb(231),Ucb(232),Ucb(233),Ucb(234),Ucb(235),Ucb(236),Ucb(237),Ucb(238),Ucb(239),
+ Ucb(240),Ucb(241),Ucb(242),Ucb(243),Ucb(244),Ucb(245),Ucb(246),Ucb(247),Ucb(248),Ucb(249),
+ Ucb(250),Ucb(251),Ucb(252),Ucb(253),Ucb(254),Ucb(255)};
+
+ static const WebRtc_Word32 mapVcr[256] = {
+ Vcr(0),Vcr(1),Vcr(2),Vcr(3),Vcr(4),Vcr(5),Vcr(6),Vcr(7),Vcr(8),Vcr(9),
+ Vcr(10),Vcr(11),Vcr(12),Vcr(13),Vcr(14),Vcr(15),Vcr(16),Vcr(17),Vcr(18),Vcr(19),
+ Vcr(20),Vcr(21),Vcr(22),Vcr(23),Vcr(24),Vcr(25),Vcr(26),Vcr(27),Vcr(28),Vcr(29),
+ Vcr(30),Vcr(31),Vcr(32),Vcr(33),Vcr(34),Vcr(35),Vcr(36),Vcr(37),Vcr(38),Vcr(39),
+ Vcr(40),Vcr(41),Vcr(42),Vcr(43),Vcr(44),Vcr(45),Vcr(46),Vcr(47),Vcr(48),Vcr(49),
+ Vcr(50),Vcr(51),Vcr(52),Vcr(53),Vcr(54),Vcr(55),Vcr(56),Vcr(57),Vcr(58),Vcr(59),
+ Vcr(60),Vcr(61),Vcr(62),Vcr(63),Vcr(64),Vcr(65),Vcr(66),Vcr(67),Vcr(68),Vcr(69),
+ Vcr(70),Vcr(71),Vcr(72),Vcr(73),Vcr(74),Vcr(75),Vcr(76),Vcr(77),Vcr(78),Vcr(79),
+ Vcr(80),Vcr(81),Vcr(82),Vcr(83),Vcr(84),Vcr(85),Vcr(86),Vcr(87),Vcr(88),Vcr(89),
+ Vcr(90),Vcr(91),Vcr(92),Vcr(93),Vcr(94),Vcr(95),Vcr(96),Vcr(97),Vcr(98),Vcr(99),
+ Vcr(100),Vcr(101),Vcr(102),Vcr(103),Vcr(104),Vcr(105),Vcr(106),Vcr(107),Vcr(108),Vcr(109),
+ Vcr(110),Vcr(111),Vcr(112),Vcr(113),Vcr(114),Vcr(115),Vcr(116),Vcr(117),Vcr(118),Vcr(119),
+ Vcr(120),Vcr(121),Vcr(122),Vcr(123),Vcr(124),Vcr(125),Vcr(126),Vcr(127),Vcr(128),Vcr(129),
+ Vcr(130),Vcr(131),Vcr(132),Vcr(133),Vcr(134),Vcr(135),Vcr(136),Vcr(137),Vcr(138),Vcr(139),
+ Vcr(140),Vcr(141),Vcr(142),Vcr(143),Vcr(144),Vcr(145),Vcr(146),Vcr(147),Vcr(148),Vcr(149),
+ Vcr(150),Vcr(151),Vcr(152),Vcr(153),Vcr(154),Vcr(155),Vcr(156),Vcr(157),Vcr(158),Vcr(159),
+ Vcr(160),Vcr(161),Vcr(162),Vcr(163),Vcr(164),Vcr(165),Vcr(166),Vcr(167),Vcr(168),Vcr(169),
+ Vcr(170),Vcr(171),Vcr(172),Vcr(173),Vcr(174),Vcr(175),Vcr(176),Vcr(177),Vcr(178),Vcr(179),
+ Vcr(180),Vcr(181),Vcr(182),Vcr(183),Vcr(184),Vcr(185),Vcr(186),Vcr(187),Vcr(188),Vcr(189),
+ Vcr(190),Vcr(191),Vcr(192),Vcr(193),Vcr(194),Vcr(195),Vcr(196),Vcr(197),Vcr(198),Vcr(199),
+ Vcr(200),Vcr(201),Vcr(202),Vcr(203),Vcr(204),Vcr(205),Vcr(206),Vcr(207),Vcr(208),Vcr(209),
+ Vcr(210),Vcr(211),Vcr(212),Vcr(213),Vcr(214),Vcr(215),Vcr(216),Vcr(217),Vcr(218),Vcr(219),
+ Vcr(220),Vcr(221),Vcr(222),Vcr(223),Vcr(224),Vcr(225),Vcr(226),Vcr(227),Vcr(228),Vcr(229),
+ Vcr(230),Vcr(231),Vcr(232),Vcr(233),Vcr(234),Vcr(235),Vcr(236),Vcr(237),Vcr(238),Vcr(239),
+ Vcr(240),Vcr(241),Vcr(242),Vcr(243),Vcr(244),Vcr(245),Vcr(246),Vcr(247),Vcr(248),Vcr(249),
+ Vcr(250),Vcr(251),Vcr(252),Vcr(253),Vcr(254),Vcr(255)};
+
+
+ static const WebRtc_Word32 mapVcg[256] = {
+ Vcg(0),Vcg(1),Vcg(2),Vcg(3),Vcg(4),Vcg(5),Vcg(6),Vcg(7),Vcg(8),Vcg(9),
+ Vcg(10),Vcg(11),Vcg(12),Vcg(13),Vcg(14),Vcg(15),Vcg(16),Vcg(17),Vcg(18),Vcg(19),
+ Vcg(20),Vcg(21),Vcg(22),Vcg(23),Vcg(24),Vcg(25),Vcg(26),Vcg(27),Vcg(28),Vcg(29),
+ Vcg(30),Vcg(31),Vcg(32),Vcg(33),Vcg(34),Vcg(35),Vcg(36),Vcg(37),Vcg(38),Vcg(39),
+ Vcg(40),Vcg(41),Vcg(42),Vcg(43),Vcg(44),Vcg(45),Vcg(46),Vcg(47),Vcg(48),Vcg(49),
+ Vcg(50),Vcg(51),Vcg(52),Vcg(53),Vcg(54),Vcg(55),Vcg(56),Vcg(57),Vcg(58),Vcg(59),
+ Vcg(60),Vcg(61),Vcg(62),Vcg(63),Vcg(64),Vcg(65),Vcg(66),Vcg(67),Vcg(68),Vcg(69),
+ Vcg(70),Vcg(71),Vcg(72),Vcg(73),Vcg(74),Vcg(75),Vcg(76),Vcg(77),Vcg(78),Vcg(79),
+ Vcg(80),Vcg(81),Vcg(82),Vcg(83),Vcg(84),Vcg(85),Vcg(86),Vcg(87),Vcg(88),Vcg(89),
+ Vcg(90),Vcg(91),Vcg(92),Vcg(93),Vcg(94),Vcg(95),Vcg(96),Vcg(97),Vcg(98),Vcg(99),
+ Vcg(100),Vcg(101),Vcg(102),Vcg(103),Vcg(104),Vcg(105),Vcg(106),Vcg(107),Vcg(108),Vcg(109),
+ Vcg(110),Vcg(111),Vcg(112),Vcg(113),Vcg(114),Vcg(115),Vcg(116),Vcg(117),Vcg(118),Vcg(119),
+ Vcg(120),Vcg(121),Vcg(122),Vcg(123),Vcg(124),Vcg(125),Vcg(126),Vcg(127),Vcg(128),Vcg(129),
+ Vcg(130),Vcg(131),Vcg(132),Vcg(133),Vcg(134),Vcg(135),Vcg(136),Vcg(137),Vcg(138),Vcg(139),
+ Vcg(140),Vcg(141),Vcg(142),Vcg(143),Vcg(144),Vcg(145),Vcg(146),Vcg(147),Vcg(148),Vcg(149),
+ Vcg(150),Vcg(151),Vcg(152),Vcg(153),Vcg(154),Vcg(155),Vcg(156),Vcg(157),Vcg(158),Vcg(159),
+ Vcg(160),Vcg(161),Vcg(162),Vcg(163),Vcg(164),Vcg(165),Vcg(166),Vcg(167),Vcg(168),Vcg(169),
+ Vcg(170),Vcg(171),Vcg(172),Vcg(173),Vcg(174),Vcg(175),Vcg(176),Vcg(177),Vcg(178),Vcg(179),
+ Vcg(180),Vcg(181),Vcg(182),Vcg(183),Vcg(184),Vcg(185),Vcg(186),Vcg(187),Vcg(188),Vcg(189),
+ Vcg(190),Vcg(191),Vcg(192),Vcg(193),Vcg(194),Vcg(195),Vcg(196),Vcg(197),Vcg(198),Vcg(199),
+ Vcg(200),Vcg(201),Vcg(202),Vcg(203),Vcg(204),Vcg(205),Vcg(206),Vcg(207),Vcg(208),Vcg(209),
+ Vcg(210),Vcg(211),Vcg(212),Vcg(213),Vcg(214),Vcg(215),Vcg(216),Vcg(217),Vcg(218),Vcg(219),
+ Vcg(220),Vcg(221),Vcg(222),Vcg(223),Vcg(224),Vcg(225),Vcg(226),Vcg(227),Vcg(228),Vcg(229),
+ Vcg(230),Vcg(231),Vcg(232),Vcg(233),Vcg(234),Vcg(235),Vcg(236),Vcg(237),Vcg(238),Vcg(239),
+ Vcg(240),Vcg(241),Vcg(242),Vcg(243),Vcg(244),Vcg(245),Vcg(246),Vcg(247),Vcg(248),Vcg(249),
+ Vcg(250),Vcg(251),Vcg(252),Vcg(253),Vcg(254),Vcg(255)};
+
+}
+#endif
+
diff --git a/common_video/vplib/main/source/interpolator.cc b/common_video/vplib/main/source/interpolator.cc
new file mode 100644
index 0000000..8e49eb1
--- /dev/null
+++ b/common_video/vplib/main/source/interpolator.cc
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#include "interpolator.h"
+#include "scale_bilinear_yuv.h"
+
+namespace webrtc
+{
+
+interpolator::interpolator():
+_method(kBilinear),
+_srcWidth(0),
+_srcHeight(0),
+_dstWidth(0),
+_dstHeight(0)
+{
+}
+
+interpolator:: ~interpolator()
+{
+ //
+}
+
+WebRtc_Word32
+interpolator::Set(WebRtc_UWord32 srcWidth, WebRtc_UWord32 srcHeight,
+ WebRtc_UWord32 dstWidth, WebRtc_UWord32 dstHeight,
+ VideoType srcVideoType, VideoType dstVideoType,
+ interpolatorType type)
+{
+ if (srcWidth < 1 || srcHeight < 1 || dstWidth < 1 || dstHeight < 1 )
+ return -1;
+
+ if (Method(type) < 0)
+ return -1;
+
+ if (!SupportedVideoType(srcVideoType, dstVideoType))
+ return -1;
+
+ _srcWidth = srcWidth;
+ _srcHeight = srcHeight;
+ _dstWidth = dstWidth;
+ _dstHeight = dstHeight;
+ return 0;
+}
+
+
+WebRtc_Word32
+interpolator::Interpolate(const WebRtc_UWord8* srcFrame,
+ WebRtc_UWord8*& dstFrame)
+{
+ if (srcFrame == NULL)
+ return -1;
+
+ switch (_method)
+ {
+ case kBilinear :
+ return ScaleBilinear (srcFrame, dstFrame,
+ _srcWidth, _srcHeight,
+ _dstWidth, _dstHeight);
+ default :
+ return -1;
+ }
+}
+
+
+
+WebRtc_Word32
+interpolator::Method(interpolatorType type)
+{
+ _method = type;
+
+ return 0;
+}
+
+
+WebRtc_Word32
+interpolator::SupportedVideoType(VideoType srcVideoType,
+ VideoType dstVideoType)
+{
+ if (srcVideoType != dstVideoType)
+ return -1;
+
+ if ((srcVideoType != kI420) ||
+ (srcVideoType != kIYUV) ||
+ (srcVideoType != kYV12))
+ return -1;
+
+ return 0;
+}
+
+} // namespace webrtc
diff --git a/common_video/vplib/main/source/scale_bilinear_yuv.cc b/common_video/vplib/main/source/scale_bilinear_yuv.cc
new file mode 100644
index 0000000..b92fb73
--- /dev/null
+++ b/common_video/vplib/main/source/scale_bilinear_yuv.cc
@@ -0,0 +1,343 @@
+/*
+ * 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.
+ */
+
+#include "scale_bilinear_yuv.h"
+#include <string.h>
+
+namespace webrtc
+{
+// 16.16 fixed point arithmetic
+const WebRtc_UWord32 kFractionBits = 16;
+const WebRtc_UWord32 kFractionMax = 1 << kFractionBits;
+const WebRtc_UWord32 kFractionMask = ((1 << kFractionBits) - 1);
+
+#if USE_MMX
+#if defined(_MSC_VER)
+#include <intrin.h>
+#else
+#include <mmintrin.h>
+#endif
+#endif
+
+#if USE_SSE2
+#include <emmintrin.h>
+#endif
+
+#if USE_SSE2
+// FilterHorizontal combines two rows of the image using linear interpolation.
+// SSE2 version does 16 pixels at a time
+
+static void FilterHorizontal(WebRtc_UWord8* ybuf,
+ const WebRtc_UWord8* y0_ptr,
+ const WebRtc_UWord8* y1_ptr,
+ WebRtc_UWord32 source_width,
+ WebRtc_UWord32 source_y_fraction)
+{
+ __m128i zero = _mm_setzero_si128();
+ __m128i y1_fraction = _mm_set1_epi16(source_y_fraction);
+ __m128i y0_fraction = _mm_set1_epi16(256 - source_y_fraction);
+
+ const __m128i* y0_ptr128 = reinterpret_cast<const __m128i*>(y0_ptr);
+ const __m128i* y1_ptr128 = reinterpret_cast<const __m128i*>(y1_ptr);
+ __m128i* dest128 = reinterpret_cast<__m128i*>(ybuf);
+ __m128i* end128 = reinterpret_cast<__m128i*>(ybuf + source_width);
+
+ do
+ {
+ __m128i y0 = _mm_loadu_si128(y0_ptr128);
+ __m128i y1 = _mm_loadu_si128(y1_ptr128);
+ __m128i y2 = _mm_unpackhi_epi8(y0, zero);
+ __m128i y3 = _mm_unpackhi_epi8(y1, zero);
+ y0 = _mm_unpacklo_epi8(y0, zero);
+ y1 = _mm_unpacklo_epi8(y1, zero);
+ y0 = _mm_mullo_epi16(y0, y0_fraction);
+ y1 = _mm_mullo_epi16(y1, y1_fraction);
+ y2 = _mm_mullo_epi16(y2, y0_fraction);
+ y3 = _mm_mullo_epi16(y3, y1_fraction);
+ y0 = _mm_add_epi16(y0, y1);
+ y2 = _mm_add_epi16(y2, y3);
+ y0 = _mm_srli_epi16(y0, 8);
+ y2 = _mm_srli_epi16(y2, 8);
+ y0 = _mm_packus_epi16(y0, y2);
+ *dest128++ = y0;
+ ++y0_ptr128;
+ ++y1_ptr128;
+ }
+ while (dest128 < end128);
+}
+#elif USE_MMX
+// MMX version does 8 pixels at a time
+static void FilterHorizontal(WebRtc_UWord8* ybuf,
+ const WebRtc_UWord8* y0_ptr,
+ const WebRtc_UWord8* y1_ptr,
+ WebRtc_UWord32 source_width,
+ WebRtc_UWord32 source_y_fraction)
+{
+ __m64 zero = _mm_setzero_si64();
+ __m64 y1_fraction = _mm_set1_pi16(source_y_fraction);
+ __m64 y0_fraction = _mm_set1_pi16(256 - source_y_fraction);
+
+ const __m64* y0_ptr64 = reinterpret_cast<const __m64*>(y0_ptr);
+ const __m64* y1_ptr64 = reinterpret_cast<const __m64*>(y1_ptr);
+ __m64* dest64 = reinterpret_cast<__m64*>(ybuf);
+ __m64* end64 = reinterpret_cast<__m64*>(ybuf + source_width);
+
+ do
+ {
+ __m64 y0 = *y0_ptr64++;
+ __m64 y1 = *y1_ptr64++;
+ __m64 y2 = _mm_unpackhi_pi8(y0, zero);
+ __m64 y3 = _mm_unpackhi_pi8(y1, zero);
+ y0 = _mm_unpacklo_pi8(y0, zero);
+ y1 = _mm_unpacklo_pi8(y1, zero);
+ y0 = _mm_mullo_pi16(y0, y0_fraction);
+ y1 = _mm_mullo_pi16(y1, y1_fraction);
+ y2 = _mm_mullo_pi16(y2, y0_fraction);
+ y3 = _mm_mullo_pi16(y3, y1_fraction);
+ y0 = _mm_add_pi16(y0, y1);
+ y2 = _mm_add_pi16(y2, y3);
+ y0 = _mm_srli_pi16(y0, 8);
+ y2 = _mm_srli_pi16(y2, 8);
+ y0 = _mm_packs_pu16(y0, y2);
+ *dest64++ = y0;
+ }
+ while (dest64 < end64);
+}
+#else // no MMX or SSE2
+// C version does 8 at a time to mimic MMX code
+static void FilterHorizontal(WebRtc_UWord8* ybuf,
+ const WebRtc_UWord8* y0_ptr,
+ const WebRtc_UWord8* y1_ptr,
+ WebRtc_UWord32 source_width,
+ WebRtc_UWord32 source_y_fraction)
+{
+ WebRtc_UWord32 y1_fraction = source_y_fraction;
+ WebRtc_UWord32 y0_fraction = 256 - y1_fraction;
+ WebRtc_UWord8* end = ybuf + source_width;
+ do
+ {
+ ybuf[0] = (y0_ptr[0] * y0_fraction + y1_ptr[0] * y1_fraction) >> 8;
+ ybuf[1] = (y0_ptr[1] * y0_fraction + y1_ptr[1] * y1_fraction) >> 8;
+ ybuf[2] = (y0_ptr[2] * y0_fraction + y1_ptr[2] * y1_fraction) >> 8;
+ ybuf[3] = (y0_ptr[3] * y0_fraction + y1_ptr[3] * y1_fraction) >> 8;
+ ybuf[4] = (y0_ptr[4] * y0_fraction + y1_ptr[4] * y1_fraction) >> 8;
+ ybuf[5] = (y0_ptr[5] * y0_fraction + y1_ptr[5] * y1_fraction) >> 8;
+ ybuf[6] = (y0_ptr[6] * y0_fraction + y1_ptr[6] * y1_fraction) >> 8;
+ ybuf[7] = (y0_ptr[7] * y0_fraction + y1_ptr[7] * y1_fraction) >> 8;
+ y0_ptr += 8;
+ y1_ptr += 8;
+ ybuf += 8;
+ }
+ while (ybuf < end);
+}
+#endif
+
+static void FilterVertical(WebRtc_UWord8* ybuf,
+ const WebRtc_UWord8* y0_ptr,
+ WebRtc_UWord32 width,
+ WebRtc_UWord32 source_dx)
+{
+ WebRtc_UWord32 x = 0;
+
+ for (WebRtc_UWord32 i = 0; i < width; i ++)
+ {
+ WebRtc_UWord32 y0 = y0_ptr[x >> 16];
+ WebRtc_UWord32 y1 = y0_ptr[(x >> 16) + 1];
+
+ WebRtc_UWord32 y_frac = (x & 65535);
+ ybuf[i] = (y_frac * y1 + (y_frac ^ 65535) * y0) >> 16;
+
+ x += source_dx;
+ }
+}
+
+
+WebRtc_Word32
+ScaleBilinear(const WebRtc_UWord8* srcFrame,
+ WebRtc_UWord8*& dstFrame,
+ WebRtc_UWord32 srcWidth,
+ WebRtc_UWord32 srcHeight,
+ WebRtc_UWord32 dstWidth,
+ WebRtc_UWord32 dstHeight)
+{
+ // Setting source
+ const WebRtc_UWord8* src = srcFrame;
+ WebRtc_UWord8* srcTmp = NULL;
+
+ const WebRtc_UWord32 srcStride = (srcWidth + 15) & ~15;
+ const WebRtc_UWord32 srcUvStride = (((srcStride + 1 >> 1) + 15) & ~15);
+
+ const WebRtc_UWord32 srcStrideArray[3] = {srcStride,
+ srcUvStride,
+ srcUvStride
+ };
+ const WebRtc_UWord32 srcWidthArray[3] = {srcWidth,
+ (srcWidth + 1) >> 1,
+ (srcWidth + 1) >> 1
+ };
+
+ // if srcFrame isn't aligned to nice boundaries then copy it over
+ // int another buffer
+ if ((srcStride > srcWidth) || (srcUvStride > ((srcWidth + 1) >> 1)))
+ {
+ // allocate buffer that can accommodate the stride
+ srcTmp = new WebRtc_UWord8[srcStride*srcHeight*3 >> 1];
+ WebRtc_UWord8* tmpPlaneArray[3];
+ tmpPlaneArray[0] = srcTmp;
+ tmpPlaneArray[1] = tmpPlaneArray[0] + srcStride * srcHeight;
+ tmpPlaneArray[2] = tmpPlaneArray[1] + (srcStride >> 1)*(srcHeight >> 1);
+
+ WebRtc_UWord8* tmpPtr = srcTmp;
+ const WebRtc_UWord8* srcPtr = srcFrame;
+
+ for (WebRtc_UWord32 p = 0; p < 3; p++)
+ {
+ WebRtc_UWord8* dstPtr = tmpPlaneArray[p];
+ const WebRtc_UWord32 h = (p == 0) ? srcHeight : srcHeight >> 1;
+
+ for (WebRtc_UWord32 i = 0; i < h; i++)
+ {
+ memcpy(dstPtr, srcPtr, srcWidthArray[p]);
+ dstPtr += srcStrideArray[p];
+ srcPtr += srcWidthArray[p];
+ }
+ }
+ src = srcTmp;
+ }
+
+ const WebRtc_UWord8* srcPlaneArray[3];
+ srcPlaneArray[0] = src;
+ srcPlaneArray[1] = srcPlaneArray[0] + srcStride*srcHeight;
+ srcPlaneArray[2] = srcPlaneArray[1] + (srcStride >> 1)*(srcHeight >> 1);
+
+ // Setting destination
+ const WebRtc_UWord32 dstStride = (dstWidth + 31) & ~31;
+ const WebRtc_UWord32 dstUvStride = (((dstStride + 1 >> 1) + 31) & ~31);
+
+ if (dstFrame)
+ {
+ delete [] dstFrame;
+ dstFrame = NULL;
+ }
+
+ WebRtc_UWord32 dstRequiredSize = dstStride*dstHeight +
+ 2*(dstUvStride*((dstHeight + 1) >> 1));
+ dstFrame = new WebRtc_UWord8[dstRequiredSize];
+ if (dstFrame == NULL)
+ return -1;
+
+ WebRtc_UWord8* dstPlaneArray[3] = {dstFrame,
+ dstPlaneArray[0] + dstStride*dstHeight,
+ dstPlaneArray[1] +
+ (dstUvStride*((dstHeight + 1) >> 1))
+ };
+
+ const WebRtc_UWord32 dstStrideArray[3] = {dstStride,
+ dstUvStride,
+ dstUvStride
+ };
+ const WebRtc_UWord32 dstWidthArray[3] = {dstWidth,
+ dstWidth>>1,
+ dstWidth>>1
+ };
+
+ for (WebRtc_UWord32 p = 0; p < 3; p++)
+ {
+ const WebRtc_UWord32 sh = (p == 0) ? srcHeight : srcHeight >> 1;
+ const WebRtc_UWord32 dh = (p == 0) ? dstHeight : dstHeight >> 1;
+ WebRtc_UWord8* filteredBuf = dstPlaneArray[p];
+ WebRtc_UWord8* horizontalFilteredBuf;
+ WebRtc_UWord8* intermediaryBuf = new WebRtc_UWord8[srcStrideArray[p]];
+
+ const WebRtc_UWord32 hscale_fixed = (sh << kFractionBits) / dh;
+ const WebRtc_UWord32 source_dx = srcWidthArray[p]*kFractionMax /
+ dstWidthArray[p];
+
+
+ for (WebRtc_UWord32 h = 0; h < dh; ++h)
+ {
+ horizontalFilteredBuf = filteredBuf;
+
+ if (source_dx != kFractionMax)
+ horizontalFilteredBuf = intermediaryBuf;
+
+ // horizontal filter
+ WebRtc_UWord32 source_h_subpixel = (h * hscale_fixed);
+ if (hscale_fixed >= (kFractionMax * 2))
+ // For 1/2 or less, center filter.
+ source_h_subpixel += kFractionMax / 2;
+
+ WebRtc_UWord32 source_h = source_h_subpixel >> kFractionBits;
+
+ const WebRtc_UWord8* ptr_0 = srcPlaneArray[p] +
+ source_h*srcStrideArray[p];
+
+ const WebRtc_UWord8* ptr_1 = ptr_0 + srcStrideArray[p];
+
+ // vertical scaler uses 16.8 fixed point
+ WebRtc_UWord32 source_h_fraction =
+ (source_h_subpixel & kFractionMask) >> 8;
+
+ if (hscale_fixed != kFractionMax &&
+ source_h_fraction && ((source_h + 1) < sh))
+ {
+ FilterHorizontal(horizontalFilteredBuf, ptr_0, ptr_1,
+ srcWidthArray[p], source_h_fraction);
+ }
+ else
+ {
+ memcpy(horizontalFilteredBuf, ptr_1, srcWidthArray[p]);
+ }
+ filteredBuf[srcWidthArray[p]] = filteredBuf[srcWidthArray[p]-1];
+
+ // vertical filter only if necessary
+ if (source_dx != kFractionMax)
+ FilterVertical(filteredBuf, horizontalFilteredBuf,
+ dstWidthArray[p], source_dx);
+
+ filteredBuf += dstStrideArray[p];
+ }
+
+ if (intermediaryBuf != NULL)
+ delete [] intermediaryBuf;
+ }
+
+ if (srcTmp != NULL)
+ delete [] srcTmp;
+
+ // Filtered image was placed in an aligned buffer. If the
+ // final output is not in an aligned buffer copy the image over.
+ if (dstStride > dstWidth)
+ {
+ WebRtc_UWord8* dstFinal =
+ new WebRtc_UWord8[(dstWidth*dstHeight*3) >> 1];
+ WebRtc_UWord8* dstPtr = dstFinal;
+
+ for (WebRtc_UWord32 p = 0; p < 3; p++)
+ {
+ WebRtc_UWord8* srcPtr = dstPlaneArray[p];
+ const WebRtc_UWord32 h = (p == 0) ? dstHeight : dstHeight >> 1;
+
+ for (WebRtc_UWord32 i = 0; i < h; i++)
+ {
+ memcpy(dstPtr, srcPtr, dstWidthArray[p]);
+ dstPtr += dstWidthArray[p];
+ srcPtr += dstStrideArray[p];
+ }
+ }
+
+ delete [] dstFrame;
+ dstFrame = dstFinal;
+ }
+
+ return dstHeight;
+}
+
+} // namespace webrtc
diff --git a/common_video/vplib/main/source/scale_bilinear_yuv.h b/common_video/vplib/main/source/scale_bilinear_yuv.h
new file mode 100644
index 0000000..08e905e
--- /dev/null
+++ b/common_video/vplib/main/source/scale_bilinear_yuv.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/*
+ * scale_bilinear_yuv.h
+ * yuv bilinear scaler
+ */
+
+#ifndef WEBRTC_COMMON_VIDEO_INTERFACE_SCALE_BILINEAR_YUV_H
+#define WEBRTC_COMMON_VIDEO_INTERFACE_SCALE_BILINEAR_YUV_H
+
+#include "typedefs.h"
+#include "vplib.h"
+
+namespace webrtc
+{
+
+WebRtc_Word32 ScaleBilinear(const WebRtc_UWord8* src, WebRtc_UWord8*& dst,
+ WebRtc_UWord32 sW, WebRtc_UWord32 sH,
+ WebRtc_UWord32 dW, WebRtc_UWord32 dH);
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_VIDEO_INTERFACE_SCALE_BILINEAR_YUV_H
diff --git a/common_video/vplib/main/source/vplib.cc b/common_video/vplib/main/source/vplib.cc
new file mode 100644
index 0000000..804a159
--- /dev/null
+++ b/common_video/vplib/main/source/vplib.cc
@@ -0,0 +1,4438 @@
+/*
+ * 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.
+ */
+
+#include "vplib.h"
+
+#include <string.h> // memcpy(), memset()
+#include <assert.h>
+#include <stdlib.h> // abs
+
+//#define SCALEOPT //Currently for windows only. June 2010
+
+#ifdef SCALEOPT
+#include <emmintrin.h>
+#endif
+
+// webrtc includes
+#include "conversion_tables.h"
+
+namespace webrtc
+{
+
+//Verify and allocate buffer
+static WebRtc_Word32 VerifyAndAllocate(WebRtc_UWord8*& buffer, WebRtc_UWord32 currentSize,
+ WebRtc_UWord32 newSize);
+// clip value to [0,255]
+inline WebRtc_UWord8 Clip(WebRtc_Word32 val);
+
+#ifdef SCALEOPT
+void *memcpy_16(void * dest, const void * src, size_t n);
+void *memcpy_8(void * dest, const void * src, size_t n);
+#endif
+
+
+WebRtc_UWord32
+CalcBufferSize(VideoType type, WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ WebRtc_UWord32 bitsPerPixel = 32;
+ switch(type)
+ {
+ case kI420:
+ bitsPerPixel = 12;
+ break;
+ case kNV12:
+ bitsPerPixel = 12;
+ break;
+ case kNV21:
+ bitsPerPixel = 12;
+ break;
+ case kIYUV:
+ bitsPerPixel = 12;
+ break;
+ case kYV12:
+ bitsPerPixel = 12;
+ break;
+ case kRGB24:
+ bitsPerPixel = 24;
+ break;
+ case kARGB:
+ bitsPerPixel = 32;
+ break;
+ case kARGB4444:
+ bitsPerPixel = 16;
+ break;
+ case kRGB565:
+ bitsPerPixel = 16;
+ break;
+ case kARGB1555:
+ bitsPerPixel = 16;
+ break;
+ case kYUY2:
+ bitsPerPixel = 16;
+ break;
+ case kUYVY:
+ bitsPerPixel = 16;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ return (width * height * bitsPerPixel) >> 3; // bytes
+}
+
+WebRtc_UWord32
+CalcBufferSize(VideoType incomingVideoType, VideoType convertedVideoType,
+ WebRtc_UWord32 length)
+{
+ WebRtc_UWord32 incomingBitsPerPixel = 32;
+ switch(incomingVideoType)
+ {
+ case kI420:
+ incomingBitsPerPixel = 12;
+ break;
+ case kNV12:
+ incomingBitsPerPixel = 12;
+ break;
+ case kNV21:
+ incomingBitsPerPixel = 12;
+ break;
+ case kIYUV:
+ incomingBitsPerPixel = 12;
+ break;
+ case kYV12:
+ incomingBitsPerPixel = 12;
+ break;
+ case kRGB24:
+ incomingBitsPerPixel = 24;
+ break;
+ case kARGB:
+ incomingBitsPerPixel = 32;
+ break;
+ case kARGB4444:
+ incomingBitsPerPixel = 16;
+ break;
+ case kRGB565:
+ incomingBitsPerPixel = 16;
+ break;
+ case kARGB1555:
+ incomingBitsPerPixel = 16;
+ break;
+ case kYUY2:
+ incomingBitsPerPixel = 16;
+ break;
+ case kUYVY:
+ incomingBitsPerPixel = 16;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ WebRtc_Word32 convertedBitsPerPixel = 32;
+ switch(convertedVideoType)
+ {
+ case kI420:
+ convertedBitsPerPixel = 12;
+ break;
+ case kIYUV:
+ convertedBitsPerPixel = 12;
+ break;
+ case kYV12:
+ convertedBitsPerPixel = 12;
+ break;
+ case kRGB24:
+ convertedBitsPerPixel = 24;
+ break;
+ case kARGB:
+ convertedBitsPerPixel = 32;
+ break;
+ case kARGB4444:
+ convertedBitsPerPixel = 16;
+ break;
+ case kRGB565:
+ convertedBitsPerPixel = 16;
+ break;
+ case kARGB1555:
+ convertedBitsPerPixel = 16;
+ break;
+ case kYUY2:
+ convertedBitsPerPixel = 16;
+ break;
+ case kUYVY:
+ convertedBitsPerPixel = 16;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ return (length * convertedBitsPerPixel) / incomingBitsPerPixel;
+}
+
+WebRtc_Word32
+ConvertI420ToRGB24(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ // RGB orientation - bottom up
+ WebRtc_UWord8* out = outFrame + width * height * 3 - width * 3;
+ WebRtc_UWord8* out2 = out - width * 3;
+ WebRtc_UWord32 h, w;
+ WebRtc_Word32 tmpR, tmpG, tmpB;
+ const WebRtc_UWord8 *y1, *y2 ,*u, *v;
+ y1 = inFrame;
+ y2 = y1 + width;
+ u = y1 + width * height;
+ v = u + ((width * height) >> 2);
+ for (h = (height >> 1); h > 0; h--)
+ { // 2 rows at a time, 2 y's at a time
+ for (w = 0; w < (width >> 1); w++)
+ {// vertical and horizontal sub-sampling
+ tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8);
+ out[2] = Clip(tmpR);
+ out[1] = Clip(tmpG);
+ out[0] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8);
+ out2[2] = Clip(tmpR);
+ out2[1] = Clip(tmpG);
+ out2[0] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8);
+ out[5] = Clip(tmpR);
+ out[4] = Clip(tmpG);
+ out[3] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8);
+ out2[5] = Clip(tmpR);
+ out2[4] = Clip(tmpG);
+ out2[3] = Clip(tmpB);
+
+ out += 6;
+ out2 += 6;
+ y1 += 2;
+ y2 += 2;
+ u++;
+ v++;
+ }
+ y1 += width;
+ y2 += width;
+ out -= width * 9;
+ out2 -= width * 9;
+ } // end height for
+
+ return width * height * 3;
+}
+
+WebRtc_Word32
+ConvertI420ToARGB(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ if (strideOut == 0)
+ {
+ strideOut = width;
+ }
+ else if (strideOut < width)
+ {
+ return -1;
+ }
+ WebRtc_Word32 diff = strideOut - width;
+ WebRtc_UWord8* out1 = outFrame;
+ WebRtc_UWord8* out2 = out1 + strideOut * 4;
+ const WebRtc_UWord8 *y1,*y2, *u, *v;
+ y1 = inFrame;
+ y2 = y1 + width;
+ u = y1 + width * height;
+ v = u + (( width * height ) >> 2 );
+ WebRtc_UWord32 h, w;
+ WebRtc_Word32 tmpR, tmpG, tmpB;
+
+ for (h = (height >> 1); h > 0; h--)
+ {
+ //do 2 rows at the time
+ for (w = 0; w < (width >> 1); w++)
+ { // vertical and horizontal sub-sampling
+
+ tmpR = (WebRtc_UWord32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_UWord32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] +128) >> 8);
+ tmpB = (WebRtc_UWord32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8);
+ out1[3] = 0xff;
+ out1[2] = Clip(tmpR);
+ out1[1] = Clip(tmpG);
+ out1[0] = Clip(tmpB);
+
+ tmpR = (WebRtc_UWord32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_UWord32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_UWord32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8);
+ out2[3] = 0xff;
+ out2[2] = Clip(tmpR);
+ out2[1] = Clip(tmpG);
+ out2[0] = Clip(tmpB);
+
+ tmpR = (WebRtc_UWord32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_UWord32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_UWord32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8);
+ out1[7] = 0xff;
+ out1[6] = Clip(tmpR);
+ out1[5] = Clip(tmpG);
+ out1[4] = Clip(tmpB);
+
+ tmpR = (WebRtc_UWord32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_UWord32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_UWord32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8);
+ out2[7] = 0xff;
+ out2[6] = Clip(tmpR);
+ out2[5] = Clip(tmpG);
+ out2[4] = Clip(tmpB);
+
+ out1 += 8;
+ out2 += 8;
+ y1 += 2;
+ y2 += 2;
+ u++;
+ v++;
+ }
+ y1 += width;
+ y2 += width;
+ out1 += (strideOut + diff) * 4;
+ out2 += (strideOut + diff) * 4;
+
+ } // end height for
+ return strideOut * height * 4;
+}
+
+WebRtc_Word32
+ConvertI420ToRGBAMac(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (height < 1 || width < 1)
+ {
+ return -1;
+ }
+
+ if (strideOut == 0)
+ {
+ strideOut = width;
+ } else if (strideOut < width)
+ {
+ return -1;
+ }
+ WebRtc_Word32 diff = strideOut - width;
+
+ WebRtc_UWord8 * out = outFrame;
+ WebRtc_UWord8 * out2 = out + strideOut * 4;
+ const WebRtc_UWord8 *y1,*y2, *u, *v;
+ WebRtc_Word32 tmpG, tmpB, tmpR;
+ WebRtc_UWord32 h, w;
+ y1 = inFrame;
+ y2 = y1 + width;
+ v = y1 + width * height;
+ u = v + ((width * height) >> 2);
+
+ for (h = (height >> 1); h > 0; h--)
+ {
+ //do 2 rows at the time
+ for (w = 0; w < (width >> 1); w++)
+ {
+ tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128 ) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128 ) >> 8);
+ out[1] = Clip(tmpR);
+ out[2] = Clip(tmpG);
+ out[3] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8);
+ out2[1] = Clip(tmpR);
+ out2[2] = Clip(tmpG);
+ out2[3] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8);
+ out[5] = Clip(tmpR);
+ out[6] = Clip(tmpG);
+ out[7] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8);
+ out2[5] = Clip(tmpR);
+ out2[6] = Clip(tmpG);
+ out2[7] = Clip(tmpB);
+
+ out[0] = 0xff;
+ out[4] = 0xff;
+ out += 8;
+ out2[0] = 0xff;
+ out2[4] = 0xff;
+ out2 += 8;
+ y1 += 2;
+ y2 += 2;
+ u++;
+ v++;
+ }
+
+ y1 += width;
+ y2 += width;
+ out += (width + diff * 2) * 4;
+ out2 += (width + diff * 2) * 4;
+ }
+ return strideOut * height * 4;
+}
+
+// Little Endian...
+WebRtc_Word32
+ConvertI420ToARGB4444(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ if (strideOut == 0)
+ {
+ strideOut = width;
+ } else if (strideOut < width)
+ {
+ return -1;
+ }
+ // RGB orientation - bottom up
+ WebRtc_UWord8* out = outFrame + strideOut * (height - 1) * 2;
+ WebRtc_UWord8* out2 = out - 2 * strideOut;
+ WebRtc_Word32 tmpR, tmpG, tmpB;
+ const WebRtc_UWord8 *y1,*y2, *u, *v;
+ y1 = inFrame;
+ y2 = y1 + width;
+ u = y1 + width * height;
+ v = u + ((width * height) >> 2);
+ WebRtc_UWord32 h, w;
+
+ for (h = (height >> 1); h > 0; h--)
+ { // 2 rows at a time, 2 y's at a time
+ for (w = 0; w < (width >> 1); w++)
+ { // vertical and horizontal sub-sampling
+ // Convert to RGB888 and re-scale to 4 bits
+ tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8);
+ out[0] =(WebRtc_UWord8)((Clip(tmpG) & 0xf0) + (Clip(tmpB) >> 4));
+ out[1] = (WebRtc_UWord8)(0xf0 + (Clip(tmpR) >> 4));
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8);
+ out2[0] = (WebRtc_UWord8)((Clip(tmpG) & 0xf0 ) + (Clip(tmpB) >> 4));
+ out2[1] = (WebRtc_UWord8) (0xf0 + (Clip(tmpR) >> 4));
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8);
+ out[2] = (WebRtc_UWord8)((Clip(tmpG) & 0xf0 ) + (Clip(tmpB) >> 4));
+ out[3] = (WebRtc_UWord8)(0xf0 + (Clip(tmpR) >> 4));
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8);
+ out2[2] = (WebRtc_UWord8)((Clip(tmpG) & 0xf0 ) + (Clip(tmpB) >> 4));
+ out2[3] = (WebRtc_UWord8)(0xf0 + (Clip(tmpR) >> 4));
+
+ out += 4;
+ out2 += 4;
+ y1 += 2;
+ y2 += 2;
+ u++;
+ v++;
+ }
+ y1 += width;
+ y2 += width;
+ out -= (2 * strideOut + width) * 2;
+ out2 -= (2 * strideOut + width) * 2;
+ } // end height for
+
+ return strideOut * height * 2;
+}
+
+WebRtc_Word32
+ConvertI420ToRGB565(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ WebRtc_UWord16* out = (WebRtc_UWord16*)(outFrame) + width * (height - 1);
+ WebRtc_UWord16* out2 = out - width ;
+ WebRtc_Word32 tmpR, tmpG, tmpB;
+ const WebRtc_UWord8 *y1,*y2, *u, *v;
+ y1 = inFrame;
+ y2 = y1 + width;
+ u = y1 + width * height;
+ v = u + (width * height >> 2);
+ WebRtc_UWord32 h, w;
+
+ for (h = (height >>1); h > 0; h--)
+ { // 2 rows at a time, 2 y's at a time
+ for (w = 0; w < (width >> 1); w++)
+ { // vertical and horizontal sub-sampling
+ // 1. Convert to RGB888
+ // 2. Shift to adequate location (in the 16 bit word) - RGB 565
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8);
+ out[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3)
+ + (Clip(tmpB) >> 3);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8);
+ out2[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3)
+ + (Clip(tmpB) >> 3);
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8);
+ out[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3)
+ + (Clip(tmpB ) >> 3);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8);
+ out2[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3)
+ + (Clip(tmpB) >> 3);
+
+ y1 += 2;
+ y2 += 2;
+ out += 2;
+ out2 += 2;
+ u++;
+ v++;
+ }
+ y1 += width;
+ y2 += width;
+ out -= 3 * width;
+ out2 -= 3 * width;
+ } // end height for
+
+ return width * height * 2;
+}
+
+
+//Same as ConvertI420ToRGB565 but doesn't flip vertically.
+WebRtc_Word32
+ConvertI420ToRGB565Android(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ WebRtc_UWord16* out = (WebRtc_UWord16*)(outFrame);
+ WebRtc_UWord16* out2 = out + (width) ;
+ WebRtc_Word32 tmpR, tmpG, tmpB;
+ const WebRtc_UWord8 *y1,*y2, *u, *v;
+ WebRtc_UWord32 h, w;
+ y1 = inFrame;
+ y2 = y1 + width;
+ u = y1 + width * height;
+ v = u + (width * height >> 2);
+
+ for (h = (height >>1); h > 0; h--)
+ {
+ // 2 rows at a time, 2 y's at a time
+ for (w = 0; w < (width >> 1); w++)
+ {
+ // vertical and horizontal sub-sampling
+ // 1. Convert to RGB888
+ // 2. Shift to adequate location (in the 16 bit word) - RGB 565
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8);
+ out[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3)
+ + (Clip(tmpB) >> 3);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8);
+ out2[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3)
+ + (Clip(tmpB) >> 3);
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8);
+ out[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3)
+ + (Clip(tmpB ) >> 3);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8);
+ out2[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3)
+ + (Clip(tmpB) >> 3);
+
+ y1 += 2;
+ y2 += 2;
+ out += 2;
+ out2 += 2;
+ u++;
+ v++;
+ }
+ y1 += width;
+ y2 += width;
+ out += width;
+ out2 += width;
+ } // end height for
+
+ return width * height * 2;
+}
+
+WebRtc_Word32
+ConvertI420ToARGB1555(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ if (strideOut == 0)
+ {
+ strideOut = width;
+ }
+ else if (strideOut < width)
+ {
+ return -1;
+ }
+
+ WebRtc_UWord16* out = (WebRtc_UWord16*)(outFrame) + width * (height - 1);
+ WebRtc_UWord16* out2 = out - width ;
+ WebRtc_Word32 tmpR, tmpG, tmpB;
+ const WebRtc_UWord8 *y1,*y2, *u, *v;
+ WebRtc_UWord32 h, w;
+
+ y1 = inFrame;
+ y2 = y1 + width;
+ u = y1 + width * height;
+ v = u + (width * height >> 2);
+
+ for (h = (height >> 1); h > 0; h--)
+ { // 2 rows at a time, 2 y's at a time
+ for (w = 0; w < (width >> 1); w++)
+ {
+ // vertical and horizontal sub-sampling
+ // 1. Convert to RGB888
+ // 2. shift to adequate location (in the 16 bit word) - RGB 555
+ // 3. Add 1 for alpha value
+ tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8);
+ out[0] = (WebRtc_UWord16)(0x8000 + ((Clip(tmpR) & 0xf8) << 10) + ((Clip(tmpG) & 0xf8) << 3)
+ + (Clip(tmpB) >> 3));
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8);
+ out2[0] = (WebRtc_UWord16)(0x8000 + ((Clip(tmpR) & 0xf8) << 10) + ((Clip(tmpG) & 0xf8) << 3)
+ + (Clip(tmpB) >> 3));
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8);
+ out[1] = (WebRtc_UWord16)(0x8000 + ((Clip(tmpR) & 0xf8) << 10) + ((Clip(tmpG) & 0xf8) << 3)
+ + (Clip(tmpB) >> 3));
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8);
+ out2[1] = (WebRtc_UWord16)(0x8000 + ((Clip(tmpR) & 0xf8) << 10) + ((Clip(tmpG) & 0xf8) << 3)
+ + (Clip(tmpB) >> 3));
+
+ y1 += 2;
+ y2 += 2;
+ out += 2;
+ out2 += 2;
+ u++;
+ v++;
+ }
+ y1 += width;
+ y2 += width;
+ out -= 3 * width;
+ out2 -= 3 * width;
+ } // end height for
+ return strideOut * height * 2;
+}
+
+WebRtc_Word32
+ConvertI420ToYUY2(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ if(strideOut == 0)
+ {
+ strideOut = width;
+ }
+ else if (strideOut < width)
+ {
+ return -1;
+ }
+
+ const WebRtc_UWord8* in1 = inFrame;
+ const WebRtc_UWord8* in2 = inFrame + width ;
+ const WebRtc_UWord8* inU = inFrame + width * height;
+ const WebRtc_UWord8* inV = inU + width * (height >> 2);
+
+ WebRtc_UWord8* out1 = outFrame;
+ WebRtc_UWord8* out2 = outFrame + 2*strideOut;
+
+ //YUY2 - Macro-pixel = 2 image pixels
+ //Y0U0Y1V0....Y2U2Y3V2...Y4U4Y5V4....
+
+#ifndef SCALEOPT
+ for (WebRtc_UWord32 i = 0; i < (height >> 1);i++)
+ {
+ for (WebRtc_UWord32 j = 0; j < (width >> 1);j++)
+ {
+ out1[0] = in1[0];
+ out1[1] = *inU;
+ out1[2] = in1[1];
+ out1[3] = *inV;
+
+ out2[0] = in2[0];
+ out2[1] = *inU;
+ out2[2] = in2[1];
+ out2[3] = *inV;
+ out1 += 4;
+ out2 += 4;
+ inU++;
+ inV++;
+ in1 += 2;
+ in2 += 2;
+ }
+ in1 += width;
+ in2 += width;
+ out1 += 2 * strideOut + 2 * (strideOut - width);
+ out2 += 2 * strideOut + 2 * (strideOut - width);
+ }
+#else
+ for (WebRtc_UWord32 i = 0; i < (height >> 1);i++)
+ {
+ WebRtc_Word32 width__ = (width >> 4);
+ _asm
+ {
+ ;pusha
+ mov eax, DWORD PTR [in1] ;1939.33
+ mov ecx, DWORD PTR [in2] ;1939.33
+ mov ebx, DWORD PTR [inU] ;1939.33
+ mov edx, DWORD PTR [inV] ;1939.33
+ loop0:
+ movq xmm6, QWORD PTR [ebx] ;inU
+ movq xmm0, QWORD PTR [edx] ;inV
+ punpcklbw xmm6, xmm0 ;inU, inV mix
+ ;movdqa xmm1, xmm6
+ ;movdqa xmm2, xmm6
+ ;movdqa xmm4, xmm6
+
+ movdqu xmm3, XMMWORD PTR [eax] ;in1
+ movdqa xmm1, xmm3
+ punpcklbw xmm1, xmm6 ;in1, inU, in1, inV
+ mov esi, DWORD PTR [out1]
+ movdqu XMMWORD PTR [esi], xmm1 ;write to out1
+
+ movdqu xmm5, XMMWORD PTR [ecx] ;in2
+ movdqa xmm2, xmm5
+ punpcklbw xmm2, xmm6 ;in2, inU, in2, inV
+ mov edi, DWORD PTR [out2]
+ movdqu XMMWORD PTR [edi], xmm2 ;write to out2
+
+ punpckhbw xmm3, xmm6 ;in1, inU, in1, inV again
+ movdqu XMMWORD PTR [esi+16], xmm3 ;write to out1 again
+ add esi, 32
+ mov DWORD PTR [out1], esi
+
+ punpckhbw xmm5, xmm6 ;inU, in2, inV again
+ movdqu XMMWORD PTR [edi+16], xmm5 ;write to out2 again
+ add edi, 32
+ mov DWORD PTR [out2], edi
+
+ add ebx, 8
+ add edx, 8
+ add eax, 16
+ add ecx, 16
+
+ mov esi, DWORD PTR [width__]
+ sub esi, 1
+ mov DWORD PTR [width__], esi
+ jg loop0
+
+ mov DWORD PTR [in1], eax ;1939.33
+ mov DWORD PTR [in2], ecx ;1939.33
+ mov DWORD PTR [inU], ebx ;1939.33
+ mov DWORD PTR [inV], edx ;1939.33
+
+ ;popa
+ emms
+ }
+ in1 += width;
+ in2 += width;
+ out1 += 2 * strideOut + 2 * (strideOut - width);
+ out2 += 2 * strideOut + 2 * (strideOut - width);
+ }
+#endif
+ return strideOut * height * 2;
+}
+
+WebRtc_Word32
+ConvertI420ToUYVY(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ if(strideOut == 0)
+ {
+ strideOut = width;
+ }
+ else if (strideOut < width)
+ {
+ return -1;
+ }
+ WebRtc_UWord32 i = 0;
+ const WebRtc_UWord8* in1 = inFrame;
+ const WebRtc_UWord8* in2 = inFrame + width ;
+ const WebRtc_UWord8* inU = inFrame + width * height;
+ const WebRtc_UWord8* inV = inFrame + width * height + width * (height >> 2);
+
+ WebRtc_UWord8* out1 = outFrame;
+ WebRtc_UWord8* out2 = outFrame + 2 * strideOut;
+
+ //Macro-pixel = 2 image pixels
+ //U0Y0V0Y1....U2Y2V2Y3...U4Y4V4Y5.....
+
+#ifndef SCALEOPT
+ for (; i < (height >> 1);i++)
+ {
+ for (WebRtc_UWord32 j = 0; j < (width >> 1) ;j++)
+ {
+ out1[0] = *inU;
+ out1[1] = in1[0];
+ out1[2] = *inV;
+ out1[3] = in1[1];
+
+ out2[0] = *inU;
+ out2[1] = in2[0];
+ out2[2] = *inV;
+ out2[3] = in2[1];
+ out1 += 4;
+ out2 += 4;
+ inU++;
+ inV++;
+ in1 += 2;
+ in2 += 2;
+ }
+ in1 += width;
+ in2 += width;
+ out1 += 2 * (strideOut + (strideOut - width));
+ out2 += 2 * (strideOut + (strideOut - width));
+ }
+#else
+ for (; i< (height >> 1);i++)
+ {
+ WebRtc_Word32 width__ = (width >> 4);
+ _asm
+ {
+ ;pusha
+ mov eax, DWORD PTR [in1] ;1939.33
+ mov ecx, DWORD PTR [in2] ;1939.33
+ mov ebx, DWORD PTR [inU] ;1939.33
+ mov edx, DWORD PTR [inV] ;1939.33
+loop0:
+ movq xmm6, QWORD PTR [ebx] ;inU
+ movq xmm0, QWORD PTR [edx] ;inV
+ punpcklbw xmm6, xmm0 ;inU, inV mix
+ movdqa xmm1, xmm6
+ movdqa xmm2, xmm6
+ movdqa xmm4, xmm6
+
+ movdqu xmm3, XMMWORD PTR [eax] ;in1
+ punpcklbw xmm1, xmm3 ;inU, in1, inV
+ mov esi, DWORD PTR [out1]
+ movdqu XMMWORD PTR [esi], xmm1 ;write to out1
+
+ movdqu xmm5, XMMWORD PTR [ecx] ;in2
+ punpcklbw xmm2, xmm5 ;inU, in2, inV
+ mov edi, DWORD PTR [out2]
+ movdqu XMMWORD PTR [edi], xmm2 ;write to out2
+
+ punpckhbw xmm4, xmm3 ;inU, in1, inV again
+ movdqu XMMWORD PTR [esi+16], xmm4 ;write to out1 again
+ add esi, 32
+ mov DWORD PTR [out1], esi
+
+ punpckhbw xmm6, xmm5 ;inU, in2, inV again
+ movdqu XMMWORD PTR [edi+16], xmm6 ;write to out2 again
+ add edi, 32
+ mov DWORD PTR [out2], edi
+
+ add ebx, 8
+ add edx, 8
+ add eax, 16
+ add ecx, 16
+
+ mov esi, DWORD PTR [width__]
+ sub esi, 1
+ mov DWORD PTR [width__], esi
+ jg loop0
+
+ mov DWORD PTR [in1], eax ;1939.33
+ mov DWORD PTR [in2], ecx ;1939.33
+ mov DWORD PTR [inU], ebx ;1939.33
+ mov DWORD PTR [inV], edx ;1939.33
+
+ ;popa
+ emms
+ }
+ in1 += width;
+ in2 += width;
+ out1 += 2 * (strideOut + (strideOut - width));
+ out2 += 2 * (strideOut + (strideOut - width));
+ }
+#endif
+ return strideOut * height * 2;
+}
+
+WebRtc_Word32
+ConvertI420ToYV12(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (height < 1 || width < 1 )
+ {
+ return -1;
+ }
+ if (strideOut == 0)
+ {
+ strideOut = width;
+ }
+ else if (strideOut < width)
+ {
+ return -1;
+ }
+
+ // copy Y
+ for (WebRtc_UWord32 i = 0; i < height; i++)
+ {
+#ifndef SCALEOPT
+ memcpy(outFrame, inFrame, width);
+#else
+ memcpy_16(outFrame, inFrame, width);
+#endif
+ inFrame += width;
+ outFrame += strideOut;
+ }
+ // copy U
+ outFrame += (strideOut >> 1) * height >> 1;
+ for (WebRtc_UWord32 i = 0; i < height >>1; i++)
+ {
+#ifndef SCALEOPT
+ memcpy(outFrame, inFrame, width >> 1);
+#else
+ memcpy_8(outFrame, inFrame, width >> 1);
+#endif
+ inFrame += width >> 1;
+ outFrame += strideOut >> 1;
+ }
+ outFrame -= strideOut*height >> 1;
+ // copy V
+ for (WebRtc_UWord32 i = 0; i < height >> 1; i++)
+ {
+#ifndef SCALEOPT
+ memcpy(outFrame, inFrame, width >> 1);
+#else
+ memcpy_8(outFrame, inFrame, width >> 1);
+#endif
+ inFrame += width >> 1;
+ outFrame += strideOut >> 1;
+ }
+ return ((3 * strideOut * height) >> 1);
+}
+
+WebRtc_Word32
+ConvertYV12ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord8* outFrame)
+{
+ if (height < 1 || width <1)
+ {
+ return -1;
+ }
+ WebRtc_UWord8 *u, *v, *uo, *vo;
+ WebRtc_Word32 lumlen = 0;
+ WebRtc_Word32 crlen = 0;
+
+ lumlen = height * width;
+ crlen = (lumlen >> 2);
+ v = (WebRtc_UWord8 *)inFrame + lumlen;
+ uo = outFrame + lumlen;
+ u = v + crlen;
+ vo = uo + crlen;
+
+ memcpy(outFrame, inFrame, lumlen); // copy luminance
+ memcpy(vo, v, crlen); // copy V to V out
+ memcpy(uo, u, crlen); // copy U to U out
+
+ return (width * height * 3) >> 1;
+}
+
+WebRtc_Word32
+ConvertNV12ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ // Bi-Planar: Y plane followed by an interlaced U and V plane
+ WebRtc_UWord8* out = outFrame;
+ // copying Y plane as is
+ memcpy(out, inFrame, width * height);
+ // de-interlacing U and V
+ const WebRtc_UWord8 *interlacedSrc;
+ WebRtc_UWord8 *u, *v;
+ u = outFrame + width * height;
+ v = u + (width * height >> 2);
+ interlacedSrc = inFrame + width * height;
+ for (WebRtc_UWord32 ind = 0; ind < (width * height >> 2); ind ++)
+ {
+ u[ind] = interlacedSrc[2 * ind];
+ v[ind] = interlacedSrc[2 * ind + 1];
+ }
+ return (width * height * 3 >> 1);
+}
+WebRtc_Word32
+ConvertNV12ToI420AndRotate180(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ // Bi-Planar: Y plane followed by an interlaced U and V plane
+ WebRtc_UWord8* out = outFrame;
+
+ for(WebRtc_UWord32 index = 0; index < width * height; index++)
+ {
+ out[index] = inFrame[width * height - index - 1];
+ }
+ // de-interlacing U and V
+ const WebRtc_UWord8 *interlacedSrc;
+ WebRtc_UWord8 *u, *v;
+ u = outFrame + width * height;
+ v = u + (width * height >> 2);
+ interlacedSrc = inFrame + width * height;
+ // extracting and rotating 180
+ for (WebRtc_UWord32 index = 0; index < (width * height >> 2); index++)
+ {
+ u[(width * height >> 2) - index - 1] = interlacedSrc[2 * index];
+ v[(width * height >> 2) - index - 1] = interlacedSrc[2 * index + 1];
+ }
+ return (width * height * 3 >> 1);
+}
+
+WebRtc_Word32
+ConvertNV12ToI420AndRotateClockwise(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ WebRtc_UWord8* targetBuffer = outFrame;
+ const WebRtc_UWord8* sourcePtr = inFrame;
+ const WebRtc_UWord8* interlacedSrc = inFrame + width * height;
+
+ WebRtc_UWord32 index = 0;
+
+ // Rotate Y
+ for(WebRtc_UWord32 newRow = 0; newRow < width; ++newRow)
+ {
+ for(WebRtc_Word32 newColumn = height-1; newColumn >= 0; --newColumn)
+ {
+ targetBuffer[index++] = sourcePtr[newColumn * width + newRow];
+ }
+ }
+
+ // extracting and rotating U and V
+ WebRtc_UWord8* u = targetBuffer + width * height;
+ WebRtc_UWord8* v = u + (width * height >> 2);
+ for (WebRtc_UWord32 colInd = 0; colInd < height >> 1; colInd ++)
+ {
+ for (WebRtc_UWord32 rowInd = 0; rowInd < width >> 1; rowInd ++)
+ {
+ u[rowInd * height / 2 + colInd] = interlacedSrc[(height / 2 - colInd - 1) * width
+ + 2 * rowInd];
+ v[rowInd * height / 2 + colInd] = interlacedSrc[(height / 2 - colInd - 1) * width
+ + 2 * rowInd + 1];
+ }
+ }
+
+ return (width * height * 3 >> 1);
+}
+
+WebRtc_Word32
+ConvertNV12ToI420AndRotateAntiClockwise(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ WebRtc_UWord8* targetBuffer = outFrame;
+ const WebRtc_UWord8* sourcePtr = inFrame;
+ const WebRtc_UWord8* interlacedSrc = inFrame + width * height;
+
+ WebRtc_UWord32 index = 0;
+ // Rotate Y
+ for(WebRtc_Word32 newRow = width - 1; newRow >= 0; --newRow)
+ {
+ for(WebRtc_UWord32 newColumn = 0; newColumn < height; ++newColumn)
+ {
+ targetBuffer[index++] = sourcePtr[newColumn * width + newRow];
+ }
+ }
+
+ // extracting and rotating U and V
+ WebRtc_UWord8* u = targetBuffer + width * height;
+ WebRtc_UWord8* v = u + (width * height >> 2);
+ index = 0;
+ for(WebRtc_Word32 newRow = (width >> 1) - 1; newRow >= 0; --newRow)
+ {
+ for(WebRtc_UWord32 newColumn = 0; newColumn < (height >> 1); ++newColumn)
+ {
+ u[index] = interlacedSrc[2 * (newColumn * (width >> 1) + newRow)];
+ v[index] = interlacedSrc[2 * (newColumn * (width >> 1) + newRow) + 1];
+ index++;
+ }
+ }
+
+ return (width * height * 3 >> 1);
+}
+
+WebRtc_Word32
+ConvertNV12ToRGB565(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ // Bi-Planar: Y plane followed by an interlaced U and V plane
+ const WebRtc_UWord8* interlacedSrc = inFrame + width * height;
+ WebRtc_UWord16* out = (WebRtc_UWord16*)(outFrame) + width * (height - 1);
+ WebRtc_UWord16* out2 = out - width;
+ WebRtc_Word32 tmpR, tmpG, tmpB;
+ const WebRtc_UWord8 *y1,*y2;
+ y1 = inFrame;
+ y2 = y1 + width;
+ WebRtc_UWord32 h, w;
+
+ for (h = (height >> 1); h > 0; h--)
+ { // 2 rows at a time, 2 y's at a time
+ for (w = 0; w < (width >> 1); w++)
+ { // vertical and horizontal sub-sampling
+ // 1. Convert to RGB888
+ // 2. Shift to adequate location (in the 16 bit word) - RGB 565
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[interlacedSrc[1]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[interlacedSrc[0]]
+ + mapVcg[interlacedSrc[1]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[interlacedSrc[0]] + 128) >> 8);
+ out[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[interlacedSrc[1]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[interlacedSrc[0]]
+ + mapVcg[interlacedSrc[1]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[interlacedSrc[0]] + 128) >> 8);
+ out2[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3);
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[interlacedSrc[1]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[interlacedSrc[0]]
+ + mapVcg[interlacedSrc[1]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[interlacedSrc[0]] + 128) >> 8);
+ out[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB ) >> 3);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[interlacedSrc[1]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[interlacedSrc[0]]
+ + mapVcg[interlacedSrc[1]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[interlacedSrc[0]] + 128) >> 8);
+ out2[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3);
+
+ y1 += 2;
+ y2 += 2;
+ out += 2;
+ out2 += 2;
+ interlacedSrc += 2;
+ }
+ y1 += width;
+ y2 += width;
+ out -= 3 * width;
+ out2 -= 3 * width;
+ } // end height for
+
+ return (width * height * 2);
+}
+
+//NV21 Android Functions
+WebRtc_Word32
+ConvertNV21ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ // Bi-Planar: Y plane followed by an interlaced U and V plane
+ WebRtc_UWord8* out = outFrame;
+ // copying Y plane as is
+ memcpy(out, inFrame, width * height);
+ // de-interlacing U and V
+ const WebRtc_UWord8 *interlacedSrc;
+ WebRtc_UWord8 *u, *v;
+ u = outFrame + width * height;
+ v = u + (width * height >> 2);
+ interlacedSrc = inFrame + width * height;
+ for (WebRtc_UWord32 ind = 0; ind < (width * height >> 2); ind ++)
+ {
+ v[ind] = interlacedSrc[2 * ind];
+ u[ind] = interlacedSrc[2 * ind + 1];
+ }
+ return (width * height * 3 >> 1);
+}
+WebRtc_Word32
+ConvertNV21ToI420AndRotate180(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ // Bi-Planar: Y plane followed by an interlaced U and V plane
+ WebRtc_UWord8* out = outFrame;
+ for(WebRtc_UWord32 index = 0; index < width * height; index++)
+ {
+ out[index] = inFrame[width * height - index - 1];
+ }
+ // de-interlacing U and V
+ const WebRtc_UWord8 *interlacedSrc;
+ WebRtc_UWord8 *u, *v;
+ u = outFrame + width * height;
+ v = u + (width * height >> 2);
+ interlacedSrc = inFrame + width * height;
+ // extracting and rotating 180
+ for (WebRtc_UWord32 index = 0; index < (width * height >> 2); index++)
+ {
+ v[(width * height >> 2) - index - 1] = interlacedSrc[2 * index];
+ u[(width * height >> 2) - index - 1] = interlacedSrc[2 * index + 1];
+ }
+ return (width * height * 3 >> 1);
+}
+
+WebRtc_Word32
+ConvertNV21ToI420AndRotateClockwise(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ // Paint the destination buffer black
+ memset(outFrame,0,width * height);
+ memset(outFrame + width * height,127,(width * height) / 2);
+ const WebRtc_Word32 offset = (width - height) / 2;
+
+ //Y
+ WebRtc_UWord8* yn= outFrame;
+ const WebRtc_UWord8* ys= inFrame;
+ for (WebRtc_UWord32 m = 0; m < height; ++m)// New row
+ {
+ yn += offset;
+ for (WebRtc_UWord32 n = 0; n < height; ++n) // new column
+ {
+ (*yn++) = ys[(height - 1 - n) * width + offset + m];
+ }
+ yn += offset;
+ }
+
+ //U & V
+ WebRtc_UWord8* un= outFrame + height * width;
+ WebRtc_UWord8* vn= outFrame+height * width + height * width / 4;
+ const WebRtc_UWord8* uvs= inFrame + height * width;
+
+ for (WebRtc_UWord32 m = 0;m < height / 2; ++m)// New row
+ {
+ un += offset / 2;
+ vn += offset / 2;
+ for (WebRtc_UWord32 n = 0;n < height / 2; ++n) // new column
+ {
+ (*un++) = uvs[(height / 2 - 1 - n) * width + offset + 2 * m + 1];
+ (*vn++) = uvs[(height / 2 - 1 - n) * width + offset + 2 * m];
+ }
+ un += offset / 2;
+ vn += offset / 2;
+ }
+
+ return (width * height * 3 >> 1);
+}
+
+WebRtc_Word32
+ConvertNV21ToI420AndRotateAntiClockwise(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ // Paint the destination buffer black
+ memset(outFrame,0,width * height);
+ memset(outFrame + width * height, 127, (width * height) / 2);
+
+ const WebRtc_Word32 offset = (width - height) / 2;
+
+ //Y
+ WebRtc_UWord8* yn = outFrame;
+ const WebRtc_UWord8* ys = inFrame;
+ for (WebRtc_UWord32 m = 0;m < height; ++m)// New row
+ {
+ yn += offset;
+ for (WebRtc_UWord32 n = 0;n < height; ++n) // new column
+ {
+ (*yn++) = ys[width * (n + 1) - 1 - offset - m];
+ }
+ yn += offset;
+ }
+
+ //U & V
+ WebRtc_UWord8* un= outFrame + height * width;
+ WebRtc_UWord8* vn= outFrame + height * width + height * width / 4;
+ const WebRtc_UWord8* uvs= inFrame + height * width;
+
+ for (WebRtc_UWord32 m = 0;m < height / 2; ++m)// New row
+ {
+ un += offset / 2;
+ vn += offset / 2;
+ for (WebRtc_UWord32 n = 0;n < height / 2; ++n) // new column
+ {
+ (*un++) = uvs[width * (n + 1) - 1 - offset - 2 * m];;
+ (*vn++) = uvs[width * (n + 1) - 1 - offset - 2 * m - 1];;
+ }
+ un += offset / 2;
+ vn += offset / 2;
+ }
+ return (width * height * 3 >> 1);
+}
+
+WebRtc_Word32
+ConvertI420ToRGBAIPhone(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ if (strideOut == 0)
+ {
+ strideOut = width;
+ } else if (strideOut < width)
+ {
+ return -1;
+ }
+
+ // RGB orientation - bottom up
+ // same as ARGB but reverting RGB <-> BGR (same as previous version)
+ WebRtc_UWord8* out = outFrame + strideOut * height * 4 - strideOut * 4;
+ WebRtc_UWord8* out2 = out - strideOut * 4;
+ WebRtc_Word32 tmpR, tmpG, tmpB;
+ const WebRtc_UWord8 *y1,*y2, *u, *v;
+ WebRtc_UWord32 h, w;
+
+ y1 = inFrame;
+ y2 = y1 + width;
+ u = y1 + width * height;
+ v = u + ((width * height) >> 2);
+
+ for (h = (height >> 1); h > 0; h--)
+ { // 2 rows at a time, 2 y's at a time
+ for (w = 0; w < (width >> 1); w++)
+ { // vertical and horizontal sub-sampling
+ tmpR = (WebRtc_Word32)((298 * (y1[0] - 16) + 409 * (v[0] - 128) + 128) >> 8);
+ tmpG = (WebRtc_Word32)((298 * (y1[0] - 16) - 100 * (u[0] - 128)
+ - 208 * (v[0] - 128) + 128 ) >> 8);
+ tmpB = (WebRtc_Word32)((298 * (y1[0] - 16) + 516 * (u[0] - 128) + 128 ) >> 8);
+
+ out[3] = 0xff;
+ out[0] = Clip(tmpR);
+ out[1] = Clip(tmpG);
+ out[2] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((298 * (y2[0] - 16) + 409 * (v[0] - 128) + 128) >> 8);
+ tmpG = (WebRtc_Word32)((298 * (y2[0] - 16) - 100 * (u[0] - 128)
+ - 208 * (v[0] - 128) + 128) >> 8);
+ tmpB = (WebRtc_Word32)((298 * (y2[0] - 16) + 516 * (u[0] - 128) + 128) >> 8);
+
+ out2[3] = 0xff;
+ out2[0] = Clip(tmpR);
+ out2[1] = Clip(tmpG);
+ out2[2] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((298 * (y1[1] - 16) + 409 * (v[0] - 128) + 128 ) >> 8);
+ tmpG = (WebRtc_Word32)((298 * (y1[1] - 16) - 100 * (u[0] - 128)
+ - 208 * (v[0] - 128) + 128 ) >> 8);
+ tmpB = (WebRtc_Word32)((298 * (y1[1] - 16) + 516 * (u[0] - 128) + 128) >> 8);
+
+ out[7] = 0xff;
+ out[4] = Clip(tmpR);
+ out[5] = Clip(tmpG);
+ out[6] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((298 * (y2[1] - 16) + 409 * (v[0] - 128) + 128) >> 8);
+ tmpG = (WebRtc_Word32)((298 * (y2[1] - 16) - 100 * (u[0] - 128)
+ - 208 * (v[0] - 128) + 128) >> 8);
+ tmpB = (WebRtc_Word32)((298 * (y2[1] - 16) + 516 * (u[0] - 128) + 128 ) >> 8);
+
+ out2[7] = 0xff;
+ out2[4] = Clip(tmpR);
+ out2[5] = Clip(tmpG);
+ out2[6] = Clip(tmpB);
+
+ out += 8;
+ out2 += 8;
+ y1 += 2;
+ y2 += 2;
+ u++;
+ v++;
+ }
+
+ y1 += width;
+ y2 += width;
+ out -= (2 * strideOut + width) * 4;
+ out2 -= (2 * strideOut + width) * 4;
+ } // end height for
+
+ return strideOut * height * 4;
+}
+
+WebRtc_Word32
+ConvertI420ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width,
+ WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (strideOut == 0 || strideOut == width)
+ {
+ memcpy(outFrame, inFrame, 3 * width * (height >> 1));
+ strideOut = width;
+ } else if (strideOut < width)
+ {
+ return -1;
+ } else
+ {
+ WebRtc_UWord32 i = 0;
+ for (; i < height; i++)
+ {
+ memcpy(outFrame,inFrame ,width);
+ outFrame += strideOut;
+ inFrame += width;
+ }
+ for (i = 0; i < (height >> 1);i++)
+ {
+ memcpy(outFrame, inFrame,width >> 1);
+ outFrame += strideOut >> 1;
+ inFrame += width >> 1;
+ }
+ for (i = 0; i< (height >> 1); i++)
+ {
+ memcpy(outFrame, inFrame,width >> 1);
+ outFrame += strideOut >> 1;
+ inFrame += width >> 1;
+ }
+ }
+ return 3 * strideOut * (height >> 1);
+}
+
+WebRtc_Word32
+ConvertUYVYToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight,
+ WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight)
+{
+ if (inWidth < 1 || inHeight < 1 || outHeight < 1 || outWidth < 1)
+ {
+ return -1;
+ }
+ WebRtc_UWord32 i = 0;
+ WebRtc_UWord32 j = 0;
+ WebRtc_Word32 cutDiff = 0; // in pixels
+ WebRtc_Word32 padDiffLow = 0; // in pixels
+ WebRtc_Word32 padDiffHigh = 0; // in pixels
+ WebRtc_UWord8* outI = outFrame;
+ WebRtc_UWord8* outCr = outFrame + outWidth * outHeight;
+ WebRtc_UWord8* outCb = outFrame + outWidth * outHeight + outWidth * (outHeight >> 2);
+
+ // cut height?
+ if (inHeight > outHeight)
+ {
+ // parse away half of the lines
+ inFrame += ((inHeight - outHeight) / 2) * inWidth * 2;
+ }
+ // cut width?
+ if (inWidth > outWidth)
+ {
+ cutDiff = (inWidth - outWidth); // in pixels
+ // start half of the width diff into the line
+ inFrame += cutDiff; // each pixel is 2 bytes hence diff is the correct value in bytes
+ }
+ // pad height?
+ if (inHeight < outHeight)
+ {
+ // pad top
+ WebRtc_Word32 diff = (outHeight - inHeight) >> 1;
+ memset(outI, 0, diff * outWidth);
+ outI += diff * outWidth;
+ WebRtc_Word32 colorLength = (diff >> 1) * (outWidth >> 1);
+ memset(outCr, 127, colorLength);
+ memset(outCb, 127, colorLength);
+ outCr += colorLength;
+ outCb += colorLength;
+
+ // pad bottom
+ memset(outI + outWidth * inHeight, 0, diff * outWidth);
+ memset(outCr + (outWidth * inHeight >> 2), 127, colorLength);
+ memset(outCb + (outWidth * inHeight >> 2), 127, colorLength);
+ }
+ // pad width?
+ if (inWidth < outWidth)
+ {
+ padDiffLow = (outWidth - inWidth) >> 1; // in pixels
+ padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels
+ }
+ WebRtc_UWord32 height = 0;
+ if (inHeight > outHeight)
+ height = outHeight;
+ else
+ height = inHeight;
+
+ for (; i< (height >> 1); i++) // 2 rows per loop
+ {
+ // pad beginning of row?
+ if (padDiffLow)
+ {
+ // pad row
+ memset(outI,0,padDiffLow);
+ memset(outCr,127,padDiffLow >> 1);
+ memset(outCb,127,padDiffLow >> 1);
+ outI += padDiffLow;
+ outCr += padDiffLow >> 1;
+ outCb += padDiffLow >> 1;
+ }
+
+ for (j = 0; j < (inWidth >> 1); j++) // 2 pixels per loop
+ {
+ outI[0] = inFrame[1];
+ *outCr = inFrame[0];
+ outI[1] = inFrame[3];
+ *outCb = inFrame[2];
+ inFrame += 4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ // pad end of row?
+ if (padDiffHigh)
+ {
+ memset(outI,0,padDiffHigh);
+ memset(outCr,127,padDiffHigh >> 1);
+ memset(outCb,127,padDiffHigh >> 1);
+ outI += padDiffHigh;
+ outCr += padDiffHigh >> 1;
+ outCb += padDiffHigh >> 1;
+ }
+ // next row
+ // pad beginning of row?
+ memset(outI,0,padDiffLow);
+ outI += padDiffLow;
+
+ for (j = 0; j < (inWidth >> 1);j++)
+ {
+ outI[0] = inFrame[1];
+ outI[1] = inFrame[3];
+ inFrame += 4;
+ outI += 2;
+ }
+ // pad end of row?
+ if (padDiffHigh)
+ {
+ memset(outI,0,padDiffHigh);
+ outI += padDiffHigh;
+ } else
+ {
+ // cut row
+ for (j = 0; j < (outWidth >> 1); j++) // 2 pixels per loop
+ {
+ outI[0] = inFrame[1];
+ *outCr = inFrame[0];
+ outI[1] = inFrame[3];
+ *outCb = inFrame[2];
+ inFrame += 4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ inFrame += cutDiff * 2;
+ // next row
+ for (j = 0; j < (outWidth >> 1);j++)
+ {
+ outI[0] = inFrame[1];
+ outI[1] = inFrame[3];
+ inFrame += 4;
+ outI += 2;
+ }
+ inFrame += cutDiff * 2;
+ }
+ }
+ return outWidth * (outHeight >> 1) * 3;
+}
+
+WebRtc_Word32
+ConvertUYVYToI420interlaced(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth,
+ WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight)
+{
+ if (inWidth < 1 || inHeight < 1 || outHeight < 1 || outWidth < 1)
+ {
+ return -1;
+ }
+ WebRtc_Word32 i = 0;
+ WebRtc_UWord32 j = 0;
+ WebRtc_Word32 cutDiff = 0; // in pixels
+ WebRtc_Word32 padDiffLow = 0; // in pixels
+ WebRtc_Word32 padDiffHigh = 0; // in pixels
+ WebRtc_UWord8* outI = outFrame;
+ WebRtc_UWord8* outCr = outFrame + outWidth * outHeight;
+ WebRtc_UWord8* outCb = outFrame + outWidth * outHeight + outWidth * ( outHeight >> 2 );
+
+ // cut height?
+ if (inHeight > outHeight)
+ {
+ // parse away half of the lines
+ inFrame += (( inHeight - outHeight ) / 2) * inWidth * 2;
+ }
+ // cut width?
+ if (inWidth > outWidth)
+ {
+ cutDiff = (inWidth - outWidth); // in pixels
+ // start half of the width diff into the line
+ inFrame += cutDiff; // each pixel is 2 bytes hence diff is the correct value in bytes
+ }
+ // pad height?
+ if (inHeight < outHeight)
+ {
+ // pad top
+ WebRtc_Word32 diff = (outHeight - inHeight) >> 1;
+ memset(outI, 0, diff * outWidth);
+ outI += diff * outWidth;
+ WebRtc_Word32 colorLength =(diff >> 1) * (outWidth >> 1);
+ memset(outCr, 127, colorLength);
+ memset(outCb, 127, colorLength);
+ outCr += colorLength;
+ outCb += colorLength;
+
+ // pad bottom
+ memset(outI+outWidth * inHeight, 0, diff * outWidth);
+ memset(outCr+(outWidth * inHeight >> 2), 127, colorLength);
+ memset(outCb+(outWidth * inHeight >> 2), 127, colorLength);
+ }
+ // pad width?
+ if (inWidth < outWidth)
+ {
+ padDiffLow = (outWidth - inWidth) >> 1; // in pixels
+ padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels
+ }
+ WebRtc_Word32 height = 0;
+ if (inHeight > outHeight)
+ height = outHeight;
+ else
+ height = inHeight;
+
+ for (; i < (height >> 1); i++) // 2 rows per loop
+ {
+ // pad beginning of row?
+ if (padDiffLow)
+ {
+ // pad row
+ memset(outI,0,padDiffLow);
+ memset(outCr,127,padDiffLow >> 1);
+ memset(outCb,127,padDiffLow >> 1);
+ outI += padDiffLow;
+ outCr += padDiffLow / 2;
+ outCb += padDiffLow / 2;
+
+ for (j = 0; j < (inWidth >> 1); j++) // 2 pixels per loop
+ {
+ outI[0] = inFrame[1];
+ *outCr = inFrame[0];
+ outI[1] = inFrame[3];
+ *outCb = inFrame[2];
+ inFrame += 4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ // pad end of row?
+ if (padDiffHigh)
+ {
+ memset(outI,0,padDiffHigh);
+ memset(outCr,127,padDiffHigh >> 1);
+ memset(outCb,127,padDiffHigh >> 1);
+ outI += padDiffHigh;
+ outCr += padDiffHigh >> 1;
+ outCb += padDiffHigh >> 1;
+ }
+ // next row
+ // pad beginning of row?
+ memset(outI,0,padDiffLow);
+ outI += padDiffLow;
+
+ for (j = 0; j < (inWidth >> 1); j++)
+ {
+ outI[0] = inFrame[1];
+ outI[1] = inFrame[3];
+ inFrame += 4;
+ outI += 2;
+ }
+ // pad end of row?
+ if (padDiffHigh)
+ {
+ memset(outI,0,padDiffHigh);
+ outI += padDiffHigh;
+ }
+ } else
+ {
+ // cut row
+ for (j = 0; j < (outWidth >> 1); j++) // 2 pixels per loop
+ {
+ outI[0] = inFrame[1];
+ *outCr = inFrame[0];
+ outI[1] = inFrame[3];
+ *outCb = inFrame[2];
+ inFrame += 4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ inFrame -= (outWidth * 2);
+ const WebRtc_UWord8 *inFrame2 = inFrame + (inWidth * 2) * 2;
+
+ if(i + 1 == (height >> 1))
+ {
+ // last row
+ for (j = 0; j < (outWidth >> 1); j++)
+ {
+ // copy last row
+ outI[0] = inFrame[1];
+ outI[1] = inFrame[3];
+ inFrame += 4;
+ inFrame2 += 4;
+ outI += 2;
+ }
+ } else
+ {
+ // next row
+ for (j = 0; j < (outWidth >> 1); j++)
+ {
+ outI[0] = (inFrame[1] + inFrame2[1]) >> 1;
+ outI[1] = (inFrame[3] + inFrame2[1]) >> 1;
+ inFrame += 4;
+ inFrame2 += 4;
+ outI += 2;
+ }
+ }
+ inFrame += cutDiff * 2;
+ inFrame += inWidth * 2; // skip next row
+ }
+ }
+ return outWidth * (outHeight >> 1) * 3;
+}
+
+WebRtc_Word32
+ConvertUYVYToI420(WebRtc_UWord32 width,WebRtc_UWord32 height, const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ WebRtc_UWord32 i = 0;
+ WebRtc_UWord32 j = 0;
+ WebRtc_UWord8* outI = outFrame;
+ WebRtc_UWord8* outCr = outFrame + width * height;
+ WebRtc_UWord8* outCb = outFrame + width * height + width * (height >> 2);
+ for (; i< (height >> 1);i++)
+ {
+ for (j = 0; j < (width >> 1); j++)
+ {
+ outI[0] = inFrame[1];
+ *outCr = inFrame[0];
+ outI[1] = inFrame[3];
+ *outCb = inFrame[2];
+ inFrame += 4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ for (j = 0; j < (width >> 1); j++)
+ {
+ outI[0] = inFrame[1];
+ outI[1] = inFrame[3];
+ inFrame += 4;
+ outI += 2;
+ }
+ }
+ return width * (height >> 1) * 3;
+}
+
+WebRtc_Word32
+ConvertYUY2ToI420interlaced(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth,
+ WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight)
+{
+ if (inWidth < 1 || inHeight < 1 || outHeight < 1 || outWidth < 1)
+ {
+ return -1;
+ }
+ // use every other row and interpolate the removed row
+ WebRtc_UWord32 i = 0;
+ WebRtc_UWord32 j = 0;
+ WebRtc_Word32 cutDiff = 0; // in pixels
+ WebRtc_Word32 padDiffLow = 0; // in pixels
+ WebRtc_Word32 padDiffHigh = 0; // in pixels
+ WebRtc_UWord8* outI = outFrame;
+ WebRtc_UWord8* inPtr3 = (WebRtc_UWord8*)inFrame + inWidth * 2 * 2; // ptr to third row
+ WebRtc_UWord8* outCr = outFrame + outWidth * outHeight;
+ WebRtc_UWord8* outCb = outFrame +outWidth * outHeight + outWidth * (outHeight >> 2);
+
+ // cut height?
+ if(inHeight > outHeight)
+ {
+ // parse away half of the lines
+ inFrame += ((inHeight - outHeight) / 2) * inWidth * 2;
+ inPtr3 += ((inHeight - outHeight) / 2) * inWidth * 2;
+ }
+ // cut width?
+ if(inWidth > outWidth)
+ {
+ cutDiff = (inWidth - outWidth); // in pixels
+ // start half of the width diff into the line
+ inPtr3 += cutDiff;
+ inFrame += cutDiff; // each pixel is 2 bytes hence diff is the correct value in bytes
+ }
+ // pad height?
+ if(inHeight < outHeight)
+ {
+ // pad top
+ WebRtc_Word32 diff = (outHeight - inHeight) / 2;
+ memset(outI, 0, diff * outWidth);
+ outI += diff * outWidth;
+ WebRtc_Word32 colorLength =(diff / 2) * (outWidth / 2);
+ memset(outCr, 127, colorLength);
+ memset(outCb, 127, colorLength);
+ outCr+= colorLength;
+ outCb+= colorLength;
+
+ // pad bottom
+ memset(outI + outWidth * inHeight, 0, diff * outWidth);
+ memset(outCr + (outWidth * inHeight / 4), 127, colorLength);
+ memset(outCb + (outWidth * inHeight / 4), 127, colorLength);
+ }
+ // pad width?
+ if(inWidth < outWidth)
+ {
+ padDiffLow = (outWidth - inWidth) / 2; // in pixels
+ padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels
+ }
+ WebRtc_UWord32 height = 0;
+ if(inHeight > outHeight)
+ height = outHeight;
+ else
+ height = inHeight;
+
+ for (; i< (height >> 1);i++) // 2 rows per loop
+ {
+ // pad beginning of row?
+ if(padDiffLow)
+ {
+ // pad row
+ memset(outI,0,padDiffLow);
+ memset(outCr,127,padDiffLow / 2);
+ memset(outCb,127,padDiffLow / 2);
+ outI += padDiffLow;
+ outCr += padDiffLow / 2;
+ outCb += padDiffLow / 2;
+
+ for (j = 0; j< (inWidth >> 1);j++) // 2 pixels per loop
+ {
+ outI[0] = inFrame[0];
+ *outCr = inFrame[1];
+ outI[1] = inFrame[2];
+ *outCb = inFrame[3];
+ inFrame +=4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ // pad end of row?
+ if (padDiffHigh)
+ {
+ memset(outI,0,padDiffHigh);
+ memset(outCr,127,padDiffHigh / 2);
+ memset(outCb,127,padDiffHigh / 2);
+ outI += padDiffHigh;
+ outCr += padDiffHigh / 2;
+ outCb += padDiffHigh / 2;
+ }
+ // next row
+ // pad beginning of row?
+ memset(outI,0,padDiffLow);
+ outI += padDiffLow;
+ inFrame -= inWidth * 2;
+ if (i == (height >> 1) - 1)
+ {
+ // last loop
+ // copy the last row
+ for (j = 0; j< (inWidth >> 1); j++)
+ {
+ outI[0] = inFrame[0];
+ outI[1] = inFrame[2];
+ inFrame += 4;
+ outI += 2;
+ }
+ } else
+ {
+ // turn back inFrame
+ for (j = 0; j < (inWidth >> 1); j++)
+ {
+ outI[0] = (inFrame[0] + inPtr3[0]) >> 1;
+ outI[1] = (inFrame[2] + inPtr3[2]) >> 1;
+ inFrame += 4;
+ inPtr3 += 4;
+ outI += 2;
+ }
+ inFrame += inWidth * 2;
+ inPtr3 += inWidth * 2;
+ }
+
+ // pad end of row?
+ if (padDiffHigh)
+ {
+ memset(outI,0,padDiffHigh);
+ outI += padDiffHigh;
+ }
+ } else
+ {
+ // cut row
+ for (j = 0; j < (outWidth >> 1); j++) // 2 pixels per loop
+ {
+ outI[0] = inFrame[0];
+ *outCr = inFrame[1];
+ outI[1] = inFrame[2];
+ *outCb = inFrame[3];
+ inFrame += 4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ inFrame += cutDiff * 2;
+ inFrame -= inWidth * 2;
+
+ if (i == (height >> 1) -1)
+ {
+ // last loop
+ // copy the last row
+ for (j = 0; j < (outWidth >> 1);j++)
+ {
+ outI[0] = inFrame[0];
+ outI[1] = inFrame[2];
+ inFrame +=4;
+ outI += 2;
+ }
+ } else
+ {
+ // next row
+ for (j = 0; j< (outWidth >> 1);j++)
+ {
+ outI[0] = (inFrame[0] + inPtr3[0]) >> 1;
+ outI[1] = (inFrame[2] + inPtr3[2]) >> 1;
+ inPtr3 += 4;
+ inFrame += 4;
+ outI += 2;
+ }
+ inFrame += cutDiff * 2;
+ inPtr3 += cutDiff * 2;
+ }
+ inFrame += inWidth * 2;
+ inPtr3 += inWidth * 2;
+ }
+ }
+ return outWidth * (outHeight >> 1) * 3;
+}
+
+WebRtc_Word32
+ConvertYUY2ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight,
+ WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight)
+{
+ if (inWidth < 1 || inHeight < 1 || outHeight < 1 || outWidth < 1)
+ {
+ return -1;
+ }
+ WebRtc_UWord32 i = 0;
+ WebRtc_UWord32 j = 0;
+ WebRtc_Word32 cutDiff = 0; // in pixels
+ WebRtc_Word32 padDiffLow = 0; // in pixels
+ WebRtc_Word32 padDiffHigh = 0; // in pixels
+ WebRtc_UWord8* outI = outFrame;
+ WebRtc_UWord8* outCr = outFrame + outWidth * outHeight;
+ WebRtc_UWord8* outCb = outFrame + outWidth * outHeight + outWidth * (outHeight >> 2);
+
+ // cut height?
+ if (inHeight > outHeight)
+ {
+ // parse away half of the lines
+ inFrame += ((inHeight - outHeight) >> 1) * inWidth * 2;
+ }
+ // cut width?
+ if (inWidth > outWidth)
+ {
+ cutDiff = (inWidth - outWidth); // in pixels
+ // start half of the width diff into the line
+ inFrame += cutDiff; // each pixel is 2 bytes hence diff is the correct value in bytes
+ }
+ // pad height?
+ if (inHeight < outHeight)
+ {
+ // pad top
+ WebRtc_Word32 diff = (outHeight - inHeight) >> 1;
+ memset(outI, 0, diff * outWidth);
+ outI += diff * outWidth;
+ WebRtc_Word32 colorLength =(diff >> 1) * (outWidth >> 1);
+ memset(outCr, 127, colorLength);
+ memset(outCb, 127, colorLength);
+ outCr += colorLength;
+ outCb += colorLength;
+
+ // pad bottom
+ memset(outI + outWidth * inHeight, 0, diff * outWidth);
+ memset(outCr + (outWidth * inHeight >> 2), 127, colorLength);
+ memset(outCb + (outWidth * inHeight >> 2), 127, colorLength);
+ }
+ // pad width?
+ if (inWidth < outWidth)
+ {
+ padDiffLow = (outWidth - inWidth) >> 1; // in pixels
+ padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels
+ }
+ WebRtc_UWord32 height = 0;
+ if (inHeight > outHeight)
+ height = outHeight;
+ else
+ height = inHeight;
+
+ for (; i< (height >> 1); i++) // 2 rows per loop
+ {
+ // pad beginning of row?
+ if (padDiffLow)
+ {
+ // pad row
+ memset(outI,0,padDiffLow);
+ memset(outCr,127,padDiffLow >> 1);
+ memset(outCb,127,padDiffLow >> 1);
+ outI += padDiffLow;
+ outCr += padDiffLow >> 1;
+ outCb += padDiffLow >> 1;
+
+ for (j = 0; j< (inWidth >> 1);j++) // 2 pixels per loop
+ {
+ outI[0] = inFrame[0];
+ *outCr = inFrame[1];
+ outI[1] = inFrame[2];
+ *outCb = inFrame[3];
+ inFrame += 4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ // pad end of row?
+ if (padDiffHigh)
+ {
+ memset(outI,0,padDiffHigh);
+ memset(outCr,127,padDiffHigh >> 1);
+ memset(outCb,127,padDiffHigh >> 1);
+ outI += padDiffHigh;
+ outCr += padDiffHigh >> 1;
+ outCb += padDiffHigh >> 1;
+ }
+ // next row
+ // pad beginning of row?
+ memset(outI,0,padDiffLow);
+ outI += padDiffLow;
+
+ for (j = 0; j< (inWidth >> 1); j++)
+ {
+ outI[0] = inFrame[0];
+ outI[1] = inFrame[2];
+ inFrame += 4;
+ outI += 2;
+ }
+ // pad end of row?
+ if (padDiffHigh)
+ {
+ memset(outI,0,padDiffHigh);
+ outI += padDiffHigh;
+ }
+ } else
+ {
+ // cut row
+ for (j = 0; j < (outWidth >> 1); j++) // 2 pixels per loop
+ {
+ outI[0] = inFrame[0];
+ *outCr = inFrame[1];
+ outI[1] = inFrame[2];
+ *outCb = inFrame[3];
+ inFrame += 4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ inFrame += cutDiff * 2;
+ // next row
+ for (j = 0; j < (outWidth >> 1); j++)
+ {
+ outI[0] = inFrame[0];
+ outI[1] = inFrame[2];
+ inFrame += 4;
+ outI += 2;
+ }
+ inFrame += cutDiff * 2;
+ }
+ }
+ return outWidth * (outHeight >> 1) * 3;
+}
+
+WebRtc_Word32
+ConvertYUY2ToI420(WebRtc_UWord32 width, WebRtc_UWord32 height,const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame)
+{
+#ifndef SCALEOPT
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ WebRtc_UWord32 i =0;
+ WebRtc_UWord32 j =0;
+ WebRtc_UWord8* outI = outFrame;
+ WebRtc_UWord8* outCr = outFrame + width * height;
+ WebRtc_UWord8* outCb = outFrame +width * height + width * (height >> 2);
+
+ for (; i < (height >> 1); i++)
+ {
+ for (j = 0; j < (width >> 1); j++)
+ {
+ outI[0] = inFrame[0];
+ *outCr = inFrame[1];
+ outI[1] = inFrame[2];
+ *outCb = inFrame[3];
+ inFrame += 4;
+ outI += 2;
+ outCr++;
+ outCb++;
+ }
+ for (j = 0; j < (width >> 1); j++)
+ {
+ outI[0] = inFrame[0];
+ outI[1] = inFrame[2];
+ inFrame += 4;
+ outI += 2;
+ }
+ }
+#else
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ WebRtc_Word32 i =0;
+ WebRtc_Word32 j =0;
+ WebRtc_UWord8* outI = outFrame;
+ WebRtc_UWord8* outCr = outFrame + width * height;
+ WebRtc_UWord8* outCb = outFrame + width * height + width * (height >> 2);
+
+ WebRtc_Word32 height_half = height / 2;
+
+ _asm{
+ mov esi, DWORD PTR [width]
+ mov edx, DWORD PTR [height_half]
+
+ ; prepare masks:
+ pxor xmm0, xmm0
+ pcmpeqd xmm1, xmm1
+ punpcklbw xmm1, xmm0
+ pcmpeqd xmm2, xmm2
+ punpcklbw xmm0, xmm2
+ test edx, edx
+ jle exit_
+
+ xor ebx, ebx
+ mov edi, DWORD PTR [outFrame]
+ sar esi, 4
+ test esi, esi
+ jle exit_
+
+ loop0:
+ add ebx, 1
+
+ mov DWORD PTR [i], ebx
+ mov ebx, DWORD PTR [inFrame]
+ mov edx, DWORD PTR [outCr]
+ mov eax, DWORD PTR [outCb]
+ xor ecx, ecx
+
+ loop1:
+
+ movdqa xmm5, xmm1
+
+ movdqa xmm2, xmm1
+ movdqu xmm4, XMMWORD PTR [ebx]
+ movdqu xmm3, XMMWORD PTR [ebx+16]
+
+ add ebx, 32
+ pand xmm5, xmm4
+ pand xmm4, xmm0
+ psrldq xmm4, 1
+ pand xmm2, xmm3
+ pand xmm3, xmm0
+ psrldq xmm3, 1
+
+ packuswb xmm5, xmm2
+
+ movdqu XMMWORD PTR [edi], xmm5
+ movdqa xmm2, xmm1
+ packuswb xmm4, xmm3
+ pand xmm2, xmm4
+ pand xmm4, xmm0
+ psrldq xmm4, 1
+ packuswb xmm2, xmm4
+
+ movq QWORD PTR [edx], xmm2
+ psrldq xmm2, 8
+ movq QWORD PTR [eax], xmm2
+
+ add edi, 16
+ add edx, 8
+ add eax, 8
+ add ecx, 1
+ cmp ecx, esi
+ jl loop1
+
+ mov DWORD PTR [outCb], eax
+ mov DWORD PTR [outCr], edx
+ mov edx, DWORD PTR [height_half]
+ mov DWORD PTR [inFrame], ebx
+ mov ebx, DWORD PTR [i]
+
+ test esi, esi
+ jle exit_
+
+ mov eax, DWORD PTR [inFrame] //now becomes 00568FE8
+ xor ecx, ecx
+
+ loop2:
+
+ movdqu xmm3, XMMWORD PTR [eax]
+ movdqu xmm2, XMMWORD PTR [eax+16]
+ add eax, 32
+ pand xmm3, xmm1
+ pand xmm2, xmm1
+ packuswb xmm3, xmm2
+ movdqu XMMWORD PTR [edi], xmm3
+
+ add edi, 16
+ add ecx, 1
+ cmp ecx, esi
+ jl loop2
+
+ mov DWORD PTR [inFrame], eax //now 005692A8
+ mov eax, DWORD PTR [width]
+ cmp ebx, edx
+ jl loop0
+ exit_:
+ }
+#endif
+ return width * (height >> 1) * 3;
+}
+
+// make a center cut
+WebRtc_Word32
+CutI420Frame(WebRtc_UWord8* frame, WebRtc_UWord32 fromWidth, WebRtc_UWord32 fromHeight,
+ WebRtc_UWord32 toWidth, WebRtc_UWord32 toHeight)
+{
+ if (toWidth < 1 || fromWidth < 1 || toHeight < 1 || fromHeight < 1 )
+ {
+ return -1;
+ }
+ if (toWidth == fromWidth && toHeight == fromHeight)
+ {
+ // nothing to do
+ return 3 * toHeight * toWidth / 2;
+ }
+ if (toWidth > fromWidth || toHeight > fromHeight)
+ {
+ // error
+ return -1;
+ }
+ WebRtc_UWord32 i = 0;
+ WebRtc_Word32 m = 0;
+ WebRtc_UWord32 loop = 0;
+ WebRtc_UWord32 halfToWidth = toWidth / 2;
+ WebRtc_UWord32 halfToHeight = toHeight / 2;
+ WebRtc_UWord32 halfFromWidth = fromWidth / 2;
+ WebRtc_UWord32 halfFromHeight= fromHeight / 2;
+ WebRtc_UWord32 cutHeight = ( fromHeight - toHeight ) / 2; //12
+ WebRtc_UWord32 cutWidth = ( fromWidth - toWidth ) / 2; // 16
+
+ for (i = fromWidth * cutHeight + cutWidth; loop < toHeight ; loop++, i += fromWidth)
+ {
+ memcpy(&frame[m],&frame[i],toWidth);
+ m += toWidth;
+ }
+ i = fromWidth * fromHeight; // ilum
+ loop = 0;
+ for ( i += (halfFromWidth * cutHeight / 2 + cutWidth / 2);
+ loop < halfToHeight; loop++,i += halfFromWidth)
+ {
+ memcpy(&frame[m],&frame[i],halfToWidth);
+ m += halfToWidth;
+ }
+ loop = 0;
+ i = fromWidth * fromHeight + halfFromHeight * halfFromWidth; // ilum +Cr
+ for( i += (halfFromWidth * cutHeight / 2 + cutWidth / 2); loop < halfToHeight; loop++, i += halfFromWidth)
+ {
+ memcpy(&frame[m],&frame[i],halfToWidth);
+ m += halfToWidth;
+ }
+ return halfToWidth * toHeight * 3;// new size 64*96*3; // 128/2 == 64
+}
+
+WebRtc_Word32
+ConvertI420ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth,
+ WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth,
+ WebRtc_UWord32 outHeight)
+{
+ if (inWidth < 1 || outWidth < 1 || inHeight < 1 || outHeight < 1 )
+ {
+ return -1;
+ }
+ if (inWidth == outWidth && inHeight == outHeight)
+ {
+ memcpy(outFrame, inFrame, 3*outWidth*(outHeight>>1));
+ } else
+ {
+ if( inHeight < outHeight)
+ {
+ // pad height
+ WebRtc_Word32 padH = outHeight - inHeight;
+ WebRtc_UWord32 i =0;
+ WebRtc_Word32 padW = 0;
+ WebRtc_Word32 cutW = 0;
+ WebRtc_Word32 width = inWidth;
+ if (inWidth < outWidth)
+ {
+ // pad width
+ padW = outWidth - inWidth;
+ } else
+ {
+ // cut width
+ cutW = inWidth - outWidth;
+ width = outWidth;
+ }
+ if (padH)
+ {
+ memset(outFrame, 0, outWidth * (padH >> 1));
+ outFrame += outWidth * (padH >> 1);
+ }
+ for (i = 0; i < inHeight;i++)
+ {
+ if (padW)
+ {
+ memset(outFrame, 0, padW / 2);
+ outFrame += padW / 2;
+ }
+ inFrame += cutW >> 1; // in case we have a cut
+ memcpy(outFrame,inFrame ,width);
+ inFrame += cutW >> 1;
+ outFrame += width;
+ inFrame += width;
+ if (padW)
+ {
+ memset(outFrame, 0, padW / 2);
+ outFrame += padW / 2;
+ }
+ }
+ if (padH)
+ {
+ memset(outFrame, 0, outWidth * (padH >> 1));
+ outFrame += outWidth * (padH >> 1);
+ }
+ if (padH)
+ {
+ memset(outFrame, 127, (outWidth >> 2) * (padH >> 1));
+ outFrame += (outWidth >> 2) * (padH >> 1);
+ }
+ for (i = 0; i < (inHeight >> 1); i++)
+ {
+ if (padW)
+ {
+ memset(outFrame, 127, padW >> 2);
+ outFrame += padW >> 2;
+ }
+ inFrame += cutW >> 2; // in case we have a cut
+ memcpy(outFrame, inFrame,width >> 1);
+ inFrame += cutW >> 2;
+ outFrame += width >> 1;
+ inFrame += width >> 1;
+ if (padW)
+ {
+ memset(outFrame, 127, padW >> 2);
+ outFrame += padW >> 2;
+ }
+ }
+ if (padH)
+ {
+ memset(outFrame, 127, (outWidth >> 1) * (padH >> 1));
+ outFrame += (outWidth >> 1) * (padH >> 1);
+ }
+ for (i = 0; i < (inHeight >> 1); i++)
+ {
+ if (padW)
+ {
+ memset(outFrame, 127, padW >> 2);
+ outFrame += padW >> 2;
+ }
+ inFrame += cutW >> 2; // in case we have a cut
+ memcpy(outFrame, inFrame,width >> 1);
+ inFrame += cutW >> 2;
+ outFrame += width >> 1;
+ inFrame += width >> 1;
+ if (padW)
+ {
+ memset(outFrame, 127, padW >> 2);
+ outFrame += padW >> 2;
+ }
+ }
+ if (padH)
+ {
+ memset(outFrame, 127, (outWidth >> 2) * (padH >> 1));
+ outFrame += (outWidth >> 2) * (padH >> 1);
+ }
+ } else
+ {
+ // cut height
+ WebRtc_UWord32 i =0;
+ WebRtc_Word32 padW = 0;
+ WebRtc_Word32 cutW = 0;
+ WebRtc_Word32 width = inWidth;
+
+ if (inWidth < outWidth)
+ {
+ // pad width
+ padW = outWidth - inWidth;
+ } else
+ {
+ // cut width
+ cutW = inWidth - outWidth;
+ width = outWidth;
+ }
+ WebRtc_Word32 diffH = inHeight - outHeight;
+ inFrame += inWidth * (diffH >> 1); // skip top I
+
+ for (i = 0; i < outHeight; i++)
+ {
+ if (padW)
+ {
+ memset(outFrame, 0, padW / 2);
+ outFrame += padW / 2;
+ }
+ inFrame += cutW >> 1; // in case we have a cut
+ memcpy(outFrame,inFrame ,width);
+ inFrame += cutW >> 1;
+ outFrame += width;
+ inFrame += width;
+ if (padW)
+ {
+ memset(outFrame, 0, padW / 2);
+ outFrame += padW / 2;
+ }
+ }
+ inFrame += inWidth * (diffH >> 1); // skip end I
+ inFrame += (inWidth >> 2) * (diffH >> 1); // skip top of Cr
+ for (i = 0; i < (outHeight >> 1); i++)
+ {
+ if (padW)
+ {
+ memset(outFrame, 127, padW >> 2);
+ outFrame += padW >> 2;
+ }
+ inFrame += cutW >> 2; // in case we have a cut
+ memcpy(outFrame, inFrame,width >> 1);
+ inFrame += cutW >> 2;
+ outFrame += width >> 1;
+ inFrame += width >> 1;
+ if (padW)
+ {
+ memset(outFrame, 127, padW >> 2);
+ outFrame += padW >> 2;
+ }
+ }
+ inFrame += (inWidth >> 2) * (diffH >> 1); // skip end of Cr
+ inFrame += (inWidth >> 2) * (diffH >> 1); // skip top of Cb
+ for (i = 0; i < (outHeight >> 1); i++)
+ {
+ if (padW)
+ {
+ memset(outFrame, 127, padW >> 2);
+ outFrame += padW >> 2;
+ }
+ inFrame += cutW >> 2; // in case we have a cut
+ memcpy(outFrame, inFrame, width >> 1);
+ inFrame += cutW >> 2;
+ outFrame += width >> 1;
+ inFrame += width >> 1;
+ if (padW)
+ {
+ memset(outFrame, 127, padW >> 2);
+ outFrame += padW >> 2;
+ }
+ }
+ }
+ }
+ return 3 * outWidth * (outHeight >> 1);
+}
+
+WebRtc_Word32
+ConvertRGB24ToARGB(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ if (strideOut == 0)
+ {
+ strideOut = width;
+ }
+ else if (strideOut < width)
+ {
+ return -1;
+ }
+
+ WebRtc_UWord32 i, j, offset;
+
+ outFrame += strideOut * (height - 1) * 4;
+ for(i = 0; i < height; i++)
+ {
+ for(j = 0; j < width; j++)
+ {
+ offset = j*4;
+ outFrame[0 + offset] = inFrame[0];
+ outFrame[1 + offset] = inFrame[1];
+ outFrame[2 + offset] = inFrame[2];
+ outFrame[3 + offset] = 0xff;
+ inFrame += 3;
+ }
+ outFrame -= 4 * (strideOut - width);
+ }
+ return strideOut * height * 4;
+}
+
+WebRtc_Word32
+ConvertRGB24ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight,
+ WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight)
+{
+ if (inWidth < 1 || outWidth < 1 || inHeight < 1 || outHeight < 1 )
+ {
+ return -1;
+ }
+ WebRtc_UWord32* yStartPtr = (WebRtc_UWord32*)(outFrame + (outWidth * outHeight));
+ WebRtc_UWord8* uStartPtr = outFrame + (outWidth * outHeight) + ((outWidth * outHeight) >> 2);
+ WebRtc_UWord8* vStartPtr = outFrame + (outWidth * outHeight) +((outWidth * outHeight) >> 1);
+
+ yStartPtr--;
+ uStartPtr--;
+ vStartPtr--;
+ const WebRtc_UWord8* inpPtr;
+ const WebRtc_UWord8* inFramePtr = inFrame;
+ WebRtc_Word32 offset = 0;
+ WebRtc_Word32 height = inHeight;
+ WebRtc_Word32 cutDiff = 0;
+ WebRtc_Word32 padDiffLow= 0;
+ WebRtc_Word32 padDiffHigh = 0;
+
+ if (inHeight > outHeight)
+ {
+ // cut height
+ inFramePtr += inWidth*3 * ((inHeight - outHeight) >> 1); // skip the first diff/2 rows
+ height = outHeight;
+ }
+ if (outHeight > inHeight)
+ {
+ // Pad height.
+ WebRtc_UWord8* outI = outFrame;
+ WebRtc_UWord8* outCr = outFrame + outWidth * outHeight;
+ WebRtc_UWord8* outCb = outCr + ((outWidth * outHeight) >> 2);
+
+ // -- I --
+ WebRtc_UWord32 padHeight = outHeight - inHeight;
+ WebRtc_UWord32 padHeightT = padHeight >> 1;
+ WebRtc_UWord32 padHeightB = padHeight - padHeightT;
+ WebRtc_UWord32 padLength = padHeightT * outWidth;
+ memset(outI, 0, padLength); // Pad the top.
+ outI += padLength;
+
+ outI += outWidth * inHeight; // Skip the image.
+ padLength = padHeightB * outWidth;
+ memset(outI, 0, padLength); // Pad the bottom.
+
+ // Shift the out poWebRtc_Word32er.
+ yStartPtr -= (padLength >> 2); // (>> 2) due to WebRtc_Word32 pointer.
+
+ // -- Cr and Cb --
+ padHeight >>= 1;
+ padHeightT >>= 1;
+ padHeightB = padHeight - padHeightT;
+
+ padLength = padHeightT * (outWidth >> 1);
+ memset(outCr, 127, padLength); // Pad the top.
+ memset(outCb, 127, padLength);
+ outCr += padLength;
+ outCb += padLength;
+
+ padLength = (outWidth * inHeight) >> 2;
+ outCr += padLength; // Skip the image.
+ outCb += padLength;
+ padLength = padHeightB * (outWidth >> 1);
+ memset(outCr, 127, padLength); // Pad the bottom.
+ memset(outCb, 127, padLength);
+
+ // Shift the out pointers.
+ uStartPtr -= padLength;
+ vStartPtr -= padLength;
+ }
+ // cut width?
+ if (inWidth > outWidth)
+ {
+ cutDiff = (inWidth - outWidth) >> 1; // in pixels
+ }
+ // pad width?
+ if (inWidth < outWidth)
+ {
+ padDiffLow = (outWidth - inWidth) >> 1; // in pixels
+ padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels
+ }
+
+ for (WebRtc_Word32 y = 0; y < height; y++)
+ {
+ offset = y * inWidth * 3;
+ inpPtr = &inFramePtr[offset + (inWidth - 4) * 3]; // right to left
+ inpPtr -= 3*cutDiff;
+ WebRtc_Word32 i = (inWidth - (cutDiff * 2)) >> 2;
+ WebRtc_UWord32 tmp;
+ if (padDiffLow)
+ {
+ yStartPtr -= padDiffLow >> 2; //div by 4 since its a WebRtc_Word32 ptr
+ memset(yStartPtr + 1, 0, padDiffLow);
+ }
+ for (; i > 0; i--) // do 4 pixels wide in one loop
+ {
+#ifdef WEBRTC_BIG_ENDIAN
+ tmp = (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0] + 128)
+ >> 8) + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3] + 128)
+ >> 8) + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[8] + 129 * inpPtr[7] + 25 * inpPtr[6] + 128)
+ >> 8) + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[11] + 129 * inpPtr[10] + 25 * inpPtr[9] + 128)
+ >> 8) + 16;
+
+#else
+ tmp = (WebRtc_UWord8)((66 * inpPtr[11] + 129 * inpPtr[10] + 25 * inpPtr[9] + 128) >> 8)
+ + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[8] + 129 * inpPtr[7] + 25 * inpPtr[6] + 128) >> 8)
+ + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3] + 128) >> 8)
+ + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0] + 128) >> 8)
+ + 16;
+#endif
+ *yStartPtr = tmp;
+ yStartPtr--;
+ inpPtr -= 12;
+ }
+ if (padDiffHigh)
+ {
+ yStartPtr -= padDiffHigh >> 2; //div by 4 since its a WebRtc_Word32 ptr
+ memset(yStartPtr + 1, 0, padDiffHigh);
+ }
+ y++; // doing an ugly add to my loop variable
+ offset = y * inWidth * 3;
+ inpPtr = &inFramePtr[offset + (inWidth - 4) * 3];
+ inpPtr -= 3 * cutDiff;
+ i = (inWidth - (cutDiff * 2)) >> 2;
+
+ if (padDiffLow)
+ {
+ yStartPtr -= padDiffLow >> 2; //div by 4 since its a WebRtc_Word32 ptr
+ uStartPtr -= padDiffLow >> 1;
+ vStartPtr -= padDiffLow >> 1;
+ memset(yStartPtr + 1, 0, padDiffLow);
+ memset(uStartPtr + 1, 127, padDiffLow >> 1);
+ memset(vStartPtr + 1, 127, padDiffLow >> 1);
+ }
+ for (; i > 0; i--)
+ {
+ *uStartPtr = (WebRtc_UWord8)((-38 * inpPtr[8] - 74 * inpPtr[7] + 112 * inpPtr[6] + 128)
+ >> 8) + 128;
+ uStartPtr--;
+ *vStartPtr = (WebRtc_UWord8)((112 * inpPtr[8] - 94 * inpPtr[7] - 18 * inpPtr[6] + 128)
+ >> 8) + 128;
+ vStartPtr--;
+ *uStartPtr = (WebRtc_UWord8)((-38 * inpPtr[2] - 74 * inpPtr[1] + 112 * inpPtr[0] + 128)
+ >> 8) + 128;
+ uStartPtr--;
+ *vStartPtr = (WebRtc_UWord8)((112 * inpPtr[2] - 94 * inpPtr[1] - 18 * inpPtr[0] + 128)
+ >> 8) + 128;
+ vStartPtr--;
+#ifdef WEBRTC_BIG_ENDIAN
+ tmp = (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0] + 128 )
+ >> 8) + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3] + 128)
+ >> 8) + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[8] + 129 * inpPtr[7] + 25 * inpPtr[6] + 128)
+ >> 8) + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[11] + 129 * inpPtr[10] + 25 * inpPtr[9] + 128)
+ >> 8) + 16;
+#else
+ tmp = (WebRtc_UWord8)((66 * inpPtr[11] + 129 * inpPtr[10] + 25 * inpPtr[9]+ 128)
+ >> 8) + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[8] + 129 * inpPtr[7] + 25 * inpPtr[6] + 128)
+ >> 8) + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3] + 128 )
+ >> 8) + 16;
+ tmp = tmp << 8;
+ tmp += (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0] + 128)
+ >> 8) + 16;
+#endif
+ *yStartPtr = tmp;
+ yStartPtr--;
+ inpPtr -= 12;
+ }
+ if (padDiffHigh)
+ {
+ yStartPtr -= padDiffHigh >> 2; //div by 4 since its a WebRtc_Word32 ptr
+ uStartPtr -= padDiffHigh >> 1;
+ vStartPtr -= padDiffHigh >> 1;
+ memset(yStartPtr + 1, 0, padDiffHigh);
+ memset(uStartPtr + 1, 127, padDiffHigh >> 1);
+ memset(vStartPtr + 1, 127, padDiffHigh >> 1);
+ }
+ }
+ return (outWidth >> 1) * outHeight * 3;
+}
+
+
+WebRtc_Word32
+ConvertRGB24ToI420(WebRtc_UWord32 width, WebRtc_UWord32 height, const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame)
+{
+ if (height < 1 || width < 1)
+ {
+ return -1;
+ }
+
+ WebRtc_UWord8* yStartPtr;
+ WebRtc_UWord8* yStartPtr2;
+ WebRtc_UWord8* uStartPtr;
+ WebRtc_UWord8* vStartPtr;
+ const WebRtc_UWord8* inpPtr;
+ const WebRtc_UWord8* inpPtr2;
+
+ // assuming RGB in a bottom up orientation.
+ yStartPtr = outFrame;
+ yStartPtr2 = yStartPtr + width;
+ uStartPtr = outFrame + (width * height);
+ vStartPtr = uStartPtr + (width * height >> 2);
+ inpPtr = inFrame + width * height * 3 - 3 * width;
+ inpPtr2 = inpPtr - 3 * width;
+
+ for (WebRtc_UWord32 h = 0; h < (height >> 1); h++ )
+ {
+ for (WebRtc_UWord32 w = 0; w < (width >> 1); w++)
+ {
+ //Y
+ yStartPtr[0] = (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0]
+ + 128) >> 8) + 16;
+ yStartPtr2[0] = (WebRtc_UWord8)((66 * inpPtr2[2] + 129 * inpPtr2[1] + 25 * inpPtr2[0]
+ + 128) >> 8) + 16;
+ // moving to next column
+ yStartPtr[1] = (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3]
+ + 128) >> 8) + 16;
+ yStartPtr2[1] = (WebRtc_UWord8)((66 * inpPtr2[5] + 129 * inpPtr2[4] + 25 * inpPtr2[3]
+ + 128) >> 8 ) + 16;
+ //U
+ uStartPtr[0] = (WebRtc_UWord8)((-38 * inpPtr[2] - 74 * inpPtr[1] + 112 * inpPtr[0]
+ + 128) >> 8) + 128;
+ //V
+ vStartPtr[0] = (WebRtc_UWord8)((112 * inpPtr[2] -94 * inpPtr[1] -18 * inpPtr[0]
+ + 128) >> 8) + 128;
+
+ yStartPtr += 2;
+ yStartPtr2 += 2;
+ uStartPtr++;
+ vStartPtr++;
+ inpPtr += 6;
+ inpPtr2 += 6;
+ } // end for w
+ yStartPtr += width;
+ yStartPtr2 += width;
+ inpPtr -= 9 * width;
+ inpPtr2 -= 9 * width;
+ } // end for h
+ return (width >> 1) * height * 3;
+}
+
+WebRtc_Word32
+ConvertI420ToARGBMac(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut)
+{
+ if (height < 1 || width < 1)
+ {
+ return -1;
+ }
+ if (strideOut == 0)
+ {
+ strideOut = width;
+ } else if (strideOut < width)
+ {
+ return -1;
+ }
+ WebRtc_Word32 diff = strideOut - width;
+ WebRtc_UWord8* out = outFrame;
+ WebRtc_UWord8* out2 = out + strideOut * 4;
+ const WebRtc_UWord8 *y1,*y2, *u, *v;
+ WebRtc_UWord32 h, w;
+ y1 = inFrame;
+ y2 = y1 + width;
+ v = y1 + width * height;
+ u = v + ((width * height) >> 2);
+
+ for (h = (height >> 1); h > 0; h--)
+ {
+ WebRtc_Word32 tmpG, tmpB, tmpR;
+ //do 2 rows at the time
+ for (w = 0; w < (width >> 1); w++)
+ {
+ tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128 )>> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128 )>> 8);
+ out[2] = Clip(tmpR);
+ out[1] = Clip(tmpG);
+ out[0] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8);
+ out2[2] = Clip(tmpR);
+ out2[1] = Clip(tmpG);
+ out2[0] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128)>> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8);
+ out[6] = Clip(tmpR);
+ out[5] = Clip(tmpG);
+ out[4] = Clip(tmpB);
+
+ tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8);
+ tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8);
+ tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8);
+ out2[6] = Clip(tmpR);
+ out2[5] = Clip(tmpG);
+ out2[4] = Clip(tmpB);
+
+
+ out[3] = 0xff;
+ out[7] = 0xff;
+ out += 8;
+ out2[3] = 0xff;
+ out2[7] = 0xff;
+ out2 += 8;
+ y1 += 2;
+ y2 += 2;
+ u++;
+ v++;
+ }
+
+ y1 += width;
+ y2 += width;
+ out += (width + diff * 2) * 4;
+ out2 += (width + diff * 2) * 4;
+ }
+ return strideOut * height * 4;
+}
+
+WebRtc_Word32
+ConvertRGB565ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 width, WebRtc_UWord32 height,
+ WebRtc_UWord8* outFrame)
+{
+ if (width < 1 || height < 1 )
+ {
+ return -1;
+ }
+ WebRtc_UWord8 tmpR, tmpG, tmpB;
+ WebRtc_UWord8 tmpR2, tmpG2, tmpB2;
+
+ WebRtc_UWord8* yStartPtr = outFrame;
+ WebRtc_UWord8* yStartPtr2 = yStartPtr + width;
+ WebRtc_UWord8* uStartPtr = outFrame + (width * height);
+ WebRtc_UWord8* vStartPtr = uStartPtr + (width * height >> 2);
+ const WebRtc_UWord16* inpPtr = (const WebRtc_UWord16*)inFrame;
+ inpPtr += width * (height - 1);
+ const WebRtc_UWord16* inpPtr2 = inpPtr - width;
+
+ for (WebRtc_UWord32 h = 0; h < (height >> 1); h++ )
+ {
+ for (WebRtc_UWord32 w = 0; w < (width >> 1); w++)
+ {
+ // calculating 8 bit values
+ tmpB = (WebRtc_UWord8)((inpPtr[0] & 0x001F) << 3);
+ tmpG = (WebRtc_UWord8)((inpPtr[0] & 0x07E0) >> 3);
+ tmpR = (WebRtc_UWord8)((inpPtr[0] & 0xF800) >> 8);
+ tmpB2 = (WebRtc_UWord8)((inpPtr2[0] & 0x001F) << 3);
+ tmpG2 = (WebRtc_UWord8)((inpPtr2[0] & 0x07E0) >> 3);
+ tmpR2 = (WebRtc_UWord8)((inpPtr2[0] & 0xF800) >> 8);
+
+ //Y
+ yStartPtr[0] = (WebRtc_UWord8)((66 * tmpR + 129 * tmpG + 25 * tmpB + 128) >> 8)
+ + 16;
+ //U
+ uStartPtr[0] = (WebRtc_UWord8)((-38 * tmpR - 74 * tmpG + 112 * tmpB + 128) >> 8)
+ + 128;
+ //V
+ vStartPtr[0] = (WebRtc_UWord8)((112 * tmpR - 94 * tmpG - 18 * tmpB + 128) >> 8)
+ + 128;
+
+ yStartPtr2[0] = (WebRtc_UWord8)((66 * tmpR2 + 129 * tmpG2 + 25 * tmpB2 + 128) >> 8)
+ + 16;
+
+ // moving to next column
+ tmpB = (WebRtc_UWord8)((inpPtr[1] & 0x001F) << 3);
+ tmpG = (WebRtc_UWord8)((inpPtr[1] & 0x07E0) >> 3);
+ tmpR = (WebRtc_UWord8)((inpPtr[1] & 0xF800) >> 8);
+
+ tmpB2 = (WebRtc_UWord8)((inpPtr2[1] & 0x001F) << 3);
+ tmpG2 = (WebRtc_UWord8)((inpPtr2[1] & 0x07E0) >> 3);
+ tmpR2 = (WebRtc_UWord8)((inpPtr2[1] & 0xF800) >> 8);
+
+ yStartPtr[1] = (WebRtc_UWord8)((66 * tmpR + 129 * tmpG + 25 * tmpB + 128) >> 8) + 16;
+ yStartPtr2[1] = (WebRtc_UWord8)((66 * tmpR2 +129 * tmpG2 + 25 * tmpB2 + 128) >> 8) + 16;
+
+ yStartPtr += 2;
+ yStartPtr2 += 2;
+ uStartPtr++;
+ vStartPtr++;
+ inpPtr += 2;
+ inpPtr2 += 2;
+ }
+ yStartPtr += width;
+ yStartPtr2 += width;
+ inpPtr -= 3 * width;
+ inpPtr2 -= 3 * width;
+ }
+ return (width >> 1) * height * 3;
+}
+
+WebRtc_Word32
+ConvertARGBMacToI420(WebRtc_UWord32 width, WebRtc_UWord32 height, const WebRtc_UWord8* inFrame,
+ WebRtc_UWord8* outFrame)
+{
+ if (height < 1 || width < 1)
+ {
+ return -1;
+ }
+
+ WebRtc_UWord8* yStartPtr;
+ WebRtc_UWord8* yStartPtr2;
+ WebRtc_UWord8* uStartPtr;
+ WebRtc_UWord8* vStartPtr;
+ const WebRtc_UWord8* inpPtr;
+ const WebRtc_UWord8* inpPtr2;
+
+ yStartPtr = outFrame;
+ yStartPtr2 = yStartPtr + width;
+ uStartPtr = outFrame + (width * height);
+ vStartPtr = uStartPtr + (width * height >> 2);
+ inpPtr = inFrame;
+ inpPtr2 = inpPtr + 4 * width;
+ WebRtc_UWord32 h, w;
+ for (h = 0; h < (height >> 1); h++)
+ {
+ for (w = 0; w < (width >> 1); w++)
+ { //Y
+ yStartPtr[0] = (WebRtc_UWord8)((66 * inpPtr[1] + 129 * inpPtr[2]
+ + 25 * inpPtr[3] + 128) >> 8) + 16;
+ yStartPtr2[0] = (WebRtc_UWord8)((66 * inpPtr2[1] + 129 * inpPtr2[2]
+ + 25 * inpPtr2[3] + 128) >> 8) + 16;
+ // moving to next column
+ yStartPtr[1] = (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[6]
+ + 25 * inpPtr[7] + 128) >> 8) + 16;
+ yStartPtr2[1] = (WebRtc_UWord8)((66 * inpPtr2[5] + 129 * inpPtr2[6]
+ + 25 * inpPtr2[7] + 128) >> 8) + 16;
+ //U
+ uStartPtr[0] = (WebRtc_UWord8)((-38 * inpPtr[1] - 74 * inpPtr[2]
+ + 112 * inpPtr[3] + 128) >> 8) + 128;
+ //V
+ vStartPtr[0] = (WebRtc_UWord8)((112 * inpPtr[1] - 94 * inpPtr[2]
+ - 18 * inpPtr[3] + 128) >> 8) + 128;
+
+ yStartPtr += 2;
+ yStartPtr2 += 2;
+ uStartPtr++;
+ vStartPtr++;
+ inpPtr += 8;
+ inpPtr2 += 8;
+ }
+ yStartPtr += width;
+ yStartPtr2 += width;
+ inpPtr += 4 * width;
+ inpPtr2 += 4 * width;
+ }
+ return (width * height * 3 >> 1);
+}
+
+
+WebRtc_Word32
+PadI420BottomRows(WebRtc_UWord8* inputVideoBuffer, WebRtc_UWord32 size, WebRtc_UWord32 width,
+ WebRtc_UWord32 height, WebRtc_Word32 nrRows, WebRtc_UWord32& newLength)
+{
+ // sanity
+ WebRtc_UWord32 length = 3 * (width >> 1) * (height + nrRows);
+ if (size < length)
+ return -1;
+
+ if (nrRows < 0)
+ return -1;
+
+ WebRtc_Word32 colorSize = (width * height) >> 2;
+ WebRtc_Word32 padSize = width * nrRows;
+ WebRtc_Word32 padSizeColor = (width * nrRows) >> 2;
+ WebRtc_Word32 outColorSize = (width *(height + nrRows)) >> 2;
+ WebRtc_Word32 j = width * (height + nrRows) + outColorSize;
+
+ WebRtc_Word32 i = width*height + colorSize; // start of Cr
+ memmove(&inputVideoBuffer[j], &inputVideoBuffer[i], colorSize);
+ memset((&inputVideoBuffer[j])+colorSize,127,padSizeColor);
+
+ i = width*height; // start of Cb
+ j = width*(height+nrRows);
+ memmove(&inputVideoBuffer[j], &inputVideoBuffer[i], colorSize);
+ memset((&inputVideoBuffer[j])+colorSize,127,padSizeColor);
+
+ memset(&inputVideoBuffer[i],0,padSize);
+
+ newLength = length;
+ return 0;
+}
+
+
+static WebRtc_UWord32
+PadI420Component(const WebRtc_UWord8* inBuf, WebRtc_UWord8* outBuf,
+ const WebRtc_UWord32 fromWidth, const WebRtc_UWord32 fromHeight,
+ const WebRtc_UWord32 padWidth, const WebRtc_UWord32 padWidthL,
+ const WebRtc_UWord32 padHeight, const WebRtc_UWord32 padHeightT,
+ const WebRtc_UWord8 padValue)
+{
+ const WebRtc_Word32 toWidth = fromWidth + padWidth;
+ const WebRtc_Word32 padWidthR = padWidth - padWidthL;
+ const WebRtc_Word32 padHeightB = padHeight - padHeightT;
+
+ // Top border
+ memset(outBuf, padValue, toWidth * padHeightT);
+ WebRtc_UWord32 outIdx = toWidth * padHeightT;
+ WebRtc_UWord32 inIdx = 0;
+ for (WebRtc_UWord32 i = 0; i < fromHeight; i++)
+ {
+ // Left border
+ memset(&outBuf[outIdx], padValue, padWidthL);
+ outIdx += padWidthL;
+
+ // Copy image
+ memcpy(&outBuf[outIdx], &inBuf[inIdx], fromWidth);
+ outIdx += fromWidth;
+ inIdx += fromWidth;
+
+ // Right border
+ memset(&outBuf[outIdx], padValue, padWidthR);
+ outIdx += padWidthR;
+ }
+ // Bottom border
+ memset(&outBuf[outIdx], padValue, toWidth * padHeightB);
+ outIdx += toWidth * padHeightB;
+
+ return outIdx;
+}
+
+WebRtc_Word32
+PadI420Frame(const WebRtc_UWord8* inBuffer, WebRtc_UWord8* outBuffer, WebRtc_UWord32 fromWidth,
+ WebRtc_UWord32 fromHeight, WebRtc_UWord32 toWidth, WebRtc_UWord32 toHeight)
+{
+ if (toWidth < 1 || fromWidth < 1 || toHeight < 1 || fromHeight < 1)
+ {
+ return -1;
+ }
+ if (toWidth == fromWidth && toHeight == fromHeight)
+ {
+ // nothing to do
+ return (3 * toHeight * toWidth) >> 1;
+ }
+
+ if (inBuffer == NULL)
+ {
+ return -1;
+ }
+
+ if (outBuffer == NULL)
+ {
+ return -1;
+ }
+
+ if (fromWidth < 0 || fromHeight < 0)
+ {
+ return -1;
+ }
+
+ if (toWidth < 0 || toHeight < 0)
+ {
+ return -1;
+ }
+
+ if (toWidth < fromWidth || toHeight < fromHeight)
+ {
+ return -1;
+ }
+
+ WebRtc_UWord32 padWidth = toWidth - fromWidth;
+ WebRtc_UWord32 padHeight = toHeight - fromHeight;
+ WebRtc_UWord32 padWidthL = 0;
+ WebRtc_UWord32 padHeightT = 0;
+
+ // If one of the padded dimensions is a multiple of 16, we apply the padding in
+ // blocks of 16.
+ if (padHeight % 16 == 0)
+ {
+ WebRtc_UWord32 num16blocks = padHeight >> 4;
+ padHeightT = ((num16blocks >> 1) << 4); // NOTE: not the same as
+ // num16blocks << 3
+ }
+ else
+ {
+ padHeightT = padHeight >> 1;
+ }
+
+ if (padWidth % 16 == 0)
+ {
+ WebRtc_UWord32 num16blocks = padWidth >> 4;
+ padWidthL = ((num16blocks >> 1) << 4);
+ }
+ else
+ {
+ padWidthL = padWidth >> 1;
+ }
+
+ // -- I --
+ WebRtc_UWord32 inIdx = 0;
+ WebRtc_UWord32 outIdx = 0;
+ outIdx = PadI420Component(&inBuffer[inIdx], &outBuffer[outIdx], fromWidth,
+ fromHeight, padWidth, padWidthL, padHeight, padHeightT, 0);
+ // -- Cr --
+ inIdx = fromWidth * fromHeight;
+ fromWidth >>= 1;
+ fromHeight >>= 1;
+ padWidth >>= 1;
+ padWidthL >>= 1;
+ padHeight >>= 1;
+ padHeightT >>= 1;
+ outIdx += PadI420Component(&inBuffer[inIdx], &outBuffer[outIdx], fromWidth,
+ fromHeight, padWidth, padWidthL, padHeight, padHeightT, 127);
+ // -- Cb --
+ inIdx += fromWidth * fromHeight;
+ outIdx += PadI420Component(&inBuffer[inIdx], &outBuffer[outIdx], fromWidth,
+ fromHeight, padWidth, padWidthL, padHeight, padHeightT, 127);
+
+ return outIdx;
+}
+
+WebRtc_Word32
+PadI420Frame(WebRtc_UWord32 size, const WebRtc_UWord8* inBuffer, WebRtc_UWord8* outBuffer,
+ bool block16Bit)
+{
+ if (size < 1)
+ {
+ return -1;
+ }
+ WebRtc_Word32 i = 0;
+ WebRtc_Word32 m = 0;
+ WebRtc_Word32 loop = 0;
+ WebRtc_Word32 dropHeightBits = 0; // must be a factor of 4
+ WebRtc_Word32 halfToWidth;
+ WebRtc_Word32 halfToHeight;
+ WebRtc_Word32 halfFromWidth;
+ WebRtc_Word32 halfFromHeight;
+ WebRtc_Word32 padHeightT;
+ WebRtc_Word32 padHeightB;
+ WebRtc_Word32 padWidthL;
+ WebRtc_Word32 padWidthR;
+ WebRtc_Word32 toWidth;
+ WebRtc_Word32 toHeight;
+ WebRtc_Word32 fromWidth;
+ WebRtc_Word32 fromHeight;
+ if (block16Bit)
+ {
+ if (size == 115200) // to 152064
+ {
+ toWidth = 352;
+ toHeight = 288;
+ fromWidth = 320;
+ fromHeight =240;
+ padHeightT = 16;
+ padHeightB = 32;
+ padWidthL = 16;
+ padWidthR = 16;
+ } else if (size == 28800)
+ {
+ fromWidth = 160;
+ fromHeight =120;
+ dropHeightBits = 8; // drop 8 bits
+ toWidth = 176;
+ toHeight = 144;
+ padHeightT = 16;
+ padHeightB = 16;
+ padWidthL = 0;
+ padWidthR = 16;
+ } else
+ {
+ return -1;
+ }
+ } else
+ {
+ return -1;
+ }
+ halfFromWidth = fromWidth >> 1;
+ halfFromHeight = fromHeight >> 1;
+ halfToWidth = toWidth >> 1;
+ halfToHeight = toHeight >> 1;
+
+ //Ilum
+ memset(outBuffer,0,toWidth * padHeightT + padWidthL); // black
+ i = toWidth * padHeightT + padWidthL;
+ m = (dropHeightBits >> 1) * fromWidth;
+ for (loop = 0; loop < (fromHeight - dropHeightBits); loop++)
+ {
+ memcpy(&outBuffer[i], &inBuffer[m],fromWidth);
+ i += fromWidth;
+ m += fromWidth;
+ memset(&outBuffer[i],0,padWidthL + padWidthR); // black
+ i += padWidthL + padWidthR;
+ }
+ memset(&outBuffer[i],0,toWidth * padHeightB - padWidthL); // black
+ m += (dropHeightBits >> 1) * fromWidth;
+ i = toWidth * toHeight; // ilum end
+
+ // Cr
+ memset(&outBuffer[i],127,halfToWidth * (padHeightT >> 1) + (padWidthL >> 1) ); // black
+ i += halfToWidth * (padHeightT >> 1) + (padWidthL >> 1);
+
+ m += (dropHeightBits >> 2) * halfFromWidth;
+ for(loop =0 ; loop < (halfFromHeight - (dropHeightBits >> 1)); loop++)
+ {
+ memcpy(&outBuffer[i],&inBuffer[m],halfFromWidth);
+ m += halfFromWidth;
+ i += halfFromWidth;
+ memset(&outBuffer[i],127,(padWidthL + padWidthR) >> 1); // black
+ i += (padWidthL + padWidthR) >> 1;
+ }
+ memset(&outBuffer[i],127,halfToWidth * (padHeightB >> 1) - (padWidthL >> 1) ); // black
+ m += (dropHeightBits>>2) * halfFromWidth;
+ i = toWidth * toHeight + halfToHeight * halfToWidth; // ilum +Cr
+
+ // Cb
+ memset(&outBuffer[i],127,halfToWidth * (padHeightT >> 1) + (padWidthL >> 2)); // black
+ i += halfToWidth * (padHeightT >> 1) + (padWidthL >> 1);
+
+ m += (dropHeightBits >> 2) * halfFromWidth;
+ for(loop = 0; loop < (halfFromHeight - (dropHeightBits >> 1)); loop++)
+ {
+ memcpy(&outBuffer[i],&inBuffer[m],halfFromWidth);
+ m += halfFromWidth;
+ i += halfFromWidth;
+ memset(&outBuffer[i],127,((padWidthL + padWidthR) >> 1)); // black
+ i+=((padWidthL + padWidthR) >> 1);
+ }
+ memset(&outBuffer[i],127,halfToWidth * (padHeightB >> 1) - (padWidthL >> 1) ); // black
+ return halfToWidth * toHeight * 3;
+}
+
+WebRtc_Word32
+ScaleI420UpHalfFrame(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* inFrame)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ WebRtc_UWord8* inPtr = inFrame + (width * height / 4 * 3) -1;
+ WebRtc_UWord8* outPtr = inFrame + (width * height / 2 * 3) -1;
+
+ for(WebRtc_Word32 i = (width * height / 4 * 3)-1; i > 0; i--)
+ {
+ *outPtr = *inPtr;
+ outPtr--;
+ inPtr--;
+ *outPtr = ((inPtr[0] + inPtr[1]) / 2);
+ outPtr--;
+ }
+ *outPtr = *inPtr;
+ outPtr--;
+ *outPtr = *inPtr;
+
+ return 3 * width * height / 2;
+}
+
+WebRtc_Word32
+ScaleI420DownHalfFrame(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* inFrame)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ WebRtc_UWord8* inPtr1 = inFrame;
+ WebRtc_UWord8* outPtr = inFrame;
+ WebRtc_UWord32 y = 0;
+ WebRtc_UWord32 x = 0;
+ // ilum
+ for(; y < (height); y++)
+ {
+ for(x = 0; x < (width >> 1); x++)
+ {
+ WebRtc_Word32 avg = inPtr1[0] + inPtr1[1];
+ avg = avg >>1;
+ *outPtr= (WebRtc_UWord8)(avg);
+ inPtr1 += 2;
+ outPtr++;
+ }
+ }
+ inPtr1 = inFrame + (width * height);
+
+ // color
+ for(y = 0; y < height; y++)
+ {
+ // 2 rows
+ for(x = 0; x < (width >> 2); x++)
+ {
+ WebRtc_Word32 avg = inPtr1[0] + inPtr1[1] ;
+ *outPtr = (WebRtc_UWord8)(avg >> 1);
+ inPtr1 += 2;
+ outPtr++;
+ }
+ }
+ return height * (width >> 1) * 3;
+}
+
+WebRtc_Word32
+ScaleI420FrameQuarter(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* inFrame)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ WebRtc_UWord8* inPtr1 = inFrame;
+ WebRtc_UWord8* inPtr2 = inFrame + width;
+ WebRtc_UWord8* outPtr = inFrame;
+
+ WebRtc_UWord32 y = 0;
+ WebRtc_UWord32 x = 0;
+ // ilum
+ for(; y < (height >> 1); y++)
+ {
+ // 2 rows
+ for(x = 0; x < (width >> 1); x++)
+ {
+ WebRtc_Word32 avg = inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1];
+ *outPtr= (WebRtc_UWord8)(avg >> 2);
+ inPtr1 += 2;
+ inPtr2 += 2;
+ outPtr++;
+ }
+ inPtr1 +=width;
+ inPtr2 +=width;
+ }
+
+ inPtr1 = inFrame + (width * height);
+ inPtr2 = inPtr1 + (width>>1);
+
+ // color
+ for(y = 0; y < (height>>1); y++)
+ {
+ // 2 rows
+ for(x = 0; x < (width>>2); x++)
+ {
+ WebRtc_Word32 avg = inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1];
+ *outPtr= (WebRtc_UWord8)(avg >> 2);
+
+ inPtr1 += 2;
+ inPtr2 += 2;
+ outPtr++;
+ }
+ inPtr1 += (width >> 1);
+ inPtr2 += (width >> 1);
+ }
+ return height * (width >> 1) * 3;
+}
+
+WebRtc_Word32
+ScaleI420Up2(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8*& buffer,
+ WebRtc_UWord32 size, WebRtc_UWord32 &scaledWidth, WebRtc_UWord32 &scaledHeight)
+{
+ if (width <= 1 || height <= 1 || (width % 2) != 0 || (height % 2) != 0)
+ {
+ return -1;
+ }
+
+ if (size < (WebRtc_UWord32)(width * height * 3 / 2))
+ {
+ return -1;
+ }
+
+ scaledWidth = (width << 1);
+ scaledHeight = (height << 1);
+
+ // Verify allocated size
+ WebRtc_UWord32 scaledBufferSize = CalcBufferSize(kI420, scaledWidth, scaledHeight);
+ VerifyAndAllocate(buffer, size, scaledBufferSize);
+ WebRtc_UWord8* inPtr1 = buffer + (3 * width * (height >> 1)) - 1;
+ WebRtc_UWord8* inPtr2 = buffer + (3 * width * (height >> 1)) - (width >> 1) - 1;
+ WebRtc_UWord8* outPtr1 = buffer + (3 * scaledWidth * (scaledHeight >> 1)) - 1;
+ WebRtc_UWord8* outPtr2 = buffer + (3 * scaledWidth * (scaledHeight >> 1)) - (scaledWidth >> 1) - 1;
+
+ // Color
+ for (WebRtc_Word32 i = 1; i <= 2; i++)
+ {
+ for (WebRtc_UWord32 y = 0; y < (height >> 1) - 1; y++)
+ {
+ for (WebRtc_UWord32 x = 0; x < (width >> 1) - 1; x++)
+ {
+ *outPtr1 = *inPtr1;
+ *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1);
+ inPtr1--;
+ inPtr2--;
+ outPtr1--;
+ outPtr2--;
+ *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1);
+ *outPtr2 = ((inPtr1[0] + inPtr1[1] + inPtr2[0] + inPtr2[1]) >> 2);
+ outPtr1--;
+ outPtr2--;
+ }
+ *outPtr1 = *inPtr1;
+ *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1);
+ outPtr1--;
+ outPtr2--;
+ *outPtr1 = *inPtr1;
+ *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1);
+ outPtr1--;
+ outPtr2--;
+ inPtr1--;
+ inPtr2--;
+ outPtr1 -= width;
+ outPtr2 -= width;
+ }
+ // First row
+ for (WebRtc_UWord32 x = 0; x < (width >> 1) - 1; x++)
+ {
+ *outPtr1 = *inPtr1;
+ *outPtr2 = *outPtr1;
+ inPtr1--;
+ inPtr2--;
+ outPtr1--;
+ outPtr2--;
+ *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1);
+ *outPtr2 = *outPtr1;
+ outPtr1--;
+ outPtr2--;
+ }
+ *outPtr1 = *inPtr1;
+ *outPtr2 = *inPtr1;
+ outPtr1--;
+ outPtr2--;
+ *outPtr1 = *inPtr1;
+ *outPtr2 = *inPtr1;
+ outPtr1--;
+ outPtr2--;
+ inPtr1--;
+ inPtr2--;
+ outPtr1 -= width;
+ outPtr2 -= width;
+ }
+
+ inPtr2 -= (width >> 1);
+ outPtr2 -= width;
+
+ // illum
+ for (WebRtc_UWord32 y = 0; y < height - 1; y++)
+ {
+ for (WebRtc_UWord32 x = 0; x < width - 1; x++)
+ {
+ *outPtr1 = *inPtr1;
+ *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1);
+ inPtr1--;
+ inPtr2--;
+ outPtr1--;
+ outPtr2--;
+ *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1);
+ *outPtr2 = ((inPtr1[0] + inPtr1[1] + inPtr2[0] + inPtr2[1]) >> 2);
+ outPtr1--;
+ outPtr2--;
+ }
+ *outPtr1 = *inPtr1;
+ *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1);
+ outPtr1--;
+ outPtr2--;
+ *outPtr1 = *inPtr1;
+ *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1);
+ outPtr1--;
+ outPtr2--;
+ inPtr1--;
+ inPtr2--;
+
+ outPtr1 -= scaledWidth;
+ outPtr2 -= scaledWidth;
+ }
+ // First row
+ for (WebRtc_UWord32 x = 0; x < width - 1; x++)
+ {
+ *outPtr1 = *inPtr1;
+ *outPtr2 = *outPtr1;
+ inPtr1--;
+ outPtr1--;
+ outPtr2--;
+ *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1);
+ *outPtr2 = *outPtr1;
+ outPtr1--;
+ outPtr2--;
+ }
+ *outPtr1 = *inPtr1;
+ *outPtr2 = *inPtr1;
+ outPtr1--;
+ outPtr2--;
+ *outPtr1 = *inPtr1;
+ *outPtr2 = *inPtr1;
+
+ return scaledHeight * (scaledWidth >> 1) * 3;
+}
+
+WebRtc_Word32
+ScaleI420Up3_2(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8*& buffer,
+ WebRtc_UWord32 size, WebRtc_UWord32 &scaledWidth, WebRtc_UWord32 &scaledHeight)
+{
+ if (width <= 1 || height <= 1)
+ {
+ return -1;
+ }
+
+ if ((width % 2) != 0 || (height % 2) != 0 || ((width >> 1) % 2) != 0 || ((height >> 1) % 2) != 0)
+ {
+ return -1;
+ }
+
+ if (size < (WebRtc_UWord32)(width * height * 3 / 2))
+ {
+ return -1;
+ }
+
+ scaledWidth = 3 * (width >> 1);
+ scaledHeight = 3 * (height >> 1);
+
+ // Verify new buffer size
+ WebRtc_UWord32 scaledBufferSize = webrtc::CalcBufferSize(kI420, scaledWidth, scaledHeight);
+ VerifyAndAllocate(buffer, size, scaledBufferSize);
+
+ WebRtc_UWord8* inPtr1 = buffer + (3 * width * (height >> 1)) - 1;
+ WebRtc_UWord8* inPtr2 = buffer + (3 * width*(height >> 1)) - (width >> 1) - 1;
+
+ WebRtc_UWord8* outPtr1 = buffer + (3 * scaledWidth * (scaledHeight >> 1)) - 1;
+ WebRtc_UWord8* outPtr2 = buffer + (3 * scaledWidth * (scaledHeight >> 1)) - (scaledWidth >> 1) - 1;
+
+ WebRtc_Word32 cy = 0;
+ WebRtc_Word32 cx = 0;
+ // Color
+ for (WebRtc_UWord32 y = 0; y < (height); y++)
+ {
+ for (WebRtc_UWord32 x = 0; x < (width >> 1); x++)
+ {
+ *outPtr1 = *inPtr1;
+ outPtr1--;
+ cy = y % 2;
+ cx = x % 2;
+ if (cy == 0)
+ {
+ *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1);
+ }
+ outPtr2--;
+ inPtr1--;
+ inPtr2--;
+
+ if (cx == 0 && cy == 0)
+ {
+ *outPtr2 = ((inPtr1[0] + inPtr1[1] + inPtr2[0] + inPtr2[1]) >> 2);
+ }
+ if (cx == 0)
+ {
+ *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1);
+ outPtr1--;
+ outPtr2--;
+ }
+ }
+ if (cy == 0)
+ {
+ outPtr1 -= (scaledWidth >> 1);
+ outPtr2 -= (scaledWidth >> 1);
+ }
+ }
+ inPtr2 -= (width >> 1);
+ outPtr2 -= (scaledWidth >> 1);
+
+ // illum
+ for (WebRtc_UWord32 y = 0; y < height; y++)
+ {
+ for (WebRtc_UWord32 x = 0; x < width; x++)
+ {
+ *outPtr1 = *inPtr1;
+ outPtr1--;
+ cy = y % 2;
+ cx = x % 2;
+ if (cy == 0)
+ {
+ *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1);
+ }
+ outPtr2--;
+ inPtr1--;
+ inPtr2--;
+ if (cx == 0 && cy == 0)
+ {
+ *outPtr2 = ((inPtr1[0] + inPtr1[1] + inPtr2[0] + inPtr2[1]) >> 2);
+ }
+ if (cx == 0)
+ {
+ *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1);
+ outPtr1--;
+ outPtr2--;
+ }
+ }
+ if (cy == 0)
+ {
+ outPtr1 -= scaledWidth;
+ outPtr2 -= scaledWidth;
+ }
+ }
+
+ return scaledHeight * (scaledWidth >> 1) * 3;
+}
+
+WebRtc_Word32
+ScaleI420Down1_3(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8*& buffer,
+ WebRtc_UWord32 size, WebRtc_UWord32 &scaledWidth,
+ WebRtc_UWord32 &scaledHeight)
+{
+ if (width <= 5 || height <= 5)
+ {
+ return -1;
+ }
+
+ if ((width % 2) != 0 || (height % 2) != 0 || (((height / 3) % 2) != 0))
+ {
+ return -1;
+ }
+
+ if (size < (WebRtc_UWord32)(width * height * 3 / 2))
+ {
+ return -1;
+ }
+
+ scaledWidth = width / 3;
+ scaledHeight = height / 3;
+ WebRtc_Word32 scaledBufferSize = CalcBufferSize(kI420, scaledWidth, scaledHeight);
+ VerifyAndAllocate(buffer, size, scaledBufferSize);
+
+ WebRtc_UWord8* inPtr1 = buffer;
+ WebRtc_UWord8* inPtr2 = buffer + width;
+ WebRtc_UWord8* outPtr = buffer;
+
+ WebRtc_Word32 remWidth = width - scaledWidth * 3;
+
+ bool addWidth = false;
+ if (scaledWidth % 2)
+ {
+ scaledWidth++;
+ addWidth = true;
+ }
+ WebRtc_Word32 remWidthCol = (width >> 1) - WebRtc_Word32((scaledWidth >> 1) * 3.0);
+
+ // illum
+ for (WebRtc_UWord32 y = 0; y < height / 3; y++)
+ {
+ for (WebRtc_UWord32 x = 0; x < width / 3; x++)
+ {
+ *outPtr = ((inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1]) >> 2);
+ inPtr1 += 3;
+ inPtr2 += 3;
+ outPtr++;
+ }
+ if (addWidth)
+ {
+ *outPtr = ((inPtr1[0] + inPtr2[0]) >> 1);
+ outPtr++;
+ }
+ inPtr1 += (width << 1) + remWidth;
+ inPtr2 += (width << 1) + remWidth;
+ }
+ inPtr1 = buffer + (width * height);
+ inPtr2 = inPtr1 + (width >> 1);
+
+ // Color
+ for (WebRtc_UWord32 y = 0; y < (scaledHeight >> 1); y++)
+ {
+ for (WebRtc_UWord32 x = 0; x < (scaledWidth >> 1); x++)
+ {
+ *outPtr = ((inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1]) >> 2);
+ inPtr1 += 3;
+ inPtr2 += 3;
+ outPtr++;
+ }
+ inPtr1 += width + (remWidthCol);
+ inPtr2 += width + (remWidthCol);
+ }
+ inPtr1 = buffer + (width * height) + (width * height >> 2);
+ inPtr2 = inPtr1 + (width >> 1);
+
+ for (WebRtc_UWord32 y = 0; y < (scaledHeight >> 1); y++)
+ {
+ for (WebRtc_UWord32 x = 0; x < (scaledWidth >> 1); x++)
+ {
+ *outPtr = ((inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1]) >> 2);
+ inPtr1 += 3;
+ inPtr2 += 3;
+ outPtr++;
+ }
+ inPtr1 += width + (remWidthCol);
+ inPtr2 += width + (remWidthCol);
+ }
+
+ return scaledHeight * (scaledWidth >> 1) * 3;
+}
+
+
+WebRtc_Word32
+ConvertToI420(VideoType incomingVideoType,
+ const WebRtc_UWord8* incomingBuffer,
+ WebRtc_UWord32 width,
+ WebRtc_UWord32 height,
+ WebRtc_UWord8* outgoingBuffer,
+ bool interlaced /* =false */,
+ VideoRotationMode rotate /* = kRotateNone */)
+
+{
+ if (width < 1 || height < 1 )
+ {
+ return -1;
+ }
+ WebRtc_Word32 outgoingLength = 0;
+ WebRtc_Word32 length = 0;
+ switch(incomingVideoType)
+ {
+ case kRGB24:
+ outgoingLength = ConvertRGB24ToI420(width, height, incomingBuffer, outgoingBuffer);
+ break;
+ case kRGB565:
+ outgoingLength = ConvertRGB565ToI420(incomingBuffer, width, height, outgoingBuffer);
+ break;
+#ifdef WEBRTC_MAC
+ case kARGB:
+ outgoingLength = ConvertARGBMacToI420(width, height, incomingBuffer, outgoingBuffer);
+ break;
+#endif
+ case kI420:
+ switch(rotate)
+ {
+ case kRotateNone:
+ length = CalcBufferSize(kI420, width, height);
+ outgoingLength = length;
+ memcpy(outgoingBuffer, incomingBuffer, length);
+ break;
+ case kRotateClockwise:
+ outgoingLength = ConvertToI420AndRotateClockwise(incomingBuffer, width,
+ height, outgoingBuffer,
+ height, width, kI420);
+ break;
+ case kRotateAntiClockwise:
+ outgoingLength = ConvertToI420AndRotateAntiClockwise(incomingBuffer, width,
+ height, outgoingBuffer,
+ height, width, kI420);
+ break;
+ case kRotate180:
+ outgoingLength = ConvertToI420AndMirrorUpDown(incomingBuffer,outgoingBuffer,
+ width, height, kI420);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ break;
+ case kYUY2:
+ if (interlaced) {
+ outgoingLength = ConvertYUY2ToI420interlaced(incomingBuffer, width, height,
+ outgoingBuffer, width, height);
+ } else {
+ outgoingLength = ConvertYUY2ToI420(incomingBuffer, width, height,
+ outgoingBuffer, width, height);
+ }
+ break;
+ case kUYVY:
+ if (interlaced) {
+ outgoingLength = ConvertUYVYToI420interlaced(incomingBuffer, width, height,
+ outgoingBuffer, width, height);
+ } else {
+ outgoingLength = ConvertUYVYToI420(width, height, incomingBuffer,
+ outgoingBuffer);
+ }
+ break;
+ case kYV12:
+ switch(rotate)
+ {
+ case kRotateNone:
+ outgoingLength = ConvertYV12ToI420(incomingBuffer, width, height,
+ outgoingBuffer);
+ break;
+ case kRotateClockwise:
+ outgoingLength = ConvertToI420AndRotateClockwise(incomingBuffer, width,
+ height, outgoingBuffer,
+ height,width, kYV12);
+ break;
+ case kRotateAntiClockwise:
+ outgoingLength = ConvertToI420AndRotateAntiClockwise(incomingBuffer,
+ width, height,
+ outgoingBuffer,
+ height, width,
+ kYV12);
+ break;
+ case kRotate180:
+ outgoingLength = ConvertToI420AndMirrorUpDown(incomingBuffer,
+ outgoingBuffer,
+ width, height, kYV12);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ break;
+ case kNV12:
+ switch(rotate)
+ {
+ case kRotateNone:
+ outgoingLength = ConvertNV12ToI420(incomingBuffer, outgoingBuffer, width,
+ height);
+ break;
+ case kRotateClockwise:
+ outgoingLength = ConvertNV12ToI420AndRotateClockwise(incomingBuffer,
+ outgoingBuffer,
+ width, height);
+ break;
+ case kRotateAntiClockwise:
+ outgoingLength = ConvertNV12ToI420AndRotateAntiClockwise(incomingBuffer,
+ outgoingBuffer,
+ width, height);
+ break;
+ case kRotate180:
+ outgoingLength = ConvertNV12ToI420AndRotate180(incomingBuffer,
+ outgoingBuffer,
+ width, height);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ break;
+ case kNV21:
+ switch(rotate)
+ {
+ case kRotateNone:
+ outgoingLength = ConvertNV21ToI420(incomingBuffer, outgoingBuffer, width,
+ height);
+ break;
+ case kRotateClockwise:
+ outgoingLength = ConvertNV21ToI420AndRotateClockwise(incomingBuffer,
+ outgoingBuffer,
+ width, height);
+ break;
+ case kRotateAntiClockwise:
+ outgoingLength = ConvertNV21ToI420AndRotateAntiClockwise(incomingBuffer,
+ outgoingBuffer,
+ width, height);
+ break;
+ case kRotate180:
+ outgoingLength = ConvertNV21ToI420AndRotate180(incomingBuffer,
+ outgoingBuffer,
+ width, height);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ return outgoingLength;
+}
+
+WebRtc_Word32 ConvertFromI420(VideoType outgoingVideoType,
+ const WebRtc_UWord8* incomingBuffer,
+ WebRtc_UWord32 width,
+ WebRtc_UWord32 height,
+ WebRtc_UWord8* outgoingBuffer,
+ bool interlaced /* = false */,
+ VideoRotationMode rotate /* = kRotateNone */)
+
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ WebRtc_Word32 outgoingLength = 0;
+ WebRtc_Word32 length = 0;
+ switch(outgoingVideoType)
+ {
+ case kRGB24:
+ outgoingLength = ConvertI420ToRGB24(incomingBuffer, outgoingBuffer, width, height);
+ break;
+ case kARGB:
+ outgoingLength = ConvertI420ToARGB(incomingBuffer, outgoingBuffer, width, height, 0);
+ break;
+ case kARGB4444:
+ outgoingLength = ConvertI420ToARGB4444(incomingBuffer, outgoingBuffer, width, height, 0);
+ break;
+ case kARGB1555:
+ outgoingLength = ConvertI420ToARGB1555(incomingBuffer, outgoingBuffer, width, height,0);
+ break;
+ case kRGB565:
+ outgoingLength = ConvertI420ToRGB565(incomingBuffer, outgoingBuffer, width, height);
+ break;
+ case kI420:
+ length = CalcBufferSize(kI420, width, height);
+ outgoingLength = length;
+ memcpy(outgoingBuffer, incomingBuffer, length);
+ break;
+ case kUYVY:
+ outgoingLength = ConvertI420ToUYVY(incomingBuffer, outgoingBuffer, width, height);
+ break;
+ case kYUY2:
+ outgoingLength = ConvertI420ToYUY2(incomingBuffer, outgoingBuffer, width, height,0);
+ break;
+ case kYV12:
+ outgoingLength = ConvertI420ToYV12(incomingBuffer, outgoingBuffer, width, height,0);
+ break;
+#ifdef WEBRTC_MAC
+ case kRGBAMac:
+ outgoingLength = ConvertI420ToRGBAMac(incomingBuffer, outgoingBuffer, width, height,0);
+ break;
+ case kARGBMac:
+ outgoingLength = ConvertI420ToARGBMac(incomingBuffer, outgoingBuffer, width, height,0);
+ break;
+#endif
+ default:
+ assert(false);
+ break;
+ }
+ return outgoingLength;
+}
+
+WebRtc_Word32
+MirrorI420LeftRight( const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+
+ WebRtc_Word32 indO = 0;
+ WebRtc_Word32 indS = 0;
+ WebRtc_UWord32 wind, hind;
+ WebRtc_UWord8 tmpVal;
+ // will swap two values per iteration
+ const WebRtc_UWord32 halfW = width >> 1;
+ // Y
+ for (wind = 0; wind < halfW; wind++ )
+ {
+ for (hind = 0; hind < height; hind++ )
+ {
+ indO = hind * width + wind;
+ indS = hind * width + (width - wind - 1); // swapping index
+ tmpVal = inFrame[indO];
+ outFrame[indO] = inFrame[indS];
+ outFrame[indS] = tmpVal;
+ } // end for (height)
+ } // end for(width)
+ const WebRtc_UWord32 lengthW = width >> 2;
+ const WebRtc_UWord32 lengthH = height >> 1;
+ // V
+ WebRtc_Word32 zeroInd = width * height;
+ for (wind = 0; wind < lengthW; wind++ )
+ {
+ for (hind = 0; hind < lengthH; hind++ )
+ {
+ indO = zeroInd + hind * halfW + wind;
+ indS = zeroInd + hind * halfW + (halfW - wind - 1); // swapping index
+ tmpVal = inFrame[indO];
+ outFrame[indO] = inFrame[indS];
+ outFrame[indS] = tmpVal;
+ } // end for (height)
+ } // end for(width)
+
+ //U
+ zeroInd += width * height >> 2;
+ for (wind = 0; wind < lengthW; wind++ )
+ {
+ for (hind = 0; hind < lengthH; hind++ )
+ {
+ indO = zeroInd + hind * halfW + wind;
+ indS = zeroInd + hind * halfW + (halfW - wind - 1); // swapping index
+ tmpVal = inFrame[indO];
+ outFrame[indO] = inFrame[indS];
+ outFrame[indS] = tmpVal;
+ } // end for (height)
+ } // end for(width)
+
+ return 0;
+}
+
+WebRtc_Word32
+MirrorI420UpDown( const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame,
+ WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+ if (width < 1 || height < 1)
+ {
+ return -1;
+ }
+ WebRtc_UWord32 indO = 0;
+ WebRtc_UWord32 indS = 0;
+ WebRtc_UWord32 wind, hind;
+ WebRtc_UWord8 tmpVal;
+ WebRtc_UWord32 halfH = height >> 1;
+ WebRtc_UWord32 halfW = width >> 1;
+ // Y
+ for (hind = 0; hind < halfH; hind++ )
+ {
+ for (wind = 0; wind < width; wind++ )
+ {
+ indO = hind * width + wind;
+ indS = (height - hind - 1) * width + wind;
+ tmpVal = inFrame[indO];
+ outFrame[indO] = inFrame[indS];
+ outFrame[indS] = tmpVal;
+ }
+ }
+ // V
+ WebRtc_UWord32 lengthW = width >> 1;
+ WebRtc_UWord32 lengthH = height >> 2;
+ WebRtc_UWord32 zeroInd = width * height;
+ for (hind = 0; hind < lengthH; hind++ )
+ {
+ for (wind = 0; wind < lengthW; wind++ )
+ {
+ indO = zeroInd + hind * halfW + wind;
+ indS = zeroInd + (halfH - hind - 1) * halfW + wind;
+ tmpVal = inFrame[indO];
+ outFrame[indO] = inFrame[indS];
+ outFrame[indS] = tmpVal;
+ }
+ }
+ // U
+ zeroInd += width * height >> 2;
+ for (hind = 0; hind < lengthH; hind++ )
+ {
+ for (wind = 0; wind < lengthW; wind++ )
+ {
+ indO = zeroInd + hind * halfW + wind;
+ indS = zeroInd + (halfH - hind - 1) * halfW + wind;
+ tmpVal = inFrame[indO];
+ outFrame[indO] = inFrame[indS];
+ outFrame[indS] = tmpVal;
+ }
+ }
+ return 0;
+}
+
+WebRtc_Word32
+ConvertToI420AndMirrorUpDown(const WebRtc_UWord8* srcBuffer, WebRtc_UWord8* dstBuffer,
+ WebRtc_UWord32 srcWidth, WebRtc_UWord32 srcHeight,
+ VideoType colorSpaceIn)
+{
+ if (colorSpaceIn != kI420 && colorSpaceIn != kYV12)
+ {
+ return -1;
+ }
+
+ const WebRtc_Word32 sourceHeight = srcHeight;
+ const WebRtc_Word32 halfHeight = srcHeight >> 1;
+ const WebRtc_Word32 sourceWidth = srcWidth;
+ const WebRtc_Word32 halfWidth = sourceWidth >> 1;
+ WebRtc_UWord8* targetBuffer = dstBuffer;
+ const WebRtc_UWord8* sourcePtr = srcBuffer;
+
+ //Mirror Y component
+ for (WebRtc_UWord32 newRow = 0; newRow < srcHeight; ++newRow)
+ {
+ memcpy(targetBuffer, &sourcePtr[((srcHeight - newRow) - 1) * sourceWidth], sourceWidth);
+ targetBuffer += sourceWidth;
+ }
+
+ //Mirror U component
+ sourcePtr += sourceHeight * sourceWidth;
+ if (colorSpaceIn == kYV12)
+ {
+ sourcePtr += (sourceHeight * sourceWidth) >> 2;
+ }
+ for (WebRtc_Word32 newRow = 0; newRow < halfHeight; ++newRow)
+ {
+ memcpy(targetBuffer, &sourcePtr[((halfHeight - newRow) - 1) * halfWidth], halfWidth);
+ targetBuffer += halfWidth;
+ }
+
+ //Mirror V component
+ if (colorSpaceIn != kYV12)
+ {
+ sourcePtr += (sourceHeight * sourceWidth) >> 2;
+ }
+ else
+ {
+ sourcePtr -= (sourceHeight * sourceWidth) >> 2;
+ }
+ for(WebRtc_Word32 newRow = 0; newRow < halfHeight; ++newRow)
+ {
+ memcpy(targetBuffer, &sourcePtr[((halfHeight - newRow) - 1) * halfWidth], halfWidth);
+ targetBuffer += halfWidth;
+ }
+ return 0;
+}
+
+
+WebRtc_Word32
+ConvertToI420AndRotateClockwise(const WebRtc_UWord8* srcBuffer, WebRtc_UWord32 srcWidth,
+ WebRtc_UWord32 srcHeight, WebRtc_UWord8* dstBuffer,
+ WebRtc_UWord32 dstWidth, WebRtc_UWord32 dstHeight,
+ VideoType colorSpaceIn)
+{
+ if (colorSpaceIn != kI420 && colorSpaceIn != kYV12)
+ {
+ return -1;
+ }
+
+ const WebRtc_Word32 targetHeight = dstHeight;
+ const WebRtc_Word32 targetWidth = dstWidth;
+ const WebRtc_Word32 sourceHeight = srcHeight;
+ const WebRtc_Word32 sourceWidth = srcWidth;
+
+ WebRtc_UWord8* targetBuffer=dstBuffer;
+ const WebRtc_UWord8* sourcePtr=srcBuffer;
+
+ // Paint the destination buffer black
+ memset(dstBuffer,0,dstWidth * dstHeight);
+ memset(dstBuffer + dstWidth * dstHeight,127,(dstWidth * dstHeight) / 2);
+
+ const WebRtc_Word32 paddingWidth = (targetWidth - sourceHeight) / 2;
+ const WebRtc_Word32 halfPaddingWidth = paddingWidth / 2;
+ const WebRtc_Word32 paddingHeight = (targetHeight - sourceWidth) / 2;
+ const WebRtc_Word32 halfPaddingHeight = paddingHeight / 2;
+
+ //Rotate Y component
+ targetBuffer += paddingHeight * targetWidth;
+ for(WebRtc_Word32 newRow = 0; newRow < sourceWidth; ++newRow)
+ {
+ targetBuffer+=paddingWidth;
+ for(WebRtc_Word32 newColumn = sourceHeight - 1;newColumn >= 0;--newColumn)
+ {
+ (*targetBuffer++) = sourcePtr[newColumn * sourceWidth + newRow];
+ }
+ targetBuffer += paddingWidth;
+ }
+ targetBuffer += paddingHeight * targetWidth;
+
+ //Rotate U component and store as kI420
+ sourcePtr += sourceHeight * sourceWidth;
+ if (colorSpaceIn == kYV12)
+ {
+ sourcePtr += (sourceHeight * sourceWidth) >> 2;
+ }
+ targetBuffer += halfPaddingHeight * targetWidth / 2;
+ for(WebRtc_Word32 newRow = 0;newRow < sourceWidth / 2; ++newRow)
+ {
+ targetBuffer += halfPaddingWidth;
+ for(WebRtc_Word32 newColumn=sourceHeight / 2 - 1; newColumn >= 0; --newColumn)
+ {
+ (*targetBuffer++) = sourcePtr[(newColumn * sourceWidth >> 1) + newRow];
+ }
+ targetBuffer += halfPaddingWidth;
+ }
+ targetBuffer += halfPaddingHeight * targetWidth / 2;
+
+ //Rotate V component
+ if (colorSpaceIn != kYV12)
+ {
+ sourcePtr += (sourceHeight * sourceWidth) >> 2;
+ } else
+ {
+ sourcePtr -= (sourceHeight * sourceWidth) >> 2;
+ }
+ targetBuffer += halfPaddingHeight * targetWidth / 2;
+ for(WebRtc_Word32 newRow = 0; newRow < sourceWidth / 2; ++newRow)
+ {
+ targetBuffer+=halfPaddingWidth;
+ for(WebRtc_Word32 newColumn = sourceHeight / 2 - 1; newColumn >= 0; --newColumn)
+ {
+ (*targetBuffer++) = sourcePtr[(newColumn * sourceWidth >> 1) + newRow];
+ }
+ targetBuffer += halfPaddingWidth;
+ }
+ targetBuffer += halfPaddingHeight * targetWidth / 2;
+ return 0;
+}
+
+
+WebRtc_Word32
+ConvertToI420AndRotateAntiClockwise(const WebRtc_UWord8* srcBuffer, WebRtc_UWord32 srcWidth,
+ WebRtc_UWord32 srcHeight, WebRtc_UWord8* dstBuffer,
+ WebRtc_UWord32 dstWidth, WebRtc_UWord32 dstHeight,
+ VideoType colorSpaceIn)
+{
+ if (colorSpaceIn != kI420 && colorSpaceIn != kYV12)
+ {
+ return -1;
+ }
+ if (dstWidth < srcHeight || dstHeight < srcWidth)
+ {
+ return -1;
+ }
+ const WebRtc_Word32 targetHeight = dstHeight;
+ const WebRtc_Word32 targetWidth = dstWidth;
+ const WebRtc_Word32 sourceHeight = srcHeight;
+ const WebRtc_Word32 sourceWidth = srcWidth;
+
+ WebRtc_UWord8* targetBuffer = dstBuffer;
+
+ const WebRtc_UWord8* sourcePtr = srcBuffer;
+
+ // Paint the destination buffer black
+ memset(dstBuffer,0,dstWidth * dstHeight);
+ memset(dstBuffer + dstWidth * dstHeight,127,(dstWidth * dstHeight) / 2);
+
+ const WebRtc_Word32 paddingWidth = (targetWidth - sourceHeight) / 2;
+ const WebRtc_Word32 halfPaddingWidth = paddingWidth / 2;
+
+ const WebRtc_Word32 paddingHeight = (targetHeight - sourceWidth) / 2;
+ const WebRtc_Word32 halfPaddingHeight = paddingHeight / 2;
+
+ //Rotate Y component
+ targetBuffer += paddingHeight*targetWidth;
+ for(WebRtc_Word32 newRow = sourceWidth - 1; newRow >= 0; --newRow)
+ {
+ targetBuffer+=paddingWidth;
+ for(WebRtc_Word32 newColumn = 0; newColumn < sourceHeight; ++newColumn)
+ {
+ (*targetBuffer++) = sourcePtr[newColumn * sourceWidth + newRow];
+ }
+ targetBuffer += paddingWidth;
+ }
+ targetBuffer += paddingHeight * targetWidth;
+
+ //Rotate U component and store as kI420
+ sourcePtr += sourceHeight * sourceWidth;
+ if (colorSpaceIn == kYV12)
+ {
+ sourcePtr += (sourceHeight * sourceWidth) >> 2;
+ }
+ targetBuffer += halfPaddingHeight * targetWidth / 2;
+ for(WebRtc_Word32 newRow = sourceWidth / 2 - 1; newRow >= 0;--newRow)
+ {
+ targetBuffer += halfPaddingWidth;
+ for(WebRtc_Word32 newColumn = 0; newColumn < sourceHeight / 2; ++newColumn)
+ {
+ (*targetBuffer++) = sourcePtr[(newColumn*sourceWidth >> 1) + newRow];
+ }
+ targetBuffer += halfPaddingWidth;
+ }
+ targetBuffer += halfPaddingHeight * targetWidth / 2;
+
+ //Rotate V component
+ if (colorSpaceIn != kYV12)
+ {
+ sourcePtr += (sourceHeight * sourceWidth) >> 2;
+ } else
+ {
+ sourcePtr -= (sourceHeight * sourceWidth) >> 2;
+ }
+ targetBuffer += halfPaddingHeight * targetWidth / 2;
+ for (WebRtc_Word32 newRow = sourceWidth / 2 - 1; newRow >= 0; --newRow)
+ {
+ targetBuffer += halfPaddingWidth;
+ for (WebRtc_Word32 newColumn = 0; newColumn < sourceHeight / 2; ++newColumn)
+ {
+ (*targetBuffer++) = sourcePtr[(newColumn*sourceWidth >> 1) + newRow];
+ }
+ targetBuffer += halfPaddingWidth;
+ }
+ targetBuffer += halfPaddingHeight * targetWidth / 2;
+ return 0;
+}
+
+
+inline
+WebRtc_UWord8 Clip(WebRtc_Word32 val)
+{
+ if (val < 0)
+ {
+ return (WebRtc_UWord8)0;
+ } else if (val > 255)
+ {
+ return (WebRtc_UWord8)255;
+ }
+ return (WebRtc_UWord8)val;
+}
+
+WebRtc_Word32
+VerifyAndAllocate(WebRtc_UWord8*& buffer, WebRtc_UWord32 currentSize, WebRtc_UWord32 newSize)
+{
+ if (newSize > currentSize)
+ {
+ // make sure that our buffer is big enough
+ WebRtc_UWord8* newBuffer = new WebRtc_UWord8[newSize];
+ if (buffer)
+ {
+ // copy old data
+ memcpy(newBuffer, buffer, currentSize);
+ delete [] buffer;
+ }
+ buffer = newBuffer;
+ return newSize;
+ }
+ return currentSize;
+}
+
+#ifdef SCALEOPT
+//memcpy_16 assumes that width is an integer multiple of 16!
+void *memcpy_16(void * dest, const void * src, size_t n)
+{
+ _asm
+ {
+ mov eax, dword ptr [src]
+ mov ebx, dword ptr [dest]
+ mov ecx, dword ptr [n]
+
+ loop0:
+
+ movdqu xmm0, XMMWORD PTR [eax]
+ movdqu XMMWORD PTR [ebx], xmm0
+ add eax, 16
+ add ebx, 16
+ sub ecx, 16
+ jg loop0
+ }
+}
+
+//memcpy_8 assumes that width is an integer multiple of 8!
+void *memcpy_8(void * dest, const void * src, size_t n)
+{
+ _asm
+ {
+ mov eax, dword ptr [src]
+ mov ebx, dword ptr [dest]
+ mov ecx, dword ptr [n]
+
+ loop0:
+
+ movq mm0, QWORD PTR [eax]
+ movq QWORD PTR [ebx], mm0
+ add eax, 8
+ add ebx, 8
+ sub ecx, 8
+ jg loop0
+
+ emms
+ }
+
+}
+
+#endif
+
+}
diff --git a/common_video/vplib/main/source/vplib.gyp b/common_video/vplib/main/source/vplib.gyp
new file mode 100644
index 0000000..e21a503
--- /dev/null
+++ b/common_video/vplib/main/source/vplib.gyp
@@ -0,0 +1,71 @@
+# 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.
+
+{
+ 'includes': [
+ '../../../../common_settings.gypi', # Common settings
+ ],
+ 'targets': [
+ {
+ 'target_name': 'webrtc_vplib',
+ 'type': '<(library)',
+ 'dependencies': [
+ ],
+ 'include_dirs': [
+ '../interface',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../interface',
+ ],
+ },
+ 'sources': [
+ # interfaces
+ '../interface/vplib.h',
+ '../interface/interpolator.h',
+
+ # headers
+ 'conversion_tables.h',
+ 'scale_bilinear_yuv.h',
+
+ # sources
+ 'vplib.cc',
+ 'interpolator.cc',
+ 'scale_bilinear_yuv.cc',
+ ],
+ },
+ {
+ 'target_name': 'vplib_test',
+ 'type': 'executable',
+ 'dependencies': [
+ 'webrtc_vplib',
+ ],
+ 'include_dirs': [
+ '../interface',
+ '../source',
+ ],
+ 'sources': [
+
+ # headers
+ '../test/test_util.h',
+
+ # sources
+ '../test/tester_main.cc',
+ '../test/scale_test.cc',
+ '../test/convert_test.cc',
+ '../test/interpolation_test.cc',
+ ], # source
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/common_video/vplib/main/test/convert_test.cc b/common_video/vplib/main/test/convert_test.cc
new file mode 100644
index 0000000..dec535d
--- /dev/null
+++ b/common_video/vplib/main/test/convert_test.cc
@@ -0,0 +1,368 @@
+/*
+ * 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.
+ */
+
+// Test application for color space conversion functions
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+#include <string>
+#include <cmath>
+#include <time.h>
+
+#include "test_util.h"
+#include "vplib.h"
+
+using namespace webrtc;
+
+
+// Optimization testing
+//#define SCALEOPT //For Windows currently, June 2010
+
+WebRtc_Word32
+ImagePSNRfromBuffer(WebRtc_UWord8 *refBufName, WebRtc_UWord8 *testBufName,
+ WebRtc_Word32 width, WebRtc_Word32 height,
+ VideoType vType, double *YPSNRptr);
+void TestRetVal(int testVal, int refVal );
+
+int convert_test(CmdArgs& args)
+{
+ // reading YUV frame - testing on the first frame of the foreman sequence
+
+ //SET UP
+ int j = 0;
+ int retVal;
+ std::string outname = args.outputFile;
+ if (outname == "")
+ {
+ outname = "conversionTest_out.yuv";
+ }
+ std::string inname;
+ inname = args.inputFile;
+ FILE* sourceFile;
+ FILE* outputFile;
+ FILE* logFile;
+ WebRtc_UWord32 width = args.width;
+ WebRtc_UWord32 height = args.height;
+ WebRtc_UWord32 lengthSourceFrame = width*height*3/2;
+ double psnr = 0;
+ if ((sourceFile = fopen(inname.c_str(), "rb")) == NULL)
+ {
+ printf("Cannot read file %s.\n", inname.c_str());
+ exit(1);
+ }
+ if ((outputFile = fopen(outname.c_str(), "wb")) == NULL)
+ {
+ printf("Cannot write file %s.\n", outname.c_str());
+ exit(1);
+ }
+ if ((logFile = fopen("../log.txt", "a")) == NULL)
+ {
+ printf("Cannot write file ../log.txt.\n");
+ exit(1);
+ }
+
+ // reading first frame of Foreman sequence
+ WebRtc_UWord8* origBuffer = new WebRtc_UWord8[width * height*3/2];
+ fread(origBuffer, 1, lengthSourceFrame, sourceFile);
+
+ // START TEST
+ printf("\nTEST #%d I420 <-> RGB24\n", j);
+
+ WebRtc_UWord8* resRGBBuffer2 = new WebRtc_UWord8[width*height*3];
+ WebRtc_UWord8* resI420Buffer = new WebRtc_UWord8[width*height*3/2];
+ retVal = ConvertFromI420(kRGB24, origBuffer, width, height,resRGBBuffer2);
+ TestRetVal(retVal, width*height*3);
+ clock_t tticks = clock();
+ for (int tt = 0; tt < 1000; tt++)
+ {
+ retVal = ConvertToI420(kRGB24, resRGBBuffer2, width, height,
+ resI420Buffer);
+ }
+ tticks = clock() - tticks;
+ printf("RGB24->I420 Time(1000): %d\n", tticks);
+
+ TestRetVal(retVal, width*height*3/2);
+ fwrite(resI420Buffer, lengthSourceFrame, 1, outputFile);
+ ImagePSNRfromBuffer(origBuffer, resI420Buffer, width, height, kI420, &psnr);
+ printf("Conversion between type #%d and type #%d, PSNR = %f\n", kI420,
+ kRGB24, psnr);
+ j++;
+ delete [] resRGBBuffer2;
+
+
+ printf("\nTEST #%d I420 <-> UYVY\n", j);
+ WebRtc_UWord8* outUYVYBuffer = new WebRtc_UWord8[width*height*2];
+
+ clock_t ticks = clock();
+ for (int t = 0; t < 100; t++)
+ {
+ retVal = ConvertFromI420(kUYVY, origBuffer, width,
+ height, outUYVYBuffer);
+ }
+ ticks = clock() - ticks;
+#ifndef SCALEOPT
+ fprintf(logFile, "\nConvertI420ToUYVY, before opt: %d\n", ticks);
+#else
+ fprintf(logFile, "\nConvertI420ToUYVY, after opt: %d\n", ticks);
+#endif
+
+ TestRetVal(retVal, width*height*2);
+ retVal = ConvertToI420(kUYVY, outUYVYBuffer, width, height, resI420Buffer);
+ TestRetVal(retVal, width*height*3/2);
+
+ ImagePSNRfromBuffer(origBuffer, resI420Buffer, width, height, kI420, &psnr);
+ printf("Conversion between type #%d and type #%d, PSNR = %f\n",
+ kI420, kUYVY, psnr);
+ j++;
+ delete [] outUYVYBuffer;
+
+
+ printf("\nTEST #%d I420 <-> I420 \n", j);
+
+ WebRtc_UWord8* outI420Buffer = new WebRtc_UWord8[width*height*2];
+ retVal = ConvertToI420(kI420, origBuffer, width, height, outI420Buffer);
+ TestRetVal(retVal, width*height*3/2);
+ retVal = ConvertToI420(kI420 ,outI420Buffer, width, height, resI420Buffer);
+ TestRetVal(retVal, width*height*3/2);
+ fwrite(resI420Buffer, lengthSourceFrame, 1, outputFile);
+ ImagePSNRfromBuffer(origBuffer, resI420Buffer, width, height,
+ kI420, &psnr);
+ printf("Conversion between type #%d and type #%d, PSNR = %f\n",
+ kI420, kUYVY, psnr);
+ j++;
+ delete [] outI420Buffer;
+
+ printf("\nTEST #%d I420 <-> YV12\n", j);
+ outI420Buffer = new WebRtc_UWord8[width*height*3/2]; // assuming DIFF = 0
+
+ ticks = clock();
+ for (int t = 0; t < 1000; t++)
+ {
+ retVal = ConvertFromI420(kYV12, origBuffer, width, height, outI420Buffer);
+ }
+ ticks = clock() - ticks;
+#ifndef SCALEOPT
+ fprintf(logFile, "\nConvertI420ToYV12, before opt: %d\n", ticks);
+#else
+ fprintf(logFile, "\nConvertI420ToYV12, after opt: %d\n", ticks);
+#endif
+ TestRetVal(retVal, width*height*3/2);
+ retVal = webrtc::ConvertYV12ToI420(outI420Buffer, width, height,
+ resI420Buffer);
+ TestRetVal(retVal, width*height*3/2);
+
+ fwrite(resI420Buffer, lengthSourceFrame, 1, outputFile);
+
+ ImagePSNRfromBuffer(origBuffer, resI420Buffer, width, height, kI420, &psnr);
+ printf("Conversion between type #%d and type #%d, PSNR = %f\n", kI420,
+ kYV12, psnr);
+ j++;
+ delete [] outI420Buffer;
+ delete [] resI420Buffer;
+
+
+ printf("\nTEST #%d I420<-> RGB565\n", j);
+ WebRtc_UWord8* res2ByteBuffer = new WebRtc_UWord8[width*height*2];
+ resI420Buffer = new WebRtc_UWord8[width * height * 3 / 2];
+ retVal = ConvertFromI420(kRGB565, origBuffer, width, height, res2ByteBuffer);
+ TestRetVal(retVal, width*height*2);
+ retVal = ConvertRGB565ToI420(res2ByteBuffer, width, height, resI420Buffer);
+ TestRetVal(retVal, width*height*3/2);
+ fwrite(resI420Buffer, lengthSourceFrame, 1, outputFile);
+ ImagePSNRfromBuffer(origBuffer, resI420Buffer, width, height, kI420, &psnr);
+ printf("Note: Frame was compressed!\n");
+ printf("Conversion between type #%d and type #%d, PSNR = %f\n", kI420,
+ kRGB565, psnr);
+
+ delete [] res2ByteBuffer;
+ j++;
+
+ printf("\nTEST #%d I420 <-> YUY2\n", j);
+ WebRtc_UWord8* outYUY2Buffer = new WebRtc_UWord8[width*height*2];
+
+ ticks = clock();
+ for (int t = 0; t < 1000; t++)
+ {
+ retVal = ConvertI420ToYUY2(origBuffer, outYUY2Buffer, width, height,0);
+ }
+ ticks = clock() - ticks;
+#ifndef SCALEOPT
+ fprintf(logFile, "\nConvertI420ToYUY2, before opt: %d\n", ticks);
+#else
+ fprintf(logFile, "\nConvertI420ToYUY2, after opt: %d\n", ticks);
+#endif
+ TestRetVal(retVal, width*height*2);
+ ticks = clock();
+ for (int t = 0; t < 1000; t++)
+ {
+ retVal = ConvertToI420(kYUY2, outYUY2Buffer, width, height,
+ resI420Buffer);
+ }
+ ticks = clock() - ticks;
+#ifndef SCALEOPT
+ fprintf(logFile, "\nConvertYUY2ToI420, before opt: %d\n", ticks);
+#else
+ fprintf(logFile, "\nConvertYUY2ToI420, after opt: %d\n", ticks);
+#endif
+ TestRetVal(retVal, width*height*3/2);
+ fwrite(resI420Buffer, lengthSourceFrame, 1, outputFile);
+ ImagePSNRfromBuffer(origBuffer, resI420Buffer, width, height, kI420, &psnr);
+ printf("Conversion between type #%d and type #%d,PSNR = %f\n", kI420,
+ kYUY2, psnr);
+
+ delete [] outYUY2Buffer;
+ j++;
+
+ printf("\nTEST #%d I420 <-> UYVY\n", j);
+
+ outUYVYBuffer = new WebRtc_UWord8[width*height*2]; // assuming DIFF = 0
+ WebRtc_UWord8* resYUVBuffer = new WebRtc_UWord8[width*height*2];
+ retVal = ConvertFromI420(kUYVY, origBuffer, width, height, outUYVYBuffer);
+ TestRetVal(retVal, width*height*2);
+ retVal = ConvertToI420(kUYVY, outUYVYBuffer, width, height, resYUVBuffer);
+ TestRetVal(retVal, width*height*3/2);
+ fwrite(resYUVBuffer, lengthSourceFrame, 1, outputFile);
+ ImagePSNRfromBuffer(origBuffer, resYUVBuffer, width, height, kI420, &psnr);
+ printf("Conversion between type #%d and type #%d,PSNR = %f\n", kI420,
+ kUYVY, psnr);
+
+ delete [] outUYVYBuffer;
+ delete [] resYUVBuffer;
+
+ j++;
+
+ /*******************************************************************
+ * THE FOLLOWING FUNCTIONS HAVE NO INVERSE, BUT ARE PART OF THE TEST
+ * IN ORDER TO VERIFY THAT THEY DO NOT CRASH
+ *******************************************************************/
+ printf("\n\n Running functions with no inverse...\n");
+
+ //printf("TEST #%d I420 -> ARGB4444 \n", j);
+ res2ByteBuffer = new WebRtc_UWord8[width*height*2];
+ ConvertI420ToARGB4444(origBuffer, res2ByteBuffer, width, height, 0);
+ delete [] res2ByteBuffer;
+
+ // YUY2 conversions
+ //printf("TEST #%d I420 -> YUY2 \n", j);
+ WebRtc_UWord8* sourceYUY2 = new WebRtc_UWord8[width*height*2];
+ ConvertI420ToYUY2(origBuffer, sourceYUY2, width, height, 0);
+
+ delete [] sourceYUY2;
+
+ //UYVY conversions
+ WebRtc_UWord8* sourceUYVY = new WebRtc_UWord8[width*height*2];
+ ConvertI420ToUYVY(origBuffer, sourceUYVY, width, height, 0);
+
+ //printf("TEST I420-> ARGB444\n");
+ res2ByteBuffer = new WebRtc_UWord8[(width+10)*height*2];
+ retVal = webrtc::ConvertI420ToARGB4444(origBuffer, res2ByteBuffer,
+ width, height, width + 10);
+ TestRetVal(retVal, (width+10)*height*2);
+ delete [] res2ByteBuffer;
+
+ //printf("TEST I420-> ARGB1555\n");
+ res2ByteBuffer = new WebRtc_UWord8[(width+10)*height*2];
+ retVal = ConvertI420ToARGB1555(origBuffer, res2ByteBuffer, width,
+ height, width + 10);
+ TestRetVal(retVal, (width+10)*height*2);
+ delete [] res2ByteBuffer;
+
+ //printf("TEST NV12 - > I420\n");
+ // using original I420 sequence - > just to verify it doesn't crash
+ ConvertNV12ToI420(origBuffer,resI420Buffer, width, height);
+ //printf("TEST NV12 - > I420 and Rotate 180\n");
+ ConvertNV12ToI420AndRotate180(origBuffer, resI420Buffer, width, height);
+ //printf("TEST NV12 - > I420 and Rotate anti Clockwise\n");
+ ConvertNV12ToI420AndRotateAntiClockwise(origBuffer, resI420Buffer,
+ width, height);
+ //printf("TEST NV12 - > I420 and Rotate Clockwise\n");
+ ConvertNV12ToI420AndRotateClockwise(origBuffer, resI420Buffer,
+ width, height);
+ //printf("TEST NV12 -> RGB565 \n");
+ res2ByteBuffer = new WebRtc_UWord8[(width+10)*height*2];
+ ConvertNV12ToRGB565(origBuffer, res2ByteBuffer, width, height);
+ delete [] res2ByteBuffer;
+
+ //printf("TEST I420 - > RGBAIPhone");
+ WebRtc_UWord8* resBuffer = new WebRtc_UWord8[(width + 10) * height * 4];
+ ConvertI420ToRGBAIPhone(origBuffer, resBuffer, width, height, width + 10);
+ delete [] resBuffer;
+
+ //printf("TEST #%d I420 <-> ARGB_Mac", j);
+ WebRtc_UWord8* outARGBBuffer = new WebRtc_UWord8[width * height * 4];
+ retVal = ConvertI420ToARGBMac(origBuffer,outARGBBuffer, width, height, 0);
+ TestRetVal(retVal, width * height * 4);
+ delete [] outARGBBuffer;
+
+
+
+
+ //closing
+ fclose(sourceFile);
+ fclose(outputFile);
+ fclose(logFile);
+ delete [] origBuffer;
+ delete [] resI420Buffer;
+ std::cout << "\n** View output file **\n";
+ std::cout << "Press enter to quit test...";
+ std::string str;
+ std::getline(std::cin, str);
+
+ return 0;
+}
+
+WebRtc_Word32
+ImagePSNRfromBuffer(WebRtc_UWord8 *refBufName, WebRtc_UWord8 *testBufName,
+ WebRtc_Word32 width, WebRtc_Word32 height,
+ VideoType vType, double *YPSNRptr)
+{
+ // currently assumes I420
+ if (vType != kI420)
+ {
+ return -1;
+ }
+ double mse = 0.0;
+ double mseLogSum = 0.0;
+
+ WebRtc_UWord8 *ref = refBufName;
+ WebRtc_UWord8 * test = testBufName;
+ // comparing only 1 frame
+ mse = 0.0;
+
+ // calculate Y sum-square-difference
+ for( int k = 0; k < width * height; k++ )
+ {
+ mse += (test[k] - ref[k]) * (test[k] - ref[k]);
+ }
+
+ // divide by number of pixels
+ mse /= (double) (width * height);
+
+ if (mse == 0)
+ {
+ *YPSNRptr = 48;
+ return 0;
+ }
+ // accumulate for total average
+ mseLogSum += std::log10( mse );
+
+ *YPSNRptr = 20.0 * std::log10(255.0) - 10.0 * mseLogSum;
+
+ return 0;
+}
+
+void TestRetVal(int testVal, int refVal )
+{
+ if (testVal != refVal)
+ {
+ printf("return value = %d, desired value = %d\n", testVal, refVal);
+ }
+}
diff --git a/common_video/vplib/main/test/convert_test/convert_test.h b/common_video/vplib/main/test/convert_test/convert_test.h
new file mode 100644
index 0000000..992b497
--- /dev/null
+++ b/common_video/vplib/main/test/convert_test/convert_test.h
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+#ifndef WEBRTC_COMMON_VIDEO_VPLIB_TEST_CONVERT_TEST_H
+#define WEBRTC_COMMON_VIDEO_VPLIB_TEST_CONVERT_TEST_H
+
+#include "vplib.h"
+
+
+void ToFile(WebRtc_UWord8 *buf, WebRtc_Word32 length, WebRtc_Word32 num);
+WebRtc_Word32
+PSNRfromFiles(const WebRtc_Word8 *refFileName, const WebRtc_Word8 *testFileName, WebRtc_Word32 width,
+ WebRtc_Word32 height, WebRtc_Word32 numberOfFrames, double *YPSNRptr);
+
+#endif
diff --git a/common_video/vplib/main/test/interpolation_test.cc b/common_video/vplib/main/test/interpolation_test.cc
new file mode 100644
index 0000000..9ae1ce5
--- /dev/null
+++ b/common_video/vplib/main/test/interpolation_test.cc
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "interpolator.h"
+#include "vplib.h"
+#include "test_util.h"
+
+using namespace webrtc;
+
+int interpolationTest(CmdArgs& args)
+{
+ // Read input file, interpolate first frame according to requested method
+ // for now only YUV input and output
+
+ FILE* sourceFile;
+ FILE* outputFile;
+
+ std::string outname = args.outputFile;
+ if (outname == "")
+ {
+ outname = "InterTest_out.yuv";
+ }
+ if (args.width < 1 || args.height < 1 ||
+ args.dstWidth < 1 || args.dstHeight < 1)
+ {
+ printf("Error in input dimensions\n" );
+ return -1;
+ }
+
+ WebRtc_Word32 ret;
+
+ // create interpolator
+ webrtc::interpolator* inter = new webrtc::interpolator();
+ ret = inter->Set(args.width, args.height,
+ args.dstWidth, args.dstHeight,
+ kI420, kI420,
+ (webrtc::interpolatorType) args.intMethod);
+ if (ret != 0)
+ {
+ printf("Set ret = %d\n", ret);
+ delete inter;
+ return ret;
+ }
+
+ // read frame into buffer / create destination buffer
+ if ((outputFile = fopen(outname.c_str(), "wb")) == NULL)
+ {
+ printf("Cannot write file %s.\n", outname.c_str());
+
+ exit(1);
+ }
+
+ std::string inname = args.inputFile;
+ if ((sourceFile = fopen(inname.c_str(), "rb")) == NULL)
+ {
+ printf("Cannot read file %s.\n", inname.c_str());
+ exit(1);
+ }
+
+ WebRtc_UWord32 inRequiredSize = args.width * args.height * 3 >> 1;
+ WebRtc_UWord32 outRequiredSize = args.dstWidth * args.dstHeight * 3 >> 1;
+ WebRtc_UWord8* inputBuffer = new WebRtc_UWord8[inRequiredSize];
+ WebRtc_UWord8* outputBuffer = NULL;
+
+ //
+ clock_t startClock, TotalClock;
+ TotalClock = 0;
+ //
+ // running through entire sequence
+ int frameCnt = 0;
+ while (feof(sourceFile)== 0)
+ {
+ if (inRequiredSize != fread(inputBuffer, 1, inRequiredSize, sourceFile))
+ break;
+
+ startClock = clock();
+ ret = inter->Interpolate(inputBuffer, outputBuffer);
+ TotalClock += clock() - startClock;
+
+ if (ret == args.dstHeight)
+ {
+ fwrite(outputBuffer, 1, outRequiredSize, outputFile);
+ ret = 0; // signaling OK to main tester
+ }
+ else
+ {
+ printf("frame #%d: Interpolation Error, ret = %d\n", frameCnt, ret);
+ }
+
+ if (outputBuffer)
+ {
+ delete [] outputBuffer;
+ outputBuffer = NULL;
+ }
+ frameCnt++;
+ printf(".");
+ }
+
+ printf("\nProcessed %d frames\n", frameCnt);
+ if (frameCnt)
+ printf("\nAvg. Time per frame[mS]: %.2lf\n",
+ (1000.0 * static_cast<double>(TotalClock + 0.0)
+ /CLOCKS_PER_SEC)/frameCnt);
+
+ if (outputBuffer)
+ delete [] outputBuffer;
+
+ fclose(sourceFile);
+ fclose(outputFile);
+
+
+ // wrap up
+ delete inter;
+ delete [] inputBuffer;
+
+ return ret;
+}
diff --git a/common_video/vplib/main/test/scale_test.cc b/common_video/vplib/main/test/scale_test.cc
new file mode 100644
index 0000000..611060d
--- /dev/null
+++ b/common_video/vplib/main/test/scale_test.cc
@@ -0,0 +1,695 @@
+/*
+ * 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.
+ */
+
+
+#include <cassert>
+#include <iostream>
+#include <string>
+
+#include "vplib.h"
+
+#include <cstring>
+
+using namespace webrtc;
+
+#define TEST_STR "Test Scale."
+#define TEST_PASSED() std::cerr << TEST_STR << " : [OK]" << std::endl
+#define PRINT_LINE std::cout << "------------------------------------------" << std::endl;
+
+void PrintFrame(WebRtc_UWord8* ptrFrame, WebRtc_Word32 width, WebRtc_Word32 height)
+{
+ WebRtc_Word32 k = 0;
+ for (WebRtc_Word32 i = 0; i < height; i++)
+ {
+ for (WebRtc_Word32 j = 0; j < width; j++)
+ {
+ std::cout << (WebRtc_Word32)ptrFrame[k++] << " ";
+ }
+ std::cout << " " << std::endl;
+ }
+ std::cout << " " << std::endl;
+}
+
+
+void PrintFrame(WebRtc_UWord8* ptrInFrame, WebRtc_Word32 width, WebRtc_Word32 height, const WebRtc_Word8* str)
+{
+ std::cout << str << " (" << width << "x" << height << ") = " << std::endl;
+
+ WebRtc_UWord8* ptrFrameY = ptrInFrame;
+ WebRtc_UWord8* ptrFrameCb = ptrFrameY + width*height;
+ WebRtc_UWord8* ptrFrameCr = ptrFrameCb + width*height/4;
+
+ PrintFrame(ptrFrameY, width, height);
+ PrintFrame(ptrFrameCb, width/2, height/2);
+ PrintFrame(ptrFrameCr, width/2, height/2);
+}
+
+void CreateImage(WebRtc_Word32 width, WebRtc_Word32 height, WebRtc_UWord8* ptrFrame, WebRtc_Word32 offset, WebRtc_Word32 heightFactor, WebRtc_Word32 widthFactor = 0)
+{
+ for (WebRtc_Word32 i = 0; i < height; i++)
+ {
+ for (WebRtc_Word32 j = 0; j < width; j++)
+ {
+ *ptrFrame = (WebRtc_UWord8)((i + offset)*heightFactor + j*widthFactor);
+ ptrFrame++;
+ }
+ }
+}
+
+void ValidateImage2(WebRtc_Word32 width, WebRtc_Word32 height, WebRtc_UWord8* ptrFrame, WebRtc_Word32 offset, WebRtc_Word32 factor)
+{
+ WebRtc_Word32 k = 0;
+ WebRtc_Word32 res = offset*factor;
+ for (WebRtc_Word32 i = 0; i < height; i++)
+ {
+ for (WebRtc_Word32 j = 0; j < width; j++)
+ {
+ assert(ptrFrame[k++] == res);
+ }
+ if (i > 0)
+ {
+ res += factor/2;
+ }
+ }
+}
+
+void ValidateImage3_2(WebRtc_Word32 width, WebRtc_Word32 height, WebRtc_UWord8* ptrFrame, WebRtc_Word32 offset, WebRtc_Word32 factor)
+{
+ WebRtc_Word32 k = 0;
+ bool inc = true;
+ WebRtc_Word32 res = offset*factor;
+ for (WebRtc_Word32 i = 1; i <= height; i++)
+ {
+ for (WebRtc_Word32 j = 0; j < width; j++)
+ {
+ assert(ptrFrame[k++] == res);
+ }
+ res += factor/2;
+ if ((i % 3) == 0)
+ {
+ res += factor/2;
+ }
+ }
+}
+
+void ValidateImage1_3(WebRtc_Word32 width, WebRtc_Word32 height, WebRtc_UWord8* ptrFrame, WebRtc_Word32 offset, WebRtc_Word32 factor)
+{
+ WebRtc_Word32 k = 0;
+ WebRtc_Word32 res = offset*factor;
+ res += factor/2;
+ for (WebRtc_Word32 i = 0; i < height; i++)
+ {
+ for (WebRtc_Word32 j = 0; j < width; j++)
+ {
+ assert(ptrFrame[k++] == res);
+ }
+ res += factor*3;
+ }
+}
+
+static void VerifyInBounds(const WebRtc_UWord8* ptrImage, const WebRtc_Word32 imageLength,
+ const WebRtc_Word32 startOffset, const WebRtc_Word32 endOffset)
+{
+ // Verify that function does not write outside buffer
+ const WebRtc_UWord8* ptrFrameStart = ptrImage - startOffset;
+ const WebRtc_UWord8* ptrFrameEnd = ptrImage + imageLength;
+
+ // Verify that function does not write outside buffer
+ for (WebRtc_Word32 i = 0; i < startOffset; i++)
+ {
+ assert(ptrFrameStart[i] == 255);
+ }
+
+ for (WebRtc_Word32 i = 0; i < endOffset; i++)
+ {
+ assert(ptrFrameEnd[i] == 255);
+ }
+}
+
+WebRtc_Word32
+VerifyAndAllocateTest(WebRtc_UWord8*& buffer, WebRtc_Word32 currentSize, WebRtc_Word32 newSize)
+{
+ if(newSize > currentSize)
+ {
+ // make sure that our buffer is big enough
+ WebRtc_UWord8* newBuffer = new WebRtc_UWord8[newSize];
+ if(buffer)
+ {
+ // copy the old data
+ memcpy(newBuffer, buffer, currentSize);
+ delete [] buffer;
+ }
+ buffer = newBuffer;
+ return newSize;
+ }
+
+ return currentSize;
+}
+
+//--------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------
+
+int
+scale_test()
+{
+
+ std::string str;
+ std::cout << "--------------------------------" << std::endl;
+ std::cout << "-------- Test Scaling ----------" << std::endl;
+ std::cout << "--------------------------------" << std::endl;
+ std::cout << " " << std::endl;
+
+ // -------------------------------
+ // Test ScaleI420Up2() -----------
+ // -------------------------------
+ PRINT_LINE;
+ std::cout << "Test ScaleI420Up2()" << std::endl;
+ PRINT_LINE;
+
+ WebRtc_UWord32 width = 12;
+ WebRtc_UWord32 height = 10;
+ WebRtc_Word32 factorY = 2;
+ WebRtc_Word32 factorCb = 10;
+ WebRtc_Word32 factorCr = 20;
+ WebRtc_Word32 offset = 5;
+ WebRtc_Word32 startBufferOffset = 10;
+ WebRtc_UWord32 length = CalcBufferSize(kI420, width, height);
+
+ // Test bad inputs
+ WebRtc_UWord32 scW = 0;
+ WebRtc_UWord32 scH = 0;
+
+ WebRtc_UWord8* testFrame = new WebRtc_UWord8[length + offset];
+ WebRtc_Word32 retVal = ScaleI420Up2(0, height,testFrame,length, scW, scH);
+ assert(retVal == -1);
+ retVal = ScaleI420Up2(width, 0, testFrame,length, scW, scH);
+ assert(retVal == -1);
+ retVal = ScaleI420Up2(49, height, testFrame, length, scW, scH);
+ assert(retVal == -1);
+ retVal = ScaleI420Up2(width, 3, testFrame,length, scW, scH); // odd height
+ assert(retVal == -1);
+ retVal = ScaleI420Up2(width + 2, height, testFrame,length, scW, scH); // width, height > allocated buffer size
+ assert(retVal == -1);
+ retVal = ScaleI420Up2(width, height + 2, testFrame,length, scW, scH); // width, height > allocated buffer size
+ assert(retVal == -1);
+ retVal = ScaleI420Up2(width, height, testFrame,length, scW, scH); // width, height == allocated buffer size, OK
+ assert(retVal == scW * scH * 3 / 2);
+ delete [] testFrame;
+
+ testFrame = new WebRtc_UWord8[ length * 4 + startBufferOffset * 2];
+ memset(testFrame, 255, length * 4 + startBufferOffset * 2);
+
+ // Create input frame
+ WebRtc_UWord8* ptrFrameY = testFrame;
+ WebRtc_UWord8* ptrFrameCb = ptrFrameY + width*height;
+ WebRtc_UWord8* ptrFrameCr = ptrFrameCb + width*height/4;
+ CreateImage(width, height, ptrFrameY, offset, factorY); // Y
+ CreateImage(width/2, height/2, ptrFrameCb, offset, factorCb); // Cb
+ CreateImage(width/2, height/2, ptrFrameCr, offset, factorCr); // Cr
+ PrintFrame(testFrame, width, height, "InputFrame");
+
+ // Scale frame to twice its size
+ WebRtc_UWord32 scaledWidth = 0;
+ WebRtc_UWord32 scaledHeight = 0;
+ retVal = ScaleI420Up2(width, height, testFrame, length * 4 + startBufferOffset * 2, scaledWidth, scaledHeight);
+
+ PrintFrame(testFrame, scaledWidth, scaledHeight, "Output Frame");
+
+ // Validate results
+ assert(retVal == scaledWidth * scaledHeight * 3 / 2);
+ ptrFrameY = testFrame;
+ ptrFrameCb = ptrFrameY + scaledWidth*scaledHeight;
+ ptrFrameCr = ptrFrameCb + scaledWidth*scaledHeight/4;
+
+ ValidateImage2(scaledWidth, scaledHeight, ptrFrameY, offset, factorY);
+ ValidateImage2(scaledWidth/2, scaledHeight/2, ptrFrameCb, offset, factorCb);
+ ValidateImage2(scaledWidth/2, scaledHeight/2, ptrFrameCr, offset, factorCr);
+
+ delete [] testFrame;
+
+ // --------------------------------
+ // Test ScaleI420Up3_2() ----------
+ // --------------------------------
+ PRINT_LINE;
+ std::cout << "Test ScaleI420Up3_2()" << std::endl;
+ PRINT_LINE;
+
+ width = 12;
+ height = 8;
+ factorY = 2;
+ factorCb = 10;
+ factorCr = 20;
+ offset = 5;
+ startBufferOffset = 10;
+ length = CalcBufferSize(kI420, width, height);
+
+ // Test bad inputs
+ testFrame = new WebRtc_UWord8[length];
+
+ retVal = ScaleI420Up3_2(0, height, testFrame,length, scW, scH);
+ assert(retVal == -1);
+ retVal = ScaleI420Up3_2(width, 0, testFrame,length, scW, scH);
+ assert(retVal == -1);
+ retVal = ScaleI420Up3_2(49, height, testFrame,length, scW, scH); // odd width
+ assert(retVal == -1);
+ retVal = ScaleI420Up3_2(width, 3, testFrame,length, scW, scH); // odd height
+ assert(retVal == -1);
+ retVal = ScaleI420Up3_2(width, 10, testFrame,length, scW, scH); // odd height (color)
+ assert(retVal == -1);
+ retVal = ScaleI420Up3_2(14, height, testFrame,length, scW, scH); // odd width (color)
+ assert(retVal == -1);
+ retVal = ScaleI420Up3_2(width + 2, height, testFrame,length, scW, scH); // width, height > allocated buffer size
+ assert(retVal == -1);
+ retVal = ScaleI420Up3_2(width, height + 2, testFrame,length, scW, scH); // width, height > allocated buffer size
+ assert(retVal == -1);
+ retVal = ScaleI420Up3_2(width, height, testFrame,length, scW, scH); // width, height == allocated buffer size, OK
+ assert(retVal == scW * scH * 3 / 2);
+
+ delete [] testFrame;
+
+ testFrame = new WebRtc_UWord8[length + startBufferOffset];
+ memset(testFrame, 255, length + startBufferOffset);
+
+ // Create input frame
+ ptrFrameY = testFrame;
+ ptrFrameCb = ptrFrameY + width*height;
+ ptrFrameCr = ptrFrameCb + width*height/4;
+ CreateImage(width, height, ptrFrameY, offset, factorY); // Y
+ CreateImage(width/2, height/2, ptrFrameCb, offset, factorCb); // Cb
+ CreateImage(width/2, height/2, ptrFrameCr, offset, factorCr); // Cr
+ PrintFrame(testFrame, width, height, "Input Frame");
+
+
+ // Scale frame to 1.5 times its size
+ scaledWidth = 0;
+ scaledHeight = 0;
+ retVal = ScaleI420Up3_2(width, height, testFrame, length + startBufferOffset, scaledWidth, scaledHeight);
+
+ PrintFrame(testFrame, scaledWidth, scaledHeight, "Output Frame");
+
+ // Validate results
+ assert(retVal == scaledWidth * scaledHeight * 3 / 2);
+
+ // Verify that function does not write outside buffer
+ ptrFrameY = testFrame;//imageBuffer.GetBuffer();
+ ptrFrameCb = ptrFrameY + scaledWidth*scaledHeight;
+ ptrFrameCr = ptrFrameCb + scaledWidth*scaledHeight/4;
+
+ ValidateImage3_2(scaledWidth, scaledHeight, ptrFrameY, offset, factorY);
+ ValidateImage3_2(scaledWidth/2, scaledHeight/2, ptrFrameCb, offset, factorCb);
+ ValidateImage3_2(scaledWidth/2, scaledHeight/2, ptrFrameCr, offset, factorCr);
+
+ delete [] testFrame;
+
+ // --------------------------------
+ // Test ScaleI420Down1_3() ----------
+ // --------------------------------
+ PRINT_LINE;
+ std::cout << "Test ScaleI420Up1_3()" << std::endl;
+ PRINT_LINE;
+
+ width = 10;
+ height = 8;
+ factorY = 2;
+ factorCb = 10;
+ factorCr = 20;
+ offset = 5;
+ startBufferOffset = 10;
+ length = webrtc::CalcBufferSize(kI420, width, height);
+
+ // Test bad inputs
+ testFrame = new WebRtc_UWord8[length];
+ retVal = ScaleI420Down1_3(0, height, testFrame, length, scW, scH);
+ assert(retVal == -1);
+ retVal = ScaleI420Down1_3(width, 0, testFrame, length, scW, scH);
+ assert(retVal == -1);
+ retVal = ScaleI420Down1_3(49, height, testFrame, length, scW, scH); // odd width
+ assert(retVal == -1);
+ retVal = ScaleI420Down1_3(width, 3, testFrame, length, scW, scH); // odd height
+ assert(retVal == -1);
+ retVal = ScaleI420Down1_3(width + 2, height, testFrame, length, scW, scH); // width, height > allocated buffer size
+ assert(retVal == -1);
+ retVal = ScaleI420Down1_3(width, height + 2, testFrame, length, scW, scH); // width, height > allocated buffer size
+ assert(retVal == -1);
+ retVal = ScaleI420Down1_3(width, height, testFrame, length, scW, scH); // width, height == allocated buffer size, ok
+ assert(retVal == scW * scH * 3 / 2);
+
+ delete [] testFrame;
+
+ testFrame = new WebRtc_UWord8[length + startBufferOffset * 2];
+ memset(testFrame, 255, length + startBufferOffset * 2);
+ // Create input frame
+ ptrFrameY = testFrame;
+ ptrFrameCb = ptrFrameY + width*height;
+ ptrFrameCr = ptrFrameCb + width*height/4;
+ CreateImage(width, height, ptrFrameY, offset, factorY); // Y
+ CreateImage(width/2, height/2, ptrFrameCb, offset, factorCb); // Cb
+ CreateImage(width/2, height/2, ptrFrameCr, offset, factorCr); // Cr
+ PrintFrame(testFrame, width, height, "Input Frame");
+
+ // Scale frame to one third its size
+ scaledWidth = 0;
+ scaledHeight = 0;
+ retVal = ScaleI420Down1_3(width, height, testFrame, length + startBufferOffset * 2 , scaledWidth, scaledHeight);
+
+ PrintFrame(testFrame, scaledWidth, scaledHeight, "Output Frame");
+
+ // Validate results
+ assert(retVal == scaledWidth * scaledHeight * 3 / 2);
+
+ // Verify that function does not write outside buffer
+ ptrFrameY = testFrame;//imageBuffer.GetBuffer();
+ ptrFrameCb = ptrFrameY + scaledWidth*scaledHeight;
+ ptrFrameCr = ptrFrameCb + scaledWidth*scaledHeight/4;
+
+ ValidateImage1_3(scaledWidth, scaledHeight, ptrFrameY, offset, factorY);
+ ValidateImage1_3(scaledWidth/2, scaledHeight/2, ptrFrameCb, offset, factorCb);
+ ValidateImage1_3(scaledWidth/2, scaledHeight/2, ptrFrameCr, offset, factorCr);
+
+ delete [] testFrame;
+
+ // -------------------
+ // Test PadI420Frame()
+ // -------------------
+ PRINT_LINE;
+ std::cout << "Test PadI420Frame()" << std::endl;
+ PRINT_LINE;
+
+ width = 16;
+ height = 8;
+ factorY = 1;
+ factorCb = 1;
+ factorCr = 1;
+ offset = 5;
+ startBufferOffset = 10;
+ length = CalcBufferSize(kI420, width, height);
+
+ testFrame = new WebRtc_UWord8[length];
+ memset(testFrame, 255, length);
+
+ // Create input frame
+ ptrFrameY = testFrame;//imageBuffer.GetBuffer();
+ ptrFrameCb = ptrFrameY + width*height;
+ ptrFrameCr = ptrFrameCb + width*height/4;
+ CreateImage(width, height, ptrFrameY, 1, factorY); // Y
+ CreateImage(width/2, height/2, ptrFrameCb, 100, factorCb); // Cb
+ CreateImage(width/2, height/2, ptrFrameCr, 200, factorCr); // Cr
+ PrintFrame(testFrame, width, height, "Input Frame");
+
+ WebRtc_UWord8* testFrame2 = new WebRtc_UWord8[352*288];
+
+ // Test bad input
+ assert(PadI420Frame(NULL, testFrame2, 16, 16, 32, 32) == -1);
+ assert(PadI420Frame(testFrame, NULL, 16, 16, 32, 32) == -1);
+ assert(PadI420Frame(testFrame, testFrame2, 0, 16, 32, 32) == -1);
+ assert(PadI420Frame(testFrame, testFrame2, 16, 0, 32, 32) == -1);
+ assert(PadI420Frame(testFrame, testFrame2, 16, 16, 0, 32) == -1);
+ assert(PadI420Frame(testFrame, testFrame2, 16, 16, 32, 0) == -1);
+ assert(PadI420Frame(testFrame, testFrame2, 16, 16, 8, 32) == -1);
+ assert(PadI420Frame(testFrame, testFrame2, 16, 16, 32, 8) == -1);
+ assert(PadI420Frame(testFrame, testFrame2, 16, 16, 16, 16) == 3 * 16 * 16 / 2);
+
+ enum { NumOfPaddedSizes = 4 };
+ WebRtc_Word32 paddedWidth[NumOfPaddedSizes] = { 32, 22, 16, 20 };
+ WebRtc_Word32 paddedHeight[NumOfPaddedSizes] = { 16, 14, 12, 8 };
+
+ for (WebRtc_Word32 i = 0; i < NumOfPaddedSizes; i++)
+ {
+ scaledWidth = paddedWidth[i];
+ scaledHeight = paddedHeight[i];
+
+ WebRtc_Word32 toLength = webrtc::CalcBufferSize(kI420, scaledWidth, scaledHeight);
+
+ if (testFrame2)
+ {
+ delete [] testFrame2;
+ }
+ testFrame2 = new WebRtc_UWord8[toLength + startBufferOffset * 2];
+ memset(testFrame2, 255, toLength + startBufferOffset * 2);
+
+
+ retVal = webrtc::PadI420Frame(testFrame, testFrame2, width, height, scaledWidth, scaledHeight);
+ PrintFrame(testFrame2, scaledWidth, scaledHeight, "Output Frame");
+
+ // Validate results
+ assert(retVal == toLength);
+
+ }
+ std::cout << "Do the padded frames look correct?" << std::endl
+ << "(Padded dimensions which are multiples of 16 will have the" << std::endl
+ << "padding applied in blocks of 16)" << std::endl
+ << "Press enter to continue...";
+ std::getline(std::cin, str);
+
+ // -----------------
+ // Test video sizes
+ // -----------------
+ const WebRtc_Word32 nr = 16;
+ // currently not keeping video sizes as a type - testing scaling functions only
+ WebRtc_UWord16 widths[nr] = {128, 160, 176, 320, 352, 640, 720, 704, 800, 960, 1024, 1440, 400, 800, 1280, 1920};
+ WebRtc_UWord16 heights[nr] = { 96, 120, 144, 240, 288, 480, 480, 576, 600, 720, 768, 1080, 240, 480, 720, 1080};
+
+ for (WebRtc_Word32 j = 0; j < 3; j++)
+ {
+ for (WebRtc_Word32 i = 0; i < nr; i++)
+ {
+ width = widths[i];
+ height = heights[i];
+ factorY = 2;
+ factorCb = 2;
+ factorCr = 2;
+ offset = 2;
+ startBufferOffset = 10;
+ length = webrtc::CalcBufferSize(kI420, width, height);
+
+ float f = 1;
+ if (j == 0)
+ {
+ f = 2;
+ }
+ else if (j == 1)
+ {
+ f = 1.5;
+ }
+ else if (j == 2)
+ {
+ f = 1;
+ }
+
+ if (testFrame)
+ {
+ delete testFrame;
+ testFrame = 0;
+ }
+ WebRtc_Word32 frameSize = (WebRtc_Word32) ((length * f * f) + startBufferOffset * 2);
+ testFrame = new WebRtc_UWord8[frameSize];
+ memset(testFrame, 255, frameSize);
+
+ // Create input frame
+ ptrFrameY = testFrame;
+ ptrFrameCb = ptrFrameY + width*height;
+ ptrFrameCr = ptrFrameCb + width*height/4;
+ CreateImage(width, height, ptrFrameY, offset, factorY); // Y
+ CreateImage(width/2, height/2, ptrFrameCb, offset, factorCb); // Cb
+ CreateImage(width/2, height/2, ptrFrameCr, offset, factorCr); // Cr
+
+ scaledWidth = 0;
+ scaledHeight = 0;
+ if (j == 0)
+ {
+ retVal = ScaleI420Up2(width, height, testFrame,frameSize, scaledWidth, scaledHeight);
+ length = scaledWidth*scaledHeight*3/2;
+ }
+ else if (j == 1)
+ {
+ retVal = ScaleI420Up3_2(width, height, testFrame,frameSize, scaledWidth, scaledHeight);
+ length = scaledWidth*scaledHeight*3/2;
+ }
+ else if (j == 2)
+ {
+ retVal = ScaleI420Down1_3(width, height, testFrame,frameSize, scaledWidth, scaledHeight);
+ length = width*height*3/2;
+ }
+
+ // Validate results
+ assert(retVal == scaledWidth * scaledHeight * 3 / 2);
+ }
+ }
+
+ // ---------------------
+ // Test mirror functions
+ // ---------------------
+ std::cout << "Test Mirror function" << std::endl;
+
+ // 4:2:0 images can't have odd width or height
+ width = 16;
+ height = 8;
+ factorY = 1;
+ factorCb = 1;
+ factorCr = 1;
+ offset = 5;
+ startBufferOffset = 10;
+ length = webrtc::CalcBufferSize(kI420, width, height);
+
+ delete [] testFrame;
+ testFrame = new WebRtc_UWord8[length];
+ memset(testFrame, 255, length);
+
+ // Create input frame
+ WebRtc_UWord8* inFrame = testFrame;
+ ptrFrameCb = inFrame + width * height;
+ ptrFrameCr = ptrFrameCb + (width * height) / 4;
+ CreateImage(width, height, inFrame, 10, factorY, 1); // Y
+ CreateImage(width/2, height/2, ptrFrameCb, 100, factorCb, 1); // Cb
+ CreateImage(width/2, height/2, ptrFrameCr, 200, factorCr, 1); // Cr
+ PrintFrame(testFrame, width, height, "Input Frame");
+
+ if (testFrame2)
+ {
+ delete [] testFrame2;
+ testFrame2 = 0;
+ }
+ testFrame2 = new WebRtc_UWord8[length + startBufferOffset * 2];
+ memset(testFrame2, 255, length + startBufferOffset * 2);
+ WebRtc_UWord8* outFrame = testFrame2;
+
+ // LeftRight
+ std::cout << "Test Mirror function: LeftRight" << std::endl;
+ retVal = MirrorI420LeftRight(inFrame, outFrame, width, height);
+ PrintFrame(testFrame2, width, height, "Output Frame");
+ retVal = MirrorI420LeftRight(outFrame, outFrame, width, height);
+
+ assert(memcmp(inFrame, outFrame, length) == 0);
+ //VerifyInBounds(outFrame, length, startBufferOffset, startBufferOffset);
+
+ //UpDown
+ std::cout << "Test Mirror function: UpDown" << std::endl;
+ retVal = MirrorI420UpDown(inFrame, outFrame, width, height);
+ PrintFrame(testFrame2, width, height, "Output Frame");
+ retVal = MirrorI420UpDown(outFrame, outFrame, width, height);
+
+ assert(memcmp(inFrame, outFrame, length) == 0);
+ //VerifyInBounds(outFrame, length, startBufferOffset, startBufferOffset);
+
+ std::cout << "Do the mirrored frames look correct?" << std::endl
+ << "Press enter to continue...";
+ std::getline(std::cin, str);
+ // end Mirror Function check
+
+ delete [] testFrame;
+ testFrame = new WebRtc_UWord8[length];
+ memset(testFrame,255,length);
+ inFrame = testFrame;
+
+ CreateImage(width, height, inFrame, 10, factorY, 1); // Y
+ CreateImage(width/2, height/2, ptrFrameCb, 100, factorCb, 1); // Cb
+ CreateImage(width/2, height/2, ptrFrameCr, 200, factorCr, 1); // Cr
+
+ PrintFrame(inFrame, width, height, "Input frame");
+
+ delete [] testFrame2;
+ testFrame2 = new WebRtc_UWord8[length];
+ memset(testFrame2, 255, length);
+ int yv12Size = CalcBufferSize(kI420, kYV12, length);
+ WebRtc_UWord8* yv12TestFrame = new WebRtc_UWord8[yv12Size];
+ memset(yv12TestFrame, 255, yv12Size);
+ outFrame = testFrame2;
+ retVal = ConvertI420ToYV12(inFrame, yv12TestFrame, width, height, 0);
+ assert(retVal >= 0);
+
+ // Test convert and mirror functions
+ ConvertToI420AndMirrorUpDown(yv12TestFrame, outFrame, width, height, kYV12);
+ std::cout << "Test: ConvertAndMirrorUpDown" << std::endl;
+ PrintFrame(outFrame, width, height, "Output Frame");
+ MirrorI420UpDown(outFrame, outFrame, width, height);
+ assert(memcmp(inFrame, outFrame, length) == 0);
+ std::cout << "Does the converted (U and V flipped) mirrored frame look correct?" << std::endl
+ << "Press enter to continue...";
+ std::getline(std::cin, str);
+ delete [] testFrame2;
+
+ PrintFrame(inFrame, width, height, "Input frame");
+
+ // Test convert and rotate functions
+ testFrame2 = new WebRtc_UWord8[length];
+ memset(testFrame2, 255, length);
+ outFrame = testFrame2;
+ WebRtc_UWord8* tempFrame = new WebRtc_UWord8[length];
+
+ ConvertToI420(kYV12, yv12TestFrame, width, height, outFrame, false, kRotateAntiClockwise);
+ std::cout << "Test: ConvertAndRotateAntiClockwise" << std::endl;
+ PrintFrame(outFrame, height, width, "Output Frame");
+ ConvertToI420(kI420, outFrame, height, width, tempFrame, false, kRotateAntiClockwise);
+ ConvertToI420(kI420, tempFrame, width, height, outFrame, false, kRotateAntiClockwise);
+ ConvertToI420(kI420, outFrame, height, width, tempFrame, false, kRotateAntiClockwise);
+ assert(memcmp(inFrame, tempFrame, length) == 0);
+
+ delete [] testFrame2;
+
+ testFrame2 = new WebRtc_UWord8[length];
+ outFrame = testFrame2;
+ memset(outFrame, 255, length);
+ memset(tempFrame, 255, length);
+ ConvertToI420(kYV12, yv12TestFrame, width, height, outFrame, false, kRotateClockwise);
+ std::cout << "Test: ConvertAndRotateClockwise" << std::endl;
+ PrintFrame(outFrame, height, width, "Output Frame");
+ ConvertToI420(kI420, outFrame, height, width, tempFrame, false, kRotateClockwise);
+ ConvertToI420(kI420, tempFrame, width, height, outFrame, false, kRotateClockwise);
+ ConvertToI420(kI420, outFrame, height, width, tempFrame, false, kRotateClockwise);
+ assert(memcmp(inFrame, tempFrame, length) == 0);
+
+ delete [] testFrame2;
+
+ std::cout << "Do the converted (U and V flipped) and rotated frames look correct?" << std::endl
+ << "Press enter to continue...";
+ std::getline(std::cin, str);
+
+
+ PrintFrame(inFrame, width, height, "Input frame");
+
+ // Test rotation with padding
+
+ height += 4;
+ length = width * height * 3 / 2;
+ testFrame2 = new WebRtc_UWord8[length];
+ memset(testFrame2, 255, length);
+ outFrame = testFrame2;
+ webrtc::ConvertToI420(kYV12, yv12TestFrame, width, height - 4, outFrame, false, webrtc::kRotateClockwise);
+ std::cout << "Test: ConvertAndRotateClockwise (width padding)" << std::endl;
+ PrintFrame(outFrame, height, width, "Output Frame");
+
+ width += 4;
+ height -= 4;
+ memset(testFrame2, 255, length);
+ outFrame = testFrame2;
+ ConvertToI420(kYV12, yv12TestFrame, width - 4, height, outFrame, false, webrtc::kRotateAntiClockwise);
+ std::cout << "Test: ConvertAndRotateClockwise (height padding)" << std::endl;
+ PrintFrame(outFrame, height, width, "Output Frame");
+
+ std::cout << "Do the rotated and padded images look correct?" << std::endl
+ << "Press enter to continue...";
+ std::getline(std::cin, str);
+
+ delete [] tempFrame;
+ tempFrame = NULL;
+ delete [] testFrame;
+ testFrame = NULL;
+ delete [] testFrame2;
+ testFrame2 = NULL;
+ delete [] yv12TestFrame;
+ yv12TestFrame = NULL;
+
+ TEST_PASSED();
+ std::cout << "Press enter to quit test...";
+ std::getline(std::cin, str);
+
+ return 0;
+}
diff --git a/common_video/vplib/main/test/test_util.h b/common_video/vplib/main/test/test_util.h
new file mode 100644
index 0000000..7fd34da
--- /dev/null
+++ b/common_video/vplib/main/test/test_util.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+#ifndef COMMON_VIDEO_VPLIB_TEST_UTIL_H
+#define COMMON_VIDEO_VPLIB_TEST_UTIL_H
+
+#include <string.h>
+#include <fstream>
+#include <cstdlib>
+
+
+class CmdArgs
+{
+public:
+ CmdArgs() : width(-1), height(-1), dstWidth(-1), dstHeight(-1),
+ intMethod(-1), inputFile(""), outputFile(""), testNum(-1)
+ {}
+ int width;
+ int height;
+ int dstWidth;
+ int dstHeight;
+ int intMethod;
+ std::string inputFile;
+ std::string outputFile;
+ int testNum;
+};
+
+int interpolationTest(CmdArgs& args);
+int convert_test(CmdArgs& args);
+int scale_test();
+
+#endif // COMMON_VIDEO_VPLIB_TEST_UTIL_H
diff --git a/common_video/vplib/main/test/tester_main.cc b/common_video/vplib/main/test/tester_main.cc
new file mode 100644
index 0000000..090a56c
--- /dev/null
+++ b/common_video/vplib/main/test/tester_main.cc
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vplib.h"
+#include "test_util.h"
+
+using namespace webrtc;
+
+int ParseArguments(int argc, char **argv, CmdArgs& args)
+{
+ int i = 1;
+ while (i < argc)
+ {
+ if (argv[i][0] != '-')
+ {
+ return -1;
+ }
+ switch (argv[i][1])
+ {
+ case 'w':
+ {
+ int w = atoi(argv[i+1]);
+ if (w < 1)
+ return -1;
+ args.width = w;
+ break;
+ }
+ case 'h':
+ {
+ int h = atoi(argv[i+1]);
+ if (h < 1)
+ return -1;
+ args.height = h;
+ break;
+ }
+ case 'x':
+ {
+ int x = atoi(argv[i+1]);
+ if (x < 1)
+ return -1;
+ args.dstWidth = x;
+ break;
+ }
+ case 'y':
+ {
+ int y = atoi(argv[i+1]);
+ if (y < 1)
+ return -1;
+ args.dstHeight = y;
+ break;
+ }
+ case 'm': // interpolation method
+ {
+ int m = atoi(argv[i+1]);
+ if (m < 0)
+ return -1;
+ args.intMethod = m;
+ break;
+ }
+ case 'i':
+ {
+ args.inputFile = argv[i+1];
+ break;
+ }
+ case 'o':
+ args.outputFile = argv[i+1];
+ break;
+ case 'n':
+ {
+ int n = atoi(argv[i+1]);
+ if (n < 1)
+ return -1;
+ args.testNum = n;
+ break;
+ }
+ default:
+ return -1;
+ }
+ i += 2;
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ CmdArgs args;
+
+ if (ParseArguments(argc, argv, args) != 0)
+ {
+ printf("Unable to parse input arguments\n");
+ printf("args: -n <test #> -w <width> -h <height> "
+ "-x <destination width> -y <destination height> -f <fps> "
+ "-b <bps> -m <method> -i <input file> -o <output file>\n");
+ return -1;
+ }
+ int ret = -1;
+ switch (args.testNum)
+ {
+ printf("\n");
+ case 1:
+ printf("VPLIB Interpolation Test\n");
+ ret = interpolationTest(args);
+ break;
+ case 2:
+ printf("VPLIB Scale Test\n");
+ ret = scale_test();
+ break;
+ case 3:
+ printf("VPLIB Convert Test\n");
+ ret = convert_test(args);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ if (ret != 0)
+ {
+ printf("Test failed!\n");
+ return -1;
+ }
+ return 0;
+}