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:
Yunqing Wang 2011-10-25 15:14:16 -04:00
parent 6127af60c1
commit aa7335e610
31 changed files with 6057 additions and 88 deletions

5
configure vendored
View File

@ -35,7 +35,7 @@ Advanced options:
${toggle_internal_stats} output of encoder internal stats for debug, if supported (encoders) ${toggle_internal_stats} output of encoder internal stats for debug, if supported (encoders)
${toggle_mem_tracker} track memory usage ${toggle_mem_tracker} track memory usage
${toggle_postproc} postprocessing ${toggle_postproc} postprocessing
${toggle_multithread} multithreaded encoding and decoding. ${toggle_multithread} multithreaded encoding and decoding
${toggle_spatial_resampling} spatial sampling (scaling) support ${toggle_spatial_resampling} spatial sampling (scaling) support
${toggle_realtime_only} enable this option while building for real-time encoding ${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 ${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_static} static library support
${toggle_small} favor smaller size over speed ${toggle_small} favor smaller size over speed
${toggle_postproc_visualizer} macro block / block level visualizers ${toggle_postproc_visualizer} macro block / block level visualizers
${toggle_multi_res_encoding} enable multiple-resolution encoding
Codecs: Codecs:
Codecs can be selectively enabled or disabled individually, or by family: Codecs can be selectively enabled or disabled individually, or by family:
@ -262,6 +263,7 @@ CONFIG_LIST="
postproc_visualizer postproc_visualizer
os_support os_support
unit_tests unit_tests
multi_res_encoding
" "
CMDLINE_SELECT=" CMDLINE_SELECT="
extra_warnings extra_warnings
@ -304,6 +306,7 @@ CMDLINE_SELECT="
small small
postproc_visualizer postproc_visualizer
unit_tests unit_tests
multi_res_encoding
" "
process_cmdline() { process_cmdline() {

View File

@ -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.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A
vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame 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 # Handle extra library flags depending on codec configuration

17
third_party/libyuv/README.webm vendored Normal file
View 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.

View 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_

View 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_

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View File

@ -82,6 +82,7 @@
The available initialization methods are: The available initialization methods are:
\if encoder - #vpx_codec_enc_init (calls vpx_codec_enc_init_ver()) \endif \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 \if decoder - #vpx_codec_dec_init (calls vpx_codec_dec_init_ver()) \endif

View File

@ -1,6 +1,6 @@
/*! \page usage_encode Encode /*! \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 processes raw images passed by the application, producing packets of
compressed data. The <code>deadline</code> parameter controls the amount compressed data. The <code>deadline</code> parameter controls the amount
of time in microseconds the encoder should spend working on the frame. For of time in microseconds the encoder should spend working on the frame. For
@ -10,5 +10,4 @@
\ref samples \ref samples
*/ */

View File

@ -170,6 +170,18 @@ typedef struct
union b_mode_info bmi[16]; union b_mode_info bmi[16];
} MODE_INFO; } 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 typedef struct
{ {
short *qcoeff; short *qcoeff;

View File

@ -17,6 +17,7 @@ extern "C"
{ {
#endif #endif
#include "vpx_config.h"
#include "vpx/internal/vpx_codec_internal.h" #include "vpx/internal/vpx_codec_internal.h"
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
@ -207,6 +208,19 @@ extern "C"
unsigned int periodicity; unsigned int periodicity;
unsigned int layer_id[MAX_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; } VP8_CONFIG;

View File

@ -49,8 +49,8 @@ extern void vp8cx_init_mbrthread_data(VP8_COMP *cpi,
int count); int count);
void vp8_build_block_offsets(MACROBLOCK *x); void vp8_build_block_offsets(MACROBLOCK *x);
void vp8_setup_block_ptrs(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_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 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 ); static void adjust_act_zbin( VP8_COMP *cpi, MACROBLOCK *x );
#ifdef MODE_STATS #ifdef MODE_STATS
@ -475,14 +475,14 @@ void encode_mb_row(VP8_COMP *cpi,
if (cm->frame_type == KEY_FRAME) 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 #ifdef MODE_STATS
y_modes[xd->mbmi.mode] ++; y_modes[xd->mbmi.mode] ++;
#endif #endif
} }
else 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 #ifdef MODE_STATS
inter_y_modes[xd->mbmi.mode] ++; inter_y_modes[xd->mbmi.mode] ++;
@ -1142,7 +1142,7 @@ static void adjust_act_zbin( VP8_COMP *cpi, MACROBLOCK *x )
#endif #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; int rate;
@ -1182,7 +1182,8 @@ extern void vp8_fix_contexts(MACROBLOCKD *x);
int vp8cx_encode_inter_macroblock int vp8cx_encode_inter_macroblock
( (
VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t, 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; MACROBLOCKD *const xd = &x->e_mbd;
@ -1230,8 +1231,25 @@ int vp8cx_encode_inter_macroblock
} }
else 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, vp8_pick_inter_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate,
&distortion, &intra_error); &distortion, &intra_error);
#endif
}
cpi->prediction_error += distortion; cpi->prediction_error += distortion;
cpi->intra_error += intra_error; cpi->intra_error += intra_error;

