From 01813fe94557bcc546dfbdfef3bc3a7b680c9af1 Mon Sep 17 00:00:00 2001 From: "niklase@google.com" Date: Mon, 30 May 2011 11:21:31 +0000 Subject: [PATCH] git-svn-id: http://webrtc.googlecode.com/svn/trunk@3 4adac7df-926f-26a2-2b94-8c16560cd09d --- common_video/OWNERS | 4 + common_video/jpeg/main/interface/jpeg.h | 96 + common_video/jpeg/main/source/data_manager.cc | 100 + common_video/jpeg/main/source/data_manager.h | 68 + common_video/jpeg/main/source/jpeg.cc | 345 ++ common_video/jpeg/main/source/jpeg.gyp | 98 + common_video/jpeg/main/test/test_buffer.cc | 161 + common_video/jpeg/main/test/test_buffer.h | 77 + common_video/jpeg/main/test/test_jpeg.cc | 141 + .../vplib/main/interface/interpolator.h | 76 + common_video/vplib/main/interface/vplib.h | 356 ++ .../vplib/main/source/conversion_tables.h | 182 + .../vplib/main/source/interpolator.cc | 100 + .../vplib/main/source/scale_bilinear_yuv.cc | 343 ++ .../vplib/main/source/scale_bilinear_yuv.h | 31 + common_video/vplib/main/source/vplib.cc | 4438 +++++++++++++++++ common_video/vplib/main/source/vplib.gyp | 71 + common_video/vplib/main/test/convert_test.cc | 368 ++ .../main/test/convert_test/convert_test.h | 22 + .../vplib/main/test/interpolation_test.cc | 128 + common_video/vplib/main/test/scale_test.cc | 695 +++ common_video/vplib/main/test/test_util.h | 38 + common_video/vplib/main/test/tester_main.cc | 133 + 23 files changed, 8071 insertions(+) create mode 100644 common_video/OWNERS create mode 100644 common_video/jpeg/main/interface/jpeg.h create mode 100644 common_video/jpeg/main/source/data_manager.cc create mode 100644 common_video/jpeg/main/source/data_manager.h create mode 100644 common_video/jpeg/main/source/jpeg.cc create mode 100644 common_video/jpeg/main/source/jpeg.gyp create mode 100644 common_video/jpeg/main/test/test_buffer.cc create mode 100644 common_video/jpeg/main/test/test_buffer.h create mode 100644 common_video/jpeg/main/test/test_jpeg.cc create mode 100644 common_video/vplib/main/interface/interpolator.h create mode 100644 common_video/vplib/main/interface/vplib.h create mode 100644 common_video/vplib/main/source/conversion_tables.h create mode 100644 common_video/vplib/main/source/interpolator.cc create mode 100644 common_video/vplib/main/source/scale_bilinear_yuv.cc create mode 100644 common_video/vplib/main/source/scale_bilinear_yuv.h create mode 100644 common_video/vplib/main/source/vplib.cc create mode 100644 common_video/vplib/main/source/vplib.gyp create mode 100644 common_video/vplib/main/test/convert_test.cc create mode 100644 common_video/vplib/main/test/convert_test/convert_test.h create mode 100644 common_video/vplib/main/test/interpolation_test.cc create mode 100644 common_video/vplib/main/test/scale_test.cc create mode 100644 common_video/vplib/main/test/test_util.h create mode 100644 common_video/vplib/main/test/tester_main.cc diff --git a/common_video/OWNERS b/common_video/OWNERS new file mode 100644 index 000000000..30eee35f1 --- /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 000000000..6f092b8e7 --- /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 000000000..2e2a870cc --- /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 000000000..56fdb2d1c --- /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 + +// 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 000000000..9fffeddc0 --- /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 +#include + +#include "vplib.h" +#include "jpeg.h" +#include "data_manager.h" +#if defined(WIN32) + #include +#endif +#ifdef WEBRTC_ANDROID +extern "C" { +#endif +#include "jpeglib.h" +#ifdef WEBRTC_ANDROID +} +#endif +#include + + +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 000000000..ad5419ed6 --- /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 000000000..98468f2b0 --- /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 +#include // 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 000000000..757fae37b --- /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 000000000..a947dbdae --- /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 +#include +#include +#include +#include + + +#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 000000000..70ec4fa5b --- /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 000000000..79f96bedc --- /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 000000000..4f3b1ec46 --- /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 ( 298 * ( i - 16 )) // Y contribution + #define Ucg(i) static_cast ( -100 * ( i - 128 )) // U contribution to G + #define Ucb(i) static_cast ( 516 * ( i - 128 )) // U contribution to B + #define Vcr(i) static_cast ( 409 * ( i - 128 )) // V contribution to R + #define Vcg(i) static_cast ( -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 000000000..8e49eb16b --- /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 + +#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 000000000..b92fb73b2 --- /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 + +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 +#else +#include +#endif +#endif + +#if USE_SSE2 +#include +#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(y0_ptr); + const __m128i* y1_ptr128 = reinterpret_cast(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(y0_ptr); + const __m64* y1_ptr64 = reinterpret_cast(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 000000000..08e905e23 --- /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 000000000..804a1592d --- /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 // memcpy(), memset() +#include +#include // abs + +//#define SCALEOPT //Currently for windows only. June 2010 + +#ifdef SCALEOPT +#include +#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 000000000..e21a503e3 --- /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 000000000..dec535d54 --- /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 +#include +#include +#include +#include +#include + +#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 000000000..992b4975e --- /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 000000000..9ae1ce57a --- /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 +#include +#include + +#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(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 000000000..611060d5d --- /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 +#include +#include + +#include "vplib.h" + +#include + +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 000000000..7fd34da6b --- /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 +#include +#include + + +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 000000000..090a56c8f --- /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 +#include +#include + +#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 -w -h " + "-x -y -f " + "-b -m -i -o \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; +}