first draft

git-svn-id: http://libyuv.googlecode.com/svn/trunk@2 16f28f9a-4ce2-e073-06de-1de4eb20be90
This commit is contained in:
mikhal@webrtc.org 2011-09-28 00:06:25 +00:00
parent 81a7628e86
commit aed1cc94c1
24 changed files with 7748 additions and 0 deletions

108
common/basic_types.h Normal file
View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2011 The LibYuv 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 LIBYUV_COMMON_BASIC_TYPES_H_
#define LIBYUV_COMMON_BASIC_TYPES_H_
#include <stddef.h> // for NULL, size_t
#ifndef WIN32
#include <stdint.h> // for uintptr_t
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "constructor_magic.h"
#ifndef INT_TYPES_DEFINED
#define INT_TYPES_DEFINED
#ifdef COMPILER_MSVC
typedef __int64 int64;
#else
typedef long long int64;
#endif /* COMPILER_MSVC */
typedef int int32;
typedef short int16;
typedef char int8;
#ifdef COMPILER_MSVC
typedef unsigned __int64 uint64;
typedef __int64 int64;
#ifndef INT64_C
#define INT64_C(x) x ## I64
#endif
#ifndef UINT64_C
#define UINT64_C(x) x ## UI64
#endif
#define INT64_F "I64"
#else
typedef unsigned long long uint64;
typedef long long int64;
#ifndef INT64_C
#define INT64_C(x) x ## LL
#endif
#ifndef UINT64_C
#define UINT64_C(x) x ## ULL
#endif
#define INT64_F "ll"
#endif /* COMPILER_MSVC */
typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
#endif // INT_TYPES_DEFINED
#ifdef WIN32
typedef int socklen_t;
#endif
namespace libyuv {
template<class T> inline T _min(T a, T b) { return (a > b) ? b : a; }
template<class T> inline T _max(T a, T b) { return (a < b) ? b : a; }
// For wait functions that take a number of milliseconds, kForever indicates
// unlimited time.
const int kForever = -1;
}
// Detect compiler is for x86 or x64.
#if defined(__x86_64__) || defined(_M_X64) || \
defined(__i386__) || defined(_M_IX86)
#define CPU_X86 1
#endif
#ifdef WIN32
#define alignof(t) __alignof(t)
#else // !WIN32
#define alignof(t) __alignof__(t)
#endif // !WIN32
#define IS_ALIGNED(p, a) (0==(reinterpret_cast<uintptr_t>(p) & ((a)-1)))
#define ALIGNP(p, t) \
(reinterpret_cast<uint8*>(((reinterpret_cast<uintptr_t>(p) + \
((t)-1)) & ~((t)-1))))
#ifndef UNUSED
#define UNUSED(x) Unused(static_cast<const void *>(&x))
#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y))
#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z))
#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a))
#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b))
inline void Unused(const void *) { }
#endif // UNUSED
#if defined(__GNUC__)
#define GCC_ATTR(x) __attribute__ ((x))
#else // !__GNUC__
#define GCC_ATTR(x)
#endif // !__GNUC__
#endif // LIBYUV_COMMON_BASIC_TYPES_H_

121
common/common.h Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2011 The LibYuv 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 LIBYUV_SOURCE_COMMON_H_
#define LIBYUV_SOURCE_COMMON_H_
#include "constructor_magic.h"
#if defined(_MSC_VER)
// warning C4355: 'this' : used in base member initializer list
#pragma warning(disable:4355)
#endif
//////////////////////////////////////////////////////////////////////
// General Utilities
//////////////////////////////////////////////////////////////////////
#ifndef UNUSED
#define UNUSED(x) Unused(static_cast<const void *>(&x))
#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y))
#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z))
#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a))
#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b))
inline void Unused(const void *) { }
#endif // UNUSED
#ifndef WIN32
#define strnicmp(x,y,n) strncasecmp(x,y,n)
#define stricmp(x,y) strcasecmp(x,y)
// TODO(sergeyu): Remove this. std::max should be used everywhere in the code.
// NOMINMAX must be defined where we include <windows.h>.
#define stdmax(x,y) std::max(x,y)
#else
#define stdmax(x,y) libyuv::_max(x,y)
#endif
#define ARRAY_SIZE(x) (static_cast<int>((sizeof(x)/sizeof(x[0]))))
/////////////////////////////////////////////////////////////////////////////
// Assertions
/////////////////////////////////////////////////////////////////////////////
#ifndef ENABLE_DEBUG
#define ENABLE_DEBUG _DEBUG
#endif // !defined(ENABLE_DEBUG)
#if ENABLE_DEBUG
namespace libyuv {
// Break causes the debugger to stop executing, or the program to abort
void Break();
// LogAssert writes information about an assertion to the log
void LogAssert(const char * function, const char * file, int line,
const char * expression);
inline bool Assert(bool result, const char * function, const char * file,
int line, const char * expression) {
if (!result) {
LogAssert(function, file, line, expression);
Break();
return false;
}
return true;
}
} // namespace libyuv
#if defined(_MSC_VER) && _MSC_VER < 1300
#define __FUNCTION__ ""
#endif
#ifndef ASSERT
#define ASSERT(x) (void)libyuv::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x)
#endif
#ifndef VERIFY
#define VERIFY(x) libyuv::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x)
#endif
#else // !ENABLE_DEBUG
namespace libyuv {
inline bool libyuv(bool result) { return result; }
} // namespace libyuv
#ifndef ASSERT
#define ASSERT(x) (void)0
#endif
#ifndef VERIFY
#define VERIFY(x) libyuv::ImplicitCastToBool(x)
#endif
#endif // !ENABLE_DEBUG
#define COMPILE_TIME_ASSERT(expr) char CTA_UNIQUE_NAME[expr]
#define CTA_UNIQUE_NAME CTA_MAKE_NAME(__LINE__)
#define CTA_MAKE_NAME(line) CTA_MAKE_NAME2(line)
#define CTA_MAKE_NAME2(line) constraint_ ## line
#ifdef __GNUC__
// Forces compiler to inline, even against its better judgement. Use wisely.
#define FORCE_INLINE __attribute__((always_inline))
#else
#define FORCE_INLINE
#endif
#endif // LIBYUV_SOURCE_COMMON_H_

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2011 The LibYuv 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 LIBYUV_COMMON_CONSTRUCTOR_MAGIC_H_
#define LIBYUV_COMMON_CONSTRUCTOR_MAGIC_H_
#define DISALLOW_ASSIGN(TypeName) \
void operator=(const TypeName&)
// A macro to disallow the evil copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
DISALLOW_ASSIGN(TypeName)
// Alternative, less-accurate legacy name.
#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
DISALLOW_COPY_AND_ASSIGN(TypeName)
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName(); \
DISALLOW_EVIL_CONSTRUCTORS(TypeName)
#endif // LIBYUV_COMMON_CONSTRUCTOR_MAGIC_H_

169
include/convert.h Normal file
View File

@ -0,0 +1,169 @@
/*
* Copyright (c) 2011 The LibYuv 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 LIBYUV_INCLUDE_CONVERT_H_
#define LIBYUV_INCLUDE_CONVERT_H_
#include "basic_types.h"
namespace libyuv
{
int
ConvertI420ToRGB24(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertI420ToARGB(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertI420ToARGB4444(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertI420ToRGB565(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertI420ToRGB565Android(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertI420ToARGB1555(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertYV12ToARGB(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertYV12ToRGBA(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertI420ToYUY2(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertUYVYToI420(const uint8* src_frame, int src_stride,
uint8* dst_yplane, int dst_ystride,
uint8* dst_uplane, int dst_ustride,
uint8* dst_vplane, int dst_vstride,
int src_width,
int src_height);
int
ConvertI420ToYUY2(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertI420ToYV12(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertRGB24ToARGB(const uint8* src_frame, int src_stride,
uint8* dst_frame, int dst_stride,
int src_width, int src_height
);
int
ConvertRGB24ToI420(const uint8* src_frame, int src_stride,
uint8* dst_yplane, int dst_ystride,
uint8* dst_uplane, int dst_ustride,
uint8* dst_vplane, int dst_vstride,
int src_width,
int src_height
);
int
ConvertABGRToI420(const uint8* src_frame, int src_stride,
uint8* dst_yplane, int dst_ystride,
uint8* dst_uplane, int dst_ustride,
uint8* dst_vplane, int dst_vstride,
int src_width,
int src_height
);
int
ConvertNv12ToRGB565(const uint8* src_yplane, int src_ystride,
const uint8* src_uvplane, int src_uvstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
int
ConvertI420ToABGR(const uint8* src_yplane, int src_ystride,
const uint8* src_uplane, int src_ustride,
const uint8* src_vplane, int src_vstride,
uint8* dst_frame, int dst_stride,
int src_width,
int src_height
);
} // namespace libyuv
#endif // LIBYUV_INCLUDE_CONVERT_H_

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2011 The LibYuv 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 LIBYUV_INCLUDE_FORMAT_CONVERSION_H_
#define LIBYUV_INCLUDE_FORMAT_CONVERSION_H_
#include "basic_types.h"
namespace libyuv {
// Converts any Bayer RGB format to I420.
void BayerRGBToI420(const uint8* src_bayer, int src_pitch_bayer,
uint32 src_fourcc_bayer,
uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
int width, int height);
// Converts any 32 bit ARGB to any Bayer RGB format.
void RGB32ToBayerRGB(const uint8* src_rgb, int src_pitch_rgb,
uint32 src_fourcc_rgb,
uint8* dst_bayer, int dst_pitch_bayer,
uint32 dst_fourcc_bayer,
int width, int height);
} // namespace libyuv
#endif // LIBYUV_INCLUDE_FORMAT_CONVERSION_H_

61
include/general.h Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2011 The LibYuv 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.
*/
/*
* General operations on YUV images.
*/
#ifndef LIBYUV_INCLUDE_GENERAL_H_
#define LIBYUV_INCLUDE_GENERAL_H_
#include "basic_types.h"
namespace libyuv {
// Supported rotation
enum VideoRotationMode
{
kRotateNone = 0,
kRotateClockwise = 90,
kRotateAntiClockwise = -90,
kRotate180 = 180,
};
// Mirror functions
// The following 2 functions perform mirroring on an 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.
int
MirrorI420LeftRight(const uint8* src_frame, int src_stride,
uint8* dst_frame, int dst_stride,
int src_width, int src_height);
// Cut/Pad I420 frame to match desird dimensions.
int
CutPadI420Frame(const uint8* inFrame, int inWidth,
int inHeight, uint8* outFrame,
int outWidth, int outHeight);
// I420 Cut - make a center cut
int
CutI420Frame(uint8* frame, int fromWidth,
int fromHeight, int toWidth,
int toHeight);
} // namespace libyuv
#endif // LIBYUV_INCLUDE_GENERAL_H_

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2011 The LibYuv 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 LIBYUV_INCLUDE_PLANAR_FUNCTIONS_H_
#define LIBYUV_INCLUDE_PLANAR_FUNCTIONS_H_
#include "basic_types.h"
namespace libyuv {
class PlanarFunctions {
public:
// Copy I420 to I420.
static void I420Copy(const uint8* src_y, int src_pitch_y,
const uint8* src_u, int src_pitch_u,
const uint8* src_v, int src_pitch_v,
uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
int width, int height);
// Convert I422 to I420. Used by MJPG.
static void I422ToI420(const uint8* src_y, int src_pitch_y,
const uint8* src_u, int src_pitch_u,
const uint8* src_v, int src_pitch_v,
uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
int width, int height);
// Convert M420 to I420.
static void M420ToI420(uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
const uint8* m420, int pitch_m420,
int width, int height);
// Convert NV12 to I420. Also used for NV21.
static void NV12ToI420(uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
const uint8* src_y,
const uint8* src_uv,
int src_pitch,
int width, int height);
DISALLOW_IMPLICIT_CONSTRUCTORS(PlanarFunctions);
};
} // namespace libyuv
#endif // LIBYUV_INCLUDE_PLANAR_FUNCTIONS_H_