View File

@ -9,6 +9,7 @@
*/ */
#include "onyx_int.h"
#include "mcomp.h" #include "mcomp.h"
#include "vpx_mem/vpx_mem.h" #include "vpx_mem/vpx_mem.h"
#include "vpx_config.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 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 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 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 vp8_find_best_sub_pixel_step_iteratively(MACROBLOCK *x, BLOCK *b, BLOCKD *d,
int_mv *bestmv, int_mv *ref_mv, 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 IFMVCV
#undef ERR #undef ERR
#undef CHECK_BETTER #undef CHECK_BETTER
#undef MIN
#undef MAX
int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int vp8_find_best_sub_pixel_step(MACROBLOCK *x, BLOCK *b, BLOCKD *d,
int_mv *bestmv, int_mv *ref_mv, int_mv *bestmv, int_mv *ref_mv,
int error_per_bit, int error_per_bit,
@ -854,6 +852,8 @@ int vp8_hex_search
int k = -1; int k = -1;
int all_in; int all_in;
int best_site = -1; int best_site = -1;
int hex_range = 127;
int dia_range = 8;
int_mv fcenter_mv; int_mv fcenter_mv;
fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3; fcenter_mv.as_mv.row = center_mv->as_mv.row >> 3;
@ -873,6 +873,18 @@ int vp8_hex_search
in_what_stride, 0x7fffffff) in_what_stride, 0x7fffffff)
+ mvsad_err_cost(&this_mv, &fcenter_mv, mvsadcost, sad_per_bit); + 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 // hex search
//j=0 //j=0
CHECK_BOUNDS(2) CHECK_BOUNDS(2)
@ -909,7 +921,7 @@ int vp8_hex_search
k = best_site; k = best_site;
} }
for (j = 1; j < 127; j++) for (j = 1; j < hex_range; j++)
{ {
best_site = -1; best_site = -1;
CHECK_BOUNDS(2) CHECK_BOUNDS(2)
@ -951,7 +963,7 @@ int vp8_hex_search
// check 4 1-away neighbors // check 4 1-away neighbors
cal_neighbors: cal_neighbors:
for (j = 0; j < 32; j++) for (j = 0; j < dia_range; j++)
{ {
best_site = -1; best_site = -1;
CHECK_BOUNDS(1) CHECK_BOUNDS(1)

201
vp8/encoder/mr_dissim.c Normal file
View 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
View 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

View File

@ -36,6 +36,9 @@
#if ARCH_ARM #if ARCH_ARM
#include "vpx_ports/arm.h" #include "vpx_ports/arm.h"
#endif #endif
#if CONFIG_MULTI_RES_ENCODING
#include "mr_dissim.h"
#endif
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
@ -2234,6 +2237,13 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf)
vp8_loop_filter_init(cm); vp8_loop_filter_init(cm);
cpi->common.error.setjmp = 0; 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; return (VP8_PTR) cpi;
} }
@ -4338,13 +4348,20 @@ static void encode_frame_to_data_rate
IF_RTCD(&cpi->rtcd.variance)); IF_RTCD(&cpi->rtcd.variance));
} }
// This frame's MVs are saved and will be used in next frame's MV prediction. /* 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. * Last frame has one more line(add to bottom) and one more column(add to
if(cm->show_frame) //do not save for altref frame * 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_row;
int mb_col; 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) 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. // Update the GF useage maps.
// This is done after completing the compression of a frame when all // This is done after completing the compression of a frame when all
// modes etc. are finalized but before loop filter // modes etc. are finalized but before loop filter

