Multiple-resolution encoder
The example encoder down-samples the input video frames a number of times with a down-sampling factor, and then encodes and outputs bitstreams with different resolutions. Support arbitrary down-sampling factor, and down-sampling factor can be different for each encoding level. For example, the encoder can be tested as follows. 1. Configure with multi-resolution encoding enabled: ../libvpx/configure --target=x86-linux-gcc --disable-codecs --enable-vp8 --enable-runtime_cpu_detect --enable-debug --disable-install-docs --enable-error-concealment --enable-multi-res-encoding 2. Run make 3. Encode: If input video is 1280x720, run: ./vp8_multi_resolution_encoder 1280 720 input.yuv 1.ivf 2.ivf 3.ivf 1 (output: 1.ivf(1280x720); 2.ivf(640x360); 3.ivf(320x180). The last parameter is set to 1/0 to show/not show PSNR.) 4. Decode: ./simple_decoder 1.ivf 1.yuv ./simple_decoder 2.ivf 2.yuv ./simple_decoder 3.ivf 3.yuv 5. View video: mplayer 1.yuv -demuxer rawvideo -rawvideo w=1280:h=720 -loop 0 -fps 30 mplayer 2.yuv -demuxer rawvideo -rawvideo w=640:h=360 -loop 0 -fps 30 mplayer 3.yuv -demuxer rawvideo -rawvideo w=320:h=180 -loop 0 -fps 30 The encoding parameters can be modified in vp8_multi_resolution_encoder.c, for example, target bitrate, frame rate... Modified API. John helped a lot with that. Thanks! Change-Id: I03be9a51167eddf94399f92d269599fb3f3d54f5
This commit is contained in:
		
							
								
								
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -35,7 +35,7 @@ Advanced options: | ||||
|   ${toggle_internal_stats}        output of encoder internal stats for debug, if supported (encoders) | ||||
|   ${toggle_mem_tracker}           track memory usage | ||||
|   ${toggle_postproc}              postprocessing | ||||
|   ${toggle_multithread}           multithreaded encoding and decoding. | ||||
|   ${toggle_multithread}           multithreaded encoding and decoding | ||||
|   ${toggle_spatial_resampling}    spatial sampling (scaling) support | ||||
|   ${toggle_realtime_only}         enable this option while building for real-time encoding | ||||
|   ${toggle_error_concealment}     enable this option to get a decoder which is able to conceal losses | ||||
| @@ -44,6 +44,7 @@ Advanced options: | ||||
|   ${toggle_static}                static library support | ||||
|   ${toggle_small}                 favor smaller size over speed | ||||
|   ${toggle_postproc_visualizer}   macro block / block level visualizers | ||||
|   ${toggle_multi_res_encoding}    enable multiple-resolution encoding | ||||
|  | ||||
| Codecs: | ||||
|   Codecs can be selectively enabled or disabled individually, or by family: | ||||
| @@ -262,6 +263,7 @@ CONFIG_LIST=" | ||||
|     postproc_visualizer | ||||
|     os_support | ||||
|     unit_tests | ||||
|     multi_res_encoding | ||||
| " | ||||
| CMDLINE_SELECT=" | ||||
|     extra_warnings | ||||
| @@ -304,6 +306,7 @@ CMDLINE_SELECT=" | ||||
|     small | ||||
|     postproc_visualizer | ||||
|     unit_tests | ||||
|     multi_res_encoding | ||||
| " | ||||
|  | ||||
| process_cmdline() { | ||||
|   | ||||
							
								
								
									
										10
									
								
								examples.mk
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								examples.mk
									
									
									
									
									
								
							| @@ -96,6 +96,16 @@ GEN_EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c | ||||
| vp8cx_set_ref.GUID                  = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A | ||||
| vp8cx_set_ref.DESCRIPTION           = VP8 set encoder reference frame | ||||
|  | ||||
| # C file is provided, not generated automatically. | ||||
| GEN_EXAMPLES-$(CONFIG_MULTI_RES_ENCODING) += vp8_multi_resolution_encoder.c | ||||
| vp8_multi_resolution_encoder.SRCS  \ | ||||
|                          += third_party/libyuv/include/libyuv/basic_types.h  \ | ||||
|                             third_party/libyuv/include/libyuv/cpu_id.h  \ | ||||
|                             third_party/libyuv/include/libyuv/scale.h  \ | ||||
|                             third_party/libyuv/source/scale.c  \ | ||||
|                             third_party/libyuv/source/cpu_id.c | ||||
| vp8_multi_resolution_encoder.GUID         = 04f8738e-63c8-423b-90fa-7c2703a374de | ||||
| vp8_multi_resolution_encoder.DESCRIPTION  = VP8 Multiple-resolution Encoding | ||||
|  | ||||
| # Handle extra library flags depending on codec configuration | ||||
|  | ||||
|   | ||||
							
								
								
									
										17
									
								
								third_party/libyuv/README.webm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								third_party/libyuv/README.webm
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| Name: libyuv | ||||
| URL: http://code.google.com/p/libyuv/ | ||||
| Version: 90 | ||||
| License: BSD | ||||
| License File: LICENSE | ||||
|  | ||||
| Description: | ||||
| libyuv is an open source project that includes YUV conversion and scaling | ||||
| functionality. | ||||
|  | ||||
| The optimized scaler in libyuv is used in multiple resolution encoder example, | ||||
| which down-samples the original input video (f.g. 1280x720) a number of times | ||||
| in order to encode multiple resolution bit streams. | ||||
|  | ||||
| Local Modifications: | ||||
| Modified the original scaler code from C++ to C to fit in our current build | ||||
| system. This is a temporal solution, and will be improved later. | ||||
							
								
								
									
										68
									
								
								third_party/libyuv/include/libyuv/basic_types.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								third_party/libyuv/include/libyuv/basic_types.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| /* | ||||
|  *  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 INCLUDE_LIBYUV_BASIC_TYPES_H_ | ||||
| #define INCLUDE_LIBYUV_BASIC_TYPES_H_ | ||||
|  | ||||
| #include <stddef.h>  // for NULL, size_t | ||||
|  | ||||
| #ifndef WIN32 | ||||
| #include <stdint.h>  // for uintptr_t | ||||
| #endif | ||||
|  | ||||
| #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 | ||||
|  | ||||
| // Detect compiler is for x86 or x64. | ||||
| #if defined(__x86_64__) || defined(_M_X64) || \ | ||||
|     defined(__i386__) || defined(_M_IX86) | ||||
| #define CPU_X86 1 | ||||
| #endif | ||||
|  | ||||
| #define IS_ALIGNED(p, a) (0==((uintptr_t)(p) & ((a)-1))) | ||||
| #define ALIGNP(p, t) \ | ||||
|   ((uint8*)((((uintptr_t)(p) + \ | ||||
|   ((t)-1)) & ~((t)-1)))) | ||||
|  | ||||
| #endif // INCLUDE_LIBYUV_BASIC_TYPES_H_ | ||||
							
								
								
									
										31
									
								
								third_party/libyuv/include/libyuv/cpu_id.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								third_party/libyuv/include/libyuv/cpu_id.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
|  *  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 INCLUDE_LIBYUV_CPU_ID_H_ | ||||
| #define INCLUDE_LIBYUV_CPU_ID_H_ | ||||
|  | ||||
| //namespace libyuv { | ||||
|  | ||||
| // 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. | ||||
| int TestCpuFlag(int flag); | ||||
|  | ||||
| // For testing, allow CPU flags to be disabled. | ||||
| void MaskCpuFlagsForTest(int enable_flags); | ||||
|  | ||||
| //}  // namespace libyuv | ||||
|  | ||||
| #endif  // INCLUDE_LIBYUV_CPU_ID_H_ | ||||
							
								
								
									
										67
									
								
								third_party/libyuv/include/libyuv/scale.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								third_party/libyuv/include/libyuv/scale.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| /* | ||||
|  *  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 INCLUDE_LIBYUV_SCALE_H_ | ||||
| #define INCLUDE_LIBYUV_SCALE_H_ | ||||
|  | ||||
| #include "third_party/libyuv/include/libyuv/basic_types.h" | ||||
|  | ||||
| //namespace libyuv { | ||||
|  | ||||
| // Supported filtering | ||||
| typedef enum { | ||||
|   kFilterNone = 0,  // Point sample; Fastest | ||||
|   kFilterBilinear = 1,  // Faster than box, but lower quality scaling down. | ||||
|   kFilterBox = 2  // Highest quality | ||||
| }FilterMode; | ||||
|  | ||||
| // Scales a YUV 4:2:0 image from the src width and height to the | ||||
| // dst width and height. | ||||
| // If filtering is kFilterNone, a simple nearest-neighbor algorithm is | ||||
| // used. This produces basic (blocky) quality at the fastest speed. | ||||
| // If filtering is kFilterBilinear, interpolation is used to produce a better | ||||
| // quality image, at the expense of speed. | ||||
| // If filtering is kFilterBox, averaging is used to produce ever better | ||||
| // quality image, at further expense of speed. | ||||
| // Returns 0 if successful. | ||||
|  | ||||
| int I420Scale(const uint8* src_y, int src_stride_y, | ||||
|               const uint8* src_u, int src_stride_u, | ||||
|               const uint8* src_v, int src_stride_v, | ||||
|               int src_width, int src_height, | ||||
|               uint8* dst_y, int dst_stride_y, | ||||
|               uint8* dst_u, int dst_stride_u, | ||||
|               uint8* dst_v, int dst_stride_v, | ||||
|               int dst_width, int dst_height, | ||||
|               FilterMode filtering); | ||||
|  | ||||
| // Legacy API | ||||
| // If dst_height_offset is non-zero, the image is offset by that many pixels | ||||
| // and stretched to (dst_height - dst_height_offset * 2) pixels high, | ||||
| // instead of dst_height. | ||||
| int Scale_1(const uint8* src, int src_width, int src_height, | ||||
|           uint8* dst, int dst_width, int dst_height, int dst_height_offset, | ||||
|           int interpolate); | ||||
|  | ||||
| // Same, but specified src terms of each plane location and stride. | ||||
| int Scale_2(const uint8* src_y, const uint8* src_u, const uint8* src_v, | ||||
|           int src_stride_y, int src_stride_u, int src_stride_v, | ||||
|           int src_width, int src_height, | ||||
|           uint8* dst_y, uint8* dst_u, uint8* dst_v, | ||||
|           int dst_stride_y, int dst_stride_u, int dst_stride_v, | ||||
|           int dst_width, int dst_height, | ||||
|           int interpolate); | ||||
|  | ||||
| // For testing, allow disabling of optimizations. | ||||
| void SetUseReferenceImpl(int use); | ||||
|  | ||||
| //} // namespace libyuv | ||||
|  | ||||
| #endif // INCLUDE_LIBYUV_SCALE_H_ | ||||
							
								
								
									
										74
									
								
								third_party/libyuv/source/cpu_id.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								third_party/libyuv/source/cpu_id.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| /* | ||||
|  *  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 "third_party/libyuv/include/libyuv/cpu_id.h" | ||||
| #include "third_party/libyuv/include/libyuv/basic_types.h"  // for CPU_X86 | ||||
|  | ||||
| #ifdef _MSC_VER | ||||
| #include <intrin.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. | ||||
| static int cpu_info_initialized_ = 0; | ||||
| static int cpu_info_ = 0; | ||||
|  | ||||
| // Global lock for cpu initialization. | ||||
| static void 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; | ||||
| #else | ||||
|   cpu_info_ = 0; | ||||
| #endif | ||||
|   cpu_info_initialized_ = 1; | ||||
| } | ||||
|  | ||||
| void MaskCpuFlagsForTest(int enable_flags) { | ||||
|   InitCpuFlags(); | ||||
|   cpu_info_ &= enable_flags; | ||||
| } | ||||
|  | ||||
| int TestCpuFlag(int flag) { | ||||
|   if (!cpu_info_initialized_) { | ||||
|     InitCpuFlags(); | ||||
|   } | ||||
|   return cpu_info_ & flag ? 1 : 0; | ||||
| } | ||||
|  | ||||
| //}  // namespace libyuv | ||||
							
								
								
									
										258
									
								
								third_party/libyuv/source/row.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								third_party/libyuv/source/row.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,258 @@ | ||||
| /* | ||||
|  *  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 "third_party/libyuv/include/libyuv/basic_types.h" | ||||
|  | ||||
| #define kMaxStride (2048 * 4) | ||||
| //#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1))) | ||||
|  | ||||
| #if defined(COVERAGE_ENABLED) || defined(TARGET_IPHONE_SIMULATOR) | ||||
| #define YUV_DISABLE_ASM | ||||
| #endif | ||||
|  | ||||
| #if defined(__ARM_NEON__) && !defined(YUV_DISABLE_ASM) | ||||
| #define HAS_FASTCONVERTYUVTOARGBROW_NEON | ||||
| void FastConvertYUVToARGBRow_NEON(const uint8* y_buf, | ||||
|                                   const uint8* u_buf, | ||||
|                                   const uint8* v_buf, | ||||
|                                   uint8* rgb_buf, | ||||
|                                   int width); | ||||
| #define HAS_FASTCONVERTYUVTOBGRAROW_NEON | ||||
| void FastConvertYUVToBGRARow_NEON(const uint8* y_buf, | ||||
|                                   const uint8* u_buf, | ||||
|                                   const uint8* v_buf, | ||||
|                                   uint8* rgb_buf, | ||||
|                                   int width); | ||||
| #define HAS_FASTCONVERTYUVTOABGRROW_NEON | ||||
| void FastConvertYUVToABGRRow_NEON(const uint8* y_buf, | ||||
|                                   const uint8* u_buf, | ||||
|                                   const uint8* v_buf, | ||||
|                                   uint8* rgb_buf, | ||||
|                                   int width); | ||||
| #endif | ||||
|  | ||||
| // The following are available on all x86 platforms | ||||
| #if (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)) && \ | ||||
|     !defined(YUV_DISABLE_ASM) | ||||
| #define HAS_ABGRTOARGBROW_SSSE3 | ||||
| #define HAS_BGRATOARGBROW_SSSE3 | ||||
| #define HAS_BG24TOARGBROW_SSSE3 | ||||
| #define HAS_RAWTOARGBROW_SSSE3 | ||||
| #define HAS_RGB24TOYROW_SSSE3 | ||||
| #define HAS_RAWTOYROW_SSSE3 | ||||
| #define HAS_RGB24TOUVROW_SSSE3 | ||||
| #define HAS_RAWTOUVROW_SSSE3 | ||||
| #define HAS_ARGBTOYROW_SSSE3 | ||||
| #define HAS_BGRATOYROW_SSSE3 | ||||
| #define HAS_ABGRTOYROW_SSSE3 | ||||
| #define HAS_ARGBTOUVROW_SSSE3 | ||||
| #define HAS_BGRATOUVROW_SSSE3 | ||||
| #define HAS_ABGRTOUVROW_SSSE3 | ||||
| #define HAS_I400TOARGBROW_SSE2 | ||||
| #define HAS_FASTCONVERTYTOARGBROW_SSE2 | ||||
| #define HAS_FASTCONVERTYUVTOARGBROW_SSSE3 | ||||
| #define HAS_FASTCONVERTYUVTOBGRAROW_SSSE3 | ||||
| #define HAS_FASTCONVERTYUVTOABGRROW_SSSE3 | ||||
| #define HAS_FASTCONVERTYUV444TOARGBROW_SSSE3 | ||||
| #define HAS_REVERSE_ROW_SSSE3 | ||||
| #endif | ||||
|  | ||||
| // The following are available on Neon platforms | ||||
| #if defined(__ARM_NEON__) && !defined(YUV_DISABLE_ASM) | ||||
| #define HAS_REVERSE_ROW_NEON | ||||
| #endif | ||||
|  | ||||
| //extern "C" { | ||||
|  | ||||
| #ifdef HAS_ARGBTOYROW_SSSE3 | ||||
| void ARGBToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void BGRAToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void ABGRToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void ARGBToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, | ||||
|                        uint8* dst_u, uint8* dst_v, int width); | ||||
| void BGRAToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, | ||||
|                        uint8* dst_u, uint8* dst_v, int width); | ||||
| void ABGRToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, | ||||
|                        uint8* dst_u, uint8* dst_v, int width); | ||||
| #endif | ||||
| #if defined(HAS_BG24TOARGBROW_SSSE3) && defined(HAS_ARGBTOYROW_SSSE3) | ||||
| #define HASRGB24TOYROW_SSSE3 | ||||
| #endif | ||||
| #ifdef HASRGB24TOYROW_SSSE3 | ||||
| void RGB24ToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void RAWToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void RGB24ToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, | ||||
|                         uint8* dst_u, uint8* dst_v, int width); | ||||
| void RAWToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, | ||||
|                       uint8* dst_u, uint8* dst_v, int width); | ||||
| #endif | ||||
| #ifdef HAS_REVERSE_ROW_SSSE3 | ||||
| void ReverseRow_SSSE3(const uint8* src, uint8* dst, int width); | ||||
| #endif | ||||
| #ifdef HAS_REVERSE_ROW_NEON | ||||
| void ReverseRow_NEON(const uint8* src, uint8* dst, int width); | ||||
| #endif | ||||
| void ReverseRow_C(const uint8* src, uint8* dst, int width); | ||||
|  | ||||
| void ARGBToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void BGRAToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void ABGRToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void RGB24ToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void RAWToYRow_C(const uint8* src_argb, uint8* dst_y, int pix); | ||||
| void ARGBToUVRow_C(const uint8* src_argb0, int src_stride_argb, | ||||
|                    uint8* dst_u, uint8* dst_v, int width); | ||||
| void BGRAToUVRow_C(const uint8* src_argb0, int src_stride_argb, | ||||
|                    uint8* dst_u, uint8* dst_v, int width); | ||||
| void ABGRToUVRow_C(const uint8* src_argb0, int src_stride_argb, | ||||
|                    uint8* dst_u, uint8* dst_v, int width); | ||||
| void RGB24ToUVRow_C(const uint8* src_argb0, int src_stride_argb, | ||||
|                     uint8* dst_u, uint8* dst_v, int width); | ||||
| void RAWToUVRow_C(const uint8* src_argb0, int src_stride_argb, | ||||
|                   uint8* dst_u, uint8* dst_v, int width); | ||||
|  | ||||
| #ifdef HAS_BG24TOARGBROW_SSSE3 | ||||
| void ABGRToARGBRow_SSSE3(const uint8* src_abgr, uint8* dst_argb, int pix); | ||||
| void BGRAToARGBRow_SSSE3(const uint8* src_bgra, uint8* dst_argb, int pix); | ||||
| void BG24ToARGBRow_SSSE3(const uint8* src_bg24, uint8* dst_argb, int pix); | ||||
| void RAWToARGBRow_SSSE3(const uint8* src_bg24, uint8* dst_argb, int pix); | ||||
| #endif | ||||
| void ABGRToARGBRow_C(const uint8* src_abgr, uint8* dst_argb, int pix); | ||||
| void BGRAToARGBRow_C(const uint8* src_bgra, uint8* dst_argb, int pix); | ||||
| void BG24ToARGBRow_C(const uint8* src_bg24, uint8* dst_argb, int pix); | ||||
| void RAWToARGBRow_C(const uint8* src_bg24, uint8* dst_argb, int pix); | ||||
|  | ||||
| #ifdef HAS_I400TOARGBROW_SSE2 | ||||
| void I400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int pix); | ||||
| #endif | ||||
| void I400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int pix); | ||||
|  | ||||
| #if defined(_MSC_VER) | ||||
| #define SIMD_ALIGNED(var) __declspec(align(16)) var | ||||
| typedef __declspec(align(16)) signed char vec8[16]; | ||||
| typedef __declspec(align(16)) unsigned char uvec8[16]; | ||||
| typedef __declspec(align(16)) signed short vec16[8]; | ||||
| #else // __GNUC__ | ||||
| #define SIMD_ALIGNED(var) var __attribute__((aligned(16))) | ||||
| typedef signed char __attribute__((vector_size(16))) vec8; | ||||
| typedef unsigned char __attribute__((vector_size(16))) uvec8; | ||||
| typedef signed short __attribute__((vector_size(16))) vec16; | ||||
| #endif | ||||
|  | ||||
| //extern "C" | ||||
| SIMD_ALIGNED(const int16 kCoefficientsRgbY[768][4]); | ||||
| //extern "C" | ||||
| SIMD_ALIGNED(const int16 kCoefficientsBgraY[768][4]); | ||||
| //extern "C" | ||||
| SIMD_ALIGNED(const int16 kCoefficientsAbgrY[768][4]); | ||||
|  | ||||
| void FastConvertYUVToARGBRow_C(const uint8* y_buf, | ||||
|                                const uint8* u_buf, | ||||
|                                const uint8* v_buf, | ||||
|                                uint8* rgb_buf, | ||||
|                                int width); | ||||
|  | ||||
| void FastConvertYUVToBGRARow_C(const uint8* y_buf, | ||||
|                                const uint8* u_buf, | ||||
|                                const uint8* v_buf, | ||||
|                                uint8* rgb_buf, | ||||
|                                int width); | ||||
|  | ||||
| void FastConvertYUVToABGRRow_C(const uint8* y_buf, | ||||
|                                const uint8* u_buf, | ||||
|                                const uint8* v_buf, | ||||
|                                uint8* rgb_buf, | ||||
|                                int width); | ||||
|  | ||||
| void FastConvertYUV444ToARGBRow_C(const uint8* y_buf, | ||||
|                                   const uint8* u_buf, | ||||
|                                   const uint8* v_buf, | ||||
|                                   uint8* rgb_buf, | ||||
|                                   int width); | ||||
|  | ||||
| void FastConvertYToARGBRow_C(const uint8* y_buf, | ||||
|                              uint8* rgb_buf, | ||||
|                              int width); | ||||
|  | ||||
| #ifdef HAS_FASTCONVERTYUVTOARGBROW_SSE2 | ||||
| void FastConvertYUVToARGBRow_SSE2(const uint8* y_buf, | ||||
|                                   const uint8* u_buf, | ||||
|                                   const uint8* v_buf, | ||||
|                                   uint8* rgb_buf, | ||||
|                                   int width); | ||||
|  | ||||
| void FastConvertYUVToARGBRow4_SSE2(const uint8* y_buf, | ||||
|                                    const uint8* u_buf, | ||||
|                                    const uint8* v_buf, | ||||
|                                    uint8* rgb_buf, | ||||
|                                    int width); | ||||
|  | ||||
| void FastConvertYUVToBGRARow_SSE2(const uint8* y_buf, | ||||
|                                   const uint8* u_buf, | ||||
|                                   const uint8* v_buf, | ||||
|                                   uint8* rgb_buf, | ||||
|                                   int width); | ||||
|  | ||||
| void FastConvertYUVToABGRRow_SSE2(const uint8* y_buf, | ||||
|                                   const uint8* u_buf, | ||||
|                                   const uint8* v_buf, | ||||
|                                   uint8* rgb_buf, | ||||
|                                   int width); | ||||
|  | ||||
| void FastConvertYUV444ToARGBRow_SSE2(const uint8* y_buf, | ||||
|                                      const uint8* u_buf, | ||||
|                                      const uint8* v_buf, | ||||
|                                      uint8* rgb_buf, | ||||
|                                      int width); | ||||
|  | ||||
| void FastConvertYToARGBRow_SSE2(const uint8* y_buf, | ||||
|                                 uint8* rgb_buf, | ||||
|                                 int width); | ||||
| #endif | ||||
|  | ||||
| #ifdef HAS_FASTCONVERTYUVTOARGBROW_SSSE3 | ||||
| void FastConvertYUVToARGBRow_SSSE3(const uint8* y_buf, | ||||
|                                    const uint8* u_buf, | ||||
|                                    const uint8* v_buf, | ||||
|                                    uint8* rgb_buf, | ||||
|                                    int width); | ||||
|  | ||||
| void FastConvertYUVToBGRARow_SSSE3(const uint8* y_buf, | ||||
|                                    const uint8* u_buf, | ||||
|                                    const uint8* v_buf, | ||||
|                                    uint8* rgb_buf, | ||||
|                                    int width); | ||||
|  | ||||
| void FastConvertYUVToABGRRow_SSSE3(const uint8* y_buf, | ||||
|                                    const uint8* u_buf, | ||||
|                                    const uint8* v_buf, | ||||
|                                    uint8* rgb_buf, | ||||
|                                    int width); | ||||
|  | ||||
| void FastConvertYUV444ToARGBRow_SSSE3(const uint8* y_buf, | ||||
|                                       const uint8* u_buf, | ||||
|                                       const uint8* v_buf, | ||||
|                                       uint8* rgb_buf, | ||||
|                                       int width); | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #ifdef HAS_FASTCONVERTYTOARGBROW_SSE2 | ||||
| void FastConvertYToARGBRow_SSE2(const uint8* y_buf, | ||||
|                                 uint8* rgb_buf, | ||||
|                                 int width); | ||||
|  | ||||
| #endif | ||||
|  | ||||
| //}  // extern "C" | ||||
|  | ||||
| #endif  // LIBYUV_SOURCE_ROW_H_ | ||||
							
								
								
									
										3914
									
								
								third_party/libyuv/source/scale.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3914
									
								
								third_party/libyuv/source/scale.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -82,6 +82,7 @@ | ||||
|  | ||||
|     The available initialization methods are: | ||||
|     \if encoder - #vpx_codec_enc_init (calls vpx_codec_enc_init_ver()) \endif | ||||
|     \if multi-encoder - #vpx_codec_enc_init_multi (calls vpx_codec_enc_init_multi_ver()) \endif | ||||
|     \if decoder - #vpx_codec_dec_init (calls vpx_codec_dec_init_ver()) \endif | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /*! \page usage_encode Encode | ||||
|  | ||||
|     The vpx_codec_encode() function is at the core of the decode loop. It | ||||
|     The vpx_codec_encode() function is at the core of the encode loop. It | ||||
|     processes raw images passed by the application, producing packets of | ||||
|     compressed data. The <code>deadline</code> parameter controls the amount | ||||
|     of time in microseconds the encoder should spend working on the frame. For | ||||
| @@ -10,5 +10,4 @@ | ||||
|  | ||||
|     \ref samples | ||||
|  | ||||
|  | ||||
| */ | ||||
|   | ||||
| @@ -170,6 +170,18 @@ typedef struct | ||||
|     union b_mode_info bmi[16]; | ||||
| } MODE_INFO; | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
| /* The information needed to be stored for higher-resolution encoder */ | ||||
| typedef struct | ||||
| { | ||||
|     MB_PREDICTION_MODE mode; | ||||
|     MV_REFERENCE_FRAME ref_frame; | ||||
|     int_mv mv; | ||||
|     //union b_mode_info bmi[16]; | ||||
|     int dissim;    // dissimilarity level of the macroblock | ||||
| } LOWER_RES_INFO; | ||||
| #endif | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|     short *qcoeff; | ||||
|   | ||||
| @@ -17,6 +17,7 @@ extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
| #include "vpx_config.h" | ||||
| #include "vpx/internal/vpx_codec_internal.h" | ||||
| #include "vpx/vp8cx.h" | ||||
| #include "vpx/vpx_encoder.h" | ||||
| @@ -207,6 +208,19 @@ extern "C" | ||||
|         unsigned int periodicity; | ||||
|         unsigned int layer_id[MAX_PERIODICITY]; | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|         /* Number of total resolutions encoded */ | ||||
|         unsigned int mr_total_resolutions; | ||||
|  | ||||
|         /* Current encoder ID */ | ||||
|         unsigned int mr_encoder_id; | ||||
|  | ||||
|         /* Down-sampling factor */ | ||||
|         vpx_rational_t mr_down_sampling_factor; | ||||
|  | ||||
|         /* Memory location to store low-resolution encoder's mode info */ | ||||
|         void* mr_low_res_mode_info; | ||||
| #endif | ||||
|     } VP8_CONFIG; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -49,8 +49,8 @@ extern void vp8cx_init_mbrthread_data(VP8_COMP *cpi, | ||||
|                                       int count); | ||||
| void vp8_build_block_offsets(MACROBLOCK *x); | ||||
| void vp8_setup_block_ptrs(MACROBLOCK *x); | ||||
| int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int recon_yoffset, int recon_uvoffset); | ||||
| int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t); | ||||
| int vp8cx_encode_inter_macroblock(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int recon_yoffset, int recon_uvoffset, int mb_row, int mb_col); | ||||
| int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int mb_row, int mb_col); | ||||
| static void adjust_act_zbin( VP8_COMP *cpi, MACROBLOCK *x ); | ||||
|  | ||||
| #ifdef MODE_STATS | ||||
| @@ -475,14 +475,14 @@ void encode_mb_row(VP8_COMP *cpi, | ||||
|  | ||||
|         if (cm->frame_type == KEY_FRAME) | ||||
|         { | ||||
|             *totalrate += vp8cx_encode_intra_macro_block(cpi, x, tp); | ||||
|             *totalrate += vp8cx_encode_intra_macro_block(cpi, x, tp, mb_row, mb_col); | ||||
| #ifdef MODE_STATS | ||||
|             y_modes[xd->mbmi.mode] ++; | ||||
| #endif | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             *totalrate += vp8cx_encode_inter_macroblock(cpi, x, tp, recon_yoffset, recon_uvoffset); | ||||
|             *totalrate += vp8cx_encode_inter_macroblock(cpi, x, tp, recon_yoffset, recon_uvoffset, mb_row, mb_col); | ||||
|  | ||||
| #ifdef MODE_STATS | ||||
|             inter_y_modes[xd->mbmi.mode] ++; | ||||
| @@ -1142,7 +1142,7 @@ static void adjust_act_zbin( VP8_COMP *cpi, MACROBLOCK *x ) | ||||
| #endif | ||||
| } | ||||
|  | ||||
| int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t) | ||||
| int vp8cx_encode_intra_macro_block(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, int mb_row, int mb_col) | ||||
| { | ||||
|     int rate; | ||||
|  | ||||
| @@ -1182,7 +1182,8 @@ extern void vp8_fix_contexts(MACROBLOCKD *x); | ||||
| int vp8cx_encode_inter_macroblock | ||||
| ( | ||||
|     VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, | ||||
|     int recon_yoffset, int recon_uvoffset | ||||
|     int recon_yoffset, int recon_uvoffset, | ||||
|     int mb_row, int mb_col | ||||
| ) | ||||
| { | ||||
|     MACROBLOCKD *const xd = &x->e_mbd; | ||||
| @@ -1230,8 +1231,25 @@ int vp8cx_encode_inter_macroblock | ||||
|  | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|         if (cpi->oxcf.mr_encoder_id == 0) | ||||
|         { | ||||
|             /* Lowest-resolution encoding */ | ||||
|             vp8_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, | ||||
|                                     &distortion, &intra_error); | ||||
|  | ||||
|         }else | ||||
|         { | ||||
|             /* Higher-resolution encoding */ | ||||
|             vp8_mr_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, | ||||
|                                 &distortion, &intra_error, mb_row, mb_col); | ||||
|         } | ||||
| #else | ||||
|         vp8_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate, | ||||
|                             &distortion, &intra_error); | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|     cpi->prediction_error += distortion; | ||||
|     cpi->intra_error += intra_error; | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include "onyx_int.h" | ||||
| #include "mcomp.h" | ||||
| #include "vpx_mem/vpx_mem.h" | ||||
| #include "vpx_config.h" | ||||
| @@ -182,8 +183,6 @@ void vp8_init3smotion_compensation(MACROBLOCK *x, int stride) | ||||
| #define IFMVCV(r,c,s,e) if ( c >= minc && c <= maxc && r >= minr && r <= maxr) s else e; | ||||
| #define ERR(r,c) (MVC(r,c)+DIST(r,c)) // returns distortion + motion vector cost | ||||
| #define CHECK_BETTER(v,r,c) IFMVCV(r,c,{thismse = DIST(r,c); if((v = (MVC(r,c)+thismse)) < besterr) { besterr = v; br=r; bc=c; *distortion = thismse; *sse1 = sse; }}, v=INT_MAX;)// checks if (r,c) has better score than previous best | ||||
| #define MIN(x,y) (((x)<(y))?(x):(y)) | ||||
| #define MAX(x,y) (((x)>(y))?(x):(y)) | ||||
|  | ||||
| int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, | ||||
|                                              int_mv *bestmv, int_mv *ref_mv, | ||||
| @@ -331,8 +330,7 @@ int vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d, | ||||
| #undef IFMVCV | ||||
| #undef ERR | ||||
| #undef CHECK_BETTER | ||||
| #undef MIN | ||||
| #undef MAX | ||||
|  | ||||
| int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, | ||||
|                                  int_mv *bestmv, int_mv *ref_mv, | ||||
|                                  int error_per_bit, | ||||
| @@ -854,6 +852,8 @@ int vp8_hex_search | ||||
|     int k = -1; | ||||
|     int all_in; | ||||
|     int best_site = -1; | ||||
|     int hex_range = 127; | ||||
|     int dia_range = 8; | ||||
|  | ||||
|     int_mv fcenter_mv; | ||||
|     fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; | ||||
| @@ -873,6 +873,18 @@ int vp8_hex_search | ||||
|                         in_what_stride, 0x7fffffff) | ||||
|             + mvsad_err_cost(&this_mv, &fcenter_mv, mvsadcost, sad_per_bit); | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|     /* Lower search range based on prediction info */ | ||||
|     if (search_param >= 6) goto cal_neighbors; | ||||
|     else if (search_param >= 5) hex_range = 4; | ||||
|     else if (search_param >= 4) hex_range = 6; | ||||
|     else if (search_param >= 3) hex_range = 15; | ||||
|     else if (search_param >= 2) hex_range = 31; | ||||
|     else if (search_param >= 1) hex_range = 63; | ||||
|  | ||||
|     dia_range = 8; | ||||
| #endif | ||||
|  | ||||
|     // hex search | ||||
|     //j=0 | ||||
|     CHECK_BOUNDS(2) | ||||
| @@ -909,7 +921,7 @@ int vp8_hex_search | ||||
|         k = best_site; | ||||
|     } | ||||
|  | ||||
|     for (j = 1; j < 127; j++) | ||||
|     for (j = 1; j < hex_range; j++) | ||||
|     { | ||||
|         best_site = -1; | ||||
|         CHECK_BOUNDS(2) | ||||
| @@ -951,7 +963,7 @@ int vp8_hex_search | ||||
|  | ||||
|     // check 4 1-away neighbors | ||||
| cal_neighbors: | ||||
|     for (j = 0; j < 32; j++) | ||||
|     for (j = 0; j < dia_range; j++) | ||||
|     { | ||||
|         best_site = -1; | ||||
|         CHECK_BOUNDS(1) | ||||
|   | ||||
							
								
								
									
										201
									
								
								vp8/encoder/mr_dissim.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								vp8/encoder/mr_dissim.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2010 The WebM 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 <limits.h> | ||||
| #include "vpx_config.h" | ||||
| #include "onyx_int.h" | ||||
| #include "mr_dissim.h" | ||||
| #include "vpx_mem/vpx_mem.h" | ||||
| #include "rdopt.h" | ||||
|  | ||||
| void vp8_cal_low_res_mb_cols(VP8_COMP *cpi) | ||||
| { | ||||
|     int low_res_w; | ||||
|  | ||||
|     /* Support arbitrary down-sampling factor */ | ||||
|     unsigned int iw = cpi->oxcf.Width*cpi->oxcf.mr_down_sampling_factor.den | ||||
|                       + cpi->oxcf.mr_down_sampling_factor.num - 1; | ||||
|  | ||||
|     low_res_w = iw/cpi->oxcf.mr_down_sampling_factor.num; | ||||
|     cpi->mr_low_res_mb_cols = ((low_res_w + 15) >> 4); | ||||
| } | ||||
|  | ||||
| #define GET_MV(x)    \ | ||||
| if(x->mbmi.ref_frame !=INTRA_FRAME)   \ | ||||
| {   \ | ||||
|     mvx[cnt] = x->mbmi.mv.as_mv.row;  \ | ||||
|     mvy[cnt] = x->mbmi.mv.as_mv.col;  \ | ||||
|     cnt++;    \ | ||||
| } | ||||
|  | ||||
| #define GET_MV_SIGN(x)    \ | ||||
| if(x->mbmi.ref_frame !=INTRA_FRAME)   \ | ||||
| {   \ | ||||
|     mvx[cnt] = x->mbmi.mv.as_mv.row;  \ | ||||
|     mvy[cnt] = x->mbmi.mv.as_mv.col;  \ | ||||
|     if (cm->ref_frame_sign_bias[x->mbmi.ref_frame]  \ | ||||
|         != cm->ref_frame_sign_bias[tmp->mbmi.ref_frame])  \ | ||||
|     {  \ | ||||
|         mvx[cnt] *= -1;   \ | ||||
|         mvy[cnt] *= -1;   \ | ||||
|     }  \ | ||||
|     cnt++;  \ | ||||
| } | ||||
|  | ||||
| void vp8_cal_dissimilarity(VP8_COMP *cpi) | ||||
| { | ||||
|     VP8_COMMON *cm = &cpi->common; | ||||
|  | ||||
|     /* Note: The first row & first column in mip are outside the frame, which | ||||
|      * were initialized to all 0.(ref_frame, mode, mv...) | ||||
|      * Their ref_frame = 0 means they won't be counted in the following | ||||
|      * calculation. | ||||
|      */ | ||||
|     if (cpi->oxcf.mr_total_resolutions >1 | ||||
|         && cpi->oxcf.mr_encoder_id < (cpi->oxcf.mr_total_resolutions - 1)) | ||||
|     { | ||||
|         /* Store info for show/no-show frames for supporting alt_ref. | ||||
|          * If parent frame is alt_ref, child has one too. | ||||
|          */ | ||||
|         if(cm->frame_type != KEY_FRAME) | ||||
|         { | ||||
|             int mb_row; | ||||
|             int mb_col; | ||||
|             /* Point to beginning of allocated MODE_INFO arrays. */ | ||||
|             MODE_INFO *tmp = cm->mip + cm->mode_info_stride; | ||||
|             LOWER_RES_INFO* store_mode_info | ||||
|                             = (LOWER_RES_INFO*)cpi->oxcf.mr_low_res_mode_info; | ||||
|  | ||||
|             for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++) | ||||
|             { | ||||
|                 tmp++; | ||||
|                 for (mb_col = 0; mb_col < cm->mb_cols; mb_col ++) | ||||
|                 { | ||||
|                     int dissim = INT_MAX; | ||||
|  | ||||
|                     if(tmp->mbmi.ref_frame !=INTRA_FRAME) | ||||
|                     { | ||||
|                         int              mvx[8]; | ||||
|                         int              mvy[8]; | ||||
|                         int              mmvx; | ||||
|                         int              mmvy; | ||||
|                         int              cnt=0; | ||||
|                         const MODE_INFO *here = tmp; | ||||
|                         const MODE_INFO *above = here - cm->mode_info_stride; | ||||
|                         const MODE_INFO *left = here - 1; | ||||
|                         const MODE_INFO *aboveleft = above - 1; | ||||
|                         const MODE_INFO *aboveright = NULL; | ||||
|                         const MODE_INFO *right = NULL; | ||||
|                         const MODE_INFO *belowleft = NULL; | ||||
|                         const MODE_INFO *below = NULL; | ||||
|                         const MODE_INFO *belowright = NULL; | ||||
|  | ||||
|                         /* If alternate reference frame is used, we have to | ||||
|                          * check sign of MV. */ | ||||
|                         if(cpi->oxcf.play_alternate) | ||||
|                         { | ||||
|                             /* Gather mv of neighboring MBs */ | ||||
|                             GET_MV_SIGN(above) | ||||
|                             GET_MV_SIGN(left) | ||||
|                             GET_MV_SIGN(aboveleft) | ||||
|  | ||||
|                             if(mb_col < (cm->mb_cols-1)) | ||||
|                             { | ||||
|                                 right = here + 1; | ||||
|                                 aboveright = above + 1; | ||||
|                                 GET_MV_SIGN(right) | ||||
|                                 GET_MV_SIGN(aboveright) | ||||
|                             } | ||||
|  | ||||
|                             if(mb_row < (cm->mb_rows-1)) | ||||
|                             { | ||||
|                                 below = here + cm->mode_info_stride; | ||||
|                                 belowleft = below - 1; | ||||
|                                 GET_MV_SIGN(below) | ||||
|                                 GET_MV_SIGN(belowleft) | ||||
|                             } | ||||
|  | ||||
|                             if(mb_col < (cm->mb_cols-1) | ||||
|                                 && mb_row < (cm->mb_rows-1)) | ||||
|                             { | ||||
|                                 belowright = below + 1; | ||||
|                                 GET_MV_SIGN(belowright) | ||||
|                             } | ||||
|                         }else | ||||
|                         { | ||||
|                             /* No alt_ref and gather mv of neighboring MBs */ | ||||
|                             GET_MV(above) | ||||
|                             GET_MV(left) | ||||
|                             GET_MV(aboveleft) | ||||
|  | ||||
|                             if(mb_col < (cm->mb_cols-1)) | ||||
|                             { | ||||
|                                 right = here + 1; | ||||
|                                 aboveright = above + 1; | ||||
|                                 GET_MV(right) | ||||
|                                 GET_MV(aboveright) | ||||
|                             } | ||||
|  | ||||
|                             if(mb_row < (cm->mb_rows-1)) | ||||
|                             { | ||||
|                                 below = here + cm->mode_info_stride; | ||||
|                                 belowleft = below - 1; | ||||
|                                 GET_MV(below) | ||||
|                                 GET_MV(belowleft) | ||||
|                             } | ||||
|  | ||||
|                             if(mb_col < (cm->mb_cols-1) | ||||
|                                 && mb_row < (cm->mb_rows-1)) | ||||
|                             { | ||||
|                                 belowright = below + 1; | ||||
|                                 GET_MV(belowright) | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                         if (cnt > 0) | ||||
|                         { | ||||
|                             int max_mvx = mvx[0]; | ||||
|                             int min_mvx = mvx[0]; | ||||
|                             int max_mvy = mvy[0]; | ||||
|                             int min_mvy = mvy[0]; | ||||
|                             int i; | ||||
|  | ||||
|                             if (cnt > 1) | ||||
|                             { | ||||
|                                 for (i=1; i< cnt; i++) | ||||
|                                 { | ||||
|                                     if (mvx[i] > max_mvx) max_mvx = mvx[i]; | ||||
|                                     else if (mvx[i] < min_mvx) min_mvx = mvx[i]; | ||||
|                                     if (mvy[i] > max_mvy) max_mvy = mvy[i]; | ||||
|                                     else if (mvy[i] < min_mvy) min_mvy = mvy[i]; | ||||
|                                 } | ||||
|                             } | ||||
|  | ||||
|                             mmvx = MAX(abs(min_mvx - here->mbmi.mv.as_mv.row), | ||||
|                                        abs(max_mvx - here->mbmi.mv.as_mv.row)); | ||||
|                             mmvy = MAX(abs(min_mvy - here->mbmi.mv.as_mv.col), | ||||
|                                        abs(max_mvy - here->mbmi.mv.as_mv.col)); | ||||
|                             dissim = MAX(mmvx, mmvy); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     /* Store mode info for next resolution encoding */ | ||||
|                     store_mode_info->mode = tmp->mbmi.mode; | ||||
|                     store_mode_info->ref_frame = tmp->mbmi.ref_frame; | ||||
|                     store_mode_info->mv.as_int = tmp->mbmi.mv.as_int; | ||||
|                     store_mode_info->dissim = dissim; | ||||
|                     tmp++; | ||||
|                     store_mode_info++; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								vp8/encoder/mr_dissim.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vp8/encoder/mr_dissim.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2010 The WebM 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 __INC_MR_DISSIM_H | ||||
| #define __INC_MR_DISSIM_H | ||||
| #include "vpx_config.h" | ||||
|  | ||||
| extern void vp8_cal_low_res_mb_cols(VP8_COMP *cpi); | ||||
| extern void vp8_cal_dissimilarity(VP8_COMP *cpi); | ||||
|  | ||||
| #endif | ||||
| @@ -36,6 +36,9 @@ | ||||
| #if ARCH_ARM | ||||
| #include "vpx_ports/arm.h" | ||||
| #endif | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
| #include "mr_dissim.h" | ||||
| #endif | ||||
|  | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| @@ -2234,6 +2237,13 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf) | ||||
|     vp8_loop_filter_init(cm); | ||||
|  | ||||
|     cpi->common.error.setjmp = 0; | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|     /* Calculate # of MBs in a row in lower-resolution level image. */ | ||||
|     if (cpi->oxcf.mr_encoder_id > 0) | ||||
|         vp8_cal_low_res_mb_cols(cpi); | ||||
| #endif | ||||
|  | ||||
|     return (VP8_PTR) cpi; | ||||
|  | ||||
| } | ||||
| @@ -4338,13 +4348,20 @@ static void encode_frame_to_data_rate | ||||
|                                            IF_RTCD(&cpi->rtcd.variance)); | ||||
|     } | ||||
|  | ||||
|     // This frame's MVs are saved and will be used in next frame's MV prediction. | ||||
|     // Last frame has one more line(add to bottom) and one more column(add to right) than cm->mip. The edge elements are initialized to 0. | ||||
|     if(cm->show_frame)   //do not save for altref frame | ||||
|     /* This frame's MVs are saved and will be used in next frame's MV predictor. | ||||
|      * Last frame has one more line(add to bottom) and one more column(add to | ||||
|      * right) than cm->mip. The edge elements are initialized to 0. | ||||
|      */ | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|     if(!cpi->oxcf.mr_encoder_id && cm->show_frame) | ||||
| #else | ||||
|     if(cm->show_frame)   /* do not save for altref frame */ | ||||
| #endif | ||||
|     { | ||||
|         int mb_row; | ||||
|         int mb_col; | ||||
|         MODE_INFO *tmp = cm->mip; //point to beginning of allocated MODE_INFO arrays. | ||||
|         /* Point to beginning of allocated MODE_INFO arrays. */ | ||||
|         MODE_INFO *tmp = cm->mip; | ||||
|  | ||||
|         if(cm->frame_type != KEY_FRAME) | ||||
|         { | ||||
| @@ -4363,6 +4380,10 @@ static void encode_frame_to_data_rate | ||||
|         } | ||||
|     } | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|     vp8_cal_dissimilarity(cpi); | ||||
| #endif | ||||
|  | ||||
|     // Update the GF useage maps. | ||||
|     // This is done after completing the compression of a frame when all | ||||
|     // modes etc. are finalized but before loop filter | ||||
|   | ||||
| @@ -58,6 +58,9 @@ | ||||
|  | ||||
| #define MAX_PERIODICITY 16 | ||||
|  | ||||
| #define MAX(x,y) (((x)>(y))?(x):(y)) | ||||
| #define MIN(x,y) (((x)<(y))?(x):(y)) | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|     int kf_indicated; | ||||
| @@ -679,6 +682,11 @@ typedef struct VP8_COMP | ||||
|     double total_ssimg_v_in_layer[MAX_LAYERS]; | ||||
|     double total_ssimg_all_in_layer[MAX_LAYERS]; | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|     /* Number of MBs per row at lower-resolution level */ | ||||
|     int    mr_low_res_mb_cols; | ||||
| #endif | ||||
|  | ||||
| } VP8_COMP; | ||||
|  | ||||
| void control_data_rate(VP8_COMP *cpi); | ||||
|   | ||||
| @@ -703,6 +703,14 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, | ||||
|  | ||||
|             if (cpi->sf.search_method == HEX) | ||||
|             { | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|                 /* TODO: In higher-res pick_inter_mode, step_param is used to | ||||
|                  * modify hex search range. Here, set step_param to 0 not to | ||||
|                  * change the behavior in lowest-resolution encoder. | ||||
|                  * Will improve it later. | ||||
|                  */ | ||||
|                 step_param = 0; | ||||
| #endif | ||||
|                 bestsme = vp8_hex_search(x, b, d, &mvp_full, &d->bmi.mv, step_param, | ||||
|                                       sadpb, &cpi->fn_ptr[BLOCK_16X16], | ||||
|                                       x->mvsadcost, x->mvcost, &best_ref_mv); | ||||
| @@ -949,3 +957,568 @@ void vp8_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate_) | ||||
|  | ||||
|     *rate_ = best_rate; | ||||
| } | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
| void vp8_mr_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, | ||||
|                          int recon_uvoffset, int *returnrate, | ||||
|                          int *returndistortion, int *returnintra, int mb_row, | ||||
|                          int mb_col) | ||||
| { | ||||
|     BLOCK *b = &x->block[0]; | ||||
|     BLOCKD *d = &x->e_mbd.block[0]; | ||||
|     MACROBLOCKD *xd = &x->e_mbd; | ||||
|     MB_MODE_INFO best_mbmode; | ||||
|  | ||||
|     int_mv best_ref_mv; | ||||
|     int_mv mode_mv[MB_MODE_COUNT]; | ||||
|     MB_PREDICTION_MODE this_mode; | ||||
|     int num00; | ||||
|     int mdcounts[4]; | ||||
|     int best_rd = INT_MAX; // 1 << 30; | ||||
|     int best_intra_rd = INT_MAX; | ||||
|     int mode_index; | ||||
|     int rate; | ||||
|     int rate2; | ||||
|     int distortion2; | ||||
|     int bestsme; | ||||
|     int best_mode_index = 0; | ||||
|     unsigned int sse = INT_MAX, best_sse = INT_MAX; | ||||
|  | ||||
|     int_mv mvp; | ||||
|     int_mv nearest_mv[4]; | ||||
|     int_mv near_mv[4]; | ||||
|     int_mv frame_best_ref_mv[4]; | ||||
|     int MDCounts[4][4]; | ||||
|     unsigned char *y_buffer[4]; | ||||
|     unsigned char *u_buffer[4]; | ||||
|     unsigned char *v_buffer[4]; | ||||
|     int skip_mode[4] = {0, 0, 0, 0}; | ||||
|     int have_subp_search = cpi->sf.half_pixel_search;  /* In real-time mode, | ||||
|                                        when Speed >= 15, no sub-pixel search. */ | ||||
|     int lfdone=0, gfdone=0, afdone=0; | ||||
|  | ||||
|     LOWER_RES_INFO* store_mode_info | ||||
|                               = (LOWER_RES_INFO*)cpi->oxcf.mr_low_res_mode_info; | ||||
|     unsigned int parent_mb_index; | ||||
|     //unsigned int parent_mb_index = map_640x480_to_320x240[mb_row][mb_col]; | ||||
|     int dissim; | ||||
|     int parent_ref_frame; | ||||
|     int_mv parent_ref_mv; | ||||
|     MB_PREDICTION_MODE parent_mode; | ||||
|  | ||||
|     /* Consider different down_sampling_factor.  */ | ||||
|     { | ||||
|         /* TODO: Removed the loop that supports special down_sampling_factor | ||||
|          * such as 2, 4, 8. Will revisit it if needed. | ||||
|          * Should also try using a look-up table to see if it helps | ||||
|          * performance. */ | ||||
|         int round = cpi->oxcf.mr_down_sampling_factor.num/2; | ||||
|         int parent_mb_row, parent_mb_col; | ||||
|  | ||||
|         parent_mb_row = (mb_row*cpi->oxcf.mr_down_sampling_factor.den+round) | ||||
|                         /cpi->oxcf.mr_down_sampling_factor.num; | ||||
|         parent_mb_col = (mb_col*cpi->oxcf.mr_down_sampling_factor.den+round) | ||||
|                         /cpi->oxcf.mr_down_sampling_factor.num; | ||||
|         parent_mb_index = parent_mb_row*cpi->mr_low_res_mb_cols + parent_mb_col; | ||||
|     } | ||||
|  | ||||
|     /* Read lower-resolution mode & motion result from memory.*/ | ||||
|     parent_ref_frame = store_mode_info[parent_mb_index].ref_frame; | ||||
|     parent_mode =  store_mode_info[parent_mb_index].mode; | ||||
|     dissim = store_mode_info[parent_mb_index].dissim; | ||||
|  | ||||
|     /* For highest-resolution encoder, adjust dissim value. Lower its quality | ||||
|      * for good performance. */ | ||||
|     if (cpi->oxcf.mr_encoder_id == (cpi->oxcf.mr_total_resolutions - 1)) | ||||
|         dissim>>=1; | ||||
|  | ||||
|     if(parent_ref_frame != INTRA_FRAME) | ||||
|     { | ||||
|         /* Consider different down_sampling_factor. | ||||
|          * The result can be rounded to be more precise, but it takes more time. | ||||
|          */ | ||||
|         //int round = cpi->oxcf.mr_down_sampling_factor.den/2; | ||||
|         parent_ref_mv.as_mv.row = store_mode_info[parent_mb_index].mv.as_mv.row | ||||
|                                   *cpi->oxcf.mr_down_sampling_factor.num | ||||
|                                   /cpi->oxcf.mr_down_sampling_factor.den; | ||||
|         parent_ref_mv.as_mv.col = store_mode_info[parent_mb_index].mv.as_mv.col | ||||
|                                   *cpi->oxcf.mr_down_sampling_factor.num | ||||
|                                   /cpi->oxcf.mr_down_sampling_factor.den; | ||||
|  | ||||
|         vp8_clamp_mv2(&parent_ref_mv, xd); | ||||
|     } | ||||
|  | ||||
|     vpx_memset(mode_mv, 0, sizeof(mode_mv)); | ||||
|     vpx_memset(nearest_mv, 0, sizeof(nearest_mv)); | ||||
|     vpx_memset(near_mv, 0, sizeof(near_mv)); | ||||
|     vpx_memset(&best_mbmode, 0, sizeof(best_mbmode)); | ||||
|  | ||||
|     cpi->mbs_tested_so_far++; | ||||
|  | ||||
|     *returnintra = INT_MAX; | ||||
|     x->skip = 0; | ||||
|  | ||||
|     x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; | ||||
|  | ||||
|     // if we encode a new mv this is important | ||||
|     // find the best new motion vector | ||||
|     for (mode_index = 0; mode_index < MAX_MODES; mode_index++) | ||||
|     { | ||||
|         int frame_cost; | ||||
|         int this_rd = INT_MAX; | ||||
|  | ||||
|         if (best_rd <= cpi->rd_threshes[mode_index]) | ||||
|             continue; | ||||
|  | ||||
|         /* If parent MB is intra, child MB is intra. */ | ||||
|         if (!parent_ref_frame && vp8_ref_frame_order[mode_index]) | ||||
|             continue; | ||||
|  | ||||
|         /* If parent MB is inter, and it is unlikely there are multiple objects | ||||
|          * in parent MB, we use parent ref frame as child MB's ref frame. */ | ||||
|         if (parent_ref_frame && dissim < 8 | ||||
|             && parent_ref_frame != vp8_ref_frame_order[mode_index]) | ||||
|             continue; | ||||
|  | ||||
|         x->e_mbd.mode_info_context->mbmi.ref_frame = vp8_ref_frame_order[mode_index]; | ||||
|  | ||||
|         if(x->e_mbd.mode_info_context->mbmi.ref_frame) | ||||
|         { | ||||
|             if(x->e_mbd.mode_info_context->mbmi.ref_frame==LAST_FRAME && !lfdone) | ||||
|             { | ||||
|                 // set up all the refframe dependent pointers. | ||||
|                 //if (x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME | ||||
|                 //&& (cpi->ref_frame_flags & VP8_LAST_FLAG)) | ||||
|                 if (cpi->ref_frame_flags & VP8_LAST_FLAG) | ||||
|                 { | ||||
|                     YV12_BUFFER_CONFIG *lst_yv12 = &cpi->common.yv12_fb[cpi->common.lst_fb_idx]; | ||||
|  | ||||
|                     vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, | ||||
|                         &nearest_mv[LAST_FRAME], &near_mv[LAST_FRAME], | ||||
|                         &frame_best_ref_mv[LAST_FRAME], MDCounts[LAST_FRAME], | ||||
|                         LAST_FRAME, cpi->common.ref_frame_sign_bias); | ||||
|  | ||||
|                     y_buffer[LAST_FRAME] = lst_yv12->y_buffer + recon_yoffset; | ||||
|                     u_buffer[LAST_FRAME] = lst_yv12->u_buffer + recon_uvoffset; | ||||
|                     v_buffer[LAST_FRAME] = lst_yv12->v_buffer + recon_uvoffset; | ||||
|                 } | ||||
|                 else | ||||
|                     skip_mode[LAST_FRAME] = 1; | ||||
|  | ||||
|                 lfdone = 1; | ||||
|             } | ||||
|  | ||||
|             if(x->e_mbd.mode_info_context->mbmi.ref_frame==GOLDEN_FRAME && !gfdone) | ||||
|             { | ||||
|                 //if (x->e_mbd.mode_info_context->mbmi.ref_frame == GOLDEN_FRAME | ||||
|                 //&& (cpi->ref_frame_flags & VP8_GOLD_FLAG)) | ||||
|                 if (cpi->ref_frame_flags & VP8_GOLD_FLAG) | ||||
|                 { | ||||
|                     YV12_BUFFER_CONFIG *gld_yv12 = &cpi->common.yv12_fb[cpi->common.gld_fb_idx]; | ||||
|  | ||||
|                     vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, | ||||
|                         &nearest_mv[GOLDEN_FRAME], &near_mv[GOLDEN_FRAME], | ||||
|                         &frame_best_ref_mv[GOLDEN_FRAME],MDCounts[GOLDEN_FRAME], | ||||
|                         GOLDEN_FRAME, cpi->common.ref_frame_sign_bias); | ||||
|  | ||||
|                     y_buffer[GOLDEN_FRAME] = gld_yv12->y_buffer + recon_yoffset; | ||||
|                     u_buffer[GOLDEN_FRAME] = gld_yv12->u_buffer + recon_uvoffset; | ||||
|                     v_buffer[GOLDEN_FRAME] = gld_yv12->v_buffer + recon_uvoffset; | ||||
|                 } | ||||
|                 else | ||||
|                     skip_mode[GOLDEN_FRAME] = 1; | ||||
|  | ||||
|                 gfdone = 1; | ||||
|             } | ||||
|  | ||||
|             if(x->e_mbd.mode_info_context->mbmi.ref_frame==ALTREF_FRAME && !afdone) | ||||
|             { | ||||
|                 //if (x->e_mbd.mode_info_context->mbmi.ref_frame == ALTREF_FRAME | ||||
|                 //&& (cpi->ref_frame_flags & VP8_ALT_FLAG && cpi->source_alt_ref_active)) | ||||
|                 if (cpi->ref_frame_flags & VP8_ALT_FLAG && cpi->source_alt_ref_active) | ||||
|                 { | ||||
|                     YV12_BUFFER_CONFIG *alt_yv12 = &cpi->common.yv12_fb[cpi->common.alt_fb_idx]; | ||||
|  | ||||
|                     vp8_find_near_mvs(&x->e_mbd, x->e_mbd.mode_info_context, | ||||
|                         &nearest_mv[ALTREF_FRAME], &near_mv[ALTREF_FRAME], | ||||
|                         &frame_best_ref_mv[ALTREF_FRAME],MDCounts[ALTREF_FRAME], | ||||
|                         ALTREF_FRAME, cpi->common.ref_frame_sign_bias); | ||||
|  | ||||
|                     y_buffer[ALTREF_FRAME] = alt_yv12->y_buffer + recon_yoffset; | ||||
|                     u_buffer[ALTREF_FRAME] = alt_yv12->u_buffer + recon_uvoffset; | ||||
|                     v_buffer[ALTREF_FRAME] = alt_yv12->v_buffer + recon_uvoffset; | ||||
|                 } | ||||
|                 else | ||||
|                     skip_mode[ALTREF_FRAME] = 1; | ||||
|  | ||||
|                 afdone = 1; | ||||
|             } | ||||
|  | ||||
|             if (skip_mode[x->e_mbd.mode_info_context->mbmi.ref_frame]) | ||||
|                 continue; | ||||
|  | ||||
|             x->e_mbd.pre.y_buffer = y_buffer[x->e_mbd.mode_info_context->mbmi.ref_frame]; | ||||
|             x->e_mbd.pre.u_buffer = u_buffer[x->e_mbd.mode_info_context->mbmi.ref_frame]; | ||||
|             x->e_mbd.pre.v_buffer = v_buffer[x->e_mbd.mode_info_context->mbmi.ref_frame]; | ||||
|             mode_mv[NEARESTMV] = nearest_mv[x->e_mbd.mode_info_context->mbmi.ref_frame]; | ||||
|             mode_mv[NEARMV] = near_mv[x->e_mbd.mode_info_context->mbmi.ref_frame]; | ||||
|             best_ref_mv = frame_best_ref_mv[x->e_mbd.mode_info_context->mbmi.ref_frame]; | ||||
|             memcpy(mdcounts, MDCounts[x->e_mbd.mode_info_context->mbmi.ref_frame], sizeof(mdcounts)); | ||||
|  | ||||
|             if (vp8_mode_order[mode_index] == NEARESTMV && mode_mv[NEARESTMV].as_int ==0) | ||||
|                 continue; | ||||
|             if (vp8_mode_order[mode_index] == NEARMV && mode_mv[NEARMV].as_int ==0) | ||||
|                 continue; | ||||
|  | ||||
|             if (vp8_mode_order[mode_index] == NEWMV && parent_mode == ZEROMV | ||||
|                 && best_ref_mv.as_int==0) //&& dissim==0 | ||||
|                 continue; | ||||
|             else if(vp8_mode_order[mode_index] == NEWMV && dissim==0 | ||||
|                 && best_ref_mv.as_int==parent_ref_mv.as_int) | ||||
|                 continue; | ||||
|         } | ||||
|  | ||||
|         // Check to see if the testing frequency for this mode is at its max | ||||
|         // If so then prevent it from being tested and increase the threshold for its testing | ||||
|         if (cpi->mode_test_hit_counts[mode_index] && (cpi->mode_check_freq[mode_index] > 1)) | ||||
|         { | ||||
|             //if ( (cpi->mbs_tested_so_far / cpi->mode_test_hit_counts[mode_index]) <= cpi->mode_check_freq[mode_index] ) | ||||
|             if (cpi->mbs_tested_so_far <= (cpi->mode_check_freq[mode_index] * cpi->mode_test_hit_counts[mode_index])) | ||||
|             { | ||||
|                 // Increase the threshold for coding this mode to make it less likely to be chosen | ||||
|                 cpi->rd_thresh_mult[mode_index] += 4; | ||||
|  | ||||
|                 if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) | ||||
|                     cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; | ||||
|  | ||||
|                 cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // We have now reached the point where we are going to test the current | ||||
|         //mode so increment the counter for the number of times it has been tested | ||||
|         cpi->mode_test_hit_counts[mode_index] ++; | ||||
|  | ||||
|         rate2 = 0; | ||||
|         distortion2 = 0; | ||||
|  | ||||
|         this_mode = vp8_mode_order[mode_index]; | ||||
|  | ||||
|         x->e_mbd.mode_info_context->mbmi.mode = this_mode; | ||||
|         x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; | ||||
|  | ||||
|         // Work out the cost assosciated with selecting the reference frame | ||||
|         frame_cost = | ||||
|             x->e_mbd.ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; | ||||
|         rate2 += frame_cost; | ||||
|  | ||||
|         // Only consider ZEROMV/ALTREF_FRAME for alt ref frame, | ||||
|         // unless ARNR filtering is enabled in which case we want | ||||
|         // an unfiltered alternative | ||||
|         if (cpi->is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) | ||||
|         { | ||||
|             if (this_mode != ZEROMV || x->e_mbd.mode_info_context->mbmi.ref_frame != ALTREF_FRAME) | ||||
|                 continue; | ||||
|         } | ||||
|  | ||||
|         switch (this_mode) | ||||
|         { | ||||
|           case B_PRED: | ||||
|               // Pass best so far to pick_intra4x4mby_modes to use as breakout | ||||
|               distortion2 = best_sse; | ||||
|               pick_intra4x4mby_modes(IF_RTCD(&cpi->rtcd), x, &rate, &distortion2); | ||||
|  | ||||
|               if (distortion2 == INT_MAX) | ||||
|               { | ||||
|                   this_rd = INT_MAX; | ||||
|               } | ||||
|               else | ||||
|               { | ||||
|                   rate2 += rate; | ||||
|                   distortion2 = VARIANCE_INVOKE | ||||
|                                   (&cpi->rtcd.variance, var16x16)( | ||||
|                                       *(b->base_src), b->src_stride, | ||||
|                                       x->e_mbd.predictor, 16, &sse); | ||||
|                   this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); | ||||
|  | ||||
|                   if (this_rd < best_intra_rd) | ||||
|                   { | ||||
|                       best_intra_rd = this_rd; | ||||
|                       *returnintra = distortion2; | ||||
|                   } | ||||
|               } | ||||
|  | ||||
|               break; | ||||
|  | ||||
|           case DC_PRED: | ||||
|           case V_PRED: | ||||
|           case H_PRED: | ||||
|           case TM_PRED: | ||||
|               RECON_INVOKE(&cpi->common.rtcd.recon, build_intra_predictors_mby) | ||||
|                   (&x->e_mbd); | ||||
|               distortion2 = VARIANCE_INVOKE(&cpi->rtcd.variance, var16x16) | ||||
|                                             (*(b->base_src), b->src_stride, | ||||
|                                             x->e_mbd.predictor, 16, &sse); | ||||
|               rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode]; | ||||
|               this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); | ||||
|  | ||||
|               if (this_rd < best_intra_rd) | ||||
|               { | ||||
|                   best_intra_rd = this_rd; | ||||
|                   *returnintra = distortion2; | ||||
|               } | ||||
|               break; | ||||
|  | ||||
|         case NEWMV: | ||||
|         { | ||||
|             int thissme; | ||||
|             int step_param; | ||||
|             int further_steps; | ||||
|             int n = 0; | ||||
|             int sadpb = x->sadperbit16; | ||||
|             int_mv mvp_full; | ||||
|  | ||||
|             int col_min = (best_ref_mv.as_mv.col>>3) - MAX_FULL_PEL_VAL | ||||
|                         + ((best_ref_mv.as_mv.col & 7)?1:0); | ||||
|             int row_min = (best_ref_mv.as_mv.row>>3) - MAX_FULL_PEL_VAL | ||||
|                         + ((best_ref_mv.as_mv.row & 7)?1:0); | ||||
|             int col_max = (best_ref_mv.as_mv.col>>3) + MAX_FULL_PEL_VAL; | ||||
|             int row_max = (best_ref_mv.as_mv.row>>3) + MAX_FULL_PEL_VAL; | ||||
|  | ||||
|             int tmp_col_min = x->mv_col_min; | ||||
|             int tmp_col_max = x->mv_col_max; | ||||
|             int tmp_row_min = x->mv_row_min; | ||||
|             int tmp_row_max = x->mv_row_max; | ||||
|  | ||||
|             int speed_adjust = (cpi->Speed > 5) ? ((cpi->Speed >= 8)? 3 : 2) : 1; | ||||
|             int diff_mv = MAX(abs(best_ref_mv.as_mv.row - parent_ref_mv.as_mv.row), | ||||
|                               abs(best_ref_mv.as_mv.col - parent_ref_mv.as_mv.col)); | ||||
|  | ||||
|             // Further step/diamond searches as necessary | ||||
|             step_param = cpi->sf.first_step + speed_adjust;   //sf->first_step = 1; for -6 step_param =3; | ||||
|  | ||||
|             // Use parent MV as predictor. Adjust search range accordingly. | ||||
|             mvp.as_int = parent_ref_mv.as_int; | ||||
|             mvp_full.as_mv.col = parent_ref_mv.as_mv.col>>3; | ||||
|             mvp_full.as_mv.row = parent_ref_mv.as_mv.row>>3; | ||||
|  | ||||
|             if(dissim <=32) step_param += 3; | ||||
|             else if(dissim <=128) step_param += 2; | ||||
|             else step_param += 1; | ||||
|  | ||||
|             if(dissim >2 || diff_mv >4) | ||||
|             { | ||||
|                 /* Get intersection of UMV window and valid MV window to | ||||
|                  * reduce # of checks in diamond search. */ | ||||
|                 if (x->mv_col_min < col_min ) | ||||
|                     x->mv_col_min = col_min; | ||||
|                 if (x->mv_col_max > col_max ) | ||||
|                     x->mv_col_max = col_max; | ||||
|                 if (x->mv_row_min < row_min ) | ||||
|                     x->mv_row_min = row_min; | ||||
|                 if (x->mv_row_max > row_max ) | ||||
|                     x->mv_row_max = row_max; | ||||
|  | ||||
|                 further_steps = (cpi->Speed >= 8)? | ||||
|                            0: (cpi->sf.max_step_search_steps - 1 - step_param); | ||||
|  | ||||
|                 if (cpi->sf.search_method == HEX) | ||||
|                 { | ||||
|                     bestsme = vp8_hex_search(x, b, d, &mvp_full, &d->bmi.mv, step_param, | ||||
|                                           sadpb, &cpi->fn_ptr[BLOCK_16X16], | ||||
|                                           x->mvsadcost, x->mvcost, &best_ref_mv); | ||||
|                     mode_mv[NEWMV].as_int = d->bmi.mv.as_int; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     bestsme = cpi->diamond_search_sad(x, b, d, &mvp_full, &d->bmi.mv, | ||||
|                                           step_param, sadpb, &num00, | ||||
|                                           &cpi->fn_ptr[BLOCK_16X16], | ||||
|                                           x->mvcost, &best_ref_mv); | ||||
|                     mode_mv[NEWMV].as_int = d->bmi.mv.as_int; | ||||
|  | ||||
|                     // Further step/diamond searches as necessary | ||||
|                     n = 0; | ||||
|                     //further_steps = (cpi->sf.max_step_search_steps - 1) - step_param; | ||||
|  | ||||
|                     n = num00; | ||||
|                     num00 = 0; | ||||
|  | ||||
|                     while (n < further_steps) | ||||
|                     { | ||||
|                         n++; | ||||
|  | ||||
|                         if (num00) | ||||
|                             num00--; | ||||
|                         else | ||||
|                         { | ||||
|                             thissme = | ||||
|                             cpi->diamond_search_sad(x, b, d, &mvp_full, | ||||
|                                                     &d->bmi.mv, | ||||
|                                                     step_param + n, | ||||
|                                                     sadpb, &num00, | ||||
|                                                     &cpi->fn_ptr[BLOCK_16X16], | ||||
|                                                     x->mvcost, &best_ref_mv); | ||||
|                             if (thissme < bestsme) | ||||
|                             { | ||||
|                                 bestsme = thissme; | ||||
|                                 mode_mv[NEWMV].as_int = d->bmi.mv.as_int; | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 d->bmi.mv.as_int = mode_mv[NEWMV].as_int; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 x->mv_col_min = tmp_col_min; | ||||
|                 x->mv_col_max = tmp_col_max; | ||||
|                 x->mv_row_min = tmp_row_min; | ||||
|                 x->mv_row_max = tmp_row_max; | ||||
|             }else | ||||
|             { | ||||
|                 d->bmi.mv.as_int = mvp_full.as_int; | ||||
|                 mode_mv[NEWMV].as_int = mvp_full.as_int; | ||||
|             } | ||||
|  | ||||
|             // This is not needed. | ||||
|             //if (bestsme < INT_MAX) | ||||
|                 cpi->find_fractional_mv_step(x, b, d, &d->bmi.mv, &best_ref_mv, | ||||
|                                              x->errorperbit, | ||||
|                                              &cpi->fn_ptr[BLOCK_16X16], | ||||
|                                              cpi->mb.mvcost, | ||||
|                                              &distortion2,&sse); | ||||
|  | ||||
|             mode_mv[NEWMV].as_int = d->bmi.mv.as_int; | ||||
|  | ||||
|             // mv cost; | ||||
|             rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, cpi->mb.mvcost, 128); | ||||
|         } | ||||
|  | ||||
|         case NEARESTMV: | ||||
|         case NEARMV: | ||||
|           // Trap vectors that reach beyond the UMV borders | ||||
|           // Note that ALL New MV, Nearest MV Near MV and Zero MV code drops | ||||
|           // through to this point because of the lack of break statements | ||||
|           // in the previous two cases. | ||||
|           if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) || | ||||
|               ((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) || | ||||
|               ((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || | ||||
|               ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max)) | ||||
|               continue; | ||||
|  | ||||
|         case ZEROMV: | ||||
|             rate2 += vp8_cost_mv_ref(this_mode, mdcounts); | ||||
|             x->e_mbd.mode_info_context->mbmi.mv.as_int = | ||||
|                                                     mode_mv[this_mode].as_int; | ||||
|  | ||||
|             if((this_mode != NEWMV) || | ||||
|                 !(have_subp_search) || cpi->common.full_pixel==1) | ||||
|                 distortion2 = get_inter_mbpred_error(x, | ||||
|                                                      &cpi->fn_ptr[BLOCK_16X16], | ||||
|                                                      &sse, mode_mv[this_mode]); | ||||
|  | ||||
|             this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); | ||||
|  | ||||
|             if (cpi->active_map_enabled && x->active_ptr[0] == 0) | ||||
|             { | ||||
|                 x->skip = 1; | ||||
|             } | ||||
|             else if (sse < x->encode_breakout) | ||||
|             { | ||||
|                 // Check u and v to make sure skip is ok | ||||
|                 int sse2 = 0; | ||||
|  | ||||
|                 sse2 = VP8_UVSSE(x, IF_RTCD(&cpi->rtcd.variance)); | ||||
|  | ||||
|                 if (sse2 * 2 < x->encode_breakout) | ||||
|                     x->skip = 1; | ||||
|                 else | ||||
|                     x->skip = 0; | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         if (this_rd < best_rd || x->skip) | ||||
|         { | ||||
|             // Note index of best mode | ||||
|             best_mode_index = mode_index; | ||||
|  | ||||
|             *returnrate = rate2; | ||||
|             *returndistortion = distortion2; | ||||
|             best_sse = sse; | ||||
|             best_rd = this_rd; | ||||
|             vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO)); | ||||
|  | ||||
|             // Testing this mode gave rise to an improvement in best error score. Lower threshold a bit for next time | ||||
|             cpi->rd_thresh_mult[mode_index] = (cpi->rd_thresh_mult[mode_index] >= (MIN_THRESHMULT + 2)) ? cpi->rd_thresh_mult[mode_index] - 2 : MIN_THRESHMULT; | ||||
|             cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; | ||||
|         } | ||||
|         // If the mode did not help improve the best error case then raise the threshold for testing that mode next time around. | ||||
|         else | ||||
|         { | ||||
|             cpi->rd_thresh_mult[mode_index] += 4; | ||||
|  | ||||
|             if (cpi->rd_thresh_mult[mode_index] > MAX_THRESHMULT) | ||||
|                 cpi->rd_thresh_mult[mode_index] = MAX_THRESHMULT; | ||||
|  | ||||
|             cpi->rd_threshes[mode_index] = (cpi->rd_baseline_thresh[mode_index] >> 7) * cpi->rd_thresh_mult[mode_index]; | ||||
|         } | ||||
|  | ||||
|         if (x->skip) | ||||
|             break; | ||||
|     } | ||||
|  | ||||
|     // Reduce the activation RD thresholds for the best choice mode | ||||
|     if ((cpi->rd_baseline_thresh[best_mode_index] > 0) && (cpi->rd_baseline_thresh[best_mode_index] < (INT_MAX >> 2))) | ||||
|     { | ||||
|         int best_adjustment = (cpi->rd_thresh_mult[best_mode_index] >> 3); | ||||
|  | ||||
|         cpi->rd_thresh_mult[best_mode_index] = (cpi->rd_thresh_mult[best_mode_index] >= (MIN_THRESHMULT + best_adjustment)) ? cpi->rd_thresh_mult[best_mode_index] - best_adjustment : MIN_THRESHMULT; | ||||
|         cpi->rd_threshes[best_mode_index] = (cpi->rd_baseline_thresh[best_mode_index] >> 7) * cpi->rd_thresh_mult[best_mode_index]; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     { | ||||
|         int this_rdbin = (*returndistortion >> 7); | ||||
|  | ||||
|         if (this_rdbin >= 1024) | ||||
|         { | ||||
|             this_rdbin = 1023; | ||||
|         } | ||||
|  | ||||
|         cpi->error_bins[this_rdbin] ++; | ||||
|     } | ||||
|  | ||||
|     if (cpi->is_src_frame_alt_ref && | ||||
|         (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME)) | ||||
|     { | ||||
|         x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; | ||||
|         x->e_mbd.mode_info_context->mbmi.ref_frame = ALTREF_FRAME; | ||||
|         x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; | ||||
|         x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; | ||||
|         x->e_mbd.mode_info_context->mbmi.mb_skip_coeff = | ||||
|                                         (cpi->common.mb_no_coeff_skip) ? 1 : 0; | ||||
|         x->e_mbd.mode_info_context->mbmi.partitioning = 0; | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /* set to the best mb mode */ | ||||
|     vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mbmode, sizeof(MB_MODE_INFO)); | ||||
|  | ||||
|     if (best_mbmode.mode <= B_PRED) | ||||
|     { | ||||
|         /* set mode_info_context->mbmi.uv_mode */ | ||||
|         pick_intra_mbuv_mode(x); | ||||
|     } | ||||
|  | ||||
|     update_mvcount(cpi, &x->e_mbd, &frame_best_ref_mv[xd->mode_info_context->mbmi.ref_frame]); | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -14,6 +14,16 @@ | ||||
| #include "vpx_config.h" | ||||
| #include "vp8/common/onyxc_int.h" | ||||
|  | ||||
| extern void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra); | ||||
| extern void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, | ||||
|                                 int recon_uvoffset, int *returnrate, | ||||
|                                 int *returndistortion, int *returnintra); | ||||
| extern void vp8_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate); | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
| extern void vp8_mr_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, | ||||
|                                    int recon_yoffset, int recon_uvoffset, | ||||
|                                    int *returnrate, int *returndistortion, | ||||
|                                    int *returnintra, int mb_row, int mb_col); | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1463,57 +1463,6 @@ static int vp8_rd_pick_best_mbsegmentation(VP8_COMP *cpi, MACROBLOCK *x, | ||||
|     return bsi.segment_rd; | ||||
| } | ||||
|  | ||||
| static void insertsortmv(int arr[], int len) | ||||
| { | ||||
|     int i, j, k; | ||||
|  | ||||
|     for ( i = 1 ; i <= len-1 ; i++ ) | ||||
|     { | ||||
|         for ( j = 0 ; j < i ; j++ ) | ||||
|         { | ||||
|             if ( arr[j] > arr[i] ) | ||||
|             { | ||||
|                 int temp; | ||||
|  | ||||
|                 temp = arr[i]; | ||||
|  | ||||
|                 for ( k = i; k >j; k--) | ||||
|                     arr[k] = arr[k - 1] ; | ||||
|  | ||||
|                 arr[j] = temp ; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void insertsortsad(int arr[],int idx[], int len) | ||||
| { | ||||
|     int i, j, k; | ||||
|  | ||||
|     for ( i = 1 ; i <= len-1 ; i++ ) | ||||
|     { | ||||
|         for ( j = 0 ; j < i ; j++ ) | ||||
|         { | ||||
|             if ( arr[j] > arr[i] ) | ||||
|             { | ||||
|                 int temp, tempi; | ||||
|  | ||||
|                 temp = arr[i]; | ||||
|                 tempi = idx[i]; | ||||
|  | ||||
|                 for ( k = i; k >j; k--) | ||||
|                 { | ||||
|                     arr[k] = arr[k - 1] ; | ||||
|                     idx[k] = idx[k - 1]; | ||||
|                 } | ||||
|  | ||||
|                 arr[j] = temp ; | ||||
|                 idx[j] = tempi; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| //The improved MV prediction | ||||
| void vp8_mv_pred | ||||
| ( | ||||
|   | ||||
| @@ -14,6 +14,57 @@ | ||||
|  | ||||
| #define RDCOST(RM,DM,R,D) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) | ||||
|  | ||||
| static void insertsortmv(int arr[], int len) | ||||
| { | ||||
|     int i, j, k; | ||||
|  | ||||
|     for ( i = 1 ; i <= len-1 ; i++ ) | ||||
|     { | ||||
|         for ( j = 0 ; j < i ; j++ ) | ||||
|         { | ||||
|             if ( arr[j] > arr[i] ) | ||||
|             { | ||||
|                 int temp; | ||||
|  | ||||
|                 temp = arr[i]; | ||||
|  | ||||
|                 for ( k = i; k >j; k--) | ||||
|                     arr[k] = arr[k - 1] ; | ||||
|  | ||||
|                 arr[j] = temp ; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void insertsortsad(int arr[],int idx[], int len) | ||||
| { | ||||
|     int i, j, k; | ||||
|  | ||||
|     for ( i = 1 ; i <= len-1 ; i++ ) | ||||
|     { | ||||
|         for ( j = 0 ; j < i ; j++ ) | ||||
|         { | ||||
|             if ( arr[j] > arr[i] ) | ||||
|             { | ||||
|                 int temp, tempi; | ||||
|  | ||||
|                 temp = arr[i]; | ||||
|                 tempi = idx[i]; | ||||
|  | ||||
|                 for ( k = i; k >j; k--) | ||||
|                 { | ||||
|                     arr[k] = arr[k - 1] ; | ||||
|                     idx[k] = idx[k - 1]; | ||||
|                 } | ||||
|  | ||||
|                 arr[j] = temp ; | ||||
|                 idx[j] = tempi; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| extern void vp8_initialize_rd_consts(VP8_COMP *cpi, int Qvalue); | ||||
| extern void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, int *returndistortion, int *returnintra); | ||||
| extern void vp8_rd_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate); | ||||
|   | ||||
| @@ -264,7 +264,8 @@ static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx, | ||||
|  | ||||
| static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, | ||||
|                                        vpx_codec_enc_cfg_t cfg, | ||||
|                                        struct vp8_extracfg vp8_cfg) | ||||
|                                        struct vp8_extracfg vp8_cfg, | ||||
|                                        vpx_codec_priv_enc_mr_cfg_t *mr_cfg) | ||||
| { | ||||
|     oxcf->multi_threaded         = cfg.g_threads; | ||||
|     oxcf->Version               = cfg.g_profile; | ||||
| @@ -355,6 +356,17 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, | ||||
|         memcpy (oxcf->layer_id, cfg.ts_layer_id, sizeof(cfg.ts_layer_id)); | ||||
|     } | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|     if(mr_cfg) | ||||
|     { | ||||
|         oxcf->mr_total_resolutions        = mr_cfg->mr_total_resolutions; | ||||
|         oxcf->mr_encoder_id               = mr_cfg->mr_encoder_id; | ||||
|         oxcf->mr_down_sampling_factor.num = mr_cfg->mr_down_sampling_factor.num; | ||||
|         oxcf->mr_down_sampling_factor.den = mr_cfg->mr_down_sampling_factor.den; | ||||
|         oxcf->mr_low_res_mode_info        = mr_cfg->mr_low_res_mode_info; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     //oxcf->delete_first_pass_file = cfg.g_delete_firstpassfile; | ||||
|     //strcpy(oxcf->first_pass_file, cfg.g_firstpass_file); | ||||
|  | ||||
| @@ -432,7 +444,7 @@ static vpx_codec_err_t vp8e_set_config(vpx_codec_alg_priv_t       *ctx, | ||||
|     if (!res) | ||||
|     { | ||||
|         ctx->cfg = *cfg; | ||||
|         set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg); | ||||
|         set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg, NULL); | ||||
|         vp8_change_config(ctx->cpi, &ctx->oxcf); | ||||
|     } | ||||
|  | ||||
| @@ -498,14 +510,38 @@ static vpx_codec_err_t set_param(vpx_codec_alg_priv_t *ctx, | ||||
|     if (!res) | ||||
|     { | ||||
|         ctx->vp8_cfg = xcfg; | ||||
|         set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg); | ||||
|         set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg, NULL); | ||||
|         vp8_change_config(ctx->cpi, &ctx->oxcf); | ||||
|     } | ||||
|  | ||||
|     return res; | ||||
| #undef MAP | ||||
| } | ||||
| static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx) | ||||
|  | ||||
| static vpx_codec_err_t vp8e_mr_alloc_mem(const vpx_codec_enc_cfg_t *cfg, | ||||
|                                         void **mem_loc) | ||||
| { | ||||
|     vpx_codec_err_t res = 0; | ||||
|  | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|     int mb_rows = ((cfg->g_w + 15) >>4); | ||||
|     int mb_cols = ((cfg->g_h + 15) >>4); | ||||
|  | ||||
|     *mem_loc = calloc(mb_rows*mb_cols, sizeof(LOWER_RES_INFO)); | ||||
|     if(!(*mem_loc)) | ||||
|     { | ||||
|         free(*mem_loc); | ||||
|         res = VPX_CODEC_MEM_ERROR; | ||||
|     } | ||||
|     else | ||||
|         res = VPX_CODEC_OK; | ||||
| #endif | ||||
|  | ||||
|     return res; | ||||
| } | ||||
|  | ||||
| static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx, | ||||
|                                  vpx_codec_priv_enc_mr_cfg_t *mr_cfg) | ||||
| { | ||||
|     vpx_codec_err_t        res = VPX_DEC_OK; | ||||
|     struct vpx_codec_alg_priv *priv; | ||||
| @@ -570,9 +606,16 @@ static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx) | ||||
|  | ||||
|         if (!res) | ||||
|         { | ||||
|             if(mr_cfg) | ||||
|                 ctx->priv->enc.total_encoders   = mr_cfg->mr_total_resolutions; | ||||
|             else | ||||
|                 ctx->priv->enc.total_encoders   = 1; | ||||
|  | ||||
|             set_vp8e_config(&ctx->priv->alg_priv->oxcf, | ||||
|                              ctx->priv->alg_priv->cfg, | ||||
|                              ctx->priv->alg_priv->vp8_cfg); | ||||
|                              ctx->priv->alg_priv->vp8_cfg, | ||||
|                              mr_cfg); | ||||
|  | ||||
|             optr = vp8_create_compressor(&ctx->priv->alg_priv->oxcf); | ||||
|  | ||||
|             if (!optr) | ||||
| @@ -587,6 +630,11 @@ static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx) | ||||
|  | ||||
| static vpx_codec_err_t vp8e_destroy(vpx_codec_alg_priv_t *ctx) | ||||
| { | ||||
| #if CONFIG_MULTI_RES_ENCODING | ||||
|     /* Free multi-encoder shared memory */ | ||||
|     if (ctx->oxcf.mr_total_resolutions > 0 && (ctx->oxcf.mr_encoder_id == ctx->oxcf.mr_total_resolutions-1)) | ||||
|         free(ctx->oxcf.mr_low_res_mode_info); | ||||
| #endif | ||||
|  | ||||
|     free(ctx->cx_data); | ||||
|     vp8_remove_compressor(&ctx->cpi); | ||||
| @@ -1223,6 +1271,7 @@ CODEC_INTERFACE(vpx_codec_vp8_cx) = | ||||
|         vp8e_set_config, | ||||
|         NOT_IMPLEMENTED, | ||||
|         vp8e_get_preview, | ||||
|         vp8e_mr_alloc_mem, | ||||
|     } /* encoder functions */ | ||||
| }; | ||||
|  | ||||
| @@ -1307,5 +1356,6 @@ vpx_codec_iface_t vpx_enc_vp8_algo = | ||||
|         vp8e_set_config, | ||||
|         NOT_IMPLEMENTED, | ||||
|         vp8e_get_preview, | ||||
|         vp8e_mr_alloc_mem, | ||||
|     } /* encoder functions */ | ||||
| }; | ||||
|   | ||||
| @@ -181,9 +181,11 @@ static void vp8_finalize_mmaps(vpx_codec_alg_priv_t *ctx) | ||||
|     /* nothing to clean up */ | ||||
| } | ||||
|  | ||||
| static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx) | ||||
| static vpx_codec_err_t vp8_init(vpx_codec_ctx_t *ctx, | ||||
|                                 vpx_codec_priv_enc_mr_cfg_t *data) | ||||
| { | ||||
|     vpx_codec_err_t        res = VPX_CODEC_OK; | ||||
|     (void) data; | ||||
|  | ||||
|     /* This function only allocates space for the vpx_codec_alg_priv_t | ||||
|      * structure. More memory may be required at the time the stream | ||||
| @@ -564,7 +566,7 @@ static vpx_codec_err_t vp8_xma_set_mmap(vpx_codec_ctx_t         *ctx, | ||||
|     if (done && !res) | ||||
|     { | ||||
|         vp8_finalize_mmaps(ctx->priv->alg_priv); | ||||
|         res = ctx->iface->init(ctx); | ||||
|         res = ctx->iface->init(ctx, NULL); | ||||
|     } | ||||
|  | ||||
|     return res; | ||||
|   | ||||
| @@ -86,6 +86,8 @@ VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/postproc.h | ||||
| VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/postproc.c | ||||
| VP8_CX_SRCS-yes += encoder/temporal_filter.c | ||||
| VP8_CX_SRCS-yes += encoder/temporal_filter.h | ||||
| VP8_CX_SRCS-$(CONFIG_MULTI_RES_ENCODING) += encoder/mr_dissim.c | ||||
| VP8_CX_SRCS-$(CONFIG_MULTI_RES_ENCODING) += encoder/mr_dissim.h | ||||
|  | ||||
| ifeq ($(CONFIG_REALTIME_ONLY),yes) | ||||
| VP8_CX_SRCS_REMOVE-yes += encoder/firstpass.c | ||||
|   | ||||
							
								
								
									
										420
									
								
								vp8_multi_resolution_encoder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										420
									
								
								vp8_multi_resolution_encoder.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,420 @@ | ||||
| /* | ||||
|  *  Copyright (c) 2010 The WebM 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. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This is an example demonstrating multi-resolution encoding in VP8. | ||||
|  * High-resolution input video is down-sampled to lower-resolutions. The | ||||
|  * encoder then encodes the video and outputs multiple bitstreams with | ||||
|  * different resolutions. | ||||
|  */ | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdarg.h> | ||||
| #include <string.h> | ||||
| #include "math.h" | ||||
| #define VPX_CODEC_DISABLE_COMPAT 1 | ||||
| #include "vpx/vpx_encoder.h" | ||||
| #include "vpx/vp8cx.h" | ||||
| #include "vpx_ports/mem_ops.h" | ||||
| #define interface (vpx_codec_vp8_cx()) | ||||
| #define fourcc    0x30385056 | ||||
|  | ||||
| #define IVF_FILE_HDR_SZ  (32) | ||||
| #define IVF_FRAME_HDR_SZ (12) | ||||
|  | ||||
| /* | ||||
|  * The input video frame is downsampled several times to generate a multi-level | ||||
|  * hierarchical structure. NUM_ENCODERS is defined as the number of encoding | ||||
|  * levels required. For example, if the size of input video is 1280x720, | ||||
|  * NUM_ENCODERS is 3, and down-sampling factor is 2, the encoder outputs 3 | ||||
|  * bitstreams with resolution of 1280x720(level 0), 640x360(level 1), and | ||||
|  * 320x180(level 2) respectively. | ||||
|  */ | ||||
| #define NUM_ENCODERS 3 | ||||
|  | ||||
| /* This example uses the scaler function in libyuv. */ | ||||
| #include "third_party/libyuv/include/libyuv/basic_types.h" | ||||
| #include "third_party/libyuv/include/libyuv/scale.h" | ||||
| #include "third_party/libyuv/include/libyuv/cpu_id.h" | ||||
|  | ||||
| static double vp8_mse2psnr(double Samples, double Peak, double Mse) | ||||
| { | ||||
|     double psnr; | ||||
|  | ||||
|     if ((double)Mse > 0.0) | ||||
|         psnr = 10.0 * log10(Peak * Peak * Samples / Mse); | ||||
|     else | ||||
|         psnr = 60;      // Limit to prevent / 0 | ||||
|  | ||||
|     if (psnr > 60) | ||||
|         psnr = 60; | ||||
|  | ||||
|     return psnr; | ||||
| } | ||||
|  | ||||
| static void die(const char *fmt, ...) { | ||||
|     va_list ap; | ||||
|  | ||||
|     va_start(ap, fmt); | ||||
|     vprintf(fmt, ap); | ||||
|     if(fmt[strlen(fmt)-1] != '\n') | ||||
|         printf("\n"); | ||||
|     exit(EXIT_FAILURE); | ||||
| } | ||||
|  | ||||
| static void die_codec(vpx_codec_ctx_t *ctx, const char *s) { | ||||
|     const char *detail = vpx_codec_error_detail(ctx); | ||||
|  | ||||
|     printf("%s: %s\n", s, vpx_codec_error(ctx)); | ||||
|     if(detail) | ||||
|         printf("    %s\n",detail); | ||||
|     exit(EXIT_FAILURE); | ||||
| } | ||||
|  | ||||
| static int read_frame(FILE *f, vpx_image_t *img) { | ||||
|     size_t nbytes, to_read; | ||||
|     int    res = 1; | ||||
|  | ||||
|     to_read = img->w*img->h*3/2; | ||||
|     nbytes = fread(img->planes[0], 1, to_read, f); | ||||
|     if(nbytes != to_read) { | ||||
|         res = 0; | ||||
|         if(nbytes > 0) | ||||
|             printf("Warning: Read partial frame. Check your width & height!\n"); | ||||
|     } | ||||
|     return res; | ||||
| } | ||||
|  | ||||
| static void write_ivf_file_header(FILE *outfile, | ||||
|                                   const vpx_codec_enc_cfg_t *cfg, | ||||
|                                   int frame_cnt) { | ||||
|     char header[32]; | ||||
|  | ||||
|     if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) | ||||
|         return; | ||||
|     header[0] = 'D'; | ||||
|     header[1] = 'K'; | ||||
|     header[2] = 'I'; | ||||
|     header[3] = 'F'; | ||||
|     mem_put_le16(header+4,  0);                   /* version */ | ||||
|     mem_put_le16(header+6,  32);                  /* headersize */ | ||||
|     mem_put_le32(header+8,  fourcc);              /* headersize */ | ||||
|     mem_put_le16(header+12, cfg->g_w);            /* width */ | ||||
|     mem_put_le16(header+14, cfg->g_h);            /* height */ | ||||
|     mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ | ||||
|     mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ | ||||
|     mem_put_le32(header+24, frame_cnt);           /* length */ | ||||
|     mem_put_le32(header+28, 0);                   /* unused */ | ||||
|  | ||||
|     if(fwrite(header, 1, 32, outfile)); | ||||
| } | ||||
|  | ||||
| static void write_ivf_frame_header(FILE *outfile, | ||||
|                                    const vpx_codec_cx_pkt_t *pkt) | ||||
| { | ||||
|     char             header[12]; | ||||
|     vpx_codec_pts_t  pts; | ||||
|  | ||||
|     if(pkt->kind != VPX_CODEC_CX_FRAME_PKT) | ||||
|         return; | ||||
|  | ||||
|     pts = pkt->data.frame.pts; | ||||
|     mem_put_le32(header, pkt->data.frame.sz); | ||||
|     mem_put_le32(header+4, pts&0xFFFFFFFF); | ||||
|     mem_put_le32(header+8, pts >> 32); | ||||
|  | ||||
|     if(fwrite(header, 1, 12, outfile)); | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|     FILE                *infile, *outfile[NUM_ENCODERS]; | ||||
|     vpx_codec_ctx_t      codec[NUM_ENCODERS]; | ||||
|     vpx_codec_enc_cfg_t  cfg[NUM_ENCODERS]; | ||||
|     vpx_codec_pts_t      frame_cnt = 0; | ||||
|     vpx_image_t          raw[NUM_ENCODERS]; | ||||
|     vpx_codec_err_t      res[NUM_ENCODERS]; | ||||
|  | ||||
|     int                  i; | ||||
|     long                 width; | ||||
|     long                 height; | ||||
|     int                  frame_avail; | ||||
|     int                  got_data; | ||||
|     int                  flags = 0; | ||||
|  | ||||
|     /*Currently, only realtime mode is supported in multi-resolution encoding.*/ | ||||
|     int                  arg_deadline = VPX_DL_REALTIME; | ||||
|  | ||||
|     /* Set show_psnr to 1/0 to show/not show PSNR. Choose show_psnr=0 if you | ||||
|        don't need to know PSNR, which will skip PSNR calculation and save | ||||
|        encoding time. */ | ||||
|     int                  show_psnr = 0; | ||||
|     uint64_t             psnr_sse_total[NUM_ENCODERS] = {0}; | ||||
|     uint64_t             psnr_samples_total[NUM_ENCODERS] = {0}; | ||||
|     double               psnr_totals[NUM_ENCODERS][4] = {{0,0}}; | ||||
|     int                  psnr_count[NUM_ENCODERS] = {0}; | ||||
|  | ||||
|     /* Set the required target bitrates for each resolution level. */ | ||||
|     unsigned int         target_bitrate[NUM_ENCODERS]={1400, 500, 100}; | ||||
|     /* Enter the frame rate of the input video */ | ||||
|     int                  framerate = 30; | ||||
|     /* Set down-sampling factor for each resolution level. | ||||
|        dsf[0] controls down sampling from level 0 to level 1; | ||||
|        dsf[1] controls down sampling from level 1 to level 2; | ||||
|        dsf[2] is not used. */ | ||||
|     vpx_rational_t dsf[NUM_ENCODERS] = {{2, 1}, {2, 1}, {1, 1}}; | ||||
|  | ||||
|     if(argc!= (5+NUM_ENCODERS)) | ||||
|         die("Usage: %s <width> <height> <infile> <outfile(s)> <output psnr?>\n", | ||||
|             argv[0]); | ||||
|  | ||||
|     printf("Using %s\n",vpx_codec_iface_name(interface)); | ||||
|  | ||||
|     width = strtol(argv[1], NULL, 0); | ||||
|     height = strtol(argv[2], NULL, 0); | ||||
|  | ||||
|     if(width < 16 || width%2 || height <16 || height%2) | ||||
|         die("Invalid resolution: %ldx%ld", width, height); | ||||
|  | ||||
|     /* Open input video file for encoding */ | ||||
|     if(!(infile = fopen(argv[3], "rb"))) | ||||
|         die("Failed to open %s for reading", argv[3]); | ||||
|  | ||||
|     /* Open output file for each encoder to output bitstreams */ | ||||
|     for (i=0; i< NUM_ENCODERS; i++) | ||||
|     { | ||||
|         if(!(outfile[i] = fopen(argv[i+4], "wb"))) | ||||
|             die("Failed to open %s for writing", argv[i+4]); | ||||
|     } | ||||
|  | ||||
|     show_psnr = strtol(argv[NUM_ENCODERS + 4], NULL, 0); | ||||
|  | ||||
|     /* Populate default encoder configuration */ | ||||
|     for (i=0; i< NUM_ENCODERS; i++) | ||||
|     { | ||||
|         res[i] = vpx_codec_enc_config_default(interface, &cfg[i], 0); | ||||
|         if(res[i]) { | ||||
|             printf("Failed to get config: %s\n", vpx_codec_err_to_string(res[i])); | ||||
|             return EXIT_FAILURE; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Update the default configuration according to needs of the application. | ||||
|      */ | ||||
|     /* Highest-resolution encoder settings */ | ||||
|     cfg[0].g_w = width; | ||||
|     cfg[0].g_h = height; | ||||
|     cfg[0].g_threads = 1;                           /* number of threads used */ | ||||
|     cfg[0].rc_dropframe_thresh = 0; | ||||
|     cfg[0].rc_end_usage = VPX_CBR; | ||||
|     cfg[0].rc_resize_allowed = 0; | ||||
|     cfg[0].rc_min_quantizer = 4; | ||||
|     cfg[0].rc_max_quantizer = 56; | ||||
|     cfg[0].rc_undershoot_pct = 98; | ||||
|     cfg[0].rc_overshoot_pct = 100; | ||||
|     cfg[0].rc_buf_initial_sz = 500; | ||||
|     cfg[0].rc_buf_optimal_sz = 600; | ||||
|     cfg[0].rc_buf_sz = 1000; | ||||
|     //cfg[0].rc_dropframe_thresh = 10; | ||||
|     cfg[0].g_error_resilient = 1;              /* Enable error resilient mode */ | ||||
|     cfg[0].g_lag_in_frames   = 0; | ||||
|  | ||||
|     /* Disable automatic keyframe placement */ | ||||
|     //cfg[0].kf_mode           = VPX_KF_DISABLED; | ||||
|     cfg[0].kf_min_dist = cfg[0].kf_max_dist = 1000; | ||||
|  | ||||
|     cfg[0].rc_target_bitrate = target_bitrate[0];       /* Set target bitrate */ | ||||
|     cfg[0].g_timebase.num = 1;                          /* Set fps */ | ||||
|     cfg[0].g_timebase.den = framerate; | ||||
|  | ||||
|     /* Other-resolution encoder settings */ | ||||
|     for (i=1; i< NUM_ENCODERS; i++) | ||||
|     { | ||||
|         memcpy(&cfg[i], &cfg[0], sizeof(vpx_codec_enc_cfg_t)); | ||||
|  | ||||
|         cfg[i].g_threads = 1;                       /* number of threads used */ | ||||
|         cfg[i].rc_target_bitrate = target_bitrate[i]; | ||||
|  | ||||
|         /* Note: Width & height of other-resolution encoders are calculated | ||||
|          * from the highest-resolution encoder's size and the corresponding | ||||
|          * down_sampling_factor. | ||||
|          */ | ||||
|         { | ||||
|             unsigned int iw = cfg[i-1].g_w*dsf[i-1].den + dsf[i-1].num - 1; | ||||
|             unsigned int ih = cfg[i-1].g_h*dsf[i-1].den + dsf[i-1].num - 1; | ||||
|             cfg[i].g_w = iw/dsf[i-1].num; | ||||
|             cfg[i].g_h = ih/dsf[i-1].num; | ||||
|         } | ||||
|  | ||||
|         /* Make width & height to be multiplier of 2. */ | ||||
|         // Should support odd size ??? | ||||
|         if((cfg[i].g_w)%2)cfg[i].g_w++; | ||||
|         if((cfg[i].g_h)%2)cfg[i].g_h++; | ||||
|     } | ||||
|  | ||||
|     /* Allocate image for each encoder */ | ||||
|     for (i=0; i< NUM_ENCODERS; i++) | ||||
|         if(!vpx_img_alloc(&raw[i], VPX_IMG_FMT_I420, cfg[i].g_w, cfg[i].g_h, 1)) | ||||
|             die("Failed to allocate image", cfg[i].g_w, cfg[i].g_h); | ||||
|  | ||||
|     for (i=0; i< NUM_ENCODERS; i++) | ||||
|         write_ivf_file_header(outfile[i], &cfg[i], 0); | ||||
|  | ||||
|     /* Initialize multi-encoder */ | ||||
|     if(vpx_codec_enc_init_multi(&codec[0], interface, &cfg[0], NUM_ENCODERS, | ||||
|                                 (show_psnr ? VPX_CODEC_USE_PSNR : 0), &dsf[0])) | ||||
|         die_codec(&codec[0], "Failed to initialize encoder"); | ||||
|  | ||||
|     /* The extra encoding configuration parameters can be set as follows. */ | ||||
|     /* Set encoding speed */ | ||||
|     for ( i=0; i<NUM_ENCODERS; i++) | ||||
|     { | ||||
|         int speed = -6; | ||||
|         if(vpx_codec_control(&codec[i], VP8E_SET_CPUUSED, speed)) | ||||
|             die_codec(&codec[i], "Failed to set cpu_used"); | ||||
|     } | ||||
|     /* Set static thresh for highest-resolution encoder. Set it to 1000 for | ||||
|      * better performance. */ | ||||
|     { | ||||
|         unsigned int static_thresh = 1000; | ||||
|         if(vpx_codec_control(&codec[0], VP8E_SET_STATIC_THRESHOLD, static_thresh)) | ||||
|             die_codec(&codec[0], "Failed to set static threshold"); | ||||
|     } | ||||
|     /* Set static thresh = 0 for other encoders for better quality */ | ||||
|     for ( i=1; i<NUM_ENCODERS; i++) | ||||
|     { | ||||
|         unsigned int static_thresh = 0; | ||||
|         if(vpx_codec_control(&codec[i], VP8E_SET_STATIC_THRESHOLD, static_thresh)) | ||||
|             die_codec(&codec[i], "Failed to set static threshold"); | ||||
|     } | ||||
|  | ||||
|     frame_avail = 1; | ||||
|     got_data = 0; | ||||
|  | ||||
|     while(frame_avail || got_data) | ||||
|     { | ||||
|         vpx_codec_iter_t iter[NUM_ENCODERS]={NULL}; | ||||
|         const vpx_codec_cx_pkt_t *pkt[NUM_ENCODERS]; | ||||
|  | ||||
|         flags = 0; | ||||
|         frame_avail = read_frame(infile, &raw[0]); | ||||
|  | ||||
|         for ( i=1; i<NUM_ENCODERS; i++) | ||||
|         { | ||||
|             if(frame_avail) | ||||
|             { | ||||
|                 /*Scale the image down a number of times by downsampling factor*/ | ||||
|                 int src_uvwidth = (raw[i-1].d_w + 1) >> 1; | ||||
|                 int src_uvheight = (raw[i-1].d_h + 1) >> 1; | ||||
|                 const unsigned char* src_y = raw[i-1].planes[VPX_PLANE_Y]; | ||||
|                 const unsigned char* src_u = raw[i-1].planes[VPX_PLANE_Y] | ||||
|                                              + raw[i-1].d_w*raw[i-1].d_h; | ||||
|                 const unsigned char* src_v = raw[i-1].planes[VPX_PLANE_Y] | ||||
|                                              + raw[i-1].d_w*raw[i-1].d_h | ||||
|                                              + src_uvwidth*src_uvheight; | ||||
|                 int dst_uvwidth = (raw[i].d_w + 1) >> 1; | ||||
|                 int dst_uvheight = (raw[i].d_h + 1) >> 1; | ||||
|                 unsigned char* dst_y = raw[i].planes[VPX_PLANE_Y]; | ||||
|                 unsigned char* dst_u = raw[i].planes[VPX_PLANE_Y] | ||||
|                                        + raw[i].d_w*raw[i].d_h; | ||||
|                 unsigned char* dst_v = raw[i].planes[VPX_PLANE_Y] | ||||
|                                        + raw[i].d_w*raw[i].d_h | ||||
|                                        + dst_uvwidth*dst_uvheight; | ||||
|  | ||||
|                 /* FilterMode 1 or 2 give better psnr than FilterMode 0. */ | ||||
|                 I420Scale(src_y, raw[i-1].d_w, src_u, src_uvwidth, src_v, | ||||
|                           src_uvwidth, raw[i-1].d_w, raw[i-1].d_h, | ||||
|                           dst_y, raw[i].d_w, dst_u, dst_uvwidth, | ||||
|                           dst_v, dst_uvwidth, raw[i].d_w, raw[i].d_h, 1); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /* Encode each frame at multi-levels */ | ||||
|         if(vpx_codec_encode(&codec[0], frame_avail? &raw[0] : NULL, | ||||
|             frame_cnt, 1, flags, arg_deadline)) | ||||
|             die_codec(&codec[0], "Failed to encode frame"); | ||||
|  | ||||
|         for (i=NUM_ENCODERS-1; i>=0 ; i--) | ||||
|         { | ||||
|             got_data = 0; | ||||
|  | ||||
|             while( (pkt[i] = vpx_codec_get_cx_data(&codec[i], &iter[i])) ) | ||||
|             { | ||||
|                 got_data = 1; | ||||
|                 switch(pkt[i]->kind) { | ||||
|                     case VPX_CODEC_CX_FRAME_PKT: | ||||
|                         write_ivf_frame_header(outfile[i], pkt[i]); | ||||
|                         if(fwrite(pkt[i]->data.frame.buf, 1, pkt[i]->data.frame.sz, | ||||
|                                   outfile[i])); | ||||
|                     break; | ||||
|                     case VPX_CODEC_PSNR_PKT: | ||||
|                         if (show_psnr) | ||||
|                         { | ||||
|                             int j; | ||||
|  | ||||
|                             psnr_sse_total[i] += pkt[i]->data.psnr.sse[0]; | ||||
|                             psnr_samples_total[i] += pkt[i]->data.psnr.samples[0]; | ||||
|                             for (j = 0; j < 4; j++) | ||||
|                             { | ||||
|                                 //fprintf(stderr, "%.3lf ", pkt[i]->data.psnr.psnr[j]); | ||||
|                                 psnr_totals[i][j] += pkt[i]->data.psnr.psnr[j]; | ||||
|                             } | ||||
|                             psnr_count[i]++; | ||||
|                         } | ||||
|  | ||||
|                         break; | ||||
|                     default: | ||||
|                         break; | ||||
|                 } | ||||
|                 printf(pkt[i]->kind == VPX_CODEC_CX_FRAME_PKT | ||||
|                        && (pkt[i]->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); | ||||
|                 fflush(stdout); | ||||
|             } | ||||
|         } | ||||
|         frame_cnt++; | ||||
|     } | ||||
|     printf("\n"); | ||||
|  | ||||
|     fclose(infile); | ||||
|  | ||||
|     for (i=0; i< NUM_ENCODERS; i++) | ||||
|     { | ||||
|         printf("Processed %ld frames.\n",(long int)frame_cnt-1); | ||||
|  | ||||
|         /* Calculate PSNR and print it out */ | ||||
|         if ( (show_psnr) && (psnr_count[i]>0) ) | ||||
|         { | ||||
|             int j; | ||||
|             double ovpsnr = vp8_mse2psnr(psnr_samples_total[i], 255.0, | ||||
|                                          psnr_sse_total[i]); | ||||
|  | ||||
|             fprintf(stderr, "\n ENC%d PSNR (Overall/Avg/Y/U/V)", i); | ||||
|  | ||||
|             fprintf(stderr, " %.3lf", ovpsnr); | ||||
|             for (j = 0; j < 4; j++) | ||||
|             { | ||||
|                 fprintf(stderr, " %.3lf", psnr_totals[i][j]/psnr_count[i]); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if(vpx_codec_destroy(&codec[i])) | ||||
|             die_codec(&codec[i], "Failed to destroy codec"); | ||||
|  | ||||
|         /* Try to rewrite the file header with the actual frame count */ | ||||
|         if(!fseek(outfile[i], 0, SEEK_SET)) | ||||
|             write_ivf_file_header(outfile[i], &cfg[i], frame_cnt-1); | ||||
|         fclose(outfile[i]); | ||||
|  | ||||
|         vpx_img_free(&raw[i]); | ||||
|     } | ||||
|  | ||||
|     return EXIT_SUCCESS; | ||||
| } | ||||
| @@ -56,9 +56,10 @@ | ||||
|  * types, removing or reassigning enums, adding/removing/rearranging | ||||
|  * fields to structures | ||||
|  */ | ||||
| #define VPX_CODEC_INTERNAL_ABI_VERSION (3) /**<\hideinitializer*/ | ||||
| #define VPX_CODEC_INTERNAL_ABI_VERSION (4) /**<\hideinitializer*/ | ||||
|  | ||||
| typedef struct vpx_codec_alg_priv  vpx_codec_alg_priv_t; | ||||
| typedef struct vpx_codec_priv_enc_mr_cfg vpx_codec_priv_enc_mr_cfg_t; | ||||
|  | ||||
| /*!\brief init function pointer prototype | ||||
|  * | ||||
| @@ -73,7 +74,8 @@ typedef struct vpx_codec_alg_priv  vpx_codec_alg_priv_t; | ||||
|  * \retval #VPX_CODEC_MEM_ERROR | ||||
|  *     Memory operation failed. | ||||
|  */ | ||||
| typedef vpx_codec_err_t (*vpx_codec_init_fn_t)(vpx_codec_ctx_t *ctx); | ||||
| typedef vpx_codec_err_t (*vpx_codec_init_fn_t)(vpx_codec_ctx_t *ctx, | ||||
|                                              vpx_codec_priv_enc_mr_cfg_t *data); | ||||
|  | ||||
| /*!\brief destroy function pointer prototype | ||||
|  * | ||||
| @@ -264,6 +266,10 @@ typedef vpx_fixed_buf_t * | ||||
| typedef vpx_image_t * | ||||
| (*vpx_codec_get_preview_frame_fn_t)(vpx_codec_alg_priv_t   *ctx); | ||||
|  | ||||
| typedef vpx_codec_err_t | ||||
| (*vpx_codec_enc_mr_get_mem_loc_fn_t)(const vpx_codec_enc_cfg_t     *cfg, | ||||
|                                    void **mem_loc); | ||||
|  | ||||
| /*!\brief usage configuration mapping | ||||
|  * | ||||
|  * This structure stores the mapping between usage identifiers and | ||||
| @@ -309,8 +315,9 @@ struct vpx_codec_iface | ||||
|         vpx_codec_encode_fn_t              encode;        /**< \copydoc ::vpx_codec_encode_fn_t */ | ||||
|         vpx_codec_get_cx_data_fn_t         get_cx_data;   /**< \copydoc ::vpx_codec_get_cx_data_fn_t */ | ||||
|         vpx_codec_enc_config_set_fn_t      cfg_set;       /**< \copydoc ::vpx_codec_enc_config_set_fn_t */ | ||||
|         vpx_codec_get_global_headers_fn_t  get_glob_hdrs; /**< \copydoc ::vpx_codec_enc_config_set_fn_t */ | ||||
|         vpx_codec_get_global_headers_fn_t  get_glob_hdrs; /**< \copydoc ::vpx_codec_get_global_headers_fn_t */ | ||||
|         vpx_codec_get_preview_frame_fn_t   get_preview;   /**< \copydoc ::vpx_codec_get_preview_frame_fn_t */ | ||||
|         vpx_codec_enc_mr_get_mem_loc_fn_t  mr_get_mem_loc;   /**< \copydoc ::vpx_codec_enc_mr_get_mem_loc_fn_t */ | ||||
|     } enc; | ||||
| }; | ||||
|  | ||||
| @@ -353,9 +360,21 @@ struct vpx_codec_priv | ||||
|         unsigned int                cx_data_pad_before; | ||||
|         unsigned int                cx_data_pad_after; | ||||
|         vpx_codec_cx_pkt_t          cx_data_pkt; | ||||
|         unsigned int                total_encoders; | ||||
|     } enc; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Multi-resolution encoding internal configuration | ||||
|  */ | ||||
| struct vpx_codec_priv_enc_mr_cfg | ||||
| { | ||||
|     unsigned int           mr_total_resolutions; | ||||
|     unsigned int           mr_encoder_id; | ||||
|     struct vpx_rational    mr_down_sampling_factor; | ||||
|     void*                  mr_low_res_mode_info; | ||||
| }; | ||||
|  | ||||
| #undef VPX_CTRL_USE_TYPE | ||||
| #define VPX_CTRL_USE_TYPE(id, typ) \ | ||||
|     static typ id##__value(va_list args) {return va_arg(args, typ);} \ | ||||
|   | ||||
| @@ -56,7 +56,7 @@ vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t      *ctx, | ||||
|  | ||||
|         if (!(flags & VPX_CODEC_USE_XMA)) | ||||
|         { | ||||
|             res = ctx->iface->init(ctx); | ||||
|             res = ctx->iface->init(ctx, NULL); | ||||
|  | ||||
|             if (res) | ||||
|             { | ||||
|   | ||||
| @@ -51,7 +51,7 @@ vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t      *ctx, | ||||
|         ctx->priv = NULL; | ||||
|         ctx->init_flags = flags; | ||||
|         ctx->config.enc = cfg; | ||||
|         res = ctx->iface->init(ctx); | ||||
|         res = ctx->iface->init(ctx, NULL); | ||||
|  | ||||
|         if (res) | ||||
|         { | ||||
| @@ -66,6 +66,85 @@ vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t      *ctx, | ||||
|     return SAVE_STATUS(ctx, res); | ||||
| } | ||||
|  | ||||
| vpx_codec_err_t vpx_codec_enc_init_multi_ver(vpx_codec_ctx_t      *ctx, | ||||
|                                              vpx_codec_iface_t    *iface, | ||||
|                                              vpx_codec_enc_cfg_t  *cfg, | ||||
|                                              int                   num_enc, | ||||
|                                              vpx_codec_flags_t     flags, | ||||
|                                              vpx_rational_t       *dsf, | ||||
|                                              int                   ver) | ||||
| { | ||||
|     vpx_codec_err_t res = 0; | ||||
|  | ||||
|     if (ver != VPX_ENCODER_ABI_VERSION) | ||||
|         res = VPX_CODEC_ABI_MISMATCH; | ||||
|     else if (!ctx || !iface || !cfg || (num_enc > 16 || num_enc < 1)) | ||||
|         res = VPX_CODEC_INVALID_PARAM; | ||||
|     else if (iface->abi_version != VPX_CODEC_INTERNAL_ABI_VERSION) | ||||
|         res = VPX_CODEC_ABI_MISMATCH; | ||||
|     else if (!(iface->caps & VPX_CODEC_CAP_ENCODER)) | ||||
|         res = VPX_CODEC_INCAPABLE; | ||||
|     else if ((flags & VPX_CODEC_USE_XMA) && !(iface->caps & VPX_CODEC_CAP_XMA)) | ||||
|         res = VPX_CODEC_INCAPABLE; | ||||
|     else if ((flags & VPX_CODEC_USE_PSNR) | ||||
|              && !(iface->caps & VPX_CODEC_CAP_PSNR)) | ||||
|         res = VPX_CODEC_INCAPABLE; | ||||
|     else if ((flags & VPX_CODEC_USE_OUTPUT_PARTITION) | ||||
|              && !(iface->caps & VPX_CODEC_CAP_OUTPUT_PARTITION)) | ||||
|         res = VPX_CODEC_INCAPABLE; | ||||
|     else | ||||
|     { | ||||
|         int i; | ||||
|         void *mem_loc = NULL; | ||||
|  | ||||
|         if(!(res = iface->enc.mr_get_mem_loc(cfg, &mem_loc))) | ||||
|         { | ||||
|             for (i = 0; i < num_enc; i++) | ||||
|             { | ||||
|                 vpx_codec_priv_enc_mr_cfg_t mr_cfg; | ||||
|  | ||||
|                 /* Validate down-sampling factor. */ | ||||
|                 if(dsf->num < 1 || dsf->num > 4096 || dsf->den < 1 || | ||||
|                    dsf->den > dsf->num) | ||||
|                 { | ||||
|                     res = VPX_CODEC_INVALID_PARAM; | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 mr_cfg.mr_low_res_mode_info = mem_loc; | ||||
|                 mr_cfg.mr_total_resolutions = num_enc; | ||||
|                 mr_cfg.mr_encoder_id = num_enc-1-i; | ||||
|                 mr_cfg.mr_down_sampling_factor.num = dsf->num; | ||||
|                 mr_cfg.mr_down_sampling_factor.den = dsf->den; | ||||
|  | ||||
|                 ctx->iface = iface; | ||||
|                 ctx->name = iface->name; | ||||
|                 ctx->priv = NULL; | ||||
|                 ctx->init_flags = flags; | ||||
|                 ctx->config.enc = cfg; | ||||
|                 res = ctx->iface->init(ctx, &mr_cfg); | ||||
|  | ||||
|                 if (res) | ||||
|                 { | ||||
|                     ctx->err_detail = ctx->priv ? ctx->priv->err_detail : NULL; | ||||
|                     vpx_codec_destroy(ctx); | ||||
|                 } | ||||
|  | ||||
|                 if (ctx->priv) | ||||
|                     ctx->priv->iface = ctx->iface; | ||||
|  | ||||
|                 if (res) | ||||
|                     break; | ||||
|  | ||||
|                 ctx++; | ||||
|                 cfg++; | ||||
|                 dsf++; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return SAVE_STATUS(ctx, res); | ||||
| } | ||||
|  | ||||
|  | ||||
| vpx_codec_err_t  vpx_codec_enc_config_default(vpx_codec_iface_t    *iface, | ||||
| @@ -123,7 +202,7 @@ vpx_codec_err_t  vpx_codec_encode(vpx_codec_ctx_t            *ctx, | ||||
|                                   vpx_enc_frame_flags_t       flags, | ||||
|                                   unsigned long               deadline) | ||||
| { | ||||
|     vpx_codec_err_t res; | ||||
|     vpx_codec_err_t res = 0; | ||||
|  | ||||
|     if (!ctx || (img && !duration)) | ||||
|         res = VPX_CODEC_INVALID_PARAM; | ||||
| @@ -136,9 +215,36 @@ vpx_codec_err_t  vpx_codec_encode(vpx_codec_ctx_t            *ctx, | ||||
|         /* Execute in a normalized floating point environment, if the platform | ||||
|          * requires it. | ||||
|          */ | ||||
|         unsigned int num_enc =ctx->priv->enc.total_encoders; | ||||
|  | ||||
|         FLOATING_POINT_INIT(); | ||||
|         res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts, | ||||
|                                      duration, flags, deadline); | ||||
|  | ||||
|         if (num_enc == 1) | ||||
|             res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts, | ||||
|                                          duration, flags, deadline); | ||||
|         else | ||||
|         { | ||||
|             /* Multi-resolution encoding: | ||||
|              * Encode multi-levels in reverse order. For example, | ||||
|              * if mr_total_resolutions = 3, first encode level 2, | ||||
|              * then encode level 1, and finally encode level 0. | ||||
|              */ | ||||
|             int i; | ||||
|  | ||||
|             ctx += num_enc - 1; | ||||
|             if (img) img += num_enc - 1; | ||||
|  | ||||
|             for (i = num_enc-1; i >= 0; i--) | ||||
|             { | ||||
|                 if ((res = ctx->iface->enc.encode(ctx->priv->alg_priv, img, pts, | ||||
|                                                   duration, flags, deadline))) | ||||
|                     break; | ||||
|  | ||||
|                 ctx--; | ||||
|                 if (img) img--; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         FLOATING_POINT_RESTORE(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -634,7 +634,6 @@ extern "C" { | ||||
|          * then ts_layer_id = (0,1,0,1,0,1,0,1). | ||||
|          */ | ||||
|         unsigned int           ts_layer_id[MAX_PERIODICITY]; | ||||
|  | ||||
|     } vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */ | ||||
|  | ||||
|  | ||||
| @@ -675,6 +674,48 @@ extern "C" { | ||||
|     vpx_codec_enc_init_ver(ctx, iface, cfg, flags, VPX_ENCODER_ABI_VERSION) | ||||
|  | ||||
|  | ||||
|     /*!\brief Initialize multi-encoder instance | ||||
|      * | ||||
|      * Initializes multi-encoder context using the given interface. | ||||
|      * Applications should call the vpx_codec_enc_init_multi convenience macro | ||||
|      * instead of this function directly, to ensure that the ABI version number | ||||
|      * parameter is properly initialized. | ||||
|      * | ||||
|      * In XMA mode (activated by setting VPX_CODEC_USE_XMA in the flags | ||||
|      * parameter), the storage pointed to by the cfg parameter must be | ||||
|      * kept readable and stable until all memory maps have been set. | ||||
|      * | ||||
|      * \param[in]    ctx     Pointer to this instance's context. | ||||
|      * \param[in]    iface   Pointer to the algorithm interface to use. | ||||
|      * \param[in]    cfg     Configuration to use, if known. May be NULL. | ||||
|      * \param[in]    num_enc Total number of encoders. | ||||
|      * \param[in]    flags   Bitfield of VPX_CODEC_USE_* flags | ||||
|      * \param[in]    dsf     Pointer to down-sampling factors. | ||||
|      * \param[in]    ver     ABI version number. Must be set to | ||||
|      *                       VPX_ENCODER_ABI_VERSION | ||||
|      * \retval #VPX_CODEC_OK | ||||
|      *     The decoder algorithm initialized. | ||||
|      * \retval #VPX_CODEC_MEM_ERROR | ||||
|      *     Memory allocation failed. | ||||
|      */ | ||||
|     vpx_codec_err_t vpx_codec_enc_init_multi_ver(vpx_codec_ctx_t      *ctx, | ||||
|                                                  vpx_codec_iface_t    *iface, | ||||
|                                                  vpx_codec_enc_cfg_t  *cfg, | ||||
|                                                  int                   num_enc, | ||||
|                                                  vpx_codec_flags_t     flags, | ||||
|                                                  vpx_rational_t       *dsf, | ||||
|                                                  int                   ver); | ||||
|  | ||||
|  | ||||
|     /*!\brief Convenience macro for vpx_codec_enc_init_multi_ver() | ||||
|      * | ||||
|      * Ensures the ABI version parameter is properly set. | ||||
|      */ | ||||
| #define vpx_codec_enc_init_multi(ctx, iface, cfg, num_enc, flags, dsf) \ | ||||
|     vpx_codec_enc_init_multi_ver(ctx, iface, cfg, num_enc, flags, dsf, \ | ||||
|                                  VPX_ENCODER_ABI_VERSION) | ||||
|  | ||||
|  | ||||
|     /*!\brief Get a default configuration | ||||
|      * | ||||
|      * Initializes a encoder configuration structure with default values. Supports | ||||
| @@ -780,7 +821,6 @@ extern "C" { | ||||
|                                       vpx_enc_frame_flags_t       flags, | ||||
|                                       unsigned long               deadline); | ||||
|  | ||||
|  | ||||
|     /*!\brief Set compressed data output buffer | ||||
|      * | ||||
|      * Sets the buffer that the codec should output the compressed data | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Yunqing Wang
					Yunqing Wang