56
include/scale.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef LIBYUV_INCLUDE_SCALE_H_
#define LIBYUV_INCLUDE_SCALE_H_
#include "basic_types.h"
#if defined(_MSC_VER)
#define ALIGN16(var) __declspec(align(16)) var
#else
#define ALIGN16(var) var __attribute__((aligned(16)))
#endif
namespace libyuv
{
class YuvScaler {
public:
// Scales a YUV 4:2:0 image from the input width and height to the
// output width and height. If outh_offset is nonzero, the image is
// offset by that many pixels and stretched to (outh - outh_offset * 2)
// pixels high, instead of outh.
// If interpolate is not set, a simple nearest-neighbor algorithm is
// used. This produces basic (blocky) quality at the fastest speed.
// If interpolate is set, interpolation is used to produce a better
// quality image, at the expense of speed.
// Returns true if successful.
static bool Scale(const uint8 *in, int32 inw, int32 inh,
uint8 *out, int32 outw, int32 outh, int32 outh_offset,
bool interpolate);
// Same, but specified in terms of each plane location and stride.
static bool Scale(const uint8 *inY, const uint8 *inU, const uint8 *inV,
int32 istrideY, int32 istrideU, int32 istrideV,
int32 iwidth, int32 iheight,
uint8 *outY, uint8 *outU, uint8 *outV,
int32 ostrideY, int32 ostrideU, int32 ostrideV,
int32 owidth, int32 oheight,
bool interpolate);
// For testing, allow disabling of optimizations.
static void SetUseReferenceImpl(bool use) { use_reference_impl_ = use; }
private:
static bool use_reference_impl_;
DISALLOW_IMPLICIT_CONSTRUCTORS(YuvScaler);
};
} // namespace libyuv
#endif // LIBYUV_INCLUDE_SCALE_H_

56
libyuv.gyp Normal file
View File

@ -0,0 +1,56 @@
# Copyright (c) 2011 The LibYuv 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.
{
'targets': [
{
'target_name': 'libyuv',
'type': 'static_library',
'dependencies': [
],
'include_dirs': [
'include',
'common',
],
'sources': [
# includes
'include/convert.h',
'include/general.h',
'include/scale.h',
'include/planar_functions.h',
# headers
'common/basic_types.h',
'common/common.h',
'common/constructor_magic.h',
'source/cpu_id.h',
'source/row.h',
'source/video_common.h',
# sources
'source/convert.cc',
'source/general.cc',
'source/scale.cc',
'source/cpu_id.cc',
'source/format_conversion.cc',
'source/planar_functions.cc',
'source/row_posix.cc',
'source/row_table.cc',
'source/video_common.cc',
],
},
], # targets
}
# Local Variables:
# tab-width:2
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=2 shiftwidth=2:

203
source/conversion_tables.h Normal file
View File