View File

@ -58,6 +58,9 @@
#define MAX_PERIODICITY 16 #define MAX_PERIODICITY 16
#define MAX(x,y) (((x)>(y))?(x):(y))
#define MIN(x,y) (((x)<(y))?(x):(y))
typedef struct typedef struct
{ {
int kf_indicated; int kf_indicated;
@ -679,6 +682,11 @@ typedef struct VP8_COMP
double total_ssimg_v_in_layer[MAX_LAYERS]; double total_ssimg_v_in_layer[MAX_LAYERS];
double total_ssimg_all_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; } VP8_COMP;
void control_data_rate(VP8_COMP *cpi); void control_data_rate(VP8_COMP *cpi);

View File

@ -703,6 +703,14 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
if (cpi->sf.search_method == HEX) 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, bestsme = vp8_hex_search(x, b, d, &mvp_full, &d->bmi.mv, step_param,
sadpb, &cpi->fn_ptr[BLOCK_16X16], sadpb, &cpi->fn_ptr[BLOCK_16X16],
x->mvsadcost, x->mvcost, &best_ref_mv); 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; *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

View File

@ -14,6 +14,16 @@
#include "vpx_config.h" #include "vpx_config.h"
#include "vp8/common/onyxc_int.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); 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 #endif

View File

@ -1463,57 +1463,6 @@ static int vp8_rd_pick_best_mbsegmentation(VP8_COMP *cpi, MACROBLOCK *x,
return bsi.segment_rd; 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 //The improved MV prediction
void vp8_mv_pred void vp8_mv_pred
( (

View File

@ -14,6 +14,57 @@
#define RDCOST(RM,DM,R,D) ( ((128+(R)*(RM)) >> 8) + (DM)*(D) ) #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_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_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); extern void vp8_rd_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate);

View File

@ -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, static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf,
vpx_codec_enc_cfg_t cfg, 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->multi_threaded = cfg.g_threads;
oxcf->Version = cfg.g_profile; 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)); 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; //oxcf->delete_first_pass_file = cfg.g_delete_firstpassfile;
//strcpy(oxcf->first_pass_file, cfg.g_firstpass_file); //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) if (!res)
{ {
ctx->cfg = *cfg; 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); 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) if (!res)
{ {
ctx->vp8_cfg = xcfg; 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); vp8_change_config(ctx->cpi, &ctx->oxcf);
} }
return res; return res;
#undef MAP #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; vpx_codec_err_t res = VPX_DEC_OK;
struct vpx_codec_alg_priv *priv; 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 (!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, set_vp8e_config(&ctx->priv->alg_priv->oxcf,
ctx->priv->alg_priv->cfg, 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); optr = vp8_create_compressor(&ctx->priv->alg_priv->oxcf);
if (!optr) 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) 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); free(ctx->cx_data);
vp8_remove_compressor(&ctx->cpi); vp8_remove_compressor(&ctx->cpi);
@ -1223,6 +1271,7 @@ CODEC_INTERFACE(vpx_codec_vp8_cx) =
vp8e_set_config, vp8e_set_config,
NOT_IMPLEMENTED, NOT_IMPLEMENTED,
vp8e_get_preview, vp8e_get_preview,
vp8e_mr_alloc_mem,
} /* encoder functions */ } /* encoder functions */
}; };
@ -1307,5 +1356,6 @@ vpx_codec_iface_t vpx_enc_vp8_algo =
vp8e_set_config, vp8e_set_config,
NOT_IMPLEMENTED, NOT_IMPLEMENTED,
vp8e_get_preview, vp8e_get_preview,
vp8e_mr_alloc_mem,
} /* encoder functions */ } /* encoder functions */
}; };

View File

