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_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() {

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.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
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:
\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

View File

@ -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
*/

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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
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
#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

View File

@ -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);

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

View File

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

View File

@ -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
(

View File

@ -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);

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,
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 */
};

View File

@ -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;

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

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
* 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);} \

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))
{
res = ctx->iface->init(ctx);
res = ctx->iface->init(ctx, NULL);
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->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();
}

View File

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