@ -0,0 +1,203 @@
/*
* Copyright (c) 2011 The LibYuv 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
namespace libyuv
{
/******************************************************************************
* 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<int> ( 298 * ( i - 16 )) // Y contribution
#define Ucg(i) static_cast<int> ( -100 * ( i - 128 ))// U contribution to G
#define Ucb(i) static_cast<int> ( 516 * ( i - 128 ))// U contribution to B
#define Vcr(i) static_cast<int> ( 409 * ( i - 128 ))// V contribution to R
#define Vcg(i) static_cast<int> ( -208 * ( i - 128 ))// V contribution to G
static const int 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 int 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 int 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 int 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 int 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)};
} // namespace libyuv
#endif

1467
source/convert.cc Normal file

File diff suppressed because it is too large Load Diff

116
source/cpu_id.cc Normal file
View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2011 The LibYuv 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 "cpu_id.h"
#ifdef _MSC_VER
#include <intrin.h>
#elif LINUX
#include "linux.h"
#endif
// TODO(fbarchard): Use cpuid.h when gcc 4.4 is used on OSX and Linux.
#if (defined(__pic__) || defined(__APPLE__)) && defined(__i386__)
static inline void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile (
"mov %%ebx, %%edi\n"
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type)
);
}
#elif defined(__i386__) || defined(__x86_64__)
static inline void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile (
"cpuid\n"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type)
);
}
#endif
namespace libyuv {
// CPU detect function for SIMD instruction sets.
bool CpuInfo::cpu_info_initialized_ = false;
int CpuInfo::cpu_info_ = 0;
// Global lock for cpu initialization.
#ifdef CPU_X86
void cpuid(int cpu_info[4], int info_type) {
__cpuid(cpu_info, info_type);
}
#endif
void CpuInfo::InitCpuFlags() {
#ifdef CPU_X86
int cpu_info[4];
__cpuid(cpu_info, 1);
cpu_info_ = (cpu_info[2] & 0x00000200 ? kCpuHasSSSE3 : 0) |
(cpu_info[3] & 0x04000000 ? kCpuHasSSE2 : 0);
#elif defined(__ARM_NEON__)
// gcc -mfpu=neon defines __ARM_NEON__
// if code is specifically built for Neon-only, enable the flag.
cpu_info_ |= kCpuHasNEON;
#elif LINUX && defined(__arm__)
cpu_info_ = 0;
// Look for NEON support in /proc/cpuinfo
ProcCpuInfo proc_info;
size_t section_count;
if (proc_info.LoadFromSystem() &&
proc_info.GetSectionCount(&section_count)) {
for (size_t i = 0; i < section_count; ++i) {
std::string out_features;
if (proc_info.GetSectionStringValue(i, "Features", &out_features)) {
if (out_features.find("neon") != std::string::npos) {
cpu_info_ |= kCpuHasNEON;
}
break;
}
}
}
#else
cpu_info_ = 0;
#endif
cpu_info_initialized_ = true;
}
void CpuInfo::MaskCpuFlagsForTest(int enable_flags) {
InitCpuFlags();
cpu_info_ &= enable_flags;
}
bool CpuInfo::TestCpuFlag(int flag) {
if (!cpu_info_initialized_) {
InitCpuFlags();
}
return cpu_info_ & flag ? true : false;
}
// Returns the vendor string from the cpu, e.g. "GenuineIntel", "AuthenticAMD".
// See "Intel Processor Identification and the CPUID Instruction"
// (Intel document number: 241618)
std::string CpuInfo::GetCpuVendor() {
#ifdef CPU_X86
int cpu_info[4];
cpuid(cpu_info, 0);
cpu_info[0] = cpu_info[1]; // Reorder output
cpu_info[1] = cpu_info[3];
cpu_info[2] = cpu_info[2];
cpu_info[3] = 0;
return std::string(reinterpret_cast<char *>(&cpu_info[0]));
#else
return std::string("Undefined");
#endif
}
} // namespace libyuv

53
source/cpu_id.h Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2011 The LibYuv 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 LIBYUV_SOURCE_CPU_ID_H_
#define LIBYUV_SOURCE_CPU_ID_H_
#include <string>
#include "basic_types.h"
namespace libyuv {
#ifdef CPU_X86
void cpuid(int cpu_info[4], int info_type);
#endif
class CpuInfo {
public:
// These flags are only valid on x86 processors
static const int kCpuHasSSE2 = 1;
static const int kCpuHasSSSE3 = 2;
// SIMD support on ARM processors
static const int kCpuHasNEON = 4;
// Detect CPU has SSE2 etc.
static bool TestCpuFlag(int flag);
// Detect CPU vendor: "GenuineIntel" or "AuthenticAMD"
static std::string GetCpuVendor();
// For testing, allow CPU flags to be disabled.
static void MaskCpuFlagsForTest(int enable_flags);
private:
// Global lock for the cpu initialization
static bool cpu_info_initialized_;
static int cpu_info_;
static void InitCpuFlags();
DISALLOW_IMPLICIT_CONSTRUCTORS(CpuInfo);
};
} // namespace libyuv
#endif // LIBYUV_SOURCE_CPU_ID_H_

488
source/format_conversion.cc Normal file
View File

@ -0,0 +1,488 @@
/*
* Copyright (c) 2011 The LibYuv 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 "format_conversion.h"
#include "common.h"
#include "video_common.h"
namespace libyuv {
enum {
RED = 0,
BLUE = 1,
GREEN_BETWEEN_RED = 2,
GREEN_BETWEEN_BLUE = 3,
};
enum Position {
LEFT = 0,
RIGHT = 1,
TOP = 2,
BOTTOM = 4,
CENTER = 6,
// Due to the choice of the above values, these are all distinct and the
// corner values and edge values are each contiguous. This allows us to
// figure out the position type of a pixel with a single addition operation
// using the above values, rather than having to use a 3x3 nested switch
// statement.
TOP_LEFT = TOP + LEFT, // 2
TOP_RIGHT = TOP + RIGHT, // 3
BOTTOM_LEFT = BOTTOM + LEFT, // 4
BOTTOM_RIGHT = BOTTOM + RIGHT, // 5
LEFT_EDGE = CENTER + LEFT, // 6
RIGHT_EDGE = CENTER + RIGHT, // 7
TOP_EDGE = TOP + CENTER, // 8
BOTTOM_EDGE = BOTTOM + CENTER, // 10
MIDDLE = CENTER + CENTER, // 12
};
static FORCE_INLINE Position GetPosition(int x, int y, int width, int height) {
Position xpos = CENTER;
Position ypos = CENTER;
if (x == 0) {
xpos = LEFT;
} else if (x == width - 1) {
xpos = RIGHT;
}
if (y == 0) {
ypos = TOP;
} else if (y == height - 1) {
ypos = BOTTOM;
}
return static_cast<Position>(xpos + ypos);
}
static FORCE_INLINE bool IsRedBlue(uint8 colour) {
return colour <= BLUE;
}
static FORCE_INLINE uint32 FourCcToBayerPixelColourMap(uint32 fourcc) {
// The colour map is a 4-byte array-as-uint32 containing the colours for the
// four pixels in each 2x2 grid, in left-to-right and top-to-bottom order.
switch (fourcc) {
default:
ASSERT(false);
case FOURCC_RGGB:
return FOURCC(RED, GREEN_BETWEEN_RED, GREEN_BETWEEN_BLUE, BLUE);
case FOURCC_BGGR:
return FOURCC(BLUE, GREEN_BETWEEN_BLUE, GREEN_BETWEEN_RED, RED);
case FOURCC_GRBG:
return FOURCC(GREEN_BETWEEN_RED, RED, BLUE, GREEN_BETWEEN_BLUE);
case FOURCC_GBRG:
return FOURCC(GREEN_BETWEEN_BLUE, BLUE, RED, GREEN_BETWEEN_RED);
}
}
static FORCE_INLINE void RGBToYUV(uint8 r, uint8 g, uint8 b,
uint8* y, uint8* u, uint8* v) {
// Taken from http://en.wikipedia.org/wiki/YUV
*y = (( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
*u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
*v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
}
static FORCE_INLINE void InterpolateBayerRGBCorner(uint8* r,
uint8* g,
uint8* b,
const uint8* src,
int src_pitch,
Position pos,
uint8 colour) {
// Compute the offsets to use for fetching the adjacent pixels.
int adjacent_row;
int adjacent_column;
switch (pos) {
case TOP_LEFT:
adjacent_row = src_pitch;
adjacent_column = 1;
break;
case TOP_RIGHT:
adjacent_row = src_pitch;
adjacent_column = -1;
break;
case BOTTOM_LEFT:
adjacent_row = -src_pitch;
adjacent_column = 1;
break;
case BOTTOM_RIGHT:
default:
adjacent_row = -src_pitch;
adjacent_column = -1;
break;
}
// Now interpolate.
if (IsRedBlue(colour)) {
uint8 current_pixel = src[0];
// Average of the adjacent green pixels (there's only two).
*g = (src[adjacent_column] + src[adjacent_row]) / 2;
// Average of the oppositely-coloured corner pixels (there's only one).
uint8 corner_average = src[adjacent_row + adjacent_column];
if (colour == RED) {
*r = current_pixel;
*b = corner_average;
} else { // i.e., BLUE
*b = current_pixel;
*r = corner_average;
}
} else { // i.e., GREEN_BETWEEN_*
*g = src[0];
// Average of the adjacent same-row pixels (there's only one).
uint8 row_average = src[adjacent_column];
// Average of the adjacent same-column pixels (there's only one).
uint8 column_average = src[adjacent_row];
if (colour == GREEN_BETWEEN_RED) {
*r = row_average;
*b = column_average;
} else { // i.e., GREEN_BETWEEN_BLUE
*b = row_average;
*r = column_average;
}
}
}
static FORCE_INLINE void InterpolateBayerRGBEdge(uint8* r,
uint8* g,
uint8* b,
const uint8* src,
int src_pitch,
Position pos,
uint8 colour) {
// Compute the offsets to use for fetching the adjacent pixels.
// Goes one pixel "in" to the image (i.e. towards the center)
int inner;
// Goes one pixel to the side (i.e. along the edge) in either the clockwise or
// counter-clockwise direction, and its negative value goes in the other
// direction.
int side;
switch (pos) {
case TOP_EDGE:
inner = src_pitch;
side = 1;
break;
case RIGHT_EDGE:
inner = -1;
side = src_pitch;
break;
case BOTTOM_EDGE:
inner = -src_pitch;
side = 1;
break;
case LEFT_EDGE:
default:
inner = 1;
side = src_pitch;
break;
}
// Now interpolate.
if (IsRedBlue(colour)) {
uint8 current_pixel = src[0];
// Average of the adjacent green pixels (there's only three).
*g = (src[inner] + src[side] + src[-side]) / 3;
// Average of the oppositely-coloured corner pixels (there's only two).
uint8 corner_average = (src[inner + side] + src[inner - side]) / 2;
if (colour == RED) {
*r = current_pixel;
*b = corner_average;
} else { // i.e., BLUE
*b = current_pixel;
*r = corner_average;
}
} else { // i.e., GREEN_BETWEEN_*
*g = src[0];
// Average of the adjacent side-ways pixels (there's only two).
uint8 side_average = (src[side] + src[-side]) / 2;
// Average of the adjacent inner-ways pixels (there's only one).
uint8 inner_pixel = src[inner];
// Including && side == 1 effectively transposes the colour logic for
// processing the left/right sides, which is needed since the "T" shape
// formed by the pixels is transposed.
if (colour == GREEN_BETWEEN_RED && side == 1) {
*r = side_average;
*b = inner_pixel;
} else { // i.e., GREEN_BETWEEN_BLUE || side != 1
*b = side_average;
*r = inner_pixel;
}
}
}
// We inline this one because it runs 99% of the time, so inlining it is
// probably beneficial.
static FORCE_INLINE void InterpolateBayerRGBCenter(uint8* r,
uint8* g,
uint8* b,
const uint8* src,
int src_pitch,
uint8 colour) {
if (IsRedBlue(colour)) {
uint8 current_pixel = src[0];
// Average of the adjacent green pixels (there's four).
// NOTE(tschmelcher): The material at
// http://www.siliconimaging.com/RGB%20Bayer.htm discusses a way to improve
// quality here by using only two of the green pixels based on the
// correlation to the nearby red/blue pixels, but that is slower and would
// result in more edge cases.
*g = (src[1] + src[-1] + src[src_pitch] + src[-src_pitch]) / 4;
// Average of the oppositely-coloured corner pixels (there's four).
uint8 corner_average = (src[src_pitch + 1] +
src[src_pitch - 1] +
src[-src_pitch + 1] +
src[-src_pitch - 1]) / 4;
if (colour == RED) {
*r = current_pixel;
*b = corner_average;
} else { // i.e., BLUE
*b = current_pixel;
*r = corner_average;
}
} else { // i.e., GREEN_BETWEEN_*
*g = src[0];
// Average of the adjacent same-row pixels (there's two).
uint8 row_adjacent = (src[1] + src[-1]) / 2;
// Average of the adjacent same-column pixels (there's two).
uint8 column_adjacent = (src[src_pitch] + src[-src_pitch]) / 2;
if (colour == GREEN_BETWEEN_RED) {
*r = row_adjacent;
*b = column_adjacent;
} else { // i.e., GREEN_BETWEEN_BLUE
*b = row_adjacent;
*r = column_adjacent;
}
}
}
// Converts any Bayer RGB format to I420.
void BayerRGBToI420(const uint8* src, int src_pitch, uint32 src_fourcc,
uint8* y, int y_pitch,
uint8* u, int u_pitch,
uint8* v, int v_pitch,
int width, int height) {
ASSERT(width % 2 == 0);
ASSERT(height % 2 == 0);
uint32 colour_map = FourCcToBayerPixelColourMap(src_fourcc);
int src_row_inc = src_pitch * 2 - width;
int y_row_inc = y_pitch * 2 - width;
int u_row_inc = u_pitch - width / 2;
int v_row_inc = v_pitch - width / 2;
// Iterate over the 2x2 grids.
for (int y1 = 0; y1 < height; y1 += 2) {
for (int x1 = 0; x1 < width; x1 += 2) {
uint32 colours = colour_map;
int total_u = 0;
int total_v = 0;
// Iterate over the four pixels within them.
for (int y2 = 0; y2 < 2; ++y2) {
for (int x2 = 0; x2 < 2; ++x2) {
uint8 r, g, b;
// The low-order byte of the colour map is the current colour.
uint8 current_colour = static_cast<uint8>(colours);
colours >>= 8;
Position pos = GetPosition(x1 + x2, y1 + y2, width, height);
const uint8* src_pixel = &src[y2 * src_pitch + x2];
uint8* y_pixel = &y[y2 * y_pitch + x2];
// Convert from Bayer RGB to regular RGB.
if (pos == MIDDLE) {
// 99% of the image is the middle.
InterpolateBayerRGBCenter(&r, &g, &b,
src_pixel, src_pitch,
current_colour);
} else if (pos >= LEFT_EDGE) {
// Next most frequent is edges.
InterpolateBayerRGBEdge(&r, &g, &b,
src_pixel, src_pitch, pos,
current_colour);
} else {
// Last is the corners. There are only 4.
InterpolateBayerRGBCorner(&r, &g, &b,
src_pixel, src_pitch, pos,
current_colour);
}
// Convert from RGB to YUV.
uint8 tmp_u, tmp_v;
RGBToYUV(r, g, b, y_pixel, &tmp_u, &tmp_v);
total_u += tmp_u;
total_v += tmp_v;
}
}
src += 2;
y += 2;
*u = total_u / 4;
*v = total_v / 4;
++u;
++v;
}
src += src_row_inc;
y += y_row_inc;
u += u_row_inc;
v += v_row_inc;
}
}
// Note: to do this with Neon vld4.8 would load ARGB values into 4 registers
// and vst would select which 2 components to write. The low level would need
// to be ARGBToBG, ARGBToGB, ARGBToRG, ARGBToGR
#if defined(WIN32) && !defined(COVERAGE_ENABLED)
#define HAS_ARGBTOBAYERROW_SSSE3
__declspec(naked)
static void ARGBToBayerRow_SSSE3(const uint8* src_argb,
uint8* dst_bayer, uint32 selector, int pix) {
__asm {
mov eax, [esp + 4] // src_argb
mov edx, [esp + 8] // dst_bayer
movd xmm0, [esp + 12] // selector
mov ecx, [esp + 16] // pix
pshufd xmm0, xmm0, 0
wloop:
movdqa xmm1, [eax]
lea eax, [eax + 16]
pshufb xmm1, xmm0
movd [edx], xmm1
lea edx, [edx + 4]
sub ecx, 4
ja wloop
ret
}
}
#elif defined(__i386__) && !defined(COVERAGE_ENABLED) && \
!TARGET_IPHONE_SIMULATOR
#define HAS_ARGBTOBAYERROW_SSSE3
extern "C" void ARGBToBayerRow_SSSE3(const uint8* src_argb, uint8* dst_bayer,
uint32 selector, int pix);
asm(
".text\n"
#if defined(OSX)
".globl _ARGBToBayerRow_SSSE3\n"
"_ARGBToBayerRow_SSSE3:\n"
#else
".global ARGBToBayerRow_SSSE3\n"
"ARGBToBayerRow_SSSE3:\n"
#endif
"mov 0x4(%esp),%eax\n"
"mov 0x8(%esp),%edx\n"
"movd 0xc(%esp),%xmm0\n"
"mov 0x10(%esp),%ecx\n"
"pshufd $0x0,%xmm0,%xmm0\n"
"1:"
"movdqa (%eax),%xmm1\n"
"lea 0x10(%eax),%eax\n"
"pshufb %xmm0,%xmm1\n"
"movd %xmm1,(%edx)\n"
"lea 0x4(%edx),%edx\n"
"sub $0x4,%ecx\n"
"ja 1b\n"
"ret\n"
);
#endif
static void ARGBToBayerRow_C(const uint8* src_argb,
uint8* dst_bayer, uint32 selector, int pix) {
int index0 = selector & 0xff;
int index1 = (selector >> 8) & 0xff;
// Copy a row of Bayer.
for (int x = 0; x < pix; x += 2) {
dst_bayer[0] = src_argb[index0];
dst_bayer[1] = src_argb[index1];
src_argb += 8;
dst_bayer += 2;
}
}
// generate a selector mask useful for pshufb
static uint32 GenerateSelector(int select0, int select1) {
return static_cast<uint32>(select0) |
static_cast<uint32>((select1 + 4) << 8) |
static_cast<uint32>((select0 + 8) << 16) |
static_cast<uint32>((select1 + 12) << 24);
}
// Converts any 32 bit ARGB to any Bayer RGB format.
void RGB32ToBayerRGB(const uint8* src_rgb, int src_pitch_rgb,
uint32 src_fourcc_rgb,
uint8* dst_bayer, int dst_pitch_bayer,
uint32 dst_fourcc_bayer,
int width, int height) {
ASSERT(width % 2 == 0);
void (*ARGBToBayerRow)(const uint8* src_argb,
uint8* dst_bayer, uint32 selector, int pix);
#if defined(HAS_ARGBTOBAYERROW_SSSE3)
if (CpuInfo::TestCpuFlag(CpuInfo::kCpuHasSSSE3) &&
(width % 4 == 0) &&
IS_ALIGNED(src_rgb, 16) && (src_pitch_rgb % 16 == 0) &&
IS_ALIGNED(dst_bayer, 4) && (dst_pitch_bayer % 4 == 0)) {
ARGBToBayerRow = ARGBToBayerRow_SSSE3;
} else
#endif
{
ARGBToBayerRow = ARGBToBayerRow_C;
}
ASSERT(src_fourcc_rgb == FOURCC_ARGB);
int blue_index = 0;
int green_index = 1;
int red_index = 2;
// Now build a lookup table containing the indices for the four pixels in each
// 2x2 Bayer grid.
uint32 index_map[2];
switch (dst_fourcc_bayer) {
default:
ASSERT(false);
case FOURCC_RGGB:
index_map[0] = GenerateSelector(red_index, green_index);
index_map[1] = GenerateSelector(green_index, blue_index);
break;
case FOURCC_BGGR:
index_map[0] = GenerateSelector(blue_index, green_index);
index_map[1] = GenerateSelector(green_index, red_index);
break;
case FOURCC_GRBG:
index_map[0] = GenerateSelector(green_index, red_index);
index_map[1] = GenerateSelector(blue_index, green_index);
break;
case FOURCC_GBRG:
index_map[0] = GenerateSelector(green_index, blue_index);
index_map[1] = GenerateSelector(red_index, green_index);
break;
}
// Now convert.
for (int y = 0; y < height; ++y) {
ARGBToBayerRow(src_rgb, dst_bayer, index_map[y & 1], width);
src_rgb += src_pitch_rgb;
dst_bayer += dst_pitch_bayer;
}
}
} // namespace libyuv

338
source/general.cc Normal file
View File

@ -0,0 +1,338 @@
/*
* Copyright (c) 2011 The LibYuv 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 "general.h"
#include <assert.h>
#include <string.h> // memcpy(), memset()
#include "video_common.h"
namespace libyuv {
int
MirrorI420LeftRight( const uint8* src_frame,uint8* dst_frame,
int src_width, int src_height)
{
if (src_width < 1 || src_height < 1)
{
return -1;
}
assert(src_width % 2 == 0 && src_height % 2 == 0);
int indO = 0;
int indS = 0;
int wind, hind;
uint8 tmpVal;
// Will swap two values per iteration
const int halfW = src_width >> 1;
const int halfStride = src_width >> 1;
// Y
for (wind = 0; wind < halfW; wind++ )
{
for (hind = 0; hind < src_height; hind++ )
{
indO = hind * src_width + wind;
indS = hind * src_width + (src_width - wind - 1); // swapping index
tmpVal = src_frame[indO];
dst_frame[indO] = src_frame[indS];
dst_frame[indS] = tmpVal;
} // end for (height)
} // end for(width)
const int lengthW = src_width >> 2;
const int lengthH = src_height >> 1;
// V
int zeroInd = src_width * src_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 = src_frame[indO];
dst_frame[indO] = src_frame[indS];
dst_frame[indS] = tmpVal;
} // end for (height)
} // end for(width)
// U
zeroInd += src_width * src_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 = src_frame[indO];
dst_frame[indO] = src_frame[indS];
dst_frame[indS] = tmpVal;
} // end for (height)
} // end for(width)
return 0;
}
// Make a center cut
int
CutI420Frame(uint8* frame,
int fromWidth, int fromHeight,
int toWidth, int 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;
}
int i = 0;
int m = 0;
int loop = 0;
int halfToWidth = toWidth / 2;
int halfToHeight = toHeight / 2;
int halfFromWidth = fromWidth / 2;
int halfFromHeight= fromHeight / 2;
int cutHeight = ( fromHeight - toHeight ) / 2;
int cutWidth = ( fromWidth - toWidth ) / 2;
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;
}
int
CutPadI420Frame(const uint8* inFrame, int inWidth,
int inHeight, uint8* outFrame,
int outWidth, int 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
int padH = outHeight - inHeight;
int i = 0;
int padW = 0;
int cutW = 0;
int 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
int i = 0;
int padW = 0;
int cutW = 0;
int width = inWidth;
if (inWidth < outWidth)
{
// pad width
padW = outWidth - inWidth;
} else
{
// cut width
cutW = inWidth - outWidth;
width = outWidth;
}
int 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);
}
} // nmaespace libyuv

350
source/linux.cc Normal file
View File

@ -0,0 +1,350 @@
/*
* Copyright (c) 2011 The LibYuv 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.
*/
#if defined(LINUX) || defined(ANDROID)
#include "linux.h"
#include <ctype.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <cstdio>
#include <set>
namespace libyuv {
static const char kCpuInfoFile[] = "/proc/cpuinfo";
static const char kCpuMaxFreqFile[] =
"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
ProcCpuInfo::ProcCpuInfo() {
}
ProcCpuInfo::~ProcCpuInfo() {
}
bool ProcCpuInfo::LoadFromSystem() {
ConfigParser procfs;
if (!procfs.Open(kCpuInfoFile)) {
return false;
}
return procfs.Parse(&sections_);
};
bool ProcCpuInfo::GetSectionCount(size_t* count) {
if (sections_.empty()) {
return false;
}
if (count) {
*count = sections_.size();
}
return true;
}
bool ProcCpuInfo::GetNumCpus(int* num) {
if (sections_.empty()) {
return false;
}
int total_cpus = 0;
#if defined(__arm__)
// Count the number of blocks that have a "processor" key defined. On ARM,
// there may be extra blocks of information that aren't per-processor.
size_t section_count = sections_.size();
for (size_t i = 0; i < section_count; ++i) {
int processor_id;
if (GetSectionIntValue(i, "processor", &processor_id)) {
++total_cpus;
}
}
// Single core ARM systems don't include "processor" keys at all, so return
// that we have a single core if we didn't find any explicitly above.
if (total_cpus == 0) {
total_cpus = 1;
}
#else
// On X86, there is exactly one info section per processor.
total_cpus = static_cast<int>(sections_.size());
#endif
if (num) {
*num = total_cpus;
}
return true;
}
bool ProcCpuInfo::GetNumPhysicalCpus(int* num) {
if (sections_.empty()) {
return false;
}
// TODO(noahric): /proc/cpuinfo only reports cores that are currently
// _online_, so this may underreport the number of physical cores.
#if defined(__arm__)
// ARM (currently) has no hyperthreading, so just return the same value
// as GetNumCpus.
return GetNumCpus(num);
#else
int total_cores = 0;
std::set<int> physical_ids;
size_t section_count = sections_.size();
for (size_t i = 0; i < section_count; ++i) {
int physical_id;
int cores;
// Count the cores for the physical id only if we have not counted the id.
if (GetSectionIntValue(i, "physical id", &physical_id) &&
GetSectionIntValue(i, "cpu cores", &cores) &&
physical_ids.find(physical_id) == physical_ids.end()) {
physical_ids.insert(physical_id);
total_cores += cores;
}
}
if (num) {
*num = total_cores;
}
return true;
#endif
}
bool ProcCpuInfo::GetCpuFamily(int* id) {
int cpu_family = 0;
// shh {
#if defined(__arm__)
// On ChromeOS seaboard, there is no 'cpu family' in '/proc/cpuinfo'. But
// there is 'CPU Architecture' which can be used as 'cpu family'.
// See http://en.wikipedia.org/wiki/ARM_architecture for a good list of
// ARM cpu families, architectures, and their mappings.
// There may be multiple sessions that aren't per-processor. We need to scan
// through each session until we find the first 'CPU architecture'.
size_t section_count = sections_.size();
for (size_t i = 0; i < section_count; ++i) {
if (GetSectionIntValue(i, "CPU architecture", &cpu_family)) {
// We returns the first one (if there are multiple entries).
break;
};
}
#else
// shh }
GetSectionIntValue(0, "cpu family", &cpu_family);
// shh {
#endif
// shh }
if (id) {
*id = cpu_family;
}
return true;
}
bool ProcCpuInfo::GetSectionStringValue(size_t section_num,
const std::string& key,
std::string* result) {
if (section_num >= sections_.size()) {
return false;
}
ConfigParser::SimpleMap::iterator iter = sections_[section_num].find(key);
if (iter == sections_[section_num].end()) {
return false;
}
*result = iter->second;
return true;
}
bool ProcCpuInfo::GetSectionIntValue(size_t section_num,
const std::string& key,
int* result) {
if (section_num >= sections_.size()) {
return false;
}
ConfigParser::SimpleMap::iterator iter = sections_[section_num].find(key);
if (iter == sections_[section_num].end()) {
return false;
}
return FromString(iter->second, result);
}
ConfigParser::ConfigParser() {}
ConfigParser::~ConfigParser() {}
bool ConfigParser::Open(const std::string& filename) {
FileStream* fs = new FileStream();
if (!fs->Open(filename, "r", NULL)) {
return false;
}
instream_.reset(fs);
return true;
}
void ConfigParser::Attach(StreamInterface* stream) {
instream_.reset(stream);
}
bool ConfigParser::Parse(MapVector* key_val_pairs) {
// Parses the file and places the found key-value pairs into key_val_pairs.
SimpleMap section;
while (ParseSection(&section)) {
key_val_pairs->push_back(section);
section.clear();
}
return (!key_val_pairs->empty());
}
bool ConfigParser::ParseSection(SimpleMap* key_val_pair) {
// Parses the next section in the filestream and places the found key-value
// pairs into key_val_pair.
std::string key, value;
while (ParseLine(&key, &value)) {
(*key_val_pair)[key] = value;
}
return (!key_val_pair->empty());
}
bool ConfigParser::ParseLine(std::string* key, std::string* value) {
// Parses the next line in the filestream and places the found key-value
// pair into key and val.
std::string line;
if ((instream_->ReadLine(&line)) == EOF) {
return false;
}
std::vector<std::string> tokens;
if (2 != split(line, ':', &tokens)) {
return false;
}
// Removes whitespace at the end of Key name
size_t pos = tokens[0].length() - 1;
while ((pos > 0) && isspace(tokens[0][pos])) {
pos--;
}
tokens[0].erase(pos + 1);
// Removes whitespace at the start of value
pos = 0;
while (pos < tokens[1].length() && isspace(tokens[1][pos])) {
pos++;
}
tokens[1].erase(0, pos);
*key = tokens[0];
*value = tokens[1];
return true;
}
static bool ExpectLineFromStream(FileStream* stream,
std::string* out) {
StreamResult res = stream->ReadLine(out);
if (res != SR_SUCCESS) {
if (res != SR_EOS) {
LOG(LS_ERROR) << "Error when reading from stream";
} else {
LOG(LS_ERROR) << "Incorrect number of lines in stream";
}
return false;
}
return true;
}
static void ExpectEofFromStream(FileStream* stream) {
std::string unused;
StreamResult res = stream->ReadLine(&unused);
if (res == SR_SUCCESS) {
LOG(LS_WARNING) << "Ignoring unexpected extra lines from stream";
} else if (res != SR_EOS) {
LOG(LS_WARNING) << "Error when checking for extra lines from stream";
}
}
// For caching the lsb_release output (reading it invokes a sub-process and
// hence is somewhat expensive).
static std::string lsb_release_string;
static CriticalSection lsb_release_string_critsec;
std::string ReadLinuxLsbRelease() {
CritScope cs(&lsb_release_string_critsec);
if (!lsb_release_string.empty()) {
// Have cached result from previous call.
return lsb_release_string;
}
// No cached result. Run lsb_release and parse output.
POpenStream lsb_release_output;
if (!lsb_release_output.Open("lsb_release -idrcs", "r", NULL)) {
LOG_ERR(LS_ERROR) << "Can't run lsb_release";
return lsb_release_string; // empty
}
// Read in the command's output and build the string.
std::ostringstream sstr;
std::string line;
int wait_status;
if (!ExpectLineFromStream(&lsb_release_output, &line)) {
return lsb_release_string; // empty
}
sstr << "DISTRIB_ID=" << line;
if (!ExpectLineFromStream(&lsb_release_output, &line)) {
return lsb_release_string; // empty
}
sstr << " DISTRIB_DESCRIPTION=\"" << line << '"';
if (!ExpectLineFromStream(&lsb_release_output, &line)) {
return lsb_release_string; // empty
}
sstr << " DISTRIB_RELEASE=" << line;
if (!ExpectLineFromStream(&lsb_release_output, &line)) {
return lsb_release_string; // empty
}
sstr << " DISTRIB_CODENAME=" << line;
// Should not be anything left.
ExpectEofFromStream(&lsb_release_output);
lsb_release_output.Close();
wait_status = lsb_release_output.GetWaitStatus();
if (wait_status == -1 ||
!WIFEXITED(wait_status) ||
WEXITSTATUS(wait_status) != 0) {
LOG(LS_WARNING) << "Unexpected exit status from lsb_release";
}
lsb_release_string = sstr.str();
return lsb_release_string;
}
std::string ReadLinuxUname() {
struct utsname buf;
if (uname(&buf) < 0) {
LOG_ERR(LS_ERROR) << "Can't call uname()";
return std::string();
}
std::ostringstream sstr;
sstr << buf.sysname << " "
<< buf.release << " "
<< buf.version << " "
<< buf.machine;
return sstr.str();
}
int ReadCpuMaxFreq() {
FileStream fs;
std::string str;
int freq = -1;
if (!fs.Open(kCpuMaxFreqFile, "r", NULL) ||
SR_SUCCESS != fs.ReadLine(&str) ||
!FromString(str, &freq)) {
return -1;
}
return freq;
}
} // namespace libyuv
#endif // defined(LINUX) || defined(ANDROID)