@ -181,9 +181,11 @@ static void vp8_finalize_mmaps(vpx_codec_alg_priv_t *ctx)
/* nothing to clean up */ /* 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; vpx_codec_err_t res = VPX_CODEC_OK;
(void) data;
/* This function only allocates space for the vpx_codec_alg_priv_t /* This function only allocates space for the vpx_codec_alg_priv_t
* structure. More memory may be required at the time the stream * 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) if (done && !res)
{ {
vp8_finalize_mmaps(ctx->priv->alg_priv); vp8_finalize_mmaps(ctx->priv->alg_priv);
res = ctx->iface->init(ctx); res = ctx->iface->init(ctx, NULL);
} }
return res; return res;

View File

@ -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-$(CONFIG_INTERNAL_STATS) += common/postproc.c
VP8_CX_SRCS-yes += encoder/temporal_filter.c VP8_CX_SRCS-yes += encoder/temporal_filter.c
VP8_CX_SRCS-yes += encoder/temporal_filter.h 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) ifeq ($(CONFIG_REALTIME_ONLY),yes)
VP8_CX_SRCS_REMOVE-yes += encoder/firstpass.c VP8_CX_SRCS_REMOVE-yes += encoder/firstpass.c

View 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;
}

View File

@ -56,9 +56,10 @@
* types, removing or reassigning enums, adding/removing/rearranging * types, removing or reassigning enums, adding/removing/rearranging
* fields to structures * 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_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 /*!\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 * \retval #VPX_CODEC_MEM_ERROR
* Memory operation failed. * 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 /*!\brief destroy function pointer prototype
* *
@ -264,6 +266,10 @@ typedef vpx_fixed_buf_t *
typedef vpx_image_t * typedef vpx_image_t *
(*vpx_codec_get_preview_frame_fn_t)(vpx_codec_alg_priv_t *ctx); (*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 /*!\brief usage configuration mapping
* *
* This structure stores the mapping between usage identifiers and * 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_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_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_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_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; } enc;
}; };
@ -353,9 +360,21 @@ struct vpx_codec_priv
unsigned int cx_data_pad_before; unsigned int cx_data_pad_before;
unsigned int cx_data_pad_after; unsigned int cx_data_pad_after;
vpx_codec_cx_pkt_t cx_data_pkt; vpx_codec_cx_pkt_t cx_data_pkt;
unsigned int total_encoders;
} enc; } 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 #undef VPX_CTRL_USE_TYPE
#define VPX_CTRL_USE_TYPE(id, typ) \ #define VPX_CTRL_USE_TYPE(id, typ) \
static typ id##__value(va_list args) {return va_arg(args, typ);} \ static typ id##__value(va_list args) {return va_arg(args, typ);} \

View File

@ -56,7 +56,7 @@ vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx,
if (!(flags & VPX_CODEC_USE_XMA)) if (!(flags & VPX_CODEC_USE_XMA))
{ {
res = ctx->iface->init(ctx); res = ctx->iface->init(ctx, NULL);
if (res) if (res)
{ {

View File

@ -51,7 +51,7 @@ vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t *ctx,
ctx->priv = NULL; ctx->priv = NULL;
ctx->init_flags = flags; ctx->init_flags = flags;
ctx->config.enc = cfg; ctx->config.enc = cfg;
res = ctx->iface->init(ctx); res = ctx->iface->init(ctx, NULL);
if (res) 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); 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, 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, vpx_enc_frame_flags_t flags,
unsigned long deadline) unsigned long deadline)
{ {
vpx_codec_err_t res; vpx_codec_err_t res = 0;
if (!ctx || (img && !duration)) if (!ctx || (img && !duration))
res = VPX_CODEC_INVALID_PARAM; 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 /* Execute in a normalized floating point environment, if the platform
* requires it. * requires it.
*/ */
unsigned int num_enc =ctx->priv->enc.total_encoders;
FLOATING_POINT_INIT(); 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(); FLOATING_POINT_RESTORE();
} }

View File

@ -634,7 +634,6 @@ extern "C" {
* then ts_layer_id = (0,1,0,1,0,1,0,1). * then ts_layer_id = (0,1,0,1,0,1,0,1).
*/ */
unsigned int ts_layer_id[MAX_PERIODICITY]; unsigned int ts_layer_id[MAX_PERIODICITY];
} vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */ } 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) 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 /*!\brief Get a default configuration
* *
* Initializes a encoder configuration structure with default values. Supports * Initializes a encoder configuration structure with default values. Supports
@ -780,7 +821,6 @@ extern "C" {
vpx_enc_frame_flags_t flags, vpx_enc_frame_flags_t flags,
unsigned long deadline); unsigned long deadline);
/*!\brief Set compressed data output buffer /*!\brief Set compressed data output buffer
* *
* Sets the buffer that the codec should output the compressed data * Sets the buffer that the codec should output the compressed data