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