118
source/linux.h Normal file
View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2011 The LibYuv 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 LIBYUV_SOURCE_LINUX_H_
#define LIBYUV_SOURCE_LINUX_H_
#if defined(LINUX) || defined(ANDROID)
#include <string>
#include <map>
#include <vector>
namespace libyuv {
//////////////////////////////////////////////////////////////////////////////
// ConfigParser parses a FileStream of an ".ini."-type format into a map.
//////////////////////////////////////////////////////////////////////////////
// Sample Usage:
// ConfigParser parser;
// ConfigParser::MapVector key_val_pairs;
// if (parser.Open(inifile) && parser.Parse(&key_val_pairs)) {
// for (int section_num=0; i < key_val_pairs.size(); ++section_num) {
// std::string val1 = key_val_pairs[section_num][key1];
// std::string val2 = key_val_pairs[section_num][key2];
// // Do something with valn;
// }
// }
class ConfigParser {
public:
typedef std::map<std::string, std::string> SimpleMap;
typedef std::vector<SimpleMap> MapVector;
ConfigParser();
virtual ~ConfigParser();
virtual bool Open(const std::string& filename);
virtual void Attach(StreamInterface* stream);
virtual bool Parse(MapVector* key_val_pairs);
virtual bool ParseSection(SimpleMap* key_val_pair);
virtual bool ParseLine(std::string* key, std::string* value);
private:
scoped_ptr<StreamInterface> instream_;
};
//////////////////////////////////////////////////////////////////////////////
// ProcCpuInfo reads CPU info from the /proc subsystem on any *NIX platform.
//////////////////////////////////////////////////////////////////////////////
// Sample Usage:
// ProcCpuInfo proc_info;
// int no_of_cpu;
// if (proc_info.LoadFromSystem()) {
// std::string out_str;
// proc_info.GetNumCpus(&no_of_cpu);
// proc_info.GetCpuStringValue(0, "vendor_id", &out_str);
// }
// }
class ProcCpuInfo {
public:
ProcCpuInfo();
virtual ~ProcCpuInfo();
// Reads the proc subsystem's cpu info into memory. If this fails, this
// returns false; if it succeeds, it returns true.
virtual bool LoadFromSystem();
// Obtains the number of logical CPU threads and places the value num.
virtual bool GetNumCpus(int* num);
// Obtains the number of physical CPU cores and places the value num.
virtual bool GetNumPhysicalCpus(int* num);
// Obtains the CPU family id.
virtual bool GetCpuFamily(int* id);
// Obtains the number of sections in /proc/cpuinfo, which may be greater
// than the number of CPUs (e.g. on ARM)
virtual bool GetSectionCount(size_t* count);
// Looks for the CPU proc item with the given name for the given section
// number and places the string value in result.
virtual bool GetSectionStringValue(size_t section_num, const std::string& key,
std::string* result);
// Looks for the CPU proc item with the given name for the given section
// number and places the int value in result.
virtual bool GetSectionIntValue(size_t section_num, const std::string& key,
int* result);
private:
ConfigParser::MapVector sections_;
};
// Builds a string containing the info from lsb_release on a single line.
std::string ReadLinuxLsbRelease();
// Returns the output of "uname".
std::string ReadLinuxUname();
// Returns the content (int) of
// /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
// Returns -1 on error.
int ReadCpuMaxFreq();
} // namespace libyuv
#endif // defined(LINUX) || defined(ANDROID)
#endif // LIBYUV_SOURCE_LINUX_H_

341
source/planar_functions.cc Normal file
View File

@ -0,0 +1,341 @@
/*
* Copyright (c) 2011 The LibYuv 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 "planar_functions.h"
#include <string.h>
#include "cpu_id.h"
namespace libyuv {
#if defined(__ARM_NEON__) && !defined(COVERAGE_ENABLED)
#define HAS_SPLITUV_NEON
// Reads 16 pairs of UV and write even values to dst_u and odd to dst_v
// Alignment requirement: 16 bytes for pointers, and multiple of 16 pixels.
static void SplitUV_NEON(const uint8* src_uv,
uint8* dst_u, uint8* dst_v, int pix) {
__asm__ volatile
(
"1:\n"
"vld2.u8 {q0,q1}, [%0]! \n" // load 16 pairs of UV
"vst1.u8 {q0}, [%1]! \n" // store U
"vst1.u8 {q1}, [%2]! \n" // Store V
"subs %3, %3, #16 \n" // 16 processed per loop
"bhi 1b \n"
: // Output registers
: "r"(src_uv), "r"(dst_u), "r"(dst_v), "r"(pix) // Input registers
: "q0", "q1" // Clobber List
);
}
#elif defined(WIN32) && !defined(COVERAGE_ENABLED)
#define HAS_SPLITUV_SSE2
static void SplitUV_SSE2(const uint8* src_uv,
uint8* dst_u, uint8* dst_v, int pix) {
__asm {
mov esi, src_uv
mov edi, dst_u
mov edx, dst_v
mov ecx, pix
mov eax, 0x00ff00ff // mask for isolating low bytes
movd xmm7, eax
pshufd xmm7, xmm7, 0
wloop:
movdqa xmm0, [esi]
movdqa xmm1, [esi + 16]
lea esi, [esi + 32]
movdqa xmm2, xmm0
movdqa xmm3, xmm1
pand xmm0, xmm7 // even bytes
pand xmm1, xmm7
packuswb xmm0, xmm1
movdqa [edi], xmm0
lea edi, [edi + 16]
psrlw xmm2, 8 // odd bytes
psrlw xmm3, 8
packuswb xmm2, xmm3
movdqa [edx], xmm2
lea edx, [edx + 16]
sub ecx, 16
ja wloop
}
}
#elif defined(__i386__) && !defined(COVERAGE_ENABLED) && \
!TARGET_IPHONE_SIMULATOR
// GCC version is same as Visual C
#define HAS_SPLITUV_SSE2
extern "C" void SplitUV_SSE2(const uint8* src_uv,
uint8* dst_u, uint8* dst_v, int pix);
asm(
".text\n"
#if defined(OSX)
".globl _SplitUV_SSE2\n"
"_SplitUV_SSE2:\n"
#else
".global SplitUV_SSE2\n"
"SplitUV_SSE2:\n"
#endif
"push %ebp\n"
"mov %esp,%ebp\n"
"push %esi\n"
"push %edi\n"
"mov 0x8(%ebp),%esi\n"
"mov 0xc(%ebp),%edi\n"
"mov 0x10(%ebp),%edx\n"
"mov 0x14(%ebp),%ecx\n"
"mov $0xff00ff,%eax\n"
"movd %eax,%xmm7\n"
"pshufd $0x0,%xmm7,%xmm7\n"
"1:"
"movdqa (%esi),%xmm0\n"
"movdqa 0x10(%esi),%xmm1\n"
"lea 0x20(%esi),%esi\n"
"movdqa %xmm0,%xmm2\n"
"movdqa %xmm1,%xmm3\n"
"pand %xmm7,%xmm0\n"
"pand %xmm7,%xmm1\n"
"packuswb %xmm1,%xmm0\n"
"movdqa %xmm0,(%edi)\n"
"lea 0x10(%edi),%edi\n"
"psrlw $0x8,%xmm2\n"
"psrlw $0x8,%xmm3\n"
"packuswb %xmm3,%xmm2\n"
"movdqa %xmm2,(%edx)\n"
"lea 0x10(%edx),%edx\n"
"sub $0x10,%ecx\n"
"ja 1b\n"
"pop %edi\n"
"pop %esi\n"
"pop %ebp\n"
"ret\n"
);
#endif
static void SplitUV_C(const uint8* src_uv,
uint8* dst_u, uint8* dst_v, int pix) {
// Copy a row of UV.
for (int x = 0; x < pix; ++x) {
dst_u[0] = src_uv[0];
dst_v[0] = src_uv[1];
src_uv += 2;
dst_u += 1;
dst_v += 1;
}
}
static void I420CopyPlane(const uint8* src_y, int src_pitch_y,
uint8* dst_y, int dst_pitch_y,
int width, int height) {
// Copy plane
for (int y = 0; y < height; ++y) {
memcpy(dst_y, src_y, width);
src_y += src_pitch_y;
dst_y += dst_pitch_y;
}
}
static void I420CopyPlane2(const uint8* src, int src_pitch_0, int src_pitch_1,
uint8* dst, int dst_pitch,
int width, int height) {
// Copy plane
for (int y = 0; y < height; y += 2) {
memcpy(dst, src, width);
src += src_pitch_0;
dst += dst_pitch;
memcpy(dst, src, width);
src += src_pitch_1;
dst += dst_pitch;
}
}
// Support converting from FOURCC_M420
// Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
// easy conversion to I420.
// M420 format description:
// M420 is row biplanar 420: 2 rows of Y and 1 row of VU.
// Chroma is half width / half height. (420)
// pitch_m420 is row planar. Normally this will be the width in pixels.
// The UV plane is half width, but 2 values, so pitch_m420 applies to this
// as well as the two Y planes.
// TODO(fbarchard): Do NV21/NV12 formats with this function
static void X420ToI420(uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
const uint8* src_y,
int src_pitch_y0, int src_pitch_y1,
const uint8* src_uv, int src_pitch_uv,
int width, int height) {
// Negative height means invert the image.
if (height < 0) {
height = -height;
dst_y = dst_y + (height - 1) * dst_pitch_y;
dst_u = dst_u + (height - 1) * dst_pitch_u;
dst_v = dst_v + (height - 1) * dst_pitch_v;
dst_pitch_y = -dst_pitch_y;
dst_pitch_u = -dst_pitch_u;
dst_pitch_v = -dst_pitch_v;
}
int halfwidth = (width + 1) >> 1;
void (*SplitUV)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix);
#if defined(HAS_SPLITUV_NEON)
if (libyuv::CpuInfo::TestCpuFlag(libyuv::CpuInfo::kCpuHasNEON) &&
(halfwidth % 16 == 0) &&
IS_ALIGNED(src_uv, 16) && (src_pitch_uv % 16 == 0) &&
IS_ALIGNED(dst_u, 16) && (dst_pitch_u % 16 == 0) &&
IS_ALIGNED(dst_v, 16) && (dst_pitch_v % 16 == 0)) {
SplitUV = SplitUV_NEON;
} else
#elif defined(HAS_SPLITUV_SSE2)
if (libyuv::CpuInfo::TestCpuFlag(libyuv::CpuInfo::kCpuHasSSE2) &&
(halfwidth % 16 == 0) &&
IS_ALIGNED(src_uv, 16) && (src_pitch_uv % 16 == 0) &&
IS_ALIGNED(dst_u, 16) && (dst_pitch_u % 16 == 0) &&
IS_ALIGNED(dst_v, 16) && (dst_pitch_v % 16 == 0)) {
SplitUV = SplitUV_SSE2;
} else
#endif
{
SplitUV = SplitUV_C;
}
I420CopyPlane2(src_y, src_pitch_y0, src_pitch_y1, dst_y, dst_pitch_y,
width, height);
int halfheight = (height + 1) >> 1;
for (int y = 0; y < halfheight; ++y) {
// Copy a row of UV.
SplitUV(src_uv, dst_u, dst_v, halfwidth);
dst_u += dst_pitch_u;
dst_v += dst_pitch_v;
src_uv += src_pitch_uv;
}
}
// TODO(fbarchard): For biplanar formats (ie NV21), the Y plane is the same
// as I420, and only the chroma plane varies. Copy the Y plane by reference,
// and just convert the UV. This method can be used for NV21, NV12, I420,
// I422, M422. 8 of the 12 bits is Y, so this would copy 3 times less data,
// which is approximately how much faster it would be.
// Helper function to copy yuv data without scaling. Used
// by our jpeg conversion callbacks to incrementally fill a yuv image.
void PlanarFunctions::I420Copy(const uint8* src_y, int src_pitch_y,
const uint8* src_u, int src_pitch_u,
const uint8* src_v, int src_pitch_v,
uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
int width, int height) {
// Negative height means invert the image.
if (height < 0) {
height = -height;
src_y = src_y + (height - 1) * src_pitch_y;
src_u = src_u + (height - 1) * src_pitch_u;
src_v = src_v + (height - 1) * src_pitch_v;
src_pitch_y = -src_pitch_y;
src_pitch_u = -src_pitch_u;
src_pitch_v = -src_pitch_v;
}
int halfwidth = (width + 1) >> 1;
int halfheight = (height + 1) >> 1;
I420CopyPlane(src_y, src_pitch_y, dst_y, dst_pitch_y, width, height);
I420CopyPlane(src_u, src_pitch_u, dst_u, dst_pitch_u, halfwidth, halfheight);
I420CopyPlane(src_v, src_pitch_v, dst_v, dst_pitch_v, halfwidth, halfheight);
}
// Helper function to copy yuv data without scaling. Used
// by our jpeg conversion callbacks to incrementally fill a yuv image.
void PlanarFunctions::I422ToI420(const uint8* src_y, int src_pitch_y,
const uint8* src_u, int src_pitch_u,
const uint8* src_v, int src_pitch_v,
uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
int width, int height) {
// Negative height means invert the image.
if (height < 0) {
height = -height;
src_y = src_y + (height - 1) * src_pitch_y;
src_u = src_u + (height - 1) * src_pitch_u;
src_v = src_v + (height - 1) * src_pitch_v;
src_pitch_y = -src_pitch_y;
src_pitch_u = -src_pitch_u;
src_pitch_v = -src_pitch_v;
}
// Copy Y plane
I420CopyPlane(src_y, src_pitch_y, dst_y, dst_pitch_y, width, height);
// SubSample UV planes.
int x, y;
int halfwidth = (width + 1) >> 1;
for (y = 0; y < height; y += 2) {
const uint8* u0 = src_u;
const uint8* u1 = src_u + src_pitch_u;
if ((y + 1) >= height) {
u1 = u0;
}
for (x = 0; x < halfwidth; ++x) {
dst_u[x] = (u0[x] + u1[x] + 1) >> 1;
}
src_u += src_pitch_u * 2;
dst_u += dst_pitch_u;
}
for (y = 0; y < height; y += 2) {
const uint8* v0 = src_v;
const uint8* v1 = src_v + src_pitch_v;
if ((y + 1) >= height) {
v1 = v0;
}
for (x = 0; x < halfwidth; ++x) {
dst_v[x] = (v0[x] + v1[x] + 1) >> 1;
}
src_v += src_pitch_v * 2;
dst_v += dst_pitch_v;
}
}
// Convert M420 to I420.
void PlanarFunctions::M420ToI420(uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
const uint8* m420, int pitch_m420,
int width, int height) {
X420ToI420(dst_y, dst_pitch_y, dst_u, dst_pitch_u, dst_v, dst_pitch_v,
m420, pitch_m420, pitch_m420 * 2,
m420 + pitch_m420 * 2, pitch_m420 * 3,
width, height);
}
// Convert NV12 to I420.
void PlanarFunctions::NV12ToI420(uint8* dst_y, int dst_pitch_y,
uint8* dst_u, int dst_pitch_u,
uint8* dst_v, int dst_pitch_v,
const uint8* src_y,
const uint8* src_uv,
int src_pitch,
int width, int height) {
X420ToI420(dst_y, dst_pitch_y, dst_u, dst_pitch_u, dst_v, dst_pitch_v,
src_y, src_pitch, src_pitch,
src_uv, src_pitch,
width, height);
}
} // namespace libyuv

73
source/row.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2011 The LibYuv 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 LIBYUV_SOURCE_ROW_H_
#define LIBYUV_SOURCE_ROW_H_
#include "basic_types.h"
extern "C" {
// Can only do 1x.
// This is the second fastest of the scalers.
void FastConvertYUVToRGB32Row(const uint8* y_buf,
const uint8* u_buf,
const uint8* v_buf,
uint8* rgb_buf,
int width);
#if defined(_MSC_VER)
#define SIMD_ALIGNED(var) __declspec(align(16)) var
#else
#define SIMD_ALIGNED(var) var __attribute__((aligned(16)))
#endif
#ifdef OSX
extern SIMD_ALIGNED(const int16 kCoefficientsRgbY[768][4]);
#else
extern SIMD_ALIGNED(const int16 _kCoefficientsRgbY[768][4]);
#endif
// Method to force C version.
//#define USE_MMX 0
//#define USE_SSE2 0
#if !defined(USE_MMX)
// Windows, Mac and Linux use MMX
#if defined(__i386__) || defined(_MSC_VER)
#define USE_MMX 1
#else
#define USE_MMX 0
#endif
#endif
#if !defined(USE_SSE2)
#if defined(__SSE2__) || defined(ARCH_CPU_X86_64) || _M_IX86_FP==2
#define USE_SSE2 1
#else
#define USE_SSE2 0
#endif
#endif
// x64 uses MMX2 (SSE) so emms is not required.
// Warning C4799: function has no EMMS instruction.
// EMMS() is slow and should be called by the calling function once per image.
#if USE_MMX && !defined(ARCH_CPU_X86_64)
#if defined(_MSC_VER)
#define EMMS() __asm emms
#pragma warning(disable: 4799)
#else
#define EMMS() asm("emms")
#endif
#else
#define EMMS()
#endif
} // extern "C"
#endif // LIBYUV_SOURCE_ROW_H_

163
source/row_posix.cc Normal file
View File

@ -0,0 +1,163 @@
/*
* Copyright (c) 2011 The LibYuv 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 "row.h"
extern "C" {
#if defined(__x86_64__)
// 64 bit linux gcc version
void FastConvertYUVToRGB32Row(const uint8* y_buf, // rdi
const uint8* u_buf, // rsi
const uint8* v_buf, // rdx
uint8* rgb_buf, // rcx
int width) { // r8
asm(
"1:"
"movzb (%1),%%r10\n"
"lea 1(%1),%1\n"
"movzb (%2),%%r11\n"
"lea 1(%2),%2\n"
"movq 2048(%5,%%r10,8),%%xmm0\n"
"movzb (%0),%%r10\n"
"movq 4096(%5,%%r11,8),%%xmm1\n"
"movzb 0x1(%0),%%r11\n"
"paddsw %%xmm1,%%xmm0\n"
"movq (%5,%%r10,8),%%xmm2\n"
"lea 2(%0),%0\n"
"movq (%5,%%r11,8),%%xmm3\n"
"paddsw %%xmm0,%%xmm2\n"
"paddsw %%xmm0,%%xmm3\n"
"shufps $0x44,%%xmm3,%%xmm2\n"
"psraw $0x6,%%xmm2\n"
"packuswb %%xmm2,%%xmm2\n"
"movq %%xmm2,0x0(%3)\n"
"lea 8(%3),%3\n"
"sub $0x2,%4\n"
"ja 1b\n"
:
: "r"(y_buf), // %0
"r"(u_buf), // %1
"r"(v_buf), // %2
"r"(rgb_buf), // %3
"r"(width), // %4
"r" (_kCoefficientsRgbY) // %5
: "memory", "r10", "r11", "xmm0", "xmm1", "xmm2", "xmm3"
);
}
#elif defined(__i386__)
// 32 bit gcc version
void FastConvertYUVToRGB32Row(const uint8* y_buf,
const uint8* u_buf,
const uint8* v_buf,
uint8* rgb_buf,
int width);
asm(
".text\n"
#if defined(OSX) || defined(IOS)
".globl _FastConvertYUVToRGB32Row\n"
"_FastConvertYUVToRGB32Row:\n"
#else
".global FastConvertYUVToRGB32Row\n"
"FastConvertYUVToRGB32Row:\n"
#endif
"pusha\n"
"mov 0x24(%esp),%edx\n"
"mov 0x28(%esp),%edi\n"
"mov 0x2c(%esp),%esi\n"
"mov 0x30(%esp),%ebp\n"
"mov 0x34(%esp),%ecx\n"
"1:"
"movzbl (%edi),%eax\n"
"lea 1(%edi),%edi\n"
"movzbl (%esi),%ebx\n"
"lea 1(%esi),%esi\n"
"movq _kCoefficientsRgbY+2048(,%eax,8),%mm0\n"
"movzbl (%edx),%eax\n"
"paddsw _kCoefficientsRgbY+4096(,%ebx,8),%mm0\n"
"movzbl 0x1(%edx),%ebx\n"
"movq _kCoefficientsRgbY(,%eax,8),%mm1\n"
"lea 2(%edx),%edx\n"
"movq _kCoefficientsRgbY(,%ebx,8),%mm2\n"
"paddsw %mm0,%mm1\n"
"paddsw %mm0,%mm2\n"
"psraw $0x6,%mm1\n"
"psraw $0x6,%mm2\n"
"packuswb %mm2,%mm1\n"
"movntq %mm1,0x0(%ebp)\n"
"lea 8(%ebp),%ebp\n"
"sub $0x2,%ecx\n"
"ja 1b\n"
"popa\n"
"ret\n"
);
#else
// C reference code that mimic the YUV assembly.
#define packuswb(x) ((x) < 0 ? 0 : ((x) > 255 ? 255 : (x)))
#define paddsw(x, y) (((x) + (y)) < -32768 ? -32768 : \
(((x) + (y)) > 32767 ? 32767 : ((x) + (y))))
static inline void YuvPixel(uint8 y,
uint8 u,
uint8 v,
uint8* rgb_buf) {
int b = _kCoefficientsRgbY[256+u][0];
int g = _kCoefficientsRgbY[256+u][1];
int r = _kCoefficientsRgbY[256+u][2];
int a = _kCoefficientsRgbY[256+u][3];
b = paddsw(b, _kCoefficientsRgbY[512+v][0]);
g = paddsw(g, _kCoefficientsRgbY[512+v][1]);
r = paddsw(r, _kCoefficientsRgbY[512+v][2]);
a = paddsw(a, _kCoefficientsRgbY[512+v][3]);
b = paddsw(b, _kCoefficientsRgbY[y][0]);
g = paddsw(g, _kCoefficientsRgbY[y][1]);
r = paddsw(r, _kCoefficientsRgbY[y][2]);
a = paddsw(a, _kCoefficientsRgbY[y][3]);
b >>= 6;
g >>= 6;
r >>= 6;
a >>= 6;
*reinterpret_cast<uint32*>(rgb_buf) = (packuswb(b)) |
(packuswb(g) << 8) |
(packuswb(r) << 16) |
(packuswb(a) << 24);
}
void FastConvertYUVToRGB32Row(const uint8* y_buf,
const uint8* u_buf,
const uint8* v_buf,
uint8* rgb_buf,
int width) {
for (int x = 0; x < width; x += 2) {
uint8 u = u_buf[x >> 1];
uint8 v = v_buf[x >> 1];
uint8 y0 = y_buf[x];
YuvPixel(y0, u, v, rgb_buf);
if ((x + 1) < width) {
uint8 y1 = y_buf[x + 1];
YuvPixel(y1, u, v, rgb_buf + 4);
}
rgb_buf += 8; // Advance 2 pixels.
}
}
#endif
} // extern "C"

245
source/row_table.cc Normal file
View File

@ -0,0 +1,245 @@
/*
* Copyright (c) 2011 The LibYuv 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 "row.h"
extern "C" {
#define RGBY(i) { \
static_cast<int16>(1.164 * 64 * (i - 16) + 0.5), \
static_cast<int16>(1.164 * 64 * (i - 16) + 0.5), \
static_cast<int16>(1.164 * 64 * (i - 16) + 0.5), \
0 \
}
#define RGBU(i) { \
static_cast<int16>(2.018 * 64 * (i - 128) + 0.5), \
static_cast<int16>(-0.391 * 64 * (i - 128) + 0.5), \
0, \
static_cast<int16>(256 * 64 - 1) \
}
#define RGBV(i) { \
0, \
static_cast<int16>(-0.813 * 64 * (i - 128) + 0.5), \
static_cast<int16>(1.596 * 64 * (i - 128) + 0.5), \
0 \
}
#ifdef OSX
SIMD_ALIGNED(const int16 kCoefficientsRgbY[256 * 3][4]) = {
#else
SIMD_ALIGNED(const int16 _kCoefficientsRgbY[256 * 3][4]) = {
#endif
// Luminance table.
RGBY(0x00), RGBY(0x01), RGBY(0x02), RGBY(0x03),
RGBY(0x04), RGBY(0x05), RGBY(0x06), RGBY(0x07),
RGBY(0x08), RGBY(0x09), RGBY(0x0A), RGBY(0x0B),
RGBY(0x0C), RGBY(0x0D), RGBY(0x0E), RGBY(0x0F),
RGBY(0x10), RGBY(0x11), RGBY(0x12), RGBY(0x13),
RGBY(0x14), RGBY(0x15), RGBY(0x16), RGBY(0x17),
RGBY(0x18), RGBY(0x19), RGBY(0x1A), RGBY(0x1B),
RGBY(0x1C), RGBY(0x1D), RGBY(0x1E), RGBY(0x1F),
RGBY(0x20), RGBY(0x21), RGBY(0x22), RGBY(0x23),
RGBY(0x24), RGBY(0x25), RGBY(0x26), RGBY(0x27),
RGBY(0x28), RGBY(0x29), RGBY(0x2A), RGBY(0x2B),
RGBY(0x2C), RGBY(0x2D), RGBY(0x2E), RGBY(0x2F),
RGBY(0x30), RGBY(0x31), RGBY(0x32), RGBY(0x33),
RGBY(0x34), RGBY(0x35), RGBY(0x36), RGBY(0x37),
RGBY(0x38), RGBY(0x39), RGBY(0x3A), RGBY(0x3B),
RGBY(0x3C), RGBY(0x3D), RGBY(0x3E), RGBY(0x3F),
RGBY(0x40), RGBY(0x41), RGBY(0x42), RGBY(0x43),
RGBY(0x44), RGBY(0x45), RGBY(0x46), RGBY(0x47),
RGBY(0x48), RGBY(0x49), RGBY(0x4A), RGBY(0x4B),
RGBY(0x4C), RGBY(0x4D), RGBY(0x4E), RGBY(0x4F),
RGBY(0x50), RGBY(0x51), RGBY(0x52), RGBY(0x53),
RGBY(0x54), RGBY(0x55), RGBY(0x56), RGBY(0x57),
RGBY(0x58), RGBY(0x59), RGBY(0x5A), RGBY(0x5B),
RGBY(0x5C), RGBY(0x5D), RGBY(0x5E), RGBY(0x5F),
RGBY(0x60), RGBY(0x61), RGBY(0x62), RGBY(0x63),
RGBY(0x64), RGBY(0x65), RGBY(0x66), RGBY(0x67),
RGBY(0x68), RGBY(0x69), RGBY(0x6A), RGBY(0x6B),
RGBY(0x6C), RGBY(0x6D), RGBY(0x6E), RGBY(0x6F),
RGBY(0x70), RGBY(0x71), RGBY(0x72), RGBY(0x73),
RGBY(0x74), RGBY(0x75), RGBY(0x76), RGBY(0x77),
RGBY(0x78), RGBY(0x79), RGBY(0x7A), RGBY(0x7B),
RGBY(0x7C), RGBY(0x7D), RGBY(0x7E), RGBY(0x7F),
RGBY(0x80), RGBY(0x81), RGBY(0x82), RGBY(0x83),
RGBY(0x84), RGBY(0x85), RGBY(0x86), RGBY(0x87),
RGBY(0x88), RGBY(0x89), RGBY(0x8A), RGBY(0x8B),
RGBY(0x8C), RGBY(0x8D), RGBY(0x8E), RGBY(0x8F),
RGBY(0x90), RGBY(0x91), RGBY(0x92), RGBY(0x93),
RGBY(0x94), RGBY(0x95), RGBY(0x96), RGBY(0x97),
RGBY(0x98), RGBY(0x99), RGBY(0x9A), RGBY(0x9B),
RGBY(0x9C), RGBY(0x9D), RGBY(0x9E), RGBY(0x9F),
RGBY(0xA0), RGBY(0xA1), RGBY(0xA2), RGBY(0xA3),
RGBY(0xA4), RGBY(0xA5), RGBY(0xA6), RGBY(0xA7),
RGBY(0xA8), RGBY(0xA9), RGBY(0xAA), RGBY(0xAB),
RGBY(0xAC), RGBY(0xAD), RGBY(0xAE), RGBY(0xAF),
RGBY(0xB0), RGBY(0xB1), RGBY(0xB2), RGBY(0xB3),
RGBY(0xB4), RGBY(0xB5), RGBY(0xB6), RGBY(0xB7),
RGBY(0xB8), RGBY(0xB9), RGBY(0xBA), RGBY(0xBB),
RGBY(0xBC), RGBY(0xBD), RGBY(0xBE), RGBY(0xBF),
RGBY(0xC0), RGBY(0xC1), RGBY(0xC2), RGBY(0xC3),
RGBY(0xC4), RGBY(0xC5), RGBY(0xC6), RGBY(0xC7),
RGBY(0xC8), RGBY(0xC9), RGBY(0xCA), RGBY(0xCB),
RGBY(0xCC), RGBY(0xCD), RGBY(0xCE), RGBY(0xCF),
RGBY(0xD0), RGBY(0xD1), RGBY(0xD2), RGBY(0xD3),
RGBY(0xD4), RGBY(0xD5), RGBY(0xD6), RGBY(0xD7),
RGBY(0xD8), RGBY(0xD9), RGBY(0xDA), RGBY(0xDB),
RGBY(0xDC), RGBY(0xDD), RGBY(0xDE), RGBY(0xDF),
RGBY(0xE0), RGBY(0xE1), RGBY(0xE2), RGBY(0xE3),
RGBY(0xE4), RGBY(0xE5), RGBY(0xE6), RGBY(0xE7),
RGBY(0xE8), RGBY(0xE9), RGBY(0xEA), RGBY(0xEB),
RGBY(0xEC), RGBY(0xED), RGBY(0xEE), RGBY(0xEF),
RGBY(0xF0), RGBY(0xF1), RGBY(0xF2), RGBY(0xF3),
RGBY(0xF4), RGBY(0xF5), RGBY(0xF6), RGBY(0xF7),
RGBY(0xF8), RGBY(0xF9), RGBY(0xFA), RGBY(0xFB),
RGBY(0xFC), RGBY(0xFD), RGBY(0xFE), RGBY(0xFF),
// Chroma U table.
RGBU(0x00), RGBU(0x01), RGBU(0x02), RGBU(0x03),
RGBU(0x04), RGBU(0x05), RGBU(0x06), RGBU(0x07),
RGBU(0x08), RGBU(0x09), RGBU(0x0A), RGBU(0x0B),
RGBU(0x0C), RGBU(0x0D), RGBU(0x0E), RGBU(0x0F),
RGBU(0x10), RGBU(0x11), RGBU(0x12), RGBU(0x13),
RGBU(0x14), RGBU(0x15), RGBU(0x16), RGBU(0x17),
RGBU(0x18), RGBU(0x19), RGBU(0x1A), RGBU(0x1B),
RGBU(0x1C), RGBU(0x1D), RGBU(0x1E), RGBU(0x1F),
RGBU(0x20), RGBU(0x21), RGBU(0x22), RGBU(0x23),
RGBU(0x24), RGBU(0x25), RGBU(0x26), RGBU(0x27),
RGBU(0x28), RGBU(0x29), RGBU(0x2A), RGBU(0x2B),
RGBU(0x2C), RGBU(0x2D), RGBU(0x2E), RGBU(0x2F),
RGBU(0x30), RGBU(0x31), RGBU(0x32), RGBU(0x33),
RGBU(0x34), RGBU(0x35), RGBU(0x36), RGBU(0x37),
RGBU(0x38), RGBU(0x39), RGBU(0x3A), RGBU(0x3B),
RGBU(0x3C), RGBU(0x3D), RGBU(0x3E), RGBU(0x3F),
RGBU(0x40), RGBU(0x41), RGBU(0x42), RGBU(0x43),
RGBU(0x44), RGBU(0x45), RGBU(0x46), RGBU(0x47),
RGBU(0x48), RGBU(0x49), RGBU(0x4A), RGBU(0x4B),
RGBU(0x4C), RGBU(0x4D), RGBU(0x4E), RGBU(0x4F),
RGBU(0x50), RGBU(0x51), RGBU(0x52), RGBU(0x53),
RGBU(0x54), RGBU(0x55), RGBU(0x56), RGBU(0x57),
RGBU(0x58), RGBU(0x59), RGBU(0x5A), RGBU(0x5B),
RGBU(0x5C), RGBU(0x5D), RGBU(0x5E), RGBU(0x5F),
RGBU(0x60), RGBU(0x61), RGBU(0x62), RGBU(0x63),
RGBU(0x64), RGBU(0x65), RGBU(0x66), RGBU(0x67),
RGBU(0x68), RGBU(0x69), RGBU(0x6A), RGBU(0x6B),
RGBU(0x6C), RGBU(0x6D), RGBU(0x6E), RGBU(0x6F),
RGBU(0x70), RGBU(0x71), RGBU(0x72), RGBU(0x73),
RGBU(0x74), RGBU(0x75), RGBU(0x76), RGBU(0x77),
RGBU(0x78), RGBU(0x79), RGBU(0x7A), RGBU(0x7B),
RGBU(0x7C), RGBU(0x7D), RGBU(0x7E), RGBU(0x7F),
RGBU(0x80), RGBU(0x81), RGBU(0x82), RGBU(0x83),
RGBU(0x84), RGBU(0x85), RGBU(0x86), RGBU(0x87),
RGBU(0x88), RGBU(0x89), RGBU(0x8A), RGBU(0x8B),
RGBU(0x8C), RGBU(0x8D), RGBU(0x8E), RGBU(0x8F),
RGBU(0x90), RGBU(0x91), RGBU(0x92), RGBU(0x93),
RGBU(0x94), RGBU(0x95), RGBU(0x96), RGBU(0x97),
RGBU(0x98), RGBU(0x99), RGBU(0x9A), RGBU(0x9B),
RGBU(0x9C), RGBU(0x9D), RGBU(0x9E), RGBU(0x9F),
RGBU(0xA0), RGBU(0xA1), RGBU(0xA2), RGBU(0xA3),
RGBU(0xA4), RGBU(0xA5), RGBU(0xA6), RGBU(0xA7),
RGBU(0xA8), RGBU(0xA9), RGBU(0xAA), RGBU(0xAB),
RGBU(0xAC), RGBU(0xAD), RGBU(0xAE), RGBU(0xAF),
RGBU(0xB0), RGBU(0xB1), RGBU(0xB2), RGBU(0xB3),
RGBU(0xB4), RGBU(0xB5), RGBU(0xB6), RGBU(0xB7),
RGBU(0xB8), RGBU(0xB9), RGBU(0xBA), RGBU(0xBB),
RGBU(0xBC), RGBU(0xBD), RGBU(0xBE), RGBU(0xBF),
RGBU(0xC0), RGBU(0xC1), RGBU(0xC2), RGBU(0xC3),
RGBU(0xC4), RGBU(0xC5), RGBU(0xC6), RGBU(0xC7),
RGBU(0xC8), RGBU(0xC9), RGBU(0xCA), RGBU(0xCB),
RGBU(0xCC), RGBU(0xCD), RGBU(0xCE), RGBU(0xCF),
RGBU(0xD0), RGBU(0xD1), RGBU(0xD2), RGBU(0xD3),
RGBU(0xD4), RGBU(0xD5), RGBU(0xD6), RGBU(0xD7),
RGBU(0xD8), RGBU(0xD9), RGBU(0xDA), RGBU(0xDB),
RGBU(0xDC), RGBU(0xDD), RGBU(0xDE), RGBU(0xDF),
RGBU(0xE0), RGBU(0xE1), RGBU(0xE2), RGBU(0xE3),
RGBU(0xE4), RGBU(0xE5), RGBU(0xE6), RGBU(0xE7),
RGBU(0xE8), RGBU(0xE9), RGBU(0xEA), RGBU(0xEB),
RGBU(0xEC), RGBU(0xED), RGBU(0xEE), RGBU(0xEF),
RGBU(0xF0), RGBU(0xF1), RGBU(0xF2), RGBU(0xF3),
RGBU(0xF4), RGBU(0xF5), RGBU(0xF6), RGBU(0xF7),
RGBU(0xF8), RGBU(0xF9), RGBU(0xFA), RGBU(0xFB),
RGBU(0xFC), RGBU(0xFD), RGBU(0xFE), RGBU(0xFF),
// Chroma V table.
RGBV(0x00), RGBV(0x01), RGBV(0x02), RGBV(0x03),
RGBV(0x04), RGBV(0x05), RGBV(0x06), RGBV(0x07),
RGBV(0x08), RGBV(0x09), RGBV(0x0A), RGBV(0x0B),
RGBV(0x0C), RGBV(0x0D), RGBV(0x0E), RGBV(0x0F),
RGBV(0x10), RGBV(0x11), RGBV(0x12), RGBV(0x13),
RGBV(0x14), RGBV(0x15), RGBV(0x16), RGBV(0x17),
RGBV(0x18), RGBV(0x19), RGBV(0x1A), RGBV(0x1B),
RGBV(0x1C), RGBV(0x1D), RGBV(0x1E), RGBV(0x1F),
RGBV(0x20), RGBV(0x21), RGBV(0x22), RGBV(0x23),
RGBV(0x24), RGBV(0x25), RGBV(0x26), RGBV(0x27),
RGBV(0x28), RGBV(0x29), RGBV(0x2A), RGBV(0x2B),
RGBV(0x2C), RGBV(0x2D), RGBV(0x2E), RGBV(0x2F),
RGBV(0x30), RGBV(0x31), RGBV(0x32), RGBV(0x33),
RGBV(0x34), RGBV(0x35), RGBV(0x36), RGBV(0x37),
RGBV(0x38), RGBV(0x39), RGBV(0x3A), RGBV(0x3B),
RGBV(0x3C), RGBV(0x3D), RGBV(0x3E), RGBV(0x3F),
RGBV(0x40), RGBV(0x41), RGBV(0x42), RGBV(0x43),
RGBV(0x44), RGBV(0x45), RGBV(0x46), RGBV(0x47),
RGBV(0x48), RGBV(0x49), RGBV(0x4A), RGBV(0x4B),
RGBV(0x4C), RGBV(0x4D), RGBV(0x4E), RGBV(0x4F),
RGBV(0x50), RGBV(0x51), RGBV(0x52), RGBV(0x53),
RGBV(0x54), RGBV(0x55), RGBV(0x56), RGBV(0x57),
RGBV(0x58), RGBV(0x59), RGBV(0x5A), RGBV(0x5B),
RGBV(0x5C), RGBV(0x5D), RGBV(0x5E), RGBV(0x5F),
RGBV(0x60), RGBV(0x61), RGBV(0x62), RGBV(0x63),
RGBV(0x64), RGBV(0x65), RGBV(0x66), RGBV(0x67),
RGBV(0x68), RGBV(0x69), RGBV(0x6A), RGBV(0x6B),
RGBV(0x6C), RGBV(0x6D), RGBV(0x6E), RGBV(0x6F),
RGBV(0x70), RGBV(0x71), RGBV(0x72), RGBV(0x73),
RGBV(0x74), RGBV(0x75), RGBV(0x76), RGBV(0x77),
RGBV(0x78), RGBV(0x79), RGBV(0x7A), RGBV(0x7B),
RGBV(0x7C), RGBV(0x7D), RGBV(0x7E), RGBV(0x7F),
RGBV(0x80), RGBV(0x81), RGBV(0x82), RGBV(0x83),
RGBV(0x84), RGBV(0x85), RGBV(0x86), RGBV(0x87),
RGBV(0x88), RGBV(0x89), RGBV(0x8A), RGBV(0x8B),
RGBV(0x8C), RGBV(0x8D), RGBV(0x8E), RGBV(0x8F),
RGBV(0x90), RGBV(0x91), RGBV(0x92), RGBV(0x93),
RGBV(0x94), RGBV(0x95), RGBV(0x96), RGBV(0x97),
RGBV(0x98), RGBV(0x99), RGBV(0x9A), RGBV(0x9B),
RGBV(0x9C), RGBV(0x9D), RGBV(0x9E), RGBV(0x9F),
RGBV(0xA0), RGBV(0xA1), RGBV(0xA2), RGBV(0xA3),
RGBV(0xA4), RGBV(0xA5), RGBV(0xA6), RGBV(0xA7),
RGBV(0xA8), RGBV(0xA9), RGBV(0xAA), RGBV(0xAB),
RGBV(0xAC), RGBV(0xAD), RGBV(0xAE), RGBV(0xAF),
RGBV(0xB0), RGBV(0xB1), RGBV(0xB2), RGBV(0xB3),
RGBV(0xB4), RGBV(0xB5), RGBV(0xB6), RGBV(0xB7),
RGBV(0xB8), RGBV(0xB9), RGBV(0xBA), RGBV(0xBB),
RGBV(0xBC), RGBV(0xBD), RGBV(0xBE), RGBV(0xBF),
RGBV(0xC0), RGBV(0xC1), RGBV(0xC2), RGBV(0xC3),
RGBV(0xC4), RGBV(0xC5), RGBV(0xC6), RGBV(0xC7),
RGBV(0xC8), RGBV(0xC9), RGBV(0xCA), RGBV(0xCB),
RGBV(0xCC), RGBV(0xCD), RGBV(0xCE), RGBV(0xCF),
RGBV(0xD0), RGBV(0xD1), RGBV(0xD2), RGBV(0xD3),
RGBV(0xD4), RGBV(0xD5), RGBV(0xD6), RGBV(0xD7),
RGBV(0xD8), RGBV(0xD9), RGBV(0xDA), RGBV(0xDB),
RGBV(0xDC), RGBV(0xDD), RGBV(0xDE), RGBV(0xDF),
RGBV(0xE0), RGBV(0xE1), RGBV(0xE2), RGBV(0xE3),
RGBV(0xE4), RGBV(0xE5), RGBV(0xE6), RGBV(0xE7),
RGBV(0xE8), RGBV(0xE9), RGBV(0xEA), RGBV(0xEB),
RGBV(0xEC), RGBV(0xED), RGBV(0xEE), RGBV(0xEF),
RGBV(0xF0), RGBV(0xF1), RGBV(0xF2), RGBV(0xF3),
RGBV(0xF4), RGBV(0xF5), RGBV(0xF6), RGBV(0xF7),
RGBV(0xF8), RGBV(0xF9), RGBV(0xFA), RGBV(0xFB),
RGBV(0xFC), RGBV(0xFD), RGBV(0xFE), RGBV(0xFF),
};
#undef RGBY
#undef RGBU
#undef RGBV
} // extern "C"

2848
source/scale.cc Normal file

File diff suppressed because it is too large Load Diff

64
source/video_common.cc Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2011 The LibYuv 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 "video_common.h"
#include <sstream>
#include "common.h"
namespace libyuv {
struct FourCCAliasEntry {
uint32 alias;
uint32 canonical;
};
static const FourCCAliasEntry kFourCCAliases[] = {
{FOURCC_IYUV, FOURCC_I420},
{FOURCC_YU12, FOURCC_I420},
{FOURCC_YUYV, FOURCC_YUY2},
{FOURCC_YUVS, FOURCC_YUY2},
{FOURCC_HDYC, FOURCC_UYVY},
{FOURCC_2VUY, FOURCC_UYVY},
{FOURCC_BA81, FOURCC_BGGR},
{FOURCC_JPEG, FOURCC_MJPG}, // Note: JPEG has DHT while MJPG does not.
{FOURCC_RGB3, FOURCC_RAW},
{FOURCC_BGR3, FOURCC_24BG},
};
uint32 CanonicalFourCC(uint32 fourcc) {
for (int i = 0; i < ARRAY_SIZE(kFourCCAliases); ++i) {
if (kFourCCAliases[i].alias == fourcc) {
return kFourCCAliases[i].canonical;
}
}
// Not an alias, so return it as-is.
return fourcc;
}
std::string VideoFormat::ToString() const {
std::string fourcc_name = GetFourccName(fourcc) + " ";
for (std::string::const_iterator i = fourcc_name.begin();
i < fourcc_name.end(); ++i) {
// Test character is printable; Avoid isprint() which asserts on negatives
if (*i < 32 || *i >= 127) {
fourcc_name = "";
break;
}
}
std::ostringstream ss;
ss << fourcc_name << width << "x" << height << "x" << IntervalToFps(interval);
return ss.str();
}
} // namespace libyuv

174
source/video_common.h Normal file
View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 2011 The LibYuv 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.
*/
/*
* Common definitions for video, including fourcc and VideoFormat
*/
#ifndef LIBYUV_SOURCE_VIDEO_COMMON_H_
#define LIBYUV_SOURCE_VIDEO_COMMON_H_
#include <string>
#include "basic_types.h"
namespace libyuv {
//////////////////////////////////////////////////////////////////////////////
// Definition of fourcc.
//////////////////////////////////////////////////////////////////////////////
// Convert four characters to a fourcc code.
// Needs to be a macro otherwise the OS X compiler complains when the kFormat*
// constants are used in a switch.
#define FOURCC(a, b, c, d) (\
(static_cast<uint32>(a)) | (static_cast<uint32>(b) << 8) | \
(static_cast<uint32>(c) << 16) | (static_cast<uint32>(d) << 24))
// Get the name, that is, string with four characters, of a fourcc code.
inline std::string GetFourccName(uint32 fourcc) {
std::string name;
name.push_back(static_cast<char>(fourcc & 0xFF));
name.push_back(static_cast<char>((fourcc >> 8) & 0xFF));
name.push_back(static_cast<char>((fourcc >> 16) & 0xFF));
name.push_back(static_cast<char>((fourcc >> 24) & 0xFF));
return name;
}
// Some good pages discussing FourCC codes:
// http://developer.apple.com/quicktime/icefloe/dispatch020.html
// http://www.fourcc.org/yuv.php
enum FourCC {
// Canonical fourcc codes used in our code.
FOURCC_I420 = FOURCC('I', '4', '2', '0'),
FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'),
FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
FOURCC_M420 = FOURCC('M', '4', '2', '0'),
FOURCC_24BG = FOURCC('2', '4', 'B', 'G'),
FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'),
FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'),
FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'),
FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
FOURCC_RAW = FOURCC('r', 'a', 'w', ' '),
FOURCC_NV21 = FOURCC('N', 'V', '2', '1'),
FOURCC_NV12 = FOURCC('N', 'V', '1', '2'),
// Next four are Bayer RGB formats. The four characters define the order of
// the colours in each 2x2 pixel grid, going left-to-right and top-to-bottom.
FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'),
FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'),
FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'),
FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'),
// Aliases for canonical fourcc codes, replaced with their canonical
// equivalents by CanonicalFourCC().
FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420
FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Alias for I420
FOURCC_YUYV = FOURCC('Y', 'U', 'Y', 'V'), // Alias for YUY2
FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'), // Alias for YUY2 on Mac
FOURCC_HDYC = FOURCC('H', 'D', 'Y', 'C'), // Alias for UYVY
FOURCC_2VUY = FOURCC('2', 'v', 'u', 'y'), // Alias for UYVY
FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'), // Alias for MJPG
FOURCC_BA81 = FOURCC('B', 'A', '8', '1'), // Alias for BGGR
FOURCC_RGB3 = FOURCC('R', 'G', 'B', '3'), // Alias for RAW
FOURCC_BGR3 = FOURCC('B', 'G', 'R', '3'), // Alias for 24BG
// Match any fourcc.
FOURCC_ANY = 0xFFFFFFFF,
};
// Converts fourcc aliases into canonical ones.
uint32 CanonicalFourCC(uint32 fourcc);
//////////////////////////////////////////////////////////////////////////////
// Definition of VideoFormat.
//////////////////////////////////////////////////////////////////////////////
static const int64 kNumNanosecsPerSec = 1000000000;
struct VideoFormat {
static const int64 kMinimumInterval = kNumNanosecsPerSec / 10000; // 10k fps
VideoFormat() : width(0), height(0), interval(0), fourcc(0) {}
VideoFormat(int w, int h, int64 interval_ns, uint32 cc)
: width(w),
height(h),
interval(interval_ns),
fourcc(cc) {
}
VideoFormat(const VideoFormat& format)
: width(format.width),
height(format.height),
interval(format.interval),
fourcc(format.fourcc) {
}
static int64 FpsToInterval(int fps) {
return fps ? kNumNanosecsPerSec / fps : kMinimumInterval;
}
static int IntervalToFps(int64 interval) {
// Normalize the interval first.
interval = libyuv::_max(interval, kMinimumInterval);
return static_cast<int>(kNumNanosecsPerSec / interval);
}
bool operator==(const VideoFormat& format) const {
return width == format.width && height == format.height &&
interval == format.interval && fourcc == format.fourcc;
}
bool operator!=(const VideoFormat& format) const {
return !(*this == format);
}
bool operator<(const VideoFormat& format) const {
return (fourcc < format.fourcc) ||
(fourcc == format.fourcc && width < format.width) ||
(fourcc == format.fourcc && width == format.width &&
height < format.height) ||
(fourcc == format.fourcc && width == format.width &&
height == format.height && interval > format.interval);
}
int framerate() const { return IntervalToFps(interval); }
// Check if both width and height are 0.
bool IsSize0x0() const { return 0 == width && 0 == height; }
// Check if this format is less than another one by comparing the resolution
// and frame rate.
bool IsPixelRateLess(const VideoFormat& format) const {
return width * height * framerate() <
format.width * format.height * format.framerate();
}
// Get a string presentation in the form of "fourcc width x height x fps"
std::string ToString() const;
int width; // in number of pixels
int height; // in number of pixels
int64 interval; // in nanoseconds
uint32 fourcc; // color space. FOURCC_ANY means that any color space is OK.
};
// Result of video capturer start.
enum CaptureResult {
CR_SUCCESS, // The capturer starts successfully.
CR_PENDING, // The capturer is pending to start the capture device.
CR_FAILURE, // The capturer fails to start.
CR_NO_DEVICE, // The capturer has no device and fails to start.
};
} // namespace libyuv
#endif // LIBYUV_SOURCE_VIDEO_COMMON_H_