Compare commits

..

32 Commits

Author SHA1 Message Date
Jingning Han
9d9b70a36a Allow backward prob update in external mode info coding flow
This commit enables vpxenc to properly count the coded motion
vector related information for backward update. This allows the
coding flow using external mode info to use backward probability
update. In the short test clip, over 10% bit-rate saving is
observed at no distortion change.

Change-Id: Ie27e97114ab91c3d95ba7b5554d617d226db5e20
2014-07-21 12:11:31 -07:00
Jingning Han
1e168d12d9 Enable motion vector based prediction mode decision
This commit enables vpxenc to compare the motion vector provided
by external file to the predicted motion vectors and select the
prediction mode with minimum rate cost if motion vector is matched.
It doesn't change reconstruction distortion, but provide rate
savings.

Change-Id: Ia682b775d2bafcaabb5a113bd90a98e1931c9c5a
2014-07-17 16:35:11 -07:00
Jingning Han
6ee6e714b4 Make key frame coding mode configurable in the command line
Add --kf-extc configuration. If it is 1, the key frame is coded
using mode info from external file; otherwise, use vpxenc internal
mode selection process to decide coding modes. It is by default 0.

Change-Id: I916f811f9eaa2d0f6cc2a2035ca381a1b0ddd974
2014-07-17 11:52:21 -07:00
Jingning Han
674cc787d3 Update the effective motion vector of sub8x8 blocks
This commit enables the vpxenc to update the effective motion
vectors stored in the mode_info struct for sub8x8 block coding. It
resolves the reference motion vector enc/dec mismatch issue.

Change-Id: I93a88fed6f15fad06a41ca21e297d7281cb75c57
2014-07-16 21:37:15 -07:00
Jingning Han
c765cd1a78 Properly handle the effective motion vector in inferred mv modes
This commit allows vpxenc to properly set the effective motion
vector values in the mode_info struct for inferred motion vector
modes. It resolves an enc/dec mismatch issue due to the mode info
struct loaded from external file has conflict effective motion
vector and inferred prediction mode.

Change-Id: I1f47aeaf2b92fcd4dd3d4f3644b88466495be070
2014-07-16 21:35:29 -07:00
Jingning Han
9e3965ae90 Make external sub8x8 block mode info conformable coding decisions
This commit converts the sub8x8 block mode info from external file
into proper format that conforms the bit-stream definitions. It
resolves an enc/dec mismatch issue in sub8x8 block coding used in
the inter frames.

Change-Id: Ie5717b19d0d06e0f525f9b7c7311abdd40f7885f
2014-07-15 22:40:33 -07:00
Jingning Han
f297504f2d Re-work configure interface for encoding based on external mi
This commit refines the configuration interface for encoding
process based on external mode info. It allows the vpxenc to read
the external file name from command line, and to produce warning
message when necessary.

Change-Id: I109d02ea9e6e418d00378d512ed9ab9bb0770dbd
2014-07-14 15:30:03 -07:00
Jingning Han
b4b897605a Allow more coding flexibility in key frame coding
This commit relaxes the encoding mode constraints on key frame
coding. It improves the key frame coding performance in speed 5 and
up.

Change-Id: I114315c2b467174bb1f135f4ab2c1f328c8c65be
2014-07-11 09:55:38 -07:00
Jingning Han
51959786d2 Merge "Use normal encoding route for key frame coding" into sandbox/Jingning/transcode 2014-07-10 10:55:24 -07:00
Jingning Han
502baedb48 Enable motion vector precision regulation conversion
This commit allows the vpxenc to check if the motion vectors read
from external file comply the frame header. If the frame is using
lower precision, the codec will convert the non-conformable motion
vectors into corresponding level.

This fixes another outstanding enc/dec mismatch issue due to the
mode_info values provided by external file not complying the
bit-stream definitions.

Change-Id: Ie5409f5d3201e9159f6a49c7608db3541f8a190c
2014-07-09 16:58:44 -07:00
Jingning Han
2568ff0081 Enforce tx_size conversion to handle invalid mode_info values
This commit forces a transform size check to handle the case where
the provided transform size is larger than the block size. In such
cases, it will convert the transform size to be the maximally
allowed value according to the block size.

Change-Id: I6ae26d5008fd60955427e2b7d5dcd3daa6eeb531
2014-07-09 10:31:41 -07:00
Jingning Han
4f2aeceabe Use normal encoding route for key frame coding
This commit makes the key frame coding to use the normal vpxenc
coding route. The encoding process based on mode_info read from
external file now starts from the first inter frame.

Change-Id: Iee5ae2c3aa35d4b89d0cb4e890b9b0f29fe89d62
2014-07-08 12:06:31 -07:00
Jim Bankoski
06eed502bd adjust the context we got from file
Change-Id: Ifeed2fa6b8dbc735f3746548e4535d522e732990
2014-07-07 16:03:32 -07:00
Jingning Han
5e9f681dec Merge "Force the use of selectable transform size" into sandbox/Jingning/transcode 2014-07-01 10:51:15 -07:00
Jingning Han
80bd67f09d Merge "Disable decoder read/write access to the mode_info array" into sandbox/Jingning/transcode 2014-07-01 10:32:07 -07:00
Jingning Han
d019119777 Force the use of selectable transform size
Change-Id: I87034c5933a9cfc6f82b925bcae11a2e6509c472
2014-06-30 17:17:31 -07:00
Jingning Han
6af2a29764 Disable decoder read/write access to the mode_info array
The decoder read/write access to the mode_info array was for the
purpose of creating a conformable coding mode decisions and hence
validating the encoding process based on exteranl mode_info
array. This commit makes a flag to disable all such potential access.

Change-Id: I21ece4b595c1c24cdf5581a3147fe76bf33a5570
2014-06-30 14:49:15 -07:00
Jingning Han
a3d2b5213e Merge "Enable vpxenc to process and convert external mode_info" into sandbox/Jingning/transcode 2014-06-30 11:15:53 -07:00
Jingning Han
0d075d907c Merge "Add optional mode_info printout function for debug purpose" into sandbox/Jingning/transcode 2014-06-27 16:34:42 -07:00
Jingning Han
1bf27df775 Enable vpxenc to process and convert external mode_info
This commit enables the encoder to convert the mode information
read from external file into effective VP9 coding decisions. Further
optimization for compression performance can be applied therein.

Change-Id: Ic3abb8e223ed4b5aa54e5ed099feb450c1ad9363
2014-06-27 16:10:26 -07:00
Jingning Han
d7e8490d04 Add optional mode_info printout function for debug purpose
This commit adds an optional function to print out the mode_info
loaded from external file for debug purpose. It can be turned on
by setting PRINT_MODE_INFO_LOAD 1.

Change-Id: I8612801cbf2eb38213105afb7434da2584b3ff2c
2014-06-26 12:11:44 -07:00
Jingning Han
68556c2f1d Merge "Silence quantization index check warnings" into sandbox/Jingning/transcode 2014-06-19 14:37:23 -07:00
Jingning Han
19c1c1f429 Merge "Make encoding process support non-switchable filter" into sandbox/Jingning/transcode 2014-06-19 14:37:05 -07:00
Jingning Han
1153454cd0 Merge "Enable encoding and bit-stream writing based on mode_info array" into sandbox/Jingning/transcode 2014-06-19 14:36:37 -07:00
Jingning Han
8f17deb617 Merge "Dump mode_info array from vp9 decoder to external file" into sandbox/Jingning/transcode 2014-06-19 14:36:20 -07:00
Jingning Han
f5bb406799 Merge "Add transcode flag in the experimental list" into sandbox/Jingning/transcode 2014-06-19 14:36:09 -07:00
Jingning Han
ff073a70ee Silence quantization index check warnings
Allow the encoder to use fixed quantization step size. Note that
this effectively breaks the internal rate control scheme and
can cause substantial compression performance.

Change-Id: I1caacb1ab06629107f8975e5f707de16d6d5b36a
2014-06-19 09:52:09 -07:00
Jingning Han
44877260a5 Make encoding process support non-switchable filter
This commit allows the encoder to handle cases where the encoder
is forced to use an arbitrary prediction filter type.

Change-Id: I984e554ef8b05d88d3c1714c0b621f5cf09f5dd6
2014-06-17 15:03:49 -07:00
Jingning Han
06510d1ff9 Enable encoding and bit-stream writing based on mode_info array
This commit enables vpxenc to encode and write out bit-stream from
coding information provided by external mode_info array file. It
currently assumes single reference frame and 8-tap switchable
prediction filters at frame header level.

Tested using the mode_info array dumped at VP9 decoder into the
external file, where the bit-stream was generated by VP9 encoder
at speed -6. The coding statics remain the same.

Note that the compression performance will be affected quite a lot
in the two pass coding setting, where at this point the rate
control scheme can not be updated properly without statistics
gathered during rate distortion optimization search.

Change-Id: Ide979d08d3ce6167c1f2e513c34fd8440f3e2aaf
2014-06-17 14:57:43 -07:00
Jingning Han
b95807f2bb Dump mode_info array from vp9 decoder to external file
This commit allows the vp9 decoder to dump the decoded mode_info
array, per 64x64, into external file, which serves as conformable
test vector for transcoding encoder. The mode_info of 8x8 block
inside a 64x64 block is aligned in raster order.

Change-Id: I0447d62922c674a674c0d4b31184625cf722f872
2014-06-11 15:26:42 -07:00
Jingning Han
de810ac620 Add transcode flag in the experimental list
Change-Id: I756b5899d3b5101643b4e084a1647a15b427d9e9
2014-06-11 11:45:46 -07:00
Jingning Han
0b3ffed9be Add transcode flag in the experimental list
Change-Id: I756b5899d3b5101643b4e084a1647a15b427d9e9
2014-06-11 11:18:02 -07:00
1189 changed files with 192279 additions and 253227 deletions

View File

@@ -1,68 +0,0 @@
---
Language: Cpp
# BasedOnStyle: Google
# Generated with clang-format 3.7.1
AccessModifierOffset: -1
AlignAfterOpenBracket: true
AlignConsecutiveAssignments: false
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IndentCaseLabels: true
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never
...

6
.gitignore vendored
View File

@@ -30,32 +30,28 @@
/examples/decode_with_partial_drops /examples/decode_with_partial_drops
/examples/example_xma /examples/example_xma
/examples/postproc /examples/postproc
/examples/resize_util
/examples/set_maps /examples/set_maps
/examples/simple_decoder /examples/simple_decoder
/examples/simple_encoder /examples/simple_encoder
/examples/twopass_encoder /examples/twopass_encoder
/examples/vp8_multi_resolution_encoder /examples/vp8_multi_resolution_encoder
/examples/vp8cx_set_ref /examples/vp8cx_set_ref
/examples/vp9_lossless_encoder
/examples/vp9_spatial_scalable_encoder /examples/vp9_spatial_scalable_encoder
/examples/vpx_temporal_scalable_patterns /examples/vpx_temporal_scalable_patterns
/examples/vpx_temporal_svc_encoder
/ivfdec /ivfdec
/ivfdec.dox /ivfdec.dox
/ivfenc /ivfenc
/ivfenc.dox /ivfenc.dox
/libvpx.so* /libvpx.so*
/libvpx.ver /libvpx.ver
/obj_int_extract
/samples.dox /samples.dox
/test_intra_pred_speed
/test_libvpx /test_libvpx
/vp8_api1_migration.dox /vp8_api1_migration.dox
/vp[89x]_rtcd.h /vp[89x]_rtcd.h
/vpx.pc /vpx.pc
/vpx_config.c /vpx_config.c
/vpx_config.h /vpx_config.h
/vpx_dsp_rtcd.h
/vpx_scale_rtcd.h /vpx_scale_rtcd.h
/vpx_version.h /vpx_version.h
/vpxdec /vpxdec

View File

@@ -1,32 +1,18 @@
Adrian Grange <agrange@google.com> Adrian Grange <agrange@google.com>
Aex Converse <aconverse@google.com>
Aex Converse <aconverse@google.com> <alex.converse@gmail.com>
Alexis Ballier <aballier@gentoo.org> <alexis.ballier@gmail.com> Alexis Ballier <aballier@gentoo.org> <alexis.ballier@gmail.com>
Alpha Lam <hclam@google.com> <hclam@chromium.org>
Deb Mukherjee <debargha@google.com>
Erik Niemeyer <erik.a.niemeyer@intel.com> <erik.a.niemeyer@gmail.com>
Guillaume Martres <gmartres@google.com> <smarter3@gmail.com>
Hangyu Kuang <hkuang@google.com> Hangyu Kuang <hkuang@google.com>
Hui Su <huisu@google.com>
Jacky Chen <jackychen@google.com>
Jim Bankoski <jimbankoski@google.com> Jim Bankoski <jimbankoski@google.com>
John Koleszar <jkoleszar@google.com>
Johann Koenig <johannkoenig@google.com> Johann Koenig <johannkoenig@google.com>
Johann Koenig <johannkoenig@google.com> <johann.koenig@duck.com> Johann Koenig <johannkoenig@google.com> <johann.koenig@duck.com>
Johann Koenig <johannkoenig@google.com> <johann.koenig@gmail.com> Johann Koenig <johannkoenig@google.com> <johannkoenig@dhcp-172-19-7-52.mtv.corp.google.com>
John Koleszar <jkoleszar@google.com>
Joshua Litt <joshualitt@google.com> <joshualitt@chromium.org>
Marco Paniconi <marpan@google.com>
Marco Paniconi <marpan@google.com> <marpan@chromium.org>
Pascal Massimino <pascal.massimino@gmail.com> Pascal Massimino <pascal.massimino@gmail.com>
Paul Wilkins <paulwilkins@google.com>
Ralph Giles <giles@xiph.org> <giles@entropywave.com>
Ralph Giles <giles@xiph.org> <giles@mozilla.com>
Ronald S. Bultje <rsbultje@gmail.com> <rbultje@google.com>
Sami Pietilä <samipietila@google.com> Sami Pietilä <samipietila@google.com>
Tamar Levy <tamar.levy@intel.com>
Tamar Levy <tamar.levy@intel.com> <levytamar82@gmail.com>
Tero Rintaluoma <teror@google.com> <tero.rintaluoma@on2.com> Tero Rintaluoma <teror@google.com> <tero.rintaluoma@on2.com>
Timothy B. Terriberry <tterribe@xiph.org> Tim Terriberry <tterriberry@mozilla.com> Timothy B. Terriberry <tterribe@xiph.org> Tim Terriberry <tterriberry@mozilla.com>
Tom Finegan <tomfinegan@google.com> Tom Finegan <tomfinegan@google.com>
Tom Finegan <tomfinegan@google.com> <tomfinegan@chromium.org> Ralph Giles <giles@xiph.org> <giles@entropywave.com>
Ralph Giles <giles@xiph.org> <giles@mozilla.com>
Alpha Lam <hclam@google.com> <hclam@chromium.org>
Deb Mukherjee <debargha@google.com>
Yaowu Xu <yaowu@google.com> <yaowu@xuyaowu.com> Yaowu Xu <yaowu@google.com> <yaowu@xuyaowu.com>

40
AUTHORS
View File

@@ -3,11 +3,10 @@
Aaron Watry <awatry@gmail.com> Aaron Watry <awatry@gmail.com>
Abo Talib Mahfoodh <ab.mahfoodh@gmail.com> Abo Talib Mahfoodh <ab.mahfoodh@gmail.com>
Adam Xu <adam@xuyaowu.com>
Adrian Grange <agrange@google.com> Adrian Grange <agrange@google.com>
Aex Converse <aconverse@google.com>
Ahmad Sharif <asharif@google.com> Ahmad Sharif <asharif@google.com>
Alexander Voronov <avoronov@graphics.cs.msu.ru> Alexander Voronov <avoronov@graphics.cs.msu.ru>
Alex Converse <alex.converse@gmail.com>
Alexis Ballier <aballier@gentoo.org> Alexis Ballier <aballier@gentoo.org>
Alok Ahuja <waveletcoeff@gmail.com> Alok Ahuja <waveletcoeff@gmail.com>
Alpha Lam <hclam@google.com> Alpha Lam <hclam@google.com>
@@ -15,65 +14,44 @@ A.Mahfoodh <ab.mahfoodh@gmail.com>
Ami Fischman <fischman@chromium.org> Ami Fischman <fischman@chromium.org>
Andoni Morales Alastruey <ylatuya@gmail.com> Andoni Morales Alastruey <ylatuya@gmail.com>
Andres Mejia <mcitadel@gmail.com> Andres Mejia <mcitadel@gmail.com>
Andrew Russell <anrussell@google.com>
Angie Chiang <angiebird@google.com>
Aron Rosenberg <arosenberg@logitech.com> Aron Rosenberg <arosenberg@logitech.com>
Attila Nagy <attilanagy@google.com> Attila Nagy <attilanagy@google.com>
Brion Vibber <bvibber@wikimedia.org>
changjun.yang <changjun.yang@intel.com> changjun.yang <changjun.yang@intel.com>
Charles 'Buck' Krasic <ckrasic@google.com>
chm <chm@rock-chips.com> chm <chm@rock-chips.com>
Christian Duvivier <cduvivier@google.com> Christian Duvivier <cduvivier@google.com>
Daniel Kang <ddkang@google.com> Daniel Kang <ddkang@google.com>
Deb Mukherjee <debargha@google.com> Deb Mukherjee <debargha@google.com>
Dim Temp <dimtemp0@gmail.com>
Dmitry Kovalev <dkovalev@google.com> Dmitry Kovalev <dkovalev@google.com>
Dragan Mrdjan <dmrdjan@mips.com> Dragan Mrdjan <dmrdjan@mips.com>
Ed Baker <edward.baker@intel.com> Erik Niemeyer <erik.a.niemeyer@gmail.com>
Ehsan Akhgari <ehsan.akhgari@gmail.com>
Erik Niemeyer <erik.a.niemeyer@intel.com>
Fabio Pedretti <fabio.ped@libero.it> Fabio Pedretti <fabio.ped@libero.it>
Frank Galligan <fgalligan@google.com> Frank Galligan <fgalligan@google.com>
Fredrik Söderquist <fs@opera.com> Fredrik Söderquist <fs@opera.com>
Fritz Koenig <frkoenig@google.com> Fritz Koenig <frkoenig@google.com>
Gaute Strokkenes <gaute.strokkenes@broadcom.com> Gaute Strokkenes <gaute.strokkenes@broadcom.com>
Geza Lore <gezalore@gmail.com>
Ghislain MARY <ghislainmary2@gmail.com>
Giuseppe Scrivano <gscrivano@gnu.org> Giuseppe Scrivano <gscrivano@gnu.org>
Gordana Cmiljanovic <gordana.cmiljanovic@imgtec.com>
Guillaume Martres <gmartres@google.com> Guillaume Martres <gmartres@google.com>
Guillermo Ballester Valor <gbvalor@gmail.com> Guillermo Ballester Valor <gbvalor@gmail.com>
Hangyu Kuang <hkuang@google.com> Hangyu Kuang <hkuang@google.com>
Hanno Böck <hanno@hboeck.de>
Henrik Lundin <hlundin@google.com> Henrik Lundin <hlundin@google.com>
Hui Su <huisu@google.com> Hui Su <huisu@google.com>
Ivan Maltz <ivanmaltz@google.com> Ivan Maltz <ivanmaltz@google.com>
Jacek Caban <cjacek@gmail.com>
Jacky Chen <jackychen@google.com>
James Berry <jamesberry@google.com> James Berry <jamesberry@google.com>
James Yu <james.yu@linaro.org>
James Zern <jzern@google.com> James Zern <jzern@google.com>
Jan Gerber <j@mailb.org>
Jan Kratochvil <jan.kratochvil@redhat.com> Jan Kratochvil <jan.kratochvil@redhat.com>
Janne Salonen <jsalonen@google.com> Janne Salonen <jsalonen@google.com>
Jeff Faust <jfaust@google.com> Jeff Faust <jfaust@google.com>
Jeff Muizelaar <jmuizelaar@mozilla.com> Jeff Muizelaar <jmuizelaar@mozilla.com>
Jeff Petkau <jpet@chromium.org> Jeff Petkau <jpet@chromium.org>
Jia Jia <jia.jia@linaro.org>
Jim Bankoski <jimbankoski@google.com> Jim Bankoski <jimbankoski@google.com>
Jingning Han <jingning@google.com> Jingning Han <jingning@google.com>
Joey Parrish <joeyparrish@google.com>
Johann Koenig <johannkoenig@google.com> Johann Koenig <johannkoenig@google.com>
John Koleszar <jkoleszar@google.com> John Koleszar <jkoleszar@google.com>
Johnny Klonaris <google@jawknee.com>
John Stark <jhnstrk@gmail.com>
Joshua Bleecher Snyder <josh@treelinelabs.com> Joshua Bleecher Snyder <josh@treelinelabs.com>
Joshua Litt <joshualitt@google.com> Joshua Litt <joshualitt@google.com>
Julia Robson <juliamrobson@gmail.com>
Justin Clift <justin@salasaga.org> Justin Clift <justin@salasaga.org>
Justin Lebar <justin.lebar@gmail.com> Justin Lebar <justin.lebar@gmail.com>
KO Myung-Hun <komh@chollian.net> KO Myung-Hun <komh@chollian.net>
Lawrence Velázquez <larryv@macports.org>
Lou Quillio <louquillio@google.com> Lou Quillio <louquillio@google.com>
Luca Barbato <lu_zero@gentoo.org> Luca Barbato <lu_zero@gentoo.org>
Makoto Kato <makoto.kt@gmail.com> Makoto Kato <makoto.kt@gmail.com>
@@ -87,48 +65,36 @@ Michael Kohler <michaelkohler@live.com>
Mike Frysinger <vapier@chromium.org> Mike Frysinger <vapier@chromium.org>
Mike Hommey <mhommey@mozilla.com> Mike Hommey <mhommey@mozilla.com>
Mikhal Shemer <mikhal@google.com> Mikhal Shemer <mikhal@google.com>
Minghai Shang <minghai@google.com>
Morton Jonuschat <yabawock@gmail.com> Morton Jonuschat <yabawock@gmail.com>
Nico Weber <thakis@chromium.org>
Parag Salasakar <img.mips1@gmail.com> Parag Salasakar <img.mips1@gmail.com>
Pascal Massimino <pascal.massimino@gmail.com> Pascal Massimino <pascal.massimino@gmail.com>
Patrik Westin <patrik.westin@gmail.com> Patrik Westin <patrik.westin@gmail.com>
Paul Wilkins <paulwilkins@google.com> Paul Wilkins <paulwilkins@google.com>
Pavol Rusnak <stick@gk2.sk> Pavol Rusnak <stick@gk2.sk>
Paweł Hajdan <phajdan@google.com> Paweł Hajdan <phajdan@google.com>
Pengchong Jin <pengchong@google.com>
Peter de Rivaz <peter.derivaz@gmail.com>
Philip Jägenstedt <philipj@opera.com> Philip Jägenstedt <philipj@opera.com>
Priit Laes <plaes@plaes.org> Priit Laes <plaes@plaes.org>
Rafael Ávila de Espíndola <rafael.espindola@gmail.com> Rafael Ávila de Espíndola <rafael.espindola@gmail.com>
Rafaël Carré <funman@videolan.org> Rafaël Carré <funman@videolan.org>
Ralph Giles <giles@xiph.org> Ralph Giles <giles@xiph.org>
Rob Bradford <rob@linux.intel.com> Rob Bradford <rob@linux.intel.com>
Ronald S. Bultje <rsbultje@gmail.com> Ronald S. Bultje <rbultje@google.com>
Rui Ueyama <ruiu@google.com>
Sami Pietilä <samipietila@google.com> Sami Pietilä <samipietila@google.com>
Scott Graham <scottmg@chromium.org> Scott Graham <scottmg@chromium.org>
Scott LaVarnway <slavarnway@google.com> Scott LaVarnway <slavarnway@google.com>
Sean McGovern <gseanmcg@gmail.com>
Sergey Ulanov <sergeyu@chromium.org>
Shimon Doodkin <helpmepro1@gmail.com> Shimon Doodkin <helpmepro1@gmail.com>
Shunyao Li <shunyaoli@google.com>
Stefan Holmer <holmer@google.com> Stefan Holmer <holmer@google.com>
Suman Sunkara <sunkaras@google.com> Suman Sunkara <sunkaras@google.com>
Taekhyun Kim <takim@nvidia.com> Taekhyun Kim <takim@nvidia.com>
Takanori MATSUURA <t.matsuu@gmail.com> Takanori MATSUURA <t.matsuu@gmail.com>
Tamar Levy <tamar.levy@intel.com> Tamar Levy <tamar.levy@intel.com>
Tao Bai <michaelbai@chromium.org>
Tero Rintaluoma <teror@google.com> Tero Rintaluoma <teror@google.com>
Thijs Vermeir <thijsvermeir@gmail.com> Thijs Vermeir <thijsvermeir@gmail.com>
Tim Kopp <tkopp@google.com>
Timothy B. Terriberry <tterribe@xiph.org> Timothy B. Terriberry <tterribe@xiph.org>
Tom Finegan <tomfinegan@google.com> Tom Finegan <tomfinegan@google.com>
Vignesh Venkatasubramanian <vigneshv@google.com> Vignesh Venkatasubramanian <vigneshv@google.com>
Yaowu Xu <yaowu@google.com> Yaowu Xu <yaowu@google.com>
Yongzhe Wang <yongzhe@google.com>
Yunqing Wang <yunqingwang@google.com> Yunqing Wang <yunqingwang@google.com>
Zoe Liu <zoeliu@google.com>
Google Inc. Google Inc.
The Mozilla Foundation The Mozilla Foundation
The Xiph.Org Foundation The Xiph.Org Foundation

View File

@@ -1,47 +1,3 @@
Next Release
- Incompatible changes:
The VP9 encoder's default keyframe interval changed to 128 from 9999.
2015-11-09 v1.5.0 "Javan Whistling Duck"
This release improves upon the VP9 encoder and speeds up the encoding and
decoding processes.
- Upgrading:
This release is ABI incompatible with 1.4.0. It drops deprecated VP8
controls and adds a variety of VP9 controls for testing.
The vpxenc utility now prefers VP9 by default.
- Enhancements:
Faster VP9 encoding and decoding
Smaller library size by combining functions used by VP8 and VP9
- Bug Fixes:
A variety of fuzzing issues
2015-04-03 v1.4.0 "Indian Runner Duck"
This release includes significant improvements to the VP9 codec.
- Upgrading:
This release is ABI incompatible with 1.3.0. It drops the compatibility
layer, requiring VPX_IMG_FMT_* instead of IMG_FMT_*, and adds several codec
controls for VP9.
- Enhancements:
Faster VP9 encoding and decoding
Multithreaded VP9 decoding (tile and frame-based)
Multithreaded VP9 encoding - on by default
YUV 4:2:2 and 4:4:4 support in VP9
10 and 12bit support in VP9
64bit ARM support by replacing ARM assembly with intrinsics
- Bug Fixes:
Fixes a VP9 bitstream issue in Profile 1. This only affected non-YUV 4:2:0
files.
- Known Issues:
Frame Parallel decoding fails for segmented and non-420 files.
2013-11-15 v1.3.0 "Forest" 2013-11-15 v1.3.0 "Forest"
This release introduces the VP9 codec in a backward-compatible way. This release introduces the VP9 codec in a backward-compatible way.
All existing users of VP8 can continue to use the library without All existing users of VP8 can continue to use the library without

39
PATENTS
View File

@@ -1,23 +1,22 @@
Additional IP Rights Grant (Patents) Additional IP Rights Grant (Patents)
------------------------------------
"These implementations" means the copyrightable works that implement the WebM "This implementation" means the copyrightable works distributed by
codecs distributed by Google as part of the WebM Project. Google as part of the WebM Project.
Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge, Google hereby grants to you a perpetual, worldwide, non-exclusive,
royalty-free, irrevocable (except as stated in this section) patent license to no-charge, royalty-free, irrevocable (except as stated in this section)
make, have made, use, offer to sell, sell, import, transfer, and otherwise patent license to make, have made, use, offer to sell, sell, import,
run, modify and propagate the contents of these implementations of WebM, where transfer, and otherwise run, modify and propagate the contents of this
such license applies only to those patent claims, both currently owned by implementation of VP8, where such license applies only to those patent
Google and acquired in the future, licensable by Google that are necessarily claims, both currently owned by Google and acquired in the future,
infringed by these implementations of WebM. This grant does not include claims licensable by Google that are necessarily infringed by this
that would be infringed only as a consequence of further modification of these implementation of VP8. This grant does not include claims that would be
implementations. If you or your agent or exclusive licensee institute or order infringed only as a consequence of further modification of this
or agree to the institution of patent litigation or any other patent implementation. If you or your agent or exclusive licensee institute or
enforcement activity against any entity (including a cross-claim or order or agree to the institution of patent litigation against any
counterclaim in a lawsuit) alleging that any of these implementations of WebM entity (including a cross-claim or counterclaim in a lawsuit) alleging
or any code incorporated within any of these implementations of WebM that this implementation of VP8 or any code incorporated within this
constitute direct or contributory patent infringement, or inducement of implementation of VP8 constitutes direct or contributory patent
patent infringement, then any patent rights granted to you under this License infringement, or inducement of patent infringement, then any patent
for these implementations of WebM shall terminate as of the date such rights granted to you under this License for this implementation of VP8
litigation is filed. shall terminate as of the date such litigation is filed.

35
README
View File

@@ -1,4 +1,4 @@
README - 23 March 2015 README - 30 May 2014
Welcome to the WebM VP8/VP9 Codec SDK! Welcome to the WebM VP8/VP9 Codec SDK!
@@ -47,10 +47,14 @@ COMPILING THE APPLICATIONS/LIBRARIES:
--help output of the configure script. As of this writing, the list of --help output of the configure script. As of this writing, the list of
available targets is: available targets is:
armv5te-android-gcc
armv5te-linux-rvct
armv5te-linux-gcc
armv5te-none-rvct
armv6-darwin-gcc
armv6-linux-rvct armv6-linux-rvct
armv6-linux-gcc armv6-linux-gcc
armv6-none-rvct armv6-none-rvct
arm64-darwin-gcc
armv7-android-gcc armv7-android-gcc
armv7-darwin-gcc armv7-darwin-gcc
armv7-linux-rvct armv7-linux-rvct
@@ -58,10 +62,13 @@ COMPILING THE APPLICATIONS/LIBRARIES:
armv7-none-rvct armv7-none-rvct
armv7-win32-vs11 armv7-win32-vs11
armv7-win32-vs12 armv7-win32-vs12
armv7-win32-vs14
armv7s-darwin-gcc
mips32-linux-gcc mips32-linux-gcc
mips64-linux-gcc ppc32-darwin8-gcc
ppc32-darwin9-gcc
ppc32-linux-gcc
ppc64-darwin8-gcc
ppc64-darwin9-gcc
ppc64-linux-gcc
sparc-solaris-gcc sparc-solaris-gcc
x86-android-gcc x86-android-gcc
x86-darwin8-gcc x86-darwin8-gcc
@@ -72,33 +79,37 @@ COMPILING THE APPLICATIONS/LIBRARIES:
x86-darwin11-gcc x86-darwin11-gcc
x86-darwin12-gcc x86-darwin12-gcc
x86-darwin13-gcc x86-darwin13-gcc
x86-darwin14-gcc
x86-iphonesimulator-gcc
x86-linux-gcc x86-linux-gcc
x86-linux-icc x86-linux-icc
x86-os2-gcc x86-os2-gcc
x86-solaris-gcc x86-solaris-gcc
x86-win32-gcc x86-win32-gcc
x86-win32-vs7
x86-win32-vs8
x86-win32-vs9
x86-win32-vs10 x86-win32-vs10
x86-win32-vs11 x86-win32-vs11
x86-win32-vs12 x86-win32-vs12
x86-win32-vs14
x86_64-android-gcc
x86_64-darwin9-gcc x86_64-darwin9-gcc
x86_64-darwin10-gcc x86_64-darwin10-gcc
x86_64-darwin11-gcc x86_64-darwin11-gcc
x86_64-darwin12-gcc x86_64-darwin12-gcc
x86_64-darwin13-gcc x86_64-darwin13-gcc
x86_64-darwin14-gcc
x86_64-iphonesimulator-gcc
x86_64-linux-gcc x86_64-linux-gcc
x86_64-linux-icc x86_64-linux-icc
x86_64-solaris-gcc x86_64-solaris-gcc
x86_64-win64-gcc x86_64-win64-gcc
x86_64-win64-vs8
x86_64-win64-vs9
x86_64-win64-vs10 x86_64-win64-vs10
x86_64-win64-vs11 x86_64-win64-vs11
x86_64-win64-vs12 x86_64-win64-vs12
x86_64-win64-vs14 universal-darwin8-gcc
universal-darwin9-gcc
universal-darwin10-gcc
universal-darwin11-gcc
universal-darwin12-gcc
universal-darwin13-gcc
generic-gnu generic-gnu
The generic-gnu target, in conjunction with the CROSS environment variable, The generic-gnu target, in conjunction with the CROSS environment variable,

4
args.c
View File

@@ -14,7 +14,9 @@
#include <limits.h> #include <limits.h>
#include "args.h" #include "args.h"
#include "vpx_ports/msvc.h" #ifdef _MSC_VER
#define snprintf _snprintf
#endif
#if defined(__GNUC__) && __GNUC__ #if defined(__GNUC__) && __GNUC__
extern void die(const char *fmt, ...) __attribute__((noreturn)); extern void die(const char *fmt, ...) __attribute__((noreturn));

1
args.h
View File

@@ -51,7 +51,6 @@ char **argv_dup(int argc, const char **argv);
unsigned int arg_parse_uint(const struct arg *arg); unsigned int arg_parse_uint(const struct arg *arg);
int arg_parse_int(const struct arg *arg); int arg_parse_int(const struct arg *arg);
struct vpx_rational arg_parse_rational(const struct arg *arg); struct vpx_rational arg_parse_rational(const struct arg *arg);
int arg_parse_enum(const struct arg *arg);
int arg_parse_enum_or_int(const struct arg *arg); int arg_parse_enum_or_int(const struct arg *arg);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View File

@@ -0,0 +1,18 @@
REM Copyright (c) 2013 The WebM project authors. All Rights Reserved.
REM
REM Use of this source code is governed by a BSD-style license
REM that can be found in the LICENSE file in the root of the source
REM tree. An additional intellectual property rights grant can be found
REM in the file PATENTS. All contributing project authors may
REM be found in the AUTHORS file in the root of the source tree.
echo on
REM Arguments:
REM %1 - Relative path to the directory containing the vp8 and vpx_scale
REM source directories.
REM %2 - Path to obj_int_extract.exe.
cl /I. /I%1 /nologo /c /DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP "%~1/vp8/encoder/vp8_asm_enc_offsets.c"
%2\obj_int_extract.exe rvds "vp8_asm_enc_offsets.obj" > "vp8_asm_enc_offsets.asm"
cl /I. /I%1 /nologo /c /DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP "%~1/vpx_scale/vpx_scale_asm_offsets.c"
%2\obj_int_extract.exe rvds "vpx_scale_asm_offsets.obj" > "vpx_scale_asm_offsets.asm"

View File

@@ -43,7 +43,7 @@
# will remove any NEON dependency. # will remove any NEON dependency.
# To change to building armeabi, run ./libvpx/configure again, but with # To change to building armeabi, run ./libvpx/configure again, but with
# --target=armv6-android-gcc and modify the Application.mk file to # --target=arm5te-android-gcc and modify the Application.mk file to
# set APP_ABI := armeabi # set APP_ABI := armeabi
# #
# Running ndk-build will build libvpx and include it in your project. # Running ndk-build will build libvpx and include it in your project.
@@ -60,15 +60,13 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
include $(CONFIG_DIR)libs-armv7-android-gcc.mk include $(CONFIG_DIR)libs-armv7-android-gcc.mk
LOCAL_ARM_MODE := arm LOCAL_ARM_MODE := arm
else ifeq ($(TARGET_ARCH_ABI),armeabi) else ifeq ($(TARGET_ARCH_ABI),armeabi)
include $(CONFIG_DIR)libs-armv6-android-gcc.mk include $(CONFIG_DIR)libs-armv5te-android-gcc.mk
LOCAL_ARM_MODE := arm LOCAL_ARM_MODE := arm
else ifeq ($(TARGET_ARCH_ABI),arm64-v8a) else ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
include $(CONFIG_DIR)libs-armv8-android-gcc.mk include $(CONFIG_DIR)libs-armv8-android-gcc.mk
LOCAL_ARM_MODE := arm LOCAL_ARM_MODE := arm
else ifeq ($(TARGET_ARCH_ABI),x86) else ifeq ($(TARGET_ARCH_ABI),x86)
include $(CONFIG_DIR)libs-x86-android-gcc.mk include $(CONFIG_DIR)libs-x86-android-gcc.mk
else ifeq ($(TARGET_ARCH_ABI),x86_64)
include $(CONFIG_DIR)libs-x86_64-android-gcc.mk
else ifeq ($(TARGET_ARCH_ABI),mips) else ifeq ($(TARGET_ARCH_ABI),mips)
include $(CONFIG_DIR)libs-mips-android-gcc.mk include $(CONFIG_DIR)libs-mips-android-gcc.mk
else else
@@ -93,8 +91,51 @@ LOCAL_CFLAGS := -O3
# like x86inc.asm and x86_abi_support.asm # like x86inc.asm and x86_abi_support.asm
LOCAL_ASMFLAGS := -I$(LIBVPX_PATH) LOCAL_ASMFLAGS := -I$(LIBVPX_PATH)
# -----------------------------------------------------------------------------
# Template : asm_offsets_template
# Arguments : 1: assembly offsets file to be created
# 2: c file to base assembly offsets on
# Returns : None
# Usage : $(eval $(call asm_offsets_template,<asmfile>, <srcfile>
# Rationale : Create offsets at compile time using for structures that are
# defined in c, but used in assembly functions.
# -----------------------------------------------------------------------------
define asm_offsets_template
_SRC:=$(2)
_OBJ:=$(ASM_CNV_PATH)/$$(notdir $(2)).S
_FLAGS = $$($$(my)CFLAGS) \
$$(call get-src-file-target-cflags,$(2)) \
$$(call host-c-includes,$$(LOCAL_C_INCLUDES) $$(CONFIG_DIR)) \
$$(LOCAL_CFLAGS) \
$$(NDK_APP_CFLAGS) \
$$(call host-c-includes,$$($(my)C_INCLUDES)) \
-DINLINE_ASM \
-S \
_TEXT = "Compile $$(call get-src-file-text,$(2))"
_CC = $$(TARGET_CC)
$$(eval $$(call ev-build-file))
$(1) : $$(_OBJ) $(2)
@mkdir -p $$(dir $$@)
@grep $(OFFSET_PATTERN) $$< | tr -d '\#' | $(CONFIG_DIR)$(ASM_CONVERSION) > $$@
endef
# Use ads2gas script to convert from RVCT format to GAS format. This
# puts the processed file under $(ASM_CNV_PATH). Local clean rule
# to handle removing these
ifeq ($(CONFIG_VP8_ENCODER), yes)
ASM_CNV_OFFSETS_DEPEND += $(ASM_CNV_PATH)/vp8_asm_enc_offsets.asm
endif
ifeq ($(HAVE_NEON_ASM), yes)
ASM_CNV_OFFSETS_DEPEND += $(ASM_CNV_PATH)/vpx_scale_asm_offsets.asm
endif
.PRECIOUS: %.asm.s .PRECIOUS: %.asm.s
$(ASM_CNV_PATH)/libvpx/%.asm.s: $(LIBVPX_PATH)/%.asm $(ASM_CNV_PATH)/libvpx/%.asm.s: $(LIBVPX_PATH)/%.asm $(ASM_CNV_OFFSETS_DEPEND)
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
@$(CONFIG_DIR)$(ASM_CONVERSION) <$< > $@ @$(CONFIG_DIR)$(ASM_CONVERSION) <$< > $@
@@ -160,38 +201,45 @@ LOCAL_CFLAGS += \
LOCAL_MODULE := libvpx LOCAL_MODULE := libvpx
LOCAL_LDLIBS := -llog
ifeq ($(CONFIG_RUNTIME_CPU_DETECT),yes) ifeq ($(CONFIG_RUNTIME_CPU_DETECT),yes)
LOCAL_STATIC_LIBRARIES := cpufeatures LOCAL_STATIC_LIBRARIES := cpufeatures
endif endif
# Add a dependency to force generation of the RTCD files. # Add a dependency to force generation of the RTCD files.
define rtcd_dep_template ifeq ($(CONFIG_VP8), yes)
rtcd_dep_template_SRCS := $(addprefix $(LOCAL_PATH)/, $(LOCAL_SRC_FILES)) $(foreach file, $(LOCAL_SRC_FILES), $(LOCAL_PATH)/$(file)): vp8_rtcd.h
rtcd_dep_template_SRCS := $$(rtcd_dep_template_SRCS:.neon=)
ifeq ($(CONFIG_VP10), yes)
$$(rtcd_dep_template_SRCS): vp10_rtcd.h
endif endif
$$(rtcd_dep_template_SRCS): vpx_scale_rtcd.h ifeq ($(CONFIG_VP9), yes)
$$(rtcd_dep_template_SRCS): vpx_dsp_rtcd.h $(foreach file, $(LOCAL_SRC_FILES), $(LOCAL_PATH)/$(file)): vp9_rtcd.h
ifneq ($(findstring $(TARGET_ARCH_ABI),x86 x86_64),)
$$(rtcd_dep_template_SRCS): vpx_config.asm
endif endif
endef $(foreach file, $(LOCAL_SRC_FILES), $(LOCAL_PATH)/$(file)): vpx_scale_rtcd.h
$(eval $(call rtcd_dep_template)) ifeq ($(TARGET_ARCH_ABI),x86)
$(foreach file, $(LOCAL_SRC_FILES), $(LOCAL_PATH)/$(file)): vpx_config.asm
endif
.PHONY: clean .PHONY: clean
clean: clean:
@echo "Clean: ads2gas files [$(TARGET_ARCH_ABI)]" @echo "Clean: ads2gas files [$(TARGET_ARCH_ABI)]"
@$(RM) $(CODEC_SRCS_ASM_ADS2GAS) $(CODEC_SRCS_ASM_NEON_ADS2GAS) @$(RM) $(CODEC_SRCS_ASM_ADS2GAS) $(CODEC_SRCS_ASM_NEON_ADS2GAS)
@$(RM) $(patsubst %.asm, %.*, $(ASM_CNV_OFFSETS_DEPEND))
@$(RM) -r $(ASM_CNV_PATH) @$(RM) -r $(ASM_CNV_PATH)
@$(RM) $(CLEAN-OBJS) @$(RM) $(CLEAN-OBJS)
ifeq ($(ENABLE_SHARED),1) include $(BUILD_SHARED_LIBRARY)
include $(BUILD_SHARED_LIBRARY)
else ifeq ($(HAVE_NEON), yes)
include $(BUILD_STATIC_LIBRARY) $(eval $(call asm_offsets_template,\
$(ASM_CNV_PATH)/vpx_scale_asm_offsets.asm, \
$(LIBVPX_PATH)/vpx_scale/vpx_scale_asm_offsets.c))
endif
ifeq ($(CONFIG_VP8_ENCODER), yes)
$(eval $(call asm_offsets_template,\
$(ASM_CNV_PATH)/vp8_asm_enc_offsets.asm, \
$(LIBVPX_PATH)/vp8/encoder/vp8_asm_enc_offsets.c))
endif endif
ifeq ($(CONFIG_RUNTIME_CPU_DETECT),yes) ifeq ($(CONFIG_RUNTIME_CPU_DETECT),yes)

View File

@@ -22,11 +22,9 @@ clean:: .DEFAULT
exampletest: .DEFAULT exampletest: .DEFAULT
install:: .DEFAULT install:: .DEFAULT
test:: .DEFAULT test:: .DEFAULT
test-no-data-check:: .DEFAULT
testdata:: .DEFAULT testdata:: .DEFAULT
utiltest: .DEFAULT utiltest: .DEFAULT
exampletest-no-data-check utiltest-no-data-check: .DEFAULT
test_%: .DEFAULT ;
# Note: md5sum is not installed on OS X, but openssl is. Openssl may not be # Note: md5sum is not installed on OS X, but openssl is. Openssl may not be
# installed on cygwin, so we need to autodetect here. # installed on cygwin, so we need to autodetect here.
@@ -58,10 +56,13 @@ dist:
fi fi
endif endif
# Since we invoke make recursively for multiple targets we need to include the
# .mk file for the correct target, but only when $(target) is non-empty.
ifneq ($(target),) ifneq ($(target),)
include $(target)-$(TOOLCHAIN).mk # Normally, we want to build the filename from the target and the toolchain.
# This disambiguates from the $(target).mk file that exists in the source tree.
# However, the toolchain is part of the target in universal builds, so we
# don't want to include TOOLCHAIN in that case. FAT_ARCHS is used to test
# if we're in the universal case.
include $(target)$(if $(FAT_ARCHS),,-$(TOOLCHAIN)).mk
endif endif
BUILD_ROOT?=. BUILD_ROOT?=.
VPATH=$(SRC_PATH_BARE) VPATH=$(SRC_PATH_BARE)
@@ -115,15 +116,8 @@ test::
testdata:: testdata::
.PHONY: utiltest .PHONY: utiltest
utiltest: utiltest:
.PHONY: test-no-data-check exampletest-no-data-check utiltest-no-data-check
test-no-data-check::
exampletest-no-data-check utiltest-no-data-check:
# Force to realign stack always on OS/2
ifeq ($(TOOLCHAIN), x86-os2-gcc)
CFLAGS += -mstackrealign
endif
# Add compiler flags for intrinsic files
$(BUILD_PFX)%_mmx.c.d: CFLAGS += -mmmx $(BUILD_PFX)%_mmx.c.d: CFLAGS += -mmmx
$(BUILD_PFX)%_mmx.c.o: CFLAGS += -mmmx $(BUILD_PFX)%_mmx.c.o: CFLAGS += -mmmx
$(BUILD_PFX)%_sse2.c.d: CFLAGS += -msse2 $(BUILD_PFX)%_sse2.c.d: CFLAGS += -msse2
@@ -146,7 +140,6 @@ $(BUILD_PFX)%.c.d: %.c
$(BUILD_PFX)%.c.o: %.c $(BUILD_PFX)%.c.o: %.c
$(if $(quiet),@echo " [CC] $@") $(if $(quiet),@echo " [CC] $@")
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
$(qexec)$(CC) $(INTERNAL_CFLAGS) $(CFLAGS) -c -o $@ $< $(qexec)$(CC) $(INTERNAL_CFLAGS) $(CFLAGS) -c -o $@ $<
$(BUILD_PFX)%.cc.d: %.cc $(BUILD_PFX)%.cc.d: %.cc
@@ -156,7 +149,6 @@ $(BUILD_PFX)%.cc.d: %.cc
$(BUILD_PFX)%.cc.o: %.cc $(BUILD_PFX)%.cc.o: %.cc
$(if $(quiet),@echo " [CXX] $@") $(if $(quiet),@echo " [CXX] $@")
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $< $(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
$(BUILD_PFX)%.cpp.d: %.cpp $(BUILD_PFX)%.cpp.d: %.cpp
@@ -166,7 +158,6 @@ $(BUILD_PFX)%.cpp.d: %.cpp
$(BUILD_PFX)%.cpp.o: %.cpp $(BUILD_PFX)%.cpp.o: %.cpp
$(if $(quiet),@echo " [CXX] $@") $(if $(quiet),@echo " [CXX] $@")
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $< $(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
$(BUILD_PFX)%.asm.d: %.asm $(BUILD_PFX)%.asm.d: %.asm
@@ -177,7 +168,6 @@ $(BUILD_PFX)%.asm.d: %.asm
$(BUILD_PFX)%.asm.o: %.asm $(BUILD_PFX)%.asm.o: %.asm
$(if $(quiet),@echo " [AS] $@") $(if $(quiet),@echo " [AS] $@")
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
$(qexec)$(AS) $(ASFLAGS) -o $@ $< $(qexec)$(AS) $(ASFLAGS) -o $@ $<
$(BUILD_PFX)%.s.d: %.s $(BUILD_PFX)%.s.d: %.s
@@ -188,14 +178,12 @@ $(BUILD_PFX)%.s.d: %.s
$(BUILD_PFX)%.s.o: %.s $(BUILD_PFX)%.s.o: %.s
$(if $(quiet),@echo " [AS] $@") $(if $(quiet),@echo " [AS] $@")
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
$(qexec)$(AS) $(ASFLAGS) -o $@ $< $(qexec)$(AS) $(ASFLAGS) -o $@ $<
.PRECIOUS: %.c.S .PRECIOUS: %.c.S
%.c.S: CFLAGS += -DINLINE_ASM %.c.S: CFLAGS += -DINLINE_ASM
$(BUILD_PFX)%.c.S: %.c $(BUILD_PFX)%.c.S: %.c
$(if $(quiet),@echo " [GEN] $@") $(if $(quiet),@echo " [GEN] $@")
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
$(qexec)$(CC) -S $(CFLAGS) -o $@ $< $(qexec)$(CC) -S $(CFLAGS) -o $@ $<
.PRECIOUS: %.asm.s .PRECIOUS: %.asm.s
@@ -208,13 +196,13 @@ $(BUILD_PFX)%.asm.s: %.asm
# the copy implementation # the copy implementation
HAVE_GNU_STRIP := $(if $(CONFIG_DEBUG),,$(HAVE_GNU_STRIP)) HAVE_GNU_STRIP := $(if $(CONFIG_DEBUG),,$(HAVE_GNU_STRIP))
ifeq ($(HAVE_GNU_STRIP),yes) ifeq ($(HAVE_GNU_STRIP),yes)
# Older binutils strip global symbols not needed for relocation processing # Older binutils strip global sybols not needed for relocation processing
# when given --strip-unneeded. Using nm and awk to identify globals and # when given --strip-unneeded. Use nm and awk to identify globals and
# keep them caused command line length issues under mingw and segfaults in # keep them.
# test_libvpx were observed under OS/2: simply use --strip-debug.
%.a: %_g.a %.a: %_g.a
$(if $(quiet),@echo " [STRIP] $@ < $<") $(if $(quiet),@echo " [STRIP] $@ < $<")
$(qexec)$(STRIP) --strip-debug \ $(qexec)$(STRIP) --strip-unneeded \
`$(NM) $< | grep ' [A-TV-Z] ' | awk '{print "-K"$$3'}`\
-o $@ $< -o $@ $<
else else
%.a: %_g.a %.a: %_g.a
@@ -222,6 +210,14 @@ else
$(qexec)cp $< $@ $(qexec)cp $< $@
endif endif
#
# Rule to extract assembly constants from C sources
#
obj_int_extract: build/make/obj_int_extract.c
$(if $(quiet),@echo " [HOSTCC] $@")
$(qexec)$(HOSTCC) -I. -I$(SRC_PATH_BARE) -o $@ $<
CLEAN-OBJS += obj_int_extract
# #
# Utility functions # Utility functions
# #
@@ -283,7 +279,7 @@ define archive_template
# for creating them. # for creating them.
$(1): $(1):
$(if $(quiet),@echo " [AR] $$@") $(if $(quiet),@echo " [AR] $$@")
$(qexec)$$(AR) $$(ARFLAGS) $$@ $$^ $(qexec)$$(AR) $$(ARFLAGS) $$@ $$?
endef endef
define so_template define so_template
@@ -313,15 +309,18 @@ $(1):
$$(filter %.o,$$^) $$(extralibs) $$(filter %.o,$$^) $$(extralibs)
endef endef
define dll_template
# Not using a pattern rule here because we don't want to generate empty
# archives when they are listed as a dependency in files not responsible define lipo_lib_template
# for creating them. $(1): $(addsuffix /$(1),$(FAT_ARCHS))
$(1): $(if $(quiet),@echo " [LIPO] $$@")
$(if $(quiet),@echo " [LD] $$@") $(qexec)libtool -static -o $$@ $$?
$(qexec)$$(LD) -Zdll $$(LDFLAGS) \ endef
-o $$@ \
$$(filter %.o,$$^) $$(extralibs) $$(EXPORTS_FILE) define lipo_bin_template
$(1): $(addsuffix /$(1),$(FAT_ARCHS))
$(if $(quiet),@echo " [LIPO] $$@")
$(qexec)lipo -output $$@ -create $$?
endef endef
@@ -331,16 +330,11 @@ endef
ifneq ($(target),) ifneq ($(target),)
include $(SRC_PATH_BARE)/$(target:-$(TOOLCHAIN)=).mk include $(SRC_PATH_BARE)/$(target:-$(TOOLCHAIN)=).mk
endif endif
ifeq ($(filter %clean,$(MAKECMDGOALS)),)
skip_deps := $(filter %clean,$(MAKECMDGOALS))
skip_deps += $(findstring testdata,$(MAKECMDGOALS))
ifeq ($(strip $(skip_deps)),)
ifeq ($(CONFIG_DEPENDENCY_TRACKING),yes)
# Older versions of make don't like -include directives with no arguments # Older versions of make don't like -include directives with no arguments
ifneq ($(filter %.d,$(OBJS-yes:.o=.d)),) ifneq ($(filter %.d,$(OBJS-yes:.o=.d)),)
-include $(filter %.d,$(OBJS-yes:.o=.d)) -include $(filter %.d,$(OBJS-yes:.o=.d))
endif endif
endif
endif endif
# #
@@ -380,9 +374,8 @@ LIBS=$(call enabled,LIBS)
.libs: $(LIBS) .libs: $(LIBS)
@touch $@ @touch $@
$(foreach lib,$(filter %_g.a,$(LIBS)),$(eval $(call archive_template,$(lib)))) $(foreach lib,$(filter %_g.a,$(LIBS)),$(eval $(call archive_template,$(lib))))
$(foreach lib,$(filter %so.$(SO_VERSION_MAJOR).$(SO_VERSION_MINOR).$(SO_VERSION_PATCH),$(LIBS)),$(eval $(call so_template,$(lib)))) $(foreach lib,$(filter %so.$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH),$(LIBS)),$(eval $(call so_template,$(lib))))
$(foreach lib,$(filter %$(SO_VERSION_MAJOR).dylib,$(LIBS)),$(eval $(call dl_template,$(lib)))) $(foreach lib,$(filter %$(VERSION_MAJOR).dylib,$(LIBS)),$(eval $(call dl_template,$(lib))))
$(foreach lib,$(filter %$(SO_VERSION_MAJOR).dll,$(LIBS)),$(eval $(call dll_template,$(lib))))
INSTALL-LIBS=$(call cond_enabled,CONFIG_INSTALL_LIBS,INSTALL-LIBS) INSTALL-LIBS=$(call cond_enabled,CONFIG_INSTALL_LIBS,INSTALL-LIBS)
ifeq ($(MAKECMDGOALS),dist) ifeq ($(MAKECMDGOALS),dist)
@@ -418,10 +411,15 @@ ifneq ($(call enabled,DIST-SRCS),)
DIST-SRCS-yes += build/make/gen_asm_deps.sh DIST-SRCS-yes += build/make/gen_asm_deps.sh
DIST-SRCS-yes += build/make/Makefile DIST-SRCS-yes += build/make/Makefile
DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_def.sh DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_def.sh
DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_proj.sh
DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_sln.sh DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_sln.sh
DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_vcxproj.sh DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_vcxproj.sh
DIST-SRCS-$(CONFIG_MSVS) += build/make/msvs_common.sh DIST-SRCS-$(CONFIG_MSVS) += build/make/msvs_common.sh
DIST-SRCS-$(CONFIG_MSVS) += build/x86-msvs/obj_int_extract.bat
DIST-SRCS-$(CONFIG_MSVS) += build/arm-msvs/obj_int_extract.bat
DIST-SRCS-$(CONFIG_RVCT) += build/make/armlink_adapter.sh DIST-SRCS-$(CONFIG_RVCT) += build/make/armlink_adapter.sh
# Include obj_int_extract if we use offsets from *_asm_*_offsets
DIST-SRCS-$(ARCH_ARM)$(ARCH_X86)$(ARCH_X86_64) += build/make/obj_int_extract.c
DIST-SRCS-$(ARCH_ARM) += build/make/ads2gas.pl DIST-SRCS-$(ARCH_ARM) += build/make/ads2gas.pl
DIST-SRCS-$(ARCH_ARM) += build/make/ads2gas_apple.pl DIST-SRCS-$(ARCH_ARM) += build/make/ads2gas_apple.pl
DIST-SRCS-$(ARCH_ARM) += build/make/ads2armasm_ms.pl DIST-SRCS-$(ARCH_ARM) += build/make/ads2armasm_ms.pl
@@ -448,5 +446,3 @@ all: $(BUILD_TARGETS)
install:: $(INSTALL_TARGETS) install:: $(INSTALL_TARGETS)
dist: $(INSTALL_TARGETS) dist: $(INSTALL_TARGETS)
test:: test::
.SUFFIXES: # Delete default suffix rules

575
build/make/configure.sh Normal file → Executable file

File diff suppressed because it is too large Load Diff

526
build/make/gen_msvs_proj.sh Executable file
View File

@@ -0,0 +1,526 @@
#!/bin/bash
##
## 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.
##
self=$0
self_basename=${self##*/}
self_dirname=$(dirname "$0")
. "$self_dirname/msvs_common.sh"|| exit 127
show_help() {
cat <<EOF
Usage: ${self_basename} --name=projname [options] file1 [file2 ...]
This script generates a Visual Studio project file from a list of source
code files.
Options:
--help Print this message
--exe Generate a project for building an Application
--lib Generate a project for creating a static library
--dll Generate a project for creating a dll
--static-crt Use the static C runtime (/MT)
--target=isa-os-cc Target specifier (required)
--out=filename Write output to a file [stdout]
--name=project_name Name of the project (required)
--proj-guid=GUID GUID to use for the project
--module-def=filename File containing export definitions (for DLLs)
--ver=version Version (7,8,9) of visual studio to generate for
--src-path-bare=dir Path to root of source tree
-Ipath/to/include Additional include directories
-DFLAG[=value] Preprocessor macros to define
-Lpath/to/lib Additional library search paths
-llibname Library to link against
EOF
exit 1
}
generate_filter() {
local var=$1
local name=$2
local pats=$3
local file_list_sz
local i
local f
local saveIFS="$IFS"
local pack
echo "generating filter '$name' from ${#file_list[@]} files" >&2
IFS=*
open_tag Filter \
Name=$name \
Filter=$pats \
UniqueIdentifier=`generate_uuid` \
file_list_sz=${#file_list[@]}
for i in ${!file_list[@]}; do
f=${file_list[i]}
for pat in ${pats//;/$IFS}; do
if [ "${f##*.}" == "$pat" ]; then
unset file_list[i]
objf=$(echo ${f%.*}.obj \
| sed -e "s,$src_path_bare,," \
-e 's/^[\./]\+//g' -e 's,[:/ ],_,g')
open_tag File RelativePath="$f"
if [ "$pat" == "asm" ] && $asm_use_custom_step; then
for plat in "${platforms[@]}"; do
for cfg in Debug Release; do
open_tag FileConfiguration \
Name="${cfg}|${plat}" \
tag Tool \
Name="VCCustomBuildTool" \
Description="Assembling \$(InputFileName)" \
CommandLine="$(eval echo \$asm_${cfg}_cmdline) -o \$(IntDir)\\$objf" \
Outputs="\$(IntDir)\\$objf" \
close_tag FileConfiguration
done
done
fi
if [ "$pat" == "c" ] || \
[ "$pat" == "cc" ] || [ "$pat" == "cpp" ]; then
for plat in "${platforms[@]}"; do
for cfg in Debug Release; do
open_tag FileConfiguration \
Name="${cfg}|${plat}" \
tag Tool \
Name="VCCLCompilerTool" \
ObjectFile="\$(IntDir)\\$objf" \
close_tag FileConfiguration
done
done
fi
close_tag File
break
fi
done
done
close_tag Filter
IFS="$saveIFS"
}
# Process command line
unset target
for opt in "$@"; do
optval="${opt#*=}"
case "$opt" in
--help|-h) show_help
;;
--target=*) target="${optval}"
;;
--out=*) outfile="$optval"
;;
--name=*) name="${optval}"
;;
--proj-guid=*) guid="${optval}"
;;
--module-def=*) link_opts="${link_opts} ModuleDefinitionFile=${optval}"
;;
--exe) proj_kind="exe"
;;
--dll) proj_kind="dll"
;;
--lib) proj_kind="lib"
;;
--src-path-bare=*) src_path_bare=$(fix_path "$optval")
;;
--static-crt) use_static_runtime=true
;;
--ver=*)
vs_ver="$optval"
case "$optval" in
[789])
;;
*) die Unrecognized Visual Studio Version in $opt
;;
esac
;;
-I*)
opt="${opt%/}"
opt=${opt##-I}
opt=$(fix_path "$opt")
incs="${incs}${incs:+;}&quot;${opt}&quot;"
yasmincs="${yasmincs} -I&quot;${opt}&quot;"
;;
-D*) defines="${defines}${defines:+;}${opt##-D}"
;;
-L*) # fudge . to $(OutDir)
if [ "${opt##-L}" == "." ]; then
libdirs="${libdirs}${libdirs:+;}&quot;\$(OutDir)&quot;"
else
# Also try directories for this platform/configuration
opt=${opt##-L}
opt=$(fix_path "$opt")
libdirs="${libdirs}${libdirs:+;}&quot;${opt}&quot;"
libdirs="${libdirs}${libdirs:+;}&quot;${opt}/\$(PlatformName)/\$(ConfigurationName)&quot;"
libdirs="${libdirs}${libdirs:+;}&quot;${opt}/\$(PlatformName)&quot;"
fi
;;
-l*) libs="${libs}${libs:+ }${opt##-l}.lib"
;;
-*) die_unknown $opt
;;
*)
# The paths in file_list are fixed outside of the loop.
file_list[${#file_list[@]}]="$opt"
case "$opt" in
*.asm) uses_asm=true
;;
esac
;;
esac
done
# Make one call to fix_path for file_list to improve performance.
fix_file_list
outfile=${outfile:-/dev/stdout}
guid=${guid:-`generate_uuid`}
asm_use_custom_step=false
uses_asm=${uses_asm:-false}
case "${vs_ver:-8}" in
7) vs_ver_id="7.10"
asm_use_custom_step=$uses_asm
warn_64bit='Detect64BitPortabilityProblems=true'
;;
8) vs_ver_id="8.00"
asm_use_custom_step=$uses_asm
warn_64bit='Detect64BitPortabilityProblems=true'
;;
9) vs_ver_id="9.00"
asm_use_custom_step=$uses_asm
warn_64bit='Detect64BitPortabilityProblems=false'
;;
esac
[ -n "$name" ] || die "Project name (--name) must be specified!"
[ -n "$target" ] || die "Target (--target) must be specified!"
if ${use_static_runtime:-false}; then
release_runtime=0
debug_runtime=1
lib_sfx=mt
else
release_runtime=2
debug_runtime=3
lib_sfx=md
fi
# Calculate debug lib names: If a lib ends in ${lib_sfx}.lib, then rename
# it to ${lib_sfx}d.lib. This precludes linking to release libs from a
# debug exe, so this may need to be refactored later.
for lib in ${libs}; do
if [ "$lib" != "${lib%${lib_sfx}.lib}" ]; then
lib=${lib%.lib}d.lib
fi
debug_libs="${debug_libs}${debug_libs:+ }${lib}"
done
# List Keyword for this target
case "$target" in
x86*) keyword="ManagedCProj"
;;
*) die "Unsupported target $target!"
esac
# List of all platforms supported for this target
case "$target" in
x86_64*)
platforms[0]="x64"
asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} &quot;\$(InputPath)&quot;"
asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} &quot;\$(InputPath)&quot;"
;;
x86*)
platforms[0]="Win32"
asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} &quot;\$(InputPath)&quot;"
asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} &quot;\$(InputPath)&quot;"
;;
*) die "Unsupported target $target!"
;;
esac
generate_vcproj() {
case "$proj_kind" in
exe) vs_ConfigurationType=1
;;
dll) vs_ConfigurationType=2
;;
*) vs_ConfigurationType=4
;;
esac
echo "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>"
open_tag VisualStudioProject \
ProjectType="Visual C++" \
Version="${vs_ver_id}" \
Name="${name}" \
ProjectGUID="{${guid}}" \
RootNamespace="${name}" \
Keyword="${keyword}" \
open_tag Platforms
for plat in "${platforms[@]}"; do
tag Platform Name="$plat"
done
close_tag Platforms
open_tag Configurations
for plat in "${platforms[@]}"; do
plat_no_ws=`echo $plat | sed 's/[^A-Za-z0-9_]/_/g'`
open_tag Configuration \
Name="Debug|$plat" \
OutputDirectory="\$(SolutionDir)$plat_no_ws/\$(ConfigurationName)" \
IntermediateDirectory="$plat_no_ws/\$(ConfigurationName)/${name}" \
ConfigurationType="$vs_ConfigurationType" \
CharacterSet="1" \
case "$target" in
x86*)
case "$name" in
obj_int_extract)
tag Tool \
Name="VCCLCompilerTool" \
Optimization="0" \
AdditionalIncludeDirectories="$incs" \
PreprocessorDefinitions="WIN32;DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE" \
RuntimeLibrary="$debug_runtime" \
WarningLevel="3" \
DebugInformationFormat="1" \
$warn_64bit \
;;
vpx)
tag Tool \
Name="VCPreBuildEventTool" \
CommandLine="call obj_int_extract.bat &quot;$src_path_bare&quot; $plat_no_ws\\\$(ConfigurationName)" \
tag Tool \
Name="VCCLCompilerTool" \
Optimization="0" \
AdditionalIncludeDirectories="$incs" \
PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;$defines" \
RuntimeLibrary="$debug_runtime" \
UsePrecompiledHeader="0" \
WarningLevel="3" \
DebugInformationFormat="2" \
$warn_64bit \
$uses_asm && tag Tool Name="YASM" IncludePaths="$incs" Debug="true"
;;
*)
tag Tool \
Name="VCCLCompilerTool" \
Optimization="0" \
AdditionalIncludeDirectories="$incs" \
PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;$defines" \
RuntimeLibrary="$debug_runtime" \
UsePrecompiledHeader="0" \
WarningLevel="3" \
DebugInformationFormat="2" \
$warn_64bit \
$uses_asm && tag Tool Name="YASM" IncludePaths="$incs" Debug="true"
;;
esac
;;
esac
case "$proj_kind" in
exe)
case "$target" in
x86*)
case "$name" in
obj_int_extract)
tag Tool \
Name="VCLinkerTool" \
GenerateDebugInformation="true" \
;;
*)
tag Tool \
Name="VCLinkerTool" \
AdditionalDependencies="$debug_libs \$(NoInherit)" \
AdditionalLibraryDirectories="$libdirs" \
GenerateDebugInformation="true" \
ProgramDatabaseFile="\$(OutDir)/${name}.pdb" \
;;
esac
;;
esac
;;
lib)
case "$target" in
x86*)
tag Tool \
Name="VCLibrarianTool" \
OutputFile="\$(OutDir)/${name}${lib_sfx}d.lib" \
;;
esac
;;
dll)
tag Tool \
Name="VCLinkerTool" \
AdditionalDependencies="\$(NoInherit)" \
LinkIncremental="2" \
GenerateDebugInformation="true" \
AssemblyDebug="1" \
TargetMachine="1" \
$link_opts \
;;
esac
close_tag Configuration
open_tag Configuration \
Name="Release|$plat" \
OutputDirectory="\$(SolutionDir)$plat_no_ws/\$(ConfigurationName)" \
IntermediateDirectory="$plat_no_ws/\$(ConfigurationName)/${name}" \
ConfigurationType="$vs_ConfigurationType" \
CharacterSet="1" \
WholeProgramOptimization="0" \
case "$target" in
x86*)
case "$name" in
obj_int_extract)
tag Tool \
Name="VCCLCompilerTool" \
Optimization="2" \
FavorSizeorSpeed="1" \
AdditionalIncludeDirectories="$incs" \
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE" \
RuntimeLibrary="$release_runtime" \
UsePrecompiledHeader="0" \
WarningLevel="3" \
DebugInformationFormat="0" \
$warn_64bit \
;;
vpx)
tag Tool \
Name="VCPreBuildEventTool" \
CommandLine="call obj_int_extract.bat $src_path_bare $plat_no_ws\\\$(ConfigurationName)" \
tag Tool \
Name="VCCLCompilerTool" \
Optimization="2" \
FavorSizeorSpeed="1" \
AdditionalIncludeDirectories="$incs" \
PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;$defines" \
RuntimeLibrary="$release_runtime" \
UsePrecompiledHeader="0" \
WarningLevel="3" \
DebugInformationFormat="0" \
$warn_64bit \
$uses_asm && tag Tool Name="YASM" IncludePaths="$incs"
;;
*)
tag Tool \
Name="VCCLCompilerTool" \
AdditionalIncludeDirectories="$incs" \
Optimization="2" \
FavorSizeorSpeed="1" \
PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;$defines" \
RuntimeLibrary="$release_runtime" \
UsePrecompiledHeader="0" \
WarningLevel="3" \
DebugInformationFormat="0" \
$warn_64bit \
$uses_asm && tag Tool Name="YASM" IncludePaths="$incs"
;;
esac
;;
esac
case "$proj_kind" in
exe)
case "$target" in
x86*)
case "$name" in
obj_int_extract)
tag Tool \
Name="VCLinkerTool" \
GenerateDebugInformation="true" \
;;
*)
tag Tool \
Name="VCLinkerTool" \
AdditionalDependencies="$libs \$(NoInherit)" \
AdditionalLibraryDirectories="$libdirs" \
;;
esac
;;
esac
;;
lib)
case "$target" in
x86*)
tag Tool \
Name="VCLibrarianTool" \
OutputFile="\$(OutDir)/${name}${lib_sfx}.lib" \
;;
esac
;;
dll) # note differences to debug version: LinkIncremental, AssemblyDebug
tag Tool \
Name="VCLinkerTool" \
AdditionalDependencies="\$(NoInherit)" \
LinkIncremental="1" \
GenerateDebugInformation="true" \
TargetMachine="1" \
$link_opts \
;;
esac
close_tag Configuration
done
close_tag Configurations
open_tag Files
generate_filter srcs "Source Files" "c;cc;cpp;def;odl;idl;hpj;bat;asm;asmx"
generate_filter hdrs "Header Files" "h;hm;inl;inc;xsd"
generate_filter resrcs "Resource Files" "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
generate_filter resrcs "Build Files" "mk"
close_tag Files
tag Globals
close_tag VisualStudioProject
# This must be done from within the {} subshell
echo "Ignored files list (${#file_list[@]} items) is:" >&2
for f in "${file_list[@]}"; do
echo " $f" >&2
done
}
generate_vcproj |
sed -e '/"/s;\([^ "]\)/;\1\\;g' > ${outfile}
exit
<!--
TODO: Add any files not captured by filters.
<File
RelativePath=".\ReadMe.txt"
>
</File>
-->

View File

@@ -19,13 +19,13 @@ show_help() {
cat <<EOF cat <<EOF
Usage: ${self_basename} [options] file1 [file2 ...] Usage: ${self_basename} [options] file1 [file2 ...]
This script generates a Visual Studio solution file from a list of project This script generates a Visual Studio 2005 solution file from a list of project
files. files.
Options: Options:
--help Print this message --help Print this message
--out=outfile Redirect output to a file --out=outfile Redirect output to a file
--ver=version Version (7,8,9,10,11,12,14) of visual studio to generate for --ver=version Version (7,8,9,10,11) of visual studio to generate for
--target=isa-os-cc Target specifier --target=isa-os-cc Target specifier
EOF EOF
exit 1 exit 1
@@ -55,11 +55,16 @@ indent_pop() {
parse_project() { parse_project() {
local file=$1 local file=$1
if [ "$sfx" = "vcproj" ]; then
local name=`grep Name "$file" | awk 'BEGIN {FS="\""}{if (NR==1) print $2}'`
local guid=`grep ProjectGUID "$file" | awk 'BEGIN {FS="\""}{if (NR==1) print $2}'`
else
local name=`grep RootNamespace "$file" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'` local name=`grep RootNamespace "$file" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'`
local guid=`grep ProjectGuid "$file" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'` local guid=`grep ProjectGuid "$file" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'`
fi
# save the project GUID to a varaible, normalizing to the basename of the # save the project GUID to a varaible, normalizing to the basename of the
# vcxproj file without the extension # vcproj file without the extension
local var local var
var=${file##*/} var=${file##*/}
var=${var%%.${sfx}} var=${var%%.${sfx}}
@@ -67,8 +72,13 @@ parse_project() {
eval "${var}_name=$name" eval "${var}_name=$name"
eval "${var}_guid=$guid" eval "${var}_guid=$guid"
if [ "$sfx" = "vcproj" ]; then
cur_config_list=`grep -A1 '<Configuration' $file |
grep Name | cut -d\" -f2`
else
cur_config_list=`grep -B1 'Label="Configuration"' $file | cur_config_list=`grep -B1 'Label="Configuration"' $file |
grep Condition | cut -d\' -f4` grep Condition | cut -d\' -f4`
fi
new_config_list=$(for i in $config_list $cur_config_list; do new_config_list=$(for i in $config_list $cur_config_list; do
echo $i echo $i
done | sort | uniq) done | sort | uniq)
@@ -93,6 +103,25 @@ process_project() {
eval "${var}_guid=$guid" eval "${var}_guid=$guid"
echo "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"$name\", \"$file\", \"$guid\"" echo "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"$name\", \"$file\", \"$guid\""
indent_push
eval "local deps=\"\${${var}_deps}\""
if [ -n "$deps" ] && [ "$sfx" = "vcproj" ]; then
echo "${indent}ProjectSection(ProjectDependencies) = postProject"
indent_push
for dep in $deps; do
eval "local dep_guid=\${${dep}_guid}"
[ -z "${dep_guid}" ] && die "Unknown GUID for $dep (dependency of $var)"
echo "${indent}$dep_guid = $dep_guid"
done
indent_pop
echo "${indent}EndProjectSection"
fi
indent_pop
echo "EndProject" echo "EndProject"
} }
@@ -162,7 +191,11 @@ process_makefile() {
IFS=$'\r'$'\n' IFS=$'\r'$'\n'
local TAB=$'\t' local TAB=$'\t'
cat <<EOF cat <<EOF
ifeq (\$(CONFIG_VS_VERSION),7)
MSBUILD_TOOL := devenv.com
else
MSBUILD_TOOL := msbuild.exe MSBUILD_TOOL := msbuild.exe
endif
found_devenv := \$(shell which \$(MSBUILD_TOOL) >/dev/null 2>&1 && echo yes) found_devenv := \$(shell which \$(MSBUILD_TOOL) >/dev/null 2>&1 && echo yes)
.nodevenv.once: .nodevenv.once:
${TAB}@echo " * \$(MSBUILD_TOOL) not found in path." ${TAB}@echo " * \$(MSBUILD_TOOL) not found in path."
@@ -171,7 +204,7 @@ ${TAB}@echo " * You will have to build all configurations manually using the"
${TAB}@echo " * Visual Studio IDE. To allow make to build them automatically," ${TAB}@echo " * Visual Studio IDE. To allow make to build them automatically,"
${TAB}@echo " * add the Common7/IDE directory of your Visual Studio" ${TAB}@echo " * add the Common7/IDE directory of your Visual Studio"
${TAB}@echo " * installation to your path, eg:" ${TAB}@echo " * installation to your path, eg:"
${TAB}@echo " * C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE" ${TAB}@echo " * C:\Program Files\Microsoft Visual Studio 8\Common7\IDE"
${TAB}@echo " * " ${TAB}@echo " * "
${TAB}@touch \$@ ${TAB}@touch \$@
CLEAN-OBJS += \$(if \$(found_devenv),,.nodevenv.once) CLEAN-OBJS += \$(if \$(found_devenv),,.nodevenv.once)
@@ -188,9 +221,16 @@ clean::
${TAB}rm -rf "$platform"/"$config" ${TAB}rm -rf "$platform"/"$config"
.PHONY: $nows_sln_config .PHONY: $nows_sln_config
ifneq (\$(found_devenv),) ifneq (\$(found_devenv),)
ifeq (\$(CONFIG_VS_VERSION),7)
$nows_sln_config: $outfile
${TAB}\$(MSBUILD_TOOL) $outfile -build "$config"
else
$nows_sln_config: $outfile $nows_sln_config: $outfile
${TAB}\$(MSBUILD_TOOL) $outfile -m -t:Build \\ ${TAB}\$(MSBUILD_TOOL) $outfile -m -t:Build \\
${TAB}${TAB}-p:Configuration="$config" -p:Platform="$platform" ${TAB}${TAB}-p:Configuration="$config" -p:Platform="$platform"
endif
else else
$nows_sln_config: $outfile .nodevenv.once $nows_sln_config: $outfile .nodevenv.once
${TAB}@echo " * Skipping build of $sln_config (\$(MSBUILD_TOOL) not in path)." ${TAB}@echo " * Skipping build of $sln_config (\$(MSBUILD_TOOL) not in path)."
@@ -215,12 +255,23 @@ for opt in "$@"; do
;; ;;
--ver=*) vs_ver="$optval" --ver=*) vs_ver="$optval"
case $optval in case $optval in
10|11|12|14) [789]|10|11|12)
;; ;;
*) die Unrecognized Visual Studio Version in $opt *) die Unrecognized Visual Studio Version in $opt
;; ;;
esac esac
;; ;;
--ver=*) vs_ver="$optval"
case $optval in
7) sln_vers="8.00"
sln_vers_str="Visual Studio .NET 2003"
;;
[89])
;;
*) die "Unrecognized Visual Studio Version '$optval' in $opt"
;;
esac
;;
--target=*) target="${optval}" --target=*) target="${optval}"
;; ;;
-*) die_unknown $opt -*) die_unknown $opt
@@ -230,7 +281,16 @@ for opt in "$@"; do
done done
outfile=${outfile:-/dev/stdout} outfile=${outfile:-/dev/stdout}
mkoutfile=${mkoutfile:-/dev/stdout} mkoutfile=${mkoutfile:-/dev/stdout}
case "${vs_ver:-10}" in case "${vs_ver:-8}" in
7) sln_vers="8.00"
sln_vers_str="Visual Studio .NET 2003"
;;
8) sln_vers="9.00"
sln_vers_str="Visual Studio 2005"
;;
9) sln_vers="10.00"
sln_vers_str="Visual Studio 2008"
;;
10) sln_vers="11.00" 10) sln_vers="11.00"
sln_vers_str="Visual Studio 2010" sln_vers_str="Visual Studio 2010"
;; ;;
@@ -240,11 +300,15 @@ case "${vs_ver:-10}" in
12) sln_vers="12.00" 12) sln_vers="12.00"
sln_vers_str="Visual Studio 2013" sln_vers_str="Visual Studio 2013"
;; ;;
14) sln_vers="14.00" esac
sln_vers_str="Visual Studio 2015" case "${vs_ver:-8}" in
[789])
sfx=vcproj
;;
10|11|12)
sfx=vcxproj
;; ;;
esac esac
sfx=vcxproj
for f in "${file_list[@]}"; do for f in "${file_list[@]}"; do
parse_project $f parse_project $f

View File

@@ -34,7 +34,7 @@ Options:
--name=project_name Name of the project (required) --name=project_name Name of the project (required)
--proj-guid=GUID GUID to use for the project --proj-guid=GUID GUID to use for the project
--module-def=filename File containing export definitions (for DLLs) --module-def=filename File containing export definitions (for DLLs)
--ver=version Version (10,11,12,14) of visual studio to generate for --ver=version Version (10,11,12) of visual studio to generate for
--src-path-bare=dir Path to root of source tree --src-path-bare=dir Path to root of source tree
-Ipath/to/include Additional include directories -Ipath/to/include Additional include directories
-DFLAG[=value] Preprocessor macros to define -DFLAG[=value] Preprocessor macros to define
@@ -157,9 +157,7 @@ for opt in "$@"; do
;; ;;
--lib) proj_kind="lib" --lib) proj_kind="lib"
;; ;;
--src-path-bare=*) --src-path-bare=*) src_path_bare=$(fix_path "$optval")
src_path_bare=$(fix_path "$optval")
src_path_bare=${src_path_bare%/}
;; ;;
--static-crt) use_static_runtime=true --static-crt) use_static_runtime=true
;; ;;
@@ -168,16 +166,16 @@ for opt in "$@"; do
--ver=*) --ver=*)
vs_ver="$optval" vs_ver="$optval"
case "$optval" in case "$optval" in
10|11|12|14) 10|11|12)
;; ;;
*) die Unrecognized Visual Studio Version in $opt *) die Unrecognized Visual Studio Version in $opt
;; ;;
esac esac
;; ;;
-I*) -I*)
opt="${opt%/}"
opt=${opt##-I} opt=${opt##-I}
opt=$(fix_path "$opt") opt=$(fix_path "$opt")
opt="${opt%/}"
incs="${incs}${incs:+;}&quot;${opt}&quot;" incs="${incs}${incs:+;}&quot;${opt}&quot;"
yasmincs="${yasmincs} -I&quot;${opt}&quot;" yasmincs="${yasmincs} -I&quot;${opt}&quot;"
;; ;;
@@ -211,14 +209,14 @@ for opt in "$@"; do
done done
# Make one call to fix_path for file_list to improve performance. # Make one call to fix_path for file_list to improve performance.
fix_file_list file_list fix_file_list
outfile=${outfile:-/dev/stdout} outfile=${outfile:-/dev/stdout}
guid=${guid:-`generate_uuid`} guid=${guid:-`generate_uuid`}
asm_use_custom_step=false asm_use_custom_step=false
uses_asm=${uses_asm:-false} uses_asm=${uses_asm:-false}
case "${vs_ver:-11}" in case "${vs_ver:-11}" in
10|11|12|14) 10|11|12)
asm_use_custom_step=$uses_asm asm_use_custom_step=$uses_asm
;; ;;
esac esac
@@ -253,18 +251,24 @@ libs=${libs// /;}
case "$target" in case "$target" in
x86_64*) x86_64*)
platforms[0]="x64" platforms[0]="x64"
asm_Debug_cmdline="yasm -Xvc -g cv8 -f win64 ${yasmincs} &quot;%(FullPath)&quot;" asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} &quot;%(FullPath)&quot;"
asm_Release_cmdline="yasm -Xvc -f win64 ${yasmincs} &quot;%(FullPath)&quot;" asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} &quot;%(FullPath)&quot;"
;; ;;
x86*) x86*)
platforms[0]="Win32" platforms[0]="Win32"
asm_Debug_cmdline="yasm -Xvc -g cv8 -f win32 ${yasmincs} &quot;%(FullPath)&quot;" asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} &quot;%(FullPath)&quot;"
asm_Release_cmdline="yasm -Xvc -f win32 ${yasmincs} &quot;%(FullPath)&quot;" asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} &quot;%(FullPath)&quot;"
;; ;;
arm*) arm*)
asm_Debug_cmdline="armasm -nologo &quot;%(FullPath)&quot;"
asm_Release_cmdline="armasm -nologo &quot;%(FullPath)&quot;"
if [ "$name" = "obj_int_extract" ]; then
# We don't want to build this tool for the target architecture,
# but for an architecture we can run locally during the build.
platforms[0]="Win32"
else
platforms[0]="ARM" platforms[0]="ARM"
asm_Debug_cmdline="armasm -nologo -oldit &quot;%(FullPath)&quot;" fi
asm_Release_cmdline="armasm -nologo -oldit &quot;%(FullPath)&quot;"
;; ;;
*) die "Unsupported target $target!" *) die "Unsupported target $target!"
;; ;;
@@ -344,9 +348,6 @@ generate_vcxproj() {
# has to enable AppContainerApplication as well. # has to enable AppContainerApplication as well.
tag_content PlatformToolset v120 tag_content PlatformToolset v120
fi fi
if [ "$vs_ver" = "14" ]; then
tag_content PlatformToolset v140
fi
tag_content CharacterSet Unicode tag_content CharacterSet Unicode
if [ "$config" = "Release" ]; then if [ "$config" = "Release" ]; then
tag_content WholeProgramOptimization true tag_content WholeProgramOptimization true
@@ -397,13 +398,23 @@ generate_vcxproj() {
if [ "$hostplat" == "ARM" ]; then if [ "$hostplat" == "ARM" ]; then
hostplat=Win32 hostplat=Win32
fi fi
open_tag PreBuildEvent
tag_content Command "call obj_int_extract.bat &quot;$src_path_bare&quot; $hostplat\\\$(Configuration)"
close_tag PreBuildEvent
fi fi
open_tag ClCompile open_tag ClCompile
if [ "$config" = "Debug" ]; then if [ "$config" = "Debug" ]; then
opt=Disabled opt=Disabled
runtime=$debug_runtime runtime=$debug_runtime
curlibs=$debug_libs curlibs=$debug_libs
case "$name" in
obj_int_extract)
debug=DEBUG
;;
*)
debug=_DEBUG debug=_DEBUG
;;
esac
else else
opt=MaxSpeed opt=MaxSpeed
runtime=$release_runtime runtime=$release_runtime
@@ -411,7 +422,14 @@ generate_vcxproj() {
tag_content FavorSizeOrSpeed Speed tag_content FavorSizeOrSpeed Speed
debug=NDEBUG debug=NDEBUG
fi fi
case "$name" in
obj_int_extract)
extradefines=";_CONSOLE"
;;
*)
extradefines=";$defines" extradefines=";$defines"
;;
esac
tag_content Optimization $opt tag_content Optimization $opt
tag_content AdditionalIncludeDirectories "$incs;%(AdditionalIncludeDirectories)" tag_content AdditionalIncludeDirectories "$incs;%(AdditionalIncludeDirectories)"
tag_content PreprocessorDefinitions "WIN32;$debug;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE$extradefines;%(PreprocessorDefinitions)" tag_content PreprocessorDefinitions "WIN32;$debug;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE$extradefines;%(PreprocessorDefinitions)"
@@ -431,6 +449,10 @@ generate_vcxproj() {
case "$proj_kind" in case "$proj_kind" in
exe) exe)
open_tag Link open_tag Link
if [ "$name" != "obj_int_extract" ]; then
tag_content AdditionalDependencies "$curlibs;%(AdditionalDependencies)"
tag_content AdditionalLibraryDirectories "$libdirs;%(AdditionalLibraryDirectories)"
fi
tag_content GenerateDebugInformation true tag_content GenerateDebugInformation true
# Console is the default normally, but if # Console is the default normally, but if
# AppContainerApplication is set, we need to override it. # AppContainerApplication is set, we need to override it.

View File

@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>VPX</string>
<key>CFBundleIdentifier</key>
<string>org.webmproject.VPX</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>VPX</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>${VERSION}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>${VERSION}</string>
<key>MinimumOSVersion</key>
<string>${IOS_VERSION_MIN}</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>VPXFullVersion</key>
<string>${FULLVERSION}</string>
</dict>
</plist>

View File

@@ -1,383 +0,0 @@
#!/bin/sh
##
## Copyright (c) 2014 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 script generates 'VPX.framework'. An iOS app can encode and decode VPx
## video by including 'VPX.framework'.
##
## Run iosbuild.sh to create 'VPX.framework' in the current directory.
##
set -e
devnull='> /dev/null 2>&1'
BUILD_ROOT="_iosbuild"
CONFIGURE_ARGS="--disable-docs
--disable-examples
--disable-libyuv
--disable-unit-tests"
DIST_DIR="_dist"
FRAMEWORK_DIR="VPX.framework"
FRAMEWORK_LIB="VPX.framework/VPX"
HEADER_DIR="${FRAMEWORK_DIR}/Headers/vpx"
SCRIPT_DIR=$(dirname "$0")
LIBVPX_SOURCE_DIR=$(cd ${SCRIPT_DIR}/../..; pwd)
LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
ORIG_PWD="$(pwd)"
ARM_TARGETS="arm64-darwin-gcc
armv7-darwin-gcc
armv7s-darwin-gcc"
SIM_TARGETS="x86-iphonesimulator-gcc
x86_64-iphonesimulator-gcc"
OSX_TARGETS="x86-darwin15-gcc
x86_64-darwin15-gcc"
TARGETS="${ARM_TARGETS} ${SIM_TARGETS}"
# Configures for the target specified by $1, and invokes make with the dist
# target using $DIST_DIR as the distribution output directory.
build_target() {
local target="$1"
local old_pwd="$(pwd)"
local target_specific_flags=""
vlog "***Building target: ${target}***"
case "${target}" in
x86-*)
target_specific_flags="--enable-pic"
vlog "Enabled PIC for ${target}"
;;
esac
mkdir "${target}"
cd "${target}"
eval "${LIBVPX_SOURCE_DIR}/configure" --target="${target}" \
${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS} ${target_specific_flags} \
${devnull}
export DIST_DIR
eval make dist ${devnull}
cd "${old_pwd}"
vlog "***Done building target: ${target}***"
}
# Returns the preprocessor symbol for the target specified by $1.
target_to_preproc_symbol() {
target="$1"
case "${target}" in
arm64-*)
echo "__aarch64__"
;;
armv7-*)
echo "__ARM_ARCH_7A__"
;;
armv7s-*)
echo "__ARM_ARCH_7S__"
;;
x86-*)
echo "__i386__"
;;
x86_64-*)
echo "__x86_64__"
;;
*)
echo "#error ${target} unknown/unsupported"
return 1
;;
esac
}
# Create a vpx_config.h shim that, based on preprocessor settings for the
# current target CPU, includes the real vpx_config.h for the current target.
# $1 is the list of targets.
create_vpx_framework_config_shim() {
local targets="$1"
local config_file="${HEADER_DIR}/vpx_config.h"
local preproc_symbol=""
local target=""
local include_guard="VPX_FRAMEWORK_HEADERS_VPX_VPX_CONFIG_H_"
local file_header="/*
* Copyright (c) $(date +%Y) 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.
*/
/* GENERATED FILE: DO NOT EDIT! */
#ifndef ${include_guard}
#define ${include_guard}
#if defined"
printf "%s" "${file_header}" > "${config_file}"
for target in ${targets}; do
preproc_symbol=$(target_to_preproc_symbol "${target}")
printf " ${preproc_symbol}\n" >> "${config_file}"
printf "#define VPX_FRAMEWORK_TARGET \"${target}\"\n" >> "${config_file}"
printf "#include \"VPX/vpx/${target}/vpx_config.h\"\n" >> "${config_file}"
printf "#elif defined" >> "${config_file}"
mkdir "${HEADER_DIR}/${target}"
cp -p "${BUILD_ROOT}/${target}/vpx_config.h" "${HEADER_DIR}/${target}"
done
# Consume the last line of output from the loop: We don't want it.
sed -i '' -e '$d' "${config_file}"
printf "#endif\n\n" >> "${config_file}"
printf "#endif // ${include_guard}" >> "${config_file}"
}
# Verifies that $FRAMEWORK_LIB fat library contains requested builds.
verify_framework_targets() {
local requested_cpus=""
local cpu=""
# Extract CPU from full target name.
for target; do
cpu="${target%%-*}"
if [ "${cpu}" = "x86" ]; then
# lipo -info outputs i386 for libvpx x86 targets.
cpu="i386"
fi
requested_cpus="${requested_cpus}${cpu} "
done
# Get target CPUs present in framework library.
local targets_built=$(${LIPO} -info ${FRAMEWORK_LIB})
# $LIPO -info outputs a string like the following:
# Architectures in the fat file: $FRAMEWORK_LIB <architectures>
# Capture only the architecture strings.
targets_built=${targets_built##*: }
# Sort CPU strings to make the next step a simple string compare.
local actual=$(echo ${targets_built} | tr " " "\n" | sort | tr "\n" " ")
local requested=$(echo ${requested_cpus} | tr " " "\n" | sort | tr "\n" " ")
vlog "Requested ${FRAMEWORK_LIB} CPUs: ${requested}"
vlog "Actual ${FRAMEWORK_LIB} CPUs: ${actual}"
if [ "${requested}" != "${actual}" ]; then
elog "Actual ${FRAMEWORK_LIB} targets do not match requested target list."
elog " Requested target CPUs: ${requested}"
elog " Actual target CPUs: ${actual}"
return 1
fi
}
# Configures and builds each target specified by $1, and then builds
# VPX.framework.
build_framework() {
local lib_list=""
local targets="$1"
local target=""
local target_dist_dir=""
# Clean up from previous build(s).
rm -rf "${BUILD_ROOT}" "${FRAMEWORK_DIR}"
# Create output dirs.
mkdir -p "${BUILD_ROOT}"
mkdir -p "${HEADER_DIR}"
cd "${BUILD_ROOT}"
for target in ${targets}; do
build_target "${target}"
target_dist_dir="${BUILD_ROOT}/${target}/${DIST_DIR}"
if [ "${ENABLE_SHARED}" = "yes" ]; then
local suffix="dylib"
else
local suffix="a"
fi
lib_list="${lib_list} ${target_dist_dir}/lib/libvpx.${suffix}"
done
cd "${ORIG_PWD}"
# The basic libvpx API includes are all the same; just grab the most recent
# set.
cp -p "${target_dist_dir}"/include/vpx/* "${HEADER_DIR}"
# Build the fat library.
${LIPO} -create ${lib_list} -output ${FRAMEWORK_DIR}/VPX
# Create the vpx_config.h shim that allows usage of vpx_config.h from
# within VPX.framework.
create_vpx_framework_config_shim "${targets}"
# Copy in vpx_version.h.
cp -p "${BUILD_ROOT}/${target}/vpx_version.h" "${HEADER_DIR}"
if [ "${ENABLE_SHARED}" = "yes" ]; then
# Adjust the dylib's name so dynamic linking in apps works as expected.
install_name_tool -id '@rpath/VPX.framework/VPX' ${FRAMEWORK_DIR}/VPX
# Copy in Info.plist.
cat "${SCRIPT_DIR}/ios-Info.plist" \
| sed "s/\${FULLVERSION}/${FULLVERSION}/g" \
| sed "s/\${VERSION}/${VERSION}/g" \
| sed "s/\${IOS_VERSION_MIN}/${IOS_VERSION_MIN}/g" \
> "${FRAMEWORK_DIR}/Info.plist"
fi
# Confirm VPX.framework/VPX contains the targets requested.
verify_framework_targets ${targets}
vlog "Created fat library ${FRAMEWORK_LIB} containing:"
for lib in ${lib_list}; do
vlog " $(echo ${lib} | awk -F / '{print $2, $NF}')"
done
}
# Trap function. Cleans up the subtree used to build all targets contained in
# $TARGETS.
cleanup() {
local readonly res=$?
cd "${ORIG_PWD}"
if [ $res -ne 0 ]; then
elog "build exited with error ($res)"
fi
if [ "${PRESERVE_BUILD_OUTPUT}" != "yes" ]; then
rm -rf "${BUILD_ROOT}"
fi
}
print_list() {
local indent="$1"
shift
local list="$@"
for entry in ${list}; do
echo "${indent}${entry}"
done
}
iosbuild_usage() {
cat << EOF
Usage: ${0##*/} [arguments]
--help: Display this message and exit.
--enable-shared: Build a dynamic framework for use on iOS 8 or later.
--extra-configure-args <args>: Extra args to pass when configuring libvpx.
--macosx: Uses darwin15 targets instead of iphonesimulator targets for x86
and x86_64. Allows linking to framework when builds target MacOSX
instead of iOS.
--preserve-build-output: Do not delete the build directory.
--show-build-output: Show output from each library build.
--targets <targets>: Override default target list. Defaults:
$(print_list " " ${TARGETS})
--test-link: Confirms all targets can be linked. Functionally identical to
passing --enable-examples via --extra-configure-args.
--verbose: Output information about the environment and each stage of the
build.
EOF
}
elog() {
echo "${0##*/} failed because: $@" 1>&2
}
vlog() {
if [ "${VERBOSE}" = "yes" ]; then
echo "$@"
fi
}
trap cleanup EXIT
# Parse the command line.
while [ -n "$1" ]; do
case "$1" in
--extra-configure-args)
EXTRA_CONFIGURE_ARGS="$2"
shift
;;
--help)
iosbuild_usage
exit
;;
--enable-shared)
ENABLE_SHARED=yes
;;
--preserve-build-output)
PRESERVE_BUILD_OUTPUT=yes
;;
--show-build-output)
devnull=
;;
--test-link)
EXTRA_CONFIGURE_ARGS="${EXTRA_CONFIGURE_ARGS} --enable-examples"
;;
--targets)
TARGETS="$2"
shift
;;
--macosx)
TARGETS="${ARM_TARGETS} ${OSX_TARGETS}"
;;
--verbose)
VERBOSE=yes
;;
*)
iosbuild_usage
exit 1
;;
esac
shift
done
if [ "${ENABLE_SHARED}" = "yes" ]; then
CONFIGURE_ARGS="--enable-shared ${CONFIGURE_ARGS}"
fi
FULLVERSION=$("${SCRIPT_DIR}"/version.sh --bare "${LIBVPX_SOURCE_DIR}")
VERSION=$(echo "${FULLVERSION}" | sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+).*$/\1/')
if [ "$ENABLE_SHARED" = "yes" ]; then
IOS_VERSION_OPTIONS="--enable-shared"
IOS_VERSION_MIN="8.0"
else
IOS_VERSION_OPTIONS=""
IOS_VERSION_MIN="6.0"
fi
if [ "${VERBOSE}" = "yes" ]; then
cat << EOF
BUILD_ROOT=${BUILD_ROOT}
DIST_DIR=${DIST_DIR}
CONFIGURE_ARGS=${CONFIGURE_ARGS}
EXTRA_CONFIGURE_ARGS=${EXTRA_CONFIGURE_ARGS}
FRAMEWORK_DIR=${FRAMEWORK_DIR}
FRAMEWORK_LIB=${FRAMEWORK_LIB}
HEADER_DIR=${HEADER_DIR}
LIBVPX_SOURCE_DIR=${LIBVPX_SOURCE_DIR}
LIPO=${LIPO}
MAKEFLAGS=${MAKEFLAGS}
ORIG_PWD=${ORIG_PWD}
PRESERVE_BUILD_OUTPUT=${PRESERVE_BUILD_OUTPUT}
TARGETS="$(print_list "" ${TARGETS})"
ENABLE_SHARED=${ENABLE_SHARED}
OSX_TARGETS="${OSX_TARGETS}"
SIM_TARGETS="${SIM_TARGETS}"
SCRIPT_DIR="${SCRIPT_DIR}"
FULLVERSION="${FULLVERSION}"
VERSION="${VERSION}"
IOS_VERSION_MIN="${IOS_VERSION_MIN}"
EOF
fi
build_framework "${TARGETS}"
echo "Successfully built '${FRAMEWORK_DIR}' for:"
print_list "" ${TARGETS}

View File

@@ -39,12 +39,11 @@ fix_path() {
} }
# Corrects the paths in file_list in one pass for efficiency. # Corrects the paths in file_list in one pass for efficiency.
# $1 is the name of the array to be modified.
fix_file_list() { fix_file_list() {
declare -n array_ref=$1 # TODO(jzern): this could be more generic and take the array as a param.
files=$(fix_path "${array_ref[@]}") files=$(fix_path "${file_list[@]}")
local IFS=$'\n' local IFS=$'\n'
array_ref=($files) file_list=($files)
} }
generate_uuid() { generate_uuid() {

View File

@@ -0,0 +1,857 @@
/*
* 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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vpx_config.h"
#include "vpx/vpx_integer.h"
typedef enum {
OUTPUT_FMT_PLAIN,
OUTPUT_FMT_RVDS,
OUTPUT_FMT_GAS,
OUTPUT_FMT_C_HEADER,
} output_fmt_t;
int log_msg(const char *fmt, ...) {
int res;
va_list ap;
va_start(ap, fmt);
res = vfprintf(stderr, fmt, ap);
va_end(ap);
return res;
}
#if defined(__GNUC__) && __GNUC__
#if defined(FORCE_PARSE_ELF)
#if defined(__MACH__)
#undef __MACH__
#endif
#if !defined(__ELF__)
#define __ELF__
#endif
#endif
#if defined(__MACH__)
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
int print_macho_equ(output_fmt_t mode, uint8_t* name, int val) {
switch (mode) {
case OUTPUT_FMT_RVDS:
printf("%-40s EQU %5d\n", name, val);
return 0;
case OUTPUT_FMT_GAS:
printf(".set %-40s, %5d\n", name, val);
return 0;
case OUTPUT_FMT_C_HEADER:
printf("#define %-40s %5d\n", name, val);
return 0;
default:
log_msg("Unsupported mode: %d", mode);
return 1;
}
}
int parse_macho(uint8_t *base_buf, size_t sz, output_fmt_t mode) {
int i, j;
struct mach_header header;
uint8_t *buf = base_buf;
int base_data_section = 0;
int bits = 0;
/* We can read in mach_header for 32 and 64 bit architectures
* because it's identical to mach_header_64 except for the last
* element (uint32_t reserved), which we don't use. Then, when
* we know which architecture we're looking at, increment buf
* appropriately.
*/
memcpy(&header, buf, sizeof(struct mach_header));
if (header.magic == MH_MAGIC) {
if (header.cputype == CPU_TYPE_ARM
|| header.cputype == CPU_TYPE_X86) {
bits = 32;
buf += sizeof(struct mach_header);
} else {
log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_[ARM|X86].\n");
goto bail;
}
} else if (header.magic == MH_MAGIC_64) {
if (header.cputype == CPU_TYPE_X86_64) {
bits = 64;
buf += sizeof(struct mach_header_64);
} else {
log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_X86_64.\n");
goto bail;
}
} else {
log_msg("Bad magic number for object file. 0x%x or 0x%x expected, 0x%x found.\n",
MH_MAGIC, MH_MAGIC_64, header.magic);
goto bail;
}
if (header.filetype != MH_OBJECT) {
log_msg("Bad filetype for object file. Currently only tested for MH_OBJECT.\n");
goto bail;
}
for (i = 0; i < header.ncmds; i++) {
struct load_command lc;
memcpy(&lc, buf, sizeof(struct load_command));
if (lc.cmd == LC_SEGMENT) {
uint8_t *seg_buf = buf;
struct section s;
struct segment_command seg_c;
memcpy(&seg_c, seg_buf, sizeof(struct segment_command));
seg_buf += sizeof(struct segment_command);
/* Although each section is given it's own offset, nlist.n_value
* references the offset of the first section. This isn't
* apparent without debug information because the offset of the
* data section is the same as the first section. However, with
* debug sections mixed in, the offset of the debug section
* increases but n_value still references the first section.
*/
if (seg_c.nsects < 1) {
log_msg("Not enough sections\n");
goto bail;
}
memcpy(&s, seg_buf, sizeof(struct section));
base_data_section = s.offset;
} else if (lc.cmd == LC_SEGMENT_64) {
uint8_t *seg_buf = buf;
struct section_64 s;
struct segment_command_64 seg_c;
memcpy(&seg_c, seg_buf, sizeof(struct segment_command_64));
seg_buf += sizeof(struct segment_command_64);
/* Explanation in LG_SEGMENT */
if (seg_c.nsects < 1) {
log_msg("Not enough sections\n");
goto bail;
}
memcpy(&s, seg_buf, sizeof(struct section_64));
base_data_section = s.offset;
} else if (lc.cmd == LC_SYMTAB) {
if (base_data_section != 0) {
struct symtab_command sc;
uint8_t *sym_buf = base_buf;
uint8_t *str_buf = base_buf;
memcpy(&sc, buf, sizeof(struct symtab_command));
if (sc.cmdsize != sizeof(struct symtab_command)) {
log_msg("Can't find symbol table!\n");
goto bail;
}
sym_buf += sc.symoff;
str_buf += sc.stroff;
for (j = 0; j < sc.nsyms; j++) {
/* Location of string is cacluated each time from the
* start of the string buffer. On darwin the symbols
* are prefixed by "_", so we bump the pointer by 1.
* The target value is defined as an int in *_asm_*_offsets.c,
* which is 4 bytes on all targets we currently use.
*/
if (bits == 32) {
struct nlist nl;
int val;
memcpy(&nl, sym_buf, sizeof(struct nlist));
sym_buf += sizeof(struct nlist);
memcpy(&val, base_buf + base_data_section + nl.n_value,
sizeof(val));
print_macho_equ(mode, str_buf + nl.n_un.n_strx + 1, val);
} else { /* if (bits == 64) */
struct nlist_64 nl;
int val;
memcpy(&nl, sym_buf, sizeof(struct nlist_64));
sym_buf += sizeof(struct nlist_64);
memcpy(&val, base_buf + base_data_section + nl.n_value,
sizeof(val));
print_macho_equ(mode, str_buf + nl.n_un.n_strx + 1, val);
}
}
}
}
buf += lc.cmdsize;
}
return 0;
bail:
return 1;
}
#elif defined(__ELF__)
#include "elf.h"
#define COPY_STRUCT(dst, buf, ofst, sz) do {\
if(ofst + sizeof((*(dst))) > sz) goto bail;\
memcpy(dst, buf+ofst, sizeof((*(dst))));\
} while(0)
#define ENDIAN_ASSIGN(val, memb) do {\
if(!elf->le_data) {log_msg("Big Endian data not supported yet!\n");goto bail;}\
(val) = (memb);\
} while(0)
#define ENDIAN_ASSIGN_IN_PLACE(memb) do {\
ENDIAN_ASSIGN(memb, memb);\
} while(0)
typedef struct {
uint8_t *buf; /* Buffer containing ELF data */
size_t sz; /* Buffer size */
int le_data; /* Data is little-endian */
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
int bits; /* 32 or 64 */
Elf32_Ehdr hdr32;
Elf64_Ehdr hdr64;
} elf_obj_t;
int parse_elf_header(elf_obj_t *elf) {
int res;
/* Verify ELF Magic numbers */
COPY_STRUCT(&elf->e_ident, elf->buf, 0, elf->sz);
res = elf->e_ident[EI_MAG0] == ELFMAG0;
res &= elf->e_ident[EI_MAG1] == ELFMAG1;
res &= elf->e_ident[EI_MAG2] == ELFMAG2;
res &= elf->e_ident[EI_MAG3] == ELFMAG3;
res &= elf->e_ident[EI_CLASS] == ELFCLASS32
|| elf->e_ident[EI_CLASS] == ELFCLASS64;
res &= elf->e_ident[EI_DATA] == ELFDATA2LSB;
if (!res) goto bail;
elf->le_data = elf->e_ident[EI_DATA] == ELFDATA2LSB;
/* Read in relevant values */
if (elf->e_ident[EI_CLASS] == ELFCLASS32) {
elf->bits = 32;
COPY_STRUCT(&elf->hdr32, elf->buf, 0, elf->sz);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_type);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_machine);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_version);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_entry);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phoff);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shoff);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_flags);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_ehsize);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phentsize);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phnum);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shentsize);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shnum);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shstrndx);
} else { /* if (elf->e_ident[EI_CLASS] == ELFCLASS64) */
elf->bits = 64;
COPY_STRUCT(&elf->hdr64, elf->buf, 0, elf->sz);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_type);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_machine);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_version);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_entry);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phoff);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shoff);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_flags);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_ehsize);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phentsize);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phnum);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shentsize);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shnum);
ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shstrndx);
}
return 0;
bail:
log_msg("Failed to parse ELF file header");
return 1;
}
int parse_elf_section(elf_obj_t *elf, int idx, Elf32_Shdr *hdr32, Elf64_Shdr *hdr64) {
if (hdr32) {
if (idx >= elf->hdr32.e_shnum)
goto bail;
COPY_STRUCT(hdr32, elf->buf, elf->hdr32.e_shoff + idx * elf->hdr32.e_shentsize,
elf->sz);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_name);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_type);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_flags);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addr);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_offset);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_size);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_link);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_info);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addralign);
ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_entsize);
} else { /* if (hdr64) */
if (idx >= elf->hdr64.e_shnum)
goto bail;
COPY_STRUCT(hdr64, elf->buf, elf->hdr64.e_shoff + idx * elf->hdr64.e_shentsize,
elf->sz);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_name);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_type);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_flags);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addr);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_offset);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_size);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_link);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_info);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addralign);
ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_entsize);
}
return 0;
bail:
return 1;
}
const char *parse_elf_string_table(elf_obj_t *elf, int s_idx, int idx) {
if (elf->bits == 32) {
Elf32_Shdr shdr;
if (parse_elf_section(elf, s_idx, &shdr, NULL)) {
log_msg("Failed to parse ELF string table: section %d, index %d\n",
s_idx, idx);
return "";
}
return (char *)(elf->buf + shdr.sh_offset + idx);
} else { /* if (elf->bits == 64) */
Elf64_Shdr shdr;
if (parse_elf_section(elf, s_idx, NULL, &shdr)) {
log_msg("Failed to parse ELF string table: section %d, index %d\n",
s_idx, idx);
return "";
}
return (char *)(elf->buf + shdr.sh_offset + idx);
}
}
int parse_elf_symbol(elf_obj_t *elf, unsigned int ofst, Elf32_Sym *sym32, Elf64_Sym *sym64) {
if (sym32) {
COPY_STRUCT(sym32, elf->buf, ofst, elf->sz);
ENDIAN_ASSIGN_IN_PLACE(sym32->st_name);
ENDIAN_ASSIGN_IN_PLACE(sym32->st_value);
ENDIAN_ASSIGN_IN_PLACE(sym32->st_size);
ENDIAN_ASSIGN_IN_PLACE(sym32->st_info);
ENDIAN_ASSIGN_IN_PLACE(sym32->st_other);
ENDIAN_ASSIGN_IN_PLACE(sym32->st_shndx);
} else { /* if (sym64) */
COPY_STRUCT(sym64, elf->buf, ofst, elf->sz);
ENDIAN_ASSIGN_IN_PLACE(sym64->st_name);
ENDIAN_ASSIGN_IN_PLACE(sym64->st_value);
ENDIAN_ASSIGN_IN_PLACE(sym64->st_size);
ENDIAN_ASSIGN_IN_PLACE(sym64->st_info);
ENDIAN_ASSIGN_IN_PLACE(sym64->st_other);
ENDIAN_ASSIGN_IN_PLACE(sym64->st_shndx);
}
return 0;
bail:
return 1;
}
int parse_elf(uint8_t *buf, size_t sz, output_fmt_t mode) {
elf_obj_t elf;
unsigned int ofst;
int i;
Elf32_Off strtab_off32;
Elf64_Off strtab_off64; /* save String Table offset for later use */
memset(&elf, 0, sizeof(elf));
elf.buf = buf;
elf.sz = sz;
/* Parse Header */
if (parse_elf_header(&elf))
goto bail;
if (elf.bits == 32) {
Elf32_Shdr shdr;
for (i = 0; i < elf.hdr32.e_shnum; i++) {
parse_elf_section(&elf, i, &shdr, NULL);
if (shdr.sh_type == SHT_STRTAB) {
char strtsb_name[128];
strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name));
if (!(strcmp(strtsb_name, ".shstrtab"))) {
/* log_msg("found section: %s\n", strtsb_name); */
strtab_off32 = shdr.sh_offset;
break;
}
}
}
} else { /* if (elf.bits == 64) */
Elf64_Shdr shdr;
for (i = 0; i < elf.hdr64.e_shnum; i++) {
parse_elf_section(&elf, i, NULL, &shdr);
if (shdr.sh_type == SHT_STRTAB) {
char strtsb_name[128];
strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name));
if (!(strcmp(strtsb_name, ".shstrtab"))) {
/* log_msg("found section: %s\n", strtsb_name); */
strtab_off64 = shdr.sh_offset;
break;
}
}
}
}
/* Parse all Symbol Tables */
if (elf.bits == 32) {
Elf32_Shdr shdr;
for (i = 0; i < elf.hdr32.e_shnum; i++) {
parse_elf_section(&elf, i, &shdr, NULL);
if (shdr.sh_type == SHT_SYMTAB) {
for (ofst = shdr.sh_offset;
ofst < shdr.sh_offset + shdr.sh_size;
ofst += shdr.sh_entsize) {
Elf32_Sym sym;
parse_elf_symbol(&elf, ofst, &sym, NULL);
/* For all OBJECTS (data objects), extract the value from the
* proper data segment.
*/
/* if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name)
log_msg("found data object %s\n",
parse_elf_string_table(&elf,
shdr.sh_link,
sym.st_name));
*/
if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT
&& sym.st_size == 4) {
Elf32_Shdr dhdr;
int val = 0;
char section_name[128];
parse_elf_section(&elf, sym.st_shndx, &dhdr, NULL);
/* For explanition - refer to _MSC_VER version of code */
strcpy(section_name, (char *)(elf.buf + strtab_off32 + dhdr.sh_name));
/* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */
if (strcmp(section_name, ".bss")) {
if (sizeof(val) != sym.st_size) {
/* The target value is declared as an int in
* *_asm_*_offsets.c, which is 4 bytes on all
* targets we currently use. Complain loudly if
* this is not true.
*/
log_msg("Symbol size is wrong\n");
goto bail;
}
memcpy(&val,
elf.buf + dhdr.sh_offset + sym.st_value,
sym.st_size);
}
if (!elf.le_data) {
log_msg("Big Endian data not supported yet!\n");
goto bail;
}
switch (mode) {
case OUTPUT_FMT_RVDS:
printf("%-40s EQU %5d\n",
parse_elf_string_table(&elf,
shdr.sh_link,
sym.st_name),
val);
break;
case OUTPUT_FMT_GAS:
printf(".equ %-40s, %5d\n",
parse_elf_string_table(&elf,
shdr.sh_link,
sym.st_name),
val);
break;
case OUTPUT_FMT_C_HEADER:
printf("#define %-40s %5d\n",
parse_elf_string_table(&elf,
shdr.sh_link,
sym.st_name),
val);
break;
default:
printf("%s = %d\n",
parse_elf_string_table(&elf,
shdr.sh_link,
sym.st_name),
val);
}
}
}
}
}
} else { /* if (elf.bits == 64) */
Elf64_Shdr shdr;
for (i = 0; i < elf.hdr64.e_shnum; i++) {
parse_elf_section(&elf, i, NULL, &shdr);
if (shdr.sh_type == SHT_SYMTAB) {
for (ofst = shdr.sh_offset;
ofst < shdr.sh_offset + shdr.sh_size;
ofst += shdr.sh_entsize) {
Elf64_Sym sym;
parse_elf_symbol(&elf, ofst, NULL, &sym);
/* For all OBJECTS (data objects), extract the value from the
* proper data segment.
*/
/* if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name)
log_msg("found data object %s\n",
parse_elf_string_table(&elf,
shdr.sh_link,
sym.st_name));
*/
if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT
&& sym.st_size == 4) {
Elf64_Shdr dhdr;
int val = 0;
char section_name[128];
parse_elf_section(&elf, sym.st_shndx, NULL, &dhdr);
/* For explanition - refer to _MSC_VER version of code */
strcpy(section_name, (char *)(elf.buf + strtab_off64 + dhdr.sh_name));
/* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */
if ((strcmp(section_name, ".bss"))) {
if (sizeof(val) != sym.st_size) {
/* The target value is declared as an int in
* *_asm_*_offsets.c, which is 4 bytes on all
* targets we currently use. Complain loudly if
* this is not true.
*/
log_msg("Symbol size is wrong\n");
goto bail;
}
memcpy(&val,
elf.buf + dhdr.sh_offset + sym.st_value,
sym.st_size);
}
if (!elf.le_data) {
log_msg("Big Endian data not supported yet!\n");
goto bail;
}
switch (mode) {
case OUTPUT_FMT_RVDS:
printf("%-40s EQU %5d\n",
parse_elf_string_table(&elf,
shdr.sh_link,
sym.st_name),
val);
break;
case OUTPUT_FMT_GAS:
printf(".equ %-40s, %5d\n",
parse_elf_string_table(&elf,
shdr.sh_link,
sym.st_name),
val);
break;
default:
printf("%s = %d\n",
parse_elf_string_table(&elf,
shdr.sh_link,
sym.st_name),
val);
}
}
}
}
}
}
if (mode == OUTPUT_FMT_RVDS)
printf(" END\n");
return 0;
bail:
log_msg("Parse error: File does not appear to be valid ELF32 or ELF64\n");
return 1;
}
#endif
#endif /* defined(__GNUC__) && __GNUC__ */
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
/* See "Microsoft Portable Executable and Common Object File Format Specification"
for reference.
*/
#define get_le32(x) ((*(x)) | (*(x+1)) << 8 |(*(x+2)) << 16 | (*(x+3)) << 24 )
#define get_le16(x) ((*(x)) | (*(x+1)) << 8)
int parse_coff(uint8_t *buf, size_t sz) {
unsigned int nsections, symtab_ptr, symtab_sz, strtab_ptr;
unsigned int sectionrawdata_ptr;
unsigned int i;
uint8_t *ptr;
uint32_t symoffset;
char **sectionlist; // this array holds all section names in their correct order.
// it is used to check if the symbol is in .bss or .rdata section.
nsections = get_le16(buf + 2);
symtab_ptr = get_le32(buf + 8);
symtab_sz = get_le32(buf + 12);
strtab_ptr = symtab_ptr + symtab_sz * 18;
if (nsections > 96) {
log_msg("Too many sections\n");
return 1;
}
sectionlist = malloc(nsections * sizeof(sectionlist));
if (sectionlist == NULL) {
log_msg("Allocating first level of section list failed\n");
return 1;
}
// log_msg("COFF: Found %u symbols in %u sections.\n", symtab_sz, nsections);
/*
The size of optional header is always zero for an obj file. So, the section header
follows the file header immediately.
*/
ptr = buf + 20; // section header
for (i = 0; i < nsections; i++) {
char sectionname[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
strncpy(sectionname, ptr, 8);
// log_msg("COFF: Parsing section %s\n",sectionname);
sectionlist[i] = malloc(strlen(sectionname) + 1);
if (sectionlist[i] == NULL) {
log_msg("Allocating storage for %s failed\n", sectionname);
goto bail;
}
strcpy(sectionlist[i], sectionname);
// check if it's .rdata and is not a COMDAT section.
if (!strcmp(sectionname, ".rdata") &&
(get_le32(ptr + 36) & 0x1000) == 0) {
sectionrawdata_ptr = get_le32(ptr + 20);
}
ptr += 40;
}
// log_msg("COFF: Symbol table at offset %u\n", symtab_ptr);
// log_msg("COFF: raw data pointer ofset for section .rdata is %u\n", sectionrawdata_ptr);
/* The compiler puts the data with non-zero offset in .rdata section, but puts the data with
zero offset in .bss section. So, if the data in in .bss section, set offset=0.
Note from Wiki: In an object module compiled from C, the bss section contains
the local variables (but not functions) that were declared with the static keyword,
except for those with non-zero initial values. (In C, static variables are initialized
to zero by default.) It also contains the non-local (both extern and static) variables
that are also initialized to zero (either explicitly or by default).
*/
// move to symbol table
/* COFF symbol table:
offset field
0 Name(*)
8 Value
12 SectionNumber
14 Type
16 StorageClass
17 NumberOfAuxSymbols
*/
ptr = buf + symtab_ptr;
for (i = 0; i < symtab_sz; i++) {
int16_t section = get_le16(ptr + 12); // section number
if (section > 0 && ptr[16] == 2) {
// if(section > 0 && ptr[16] == 3 && get_le32(ptr+8)) {
if (get_le32(ptr)) {
char name[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
strncpy(name, ptr, 8);
// log_msg("COFF: Parsing symbol %s\n",name);
/* The 64bit Windows compiler doesn't prefix with an _.
* Check what's there, and bump if necessary
*/
if (name[0] == '_')
printf("%-40s EQU ", name + 1);
else
printf("%-40s EQU ", name);
} else {
// log_msg("COFF: Parsing symbol %s\n",
// buf + strtab_ptr + get_le32(ptr+4));
if ((buf + strtab_ptr + get_le32(ptr + 4))[0] == '_')
printf("%-40s EQU ",
buf + strtab_ptr + get_le32(ptr + 4) + 1);
else
printf("%-40s EQU ", buf + strtab_ptr + get_le32(ptr + 4));
}
if (!(strcmp(sectionlist[section - 1], ".bss"))) {
symoffset = 0;
} else {
symoffset = get_le32(buf + sectionrawdata_ptr + get_le32(ptr + 8));
}
// log_msg(" Section: %d\n",section);
// log_msg(" Class: %d\n",ptr[16]);
// log_msg(" Address: %u\n",get_le32(ptr+8));
// log_msg(" Offset: %u\n", symoffset);
printf("%5d\n", symoffset);
}
ptr += 18;
}
printf(" END\n");
for (i = 0; i < nsections; i++) {
free(sectionlist[i]);
}
free(sectionlist);
return 0;
bail:
for (i = 0; i < nsections; i++) {
free(sectionlist[i]);
}
free(sectionlist);
return 1;
}
#endif /* defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) */
int main(int argc, char **argv) {
output_fmt_t mode = OUTPUT_FMT_PLAIN;
const char *f;
uint8_t *file_buf;
int res;
FILE *fp;
long int file_size;
if (argc < 2 || argc > 3) {
fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]);
fprintf(stderr, " <obj file>\tobject file to parse\n");
fprintf(stderr, "Output Formats:\n");
fprintf(stderr, " gas - compatible with GNU assembler\n");
fprintf(stderr, " rvds - compatible with armasm\n");
fprintf(stderr, " cheader - c/c++ header file\n");
goto bail;
}
f = argv[2];
if (!strcmp(argv[1], "rvds"))
mode = OUTPUT_FMT_RVDS;
else if (!strcmp(argv[1], "gas"))
mode = OUTPUT_FMT_GAS;
else if (!strcmp(argv[1], "cheader"))
mode = OUTPUT_FMT_C_HEADER;
else
f = argv[1];
fp = fopen(f, "rb");
if (!fp) {
perror("Unable to open file");
goto bail;
}
if (fseek(fp, 0, SEEK_END)) {
perror("stat");
goto bail;
}
file_size = ftell(fp);
file_buf = malloc(file_size);
if (!file_buf) {
perror("malloc");
goto bail;
}
rewind(fp);
if (fread(file_buf, sizeof(char), file_size, fp) != file_size) {
perror("read");
goto bail;
}
if (fclose(fp)) {
perror("close");
goto bail;
}
#if defined(__GNUC__) && __GNUC__
#if defined(__MACH__)
res = parse_macho(file_buf, file_size, mode);
#elif defined(__ELF__)
res = parse_elf(file_buf, file_size, mode);
#endif
#endif
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
res = parse_coff(file_buf, file_size);
#endif
free(file_buf);
if (!res)
return EXIT_SUCCESS;
bail:
return EXIT_FAILURE;
}

View File

@@ -3,7 +3,7 @@
no strict 'refs'; no strict 'refs';
use warnings; use warnings;
use Getopt::Long; use Getopt::Long;
Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32; Getopt::Long::Configure("auto_help");
my %ALL_FUNCS = (); my %ALL_FUNCS = ();
my @ALL_ARCHS; my @ALL_ARCHS;
@@ -49,7 +49,7 @@ open CONFIG_FILE, $opts{config} or
my %config = (); my %config = ();
while (<CONFIG_FILE>) { while (<CONFIG_FILE>) {
next if !/^(?:CONFIG_|HAVE_)/; next if !/^CONFIG_/;
chomp; chomp;
my @pair = split /=/; my @pair = split /=/;
$config{$pair[0]} = $pair[1]; $config{$pair[0]} = $pair[1];
@@ -209,16 +209,14 @@ sub common_top() {
#define RTCD_EXTERN extern #define RTCD_EXTERN extern
#endif #endif
EOF
process_forward_decls();
print <<EOF;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
EOF EOF
process_forward_decls();
print "\n";
declare_function_pointers("c", @ALL_ARCHS); declare_function_pointers("c", @ALL_ARCHS);
print <<EOF; print <<EOF;
@@ -319,8 +317,14 @@ EOF
print <<EOF; print <<EOF;
#if HAVE_DSPR2 #if HAVE_DSPR2
void vpx_dsputil_static_init(); #if CONFIG_VP8
vpx_dsputil_static_init(); void dsputil_static_init();
dsputil_static_init();
#endif
#if CONFIG_VP9
void vp9_dsputil_static_init();
vp9_dsputil_static_init();
#endif
#endif #endif
} }
#endif #endif
@@ -361,31 +365,28 @@ if ($opts{arch} eq 'x86') {
@REQUIRES = filter(keys %required ? keys %required : qw/mmx sse sse2/); @REQUIRES = filter(keys %required ? keys %required : qw/mmx sse sse2/);
&require(@REQUIRES); &require(@REQUIRES);
x86; x86;
} elsif ($opts{arch} eq 'mips32' || $opts{arch} eq 'mips64') { } elsif ($opts{arch} eq 'mips32') {
@ALL_ARCHS = filter("$opts{arch}"); @ALL_ARCHS = filter(qw/mips32/);
open CONFIG_FILE, $opts{config} or open CONFIG_FILE, $opts{config} or
die "Error opening config file '$opts{config}': $!\n"; die "Error opening config file '$opts{config}': $!\n";
while (<CONFIG_FILE>) { while (<CONFIG_FILE>) {
if (/HAVE_DSPR2=yes/) { if (/HAVE_DSPR2=yes/) {
@ALL_ARCHS = filter("$opts{arch}", qw/dspr2/); @ALL_ARCHS = filter(qw/mips32 dspr2/);
last;
}
if (/HAVE_MSA=yes/) {
@ALL_ARCHS = filter("$opts{arch}", qw/msa/);
last; last;
} }
} }
close CONFIG_FILE; close CONFIG_FILE;
mips; mips;
} elsif ($opts{arch} eq 'armv5te') {
@ALL_ARCHS = filter(qw/edsp/);
arm;
} elsif ($opts{arch} eq 'armv6') { } elsif ($opts{arch} eq 'armv6') {
@ALL_ARCHS = filter(qw/media/); @ALL_ARCHS = filter(qw/edsp media/);
arm; arm;
} elsif ($opts{arch} =~ /armv7\w?/) { } elsif ($opts{arch} eq 'armv7') {
@ALL_ARCHS = filter(qw/media neon_asm neon/); @ALL_ARCHS = filter(qw/edsp media neon_asm neon/);
@REQUIRES = filter(keys %required ? keys %required : qw/media/);
&require(@REQUIRES);
arm; arm;
} elsif ($opts{arch} eq 'armv8' || $opts{arch} eq 'arm64' ) { } elsif ($opts{arch} eq 'armv8') {
@ALL_ARCHS = filter(qw/neon/); @ALL_ARCHS = filter(qw/neon/);
arm; arm;
} else { } else {

View File

@@ -24,9 +24,8 @@ out_file=${2}
id=${3:-VERSION_STRING} id=${3:-VERSION_STRING}
git_version_id="" git_version_id=""
if [ -e "${source_path}/.git" ]; then if [ -d "${source_path}/.git" ]; then
# Source Path is a git working copy. Check for local modifications. # Source Path is a git working copy. Check for local modifications.
# Note that git submodules may have a file as .git, not a directory.
export GIT_DIR="${source_path}/.git" export GIT_DIR="${source_path}/.git"
git_version_id=`git describe --match=v[0-9]* 2>/dev/null` git_version_id=`git describe --match=v[0-9]* 2>/dev/null`
fi fi

View File

@@ -0,0 +1,15 @@
REM Copyright (c) 2011 The WebM project authors. All Rights Reserved.
REM
REM Use of this source code is governed by a BSD-style license
REM that can be found in the LICENSE file in the root of the source
REM tree. An additional intellectual property rights grant can be found
REM in the file PATENTS. All contributing project authors may
REM be found in the AUTHORS file in the root of the source tree.
echo on
REM Arguments:
REM %1 - Relative path to the directory containing the vp8 source directory.
REM %2 - Path to obj_int_extract.exe.
cl /I. /I%1 /nologo /c "%~1/vp8/encoder/vp8_asm_enc_offsets.c"
%2\obj_int_extract.exe rvds "vp8_asm_enc_offsets.obj" > "vp8_asm_enc_offsets.asm"

View File

@@ -1,4 +0,0 @@
# This file is used by gcl to get repository specific information.
GERRIT_HOST: chromium-review.googlesource.com
GERRIT_PORT: 29418
CODE_REVIEW_SERVER: chromium-review.googlesource.com

290
configure vendored
View File

@@ -25,21 +25,18 @@ Advanced options:
${toggle_docs} documentation ${toggle_docs} documentation
${toggle_unit_tests} unit tests ${toggle_unit_tests} unit tests
${toggle_decode_perf_tests} build decoder perf tests with unit tests ${toggle_decode_perf_tests} build decoder perf tests with unit tests
${toggle_encode_perf_tests} build encoder perf tests with unit tests
--cpu=CPU tune for the specified CPU (ARM: cortex-a8, X86: sse3)
--libc=PATH path to alternate libc --libc=PATH path to alternate libc
--size-limit=WxH max size to allow in the decoder
--as={yasm|nasm|auto} use specified assembler [auto, yasm preferred] --as={yasm|nasm|auto} use specified assembler [auto, yasm preferred]
--sdk-path=PATH path to root of sdk (android builds only) --sdk-path=PATH path to root of sdk (android builds only)
${toggle_fast_unaligned} don't use unaligned accesses, even when
supported by hardware [auto]
${toggle_codec_srcs} in/exclude codec library source code ${toggle_codec_srcs} in/exclude codec library source code
${toggle_debug_libs} in/exclude debug version of libraries ${toggle_debug_libs} in/exclude debug version of libraries
${toggle_static_msvcrt} use static MSVCRT (VS builds only) ${toggle_static_msvcrt} use static MSVCRT (VS builds only)
${toggle_vpx_highbitdepth} use VPX high bit depth (10/12) profiles ${toggle_vp8} VP8 codec support
${toggle_better_hw_compatibility} ${toggle_vp9} VP9 codec support
enable encoder to produce streams with better
hardware decoder compatibility
${toggle_vp10} VP10 codec support
${toggle_internal_stats} output of encoder internal stats for debug, if supported (encoders) ${toggle_internal_stats} output of encoder internal stats for debug, if supported (encoders)
${toggle_mem_tracker} track memory usage
${toggle_postproc} postprocessing ${toggle_postproc} postprocessing
${toggle_vp9_postproc} vp9 specific postprocessing ${toggle_vp9_postproc} vp9 specific postprocessing
${toggle_multithread} multithreaded encoding and decoding ${toggle_multithread} multithreaded encoding and decoding
@@ -47,9 +44,6 @@ Advanced options:
${toggle_realtime_only} enable this option while building for real-time encoding ${toggle_realtime_only} enable this option while building for real-time encoding
${toggle_onthefly_bitpacking} enable on-the-fly bitpacking in real-time encoding ${toggle_onthefly_bitpacking} enable on-the-fly bitpacking in real-time encoding
${toggle_error_concealment} enable this option to get a decoder which is able to conceal losses ${toggle_error_concealment} enable this option to get a decoder which is able to conceal losses
${toggle_coefficient_range_checking}
enable decoder to check if intermediate
transform coefficients are in valid range
${toggle_runtime_cpu_detect} runtime cpu detection ${toggle_runtime_cpu_detect} runtime cpu detection
${toggle_shared} shared library support ${toggle_shared} shared library support
${toggle_static} static library support ${toggle_static} static library support
@@ -57,8 +51,6 @@ Advanced options:
${toggle_postproc_visualizer} macro block / block level visualizers ${toggle_postproc_visualizer} macro block / block level visualizers
${toggle_multi_res_encoding} enable multiple-resolution encoding ${toggle_multi_res_encoding} enable multiple-resolution encoding
${toggle_temporal_denoising} enable temporal denoising and disable the spatial denoiser ${toggle_temporal_denoising} enable temporal denoising and disable the spatial denoiser
${toggle_vp9_temporal_denoising}
enable vp9 temporal denoising
${toggle_webm_io} enable input from and output to WebM container ${toggle_webm_io} enable input from and output to WebM container
${toggle_libyuv} enable libyuv ${toggle_libyuv} enable libyuv
@@ -73,10 +65,10 @@ Codecs:
EOF EOF
#restore editor state ' #restore editor state '
family=""; local family;
last_family=""; local last_family;
c=""; local c;
str=""; local str;
for c in ${CODECS}; do for c in ${CODECS}; do
family=${c%_*} family=${c%_*}
if [ "${family}" != "${last_family}" ]; then if [ "${family}" != "${last_family}" ]; then
@@ -96,8 +88,11 @@ EOF
# all_platforms is a list of all supported target platforms. Maintain # all_platforms is a list of all supported target platforms. Maintain
# alphabetically by architecture, generic-gnu last. # alphabetically by architecture, generic-gnu last.
all_platforms="${all_platforms} arm64-darwin-gcc" all_platforms="${all_platforms} armv5te-android-gcc"
all_platforms="${all_platforms} arm64-linux-gcc" all_platforms="${all_platforms} armv5te-linux-rvct"
all_platforms="${all_platforms} armv5te-linux-gcc"
all_platforms="${all_platforms} armv5te-none-rvct"
all_platforms="${all_platforms} armv6-darwin-gcc"
all_platforms="${all_platforms} armv6-linux-rvct" all_platforms="${all_platforms} armv6-linux-rvct"
all_platforms="${all_platforms} armv6-linux-gcc" all_platforms="${all_platforms} armv6-linux-gcc"
all_platforms="${all_platforms} armv6-none-rvct" all_platforms="${all_platforms} armv6-none-rvct"
@@ -108,11 +103,13 @@ all_platforms="${all_platforms} armv7-linux-gcc" #neon Cortex-A8
all_platforms="${all_platforms} armv7-none-rvct" #neon Cortex-A8 all_platforms="${all_platforms} armv7-none-rvct" #neon Cortex-A8
all_platforms="${all_platforms} armv7-win32-vs11" all_platforms="${all_platforms} armv7-win32-vs11"
all_platforms="${all_platforms} armv7-win32-vs12" all_platforms="${all_platforms} armv7-win32-vs12"
all_platforms="${all_platforms} armv7-win32-vs14"
all_platforms="${all_platforms} armv7s-darwin-gcc"
all_platforms="${all_platforms} armv8-linux-gcc"
all_platforms="${all_platforms} mips32-linux-gcc" all_platforms="${all_platforms} mips32-linux-gcc"
all_platforms="${all_platforms} mips64-linux-gcc" all_platforms="${all_platforms} ppc32-darwin8-gcc"
all_platforms="${all_platforms} ppc32-darwin9-gcc"
all_platforms="${all_platforms} ppc32-linux-gcc"
all_platforms="${all_platforms} ppc64-darwin8-gcc"
all_platforms="${all_platforms} ppc64-darwin9-gcc"
all_platforms="${all_platforms} ppc64-linux-gcc"
all_platforms="${all_platforms} sparc-solaris-gcc" all_platforms="${all_platforms} sparc-solaris-gcc"
all_platforms="${all_platforms} x86-android-gcc" all_platforms="${all_platforms} x86-android-gcc"
all_platforms="${all_platforms} x86-darwin8-gcc" all_platforms="${all_platforms} x86-darwin8-gcc"
@@ -123,35 +120,39 @@ all_platforms="${all_platforms} x86-darwin10-gcc"
all_platforms="${all_platforms} x86-darwin11-gcc" all_platforms="${all_platforms} x86-darwin11-gcc"
all_platforms="${all_platforms} x86-darwin12-gcc" all_platforms="${all_platforms} x86-darwin12-gcc"
all_platforms="${all_platforms} x86-darwin13-gcc" all_platforms="${all_platforms} x86-darwin13-gcc"
all_platforms="${all_platforms} x86-darwin14-gcc"
all_platforms="${all_platforms} x86-darwin15-gcc"
all_platforms="${all_platforms} x86-iphonesimulator-gcc" all_platforms="${all_platforms} x86-iphonesimulator-gcc"
all_platforms="${all_platforms} x86-linux-gcc" all_platforms="${all_platforms} x86-linux-gcc"
all_platforms="${all_platforms} x86-linux-icc" all_platforms="${all_platforms} x86-linux-icc"
all_platforms="${all_platforms} x86-os2-gcc" all_platforms="${all_platforms} x86-os2-gcc"
all_platforms="${all_platforms} x86-solaris-gcc" all_platforms="${all_platforms} x86-solaris-gcc"
all_platforms="${all_platforms} x86-win32-gcc" all_platforms="${all_platforms} x86-win32-gcc"
all_platforms="${all_platforms} x86-win32-vs7"
all_platforms="${all_platforms} x86-win32-vs8"
all_platforms="${all_platforms} x86-win32-vs9"
all_platforms="${all_platforms} x86-win32-vs10" all_platforms="${all_platforms} x86-win32-vs10"
all_platforms="${all_platforms} x86-win32-vs11" all_platforms="${all_platforms} x86-win32-vs11"
all_platforms="${all_platforms} x86-win32-vs12" all_platforms="${all_platforms} x86-win32-vs12"
all_platforms="${all_platforms} x86-win32-vs14"
all_platforms="${all_platforms} x86_64-android-gcc"
all_platforms="${all_platforms} x86_64-darwin9-gcc" all_platforms="${all_platforms} x86_64-darwin9-gcc"
all_platforms="${all_platforms} x86_64-darwin10-gcc" all_platforms="${all_platforms} x86_64-darwin10-gcc"
all_platforms="${all_platforms} x86_64-darwin11-gcc" all_platforms="${all_platforms} x86_64-darwin11-gcc"
all_platforms="${all_platforms} x86_64-darwin12-gcc" all_platforms="${all_platforms} x86_64-darwin12-gcc"
all_platforms="${all_platforms} x86_64-darwin13-gcc" all_platforms="${all_platforms} x86_64-darwin13-gcc"
all_platforms="${all_platforms} x86_64-darwin14-gcc"
all_platforms="${all_platforms} x86_64-darwin15-gcc"
all_platforms="${all_platforms} x86_64-iphonesimulator-gcc" all_platforms="${all_platforms} x86_64-iphonesimulator-gcc"
all_platforms="${all_platforms} x86_64-linux-gcc" all_platforms="${all_platforms} x86_64-linux-gcc"
all_platforms="${all_platforms} x86_64-linux-icc" all_platforms="${all_platforms} x86_64-linux-icc"
all_platforms="${all_platforms} x86_64-solaris-gcc" all_platforms="${all_platforms} x86_64-solaris-gcc"
all_platforms="${all_platforms} x86_64-win64-gcc" all_platforms="${all_platforms} x86_64-win64-gcc"
all_platforms="${all_platforms} x86_64-win64-vs8"
all_platforms="${all_platforms} x86_64-win64-vs9"
all_platforms="${all_platforms} x86_64-win64-vs10" all_platforms="${all_platforms} x86_64-win64-vs10"
all_platforms="${all_platforms} x86_64-win64-vs11" all_platforms="${all_platforms} x86_64-win64-vs11"
all_platforms="${all_platforms} x86_64-win64-vs12" all_platforms="${all_platforms} x86_64-win64-vs12"
all_platforms="${all_platforms} x86_64-win64-vs14" all_platforms="${all_platforms} universal-darwin8-gcc"
all_platforms="${all_platforms} universal-darwin9-gcc"
all_platforms="${all_platforms} universal-darwin10-gcc"
all_platforms="${all_platforms} universal-darwin11-gcc"
all_platforms="${all_platforms} universal-darwin12-gcc"
all_platforms="${all_platforms} universal-darwin13-gcc"
all_platforms="${all_platforms} generic-gnu" all_platforms="${all_platforms} generic-gnu"
# all_targets is a list of all targets that can be configured # all_targets is a list of all targets that can be configured
@@ -188,9 +189,6 @@ if [ ${doxy_major:-0} -ge 1 ]; then
[ $doxy_minor -eq 5 ] && [ $doxy_patch -ge 3 ] && enable_feature doxygen [ $doxy_minor -eq 5 ] && [ $doxy_patch -ge 3 ] && enable_feature doxygen
fi fi
# disable codecs when their source directory does not exist
[ -d "${source_path}/vp10" ] || disable_codec vp10
# install everything except the sources, by default. sources will have # install everything except the sources, by default. sources will have
# to be enabled when doing dist builds, since that's no longer a common # to be enabled when doing dist builds, since that's no longer a common
# case. # case.
@@ -200,35 +198,45 @@ enable_feature install_libs
enable_feature static enable_feature static
enable_feature optimizations enable_feature optimizations
enable_feature dependency_tracking enable_feature fast_unaligned #allow unaligned accesses, if supported by hw
enable_feature spatial_resampling enable_feature spatial_resampling
enable_feature multithread enable_feature multithread
enable_feature os_support enable_feature os_support
enable_feature temporal_denoising enable_feature temporal_denoising
CODECS=" [ -d "${source_path}/../include" ] && enable_feature alt_tree_layout
vp10_encoder for d in vp8 vp9; do
vp10_decoder [ -d "${source_path}/${d}" ] && disable_feature alt_tree_layout;
" done
CODEC_FAMILIES="
vp10 if ! enabled alt_tree_layout; then
" # development environment
[ -d "${source_path}/vp8" ] && CODECS="${CODECS} vp8_encoder vp8_decoder"
[ -d "${source_path}/vp9" ] && CODECS="${CODECS} vp9_encoder vp9_decoder"
else
# customer environment
[ -f "${source_path}/../include/vpx/vp8cx.h" ] && CODECS="${CODECS} vp8_encoder"
[ -f "${source_path}/../include/vpx/vp8dx.h" ] && CODECS="${CODECS} vp8_decoder"
[ -f "${source_path}/../include/vpx/vp9cx.h" ] && CODECS="${CODECS} vp9_encoder"
[ -f "${source_path}/../include/vpx/vp9dx.h" ] && CODECS="${CODECS} vp9_decoder"
[ -f "${source_path}/../include/vpx/vp8cx.h" ] || disable_feature vp8_encoder
[ -f "${source_path}/../include/vpx/vp8dx.h" ] || disable_feature vp8_decoder
[ -f "${source_path}/../include/vpx/vp9cx.h" ] || disable_feature vp9_encoder
[ -f "${source_path}/../include/vpx/vp9dx.h" ] || disable_feature vp9_decoder
[ -f "${source_path}/../lib/*/*mt.lib" ] && soft_enable static_msvcrt
fi
CODECS="$(echo ${CODECS} | tr ' ' '\n')"
CODEC_FAMILIES="$(for c in ${CODECS}; do echo ${c%_*}; done | sort | uniq)"
ARCH_LIST=" ARCH_LIST="
arm arm
mips mips
x86 x86
x86_64 x86_64
" ppc32
ARCH_EXT_LIST_X86=" ppc64
mmx
sse
sse2
sse3
ssse3
sse4_1
avx
avx2
" "
ARCH_EXT_LIST=" ARCH_EXT_LIST="
edsp edsp
@@ -238,50 +246,40 @@ ARCH_EXT_LIST="
mips32 mips32
dspr2 dspr2
msa
mips64
${ARCH_EXT_LIST_X86} mmx
sse
sse2
sse3
ssse3
sse4_1
avx
avx2
altivec
" "
HAVE_LIST=" HAVE_LIST="
${ARCH_EXT_LIST} ${ARCH_EXT_LIST}
vpx_ports vpx_ports
stdint_h
alt_tree_layout
pthread_h pthread_h
sys_mman_h
unistd_h unistd_h
" "
EXPERIMENT_LIST=" EXPERIMENT_LIST="
alpha
multiple_arf
spatial_svc spatial_svc
fp_mb_stats transcode
emulate_hardware
var_tx
rect_tx
ref_mv
dual_filter
ext_tx
ext_intra
ext_inter
ext_interp
ext_refs
global_motion
new_quant
supertx
ans
loop_restoration
ext_partition
ext_partition_types
ext_tile
obmc
warped_motion
entropy
bidir_pred
" "
CONFIG_LIST=" CONFIG_LIST="
dependency_tracking
external_build external_build
install_docs install_docs
install_bins install_bins
install_libs install_libs
install_srcs install_srcs
use_x86inc
debug debug
gprof gprof
gcov gcov
@@ -293,6 +291,10 @@ CONFIG_LIST="
codec_srcs codec_srcs
debug_libs debug_libs
fast_unaligned
mem_manager
mem_tracker
mem_checks
dequant_tokens dequant_tokens
dc_recon dc_recon
@@ -319,19 +321,12 @@ CONFIG_LIST="
webm_io webm_io
libyuv libyuv
decode_perf_tests decode_perf_tests
encode_perf_tests
multi_res_encoding multi_res_encoding
temporal_denoising temporal_denoising
vp9_temporal_denoising
coefficient_range_checking
vpx_highbitdepth
better_hw_compatibility
experimental experimental
size_limit
${EXPERIMENT_LIST} ${EXPERIMENT_LIST}
" "
CMDLINE_SELECT=" CMDLINE_SELECT="
dependency_tracking
external_build external_build
extra_warnings extra_warnings
werror werror
@@ -343,6 +338,7 @@ CMDLINE_SELECT="
gprof gprof
gcov gcov
pic pic
use_x86inc
optimizations optimizations
ccache ccache
runtime_cpu_detect runtime_cpu_detect
@@ -353,7 +349,7 @@ CMDLINE_SELECT="
docs docs
libc libc
as as
size_limit fast_unaligned
codec_srcs codec_srcs
debug_libs debug_libs
@@ -366,6 +362,7 @@ CMDLINE_SELECT="
${CODECS} ${CODECS}
${CODEC_FAMILIES} ${CODEC_FAMILIES}
static_msvcrt static_msvcrt
mem_tracker
spatial_resampling spatial_resampling
realtime_only realtime_only
onthefly_bitpacking onthefly_bitpacking
@@ -378,13 +375,8 @@ CMDLINE_SELECT="
webm_io webm_io
libyuv libyuv
decode_perf_tests decode_perf_tests
encode_perf_tests
multi_res_encoding multi_res_encoding
temporal_denoising temporal_denoising
vp9_temporal_denoising
coefficient_range_checking
better_hw_compatibility
vpx_highbitdepth
experimental experimental
" "
@@ -392,19 +384,15 @@ process_cmdline() {
for opt do for opt do
optval="${opt#*=}" optval="${opt#*=}"
case "$opt" in case "$opt" in
--disable-codecs) --disable-codecs) for c in ${CODECS}; do disable_feature $c; done ;;
for c in ${CODEC_FAMILIES}; do disable_codec $c; done
;;
--enable-?*|--disable-?*) --enable-?*|--disable-?*)
eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'` eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'`
if is_in ${option} ${EXPERIMENT_LIST}; then if echo "${EXPERIMENT_LIST}" | grep "^ *$option\$" >/dev/null; then
if enabled experimental; then if enabled experimental; then
${action}_feature $option ${action}_feature $option
else else
log_echo "Ignoring $opt -- not in experimental mode." log_echo "Ignoring $opt -- not in experimental mode."
fi fi
elif is_in ${option} "${CODECS} ${CODEC_FAMILIES}"; then
${action}_codec ${option}
else else
process_common_cmdline $opt process_common_cmdline $opt
fi fi
@@ -416,7 +404,15 @@ process_cmdline() {
} }
post_process_cmdline() { post_process_cmdline() {
c="" local c
# If the codec family is disabled, disable all components of that family.
# If the codec family is enabled, enable all components of that family.
log_echo "Configuring selected codecs"
for c in ${CODECS}; do
disabled ${c%%_*} && disable_feature ${c}
enabled ${c%%_*} && enable_feature ${c}
done
# Enable all detected codecs, if they haven't been disabled # Enable all detected codecs, if they haven't been disabled
for c in ${CODECS}; do soft_enable $c; done for c in ${CODECS}; do soft_enable $c; done
@@ -435,12 +431,28 @@ post_process_cmdline() {
process_targets() { process_targets() {
enabled child || write_common_config_banner enabled child || write_common_config_banner
write_common_target_config_h ${BUILD_PFX}vpx_config.h enabled universal || write_common_target_config_h ${BUILD_PFX}vpx_config.h
# TODO: add host tools target (obj_int_extract, etc)
# For fat binaries, call configure recursively to configure for each
# binary architecture to be included.
if enabled universal; then
# Call configure (ourselves) for each subarchitecture
for arch in $fat_bin_archs; do
BUILD_PFX=${arch}/ toolchain=${arch} $self --child $cmdline_args || exit $?
done
fi
# The write_common_config (config.mk) logic is deferred until after the
# recursive calls to configure complete, because we want our universal
# targets to be executed last.
write_common_config_targets write_common_config_targets
enabled universal && echo "FAT_ARCHS=${fat_bin_archs}" >> config.mk
# Calculate the default distribution name, based on the enabled features # Calculate the default distribution name, based on the enabled features
cf="" local cf
DIST_DIR=vpx local DIST_DIR=vpx
for cf in $CODEC_FAMILIES; do for cf in $CODEC_FAMILIES; do
if enabled ${cf}_encoder && enabled ${cf}_decoder; then if enabled ${cf}_encoder && enabled ${cf}_decoder; then
DIST_DIR="${DIST_DIR}-${cf}" DIST_DIR="${DIST_DIR}-${cf}"
@@ -462,7 +474,7 @@ process_targets() {
;; ;;
esac esac
if [ -f "${source_path}/build/make/version.sh" ]; then if [ -f "${source_path}/build/make/version.sh" ]; then
ver=`"$source_path/build/make/version.sh" --bare "$source_path"` local ver=`"$source_path/build/make/version.sh" --bare "$source_path"`
DIST_DIR="${DIST_DIR}-${ver}" DIST_DIR="${DIST_DIR}-${ver}"
VERSION_STRING=${ver} VERSION_STRING=${ver}
ver=${ver%%-*} ver=${ver%%-*}
@@ -496,7 +508,7 @@ EOF
# Write makefiles for all enabled targets # Write makefiles for all enabled targets
# #
for tgt in libs examples docs solution; do for tgt in libs examples docs solution; do
tgt_fn="$tgt-$toolchain.mk" local tgt_fn="$tgt-$toolchain.mk"
if enabled $tgt; then if enabled $tgt; then
echo "Creating makefiles for ${toolchain} ${tgt}" echo "Creating makefiles for ${toolchain} ${tgt}"
@@ -512,18 +524,13 @@ process_detect() {
# Can only build shared libs on a subset of platforms. Doing this check # Can only build shared libs on a subset of platforms. Doing this check
# here rather than at option parse time because the target auto-detect # here rather than at option parse time because the target auto-detect
# magic happens after the command line has been parsed. # magic happens after the command line has been parsed.
case "${tgt_os}" in if ! enabled linux; then
linux|os2|darwin*|iphonesimulator*)
# Supported platforms
;;
*)
if enabled gnu; then if enabled gnu; then
echo "--enable-shared is only supported on ELF; assuming this is OK" echo "--enable-shared is only supported on ELF; assuming this is OK"
else else
die "--enable-shared only supported on ELF, OS/2, and Darwin for now" die "--enable-shared only supported on ELF for now"
fi
fi fi
;;
esac
fi fi
if [ -z "$CC" ] || enabled external_build; then if [ -z "$CC" ] || enabled external_build; then
echo "Bypassing toolchain for environment detection." echo "Bypassing toolchain for environment detection."
@@ -540,7 +547,7 @@ process_detect() {
true; true;
;; ;;
*) *)
result=false local result=false
for d in "$@"; do for d in "$@"; do
[ -f "${d##-I}/$header" ] && result=true && break [ -f "${d##-I}/$header" ] && result=true && break
done done
@@ -550,12 +557,16 @@ process_detect() {
# Specialize windows and POSIX environments. # Specialize windows and POSIX environments.
case $toolchain in case $toolchain in
*-win*-*) *-win*-*)
# Don't check for any headers in Windows builds. case $header-$toolchain in
false stdint*-gcc) true;;
*) false;;
esac && enable_feature $var
;; ;;
*) *)
case $header in case $header in
stdint.h) true;;
pthread.h) true;; pthread.h) true;;
sys/mman.h) true;;
unistd.h) true;; unistd.h) true;;
*) false;; *) false;;
esac && enable_feature $var esac && enable_feature $var
@@ -571,7 +582,9 @@ process_detect() {
int main(void) {return 0;} int main(void) {return 0;}
EOF EOF
# check system headers # check system headers
check_header stdint.h
check_header pthread.h check_header pthread.h
check_header sys/mman.h
check_header unistd.h # for sysconf(3) and friends. check_header unistd.h # for sysconf(3) and friends.
check_header vpx/vpx_integer.h -I${source_path} && enable_feature vpx_ports check_header vpx/vpx_integer.h -I${source_path} && enable_feature vpx_ports
@@ -580,6 +593,30 @@ EOF
process_toolchain() { process_toolchain() {
process_common_toolchain process_common_toolchain
# Handle universal binaries for this architecture
case $toolchain in
universal-darwin*)
local darwin_ver=${tgt_os##darwin}
# Snow Leopard (10.6/darwin10) dropped support for PPC
# Include PPC support for all prior versions
if [ $darwin_ver -lt 10 ]; then
fat_bin_archs="$fat_bin_archs ppc32-${tgt_os}-gcc"
fi
# Tiger (10.4/darwin8) brought support for x86
if [ $darwin_ver -ge 8 ]; then
fat_bin_archs="$fat_bin_archs x86-${tgt_os}-${tgt_cc}"
fi
# Leopard (10.5/darwin9) brought 64 bit support
if [ $darwin_ver -ge 9 ]; then
fat_bin_archs="$fat_bin_archs x86_64-${tgt_os}-${tgt_cc}"
fi
;;
esac
# Enable some useful compiler flags # Enable some useful compiler flags
if enabled gcc; then if enabled gcc; then
enabled werror && check_add_cflags -Werror enabled werror && check_add_cflags -Werror
@@ -602,11 +639,7 @@ process_toolchain() {
;; ;;
*) check_add_cflags -Wunused-but-set-variable ;; *) check_add_cflags -Wunused-but-set-variable ;;
esac esac
if enabled mips || [ -z "${INLINE}" ]; then
enabled extra_warnings || check_add_cflags -Wno-unused-function enabled extra_warnings || check_add_cflags -Wno-unused-function
else
check_add_cflags -Wunused-function
fi
fi fi
if enabled icc; then if enabled icc; then
@@ -654,16 +687,24 @@ process_toolchain() {
vs*) enable_feature msvs vs*) enable_feature msvs
enable_feature solution enable_feature solution
vs_version=${tgt_cc##vs} vs_version=${tgt_cc##vs}
case $vs_version in
[789])
VCPROJ_SFX=vcproj
gen_vcproj_cmd=${source_path}/build/make/gen_msvs_proj.sh
;;
10|11|12)
VCPROJ_SFX=vcxproj VCPROJ_SFX=vcxproj
gen_vcproj_cmd=${source_path}/build/make/gen_msvs_vcxproj.sh gen_vcproj_cmd=${source_path}/build/make/gen_msvs_vcxproj.sh
enabled werror && gen_vcproj_cmd="${gen_vcproj_cmd} --enable-werror" enabled werror && gen_vcproj_cmd="${gen_vcproj_cmd} --enable-werror"
;;
esac
all_targets="${all_targets} solution" all_targets="${all_targets} solution"
INLINE="__forceinline" INLINE="__forceinline"
;; ;;
esac esac
# Other toolchain specific defaults # Other toolchain specific defaults
case $toolchain in x86*) soft_enable postproc;; esac case $toolchain in x86*|ppc*|universal*) soft_enable postproc;; esac
if enabled postproc_visualizer; then if enabled postproc_visualizer; then
enabled postproc || die "postproc_visualizer requires postproc to be enabled" enabled postproc || die "postproc_visualizer requires postproc to be enabled"
@@ -717,16 +758,6 @@ EOF
esac esac
# libwebm needs to be linked with C++ standard library # libwebm needs to be linked with C++ standard library
enabled webm_io && LD=${CXX} enabled webm_io && LD=${CXX}
# append any user defined extra cflags
if [ -n "${extra_cflags}" ] ; then
check_add_cflags ${extra_cflags} || \
die "Requested extra CFLAGS '${extra_cflags}' not supported by compiler"
fi
if [ -n "${extra_cxxflags}" ]; then
check_add_cxxflags ${extra_cxxflags} || \
die "Requested extra CXXFLAGS '${extra_cxxflags}' not supported by compiler"
fi
} }
@@ -737,7 +768,6 @@ CONFIGURE_ARGS="$@"
process "$@" process "$@"
print_webm_license ${BUILD_PFX}vpx_config.c "/*" " */" print_webm_license ${BUILD_PFX}vpx_config.c "/*" " */"
cat <<EOF >> ${BUILD_PFX}vpx_config.c cat <<EOF >> ${BUILD_PFX}vpx_config.c
#include "vpx/vpx_codec.h"
static const char* const cfg = "$CONFIGURE_ARGS"; static const char* const cfg = "$CONFIGURE_ARGS";
const char *vpx_codec_build_config(void) {return cfg;} const char *vpx_codec_build_config(void) {return cfg;}
EOF EOF

View File

@@ -9,12 +9,8 @@
## ##
LIBYUV_SRCS += third_party/libyuv/include/libyuv/basic_types.h \ LIBYUV_SRCS += third_party/libyuv/include/libyuv/basic_types.h \
third_party/libyuv/include/libyuv/convert.h \
third_party/libyuv/include/libyuv/convert_argb.h \
third_party/libyuv/include/libyuv/convert_from.h \
third_party/libyuv/include/libyuv/cpu_id.h \ third_party/libyuv/include/libyuv/cpu_id.h \
third_party/libyuv/include/libyuv/planar_functions.h \ third_party/libyuv/include/libyuv/planar_functions.h \
third_party/libyuv/include/libyuv/rotate.h \
third_party/libyuv/include/libyuv/row.h \ third_party/libyuv/include/libyuv/row.h \
third_party/libyuv/include/libyuv/scale.h \ third_party/libyuv/include/libyuv/scale.h \
third_party/libyuv/include/libyuv/scale_row.h \ third_party/libyuv/include/libyuv/scale_row.h \
@@ -22,44 +18,31 @@ LIBYUV_SRCS += third_party/libyuv/include/libyuv/basic_types.h \
third_party/libyuv/source/planar_functions.cc \ third_party/libyuv/source/planar_functions.cc \
third_party/libyuv/source/row_any.cc \ third_party/libyuv/source/row_any.cc \
third_party/libyuv/source/row_common.cc \ third_party/libyuv/source/row_common.cc \
third_party/libyuv/source/row_gcc.cc \
third_party/libyuv/source/row_mips.cc \ third_party/libyuv/source/row_mips.cc \
third_party/libyuv/source/row_neon.cc \ third_party/libyuv/source/row_neon.cc \
third_party/libyuv/source/row_neon64.cc \ third_party/libyuv/source/row_posix.cc \
third_party/libyuv/source/row_win.cc \ third_party/libyuv/source/row_win.cc \
third_party/libyuv/source/scale.cc \ third_party/libyuv/source/scale.cc \
third_party/libyuv/source/scale_any.cc \
third_party/libyuv/source/scale_common.cc \ third_party/libyuv/source/scale_common.cc \
third_party/libyuv/source/scale_gcc.cc \
third_party/libyuv/source/scale_mips.cc \ third_party/libyuv/source/scale_mips.cc \
third_party/libyuv/source/scale_neon.cc \ third_party/libyuv/source/scale_neon.cc \
third_party/libyuv/source/scale_neon64.cc \ third_party/libyuv/source/scale_posix.cc \
third_party/libyuv/source/scale_win.cc \ third_party/libyuv/source/scale_win.cc
LIBWEBM_COMMON_SRCS += third_party/libwebm/common/hdr_util.cc \ LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer.cpp \
third_party/libwebm/common/hdr_util.h \ third_party/libwebm/mkvmuxerutil.cpp \
third_party/libwebm/common/webmids.h third_party/libwebm/mkvwriter.cpp \
third_party/libwebm/mkvmuxer.hpp \
LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer/mkvmuxer.cc \ third_party/libwebm/mkvmuxertypes.hpp \
third_party/libwebm/mkvmuxer/mkvmuxerutil.cc \ third_party/libwebm/mkvmuxerutil.hpp \
third_party/libwebm/mkvmuxer/mkvwriter.cc \ third_party/libwebm/mkvparser.hpp \
third_party/libwebm/mkvmuxer/mkvmuxer.h \ third_party/libwebm/mkvwriter.hpp \
third_party/libwebm/mkvmuxer/mkvmuxertypes.h \ third_party/libwebm/webmids.hpp
third_party/libwebm/mkvmuxer/mkvmuxerutil.h \
third_party/libwebm/mkvparser/mkvparser.h \
third_party/libwebm/mkvmuxer/mkvwriter.h
LIBWEBM_PARSER_SRCS = third_party/libwebm/mkvparser/mkvparser.cc \
third_party/libwebm/mkvparser/mkvreader.cc \
third_party/libwebm/mkvparser/mkvparser.h \
third_party/libwebm/mkvparser/mkvreader.h
# Add compile flags and include path for libwebm sources.
ifeq ($(CONFIG_WEBM_IO),yes)
CXXFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
INC_PATH-yes += $(SRC_PATH_BARE)/third_party/libwebm
endif
LIBWEBM_PARSER_SRCS = third_party/libwebm/mkvparser.cpp \
third_party/libwebm/mkvreader.cpp \
third_party/libwebm/mkvparser.hpp \
third_party/libwebm/mkvreader.hpp
# List of examples to build. UTILS are tools meant for distribution # List of examples to build. UTILS are tools meant for distribution
# while EXAMPLES demonstrate specific portions of the API. # while EXAMPLES demonstrate specific portions of the API.
@@ -67,7 +50,6 @@ UTILS-$(CONFIG_DECODERS) += vpxdec.c
vpxdec.SRCS += md5_utils.c md5_utils.h vpxdec.SRCS += md5_utils.c md5_utils.h
vpxdec.SRCS += vpx_ports/mem_ops.h vpxdec.SRCS += vpx_ports/mem_ops.h
vpxdec.SRCS += vpx_ports/mem_ops_aligned.h vpxdec.SRCS += vpx_ports/mem_ops_aligned.h
vpxdec.SRCS += vpx_ports/msvc.h
vpxdec.SRCS += vpx_ports/vpx_timer.h vpxdec.SRCS += vpx_ports/vpx_timer.h
vpxdec.SRCS += vpx/vpx_integer.h vpxdec.SRCS += vpx/vpx_integer.h
vpxdec.SRCS += args.c args.h vpxdec.SRCS += args.c args.h
@@ -78,8 +60,6 @@ ifeq ($(CONFIG_LIBYUV),yes)
vpxdec.SRCS += $(LIBYUV_SRCS) vpxdec.SRCS += $(LIBYUV_SRCS)
endif endif
ifeq ($(CONFIG_WEBM_IO),yes) ifeq ($(CONFIG_WEBM_IO),yes)
vpxdec.SRCS += $(LIBWEBM_COMMON_SRCS)
vpxdec.SRCS += $(LIBWEBM_MUXER_SRCS)
vpxdec.SRCS += $(LIBWEBM_PARSER_SRCS) vpxdec.SRCS += $(LIBWEBM_PARSER_SRCS)
vpxdec.SRCS += webmdec.cc webmdec.h vpxdec.SRCS += webmdec.cc webmdec.h
endif endif
@@ -94,30 +74,41 @@ vpxenc.SRCS += tools_common.c tools_common.h
vpxenc.SRCS += warnings.c warnings.h vpxenc.SRCS += warnings.c warnings.h
vpxenc.SRCS += vpx_ports/mem_ops.h vpxenc.SRCS += vpx_ports/mem_ops.h
vpxenc.SRCS += vpx_ports/mem_ops_aligned.h vpxenc.SRCS += vpx_ports/mem_ops_aligned.h
vpxenc.SRCS += vpx_ports/msvc.h
vpxenc.SRCS += vpx_ports/vpx_timer.h vpxenc.SRCS += vpx_ports/vpx_timer.h
vpxenc.SRCS += vpxstats.c vpxstats.h vpxenc.SRCS += vpxstats.c vpxstats.h
ifeq ($(CONFIG_LIBYUV),yes) ifeq ($(CONFIG_LIBYUV),yes)
vpxenc.SRCS += $(LIBYUV_SRCS) vpxenc.SRCS += $(LIBYUV_SRCS)
endif endif
ifeq ($(CONFIG_WEBM_IO),yes) ifeq ($(CONFIG_WEBM_IO),yes)
vpxenc.SRCS += $(LIBWEBM_COMMON_SRCS)
vpxenc.SRCS += $(LIBWEBM_MUXER_SRCS) vpxenc.SRCS += $(LIBWEBM_MUXER_SRCS)
vpxenc.SRCS += $(LIBWEBM_PARSER_SRCS)
vpxenc.SRCS += webmenc.cc webmenc.h vpxenc.SRCS += webmenc.cc webmenc.h
endif endif
vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1 vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
vpxenc.DESCRIPTION = Full featured encoder vpxenc.DESCRIPTION = Full featured encoder
ifeq ($(CONFIG_SPATIAL_SVC),yes)
EXAMPLES-$(CONFIG_VP9_ENCODER) += vp9_spatial_svc_encoder.c
vp9_spatial_svc_encoder.SRCS += args.c args.h
vp9_spatial_svc_encoder.SRCS += ivfenc.c ivfenc.h
vp9_spatial_svc_encoder.SRCS += tools_common.c tools_common.h
vp9_spatial_svc_encoder.SRCS += video_common.h
vp9_spatial_svc_encoder.SRCS += video_writer.h video_writer.c
vp9_spatial_svc_encoder.SRCS += vpxstats.c vpxstats.h
vp9_spatial_svc_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D
vp9_spatial_svc_encoder.DESCRIPTION = VP9 Spatial SVC Encoder
endif
ifneq ($(CONFIG_SHARED),yes)
EXAMPLES-$(CONFIG_VP9_ENCODER) += resize_util.c
endif
EXAMPLES-$(CONFIG_ENCODERS) += vpx_temporal_svc_encoder.c EXAMPLES-$(CONFIG_ENCODERS) += vpx_temporal_svc_encoder.c
vpx_temporal_svc_encoder.SRCS += ivfenc.c ivfenc.h vpx_temporal_svc_encoder.SRCS += ivfenc.c ivfenc.h
vpx_temporal_svc_encoder.SRCS += tools_common.c tools_common.h vpx_temporal_svc_encoder.SRCS += tools_common.c tools_common.h
vpx_temporal_svc_encoder.SRCS += video_common.h vpx_temporal_svc_encoder.SRCS += video_common.h
vpx_temporal_svc_encoder.SRCS += video_writer.h video_writer.c vpx_temporal_svc_encoder.SRCS += video_writer.h video_writer.c
vpx_temporal_svc_encoder.SRCS += vpx_ports/msvc.h
vpx_temporal_svc_encoder.GUID = B18C08F2-A439-4502-A78E-849BE3D60947 vpx_temporal_svc_encoder.GUID = B18C08F2-A439-4502-A78E-849BE3D60947
vpx_temporal_svc_encoder.DESCRIPTION = Temporal SVC Encoder vpx_temporal_svc_encoder.DESCRIPTION = Temporal SVC Encoder
EXAMPLES-$(CONFIG_DECODERS) += simple_decoder.c EXAMPLES-$(CONFIG_VP8_DECODER) += simple_decoder.c
simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC
simple_decoder.SRCS += ivfdec.h ivfdec.c simple_decoder.SRCS += ivfdec.h ivfdec.c
simple_decoder.SRCS += tools_common.h tools_common.c simple_decoder.SRCS += tools_common.h tools_common.c
@@ -125,9 +116,17 @@ simple_decoder.SRCS += video_common.h
simple_decoder.SRCS += video_reader.h video_reader.c simple_decoder.SRCS += video_reader.h video_reader.c
simple_decoder.SRCS += vpx_ports/mem_ops.h simple_decoder.SRCS += vpx_ports/mem_ops.h
simple_decoder.SRCS += vpx_ports/mem_ops_aligned.h simple_decoder.SRCS += vpx_ports/mem_ops_aligned.h
simple_decoder.SRCS += vpx_ports/msvc.h
simple_decoder.DESCRIPTION = Simplified decoder loop simple_decoder.DESCRIPTION = Simplified decoder loop
EXAMPLES-$(CONFIG_DECODERS) += decode_to_md5.c EXAMPLES-$(CONFIG_VP8_DECODER) += postproc.c
postproc.SRCS += ivfdec.h ivfdec.c
postproc.SRCS += tools_common.h tools_common.c
postproc.SRCS += video_common.h
postproc.SRCS += video_reader.h video_reader.c
postproc.SRCS += vpx_ports/mem_ops.h
postproc.SRCS += vpx_ports/mem_ops_aligned.h
postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7
postproc.DESCRIPTION = Decoder postprocessor control
EXAMPLES-$(CONFIG_VP8_DECODER) += decode_to_md5.c
decode_to_md5.SRCS += md5_utils.h md5_utils.c decode_to_md5.SRCS += md5_utils.h md5_utils.c
decode_to_md5.SRCS += ivfdec.h ivfdec.c decode_to_md5.SRCS += ivfdec.h ivfdec.c
decode_to_md5.SRCS += tools_common.h tools_common.c decode_to_md5.SRCS += tools_common.h tools_common.c
@@ -135,41 +134,31 @@ decode_to_md5.SRCS += video_common.h
decode_to_md5.SRCS += video_reader.h video_reader.c decode_to_md5.SRCS += video_reader.h video_reader.c
decode_to_md5.SRCS += vpx_ports/mem_ops.h decode_to_md5.SRCS += vpx_ports/mem_ops.h
decode_to_md5.SRCS += vpx_ports/mem_ops_aligned.h decode_to_md5.SRCS += vpx_ports/mem_ops_aligned.h
decode_to_md5.SRCS += vpx_ports/msvc.h
decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42 decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42
decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum
EXAMPLES-$(CONFIG_ENCODERS) += simple_encoder.c EXAMPLES-$(CONFIG_VP8_ENCODER) += simple_encoder.c
simple_encoder.SRCS += ivfenc.h ivfenc.c simple_encoder.SRCS += ivfenc.h ivfenc.c
simple_encoder.SRCS += tools_common.h tools_common.c simple_encoder.SRCS += tools_common.h tools_common.c
simple_encoder.SRCS += video_common.h simple_encoder.SRCS += video_common.h
simple_encoder.SRCS += video_writer.h video_writer.c simple_encoder.SRCS += video_writer.h video_writer.c
simple_encoder.SRCS += vpx_ports/msvc.h
simple_encoder.GUID = 4607D299-8A71-4D2C-9B1D-071899B6FBFD simple_encoder.GUID = 4607D299-8A71-4D2C-9B1D-071899B6FBFD
simple_encoder.DESCRIPTION = Simplified encoder loop simple_encoder.DESCRIPTION = Simplified encoder loop
EXAMPLES-$(CONFIG_VP10_ENCODER) += lossless_encoder.c EXAMPLES-$(CONFIG_VP8_ENCODER) += twopass_encoder.c
lossless_encoder.SRCS += ivfenc.h ivfenc.c
lossless_encoder.SRCS += tools_common.h tools_common.c
lossless_encoder.SRCS += video_common.h
lossless_encoder.SRCS += video_writer.h video_writer.c
lossless_encoder.SRCS += vpx_ports/msvc.h
lossless_encoder.GUID = B63C7C88-5348-46DC-A5A6-CC151EF93366
lossless_encoder.DESCRIPTION = Simplified lossless encoder
EXAMPLES-$(CONFIG_ENCODERS) += twopass_encoder.c
twopass_encoder.SRCS += ivfenc.h ivfenc.c twopass_encoder.SRCS += ivfenc.h ivfenc.c
twopass_encoder.SRCS += tools_common.h tools_common.c twopass_encoder.SRCS += tools_common.h tools_common.c
twopass_encoder.SRCS += video_common.h twopass_encoder.SRCS += video_common.h
twopass_encoder.SRCS += video_writer.h video_writer.c twopass_encoder.SRCS += video_writer.h video_writer.c
twopass_encoder.SRCS += vpx_ports/msvc.h
twopass_encoder.GUID = 73494FA6-4AF9-4763-8FBB-265C92402FD8 twopass_encoder.GUID = 73494FA6-4AF9-4763-8FBB-265C92402FD8
twopass_encoder.DESCRIPTION = Two-pass encoder loop twopass_encoder.DESCRIPTION = Two-pass encoder loop
EXAMPLES-$(CONFIG_DECODERS) += decode_with_drops.c ifeq ($(CONFIG_DECODERS),yes)
EXAMPLES-$(CONFIG_VP8_ENCODER) += decode_with_drops.c
decode_with_drops.SRCS += ivfdec.h ivfdec.c decode_with_drops.SRCS += ivfdec.h ivfdec.c
decode_with_drops.SRCS += tools_common.h tools_common.c decode_with_drops.SRCS += tools_common.h tools_common.c
decode_with_drops.SRCS += video_common.h decode_with_drops.SRCS += video_common.h
decode_with_drops.SRCS += video_reader.h video_reader.c decode_with_drops.SRCS += video_reader.h video_reader.c
decode_with_drops.SRCS += vpx_ports/mem_ops.h decode_with_drops.SRCS += vpx_ports/mem_ops.h
decode_with_drops.SRCS += vpx_ports/mem_ops_aligned.h decode_with_drops.SRCS += vpx_ports/mem_ops_aligned.h
decode_with_drops.SRCS += vpx_ports/msvc.h endif
decode_with_drops.GUID = CE5C53C4-8DDA-438A-86ED-0DDD3CDB8D26 decode_with_drops.GUID = CE5C53C4-8DDA-438A-86ED-0DDD3CDB8D26
decode_with_drops.DESCRIPTION = Drops frames while decoding decode_with_drops.DESCRIPTION = Drops frames while decoding
EXAMPLES-$(CONFIG_ENCODERS) += set_maps.c EXAMPLES-$(CONFIG_ENCODERS) += set_maps.c
@@ -177,33 +166,37 @@ set_maps.SRCS += ivfenc.h ivfenc.c
set_maps.SRCS += tools_common.h tools_common.c set_maps.SRCS += tools_common.h tools_common.c
set_maps.SRCS += video_common.h set_maps.SRCS += video_common.h
set_maps.SRCS += video_writer.h video_writer.c set_maps.SRCS += video_writer.h video_writer.c
set_maps.SRCS += vpx_ports/msvc.h
set_maps.GUID = ECB2D24D-98B8-4015-A465-A4AF3DCC145F set_maps.GUID = ECB2D24D-98B8-4015-A465-A4AF3DCC145F
set_maps.DESCRIPTION = Set active and ROI maps set_maps.DESCRIPTION = Set active and ROI maps
EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c
vp8cx_set_ref.SRCS += ivfenc.h ivfenc.c
vp8cx_set_ref.SRCS += tools_common.h tools_common.c
vp8cx_set_ref.SRCS += video_common.h
vp8cx_set_ref.SRCS += video_writer.h video_writer.c
vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A
vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame
ifeq ($(CONFIG_VP10_ENCODER), yes) ifeq ($(CONFIG_MULTI_RES_ENCODING),yes)
ifeq ($(CONFIG_DECODERS),yes) ifeq ($(CONFIG_LIBYUV),yes)
EXAMPLES-yes += vpxcx_set_ref.c EXAMPLES-$(CONFIG_VP8_DECODER) += vp8_multi_resolution_encoder.c
vpxcx_set_ref.SRCS += ivfenc.h ivfenc.c vp8_multi_resolution_encoder.SRCS += $(LIBYUV_SRCS)
vpxcx_set_ref.SRCS += tools_common.h tools_common.c vp8_multi_resolution_encoder.GUID = 04f8738e-63c8-423b-90fa-7c2703a374de
vpxcx_set_ref.SRCS += video_common.h vp8_multi_resolution_encoder.DESCRIPTION = VP8 Multiple-resolution Encoding
vpxcx_set_ref.SRCS += video_writer.h video_writer.c
vpxcx_set_ref.GUID = 65D7F14A-2EE6-4293-B958-AB5107A03B55
vpxcx_set_ref.DESCRIPTION = VP10 set encoder reference frame
endif endif
endif endif
# Handle extra library flags depending on codec configuration # Handle extra library flags depending on codec configuration
# We should not link to math library (libm) on RVCT # We should not link to math library (libm) on RVCT
# when building for bare-metal targets # when building for bare-metal targets
ifeq ($(CONFIG_OS_SUPPORT), yes) ifeq ($(CONFIG_OS_SUPPORT), yes)
CODEC_EXTRA_LIBS-$(CONFIG_VP10) += m CODEC_EXTRA_LIBS-$(CONFIG_VP8) += m
CODEC_EXTRA_LIBS-$(CONFIG_VP9) += m
else else
ifeq ($(CONFIG_GCC), yes) ifeq ($(CONFIG_GCC), yes)
CODEC_EXTRA_LIBS-$(CONFIG_VP10) += m CODEC_EXTRA_LIBS-$(CONFIG_VP8) += m
CODEC_EXTRA_LIBS-$(CONFIG_VP9) += m
endif endif
endif endif
# #
@@ -216,16 +209,17 @@ endif
# from an installed tree or a version controlled tree. Determine # from an installed tree or a version controlled tree. Determine
# the proper paths. # the proper paths.
ifeq ($(HAVE_ALT_TREE_LAYOUT),yes) ifeq ($(HAVE_ALT_TREE_LAYOUT),yes)
LIB_PATH-yes := $(SRC_PATH_BARE)/../lib LIB_PATH := $(SRC_PATH_BARE)/../lib
INC_PATH-yes := $(SRC_PATH_BARE)/../include INC_PATH := $(SRC_PATH_BARE)/../include
else else
LIB_PATH-yes += $(if $(BUILD_PFX),$(BUILD_PFX),.) LIB_PATH-yes += $(if $(BUILD_PFX),$(BUILD_PFX),.)
INC_PATH-$(CONFIG_VP10_DECODER) += $(SRC_PATH_BARE)/vp10 INC_PATH-$(CONFIG_VP8_DECODER) += $(SRC_PATH_BARE)/vp8
INC_PATH-$(CONFIG_VP10_ENCODER) += $(SRC_PATH_BARE)/vp10 INC_PATH-$(CONFIG_VP8_ENCODER) += $(SRC_PATH_BARE)/vp8
INC_PATH-$(CONFIG_VP9_DECODER) += $(SRC_PATH_BARE)/vp9
INC_PATH-$(CONFIG_VP9_ENCODER) += $(SRC_PATH_BARE)/vp9
LIB_PATH := $(call enabled,LIB_PATH)
INC_PATH := $(call enabled,INC_PATH)
endif endif
INC_PATH-$(CONFIG_LIBYUV) += $(SRC_PATH_BARE)/third_party/libyuv/include
LIB_PATH := $(call enabled,LIB_PATH)
INC_PATH := $(call enabled,INC_PATH)
INTERNAL_CFLAGS = $(addprefix -I,$(INC_PATH)) INTERNAL_CFLAGS = $(addprefix -I,$(INC_PATH))
INTERNAL_LDFLAGS += $(addprefix -L,$(LIB_PATH)) INTERNAL_LDFLAGS += $(addprefix -L,$(LIB_PATH))
@@ -245,6 +239,14 @@ CODEC_EXTRA_LIBS=$(sort $(call enabled,CODEC_EXTRA_LIBS))
$(foreach ex,$(ALL_EXAMPLES),$(eval $(notdir $(ex:.c=)).SRCS += $(ex) examples.mk)) $(foreach ex,$(ALL_EXAMPLES),$(eval $(notdir $(ex:.c=)).SRCS += $(ex) examples.mk))
# If this is a universal (fat) binary, then all the subarchitectures have
# already been built and our job is to stitch them together. The
# BUILD_OBJS variable indicates whether we should be building
# (compiling, linking) the library. The LIPO_OBJS variable indicates
# that we're stitching.
$(eval $(if $(filter universal%,$(TOOLCHAIN)),LIPO_OBJS,BUILD_OBJS):=yes)
# Create build/install dependencies for all examples. The common case # Create build/install dependencies for all examples. The common case
# is handled here. The MSVS case is handled below. # is handled here. The MSVS case is handled below.
NOT_MSVS = $(if $(CONFIG_MSVS),,yes) NOT_MSVS = $(if $(CONFIG_MSVS),,yes)
@@ -252,28 +254,24 @@ DIST-BINS-$(NOT_MSVS) += $(addprefix bin/,$(ALL_EXAMPLES:.c=$(EXE_SFX)))
INSTALL-BINS-$(NOT_MSVS) += $(addprefix bin/,$(UTILS:.c=$(EXE_SFX))) INSTALL-BINS-$(NOT_MSVS) += $(addprefix bin/,$(UTILS:.c=$(EXE_SFX)))
DIST-SRCS-yes += $(ALL_SRCS) DIST-SRCS-yes += $(ALL_SRCS)
INSTALL-SRCS-yes += $(UTIL_SRCS) INSTALL-SRCS-yes += $(UTIL_SRCS)
OBJS-$(NOT_MSVS) += $(call objs,$(ALL_SRCS)) OBJS-$(NOT_MSVS) += $(if $(BUILD_OBJS),$(call objs,$(ALL_SRCS)))
BINS-$(NOT_MSVS) += $(addprefix $(BUILD_PFX),$(ALL_EXAMPLES:.c=$(EXE_SFX))) BINS-$(NOT_MSVS) += $(addprefix $(BUILD_PFX),$(ALL_EXAMPLES:.c=$(EXE_SFX)))
# Instantiate linker template for all examples. # Instantiate linker template for all examples.
CODEC_LIB=$(if $(CONFIG_DEBUG_LIBS),vpx_g,vpx) CODEC_LIB=$(if $(CONFIG_DEBUG_LIBS),vpx_g,vpx)
ifneq ($(filter darwin%,$(TGT_OS)),) SHARED_LIB_SUF=$(if $(filter darwin%,$(TGT_OS)),.dylib,.so)
SHARED_LIB_SUF=.dylib
else
ifneq ($(filter os2%,$(TGT_OS)),)
SHARED_LIB_SUF=_dll.a
else
SHARED_LIB_SUF=.so
endif
endif
CODEC_LIB_SUF=$(if $(CONFIG_SHARED),$(SHARED_LIB_SUF),.a) CODEC_LIB_SUF=$(if $(CONFIG_SHARED),$(SHARED_LIB_SUF),.a)
$(foreach bin,$(BINS-yes),\ $(foreach bin,$(BINS-yes),\
$(eval $(bin):$(LIB_PATH)/lib$(CODEC_LIB)$(CODEC_LIB_SUF))\ $(if $(BUILD_OBJS),$(eval $(bin):\
$(eval $(call linker_template,$(bin),\ $(LIB_PATH)/lib$(CODEC_LIB)$(CODEC_LIB_SUF)))\
$(if $(BUILD_OBJS),$(eval $(call linker_template,$(bin),\
$(call objs,$($(notdir $(bin:$(EXE_SFX)=)).SRCS)) \ $(call objs,$($(notdir $(bin:$(EXE_SFX)=)).SRCS)) \
-l$(CODEC_LIB) $(addprefix -l,$(CODEC_EXTRA_LIBS))\ -l$(CODEC_LIB) $(addprefix -l,$(CODEC_EXTRA_LIBS))\
))) )))\
$(if $(LIPO_OBJS),$(eval $(call lipo_bin_template,$(bin))))\
)
# The following pairs define a mapping of locations in the distribution # The following pairs define a mapping of locations in the distribution
# tree to locations in the source/build trees. # tree to locations in the source/build trees.
@@ -301,8 +299,8 @@ endif
# the makefiles). We may want to revisit this. # the makefiles). We may want to revisit this.
define vcproj_template define vcproj_template
$(1): $($(1:.$(VCPROJ_SFX)=).SRCS) vpx.$(VCPROJ_SFX) $(1): $($(1:.$(VCPROJ_SFX)=).SRCS) vpx.$(VCPROJ_SFX)
$(if $(quiet),@echo " [vcproj] $$@") @echo " [vcproj] $$@"
$(qexec)$$(GEN_VCPROJ)\ $$(GEN_VCPROJ)\
--exe\ --exe\
--target=$$(TOOLCHAIN)\ --target=$$(TOOLCHAIN)\
--name=$$(@:.$(VCPROJ_SFX)=)\ --name=$$(@:.$(VCPROJ_SFX)=)\
@@ -325,7 +323,6 @@ $(foreach proj,$(call enabled,PROJECTS),\
# #
%.dox: %.c %.dox: %.c
@echo " [DOXY] $@" @echo " [DOXY] $@"
@mkdir -p $(dir $@)
@echo "/*!\page example_$(@F:.dox=) $(@F:.dox=)" > $@ @echo "/*!\page example_$(@F:.dox=) $(@F:.dox=)" > $@
@echo " \includelineno $(<F)" >> $@ @echo " \includelineno $(<F)" >> $@
@echo "*/" >> $@ @echo "*/" >> $@

View File

@@ -33,12 +33,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8dx.h" #include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h" #include "vpx/vpx_decoder.h"
#include "../md5_utils.h" #include "./md5_utils.h"
#include "../tools_common.h" #include "./tools_common.h"
#include "../video_reader.h" #include "./video_reader.h"
#include "./vpx_config.h" #include "./vpx_config.h"
static void get_image_md5(const vpx_image_t *img, unsigned char digest[16]) { static void get_image_md5(const vpx_image_t *img, unsigned char digest[16]) {
@@ -71,7 +73,7 @@ static void print_md5(FILE *stream, unsigned char digest[16]) {
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { void usage_exit() {
fprintf(stderr, "Usage: %s <infile> <outfile>\n", exec_name); fprintf(stderr, "Usage: %s <infile> <outfile>\n", exec_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -102,9 +104,9 @@ int main(int argc, char **argv) {
if (!decoder) if (!decoder)
die("Unknown input codec."); die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(decoder->interface()));
if (vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0)) if (vpx_codec_dec_init(&codec, decoder->interface(), NULL, 0))
die_codec(&codec, "Failed to initialize decoder"); die_codec(&codec, "Failed to initialize decoder");
while (vpx_video_reader_read_frame(reader)) { while (vpx_video_reader_read_frame(reader)) {

View File

@@ -56,16 +56,18 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8dx.h" #include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h" #include "vpx/vpx_decoder.h"
#include "../tools_common.h" #include "./tools_common.h"
#include "../video_reader.h" #include "./video_reader.h"
#include "./vpx_config.h" #include "./vpx_config.h"
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { void usage_exit() {
fprintf(stderr, "Usage: %s <infile> <outfile> <N-M|N/M>\n", exec_name); fprintf(stderr, "Usage: %s <infile> <outfile> <N-M|N/M>\n", exec_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -106,9 +108,9 @@ int main(int argc, char **argv) {
if (!decoder) if (!decoder)
die("Unknown input codec."); die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(decoder->interface()));
if (vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0)) if (vpx_codec_dec_init(&codec, decoder->interface(), NULL, 0))
die_codec(&codec, "Failed to initialize decoder."); die_codec(&codec, "Failed to initialize decoder.");
while (vpx_video_reader_read_frame(reader)) { while (vpx_video_reader_read_frame(reader)) {

View File

@@ -1,144 +0,0 @@
/*
* Copyright (c) 2014 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
#include "../tools_common.h"
#include "../video_writer.h"
static const char *exec_name;
void usage_exit(void) {
fprintf(stderr, "lossless_encoder: Example demonstrating lossless "
"encoding feature. Supports raw input only.\n");
fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile>\n", exec_name);
exit(EXIT_FAILURE);
}
static int encode_frame(vpx_codec_ctx_t *codec,
vpx_image_t *img,
int frame_index,
int flags,
VpxVideoWriter *writer) {
int got_pkts = 0;
vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt = NULL;
const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1,
flags, VPX_DL_GOOD_QUALITY);
if (res != VPX_CODEC_OK)
die_codec(codec, "Failed to encode frame");
while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) {
got_pkts = 1;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
if (!vpx_video_writer_write_frame(writer,
pkt->data.frame.buf,
pkt->data.frame.sz,
pkt->data.frame.pts)) {
die_codec(codec, "Failed to write compressed frame");
}
printf(keyframe ? "K" : ".");
fflush(stdout);
}
}
return got_pkts;
}
int main(int argc, char **argv) {
FILE *infile = NULL;
vpx_codec_ctx_t codec;
vpx_codec_enc_cfg_t cfg;
int frame_count = 0;
vpx_image_t raw;
vpx_codec_err_t res;
VpxVideoInfo info = {0};
VpxVideoWriter *writer = NULL;
const VpxInterface *encoder = NULL;
const int fps = 30;
exec_name = argv[0];
if (argc < 5)
die("Invalid number of arguments");
encoder = get_vpx_encoder_by_name("vp9");
if (!encoder)
die("Unsupported codec.");
info.codec_fourcc = encoder->fourcc;
info.frame_width = strtol(argv[1], NULL, 0);
info.frame_height = strtol(argv[2], NULL, 0);
info.time_base.numerator = 1;
info.time_base.denominator = fps;
if (info.frame_width <= 0 ||
info.frame_height <= 0 ||
(info.frame_width % 2) != 0 ||
(info.frame_height % 2) != 0) {
die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
}
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
info.frame_height, 1)) {
die("Failed to allocate image.");
}
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
if (res)
die_codec(&codec, "Failed to get default codec config.");
cfg.g_w = info.frame_width;
cfg.g_h = info.frame_height;
cfg.g_timebase.num = info.time_base.numerator;
cfg.g_timebase.den = info.time_base.denominator;
writer = vpx_video_writer_open(argv[4], kContainerIVF, &info);
if (!writer)
die("Failed to open %s for writing.", argv[4]);
if (!(infile = fopen(argv[3], "rb")))
die("Failed to open %s for reading.", argv[3]);
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
die_codec(&codec, "Failed to initialize encoder");
if (vpx_codec_control_(&codec, VP9E_SET_LOSSLESS, 1))
die_codec(&codec, "Failed to use lossless mode");
// Encode frames.
while (vpx_img_read(&raw, infile)) {
encode_frame(&codec, &raw, frame_count++, 0, writer);
}
// Flush encoder.
while (encode_frame(&codec, NULL, -1, 0, writer)) {}
printf("\n");
fclose(infile);
printf("Processed %d frames.\n", frame_count);
vpx_img_free(&raw);
if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
vpx_video_writer_close(writer);
return EXIT_SUCCESS;
}

140
examples/postproc.c Normal file
View File

@@ -0,0 +1,140 @@
/*
* 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.
*/
// Postprocessing Decoder
// ======================
//
// This example adds postprocessing to the simple decoder loop.
//
// Initializing Postprocessing
// ---------------------------
// You must inform the codec that you might request postprocessing at
// initialization time. This is done by passing the VPX_CODEC_USE_POSTPROC
// flag to `vpx_codec_dec_init`. If the codec does not support
// postprocessing, this call will return VPX_CODEC_INCAPABLE. For
// demonstration purposes, we also fall back to default initialization if
// the codec does not provide support.
//
// Using Adaptive Postprocessing
// -----------------------------
// VP6 provides "adaptive postprocessing." It will automatically select the
// best postprocessing filter on a frame by frame basis based on the amount
// of time remaining before the user's specified deadline expires. The
// special value 0 indicates that the codec should take as long as
// necessary to provide the best quality frame. This example gives the
// codec 15ms (15000us) to return a frame. Remember that this is a soft
// deadline, and the codec may exceed it doing its regular processing. In
// these cases, no additional postprocessing will be done.
//
// Codec Specific Postprocessing Controls
// --------------------------------------
// Some codecs provide fine grained controls over their built-in
// postprocessors. VP8 is one example. The following sample code toggles
// postprocessing on and off every 15 frames.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
#include "./tools_common.h"
#include "./video_reader.h"
#include "./vpx_config.h"
static const char *exec_name;
void usage_exit() {
fprintf(stderr, "Usage: %s <infile> <outfile>\n", exec_name);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv) {
int frame_cnt = 0;
FILE *outfile = NULL;
vpx_codec_ctx_t codec;
vpx_codec_err_t res;
VpxVideoReader *reader = NULL;
const VpxInterface *decoder = NULL;
const VpxVideoInfo *info = NULL;
exec_name = argv[0];
if (argc != 3)
die("Invalid number of arguments.");
reader = vpx_video_reader_open(argv[1]);
if (!reader)
die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb")))
die("Failed to open %s for writing", argv[2]);
info = vpx_video_reader_get_info(reader);
decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc);
if (!decoder)
die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(decoder->interface()));
res = vpx_codec_dec_init(&codec, decoder->interface(), NULL,
VPX_CODEC_USE_POSTPROC);
if (res == VPX_CODEC_INCAPABLE)
die_codec(&codec, "Postproc not supported by this decoder.");
if (res)
die_codec(&codec, "Failed to initialize decoder.");
while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL;
size_t frame_size = 0;
const unsigned char *frame = vpx_video_reader_get_frame(reader,
&frame_size);
++frame_cnt;
if (frame_cnt % 30 == 1) {
vp8_postproc_cfg_t pp = {0, 0, 0};
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
die_codec(&codec, "Failed to turn off postproc.");
} else if (frame_cnt % 30 == 16) {
vp8_postproc_cfg_t pp = {VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE,
4, 0};
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
die_codec(&codec, "Failed to turn on postproc.");
};
// Decode the frame with 15ms deadline
if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 15000))
die_codec(&codec, "Failed to decode frame");
while ((img = vpx_codec_get_frame(&codec, &iter)) != NULL) {
vpx_img_write(img, outfile);
}
}
printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec");
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
info->frame_width, info->frame_height, argv[2]);
vpx_video_reader_close(reader);
fclose(outfile);
return EXIT_SUCCESS;
}

View File

@@ -15,23 +15,15 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "../tools_common.h" #include "./vp9/encoder/vp9_resize.h"
#include "../vp9/encoder/vp9_resize.h"
static const char *exec_name = NULL; static void usage(char *progname) {
static void usage() {
printf("Usage:\n"); printf("Usage:\n");
printf("%s <input_yuv> <width>x<height> <target_width>x<target_height> ", printf("%s <input_yuv> <width>x<height> <target_width>x<target_height> ",
exec_name); progname);
printf("<output_yuv> [<frames>]\n"); printf("<output_yuv> [<frames>]\n");
} }
void usage_exit(void) {
usage();
exit(EXIT_FAILURE);
}
static int parse_dim(char *v, int *width, int *height) { static int parse_dim(char *v, int *width, int *height) {
char *x = strchr(v, 'x'); char *x = strchr(v, 'x');
if (x == NULL) if (x == NULL)
@@ -55,11 +47,9 @@ int main(int argc, char *argv[]) {
int f, frames; int f, frames;
int width, height, target_width, target_height; int width, height, target_width, target_height;
exec_name = argv[0];
if (argc < 5) { if (argc < 5) {
printf("Incorrect parameters:\n"); printf("Incorrect parameters:\n");
usage(); usage(argv[0]);
return 1; return 1;
} }
@@ -67,25 +57,25 @@ int main(int argc, char *argv[]) {
fout = argv[4]; fout = argv[4];
if (!parse_dim(argv[2], &width, &height)) { if (!parse_dim(argv[2], &width, &height)) {
printf("Incorrect parameters: %s\n", argv[2]); printf("Incorrect parameters: %s\n", argv[2]);
usage(); usage(argv[0]);
return 1; return 1;
} }
if (!parse_dim(argv[3], &target_width, &target_height)) { if (!parse_dim(argv[3], &target_width, &target_height)) {
printf("Incorrect parameters: %s\n", argv[3]); printf("Incorrect parameters: %s\n", argv[3]);
usage(); usage(argv[0]);
return 1; return 1;
} }
fpin = fopen(fin, "rb"); fpin = fopen(fin, "rb");
if (fpin == NULL) { if (fpin == NULL) {
printf("Can't open file %s to read\n", fin); printf("Can't open file %s to read\n", fin);
usage(); usage(argv[0]);
return 1; return 1;
} }
fpout = fopen(fout, "wb"); fpout = fopen(fout, "wb");
if (fpout == NULL) { if (fpout == NULL) {
printf("Can't open file %s to write\n", fout); printf("Can't open file %s to write\n", fout);
usage(); usage(argv[0]);
return 1; return 1;
} }
if (argc >= 6) if (argc >= 6)

View File

@@ -42,20 +42,20 @@
// Use the `simple_decoder` example to decode this sample, and observe // Use the `simple_decoder` example to decode this sample, and observe
// the change in the image at frames 22, 33, and 44. // the change in the image at frames 22, 33, and 44.
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "../tools_common.h" #include "./tools_common.h"
#include "../video_writer.h" #include "./video_writer.h"
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { void usage_exit() {
fprintf(stderr, "Usage: %s <codec> <width> <height> <infile> <outfile>\n", fprintf(stderr, "Usage: %s <codec> <width> <height> <infile> <outfile>\n",
exec_name); exec_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -125,11 +125,10 @@ static void unset_active_map(const vpx_codec_enc_cfg_t *cfg,
die_codec(codec, "Failed to set active map"); die_codec(codec, "Failed to set active map");
} }
static int encode_frame(vpx_codec_ctx_t *codec, static void encode_frame(vpx_codec_ctx_t *codec,
vpx_image_t *img, vpx_image_t *img,
int frame_index, int frame_index,
VpxVideoWriter *writer) { VpxVideoWriter *writer) {
int got_pkts = 0;
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt = NULL; const vpx_codec_cx_pkt_t *pkt = NULL;
const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, 0, const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, 0,
@@ -138,8 +137,6 @@ static int encode_frame(vpx_codec_ctx_t *codec,
die_codec(codec, "Failed to encode frame"); die_codec(codec, "Failed to encode frame");
while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) { while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) {
got_pkts = 1;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
if (!vpx_video_writer_write_frame(writer, if (!vpx_video_writer_write_frame(writer,
@@ -153,8 +150,6 @@ static int encode_frame(vpx_codec_ctx_t *codec,
fflush(stdout); fflush(stdout);
} }
} }
return got_pkts;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
@@ -177,10 +172,9 @@ int main(int argc, char **argv) {
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
encoder = get_vpx_encoder_by_name(argv[1]); encoder = get_vpx_encoder_by_name(argv[1]);
if (encoder == NULL) { if (!encoder)
die("Unsupported codec."); die("Unsupported codec.");
}
assert(encoder != NULL);
info.codec_fourcc = encoder->fourcc; info.codec_fourcc = encoder->fourcc;
info.frame_width = strtol(argv[2], NULL, 0); info.frame_width = strtol(argv[2], NULL, 0);
info.frame_height = strtol(argv[3], NULL, 0); info.frame_height = strtol(argv[3], NULL, 0);
@@ -199,9 +193,9 @@ int main(int argc, char **argv) {
die("Failed to allocate image."); die("Failed to allocate image.");
} }
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(encoder->interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); res = vpx_codec_enc_config_default(encoder->interface(), &cfg, 0);
if (res) if (res)
die_codec(&codec, "Failed to get default codec config."); die_codec(&codec, "Failed to get default codec config.");
@@ -220,10 +214,9 @@ int main(int argc, char **argv) {
if (!(infile = fopen(argv[4], "rb"))) if (!(infile = fopen(argv[4], "rb")))
die("Failed to open %s for reading.", argv[4]); die("Failed to open %s for reading.", argv[4]);
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0))
die_codec(&codec, "Failed to initialize encoder"); die_codec(&codec, "Failed to initialize encoder");
// Encode frames.
while (vpx_img_read(&raw, infile)) { while (vpx_img_read(&raw, infile)) {
++frame_count; ++frame_count;
@@ -237,10 +230,7 @@ int main(int argc, char **argv) {
encode_frame(&codec, &raw, frame_count, writer); encode_frame(&codec, &raw, frame_count, writer);
} }
encode_frame(&codec, NULL, -1, writer);
// Flush encoder.
while (encode_frame(&codec, NULL, -1, writer)) {}
printf("\n"); printf("\n");
fclose(infile); fclose(infile);
printf("Processed %d frames.\n", frame_count); printf("Processed %d frames.\n", frame_count);

View File

@@ -29,29 +29,30 @@
// ----------------- // -----------------
// For decoders, you only have to include `vpx_decoder.h` and then any // For decoders, you only have to include `vpx_decoder.h` and then any
// header files for the specific codecs you use. In this case, we're using // header files for the specific codecs you use. In this case, we're using
// vp8. // vp8. The `VPX_CODEC_DISABLE_COMPAT` macro can be defined to ensure
// strict compliance with the latest SDK by disabling some backwards
// compatibility features. Defining this macro is encouraged.
// //
// Initializing The Codec // Initializing The Codec
// ---------------------- // ----------------------
// The libvpx decoder is initialized by the call to vpx_codec_dec_init(). // The decoder is initialized by the following code. This is an example for
// Determining the codec interface to use is handled by VpxVideoReader and the // the VP8 decoder, but the code is analogous for all algorithms. Replace
// functions prefixed with vpx_video_reader_. Discussion of those functions is // `vpx_codec_vp8_dx()` with a pointer to the interface exposed by the
// beyond the scope of this example, but the main gist is to open the input file // algorithm you want to use. The `cfg` argument is left as NULL in this
// and parse just enough of it to determine if it's a VPx file and which VPx // example, because we want the algorithm to determine the stream
// codec is contained within the file. // configuration (width/height) and allocate memory automatically. This
// Note the NULL pointer passed to vpx_codec_dec_init(). We do that in this // parameter is generally only used if you need to preallocate memory,
// example because we want the algorithm to determine the stream configuration // particularly in External Memory Allocation mode.
// (width/height) and allocate memory automatically.
// //
// Decoding A Frame // Decoding A Frame
// ---------------- // ----------------
// Once the frame has been read into memory, it is decoded using the // Once the frame has been read into memory, it is decoded using the
// `vpx_codec_decode` function. The call takes a pointer to the data // `vpx_codec_decode` function. The call takes a pointer to the data
// (`frame`) and the length of the data (`frame_size`). No application data // (`frame`) and the length of the data (`frame_sz`). No application data
// is associated with the frame in this example, so the `user_priv` // is associated with the frame in this example, so the `user_priv`
// parameter is NULL. The `deadline` parameter is left at zero for this // parameter is NULL. The `deadline` parameter is left at zero for this
// example. This parameter is generally only used when doing adaptive post // example. This parameter is generally only used when doing adaptive
// processing. // postprocessing.
// //
// Codecs may produce a variable number of output frames for every call to // Codecs may produce a variable number of output frames for every call to
// `vpx_codec_decode`. These frames are retrieved by the // `vpx_codec_decode`. These frames are retrieved by the
@@ -73,22 +74,25 @@
// -------------- // --------------
// This example does not special case any error return codes. If there was // This example does not special case any error return codes. If there was
// an error, a descriptive message is printed and the program exits. With // an error, a descriptive message is printed and the program exits. With
// few exceptions, vpx_codec functions return an enumerated error status, // few exeptions, vpx_codec functions return an enumerated error status,
// with the value `0` indicating success. // with the value `0` indicating success.
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h" #include "vpx/vpx_decoder.h"
#include "../tools_common.h" #include "./tools_common.h"
#include "../video_reader.h" #include "./video_reader.h"
#include "./vpx_config.h" #include "./vpx_config.h"
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { void usage_exit() {
fprintf(stderr, "Usage: %s <infile> <outfile>\n", exec_name); fprintf(stderr, "Usage: %s <infile> <outfile>\n", exec_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -119,9 +123,9 @@ int main(int argc, char **argv) {
if (!decoder) if (!decoder)
die("Unknown input codec."); die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(decoder->interface()));
if (vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0)) if (vpx_codec_dec_init(&codec, decoder->interface(), NULL, 0))
die_codec(&codec, "Failed to initialize decoder."); die_codec(&codec, "Failed to initialize decoder.");
while (vpx_video_reader_read_frame(reader)) { while (vpx_video_reader_read_frame(reader)) {

View File

@@ -28,7 +28,9 @@
// ----------------- // -----------------
// For encoders, you only have to include `vpx_encoder.h` and then any // For encoders, you only have to include `vpx_encoder.h` and then any
// header files for the specific codecs you use. In this case, we're using // header files for the specific codecs you use. In this case, we're using
// vp8. // vp8. The `VPX_CODEC_DISABLE_COMPAT` macro can be defined to ensure
// strict compliance with the latest SDK by disabling some backwards
// compatibility features. Defining this macro is encouraged.
// //
// Getting The Default Configuration // Getting The Default Configuration
// --------------------------------- // ---------------------------------
@@ -99,28 +101,28 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "../tools_common.h" #include "./tools_common.h"
#include "../video_writer.h" #include "./video_writer.h"
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { void usage_exit() {
fprintf(stderr, fprintf(stderr,
"Usage: %s <codec> <width> <height> <infile> <outfile> " "Usage: %s <codec> <width> <height> <infile> <outfile> "
"<keyframe-interval> <error-resilient> <frames to encode>\n" "<keyframe-interval> [<error-resilient>]\nSee comments in "
"See comments in simple_encoder.c for more information.\n", "simple_encoder.c for more information.\n",
exec_name); exec_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
static int encode_frame(vpx_codec_ctx_t *codec, static void encode_frame(vpx_codec_ctx_t *codec,
vpx_image_t *img, vpx_image_t *img,
int frame_index, int frame_index,
int flags, int flags,
VpxVideoWriter *writer) { VpxVideoWriter *writer) {
int got_pkts = 0;
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt = NULL; const vpx_codec_cx_pkt_t *pkt = NULL;
const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1,
@@ -129,8 +131,6 @@ static int encode_frame(vpx_codec_ctx_t *codec,
die_codec(codec, "Failed to encode frame"); die_codec(codec, "Failed to encode frame");
while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) { while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) {
got_pkts = 1;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
if (!vpx_video_writer_write_frame(writer, if (!vpx_video_writer_write_frame(writer,
@@ -139,15 +139,13 @@ static int encode_frame(vpx_codec_ctx_t *codec,
pkt->data.frame.pts)) { pkt->data.frame.pts)) {
die_codec(codec, "Failed to write compressed frame"); die_codec(codec, "Failed to write compressed frame");
} }
printf(keyframe ? "K" : "."); printf(keyframe ? "K" : ".");
fflush(stdout); fflush(stdout);
} }
} }
return got_pkts;
} }
// TODO(tomfinegan): Improve command line parsing and add args for bitrate/fps.
int main(int argc, char **argv) { int main(int argc, char **argv) {
FILE *infile = NULL; FILE *infile = NULL;
vpx_codec_ctx_t codec; vpx_codec_ctx_t codec;
@@ -158,11 +156,12 @@ int main(int argc, char **argv) {
VpxVideoInfo info = {0}; VpxVideoInfo info = {0};
VpxVideoWriter *writer = NULL; VpxVideoWriter *writer = NULL;
const VpxInterface *encoder = NULL; const VpxInterface *encoder = NULL;
const int fps = 30; const int fps = 30; // TODO(dkovalev) add command line argument
const int bitrate = 200; const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument
int keyframe_interval = 0; int keyframe_interval = 0;
int max_frames = 0;
int frames_encoded = 0; // TODO(dkovalev): Add some simple command line parsing code to make the
// command line more flexible.
const char *codec_arg = NULL; const char *codec_arg = NULL;
const char *width_arg = NULL; const char *width_arg = NULL;
const char *height_arg = NULL; const char *height_arg = NULL;
@@ -172,7 +171,7 @@ int main(int argc, char **argv) {
exec_name = argv[0]; exec_name = argv[0];
if (argc != 9) if (argc < 7)
die("Invalid number of arguments"); die("Invalid number of arguments");
codec_arg = argv[1]; codec_arg = argv[1];
@@ -181,7 +180,6 @@ int main(int argc, char **argv) {
infile_arg = argv[4]; infile_arg = argv[4];
outfile_arg = argv[5]; outfile_arg = argv[5];
keyframe_interval_arg = argv[6]; keyframe_interval_arg = argv[6];
max_frames = strtol(argv[8], NULL, 0);
encoder = get_vpx_encoder_by_name(codec_arg); encoder = get_vpx_encoder_by_name(codec_arg);
if (!encoder) if (!encoder)
@@ -209,9 +207,9 @@ int main(int argc, char **argv) {
if (keyframe_interval < 0) if (keyframe_interval < 0)
die("Invalid keyframe interval value."); die("Invalid keyframe interval value.");
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(encoder->interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); res = vpx_codec_enc_config_default(encoder->interface(), &cfg, 0);
if (res) if (res)
die_codec(&codec, "Failed to get default codec config."); die_codec(&codec, "Failed to get default codec config.");
@@ -220,7 +218,7 @@ int main(int argc, char **argv) {
cfg.g_timebase.num = info.time_base.numerator; cfg.g_timebase.num = info.time_base.numerator;
cfg.g_timebase.den = info.time_base.denominator; cfg.g_timebase.den = info.time_base.denominator;
cfg.rc_target_bitrate = bitrate; cfg.rc_target_bitrate = bitrate;
cfg.g_error_resilient = strtol(argv[7], NULL, 0); cfg.g_error_resilient = argc > 7 ? strtol(argv[7], NULL, 0) : 0;
writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info); writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info);
if (!writer) if (!writer)
@@ -229,22 +227,16 @@ int main(int argc, char **argv) {
if (!(infile = fopen(infile_arg, "rb"))) if (!(infile = fopen(infile_arg, "rb")))
die("Failed to open %s for reading.", infile_arg); die("Failed to open %s for reading.", infile_arg);
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0))
die_codec(&codec, "Failed to initialize encoder"); die_codec(&codec, "Failed to initialize encoder");
// Encode frames.
while (vpx_img_read(&raw, infile)) { while (vpx_img_read(&raw, infile)) {
int flags = 0; int flags = 0;
if (keyframe_interval > 0 && frame_count % keyframe_interval == 0) if (keyframe_interval > 0 && frame_count % keyframe_interval == 0)
flags |= VPX_EFLAG_FORCE_KF; flags |= VPX_EFLAG_FORCE_KF;
encode_frame(&codec, &raw, frame_count++, flags, writer); encode_frame(&codec, &raw, frame_count++, flags, writer);
frames_encoded++;
if (max_frames > 0 && frames_encoded >= max_frames)
break;
} }
encode_frame(&codec, NULL, -1, 0, writer); // flush the encoder
// Flush encoder.
while (encode_frame(&codec, NULL, -1, 0, writer)) {};
printf("\n"); printf("\n");
fclose(infile); fclose(infile);

View File

@@ -28,8 +28,9 @@
// Encoding A Frame // Encoding A Frame
// ---------------- // ----------------
// Encoding a frame in two pass mode is identical to the simple encoder // Encoding a frame in two pass mode is identical to the simple encoder
// example. To increase the quality while sacrificing encoding speed, // example, except the deadline is set to VPX_DL_BEST_QUALITY to get the
// VPX_DL_BEST_QUALITY can be used in place of VPX_DL_GOOD_QUALITY. // best quality possible. VPX_DL_GOOD_QUALITY could also be used.
//
// //
// Processing Statistics Packets // Processing Statistics Packets
// ----------------------------- // -----------------------------
@@ -51,29 +52,27 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "../tools_common.h" #include "./tools_common.h"
#include "../video_writer.h" #include "./video_writer.h"
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { void usage_exit() {
fprintf(stderr, fprintf(stderr, "Usage: %s <codec> <width> <height> <infile> <outfile>\n",
"Usage: %s <codec> <width> <height> <infile> <outfile> "
"<frame limit>\n",
exec_name); exec_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
static int get_frame_stats(vpx_codec_ctx_t *ctx, static void get_frame_stats(vpx_codec_ctx_t *ctx,
const vpx_image_t *img, const vpx_image_t *img,
vpx_codec_pts_t pts, vpx_codec_pts_t pts,
unsigned int duration, unsigned int duration,
vpx_enc_frame_flags_t flags, vpx_enc_frame_flags_t flags,
unsigned int deadline, unsigned int deadline,
vpx_fixed_buf_t *stats) { vpx_fixed_buf_t *stats) {
int got_pkts = 0;
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt = NULL; const vpx_codec_cx_pkt_t *pkt = NULL;
const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags, const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
@@ -82,8 +81,6 @@ static int get_frame_stats(vpx_codec_ctx_t *ctx,
die_codec(ctx, "Failed to get frame stats."); die_codec(ctx, "Failed to get frame stats.");
while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) { while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
got_pkts = 1;
if (pkt->kind == VPX_CODEC_STATS_PKT) { if (pkt->kind == VPX_CODEC_STATS_PKT) {
const uint8_t *const pkt_buf = pkt->data.twopass_stats.buf; const uint8_t *const pkt_buf = pkt->data.twopass_stats.buf;
const size_t pkt_size = pkt->data.twopass_stats.sz; const size_t pkt_size = pkt->data.twopass_stats.sz;
@@ -92,18 +89,15 @@ static int get_frame_stats(vpx_codec_ctx_t *ctx,
stats->sz += pkt_size; stats->sz += pkt_size;
} }
} }
return got_pkts;
} }
static int encode_frame(vpx_codec_ctx_t *ctx, static void encode_frame(vpx_codec_ctx_t *ctx,
const vpx_image_t *img, const vpx_image_t *img,
vpx_codec_pts_t pts, vpx_codec_pts_t pts,
unsigned int duration, unsigned int duration,
vpx_enc_frame_flags_t flags, vpx_enc_frame_flags_t flags,
unsigned int deadline, unsigned int deadline,
VpxVideoWriter *writer) { VpxVideoWriter *writer) {
int got_pkts = 0;
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt = NULL; const vpx_codec_cx_pkt_t *pkt = NULL;
const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags, const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
@@ -112,7 +106,6 @@ static int encode_frame(vpx_codec_ctx_t *ctx,
die_codec(ctx, "Failed to encode frame."); die_codec(ctx, "Failed to encode frame.");
while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) { while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
got_pkts = 1;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
@@ -124,97 +117,19 @@ static int encode_frame(vpx_codec_ctx_t *ctx,
fflush(stdout); fflush(stdout);
} }
} }
return got_pkts;
}
static vpx_fixed_buf_t pass0(vpx_image_t *raw,
FILE *infile,
const VpxInterface *encoder,
const vpx_codec_enc_cfg_t *cfg,
int max_frames) {
vpx_codec_ctx_t codec;
int frame_count = 0;
vpx_fixed_buf_t stats = {NULL, 0};
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0))
die_codec(&codec, "Failed to initialize encoder");
// Calculate frame statistics.
while (vpx_img_read(raw, infile)) {
++frame_count;
get_frame_stats(&codec, raw, frame_count, 1, 0, VPX_DL_GOOD_QUALITY,
&stats);
if (max_frames > 0 && frame_count >= max_frames)
break;
}
// Flush encoder.
while (get_frame_stats(&codec, NULL, frame_count, 1, 0,
VPX_DL_GOOD_QUALITY, &stats)) {}
printf("Pass 0 complete. Processed %d frames.\n", frame_count);
if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
return stats;
}
static void pass1(vpx_image_t *raw,
FILE *infile,
const char *outfile_name,
const VpxInterface *encoder,
const vpx_codec_enc_cfg_t *cfg,
int max_frames) {
VpxVideoInfo info = {
encoder->fourcc,
cfg->g_w,
cfg->g_h,
{cfg->g_timebase.num, cfg->g_timebase.den}
};
VpxVideoWriter *writer = NULL;
vpx_codec_ctx_t codec;
int frame_count = 0;
writer = vpx_video_writer_open(outfile_name, kContainerIVF, &info);
if (!writer)
die("Failed to open %s for writing", outfile_name);
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0))
die_codec(&codec, "Failed to initialize encoder");
// Encode frames.
while (vpx_img_read(raw, infile)) {
++frame_count;
encode_frame(&codec, raw, frame_count, 1, 0, VPX_DL_GOOD_QUALITY, writer);
if (max_frames > 0 && frame_count >= max_frames)
break;
}
// Flush encoder.
while (encode_frame(&codec, NULL, -1, 1, 0, VPX_DL_GOOD_QUALITY, writer)) {}
printf("\n");
if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
vpx_video_writer_close(writer);
printf("Pass 1 complete. Processed %d frames.\n", frame_count);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
FILE *infile = NULL; FILE *infile = NULL;
int w, h; VpxVideoWriter *writer = NULL;
vpx_codec_ctx_t codec; vpx_codec_ctx_t codec;
vpx_codec_enc_cfg_t cfg; vpx_codec_enc_cfg_t cfg;
vpx_image_t raw; vpx_image_t raw;
vpx_codec_err_t res; vpx_codec_err_t res;
vpx_fixed_buf_t stats; vpx_fixed_buf_t stats = {0};
VpxVideoInfo info = {0};
const VpxInterface *encoder = NULL; const VpxInterface *encoder = NULL;
int pass;
const int fps = 30; // TODO(dkovalev) add command line argument const int fps = 30; // TODO(dkovalev) add command line argument
const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument
const char *const codec_arg = argv[1]; const char *const codec_arg = argv[1];
@@ -222,56 +137,94 @@ int main(int argc, char **argv) {
const char *const height_arg = argv[3]; const char *const height_arg = argv[3];
const char *const infile_arg = argv[4]; const char *const infile_arg = argv[4];
const char *const outfile_arg = argv[5]; const char *const outfile_arg = argv[5];
int max_frames = 0;
exec_name = argv[0]; exec_name = argv[0];
if (argc != 7) if (argc != 6)
die("Invalid number of arguments."); die("Invalid number of arguments.");
max_frames = strtol(argv[6], NULL, 0);
encoder = get_vpx_encoder_by_name(codec_arg); encoder = get_vpx_encoder_by_name(codec_arg);
if (!encoder) if (!encoder)
die("Unsupported codec."); die("Unsupported codec.");
w = strtol(width_arg, NULL, 0); info.codec_fourcc = encoder->fourcc;
h = strtol(height_arg, NULL, 0); info.time_base.numerator = 1;
info.time_base.denominator = fps;
info.frame_width = strtol(width_arg, NULL, 0);
info.frame_height = strtol(height_arg, NULL, 0);
if (w <= 0 || h <= 0 || (w % 2) != 0 || (h % 2) != 0) if (info.frame_width <= 0 ||
die("Invalid frame size: %dx%d", w, h); info.frame_height <= 0 ||
(info.frame_width % 2) != 0 ||
(info.frame_height % 2) != 0) {
die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
}
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, w, h, 1)) if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
die("Failed to allocate image", w, h); info.frame_height, 1)) {
die("Failed to allocate image", info.frame_width, info.frame_height);
}
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info);
if (!writer)
die("Failed to open %s for writing", outfile_arg);
// Configuration printf("Using %s\n", vpx_codec_iface_name(encoder->interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
res = vpx_codec_enc_config_default(encoder->interface(), &cfg, 0);
if (res) if (res)
die_codec(&codec, "Failed to get default codec config."); die_codec(&codec, "Failed to get default codec config.");
cfg.g_w = w; cfg.g_w = info.frame_width;
cfg.g_h = h; cfg.g_h = info.frame_height;
cfg.g_timebase.num = 1; cfg.g_timebase.num = info.time_base.numerator;
cfg.g_timebase.den = fps; cfg.g_timebase.den = info.time_base.denominator;
cfg.rc_target_bitrate = bitrate; cfg.rc_target_bitrate = bitrate;
for (pass = 0; pass < 2; ++pass) {
int frame_count = 0;
if (pass == 0) {
cfg.g_pass = VPX_RC_FIRST_PASS;
} else {
cfg.g_pass = VPX_RC_LAST_PASS;
cfg.rc_twopass_stats_in = stats;
}
if (!(infile = fopen(infile_arg, "rb"))) if (!(infile = fopen(infile_arg, "rb")))
die("Failed to open %s for reading", infile_arg); die("Failed to open %s for reading", infile_arg);
// Pass 0 if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0))
cfg.g_pass = VPX_RC_FIRST_PASS; die_codec(&codec, "Failed to initialize encoder");
stats = pass0(&raw, infile, encoder, &cfg, max_frames);
// Pass 1 while (vpx_img_read(&raw, infile)) {
rewind(infile); ++frame_count;
cfg.g_pass = VPX_RC_LAST_PASS;
cfg.rc_twopass_stats_in = stats; if (pass == 0) {
pass1(&raw, infile, outfile_arg, encoder, &cfg, max_frames); get_frame_stats(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
free(stats.buf); &stats);
} else {
encode_frame(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
writer);
}
}
if (pass == 0) {
get_frame_stats(&codec, NULL, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
&stats);
} else {
printf("\n");
}
fclose(infile);
printf("Pass %d complete. Processed %d frames.\n", pass + 1, frame_count);
if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
}
vpx_img_free(&raw); vpx_img_free(&raw);
fclose(infile); free(stats.buf);
vpx_video_writer_close(writer);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -0,0 +1,471 @@
/*
* 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"
#include "./tools_common.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 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);
}
int (*read_frame_p)(FILE *f, vpx_image_t *img);
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 int read_frame_by_row(FILE *f, vpx_image_t *img) {
size_t nbytes, to_read;
int res = 1;
int plane;
for (plane = 0; plane < 3; plane++)
{
unsigned char *ptr;
int w = (plane ? (1 + img->d_w) / 2 : img->d_w);
int h = (plane ? (1 + img->d_h) / 2 : img->d_h);
int r;
/* Determine the correct plane based on the image format. The for-loop
* always counts in Y,U,V order, but this may not match the order of
* the data on disk.
*/
switch (plane)
{
case 1:
ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12? VPX_PLANE_V : VPX_PLANE_U];
break;
case 2:
ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12?VPX_PLANE_U : VPX_PLANE_V];
break;
default:
ptr = img->planes[plane];
}
for (r = 0; r < h; r++)
{
to_read = w;
nbytes = fread(ptr, 1, to_read, f);
if(nbytes != to_read) {
res = 0;
if(nbytes > 0)
printf("Warning: Read partial frame. Check your width & height!\n");
break;
}
ptr += img->stride[plane];
}
if (!res)
break;
}
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 */
(void) 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);
(void) 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.
* If target bitrate for highest-resolution level is set to 0,
* (i.e. target_bitrate[0]=0), we skip encoding at that level.
*/
unsigned int target_bitrate[NUM_ENCODERS]={1000, 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(!target_bitrate[i])
{
outfile[i] = NULL;
continue;
}
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 = 30;
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].g_error_resilient = 1; /* Enable error resilient mode */
cfg[0].g_lag_in_frames = 0;
/* Disable automatic keyframe placement */
/* Note: These 3 settings are copied to all levels. But, except the lowest
* resolution level, all other levels are set to VPX_KF_DISABLED internally.
*/
//cfg[0].kf_mode = VPX_KF_DISABLED;
cfg[0].kf_mode = VPX_KF_AUTO;
cfg[0].kf_min_dist = 3000;
cfg[0].kf_max_dist = 3000;
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, 32))
die("Failed to allocate image", cfg[i].g_w, cfg[i].g_h);
if (raw[0].stride[VPX_PLANE_Y] == raw[0].d_w)
read_frame_p = read_frame;
else
read_frame_p = read_frame_by_row;
for (i=0; i< NUM_ENCODERS; i++)
if(outfile[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 threshold. */
for ( i=0; i<NUM_ENCODERS; i++)
{
unsigned int static_thresh = 1;
if(vpx_codec_control(&codec[i], VP8E_SET_STATIC_THRESHOLD, static_thresh))
die_codec(&codec[i], "Failed to set static threshold");
}
/* Set NOISE_SENSITIVITY to do TEMPORAL_DENOISING */
/* Enable denoising for the highest-resolution encoder. */
if(vpx_codec_control(&codec[0], VP8E_SET_NOISE_SENSITIVITY, 1))
die_codec(&codec[0], "Failed to set noise_sensitivity");
for ( i=1; i< NUM_ENCODERS; i++)
{
if(vpx_codec_control(&codec[i], VP8E_SET_NOISE_SENSITIVITY, 0))
die_codec(&codec[i], "Failed to set noise_sensitivity");
}
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_p(infile, &raw[0]);
if(frame_avail)
{
for ( i=1; i<NUM_ENCODERS; i++)
{
/*Scale the image down a number of times by downsampling factor*/
/* FilterMode 1 or 2 give better psnr than FilterMode 0. */
I420Scale(raw[i-1].planes[VPX_PLANE_Y], raw[i-1].stride[VPX_PLANE_Y],
raw[i-1].planes[VPX_PLANE_U], raw[i-1].stride[VPX_PLANE_U],
raw[i-1].planes[VPX_PLANE_V], raw[i-1].stride[VPX_PLANE_V],
raw[i-1].d_w, raw[i-1].d_h,
raw[i].planes[VPX_PLANE_Y], raw[i].stride[VPX_PLANE_Y],
raw[i].planes[VPX_PLANE_U], raw[i].stride[VPX_PLANE_U],
raw[i].planes[VPX_PLANE_V], raw[i].stride[VPX_PLANE_V],
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]);
(void) 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);
printf("Processed %ld frames.\n",(long int)frame_cnt-1);
for (i=0; i< NUM_ENCODERS; i++)
{
/* Calculate PSNR and print it out */
if ( (show_psnr) && (psnr_count[i]>0) )
{
int j;
double ovpsnr = sse_to_psnr(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");
vpx_img_free(&raw[i]);
if(!outfile[i])
continue;
/* 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]);
}
printf("\n");
return EXIT_SUCCESS;
}

View File

@@ -50,25 +50,25 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define VPX_CODEC_DISABLE_COMPAT 1
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "../tools_common.h" #include "./tools_common.h"
#include "../video_writer.h" #include "./video_writer.h"
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { void usage_exit() {
fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile> <frame>\n", fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile> <frame>\n",
exec_name); exec_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
static int encode_frame(vpx_codec_ctx_t *codec, static void encode_frame(vpx_codec_ctx_t *codec,
vpx_image_t *img, vpx_image_t *img,
int frame_index, int frame_index,
VpxVideoWriter *writer) { VpxVideoWriter *writer) {
int got_pkts = 0;
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt = NULL; const vpx_codec_cx_pkt_t *pkt = NULL;
const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, 0, const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, 0,
@@ -77,8 +77,6 @@ static int encode_frame(vpx_codec_ctx_t *codec,
die_codec(codec, "Failed to encode frame"); die_codec(codec, "Failed to encode frame");
while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) { while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) {
got_pkts = 1;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
if (!vpx_video_writer_write_frame(writer, if (!vpx_video_writer_write_frame(writer,
@@ -92,8 +90,6 @@ static int encode_frame(vpx_codec_ctx_t *codec,
fflush(stdout); fflush(stdout);
} }
} }
return got_pkts;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
@@ -142,9 +138,9 @@ int main(int argc, char **argv) {
die("Failed to allocate image."); die("Failed to allocate image.");
} }
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(encoder->interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); res = vpx_codec_enc_config_default(encoder->interface(), &cfg, 0);
if (res) if (res)
die_codec(&codec, "Failed to get default codec config."); die_codec(&codec, "Failed to get default codec config.");
@@ -161,10 +157,9 @@ int main(int argc, char **argv) {
if (!(infile = fopen(argv[3], "rb"))) if (!(infile = fopen(argv[3], "rb")))
die("Failed to open %s for reading.", argv[3]); die("Failed to open %s for reading.", argv[3]);
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0))
die_codec(&codec, "Failed to initialize encoder"); die_codec(&codec, "Failed to initialize encoder");
// Encode frames.
while (vpx_img_read(&raw, infile)) { while (vpx_img_read(&raw, infile)) {
if (frame_count + 1 == update_frame_num) { if (frame_count + 1 == update_frame_num) {
vpx_ref_frame_t ref; vpx_ref_frame_t ref;
@@ -176,9 +171,7 @@ int main(int argc, char **argv) {
encode_frame(&codec, &raw, frame_count++, writer); encode_frame(&codec, &raw, frame_count++, writer);
} }
encode_frame(&codec, NULL, -1, writer);
// Flush encoder.
while (encode_frame(&codec, NULL, -1, writer)) {}
printf("\n"); printf("\n");
fclose(infile); fclose(infile);

View File

@@ -0,0 +1,392 @@
/*
* Copyright (c) 2012 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 how to implement a multi-layer
* VP9 encoding scheme based on spatial scalability for video applications
* that benefit from a scalable bitstream.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "./args.h"
#include "./tools_common.h"
#include "./video_writer.h"
#include "vpx/svc_context.h"
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
#include "./vpxstats.h"
static const struct arg_enum_list encoding_mode_enum[] = {
{"i", INTER_LAYER_PREDICTION_I},
{"alt-ip", ALT_INTER_LAYER_PREDICTION_IP},
{"ip", INTER_LAYER_PREDICTION_IP},
{"gf", USE_GOLDEN_FRAME},
{NULL, 0}
};
static const arg_def_t encoding_mode_arg = ARG_DEF_ENUM(
"m", "encoding-mode", 1, "Encoding mode algorithm", encoding_mode_enum);
static const arg_def_t skip_frames_arg =
ARG_DEF("s", "skip-frames", 1, "input frames to skip");
static const arg_def_t frames_arg =
ARG_DEF("f", "frames", 1, "number of frames to encode");
static const arg_def_t width_arg = ARG_DEF("w", "width", 1, "source width");
static const arg_def_t height_arg = ARG_DEF("h", "height", 1, "source height");
static const arg_def_t timebase_arg =
ARG_DEF("t", "timebase", 1, "timebase (num/den)");
static const arg_def_t bitrate_arg = ARG_DEF(
"b", "target-bitrate", 1, "encoding bitrate, in kilobits per second");
static const arg_def_t layers_arg =
ARG_DEF("l", "layers", 1, "number of SVC layers");
static const arg_def_t kf_dist_arg =
ARG_DEF("k", "kf-dist", 1, "number of frames between keyframes");
static const arg_def_t scale_factors_arg =
ARG_DEF("r", "scale-factors", 1, "scale factors (lowest to highest layer)");
static const arg_def_t quantizers_arg =
ARG_DEF("q", "quantizers", 1, "quantizers for non key frames, also will "
"be applied to key frames if -qn is not specified (lowest to "
"highest layer)");
static const arg_def_t quantizers_keyframe_arg =
ARG_DEF("qn", "quantizers-keyframe", 1, "quantizers for key frames (lowest "
"to highest layer)");
static const arg_def_t passes_arg =
ARG_DEF("p", "passes", 1, "Number of passes (1/2)");
static const arg_def_t pass_arg =
ARG_DEF(NULL, "pass", 1, "Pass to execute (1/2)");
static const arg_def_t fpf_name_arg =
ARG_DEF(NULL, "fpf", 1, "First pass statistics file name");
static const arg_def_t min_q_arg =
ARG_DEF(NULL, "min-q", 1, "Minimum quantizer");
static const arg_def_t max_q_arg =
ARG_DEF(NULL, "max-q", 1, "Maximum quantizer");
static const arg_def_t min_bitrate_arg =
ARG_DEF(NULL, "min-bitrate", 1, "Minimum bitrate");
static const arg_def_t max_bitrate_arg =
ARG_DEF(NULL, "max-bitrate", 1, "Maximum bitrate");
static const arg_def_t *svc_args[] = {
&encoding_mode_arg, &frames_arg, &width_arg, &height_arg,
&timebase_arg, &bitrate_arg, &skip_frames_arg, &layers_arg,
&kf_dist_arg, &scale_factors_arg, &quantizers_arg,
&quantizers_keyframe_arg, &passes_arg, &pass_arg,
&fpf_name_arg, &min_q_arg, &max_q_arg, &min_bitrate_arg,
&max_bitrate_arg, NULL
};
static const SVC_ENCODING_MODE default_encoding_mode =
INTER_LAYER_PREDICTION_IP;
static const uint32_t default_frames_to_skip = 0;
static const uint32_t default_frames_to_code = 60 * 60;
static const uint32_t default_width = 1920;
static const uint32_t default_height = 1080;
static const uint32_t default_timebase_num = 1;
static const uint32_t default_timebase_den = 60;
static const uint32_t default_bitrate = 1000;
static const uint32_t default_spatial_layers = 5;
static const uint32_t default_kf_dist = 100;
typedef struct {
const char *input_filename;
const char *output_filename;
uint32_t frames_to_code;
uint32_t frames_to_skip;
struct VpxInputContext input_ctx;
stats_io_t rc_stats;
int passes;
int pass;
} AppInput;
static const char *exec_name;
void usage_exit() {
fprintf(stderr, "Usage: %s <options> input_filename output_filename\n",
exec_name);
fprintf(stderr, "Options:\n");
arg_show_usage(stderr, svc_args);
exit(EXIT_FAILURE);
}
static void parse_command_line(int argc, const char **argv_,
AppInput *app_input, SvcContext *svc_ctx,
vpx_codec_enc_cfg_t *enc_cfg) {
struct arg arg = {0};
char **argv = NULL;
char **argi = NULL;
char **argj = NULL;
vpx_codec_err_t res;
int passes = 0;
int pass = 0;
const char *fpf_file_name = NULL;
unsigned int min_bitrate = 0;
unsigned int max_bitrate = 0;
// initialize SvcContext with parameters that will be passed to vpx_svc_init
svc_ctx->log_level = SVC_LOG_DEBUG;
svc_ctx->spatial_layers = default_spatial_layers;
svc_ctx->encoding_mode = default_encoding_mode;
// start with default encoder configuration
res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0);
if (res) {
die("Failed to get config: %s\n", vpx_codec_err_to_string(res));
}
// update enc_cfg with app default values
enc_cfg->g_w = default_width;
enc_cfg->g_h = default_height;
enc_cfg->g_timebase.num = default_timebase_num;
enc_cfg->g_timebase.den = default_timebase_den;
enc_cfg->rc_target_bitrate = default_bitrate;
enc_cfg->kf_min_dist = default_kf_dist;
enc_cfg->kf_max_dist = default_kf_dist;
enc_cfg->rc_end_usage = VPX_CQ;
// initialize AppInput with default values
app_input->frames_to_code = default_frames_to_code;
app_input->frames_to_skip = default_frames_to_skip;
// process command line options
argv = argv_dup(argc - 1, argv_ + 1);
for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
arg.argv_step = 1;
if (arg_match(&arg, &encoding_mode_arg, argi)) {
svc_ctx->encoding_mode = arg_parse_enum_or_int(&arg);
} else if (arg_match(&arg, &frames_arg, argi)) {
app_input->frames_to_code = arg_parse_uint(&arg);
} else if (arg_match(&arg, &width_arg, argi)) {
enc_cfg->g_w = arg_parse_uint(&arg);
} else if (arg_match(&arg, &height_arg, argi)) {
enc_cfg->g_h = arg_parse_uint(&arg);
} else if (arg_match(&arg, &timebase_arg, argi)) {
enc_cfg->g_timebase = arg_parse_rational(&arg);
} else if (arg_match(&arg, &bitrate_arg, argi)) {
enc_cfg->rc_target_bitrate = arg_parse_uint(&arg);
} else if (arg_match(&arg, &skip_frames_arg, argi)) {
app_input->frames_to_skip = arg_parse_uint(&arg);
} else if (arg_match(&arg, &layers_arg, argi)) {
svc_ctx->spatial_layers = arg_parse_uint(&arg);
} else if (arg_match(&arg, &kf_dist_arg, argi)) {
enc_cfg->kf_min_dist = arg_parse_uint(&arg);
enc_cfg->kf_max_dist = enc_cfg->kf_min_dist;
} else if (arg_match(&arg, &scale_factors_arg, argi)) {
vpx_svc_set_scale_factors(svc_ctx, arg.val);
} else if (arg_match(&arg, &quantizers_arg, argi)) {
vpx_svc_set_quantizers(svc_ctx, arg.val, 0);
} else if (arg_match(&arg, &quantizers_keyframe_arg, argi)) {
vpx_svc_set_quantizers(svc_ctx, arg.val, 1);
} else if (arg_match(&arg, &passes_arg, argi)) {
passes = arg_parse_uint(&arg);
if (passes < 1 || passes > 2) {
die("Error: Invalid number of passes (%d)\n", passes);
}
} else if (arg_match(&arg, &pass_arg, argi)) {
pass = arg_parse_uint(&arg);
if (pass < 1 || pass > 2) {
die("Error: Invalid pass selected (%d)\n", pass);
}
} else if (arg_match(&arg, &fpf_name_arg, argi)) {
fpf_file_name = arg.val;
} else if (arg_match(&arg, &min_q_arg, argi)) {
enc_cfg->rc_min_quantizer = arg_parse_uint(&arg);
} else if (arg_match(&arg, &max_q_arg, argi)) {
enc_cfg->rc_max_quantizer = arg_parse_uint(&arg);
} else if (arg_match(&arg, &min_bitrate_arg, argi)) {
min_bitrate = arg_parse_uint(&arg);
} else if (arg_match(&arg, &max_bitrate_arg, argi)) {
max_bitrate = arg_parse_uint(&arg);
} else {
++argj;
}
}
if (passes == 0 || passes == 1) {
if (pass) {
fprintf(stderr, "pass is ignored since there's only one pass\n");
}
enc_cfg->g_pass = VPX_RC_ONE_PASS;
} else {
if (pass == 0) {
die("pass must be specified when passes is 2\n");
}
if (fpf_file_name == NULL) {
die("fpf must be specified when passes is 2\n");
}
if (pass == 1) {
enc_cfg->g_pass = VPX_RC_FIRST_PASS;
if (!stats_open_file(&app_input->rc_stats, fpf_file_name, 0)) {
fatal("Failed to open statistics store");
}
} else {
enc_cfg->g_pass = VPX_RC_LAST_PASS;
if (!stats_open_file(&app_input->rc_stats, fpf_file_name, 1)) {
fatal("Failed to open statistics store");
}
enc_cfg->rc_twopass_stats_in = stats_get(&app_input->rc_stats);
}
app_input->passes = passes;
app_input->pass = pass;
}
if (enc_cfg->rc_target_bitrate > 0) {
if (min_bitrate > 0) {
enc_cfg->rc_2pass_vbr_minsection_pct =
min_bitrate * 100 / enc_cfg->rc_target_bitrate;
}
if (max_bitrate > 0) {
enc_cfg->rc_2pass_vbr_maxsection_pct =
max_bitrate * 100 / enc_cfg->rc_target_bitrate;
}
}
// Check for unrecognized options
for (argi = argv; *argi; ++argi)
if (argi[0][0] == '-' && strlen(argi[0]) > 1)
die("Error: Unrecognized option %s\n", *argi);
if (argv[0] == NULL || argv[1] == 0) {
usage_exit();
}
app_input->input_filename = argv[0];
app_input->output_filename = argv[1];
free(argv);
if (enc_cfg->g_w < 16 || enc_cfg->g_w % 2 || enc_cfg->g_h < 16 ||
enc_cfg->g_h % 2)
die("Invalid resolution: %d x %d\n", enc_cfg->g_w, enc_cfg->g_h);
printf(
"Codec %s\nframes: %d, skip: %d\n"
"mode: %d, layers: %d\n"
"width %d, height: %d,\n"
"num: %d, den: %d, bitrate: %d,\n"
"gop size: %d\n",
vpx_codec_iface_name(vpx_codec_vp9_cx()), app_input->frames_to_code,
app_input->frames_to_skip, svc_ctx->encoding_mode,
svc_ctx->spatial_layers, enc_cfg->g_w, enc_cfg->g_h,
enc_cfg->g_timebase.num, enc_cfg->g_timebase.den,
enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist);
}
int main(int argc, const char **argv) {
AppInput app_input = {0};
VpxVideoWriter *writer = NULL;
VpxVideoInfo info = {0};
vpx_codec_ctx_t codec;
vpx_codec_enc_cfg_t enc_cfg;
SvcContext svc_ctx;
uint32_t i;
uint32_t frame_cnt = 0;
vpx_image_t raw;
vpx_codec_err_t res;
int pts = 0; /* PTS starts at 0 */
int frame_duration = 1; /* 1 timebase tick per frame */
FILE *infile = NULL;
int end_of_stream = 0;
memset(&svc_ctx, 0, sizeof(svc_ctx));
svc_ctx.log_print = 1;
exec_name = argv[0];
parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg);
// Allocate image buffer
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32))
die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h);
if (!(infile = fopen(app_input.input_filename, "rb")))
die("Failed to open %s for reading\n", app_input.input_filename);
// Initialize codec
if (vpx_svc_init(&svc_ctx, &codec, vpx_codec_vp9_cx(), &enc_cfg) !=
VPX_CODEC_OK)
die("Failed to initialize encoder\n");
info.codec_fourcc = VP9_FOURCC;
info.time_base.numerator = enc_cfg.g_timebase.num;
info.time_base.denominator = enc_cfg.g_timebase.den;
if (vpx_svc_get_layer_resolution(&svc_ctx, svc_ctx.spatial_layers - 1,
(unsigned int *)&info.frame_width,
(unsigned int *)&info.frame_height) !=
VPX_CODEC_OK) {
die("Failed to get output resolution");
}
if (!(app_input.passes == 2 && app_input.pass == 1)) {
// We don't save the bitstream for the 1st pass on two pass rate control
writer = vpx_video_writer_open(app_input.output_filename, kContainerIVF,
&info);
if (!writer)
die("Failed to open %s for writing\n", app_input.output_filename);
}
// skip initial frames
for (i = 0; i < app_input.frames_to_skip; ++i)
vpx_img_read(&raw, infile);
// Encode frames
while (!end_of_stream) {
if (frame_cnt >= app_input.frames_to_code || !vpx_img_read(&raw, infile)) {
// We need one extra vpx_svc_encode call at end of stream to flush
// encoder and get remaining data
end_of_stream = 1;
}
res = vpx_svc_encode(&svc_ctx, &codec, (end_of_stream ? NULL : &raw),
pts, frame_duration, VPX_DL_GOOD_QUALITY);
printf("%s", vpx_svc_get_message(&svc_ctx));
if (res != VPX_CODEC_OK) {
die_codec(&codec, "Failed to encode frame");
}
if (!(app_input.passes == 2 && app_input.pass == 1)) {
if (vpx_svc_get_frame_size(&svc_ctx) > 0) {
vpx_video_writer_write_frame(writer,
vpx_svc_get_buffer(&svc_ctx),
vpx_svc_get_frame_size(&svc_ctx),
pts);
}
}
if (vpx_svc_get_rc_stats_buffer_size(&svc_ctx) > 0) {
stats_write(&app_input.rc_stats,
vpx_svc_get_rc_stats_buffer(&svc_ctx),
vpx_svc_get_rc_stats_buffer_size(&svc_ctx));
}
if (!end_of_stream) {
++frame_cnt;
pts += frame_duration;
}
}
printf("Processed %d frames\n", frame_cnt);
fclose(infile);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
if (app_input.passes == 2)
stats_close(&app_input.rc_stats, 1);
if (writer) {
vpx_video_writer_close(writer);
}
vpx_img_free(&raw);
// display average size, psnr
printf("%s", vpx_svc_dump_statistics(&svc_ctx));
vpx_svc_release(&svc_ctx);
return EXIT_SUCCESS;
}

View File

@@ -12,36 +12,27 @@
// encoding scheme based on temporal scalability for video applications // encoding scheme based on temporal scalability for video applications
// that benefit from a scalable bitstream. // that benefit from a scalable bitstream.
#include <assert.h>
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define VPX_CODEC_DISABLE_COMPAT 1
#include "./vpx_config.h" #include "./vpx_config.h"
#include "../vpx_ports/vpx_timer.h" #include "vpx_ports/vpx_timer.h"
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "../tools_common.h" #include "./tools_common.h"
#include "../video_writer.h" #include "./video_writer.h"
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { void usage_exit() {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Denoiser states, for temporal denoising. static int mode_to_num_layers[12] = {1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3};
enum denoiserState {
kDenoiserOff,
kDenoiserOnYOnly,
kDenoiserOnYUV,
kDenoiserOnYUVAggressive,
kDenoiserOnAdaptive
};
static int mode_to_num_layers[13] = {1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3, 3};
// For rate control encoding stats. // For rate control encoding stats.
struct RateControlMetrics { struct RateControlMetrics {
@@ -61,16 +52,6 @@ struct RateControlMetrics {
double layer_avg_rate_mismatch[VPX_TS_MAX_LAYERS]; double layer_avg_rate_mismatch[VPX_TS_MAX_LAYERS];
// Actual encoding bitrate per layer (cumulative). // Actual encoding bitrate per layer (cumulative).
double layer_encoding_bitrate[VPX_TS_MAX_LAYERS]; double layer_encoding_bitrate[VPX_TS_MAX_LAYERS];
// Average of the short-time encoder actual bitrate.
// TODO(marpan): Should we add these short-time stats for each layer?
double avg_st_encoding_bitrate;
// Variance of the short-time encoder actual bitrate.
double variance_st_encoding_bitrate;
// Window (number of frames) for computing short-timee encoding bitrate.
int window_size;
// Number of window measurements.
int window_count;
int layer_target_bitrate[VPX_MAX_LAYERS];
}; };
// Note: these rate control metrics assume only 1 key frame in the // Note: these rate control metrics assume only 1 key frame in the
@@ -86,13 +67,13 @@ static void set_rate_control_metrics(struct RateControlMetrics *rc,
// per-frame-bandwidth, for the rate control encoding stats below. // per-frame-bandwidth, for the rate control encoding stats below.
const double framerate = cfg->g_timebase.den / cfg->g_timebase.num; const double framerate = cfg->g_timebase.den / cfg->g_timebase.num;
rc->layer_framerate[0] = framerate / cfg->ts_rate_decimator[0]; rc->layer_framerate[0] = framerate / cfg->ts_rate_decimator[0];
rc->layer_pfb[0] = 1000.0 * rc->layer_target_bitrate[0] / rc->layer_pfb[0] = 1000.0 * cfg->ts_target_bitrate[0] /
rc->layer_framerate[0]; rc->layer_framerate[0];
for (i = 0; i < cfg->ts_number_layers; ++i) { for (i = 0; i < cfg->ts_number_layers; ++i) {
if (i > 0) { if (i > 0) {
rc->layer_framerate[i] = framerate / cfg->ts_rate_decimator[i]; rc->layer_framerate[i] = framerate / cfg->ts_rate_decimator[i];
rc->layer_pfb[i] = 1000.0 * rc->layer_pfb[i] = 1000.0 *
(rc->layer_target_bitrate[i] - rc->layer_target_bitrate[i - 1]) / (cfg->ts_target_bitrate[i] - cfg->ts_target_bitrate[i - 1]) /
(rc->layer_framerate[i] - rc->layer_framerate[i - 1]); (rc->layer_framerate[i] - rc->layer_framerate[i - 1]);
} }
rc->layer_input_frames[i] = 0; rc->layer_input_frames[i] = 0;
@@ -102,10 +83,6 @@ static void set_rate_control_metrics(struct RateControlMetrics *rc,
rc->layer_avg_frame_size[i] = 0.0; rc->layer_avg_frame_size[i] = 0.0;
rc->layer_avg_rate_mismatch[i] = 0.0; rc->layer_avg_rate_mismatch[i] = 0.0;
} }
rc->window_count = 0;
rc->window_size = 15;
rc->avg_st_encoding_bitrate = 0.0;
rc->variance_st_encoding_bitrate = 0.0;
} }
static void printout_rate_control_summary(struct RateControlMetrics *rc, static void printout_rate_control_summary(struct RateControlMetrics *rc,
@@ -113,7 +90,6 @@ static void printout_rate_control_summary(struct RateControlMetrics *rc,
int frame_cnt) { int frame_cnt) {
unsigned int i = 0; unsigned int i = 0;
int tot_num_frames = 0; int tot_num_frames = 0;
double perc_fluctuation = 0.0;
printf("Total number of processed frames: %d\n\n", frame_cnt -1); printf("Total number of processed frames: %d\n\n", frame_cnt -1);
printf("Rate control layer stats for %d layer(s):\n\n", printf("Rate control layer stats for %d layer(s):\n\n",
cfg->ts_number_layers); cfg->ts_number_layers);
@@ -129,7 +105,7 @@ static void printout_rate_control_summary(struct RateControlMetrics *rc,
rc->layer_avg_rate_mismatch[i] = 100.0 * rc->layer_avg_rate_mismatch[i] / rc->layer_avg_rate_mismatch[i] = 100.0 * rc->layer_avg_rate_mismatch[i] /
rc->layer_enc_frames[i]; rc->layer_enc_frames[i];
printf("For layer#: %d \n", i); printf("For layer#: %d \n", i);
printf("Bitrate (target vs actual): %d %f \n", rc->layer_target_bitrate[i], printf("Bitrate (target vs actual): %d %f \n", cfg->ts_target_bitrate[i],
rc->layer_encoding_bitrate[i]); rc->layer_encoding_bitrate[i]);
printf("Average frame size (target vs actual): %f %f \n", rc->layer_pfb[i], printf("Average frame size (target vs actual): %f %f \n", rc->layer_pfb[i],
rc->layer_avg_frame_size[i]); rc->layer_avg_frame_size[i]);
@@ -140,17 +116,6 @@ static void printout_rate_control_summary(struct RateControlMetrics *rc,
100.0 * num_dropped / rc->layer_input_frames[i]); 100.0 * num_dropped / rc->layer_input_frames[i]);
printf("\n"); printf("\n");
} }
rc->avg_st_encoding_bitrate = rc->avg_st_encoding_bitrate / rc->window_count;
rc->variance_st_encoding_bitrate =
rc->variance_st_encoding_bitrate / rc->window_count -
(rc->avg_st_encoding_bitrate * rc->avg_st_encoding_bitrate);
perc_fluctuation = 100.0 * sqrt(rc->variance_st_encoding_bitrate) /
rc->avg_st_encoding_bitrate;
printf("Short-time stats, for window of %d frames: \n",rc->window_size);
printf("Average, rms-variance, and percent-fluct: %f %f %f \n",
rc->avg_st_encoding_bitrate,
sqrt(rc->variance_st_encoding_bitrate),
perc_fluctuation);
if ((frame_cnt - 1) != tot_num_frames) if ((frame_cnt - 1) != tot_num_frames)
die("Error: Number of input frames not equal to output! \n"); die("Error: Number of input frames not equal to output! \n");
} }
@@ -432,32 +397,7 @@ static void set_temporal_layer_pattern(int layering_mode,
layer_flags[7] = layer_flags[3]; layer_flags[7] = layer_flags[3];
break; break;
} }
case 11: { case 11:
// 3-layers structure with one reference frame.
// This works same as temporal_layering_mode 3.
// This was added to compare with vp9_spatial_svc_encoder.
// 3-layers, 4-frame period.
int ids[4] = {0, 2, 1, 2};
cfg->ts_periodicity = 4;
*flag_periodicity = 4;
cfg->ts_number_layers = 3;
cfg->ts_rate_decimator[0] = 4;
cfg->ts_rate_decimator[1] = 2;
cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled.
layer_flags[0] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
layer_flags[3] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
break;
}
case 12:
default: { default: {
// 3-layers structure as in case 10, but no sync/refresh points for // 3-layers structure as in case 10, but no sync/refresh points for
// layer 1 and 2. // layer 1 and 2.
@@ -489,7 +429,7 @@ static void set_temporal_layer_pattern(int layering_mode,
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS] = {NULL}; VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS];
vpx_codec_ctx_t codec; vpx_codec_ctx_t codec;
vpx_codec_enc_cfg_t cfg; vpx_codec_enc_cfg_t cfg;
int frame_cnt = 0; int frame_cnt = 0;
@@ -507,46 +447,26 @@ int main(int argc, char **argv) {
int layering_mode = 0; int layering_mode = 0;
int layer_flags[VPX_TS_MAX_PERIODICITY] = {0}; int layer_flags[VPX_TS_MAX_PERIODICITY] = {0};
int flag_periodicity = 1; int flag_periodicity = 1;
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION) int max_intra_size_pct;
vpx_svc_layer_id_t layer_id = {0, 0}; vpx_svc_layer_id_t layer_id = {0, 0};
#else
vpx_svc_layer_id_t layer_id = {0};
#endif
const VpxInterface *encoder = NULL; const VpxInterface *encoder = NULL;
FILE *infile = NULL; FILE *infile = NULL;
struct RateControlMetrics rc; struct RateControlMetrics rc;
int64_t cx_time = 0; int64_t cx_time = 0;
const int min_args_base = 11;
#if CONFIG_VPX_HIGHBITDEPTH
vpx_bit_depth_t bit_depth = VPX_BITS_8;
int input_bit_depth = 8;
const int min_args = min_args_base + 1;
#else
const int min_args = min_args_base;
#endif // CONFIG_VPX_HIGHBITDEPTH
double sum_bitrate = 0.0;
double sum_bitrate2 = 0.0;
double framerate = 30.0;
exec_name = argv[0]; exec_name = argv[0];
// Check usage and arguments. // Check usage and arguments.
if (argc < min_args) { if (argc < 11) {
#if CONFIG_VPX_HIGHBITDEPTH
die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> "
"<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> "
"<Rate_0> ... <Rate_nlayers-1> <bit-depth> \n", argv[0]);
#else
die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> " die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> "
"<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> " "<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> "
"<Rate_0> ... <Rate_nlayers-1> \n", argv[0]); "<Rate_0> ... <Rate_nlayers-1> \n", argv[0]);
#endif // CONFIG_VPX_HIGHBITDEPTH
} }
encoder = get_vpx_encoder_by_name(argv[3]); encoder = get_vpx_encoder_by_name(argv[3]);
if (!encoder) if (!encoder)
die("Unsupported codec."); die("Unsupported codec.");
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(encoder->interface()));
width = strtol(argv[4], NULL, 0); width = strtol(argv[4], NULL, 0);
height = strtol(argv[5], NULL, 0); height = strtol(argv[5], NULL, 0);
@@ -555,45 +475,20 @@ int main(int argc, char **argv) {
} }
layering_mode = strtol(argv[10], NULL, 0); layering_mode = strtol(argv[10], NULL, 0);
if (layering_mode < 0 || layering_mode > 13) { if (layering_mode < 0 || layering_mode > 12) {
die("Invalid layering mode (0..12) %s", argv[10]); die("Invalid layering mode (0..12) %s", argv[10]);
} }
if (argc != min_args + mode_to_num_layers[layering_mode]) { if (argc != 11 + mode_to_num_layers[layering_mode]) {
die("Invalid number of arguments"); die("Invalid number of arguments");
} }
#if CONFIG_VPX_HIGHBITDEPTH
switch (strtol(argv[argc-1], NULL, 0)) {
case 8:
bit_depth = VPX_BITS_8;
input_bit_depth = 8;
break;
case 10:
bit_depth = VPX_BITS_10;
input_bit_depth = 10;
break;
case 12:
bit_depth = VPX_BITS_12;
input_bit_depth = 12;
break;
default:
die("Invalid bit depth (8, 10, 12) %s", argv[argc-1]);
}
if (!vpx_img_alloc(&raw,
bit_depth == VPX_BITS_8 ? VPX_IMG_FMT_I420 :
VPX_IMG_FMT_I42016,
width, height, 32)) {
die("Failed to allocate image", width, height);
}
#else
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 32)) { if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 32)) {
die("Failed to allocate image", width, height); die("Failed to allocate image", width, height);
} }
#endif // CONFIG_VPX_HIGHBITDEPTH
// Populate encoder configuration. // Populate encoder configuration.
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); res = vpx_codec_enc_config_default(encoder->interface(), &cfg, 0);
if (res) { if (res) {
printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -603,14 +498,6 @@ int main(int argc, char **argv) {
cfg.g_w = width; cfg.g_w = width;
cfg.g_h = height; cfg.g_h = height;
#if CONFIG_VPX_HIGHBITDEPTH
if (bit_depth != VPX_BITS_8) {
cfg.g_bit_depth = bit_depth;
cfg.g_input_bit_depth = input_bit_depth;
cfg.g_profile = 2;
}
#endif // CONFIG_VPX_HIGHBITDEPTH
// Timebase format e.g. 30fps: numerator=1, demoninator = 30. // Timebase format e.g. 30fps: numerator=1, demoninator = 30.
cfg.g_timebase.num = strtol(argv[6], NULL, 0); cfg.g_timebase.num = strtol(argv[6], NULL, 0);
cfg.g_timebase.den = strtol(argv[7], NULL, 0); cfg.g_timebase.den = strtol(argv[7], NULL, 0);
@@ -620,35 +507,22 @@ int main(int argc, char **argv) {
die("Invalid speed setting: must be positive"); die("Invalid speed setting: must be positive");
} }
for (i = min_args_base; for (i = 11; (int)i < 11 + mode_to_num_layers[layering_mode]; ++i) {
(int)i < min_args_base + mode_to_num_layers[layering_mode]; cfg.ts_target_bitrate[i - 11] = strtol(argv[i], NULL, 0);
++i) {
rc.layer_target_bitrate[i - 11] = strtol(argv[i], NULL, 0);
if (strncmp(encoder->name, "vp8", 3) == 0)
cfg.ts_target_bitrate[i - 11] = rc.layer_target_bitrate[i - 11];
else if (strncmp(encoder->name, "vp9", 3) == 0)
cfg.layer_target_bitrate[i - 11] = rc.layer_target_bitrate[i - 11];
} }
// Real time parameters. // Real time parameters.
cfg.rc_dropframe_thresh = strtol(argv[9], NULL, 0); cfg.rc_dropframe_thresh = strtol(argv[9], NULL, 0);
cfg.rc_end_usage = VPX_CBR; cfg.rc_end_usage = VPX_CBR;
cfg.rc_resize_allowed = 0;
cfg.rc_min_quantizer = 2; cfg.rc_min_quantizer = 2;
cfg.rc_max_quantizer = 56; cfg.rc_max_quantizer = 56;
if (strncmp(encoder->name, "vp9", 3) == 0)
cfg.rc_max_quantizer = 52;
cfg.rc_undershoot_pct = 50; cfg.rc_undershoot_pct = 50;
cfg.rc_overshoot_pct = 50; cfg.rc_overshoot_pct = 50;
cfg.rc_buf_initial_sz = 500; cfg.rc_buf_initial_sz = 500;
cfg.rc_buf_optimal_sz = 600; cfg.rc_buf_optimal_sz = 600;
cfg.rc_buf_sz = 1000; cfg.rc_buf_sz = 1000;
// Disable dynamic resizing by default.
cfg.rc_resize_allowed = 0;
// Use 1 thread as default.
cfg.g_threads = 1;
// Enable error resilient mode. // Enable error resilient mode.
cfg.g_error_resilient = 1; cfg.g_error_resilient = 1;
cfg.g_lag_in_frames = 0; cfg.g_lag_in_frames = 0;
@@ -657,8 +531,6 @@ int main(int argc, char **argv) {
// Disable automatic keyframe placement. // Disable automatic keyframe placement.
cfg.kf_min_dist = cfg.kf_max_dist = 3000; cfg.kf_min_dist = cfg.kf_max_dist = 3000;
cfg.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
set_temporal_layer_pattern(layering_mode, set_temporal_layer_pattern(layering_mode,
&cfg, &cfg,
layer_flags, layer_flags,
@@ -667,15 +539,14 @@ int main(int argc, char **argv) {
set_rate_control_metrics(&rc, &cfg); set_rate_control_metrics(&rc, &cfg);
// Target bandwidth for the whole stream. // Target bandwidth for the whole stream.
// Set to layer_target_bitrate for highest layer (total bitrate). // Set to ts_target_bitrate for highest layer (total bitrate).
cfg.rc_target_bitrate = rc.layer_target_bitrate[cfg.ts_number_layers - 1]; cfg.rc_target_bitrate = cfg.ts_target_bitrate[cfg.ts_number_layers - 1];
// Open input file. // Open input file.
if (!(infile = fopen(argv[1], "rb"))) { if (!(infile = fopen(argv[1], "rb"))) {
die("Failed to open %s for reading", argv[1]); die("Failed to open %s for reading", argv[1]);
} }
framerate = cfg.g_timebase.den / cfg.g_timebase.num;
// Open an output file for each stream. // Open an output file for each stream.
for (i = 0; i < cfg.ts_number_layers; ++i) { for (i = 0; i < cfg.ts_number_layers; ++i) {
char file_name[PATH_MAX]; char file_name[PATH_MAX];
@@ -690,78 +561,50 @@ int main(int argc, char **argv) {
outfile[i] = vpx_video_writer_open(file_name, kContainerIVF, &info); outfile[i] = vpx_video_writer_open(file_name, kContainerIVF, &info);
if (!outfile[i]) if (!outfile[i])
die("Failed to open %s for writing", file_name); die("Failed to open %s for writing", file_name);
assert(outfile[i] != NULL);
} }
// No spatial layers in this encoder. // No spatial layers in this encoder.
cfg.ss_number_layers = 1; cfg.ss_number_layers = 1;
// Initialize codec. // Initialize codec.
#if CONFIG_VPX_HIGHBITDEPTH if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0))
if (vpx_codec_enc_init(
&codec, encoder->codec_interface(), &cfg,
bit_depth == VPX_BITS_8 ? 0 : VPX_CODEC_USE_HIGHBITDEPTH))
#else
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
#endif // CONFIG_VPX_HIGHBITDEPTH
die_codec(&codec, "Failed to initialize encoder"); die_codec(&codec, "Failed to initialize encoder");
if (strncmp(encoder->name, "vp8", 3) == 0) { if (strncmp(encoder->name, "vp8", 3) == 0) {
vpx_codec_control(&codec, VP8E_SET_CPUUSED, -speed); vpx_codec_control(&codec, VP8E_SET_CPUUSED, -speed);
vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kDenoiserOff); vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 1);
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
} else if (strncmp(encoder->name, "vp9", 3) == 0) { } else if (strncmp(encoder->name, "vp9", 3) == 0) {
vpx_svc_extra_cfg_t svc_params;
vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed); vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed);
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3); vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0); vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0);
vpx_codec_control(&codec, VP9E_SET_NOISE_SENSITIVITY, kDenoiserOff); vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 0);
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1); if (vpx_codec_control(&codec, VP9E_SET_SVC, 1)) {
vpx_codec_control(&codec, VP9E_SET_TUNE_CONTENT, 0);
vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, (cfg.g_threads >> 1));
if (vpx_codec_control(&codec, VP9E_SET_SVC, layering_mode > 0 ? 1: 0))
die_codec(&codec, "Failed to set SVC"); die_codec(&codec, "Failed to set SVC");
for (i = 0; i < cfg.ts_number_layers; ++i) {
svc_params.max_quantizers[i] = cfg.rc_max_quantizer;
svc_params.min_quantizers[i] = cfg.rc_min_quantizer;
} }
svc_params.scaling_factor_num[0] = cfg.g_h;
svc_params.scaling_factor_den[0] = cfg.g_h;
vpx_codec_control(&codec, VP9E_SET_SVC_PARAMETERS, &svc_params);
}
if (strncmp(encoder->name, "vp8", 3) == 0) {
vpx_codec_control(&codec, VP8E_SET_SCREEN_CONTENT_MODE, 0);
} }
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
vpx_codec_control(&codec, VP8E_SET_TOKEN_PARTITIONS, 1); vpx_codec_control(&codec, VP8E_SET_TOKEN_PARTITIONS, 1);
// This controls the maximum target size of the key frame. // This controls the maximum target size of the key frame.
// For generating smaller key frames, use a smaller max_intra_size_pct // For generating smaller key frames, use a smaller max_intra_size_pct
// value, like 100 or 200. // value, like 100 or 200.
{ max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5)
const int max_intra_size_pct = 900; * ((double) cfg.g_timebase.den / cfg.g_timebase.num) / 10.0);
vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, // For low-quality key frame.
max_intra_size_pct); max_intra_size_pct = 200;
} vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, max_intra_size_pct);
frame_avail = 1; frame_avail = 1;
while (frame_avail || got_data) { while (frame_avail || got_data) {
struct vpx_usec_timer timer; struct vpx_usec_timer timer;
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt; const vpx_codec_cx_pkt_t *pkt;
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
// Update the temporal layer_id. No spatial layers in this test. // Update the temporal layer_id. No spatial layers in this test.
layer_id.spatial_layer_id = 0; layer_id.spatial_layer_id = 0;
#endif
layer_id.temporal_layer_id = layer_id.temporal_layer_id =
cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
if (strncmp(encoder->name, "vp9", 3) == 0) { if (strncmp(encoder->name, "vp9", 3) == 0) {
vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id); vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id);
} else if (strncmp(encoder->name, "vp8", 3) == 0) {
vpx_codec_control(&codec, VP8E_SET_TEMPORAL_LAYER_ID,
layer_id.temporal_layer_id);
} }
flags = layer_flags[frame_cnt % flag_periodicity]; flags = layer_flags[frame_cnt % flag_periodicity];
if (layering_mode == 0)
flags = 0;
frame_avail = vpx_img_read(&raw, infile); frame_avail = vpx_img_read(&raw, infile);
if (frame_avail) if (frame_avail)
++rc.layer_input_frames[layer_id.temporal_layer_id]; ++rc.layer_input_frames[layer_id.temporal_layer_id];
@@ -797,33 +640,6 @@ int main(int argc, char **argv) {
++rc.layer_enc_frames[i]; ++rc.layer_enc_frames[i];
} }
} }
// Update for short-time encoding bitrate states, for moving window
// of size rc->window, shifted by rc->window / 2.
// Ignore first window segment, due to key frame.
if (frame_cnt > rc.window_size) {
sum_bitrate += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
if (frame_cnt % rc.window_size == 0) {
rc.window_count += 1;
rc.avg_st_encoding_bitrate += sum_bitrate / rc.window_size;
rc.variance_st_encoding_bitrate +=
(sum_bitrate / rc.window_size) *
(sum_bitrate / rc.window_size);
sum_bitrate = 0.0;
}
}
// Second shifted window.
if (frame_cnt > rc.window_size + rc.window_size / 2) {
sum_bitrate2 += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
if (frame_cnt > 2 * rc.window_size &&
frame_cnt % rc.window_size == 0) {
rc.window_count += 1;
rc.avg_st_encoding_bitrate += sum_bitrate2 / rc.window_size;
rc.variance_st_encoding_bitrate +=
(sum_bitrate2 / rc.window_size) *
(sum_bitrate2 / rc.window_size);
sum_bitrate2 = 0.0;
}
}
break; break;
default: default:
break; break;

View File

@@ -1,455 +0,0 @@
/*
* Copyright (c) 2016 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.
*/
// VP10 Set Reference Frame
// ============================
//
// This is an example demonstrating how to overwrite the VP10 encoder's
// internal reference frame. In the sample we set the last frame to the
// current frame. This technique could be used to bounce between two cameras.
//
// The decoder would also have to set the reference frame to the same value
// on the same frame, or the video will become corrupt. The 'test_decode'
// variable is set to 1 in this example that tests if the encoder and decoder
// results are matching.
//
// Usage
// -----
// This example encodes a raw video. And the last argument passed in specifies
// the frame number to update the reference frame on. For example, run
// examples/vpx_cx_set_ref vp10 352 288 in.yuv out.ivf 4 30
// The parameter is parsed as follows:
//
//
// Extra Variables
// ---------------
// This example maintains the frame number passed on the command line
// in the `update_frame_num` variable.
//
//
// Configuration
// -------------
//
// The reference frame is updated on the frame specified on the command
// line.
//
// Observing The Effects
// ---------------------
// The encoder and decoder results should be matching when the same reference
// frame setting operation is done in both encoder and decoder. Otherwise,
// the encoder/decoder mismatch would be seen.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vpx/vp8cx.h"
#include "vpx/vpx_decoder.h"
#include "vpx/vpx_encoder.h"
#include "./tools_common.h"
#include "./video_writer.h"
static const char *exec_name;
void usage_exit() {
fprintf(stderr, "Usage: %s <codec> <width> <height> <infile> <outfile> "
"<frame> <limit(optional)>\n",
exec_name);
exit(EXIT_FAILURE);
}
static int compare_img(const vpx_image_t *const img1,
const vpx_image_t *const img2) {
uint32_t l_w = img1->d_w;
uint32_t c_w =
(img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
const uint32_t c_h =
(img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
uint32_t i;
int match = 1;
match &= (img1->fmt == img2->fmt);
match &= (img1->d_w == img2->d_w);
match &= (img1->d_h == img2->d_h);
for (i = 0; i < img1->d_h; ++i)
match &= (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y],
img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y],
l_w) == 0);
for (i = 0; i < c_h; ++i)
match &= (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U],
img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U],
c_w) == 0);
for (i = 0; i < c_h; ++i)
match &= (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V],
img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V],
c_w) == 0);
return match;
}
#define mmin(a, b) ((a) < (b) ? (a) : (b))
static void find_mismatch(const vpx_image_t *const img1,
const vpx_image_t *const img2,
int yloc[4], int uloc[4], int vloc[4]) {
const uint32_t bsize = 64;
const uint32_t bsizey = bsize >> img1->y_chroma_shift;
const uint32_t bsizex = bsize >> img1->x_chroma_shift;
const uint32_t c_w =
(img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
const uint32_t c_h =
(img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
int match = 1;
uint32_t i, j;
yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1;
for (i = 0, match = 1; match && i < img1->d_h; i += bsize) {
for (j = 0; match && j < img1->d_w; j += bsize) {
int k, l;
const int si = mmin(i + bsize, img1->d_h) - i;
const int sj = mmin(j + bsize, img1->d_w) - j;
for (k = 0; match && k < si; ++k) {
for (l = 0; match && l < sj; ++l) {
if (*(img1->planes[VPX_PLANE_Y] +
(i + k) * img1->stride[VPX_PLANE_Y] + j + l) !=
*(img2->planes[VPX_PLANE_Y] +
(i + k) * img2->stride[VPX_PLANE_Y] + j + l)) {
yloc[0] = i + k;
yloc[1] = j + l;
yloc[2] = *(img1->planes[VPX_PLANE_Y] +
(i + k) * img1->stride[VPX_PLANE_Y] + j + l);
yloc[3] = *(img2->planes[VPX_PLANE_Y] +
(i + k) * img2->stride[VPX_PLANE_Y] + j + l);
match = 0;
break;
}
}
}
}
}
uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1;
for (i = 0, match = 1; match && i < c_h; i += bsizey) {
for (j = 0; match && j < c_w; j += bsizex) {
int k, l;
const int si = mmin(i + bsizey, c_h - i);
const int sj = mmin(j + bsizex, c_w - j);
for (k = 0; match && k < si; ++k) {
for (l = 0; match && l < sj; ++l) {
if (*(img1->planes[VPX_PLANE_U] +
(i + k) * img1->stride[VPX_PLANE_U] + j + l) !=
*(img2->planes[VPX_PLANE_U] +
(i + k) * img2->stride[VPX_PLANE_U] + j + l)) {
uloc[0] = i + k;
uloc[1] = j + l;
uloc[2] = *(img1->planes[VPX_PLANE_U] +
(i + k) * img1->stride[VPX_PLANE_U] + j + l);
uloc[3] = *(img2->planes[VPX_PLANE_U] +
(i + k) * img2->stride[VPX_PLANE_U] + j + l);
match = 0;
break;
}
}
}
}
}
vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1;
for (i = 0, match = 1; match && i < c_h; i += bsizey) {
for (j = 0; match && j < c_w; j += bsizex) {
int k, l;
const int si = mmin(i + bsizey, c_h - i);
const int sj = mmin(j + bsizex, c_w - j);
for (k = 0; match && k < si; ++k) {
for (l = 0; match && l < sj; ++l) {
if (*(img1->planes[VPX_PLANE_V] +
(i + k) * img1->stride[VPX_PLANE_V] + j + l) !=
*(img2->planes[VPX_PLANE_V] +
(i + k) * img2->stride[VPX_PLANE_V] + j + l)) {
vloc[0] = i + k;
vloc[1] = j + l;
vloc[2] = *(img1->planes[VPX_PLANE_V] +
(i + k) * img1->stride[VPX_PLANE_V] + j + l);
vloc[3] = *(img2->planes[VPX_PLANE_V] +
(i + k) * img2->stride[VPX_PLANE_V] + j + l);
match = 0;
break;
}
}
}
}
}
}
static void testing_decode(vpx_codec_ctx_t *encoder,
vpx_codec_ctx_t *decoder,
vpx_codec_enc_cfg_t *cfg,
unsigned int frame_out,
int *mismatch_seen) {
vpx_image_t enc_img, dec_img;
struct vp9_ref_frame ref_enc, ref_dec;
if (*mismatch_seen)
return;
ref_enc.idx = 0;
ref_dec.idx = 0;
if (vpx_codec_control(encoder, VP9_GET_REFERENCE, &ref_enc))
die_codec(encoder, "Failed to get encoder reference frame");
enc_img = ref_enc.img;
if (vpx_codec_control(decoder, VP9_GET_REFERENCE, &ref_dec))
die_codec(decoder, "Failed to get decoder reference frame");
dec_img = ref_dec.img;
if (!compare_img(&enc_img, &dec_img)) {
int y[4], u[4], v[4];
*mismatch_seen = 1;
find_mismatch(&enc_img, &dec_img, y, u, v);
printf("Encode/decode mismatch on frame %d at"
" Y[%d, %d] {%d/%d},"
" U[%d, %d] {%d/%d},"
" V[%d, %d] {%d/%d}",
frame_out,
y[0], y[1], y[2], y[3],
u[0], u[1], u[2], u[3],
v[0], v[1], v[2], v[3]);
}
vpx_img_free(&enc_img);
vpx_img_free(&dec_img);
}
static int encode_frame(vpx_codec_ctx_t *ecodec,
vpx_codec_enc_cfg_t *cfg,
vpx_image_t *img,
unsigned int frame_in,
VpxVideoWriter *writer,
int test_decode,
vpx_codec_ctx_t *dcodec,
unsigned int *frame_out,
int *mismatch_seen) {
int got_pkts = 0;
vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt = NULL;
int got_data;
const vpx_codec_err_t res = vpx_codec_encode(ecodec, img, frame_in, 1,
0, VPX_DL_GOOD_QUALITY);
if (res != VPX_CODEC_OK)
die_codec(ecodec, "Failed to encode frame");
got_data = 0;
while ((pkt = vpx_codec_get_cx_data(ecodec, &iter)) != NULL) {
got_pkts = 1;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) {
*frame_out += 1;
}
if (!vpx_video_writer_write_frame(writer,
pkt->data.frame.buf,
pkt->data.frame.sz,
pkt->data.frame.pts)) {
die_codec(ecodec, "Failed to write compressed frame");
}
printf(keyframe ? "K" : ".");
fflush(stdout);
got_data = 1;
// Decode 1 frame.
if (test_decode) {
if (vpx_codec_decode(dcodec, pkt->data.frame.buf,
(unsigned int)pkt->data.frame.sz, NULL, 0))
die_codec(dcodec, "Failed to decode frame.");
}
}
}
// Mismatch checking
if (got_data && test_decode) {
testing_decode(ecodec, dcodec, cfg, *frame_out, mismatch_seen);
}
return got_pkts;
}
int main(int argc, char **argv) {
FILE *infile = NULL;
// Encoder
vpx_codec_ctx_t ecodec = {0};
vpx_codec_enc_cfg_t cfg = {0};
unsigned int frame_in = 0;
vpx_image_t raw;
vpx_codec_err_t res;
VpxVideoInfo info = {0};
VpxVideoWriter *writer = NULL;
const VpxInterface *encoder = NULL;
// Test encoder/decoder mismatch.
int test_decode = 1;
// Decoder
vpx_codec_ctx_t dcodec;
unsigned int frame_out = 0;
// The frame number to set reference frame on
unsigned int update_frame_num = 0;
int mismatch_seen = 0;
const int fps = 30;
const int bitrate = 500;
const char *codec_arg = NULL;
const char *width_arg = NULL;
const char *height_arg = NULL;
const char *infile_arg = NULL;
const char *outfile_arg = NULL;
unsigned int limit = 0;
exec_name = argv[0];
if (argc < 7)
die("Invalid number of arguments");
codec_arg = argv[1];
width_arg = argv[2];
height_arg = argv[3];
infile_arg = argv[4];
outfile_arg = argv[5];
encoder = get_vpx_encoder_by_name(codec_arg);
if (!encoder)
die("Unsupported codec.");
update_frame_num = atoi(argv[6]);
// In VP10, the reference buffers (cm->buffer_pool->frame_bufs[i].buf) are
// allocated while calling vpx_codec_encode(), thus, setting reference for
// 1st frame isn't supported.
if (update_frame_num <= 1)
die("Couldn't parse frame number '%s'\n", argv[6]);
if (argc > 7) {
limit = atoi(argv[7]);
if (update_frame_num > limit)
die("Update frame number couldn't larger than limit\n");
}
info.codec_fourcc = encoder->fourcc;
info.frame_width = strtol(width_arg, NULL, 0);
info.frame_height = strtol(height_arg, NULL, 0);
info.time_base.numerator = 1;
info.time_base.denominator = fps;
if (info.frame_width <= 0 ||
info.frame_height <= 0 ||
(info.frame_width % 2) != 0 ||
(info.frame_height % 2) != 0) {
die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
}
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
info.frame_height, 1)) {
die("Failed to allocate image.");
}
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
if (res)
die_codec(&ecodec, "Failed to get default codec config.");
cfg.g_w = info.frame_width;
cfg.g_h = info.frame_height;
cfg.g_timebase.num = info.time_base.numerator;
cfg.g_timebase.den = info.time_base.denominator;
cfg.rc_target_bitrate = bitrate;
cfg.g_lag_in_frames = 3;
writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info);
if (!writer)
die("Failed to open %s for writing.", outfile_arg);
if (!(infile = fopen(infile_arg, "rb")))
die("Failed to open %s for reading.", infile_arg);
if (vpx_codec_enc_init(&ecodec, encoder->codec_interface(), &cfg, 0))
die_codec(&ecodec, "Failed to initialize encoder");
// Disable alt_ref.
if (vpx_codec_control(&ecodec, VP8E_SET_ENABLEAUTOALTREF, 0))
die_codec(&ecodec, "Failed to set enable auto alt ref");
if (test_decode) {
const VpxInterface *decoder = get_vpx_decoder_by_name(codec_arg);
if (vpx_codec_dec_init(&dcodec, decoder->codec_interface(), NULL, 0))
die_codec(&dcodec, "Failed to initialize decoder.");
}
// Encode frames.
while (vpx_img_read(&raw, infile)) {
if (limit && frame_in >= limit)
break;
if (update_frame_num > 1 && frame_out + 1 == update_frame_num) {
vpx_ref_frame_t ref;
ref.frame_type = VP8_LAST_FRAME;
ref.img = raw;
// Set reference frame in encoder.
if (vpx_codec_control(&ecodec, VP8_SET_REFERENCE, &ref))
die_codec(&ecodec, "Failed to set reference frame");
printf(" <SET_REF>");
// If set_reference in decoder is commented out, the enc/dec mismatch
// would be seen.
if (test_decode) {
if (vpx_codec_control(&dcodec, VP8_SET_REFERENCE, &ref))
die_codec(&dcodec, "Failed to set reference frame");
}
}
encode_frame(&ecodec, &cfg, &raw, frame_in, writer, test_decode,
&dcodec, &frame_out, &mismatch_seen);
frame_in++;
if (mismatch_seen)
break;
}
// Flush encoder.
if (!mismatch_seen)
while (encode_frame(&ecodec, &cfg, NULL, frame_in, writer, test_decode,
&dcodec, &frame_out, &mismatch_seen)) {}
printf("\n");
fclose(infile);
printf("Processed %d frames.\n", frame_out);
if (test_decode) {
if (!mismatch_seen)
printf("Encoder/decoder results are matching.\n");
else
printf("Encoder/decoder results are NOT matching.\n");
}
if (test_decode)
if (vpx_codec_destroy(&dcodec))
die_codec(&dcodec, "Failed to destroy decoder");
vpx_img_free(&raw);
if (vpx_codec_destroy(&ecodec))
die_codec(&ecodec, "Failed to destroy encoder.");
vpx_video_writer_close(writer);
return EXIT_SUCCESS;
}

View File

@@ -23,7 +23,7 @@ static void fix_framerate(int *num, int *den) {
// we can guess the framerate using only the timebase in this // we can guess the framerate using only the timebase in this
// case. Other files would require reading ahead to guess the // case. Other files would require reading ahead to guess the
// timebase, like we do for webm. // timebase, like we do for webm.
if (*den > 0 && *den < 1000000000 && *num > 0 && *num < 1000) { if (*num < 1000) {
// Correct for the factor of 2 applied to the timebase in the encoder. // Correct for the factor of 2 applied to the timebase in the encoder.
if (*num & 1) if (*num & 1)
*den *= 2; *den *= 2;

View File

@@ -36,7 +36,7 @@ DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded # The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project. # by quotes) that should identify the project.
PROJECT_NAME = "WebM Codec SDK" PROJECT_NAME = "WebM VP8 Codec SDK"
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put. # base path where the generated documentation will be put.
@@ -415,6 +415,12 @@ MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES SHOW_USED_FILES = YES
# If the sources in your project are distributed over multiple directories
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
# in the documentation. The default is NO.
SHOW_DIRECTORIES = NO
# The FILE_VERSION_FILTER tag can be used to specify a program or script that # The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from the # doxygen should invoke to get the current version for each file (typically from the
# version control system). Doxygen will invoke the program by executing (via # version control system). Doxygen will invoke the program by executing (via
@@ -709,6 +715,12 @@ HTML_FOOTER =
HTML_STYLESHEET = HTML_STYLESHEET =
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
# If the GENERATE_HTMLHELP tag is set to YES, additional index files # If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the # will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # Microsoft HTML help workshop to generate a compressed HTML help file (.chm)

327
libs.mk
View File

@@ -17,6 +17,32 @@ else
ASM:=.asm ASM:=.asm
endif endif
#
# Calculate platform- and compiler-specific offsets for hand coded assembly
#
ifeq ($(filter icc gcc,$(TGT_CC)), $(TGT_CC))
OFFSET_PATTERN:='^[a-zA-Z0-9_]* EQU'
define asm_offsets_template
$$(BUILD_PFX)$(1): $$(BUILD_PFX)$(2).S
@echo " [CREATE] $$@"
$$(qexec)LC_ALL=C grep $$(OFFSET_PATTERN) $$< | tr -d '$$$$\#' $$(ADS2GAS) > $$@
$$(BUILD_PFX)$(2).S: $(2)
CLEAN-OBJS += $$(BUILD_PFX)$(1) $(2).S
endef
else
ifeq ($(filter rvct,$(TGT_CC)), $(TGT_CC))
define asm_offsets_template
$$(BUILD_PFX)$(1): obj_int_extract
$$(BUILD_PFX)$(1): $$(BUILD_PFX)$(2).o
@echo " [CREATE] $$@"
$$(qexec)./obj_int_extract rvds $$< $$(ADS2GAS) > $$@
OBJS-yes += $$(BUILD_PFX)$(2).o
CLEAN-OBJS += $$(BUILD_PFX)$(1)
$$(filter %$$(ASM).o,$$(OBJS-yes)): $$(BUILD_PFX)$(1)
endef
endif # rvct
endif # !gcc
# #
# Rule to generate runtime cpu detection files # Rule to generate runtime cpu detection files
# #
@@ -25,7 +51,7 @@ $$(BUILD_PFX)$(1).h: $$(SRC_PATH_BARE)/$(2)
@echo " [CREATE] $$@" @echo " [CREATE] $$@"
$$(qexec)$$(SRC_PATH_BARE)/build/make/rtcd.pl --arch=$$(TGT_ISA) \ $$(qexec)$$(SRC_PATH_BARE)/build/make/rtcd.pl --arch=$$(TGT_ISA) \
--sym=$(1) \ --sym=$(1) \
--config=$$(CONFIG_DIR)$$(target)-$$(TOOLCHAIN).mk \ --config=$$(CONFIG_DIR)$$(target)$$(if $$(FAT_ARCHS),,-$$(TOOLCHAIN)).mk \
$$(RTCD_OPTIONS) $$^ > $$@ $$(RTCD_OPTIONS) $$^ > $$@
CLEAN-OBJS += $$(BUILD_PFX)$(1).h CLEAN-OBJS += $$(BUILD_PFX)$(1).h
RTCD += $$(BUILD_PFX)$(1).h RTCD += $$(BUILD_PFX)$(1).h
@@ -34,6 +60,13 @@ endef
CODEC_SRCS-yes += CHANGELOG CODEC_SRCS-yes += CHANGELOG
CODEC_SRCS-yes += libs.mk CODEC_SRCS-yes += libs.mk
# If this is a universal (fat) binary, then all the subarchitectures have
# already been built and our job is to stitch them together. The
# BUILD_LIBVPX variable indicates whether we should be building
# (compiling, linking) the library. The LIPO_LIBVPX variable indicates
# that we're stitching.
$(eval $(if $(filter universal%,$(TOOLCHAIN)),LIPO_LIBVPX,BUILD_LIBVPX):=yes)
include $(SRC_PATH_BARE)/vpx/vpx_codec.mk include $(SRC_PATH_BARE)/vpx/vpx_codec.mk
CODEC_SRCS-yes += $(addprefix vpx/,$(call enabled,API_SRCS)) CODEC_SRCS-yes += $(addprefix vpx/,$(call enabled,API_SRCS))
CODEC_DOC_SRCS += $(addprefix vpx/,$(call enabled,API_DOC_SRCS)) CODEC_DOC_SRCS += $(addprefix vpx/,$(call enabled,API_DOC_SRCS))
@@ -47,45 +80,59 @@ CODEC_SRCS-yes += $(addprefix vpx_scale/,$(call enabled,SCALE_SRCS))
include $(SRC_PATH_BARE)/vpx_ports/vpx_ports.mk include $(SRC_PATH_BARE)/vpx_ports/vpx_ports.mk
CODEC_SRCS-yes += $(addprefix vpx_ports/,$(call enabled,PORTS_SRCS)) CODEC_SRCS-yes += $(addprefix vpx_ports/,$(call enabled,PORTS_SRCS))
include $(SRC_PATH_BARE)/vpx_dsp/vpx_dsp.mk ifneq ($(CONFIG_VP8_ENCODER)$(CONFIG_VP8_DECODER),)
CODEC_SRCS-yes += $(addprefix vpx_dsp/,$(call enabled,DSP_SRCS)) VP8_PREFIX=vp8/
include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8_common.mk
include $(SRC_PATH_BARE)/vpx_util/vpx_util.mk
CODEC_SRCS-yes += $(addprefix vpx_util/,$(call enabled,UTIL_SRCS))
# VP10 make file
ifeq ($(CONFIG_VP10),yes)
VP10_PREFIX=vp10/
include $(SRC_PATH_BARE)/$(VP10_PREFIX)vp10_common.mk
endif endif
ifeq ($(CONFIG_VP10_ENCODER),yes) ifeq ($(CONFIG_VP8_ENCODER),yes)
VP10_PREFIX=vp10/ include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8cx.mk
include $(SRC_PATH_BARE)/$(VP10_PREFIX)vp10cx.mk CODEC_SRCS-yes += $(addprefix $(VP8_PREFIX),$(call enabled,VP8_CX_SRCS))
CODEC_SRCS-yes += $(addprefix $(VP10_PREFIX),$(call enabled,VP10_CX_SRCS)) CODEC_EXPORTS-yes += $(addprefix $(VP8_PREFIX),$(VP8_CX_EXPORTS))
CODEC_EXPORTS-yes += $(addprefix $(VP10_PREFIX),$(VP10_CX_EXPORTS)) INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h
CODEC_SRCS-yes += $(VP10_PREFIX)vp10cx.mk vpx/vp8.h vpx/vp8cx.h INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP8_PREFIX)/%
CODEC_DOC_SECTIONS += vp8 vp8_encoder
endif
ifeq ($(CONFIG_VP8_DECODER),yes)
include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8dx.mk
CODEC_SRCS-yes += $(addprefix $(VP8_PREFIX),$(call enabled,VP8_DX_SRCS))
CODEC_EXPORTS-yes += $(addprefix $(VP8_PREFIX),$(VP8_DX_EXPORTS))
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8dx.h
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP8_PREFIX)/%
CODEC_DOC_SECTIONS += vp8 vp8_decoder
endif
ifneq ($(CONFIG_VP9_ENCODER)$(CONFIG_VP9_DECODER),)
VP9_PREFIX=vp9/
include $(SRC_PATH_BARE)/$(VP9_PREFIX)vp9_common.mk
endif
ifeq ($(CONFIG_VP9_ENCODER),yes)
VP9_PREFIX=vp9/
include $(SRC_PATH_BARE)/$(VP9_PREFIX)vp9cx.mk
CODEC_SRCS-yes += $(addprefix $(VP9_PREFIX),$(call enabled,VP9_CX_SRCS))
CODEC_EXPORTS-yes += $(addprefix $(VP9_PREFIX),$(VP9_CX_EXPORTS))
CODEC_SRCS-yes += $(VP9_PREFIX)vp9cx.mk vpx/vp8.h vpx/vp8cx.h
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h
INSTALL-LIBS-$(CONFIG_SPATIAL_SVC) += include/vpx/svc_context.h INSTALL-LIBS-$(CONFIG_SPATIAL_SVC) += include/vpx/svc_context.h
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP10_PREFIX)/% INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_PREFIX)/%
CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h
CODEC_DOC_SECTIONS += vp9 vp9_encoder CODEC_DOC_SECTIONS += vp9 vp9_encoder
endif endif
ifeq ($(CONFIG_VP10_DECODER),yes) ifeq ($(CONFIG_VP9_DECODER),yes)
VP10_PREFIX=vp10/ VP9_PREFIX=vp9/
include $(SRC_PATH_BARE)/$(VP10_PREFIX)vp10dx.mk include $(SRC_PATH_BARE)/$(VP9_PREFIX)vp9dx.mk
CODEC_SRCS-yes += $(addprefix $(VP10_PREFIX),$(call enabled,VP10_DX_SRCS)) CODEC_SRCS-yes += $(addprefix $(VP9_PREFIX),$(call enabled,VP9_DX_SRCS))
CODEC_EXPORTS-yes += $(addprefix $(VP10_PREFIX),$(VP10_DX_EXPORTS)) CODEC_EXPORTS-yes += $(addprefix $(VP9_PREFIX),$(VP9_DX_EXPORTS))
CODEC_SRCS-yes += $(VP10_PREFIX)vp10dx.mk vpx/vp8.h vpx/vp8dx.h CODEC_SRCS-yes += $(VP9_PREFIX)vp9dx.mk vpx/vp8.h vpx/vp8dx.h
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8dx.h INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8dx.h
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP10_PREFIX)/% INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_PREFIX)/%
CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8dx.h CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8dx.h
CODEC_DOC_SECTIONS += vp9 vp9_decoder CODEC_DOC_SECTIONS += vp9 vp9_decoder
endif endif
VP10_PREFIX=vp10/
$(BUILD_PFX)$(VP10_PREFIX)%.c.o: CFLAGS += -Wextra
ifeq ($(CONFIG_ENCODERS),yes) ifeq ($(CONFIG_ENCODERS),yes)
CODEC_DOC_SECTIONS += encoder CODEC_DOC_SECTIONS += encoder
@@ -114,22 +161,19 @@ INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/% $(p)/Release/%)
INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/% $(p)/Debug/%) INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/% $(p)/Debug/%)
endif endif
CODEC_SRCS-yes += build/make/version.sh CODEC_SRCS-$(BUILD_LIBVPX) += build/make/version.sh
CODEC_SRCS-yes += build/make/rtcd.pl CODEC_SRCS-$(BUILD_LIBVPX) += build/make/rtcd.pl
CODEC_SRCS-yes += vpx_ports/emmintrin_compat.h CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/emmintrin_compat.h
CODEC_SRCS-yes += vpx_ports/mem_ops.h CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/mem_ops.h
CODEC_SRCS-yes += vpx_ports/mem_ops_aligned.h CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/mem_ops_aligned.h
CODEC_SRCS-yes += vpx_ports/vpx_once.h CODEC_SRCS-$(BUILD_LIBVPX) += vpx_ports/vpx_once.h
CODEC_SRCS-yes += $(BUILD_PFX)vpx_config.c CODEC_SRCS-$(BUILD_LIBVPX) += $(BUILD_PFX)vpx_config.c
INSTALL-SRCS-no += $(BUILD_PFX)vpx_config.c INSTALL-SRCS-no += $(BUILD_PFX)vpx_config.c
ifeq ($(ARCH_X86)$(ARCH_X86_64),yes) ifeq ($(ARCH_X86)$(ARCH_X86_64),yes)
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += third_party/x86inc/x86inc.asm CODEC_SRCS-$(BUILD_LIBVPX) += third_party/x86inc/x86inc.asm
endif endif
CODEC_EXPORTS-yes += vpx/exports_com CODEC_EXPORTS-$(BUILD_LIBVPX) += vpx/exports_com
CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_enc CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_enc
ifeq ($(CONFIG_SPATIAL_SVC),yes)
CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_spatial_svc
endif
CODEC_EXPORTS-$(CONFIG_DECODERS) += vpx/exports_dec CODEC_EXPORTS-$(CONFIG_DECODERS) += vpx/exports_dec
INSTALL-LIBS-yes += include/vpx/vpx_codec.h INSTALL-LIBS-yes += include/vpx/vpx_codec.h
@@ -159,13 +203,33 @@ INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(call enabled,CODEC_EXPORTS)
# based build systems. # based build systems.
libvpx_srcs.txt: libvpx_srcs.txt:
@echo " [CREATE] $@" @echo " [CREATE] $@"
@echo $(CODEC_SRCS) | xargs -n1 echo | LC_ALL=C sort -u > $@ @echo $(CODEC_SRCS) | xargs -n1 echo | sort -u > $@
CLEAN-OBJS += libvpx_srcs.txt CLEAN-OBJS += libvpx_srcs.txt
ifeq ($(CONFIG_EXTERNAL_BUILD),yes) ifeq ($(CONFIG_EXTERNAL_BUILD),yes)
ifeq ($(CONFIG_MSVS),yes) ifeq ($(CONFIG_MSVS),yes)
obj_int_extract.bat: $(SRC_PATH_BARE)/build/$(MSVS_ARCH_DIR)/obj_int_extract.bat
@cp $^ $@
obj_int_extract.$(VCPROJ_SFX): obj_int_extract.bat
obj_int_extract.$(VCPROJ_SFX): $(SRC_PATH_BARE)/build/make/obj_int_extract.c
@echo " [CREATE] $@"
$(qexec)$(GEN_VCPROJ) \
--exe \
--target=$(TOOLCHAIN) \
--name=obj_int_extract \
--ver=$(CONFIG_VS_VERSION) \
--proj-guid=E1360C65-D375-4335-8057-7ED99CC3F9B2 \
--src-path-bare="$(SRC_PATH_BARE)" \
$(if $(CONFIG_STATIC_MSVCRT),--static-crt) \
--out=$@ $^ \
-I. \
-I"$(SRC_PATH_BARE)" \
PROJECTS-$(BUILD_LIBVPX) += obj_int_extract.$(VCPROJ_SFX)
vpx.def: $(call enabled,CODEC_EXPORTS) vpx.def: $(call enabled,CODEC_EXPORTS)
@echo " [CREATE] $@" @echo " [CREATE] $@"
$(qexec)$(SRC_PATH_BARE)/build/make/gen_msvs_def.sh\ $(qexec)$(SRC_PATH_BARE)/build/make/gen_msvs_def.sh\
@@ -180,7 +244,7 @@ ASM_INCLUDES := \
vpx_config.asm \ vpx_config.asm \
vpx_ports/x86_abi_support.asm \ vpx_ports/x86_abi_support.asm \
vpx.$(VCPROJ_SFX): $(CODEC_SRCS) vpx.def vpx.$(VCPROJ_SFX): $(CODEC_SRCS) vpx.def obj_int_extract.$(VCPROJ_SFX)
@echo " [CREATE] $@" @echo " [CREATE] $@"
$(qexec)$(GEN_VCPROJ) \ $(qexec)$(GEN_VCPROJ) \
$(if $(CONFIG_SHARED),--dll,--lib) \ $(if $(CONFIG_SHARED),--dll,--lib) \
@@ -195,7 +259,7 @@ vpx.$(VCPROJ_SFX): $(CODEC_SRCS) vpx.def
$(filter-out $(addprefix %, $(ASM_INCLUDES)), $^) \ $(filter-out $(addprefix %, $(ASM_INCLUDES)), $^) \
--src-path-bare="$(SRC_PATH_BARE)" \ --src-path-bare="$(SRC_PATH_BARE)" \
PROJECTS-yes += vpx.$(VCPROJ_SFX) PROJECTS-$(BUILD_LIBVPX) += vpx.$(VCPROJ_SFX)
vpx.$(VCPROJ_SFX): vpx_config.asm vpx.$(VCPROJ_SFX): vpx_config.asm
vpx.$(VCPROJ_SFX): $(RTCD) vpx.$(VCPROJ_SFX): $(RTCD)
@@ -203,49 +267,32 @@ vpx.$(VCPROJ_SFX): $(RTCD)
endif endif
else else
LIBVPX_OBJS=$(call objs,$(CODEC_SRCS)) LIBVPX_OBJS=$(call objs,$(CODEC_SRCS))
OBJS-yes += $(LIBVPX_OBJS) OBJS-$(BUILD_LIBVPX) += $(LIBVPX_OBJS)
LIBS-$(if yes,$(CONFIG_STATIC)) += $(BUILD_PFX)libvpx.a $(BUILD_PFX)libvpx_g.a LIBS-$(if $(BUILD_LIBVPX),$(CONFIG_STATIC)) += $(BUILD_PFX)libvpx.a $(BUILD_PFX)libvpx_g.a
$(BUILD_PFX)libvpx_g.a: $(LIBVPX_OBJS) $(BUILD_PFX)libvpx_g.a: $(LIBVPX_OBJS)
SO_VERSION_MAJOR := 3
SO_VERSION_MINOR := 0 BUILD_LIBVPX_SO := $(if $(BUILD_LIBVPX),$(CONFIG_SHARED))
SO_VERSION_PATCH := 0
ifeq ($(filter darwin%,$(TGT_OS)),$(TGT_OS)) ifeq ($(filter darwin%,$(TGT_OS)),$(TGT_OS))
LIBVPX_SO := libvpx.$(SO_VERSION_MAJOR).dylib LIBVPX_SO := libvpx.$(VERSION_MAJOR).dylib
SHARED_LIB_SUF := .dylib
EXPORT_FILE := libvpx.syms EXPORT_FILE := libvpx.syms
LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, \ LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, \
libvpx.dylib ) libvpx.dylib )
else else
ifeq ($(filter iphonesimulator%,$(TGT_OS)),$(TGT_OS)) LIBVPX_SO := libvpx.so.$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)
LIBVPX_SO := libvpx.$(SO_VERSION_MAJOR).dylib
SHARED_LIB_SUF := .dylib
EXPORT_FILE := libvpx.syms
LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, libvpx.dylib)
else
ifeq ($(filter os2%,$(TGT_OS)),$(TGT_OS))
LIBVPX_SO := libvpx$(SO_VERSION_MAJOR).dll
SHARED_LIB_SUF := _dll.a
EXPORT_FILE := libvpx.def
LIBVPX_SO_SYMLINKS :=
LIBVPX_SO_IMPLIB := libvpx_dll.a
else
LIBVPX_SO := libvpx.so.$(SO_VERSION_MAJOR).$(SO_VERSION_MINOR).$(SO_VERSION_PATCH)
SHARED_LIB_SUF := .so
EXPORT_FILE := libvpx.ver EXPORT_FILE := libvpx.ver
SYM_LINK := libvpx.so
LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, \ LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, \
libvpx.so libvpx.so.$(SO_VERSION_MAJOR) \ libvpx.so libvpx.so.$(VERSION_MAJOR) \
libvpx.so.$(SO_VERSION_MAJOR).$(SO_VERSION_MINOR)) libvpx.so.$(VERSION_MAJOR).$(VERSION_MINOR))
endif
endif
endif endif
LIBS-$(CONFIG_SHARED) += $(BUILD_PFX)$(LIBVPX_SO)\ LIBS-$(BUILD_LIBVPX_SO) += $(BUILD_PFX)$(LIBVPX_SO)\
$(notdir $(LIBVPX_SO_SYMLINKS)) \ $(notdir $(LIBVPX_SO_SYMLINKS))
$(if $(LIBVPX_SO_IMPLIB), $(BUILD_PFX)$(LIBVPX_SO_IMPLIB))
$(BUILD_PFX)$(LIBVPX_SO): $(LIBVPX_OBJS) $(EXPORT_FILE) $(BUILD_PFX)$(LIBVPX_SO): $(LIBVPX_OBJS) $(EXPORT_FILE)
$(BUILD_PFX)$(LIBVPX_SO): extralibs += -lm $(BUILD_PFX)$(LIBVPX_SO): extralibs += -lm
$(BUILD_PFX)$(LIBVPX_SO): SONAME = libvpx.so.$(SO_VERSION_MAJOR) $(BUILD_PFX)$(LIBVPX_SO): SONAME = libvpx.so.$(VERSION_MAJOR)
$(BUILD_PFX)$(LIBVPX_SO): EXPORTS_FILE = $(EXPORT_FILE) $(BUILD_PFX)$(LIBVPX_SO): EXPORTS_FILE = $(EXPORT_FILE)
libvpx.ver: $(call enabled,CODEC_EXPORTS) libvpx.ver: $(call enabled,CODEC_EXPORTS)
@@ -260,19 +307,6 @@ libvpx.syms: $(call enabled,CODEC_EXPORTS)
$(qexec)awk '{print "_"$$2}' $^ >$@ $(qexec)awk '{print "_"$$2}' $^ >$@
CLEAN-OBJS += libvpx.syms CLEAN-OBJS += libvpx.syms
libvpx.def: $(call enabled,CODEC_EXPORTS)
@echo " [CREATE] $@"
$(qexec)echo LIBRARY $(LIBVPX_SO:.dll=) INITINSTANCE TERMINSTANCE > $@
$(qexec)echo "DATA MULTIPLE NONSHARED" >> $@
$(qexec)echo "EXPORTS" >> $@
$(qexec)awk '!/vpx_svc_*/ {print "_"$$2}' $^ >>$@
CLEAN-OBJS += libvpx.def
libvpx_dll.a: $(LIBVPX_SO)
@echo " [IMPLIB] $@"
$(qexec)emximp -o $@ $<
CLEAN-OBJS += libvpx_dll.a
define libvpx_symlink_template define libvpx_symlink_template
$(1): $(2) $(1): $(2)
@echo " [LN] $(2) $$@" @echo " [LN] $(2) $$@"
@@ -288,12 +322,11 @@ $(eval $(call libvpx_symlink_template,\
$(LIBVPX_SO))) $(LIBVPX_SO)))
INSTALL-LIBS-$(CONFIG_SHARED) += $(LIBVPX_SO_SYMLINKS) INSTALL-LIBS-$(BUILD_LIBVPX_SO) += $(LIBVPX_SO_SYMLINKS)
INSTALL-LIBS-$(CONFIG_SHARED) += $(LIBSUBDIR)/$(LIBVPX_SO) INSTALL-LIBS-$(BUILD_LIBVPX_SO) += $(LIBSUBDIR)/$(LIBVPX_SO)
INSTALL-LIBS-$(CONFIG_SHARED) += $(if $(LIBVPX_SO_IMPLIB),$(LIBSUBDIR)/$(LIBVPX_SO_IMPLIB))
LIBS-yes += vpx.pc LIBS-$(BUILD_LIBVPX) += vpx.pc
vpx.pc: config.mk libs.mk vpx.pc: config.mk libs.mk
@echo " [CREATE] $@" @echo " [CREATE] $@"
$(qexec)echo '# pkg-config file from libvpx $(VERSION_STRING)' > $@ $(qexec)echo '# pkg-config file from libvpx $(VERSION_STRING)' > $@
@@ -319,6 +352,9 @@ INSTALL_MAPS += $(LIBSUBDIR)/pkgconfig/%.pc %.pc
CLEAN-OBJS += vpx.pc CLEAN-OBJS += vpx.pc
endif endif
LIBS-$(LIPO_LIBVPX) += libvpx.a
$(eval $(if $(LIPO_LIBVPX),$(call lipo_lib_template,libvpx.a)))
# #
# Rule to make assembler configuration file from C configuration file # Rule to make assembler configuration file from C configuration file
# #
@@ -339,7 +375,7 @@ CLEAN-OBJS += $(BUILD_PFX)vpx_config.asm
endif endif
# #
# Add assembler dependencies for configuration. # Add assembler dependencies for configuration and offsets
# #
$(filter %.s.o,$(OBJS-yes)): $(BUILD_PFX)vpx_config.asm $(filter %.s.o,$(OBJS-yes)): $(BUILD_PFX)vpx_config.asm
$(filter %$(ASM).o,$(OBJS-yes)): $(BUILD_PFX)vpx_config.asm $(filter %$(ASM).o,$(OBJS-yes)): $(BUILD_PFX)vpx_config.asm
@@ -348,12 +384,6 @@ $(filter %$(ASM).o,$(OBJS-yes)): $(BUILD_PFX)vpx_config.asm
$(shell $(SRC_PATH_BARE)/build/make/version.sh "$(SRC_PATH_BARE)" $(BUILD_PFX)vpx_version.h) $(shell $(SRC_PATH_BARE)/build/make/version.sh "$(SRC_PATH_BARE)" $(BUILD_PFX)vpx_version.h)
CLEAN-OBJS += $(BUILD_PFX)vpx_version.h CLEAN-OBJS += $(BUILD_PFX)vpx_version.h
#
# Add include path for libwebm sources.
#
ifeq ($(CONFIG_WEBM_IO),yes)
CXXFLAGS += -I$(SRC_PATH_BARE)/third_party/libwebm
endif
## ##
## libvpx test directives ## libvpx test directives
@@ -363,18 +393,14 @@ LIBVPX_TEST_DATA_PATH ?= .
include $(SRC_PATH_BARE)/test/test.mk include $(SRC_PATH_BARE)/test/test.mk
LIBVPX_TEST_SRCS=$(addprefix test/,$(call enabled,LIBVPX_TEST_SRCS)) LIBVPX_TEST_SRCS=$(addprefix test/,$(call enabled,LIBVPX_TEST_SRCS))
LIBVPX_TEST_BIN=./test_libvpx$(EXE_SFX) LIBVPX_TEST_BINS=./test_libvpx$(EXE_SFX)
LIBVPX_TEST_DATA=$(addprefix $(LIBVPX_TEST_DATA_PATH)/,\ LIBVPX_TEST_DATA=$(addprefix $(LIBVPX_TEST_DATA_PATH)/,\
$(call enabled,LIBVPX_TEST_DATA)) $(call enabled,LIBVPX_TEST_DATA))
libvpx_test_data_url=http://downloads.webmproject.org/test_data/libvpx/$(1) libvpx_test_data_url=http://downloads.webmproject.org/test_data/libvpx/$(1)
TEST_INTRA_PRED_SPEED_BIN=./test_intra_pred_speed$(EXE_SFX)
TEST_INTRA_PRED_SPEED_SRCS=$(addprefix test/,$(call enabled,TEST_INTRA_PRED_SPEED_SRCS))
TEST_INTRA_PRED_SPEED_OBJS := $(sort $(call objs,$(TEST_INTRA_PRED_SPEED_SRCS)))
libvpx_test_srcs.txt: libvpx_test_srcs.txt:
@echo " [CREATE] $@" @echo " [CREATE] $@"
@echo $(LIBVPX_TEST_SRCS) | xargs -n1 echo | LC_ALL=C sort -u > $@ @echo $(LIBVPX_TEST_SRCS) | xargs -n1 echo | sort -u > $@
CLEAN-OBJS += libvpx_test_srcs.txt CLEAN-OBJS += libvpx_test_srcs.txt
$(LIBVPX_TEST_DATA): $(SRC_PATH_BARE)/test/test-data.sha1 $(LIBVPX_TEST_DATA): $(SRC_PATH_BARE)/test/test-data.sha1
@@ -383,16 +409,14 @@ $(LIBVPX_TEST_DATA): $(SRC_PATH_BARE)/test/test-data.sha1
curl -L -o $@ $(call libvpx_test_data_url,$(@F)) curl -L -o $@ $(call libvpx_test_data_url,$(@F))
testdata:: $(LIBVPX_TEST_DATA) testdata:: $(LIBVPX_TEST_DATA)
$(qexec)[ -x "$$(which sha1sum)" ] && sha1sum=sha1sum;\ $(qexec)if [ -x "$$(which sha1sum)" ]; then\
[ -x "$$(which shasum)" ] && sha1sum=shasum;\
[ -x "$$(which sha1)" ] && sha1sum=sha1;\
if [ -n "$${sha1sum}" ]; then\
set -e;\
echo "Checking test data:";\ echo "Checking test data:";\
if [ -n "$(LIBVPX_TEST_DATA)" ]; then\
for f in $(call enabled,LIBVPX_TEST_DATA); do\ for f in $(call enabled,LIBVPX_TEST_DATA); do\
grep $$f $(SRC_PATH_BARE)/test/test-data.sha1 |\ grep $$f $(SRC_PATH_BARE)/test/test-data.sha1 |\
(cd $(LIBVPX_TEST_DATA_PATH); $${sha1sum} -c);\ (cd $(LIBVPX_TEST_DATA_PATH); sha1sum -c);\
done; \ done; \
fi; \
else\ else\
echo "Skipping test data integrity check, sha1sum not found.";\ echo "Skipping test data integrity check, sha1sum not found.";\
fi fi
@@ -429,30 +453,11 @@ test_libvpx.$(VCPROJ_SFX): $(LIBVPX_TEST_SRCS) vpx.$(VCPROJ_SFX) gtest.$(VCPROJ_
$(if $(CONFIG_STATIC_MSVCRT),--static-crt) \ $(if $(CONFIG_STATIC_MSVCRT),--static-crt) \
--out=$@ $(INTERNAL_CFLAGS) $(CFLAGS) \ --out=$@ $(INTERNAL_CFLAGS) $(CFLAGS) \
-I. -I"$(SRC_PATH_BARE)/third_party/googletest/src/include" \ -I. -I"$(SRC_PATH_BARE)/third_party/googletest/src/include" \
$(if $(CONFIG_WEBM_IO),-I"$(SRC_PATH_BARE)/third_party/libwebm") \
-L. -l$(CODEC_LIB) -l$(GTEST_LIB) $^ -L. -l$(CODEC_LIB) -l$(GTEST_LIB) $^
PROJECTS-$(CONFIG_MSVS) += test_libvpx.$(VCPROJ_SFX) PROJECTS-$(CONFIG_MSVS) += test_libvpx.$(VCPROJ_SFX)
LIBVPX_TEST_BIN := $(addprefix $(TGT_OS:win64=x64)/Release/,$(notdir $(LIBVPX_TEST_BIN))) LIBVPX_TEST_BINS := $(addprefix $(TGT_OS:win64=x64)/Release/,$(notdir $(LIBVPX_TEST_BINS)))
ifneq ($(strip $(TEST_INTRA_PRED_SPEED_OBJS)),)
PROJECTS-$(CONFIG_MSVS) += test_intra_pred_speed.$(VCPROJ_SFX)
test_intra_pred_speed.$(VCPROJ_SFX): $(TEST_INTRA_PRED_SPEED_SRCS) vpx.$(VCPROJ_SFX) gtest.$(VCPROJ_SFX)
@echo " [CREATE] $@"
$(qexec)$(GEN_VCPROJ) \
--exe \
--target=$(TOOLCHAIN) \
--name=test_intra_pred_speed \
-D_VARIADIC_MAX=10 \
--proj-guid=CD837F5F-52D8-4314-A370-895D614166A7 \
--ver=$(CONFIG_VS_VERSION) \
--src-path-bare="$(SRC_PATH_BARE)" \
$(if $(CONFIG_STATIC_MSVCRT),--static-crt) \
--out=$@ $(INTERNAL_CFLAGS) $(CFLAGS) \
-I. -I"$(SRC_PATH_BARE)/third_party/googletest/src/include" \
-L. -l$(CODEC_LIB) -l$(GTEST_LIB) $^
endif # TEST_INTRA_PRED_SPEED
endif endif
else else
@@ -463,54 +468,45 @@ ifeq ($(filter win%,$(TGT_OS)),$(TGT_OS))
# Disabling pthreads globally will cause issues on darwin and possibly elsewhere # Disabling pthreads globally will cause issues on darwin and possibly elsewhere
$(GTEST_OBJS) $(GTEST_OBJS:.o=.d): CXXFLAGS += -DGTEST_HAS_PTHREAD=0 $(GTEST_OBJS) $(GTEST_OBJS:.o=.d): CXXFLAGS += -DGTEST_HAS_PTHREAD=0
endif endif
GTEST_INCLUDES := -I$(SRC_PATH_BARE)/third_party/googletest/src $(GTEST_OBJS) $(GTEST_OBJS:.o=.d): CXXFLAGS += -I$(SRC_PATH_BARE)/third_party/googletest/src
GTEST_INCLUDES += -I$(SRC_PATH_BARE)/third_party/googletest/src/include $(GTEST_OBJS) $(GTEST_OBJS:.o=.d): CXXFLAGS += -I$(SRC_PATH_BARE)/third_party/googletest/src/include
$(GTEST_OBJS) $(GTEST_OBJS:.o=.d): CXXFLAGS += $(GTEST_INCLUDES) OBJS-$(BUILD_LIBVPX) += $(GTEST_OBJS)
OBJS-yes += $(GTEST_OBJS) LIBS-$(BUILD_LIBVPX) += $(BUILD_PFX)libgtest.a $(BUILD_PFX)libgtest_g.a
LIBS-yes += $(BUILD_PFX)libgtest.a $(BUILD_PFX)libgtest_g.a
$(BUILD_PFX)libgtest_g.a: $(GTEST_OBJS) $(BUILD_PFX)libgtest_g.a: $(GTEST_OBJS)
LIBVPX_TEST_OBJS=$(sort $(call objs,$(LIBVPX_TEST_SRCS))) LIBVPX_TEST_OBJS=$(sort $(call objs,$(LIBVPX_TEST_SRCS)))
$(LIBVPX_TEST_OBJS) $(LIBVPX_TEST_OBJS:.o=.d): CXXFLAGS += $(GTEST_INCLUDES) $(LIBVPX_TEST_OBJS) $(LIBVPX_TEST_OBJS:.o=.d): CXXFLAGS += -I$(SRC_PATH_BARE)/third_party/googletest/src
OBJS-yes += $(LIBVPX_TEST_OBJS) $(LIBVPX_TEST_OBJS) $(LIBVPX_TEST_OBJS:.o=.d): CXXFLAGS += -I$(SRC_PATH_BARE)/third_party/googletest/src/include
BINS-yes += $(LIBVPX_TEST_BIN) OBJS-$(BUILD_LIBVPX) += $(LIBVPX_TEST_OBJS)
BINS-$(BUILD_LIBVPX) += $(LIBVPX_TEST_BINS)
CODEC_LIB=$(if $(CONFIG_DEBUG_LIBS),vpx_g,vpx) CODEC_LIB=$(if $(CONFIG_DEBUG_LIBS),vpx_g,vpx)
CODEC_LIB_SUF=$(if $(CONFIG_SHARED),$(SHARED_LIB_SUF),.a) CODEC_LIB_SUF=$(if $(CONFIG_SHARED),.so,.a)
TEST_LIBS := lib$(CODEC_LIB)$(CODEC_LIB_SUF) libgtest.a $(foreach bin,$(LIBVPX_TEST_BINS),\
$(LIBVPX_TEST_BIN): $(TEST_LIBS) $(if $(BUILD_LIBVPX),$(eval $(bin): \
$(eval $(call linkerxx_template,$(LIBVPX_TEST_BIN), \ lib$(CODEC_LIB)$(CODEC_LIB_SUF) libgtest.a ))\
$(if $(BUILD_LIBVPX),$(eval $(call linkerxx_template,$(bin),\
$(LIBVPX_TEST_OBJS) \ $(LIBVPX_TEST_OBJS) \
-L. -lvpx -lgtest $(extralibs) -lm)) -L. -lvpx -lgtest $(extralibs) -lm)\
)))\
$(if $(LIPO_LIBS),$(eval $(call lipo_bin_template,$(bin))))\
ifneq ($(strip $(TEST_INTRA_PRED_SPEED_OBJS)),) endif
$(TEST_INTRA_PRED_SPEED_OBJS) $(TEST_INTRA_PRED_SPEED_OBJS:.o=.d): CXXFLAGS += $(GTEST_INCLUDES)
OBJS-yes += $(TEST_INTRA_PRED_SPEED_OBJS)
BINS-yes += $(TEST_INTRA_PRED_SPEED_BIN)
$(TEST_INTRA_PRED_SPEED_BIN): $(TEST_LIBS)
$(eval $(call linkerxx_template,$(TEST_INTRA_PRED_SPEED_BIN), \
$(TEST_INTRA_PRED_SPEED_OBJS) \
-L. -lvpx -lgtest $(extralibs) -lm))
endif # TEST_INTRA_PRED_SPEED
endif # CONFIG_UNIT_TESTS
# Install test sources only if codec source is included # Install test sources only if codec source is included
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(patsubst $(SRC_PATH_BARE)/%,%,\ INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(patsubst $(SRC_PATH_BARE)/%,%,\
$(shell find $(SRC_PATH_BARE)/third_party/googletest -type f)) $(shell find $(SRC_PATH_BARE)/third_party/googletest -type f))
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(LIBVPX_TEST_SRCS) INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(LIBVPX_TEST_SRCS)
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(TEST_INTRA_PRED_SPEED_SRCS)
define test_shard_template define test_shard_template
test:: test_shard.$(1) test:: test_shard.$(1)
test-no-data-check:: test_shard_ndc.$(1) test_shard.$(1): $(LIBVPX_TEST_BINS) testdata
test_shard.$(1) test_shard_ndc.$(1): $(LIBVPX_TEST_BIN)
@set -e; \ @set -e; \
for t in $(LIBVPX_TEST_BINS); do \
export GTEST_SHARD_INDEX=$(1); \ export GTEST_SHARD_INDEX=$(1); \
export GTEST_TOTAL_SHARDS=$(2); \ export GTEST_TOTAL_SHARDS=$(2); \
$(LIBVPX_TEST_BIN) $$$$t; \
test_shard.$(1): testdata done
.PHONY: test_shard.$(1) .PHONY: test_shard.$(1)
endef endef
@@ -529,15 +525,12 @@ libs.doxy: $(CODEC_DOC_SRCS)
@echo " [CREATE] $@" @echo " [CREATE] $@"
@rm -f $@ @rm -f $@
@echo "INPUT += $^" >> $@ @echo "INPUT += $^" >> $@
@echo "PREDEFINED = VPX_CODEC_DISABLE_COMPAT" >> $@
@echo "INCLUDE_PATH += ." >> $@; @echo "INCLUDE_PATH += ." >> $@;
@echo "ENABLED_SECTIONS += $(sort $(CODEC_DOC_SECTIONS))" >> $@ @echo "ENABLED_SECTIONS += $(sort $(CODEC_DOC_SECTIONS))" >> $@
## Generate rtcd.h for all objects ## Generate rtcd.h for all objects
ifeq ($(CONFIG_DEPENDENCY_TRACKING),yes)
$(OBJS-yes:.o=.d): $(RTCD) $(OBJS-yes:.o=.d): $(RTCD)
else
$(OBJS-yes): $(RTCD)
endif
## Update the global src list ## Update the global src list
SRCS += $(CODEC_SRCS) $(LIBVPX_TEST_SRCS) $(GTEST_SRCS) SRCS += $(CODEC_SRCS) $(LIBVPX_TEST_SRCS) $(GTEST_SRCS)
@@ -555,16 +548,15 @@ ifeq ($(CONFIG_MSVS),yes)
# TODO(tomfinegan): Support running the debug versions of tools? # TODO(tomfinegan): Support running the debug versions of tools?
TEST_BIN_PATH := $(addsuffix /$(TGT_OS:win64=x64)/Release, $(TEST_BIN_PATH)) TEST_BIN_PATH := $(addsuffix /$(TGT_OS:win64=x64)/Release, $(TEST_BIN_PATH))
endif endif
utiltest utiltest-no-data-check: utiltest: testdata
$(qexec)$(SRC_PATH_BARE)/test/vpxdec.sh \ $(qexec)$(SRC_PATH_BARE)/test/vpxdec.sh \
--test-data-path $(LIBVPX_TEST_DATA_PATH) \ --test-data-path $(LIBVPX_TEST_DATA_PATH) \
--bin-path $(TEST_BIN_PATH) --bin-path $(TEST_BIN_PATH)
$(qexec)$(SRC_PATH_BARE)/test/vpxenc.sh \ $(qexec)$(SRC_PATH_BARE)/test/vpxenc.sh \
--test-data-path $(LIBVPX_TEST_DATA_PATH) \ --test-data-path $(LIBVPX_TEST_DATA_PATH) \
--bin-path $(TEST_BIN_PATH) --bin-path $(TEST_BIN_PATH)
utiltest: testdata
else else
utiltest utiltest-no-data-check: utiltest:
@echo Unit tests must be enabled to make the utiltest target. @echo Unit tests must be enabled to make the utiltest target.
endif endif
@@ -582,12 +574,11 @@ ifeq ($(CONFIG_MSVS),yes)
# TODO(tomfinegan): Support running the debug versions of tools? # TODO(tomfinegan): Support running the debug versions of tools?
EXAMPLES_BIN_PATH := $(TGT_OS:win64=x64)/Release EXAMPLES_BIN_PATH := $(TGT_OS:win64=x64)/Release
endif endif
exampletest exampletest-no-data-check: examples exampletest: examples testdata
$(qexec)$(SRC_PATH_BARE)/test/examples.sh \ $(qexec)$(SRC_PATH_BARE)/test/examples.sh \
--test-data-path $(LIBVPX_TEST_DATA_PATH) \ --test-data-path $(LIBVPX_TEST_DATA_PATH) \
--bin-path $(EXAMPLES_BIN_PATH) --bin-path $(EXAMPLES_BIN_PATH)
exampletest: testdata
else else
exampletest exampletest-no-data-check: exampletest:
@echo Unit tests must be enabled to make the exampletest target. @echo Unit tests must be enabled to make the exampletest target.
endif endif

View File

@@ -1,4 +1,4 @@
/*!\mainpage WebM Codec SDK /*!\mainpage WebM VP8 Codec SDK
\section main_contents Page Contents \section main_contents Page Contents
- \ref main_intro - \ref main_intro
@@ -6,11 +6,11 @@
- \ref main_support - \ref main_support
\section main_intro Introduction \section main_intro Introduction
Welcome to the WebM Codec SDK. This SDK allows you to integrate your Welcome to the WebM VP8 Codec SDK. This SDK allows you to integrate your
applications with the VP8 and VP9 video codecs, high quality, royalty free, applications with the VP8 video codec, a high quality, royalty free, open
open source codecs deployed on billions of computers and devices worldwide. source codec deployed on millions of computers and devices worldwide.
This distribution of the WebM Codec SDK includes the following support: This distribution of the WebM VP8 Codec SDK includes the following support:
\if vp8_encoder \if vp8_encoder
- \ref vp8_encoder - \ref vp8_encoder

View File

@@ -24,7 +24,7 @@
#include "md5_utils.h" #include "md5_utils.h"
static void void
byteSwap(UWORD32 *buf, unsigned words) { byteSwap(UWORD32 *buf, unsigned words) {
md5byte *p; md5byte *p;
@@ -150,23 +150,12 @@ MD5Final(md5byte digest[16], struct MD5Context *ctx) {
#define MD5STEP(f,w,x,y,z,in,s) \ #define MD5STEP(f,w,x,y,z,in,s) \
(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(no_sanitize)
#define VPX_NO_UNSIGNED_OVERFLOW_CHECK \
__attribute__((no_sanitize("unsigned-integer-overflow")))
#endif
#endif
#ifndef VPX_NO_UNSIGNED_OVERFLOW_CHECK
#define VPX_NO_UNSIGNED_OVERFLOW_CHECK
#endif
/* /*
* The core of the MD5 algorithm, this alters an existing MD5 hash to * The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks * reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine. * the data and converts bytes into longwords for this routine.
*/ */
VPX_NO_UNSIGNED_OVERFLOW_CHECK void void
MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) { MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) {
register UWORD32 a, b, c, d; register UWORD32 a, b, c, d;
@@ -249,6 +238,4 @@ MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) {
buf[3] += d; buf[3] += d;
} }
#undef VPX_NO_UNSIGNED_OVERFLOW_CHECK
#endif #endif

View File

@@ -88,9 +88,6 @@ void update_rate_histogram(struct rate_hist *hist,
if (now < cfg->rc_buf_initial_sz) if (now < cfg->rc_buf_initial_sz)
return; return;
if (!cfg->rc_target_bitrate)
return;
then = now; then = now;
/* Sum the size over the past rc_buf_sz ms */ /* Sum the size over the past rc_buf_sz ms */

View File

@@ -9,7 +9,7 @@
## ##
# libvpx reverse dependencies (targets that depend on libvpx) # libvpx reverse dependencies (targets that depend on libvpx)
VPX_NONDEPS=$(addsuffix .$(VCPROJ_SFX),vpx gtest) VPX_NONDEPS=$(addsuffix .$(VCPROJ_SFX),vpx gtest obj_int_extract)
VPX_RDEPS=$(foreach vcp,\ VPX_RDEPS=$(foreach vcp,\
$(filter-out $(VPX_NONDEPS),$^), --dep=$(vcp:.$(VCPROJ_SFX)=):vpx) $(filter-out $(VPX_NONDEPS),$^), --dep=$(vcp:.$(VCPROJ_SFX)=):vpx)
@@ -17,6 +17,7 @@ vpx.sln: $(wildcard *.$(VCPROJ_SFX))
@echo " [CREATE] $@" @echo " [CREATE] $@"
$(SRC_PATH_BARE)/build/make/gen_msvs_sln.sh \ $(SRC_PATH_BARE)/build/make/gen_msvs_sln.sh \
$(if $(filter vpx.$(VCPROJ_SFX),$^),$(VPX_RDEPS)) \ $(if $(filter vpx.$(VCPROJ_SFX),$^),$(VPX_RDEPS)) \
--dep=vpx:obj_int_extract \
--dep=test_libvpx:gtest \ --dep=test_libvpx:gtest \
--ver=$(CONFIG_VS_VERSION)\ --ver=$(CONFIG_VS_VERSION)\
--out=$@ $^ --out=$@ $^

View File

@@ -29,20 +29,14 @@ class ACMRandom {
uint16_t Rand16(void) { uint16_t Rand16(void) {
const uint32_t value = const uint32_t value =
random_.Generate(testing::internal::Random::kMaxRange); random_.Generate(testing::internal::Random::kMaxRange);
return (value >> 15) & 0xffff; return (value >> 16) & 0xffff;
}
int16_t Rand9Signed(void) {
// Use 9 bits: values between 255 (0x0FF) and -256 (0x100).
const uint32_t value = random_.Generate(512);
return static_cast<int16_t>(value) - 256;
} }
uint8_t Rand8(void) { uint8_t Rand8(void) {
const uint32_t value = const uint32_t value =
random_.Generate(testing::internal::Random::kMaxRange); random_.Generate(testing::internal::Random::kMaxRange);
// There's a bit more entropy in the upper bits of this implementation. // There's a bit more entropy in the upper bits of this implementation.
return (value >> 23) & 0xff; return (value >> 24) & 0xff;
} }
uint8_t Rand8Extremes(void) { uint8_t Rand8Extremes(void) {

View File

@@ -1,134 +0,0 @@
/*
* Copyright (c) 2015 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 <algorithm>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
namespace {
// Check if any pixel in a 16x16 macroblock varies between frames.
int CheckMb(const vpx_image_t &current, const vpx_image_t &previous,
int mb_r, int mb_c) {
for (int plane = 0; plane < 3; plane++) {
int r = 16 * mb_r;
int c0 = 16 * mb_c;
int r_top = std::min(r + 16, static_cast<int>(current.d_h));
int c_top = std::min(c0 + 16, static_cast<int>(current.d_w));
r = std::max(r, 0);
c0 = std::max(c0, 0);
if (plane > 0 && current.x_chroma_shift) {
c_top = (c_top + 1) >> 1;
c0 >>= 1;
}
if (plane > 0 && current.y_chroma_shift) {
r_top = (r_top + 1) >> 1;
r >>= 1;
}
for (; r < r_top; ++r) {
for (int c = c0; c < c_top; ++c) {
if (current.planes[plane][current.stride[plane] * r + c] !=
previous.planes[plane][previous.stride[plane] * r + c])
return 1;
}
}
}
return 0;
}
void GenerateMap(int mb_rows, int mb_cols, const vpx_image_t &current,
const vpx_image_t &previous, uint8_t *map) {
for (int mb_r = 0; mb_r < mb_rows; ++mb_r) {
for (int mb_c = 0; mb_c < mb_cols; ++mb_c) {
map[mb_r * mb_cols + mb_c] = CheckMb(current, previous, mb_r, mb_c);
}
}
}
const int kAqModeCyclicRefresh = 3;
class ActiveMapRefreshTest
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
protected:
ActiveMapRefreshTest() : EncoderTest(GET_PARAM(0)) {}
virtual ~ActiveMapRefreshTest() {}
virtual void SetUp() {
InitializeConfig();
SetMode(GET_PARAM(1));
cpu_used_ = GET_PARAM(2);
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
::libvpx_test::Y4mVideoSource *y4m_video =
static_cast<libvpx_test::Y4mVideoSource *>(video);
if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, cpu_used_);
encoder->Control(VP9E_SET_AQ_MODE, kAqModeCyclicRefresh);
} else if (video->frame() >= 2 && video->img()) {
vpx_image_t *current = video->img();
vpx_image_t *previous = y4m_holder_->img();
ASSERT_TRUE(previous != NULL);
vpx_active_map_t map = vpx_active_map_t();
const int width = static_cast<int>(current->d_w);
const int height = static_cast<int>(current->d_h);
const int mb_width = (width + 15) / 16;
const int mb_height = (height + 15) / 16;
uint8_t *active_map = new uint8_t[mb_width * mb_height];
GenerateMap(mb_height, mb_width, *current, *previous, active_map);
map.cols = mb_width;
map.rows = mb_height;
map.active_map = active_map;
encoder->Control(VP8E_SET_ACTIVEMAP, &map);
delete[] active_map;
}
if (video->img()) {
y4m_video->SwapBuffers(y4m_holder_);
}
}
int cpu_used_;
::libvpx_test::Y4mVideoSource *y4m_holder_;
};
TEST_P(ActiveMapRefreshTest, Test) {
cfg_.g_lag_in_frames = 0;
cfg_.g_profile = 1;
cfg_.rc_target_bitrate = 600;
cfg_.rc_resize_allowed = 0;
cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 30;
cfg_.g_pass = VPX_RC_ONE_PASS;
cfg_.rc_end_usage = VPX_CBR;
cfg_.kf_max_dist = 90000;
#if CONFIG_VP10
const int nframes = codec_ == &libvpx_test::kVP10 ? 10 : 30;
#else
const int nframes = 30;
#endif // CONFIG_VP10
::libvpx_test::Y4mVideoSource video("desktop_credits.y4m", 0, nframes);
::libvpx_test::Y4mVideoSource video_holder("desktop_credits.y4m", 0, nframes);
video_holder.Begin();
y4m_holder_ = &video_holder;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
#if CONFIG_VP10
VP10_INSTANTIATE_TEST_CASE(ActiveMapRefreshTest,
::testing::Values(::libvpx_test::kRealTime),
::testing::Range(5, 6));
#endif // CONFIG_VP10
} // namespace

View File

@@ -38,7 +38,7 @@ class ActiveMapTest
if (video->frame() == 1) { if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, cpu_used_); encoder->Control(VP8E_SET_CPUUSED, cpu_used_);
} else if (video->frame() == 3) { } else if (video->frame() == 3) {
vpx_active_map_t map = vpx_active_map_t(); vpx_active_map_t map = {0};
uint8_t active_map[9 * 13] = { uint8_t active_map[9 * 13] = {
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0,
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0,
@@ -57,7 +57,7 @@ class ActiveMapTest
map.active_map = active_map; map.active_map = active_map;
encoder->Control(VP8E_SET_ACTIVEMAP, &map); encoder->Control(VP8E_SET_ACTIVEMAP, &map);
} else if (video->frame() == 15) { } else if (video->frame() == 15) {
vpx_active_map_t map = vpx_active_map_t(); vpx_active_map_t map = {0};
map.cols = (kWidth + 15) / 16; map.cols = (kWidth + 15) / 16;
map.rows = (kHeight + 15) / 16; map.rows = (kHeight + 15) / 16;
map.active_map = NULL; map.active_map = NULL;
@@ -65,7 +65,10 @@ class ActiveMapTest
} }
} }
void DoTest() { int cpu_used_;
};
TEST_P(ActiveMapTest, Test) {
// Validate that this non multiple of 64 wide clip encodes // Validate that this non multiple of 64 wide clip encodes
cfg_.g_lag_in_frames = 0; cfg_.g_lag_in_frames = 0;
cfg_.rc_target_bitrate = 400; cfg_.rc_target_bitrate = 400;
@@ -73,31 +76,17 @@ class ActiveMapTest
cfg_.g_pass = VPX_RC_ONE_PASS; cfg_.g_pass = VPX_RC_ONE_PASS;
cfg_.rc_end_usage = VPX_CBR; cfg_.rc_end_usage = VPX_CBR;
cfg_.kf_max_dist = 90000; cfg_.kf_max_dist = 90000;
::libvpx_test::I420VideoSource video("hantro_odd.yuv", kWidth, kHeight, 30, ::libvpx_test::I420VideoSource video("hantro_odd.yuv", kWidth, kHeight, 30,
1, 0, 20); 1, 0, 20);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
int cpu_used_;
};
TEST_P(ActiveMapTest, Test) {
DoTest();
} }
class ActiveMapTestLarge : public ActiveMapTest {}; #define VP9_FACTORY \
static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)
TEST_P(ActiveMapTestLarge, Test) { VP9_INSTANTIATE_TEST_CASE(ActiveMapTest,
DoTest();
}
VP10_INSTANTIATE_TEST_CASE(ActiveMapTestLarge,
::testing::Values(::libvpx_test::kRealTime), ::testing::Values(::libvpx_test::kRealTime),
::testing::Range(0, 5)); ::testing::Range(0, 6));
VP10_INSTANTIATE_TEST_CASE(ActiveMapTest,
::testing::Values(::libvpx_test::kRealTime),
::testing::Range(5, 9));
} // namespace } // namespace

View File

@@ -1,155 +0,0 @@
/*
* Copyright (c) 2016 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 <math.h>
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/postproc.h"
#include "vpx_mem/vpx_mem.h"
namespace {
// TODO(jimbankoski): make width and height integers not unsigned.
typedef void (*AddNoiseFunc)(unsigned char *start, char *noise,
char blackclamp[16], char whiteclamp[16],
char bothclamp[16], unsigned int width,
unsigned int height, int pitch);
class AddNoiseTest
: public ::testing::TestWithParam<AddNoiseFunc> {
public:
virtual void TearDown() {
libvpx_test::ClearSystemState();
}
virtual ~AddNoiseTest() {}
};
double stddev6(char a, char b, char c, char d, char e, char f) {
const double n = (a + b + c + d + e + f) / 6.0;
const double v = ((a - n) * (a - n) + (b - n) * (b - n) + (c - n) * (c - n) +
(d - n) * (d - n) + (e - n) * (e - n) + (f - n) * (f - n)) /
6.0;
return sqrt(v);
}
TEST_P(AddNoiseTest, CheckNoiseAdded) {
DECLARE_ALIGNED(16, char, blackclamp[16]);
DECLARE_ALIGNED(16, char, whiteclamp[16]);
DECLARE_ALIGNED(16, char, bothclamp[16]);
const int width = 64;
const int height = 64;
const int image_size = width * height;
char noise[3072];
const int clamp = vpx_setup_noise(4.4, sizeof(noise), noise);
for (int i = 0; i < 16; i++) {
blackclamp[i] = clamp;
whiteclamp[i] = clamp;
bothclamp[i] = 2 * clamp;
}
uint8_t *const s = reinterpret_cast<uint8_t *>(vpx_calloc(image_size, 1));
memset(s, 99, image_size);
ASM_REGISTER_STATE_CHECK(GetParam()(s, noise, blackclamp, whiteclamp,
bothclamp, width, height, width));
// Check to make sure we don't end up having either the same or no added
// noise either vertically or horizontally.
for (int i = 0; i < image_size - 6 * width - 6; ++i) {
const double hd = stddev6(s[i] - 99, s[i + 1] - 99, s[i + 2] - 99,
s[i + 3] - 99, s[i + 4] - 99, s[i + 5] - 99);
const double vd = stddev6(s[i] - 99, s[i + width] - 99,
s[i + 2 * width] - 99, s[i + 3 * width] - 99,
s[i + 4 * width] - 99, s[i + 5 * width] - 99);
EXPECT_NE(hd, 0);
EXPECT_NE(vd, 0);
}
// Initialize pixels in the image to 255 and check for roll over.
memset(s, 255, image_size);
ASM_REGISTER_STATE_CHECK(GetParam()(s, noise, blackclamp, whiteclamp,
bothclamp, width, height, width));
// Check to make sure don't roll over.
for (int i = 0; i < image_size; ++i) {
EXPECT_GT(static_cast<int>(s[i]), clamp) << "i = " << i;
}
// Initialize pixels in the image to 0 and check for roll under.
memset(s, 0, image_size);
ASM_REGISTER_STATE_CHECK(GetParam()(s, noise, blackclamp, whiteclamp,
bothclamp, width, height, width));
// Check to make sure don't roll under.
for (int i = 0; i < image_size; ++i) {
EXPECT_LT(static_cast<int>(s[i]), 255 - clamp) << "i = " << i;
}
vpx_free(s);
}
TEST_P(AddNoiseTest, CheckCvsAssembly) {
DECLARE_ALIGNED(16, char, blackclamp[16]);
DECLARE_ALIGNED(16, char, whiteclamp[16]);
DECLARE_ALIGNED(16, char, bothclamp[16]);
const int width = 64;
const int height = 64;
const int image_size = width * height;
char noise[3072];
const int clamp = vpx_setup_noise(4.4, sizeof(noise), noise);
for (int i = 0; i < 16; i++) {
blackclamp[i] = clamp;
whiteclamp[i] = clamp;
bothclamp[i] = 2 * clamp;
}
uint8_t *const s = reinterpret_cast<uint8_t *>(vpx_calloc(image_size, 1));
uint8_t *const d = reinterpret_cast<uint8_t *>(vpx_calloc(image_size, 1));
memset(s, 99, image_size);
memset(d, 99, image_size);
srand(0);
ASM_REGISTER_STATE_CHECK(GetParam()(s, noise, blackclamp, whiteclamp,
bothclamp, width, height, width));
srand(0);
ASM_REGISTER_STATE_CHECK(vpx_plane_add_noise_c(d, noise, blackclamp,
whiteclamp, bothclamp,
width, height, width));
for (int i = 0; i < image_size; ++i) {
EXPECT_EQ(static_cast<int>(s[i]), static_cast<int>(d[i])) << "i = " << i;
}
vpx_free(d);
vpx_free(s);
}
INSTANTIATE_TEST_CASE_P(C, AddNoiseTest,
::testing::Values(vpx_plane_add_noise_c));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(SSE2, AddNoiseTest,
::testing::Values(vpx_plane_add_noise_sse2));
#endif
#if HAVE_MSA
INSTANTIATE_TEST_CASE_P(MSA, AddNoiseTest,
::testing::Values(vpx_plane_add_noise_msa));
#endif
} // namespace

View File

@@ -14,86 +14,56 @@
#include "test/util.h" #include "test/util.h"
namespace { namespace {
class AltRefForcedKeyTestLarge // lookahead range: [kLookAheadMin, kLookAheadMax).
: public ::libvpx_test::EncoderTest, const int kLookAheadMin = 5;
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> { const int kLookAheadMax = 26;
class AltRefTest : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<int> {
protected: protected:
AltRefForcedKeyTestLarge() AltRefTest() : EncoderTest(GET_PARAM(0)), altref_count_(0) {}
: EncoderTest(GET_PARAM(0)), virtual ~AltRefTest() {}
encoding_mode_(GET_PARAM(1)),
cpu_used_(GET_PARAM(2)),
forced_kf_frame_num_(1),
frame_num_(0) {}
virtual ~AltRefForcedKeyTestLarge() {}
virtual void SetUp() { virtual void SetUp() {
InitializeConfig(); InitializeConfig();
SetMode(encoding_mode_); SetMode(libvpx_test::kTwoPassGood);
cfg_.rc_end_usage = VPX_VBR;
cfg_.g_threads = 0;
} }
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, virtual void BeginPassHook(unsigned int pass) {
::libvpx_test::Encoder *encoder) { altref_count_ = 0;
if (video->frame() == 0) { }
encoder->Control(VP8E_SET_CPUUSED, cpu_used_);
virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
libvpx_test::Encoder *encoder) {
if (video->frame() == 1) {
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1); encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
// override test default for tile columns if necessary. encoder->Control(VP8E_SET_CPUUSED, 3);
#if CONFIG_VP10_ENCODER
if (GET_PARAM(0) == &libvpx_test::kVP10) {
encoder->Control(VP9E_SET_TILE_COLUMNS, 6);
} }
#endif
}
frame_flags_ =
(video->frame() == forced_kf_frame_num_) ? VPX_EFLAG_FORCE_KF : 0;
} }
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
if (frame_num_ == forced_kf_frame_num_) { if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) ++altref_count_;
ASSERT_TRUE(!!(pkt->data.frame.flags & VPX_FRAME_IS_KEY))
<< "Frame #" << frame_num_ << " isn't a keyframe!";
}
++frame_num_;
} }
::libvpx_test::TestMode encoding_mode_; int altref_count() const { return altref_count_; }
int cpu_used_;
unsigned int forced_kf_frame_num_; private:
unsigned int frame_num_; int altref_count_;
}; };
TEST_P(AltRefForcedKeyTestLarge, Frame1IsKey) { TEST_P(AltRefTest, MonotonicTimestamps) {
const vpx_rational timebase = { 1, 30 }; const vpx_rational timebase = { 33333333, 1000000000 };
const int lag_values[] = { 3, 15, 25, -1 }; cfg_.g_timebase = timebase;
cfg_.rc_target_bitrate = 1000;
cfg_.g_lag_in_frames = GET_PARAM(1);
forced_kf_frame_num_ = 1;
for (int i = 0; lag_values[i] != -1; ++i) {
frame_num_ = 0;
cfg_.g_lag_in_frames = lag_values[i];
libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
timebase.den, timebase.num, 0, 30); timebase.den, timebase.num, 0, 30);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} EXPECT_GE(altref_count(), 1);
} }
TEST_P(AltRefForcedKeyTestLarge, ForcedFrameIsKey) {
const vpx_rational timebase = { 1, 30 };
const int lag_values[] = { 3, 15, 25, -1 };
for (int i = 0; lag_values[i] != -1; ++i) {
frame_num_ = 0;
forced_kf_frame_num_ = lag_values[i] - 1;
cfg_.g_lag_in_frames = lag_values[i];
libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
timebase.den, timebase.num, 0, 30);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
}
VP10_INSTANTIATE_TEST_CASE(
AltRefForcedKeyTestLarge,
::testing::Values(::libvpx_test::kOnePassGood),
::testing::Range(0, 9));
VP8_INSTANTIATE_TEST_CASE(AltRefTest,
::testing::Range(kLookAheadMin, kLookAheadMax));
} // namespace } // namespace

View File

@@ -40,17 +40,9 @@ include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm LOCAL_ARM_MODE := arm
LOCAL_MODULE := libvpx_test LOCAL_MODULE := libvpx_test
LOCAL_STATIC_LIBRARIES := gtest libwebm LOCAL_STATIC_LIBRARIES := gtest libwebm
LOCAL_SHARED_LIBRARIES := vpx
ifeq ($(ENABLE_SHARED),1)
LOCAL_SHARED_LIBRARIES := vpx
else
LOCAL_STATIC_LIBRARIES += vpx
endif
include $(LOCAL_PATH)/test/test.mk include $(LOCAL_PATH)/test/test.mk
LOCAL_C_INCLUDES := $(BINDINGS_DIR) LOCAL_C_INCLUDES := $(BINDINGS_DIR)
FILTERED_SRC := $(sort $(filter %.cc %.c, $(LIBVPX_TEST_SRCS-yes))) FILTERED_SRC := $(sort $(filter %.cc %.c, $(LIBVPX_TEST_SRCS-yes)))
LOCAL_SRC_FILES := $(addprefix ./test/, $(FILTERED_SRC)) LOCAL_SRC_FILES := $(addprefix ./test/, $(FILTERED_SRC))
# some test files depend on *_rtcd.h, ensure they're generated first.
$(eval $(call rtcd_dep_template))
include $(BUILD_EXECUTABLE) include $(BUILD_EXECUTABLE)

View File

@@ -7,6 +7,8 @@
* in the file PATENTS. All contributing project authors may * in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include <climits>
#include <vector>
#include "third_party/googletest/src/include/gtest/gtest.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h" #include "test/codec_factory.h"
#include "test/encode_test_driver.h" #include "test/encode_test_driver.h"
@@ -15,12 +17,11 @@
namespace { namespace {
class AqSegmentTest class AqSegmentTest : public ::libvpx_test::EncoderTest,
: public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWith2Params<
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> { libvpx_test::TestMode, int> {
protected: protected:
AqSegmentTest() : EncoderTest(GET_PARAM(0)) {} AqSegmentTest() : EncoderTest(GET_PARAM(0)) {}
virtual ~AqSegmentTest() {}
virtual void SetUp() { virtual void SetUp() {
InitializeConfig(); InitializeConfig();
@@ -38,22 +39,10 @@ class AqSegmentTest
} }
} }
void DoTest(int aq_mode) { virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
aq_mode_ = aq_mode; if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
cfg_.kf_max_dist = 12; }
cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 6;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_target_bitrate = 300;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv",
352, 288, 30, 1, 0, 15);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
int set_cpu_used_; int set_cpu_used_;
int aq_mode_; int aq_mode_;
}; };
@@ -61,42 +50,70 @@ class AqSegmentTest
// Validate that this AQ segmentation mode (AQ=1, variance_ap) // Validate that this AQ segmentation mode (AQ=1, variance_ap)
// encodes and decodes without a mismatch. // encodes and decodes without a mismatch.
TEST_P(AqSegmentTest, TestNoMisMatchAQ1) { TEST_P(AqSegmentTest, TestNoMisMatchAQ1) {
DoTest(1); cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_target_bitrate = 300;
aq_mode_ = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 100);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
// Validate that this AQ segmentation mode (AQ=2, complexity_aq) // Validate that this AQ segmentation mode (AQ=2, complexity_aq)
// encodes and decodes without a mismatch. // encodes and decodes without a mismatch.
TEST_P(AqSegmentTest, TestNoMisMatchAQ2) { TEST_P(AqSegmentTest, TestNoMisMatchAQ2) {
DoTest(2); cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_target_bitrate = 300;
aq_mode_ = 2;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 100);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
// Validate that this AQ segmentation mode (AQ=3, cyclic_refresh_aq) // Validate that this AQ segmentation mode (AQ=3, cyclic_refresh_aq)
// encodes and decodes without a mismatch. // encodes and decodes without a mismatch.
TEST_P(AqSegmentTest, TestNoMisMatchAQ3) { TEST_P(AqSegmentTest, TestNoMisMatchAQ3) {
DoTest(3); cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_target_bitrate = 300;
aq_mode_ = 3;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 100);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
class AqSegmentTestLarge : public AqSegmentTest {}; using std::tr1::make_tuple;
TEST_P(AqSegmentTestLarge, TestNoMisMatchAQ1) { #define VP9_FACTORY \
DoTest(1); static_cast<const libvpx_test::CodecFactory*> (&libvpx_test::kVP9)
}
TEST_P(AqSegmentTestLarge, TestNoMisMatchAQ2) { VP9_INSTANTIATE_TEST_CASE(AqSegmentTest,
DoTest(2);
}
TEST_P(AqSegmentTestLarge, TestNoMisMatchAQ3) {
DoTest(3);
}
VP10_INSTANTIATE_TEST_CASE(AqSegmentTest,
::testing::Values(::libvpx_test::kRealTime, ::testing::Values(::libvpx_test::kRealTime,
::libvpx_test::kOnePassGood), ::libvpx_test::kOnePassGood),
::testing::Range(5, 9)); ::testing::Range(3, 9));
VP10_INSTANTIATE_TEST_CASE(AqSegmentTestLarge,
::testing::Values(::libvpx_test::kRealTime,
::libvpx_test::kOnePassGood),
::testing::Range(3, 5));
} // namespace } // namespace

View File

@@ -1,249 +0,0 @@
/*
* Copyright (c) 2015 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 "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "test/yuv_video_source.h"
#include "vp10/encoder/ratectrl.h"
namespace {
const unsigned int kFrames = 100;
const int kBitrate = 500;
#define ARF_NOT_SEEN 1000001
#define ARF_SEEN_ONCE 1000000
typedef struct {
const char *filename;
unsigned int width;
unsigned int height;
unsigned int framerate_num;
unsigned int framerate_den;
unsigned int input_bit_depth;
vpx_img_fmt fmt;
vpx_bit_depth_t bit_depth;
unsigned int profile;
} TestVideoParam;
typedef struct {
libvpx_test::TestMode mode;
int cpu_used;
} TestEncodeParam;
const TestVideoParam kTestVectors[] = {
// artificially increase framerate to trigger default check
{"hantro_collage_w352h288.yuv", 352, 288, 5000, 1,
8, VPX_IMG_FMT_I420, VPX_BITS_8, 0},
{"hantro_collage_w352h288.yuv", 352, 288, 30, 1,
8, VPX_IMG_FMT_I420, VPX_BITS_8, 0},
{"rush_hour_444.y4m", 352, 288, 30, 1,
8, VPX_IMG_FMT_I444, VPX_BITS_8, 1},
#if CONFIG_VPX_HIGHBITDEPTH
// Add list of profile 2/3 test videos here ...
#endif // CONFIG_VPX_HIGHBITDEPTH
};
const TestEncodeParam kEncodeVectors[] = {
{::libvpx_test::kOnePassGood, 2},
{::libvpx_test::kOnePassGood, 5},
{::libvpx_test::kTwoPassGood, 1},
{::libvpx_test::kTwoPassGood, 2},
{::libvpx_test::kTwoPassGood, 5},
{::libvpx_test::kRealTime, 5},
};
const int kMinArfVectors[] = {
// NOTE: 0 refers to the default built-in logic in:
// vp9_rc_get_default_min_gf_interval(...)
0, 4, 8, 12, 15
};
int is_extension_y4m(const char *filename) {
const char *dot = strrchr(filename, '.');
if (!dot || dot == filename)
return 0;
else
return !strcmp(dot, ".y4m");
}
class ArfFreqTestLarge
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith3Params<TestVideoParam, \
TestEncodeParam, int> {
protected:
ArfFreqTestLarge()
: EncoderTest(GET_PARAM(0)),
test_video_param_(GET_PARAM(1)),
test_encode_param_(GET_PARAM(2)),
min_arf_requested_(GET_PARAM(3)) {
}
virtual ~ArfFreqTestLarge() {}
virtual void SetUp() {
InitializeConfig();
SetMode(test_encode_param_.mode);
if (test_encode_param_.mode != ::libvpx_test::kRealTime) {
cfg_.g_lag_in_frames = 25;
cfg_.rc_end_usage = VPX_VBR;
} else {
cfg_.g_lag_in_frames = 0;
cfg_.rc_end_usage = VPX_CBR;
cfg_.rc_buf_sz = 1000;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 600;
}
dec_cfg_.threads = 4;
}
virtual void BeginPassHook(unsigned int) {
min_run_ = ARF_NOT_SEEN;
run_of_visible_frames_ = 0;
}
int GetNumFramesInPkt(const vpx_codec_cx_pkt_t *pkt) {
const uint8_t *buffer = reinterpret_cast<uint8_t*>(pkt->data.frame.buf);
const uint8_t marker = buffer[pkt->data.frame.sz - 1];
const int mag = ((marker >> 3) & 3) + 1;
int frames = (marker & 0x7) + 1;
const unsigned int index_sz = 2 + mag * frames;
// Check for superframe or not.
// Assume superframe has only one visible frame, the rest being
// invisible. If superframe index is not found, then there is only
// one frame.
if (!((marker & 0xe0) == 0xc0 &&
pkt->data.frame.sz >= index_sz &&
buffer[pkt->data.frame.sz - index_sz] == marker)) {
frames = 1;
}
return frames;
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
return;
const int frames = GetNumFramesInPkt(pkt);
if (frames == 1) {
run_of_visible_frames_++;
} else if (frames == 2) {
if (min_run_ == ARF_NOT_SEEN) {
min_run_ = ARF_SEEN_ONCE;
} else if (min_run_ == ARF_SEEN_ONCE ||
run_of_visible_frames_ < min_run_) {
min_run_ = run_of_visible_frames_;
}
run_of_visible_frames_ = 1;
} else {
min_run_ = 0;
run_of_visible_frames_ = 1;
}
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 0) {
encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
encoder->Control(VP9E_SET_TILE_COLUMNS, 4);
encoder->Control(VP8E_SET_CPUUSED, test_encode_param_.cpu_used);
encoder->Control(VP9E_SET_MIN_GF_INTERVAL, min_arf_requested_);
if (test_encode_param_.mode != ::libvpx_test::kRealTime) {
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
encoder->Control(VP8E_SET_ARNR_TYPE, 3);
}
}
}
int GetMinVisibleRun() const {
return min_run_;
}
int GetMinArfDistanceRequested() const {
if (min_arf_requested_)
return min_arf_requested_;
else
return vp10_rc_get_default_min_gf_interval(
test_video_param_.width, test_video_param_.height,
(double)test_video_param_.framerate_num /
test_video_param_.framerate_den);
}
TestVideoParam test_video_param_;
TestEncodeParam test_encode_param_;
private:
int min_arf_requested_;
int min_run_;
int run_of_visible_frames_;
};
TEST_P(ArfFreqTestLarge, MinArfFreqTest) {
cfg_.rc_target_bitrate = kBitrate;
cfg_.g_error_resilient = 0;
cfg_.g_profile = test_video_param_.profile;
cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
cfg_.g_bit_depth = test_video_param_.bit_depth;
init_flags_ = VPX_CODEC_USE_PSNR;
if (cfg_.g_bit_depth > 8)
init_flags_ |= VPX_CODEC_USE_HIGHBITDEPTH;
testing::internal::scoped_ptr<libvpx_test::VideoSource> video;
if (is_extension_y4m(test_video_param_.filename)) {
video.reset(new libvpx_test::Y4mVideoSource(test_video_param_.filename,
0, kFrames));
} else {
video.reset(new libvpx_test::YUVVideoSource(test_video_param_.filename,
test_video_param_.fmt,
test_video_param_.width,
test_video_param_.height,
test_video_param_.framerate_num,
test_video_param_.framerate_den,
0, kFrames));
}
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
const int min_run = GetMinVisibleRun();
const int min_arf_dist_requested = GetMinArfDistanceRequested();
if (min_run != ARF_NOT_SEEN && min_run != ARF_SEEN_ONCE) {
const int min_arf_dist = min_run + 1;
EXPECT_GE(min_arf_dist, min_arf_dist_requested);
}
}
#if CONFIG_VPX_HIGHBITDEPTH || CONFIG_EXT_REFS
#if CONFIG_VP10_ENCODER
// TODO(angiebird): 25-29 fail in high bitdepth mode.
// TODO(zoeliu): This ArfFreqTest does not work with BWDREF_FRAME, as
// BWDREF_FRAME is also a non-show frame, and the minimum run between two
// consecutive BWDREF_FRAME's may vary between 1 and any arbitrary positive
// number as long as it does not exceed the gf_group interval.
INSTANTIATE_TEST_CASE_P(
DISABLED_VP10, ArfFreqTestLarge,
::testing::Combine(
::testing::Values(static_cast<const libvpx_test::CodecFactory *>(
&libvpx_test::kVP10)),
::testing::ValuesIn(kTestVectors),
::testing::ValuesIn(kEncodeVectors),
::testing::ValuesIn(kMinArfVectors)));
#endif // CONFIG_VP10_ENCODER
#else
VP10_INSTANTIATE_TEST_CASE(
ArfFreqTestLarge,
::testing::ValuesIn(kTestVectors),
::testing::ValuesIn(kEncodeVectors),
::testing::ValuesIn(kMinArfVectors));
#endif // CONFIG_VPX_HIGHBITDEPTH || CONFIG_EXT_REFS
} // namespace

View File

@@ -1,411 +0,0 @@
/*
* Copyright (c) 2012 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 <stdio.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "vpx_mem/vpx_mem.h"
using libvpx_test::ACMRandom;
namespace {
class AverageTestBase : public ::testing::Test {
public:
AverageTestBase(int width, int height) : width_(width), height_(height) {}
static void SetUpTestCase() {
source_data_ = reinterpret_cast<uint8_t*>(
vpx_memalign(kDataAlignment, kDataBlockSize));
}
static void TearDownTestCase() {
vpx_free(source_data_);
source_data_ = NULL;
}
virtual void TearDown() {
libvpx_test::ClearSystemState();
}
protected:
// Handle blocks up to 4 blocks 64x64 with stride up to 128
static const int kDataAlignment = 16;
static const int kDataBlockSize = 64 * 128;
virtual void SetUp() {
source_stride_ = (width_ + 31) & ~31;
rnd_.Reset(ACMRandom::DeterministicSeed());
}
// Sum Pixels
unsigned int ReferenceAverage8x8(const uint8_t* source, int pitch) {
unsigned int average = 0;
for (int h = 0; h < 8; ++h)
for (int w = 0; w < 8; ++w)
average += source[h * pitch + w];
return ((average + 32) >> 6);
}
unsigned int ReferenceAverage4x4(const uint8_t* source, int pitch) {
unsigned int average = 0;
for (int h = 0; h < 4; ++h)
for (int w = 0; w < 4; ++w)
average += source[h * pitch + w];
return ((average + 8) >> 4);
}
void FillConstant(uint8_t fill_constant) {
for (int i = 0; i < width_ * height_; ++i) {
source_data_[i] = fill_constant;
}
}
void FillRandom() {
for (int i = 0; i < width_ * height_; ++i) {
source_data_[i] = rnd_.Rand8();
}
}
int width_, height_;
static uint8_t* source_data_;
int source_stride_;
ACMRandom rnd_;
};
typedef unsigned int (*AverageFunction)(const uint8_t* s, int pitch);
typedef std::tr1::tuple<int, int, int, int, AverageFunction> AvgFunc;
class AverageTest
: public AverageTestBase,
public ::testing::WithParamInterface<AvgFunc>{
public:
AverageTest() : AverageTestBase(GET_PARAM(0), GET_PARAM(1)) {}
protected:
void CheckAverages() {
unsigned int expected = 0;
if (GET_PARAM(3) == 8) {
expected = ReferenceAverage8x8(source_data_+ GET_PARAM(2),
source_stride_);
} else if (GET_PARAM(3) == 4) {
expected = ReferenceAverage4x4(source_data_+ GET_PARAM(2),
source_stride_);
}
ASM_REGISTER_STATE_CHECK(GET_PARAM(4)(source_data_+ GET_PARAM(2),
source_stride_));
unsigned int actual = GET_PARAM(4)(source_data_+ GET_PARAM(2),
source_stride_);
EXPECT_EQ(expected, actual);
}
};
typedef void (*IntProRowFunc)(int16_t hbuf[16], uint8_t const *ref,
const int ref_stride, const int height);
typedef std::tr1::tuple<int, IntProRowFunc, IntProRowFunc> IntProRowParam;
class IntProRowTest
: public AverageTestBase,
public ::testing::WithParamInterface<IntProRowParam> {
public:
IntProRowTest()
: AverageTestBase(16, GET_PARAM(0)),
hbuf_asm_(NULL),
hbuf_c_(NULL) {
asm_func_ = GET_PARAM(1);
c_func_ = GET_PARAM(2);
}
protected:
virtual void SetUp() {
hbuf_asm_ = reinterpret_cast<int16_t*>(
vpx_memalign(kDataAlignment, sizeof(*hbuf_asm_) * 16));
hbuf_c_ = reinterpret_cast<int16_t*>(
vpx_memalign(kDataAlignment, sizeof(*hbuf_c_) * 16));
}
virtual void TearDown() {
vpx_free(hbuf_c_);
hbuf_c_ = NULL;
vpx_free(hbuf_asm_);
hbuf_asm_ = NULL;
}
void RunComparison() {
ASM_REGISTER_STATE_CHECK(c_func_(hbuf_c_, source_data_, 0, height_));
ASM_REGISTER_STATE_CHECK(asm_func_(hbuf_asm_, source_data_, 0, height_));
EXPECT_EQ(0, memcmp(hbuf_c_, hbuf_asm_, sizeof(*hbuf_c_) * 16))
<< "Output mismatch";
}
private:
IntProRowFunc asm_func_;
IntProRowFunc c_func_;
int16_t *hbuf_asm_;
int16_t *hbuf_c_;
};
typedef int16_t (*IntProColFunc)(uint8_t const *ref, const int width);
typedef std::tr1::tuple<int, IntProColFunc, IntProColFunc> IntProColParam;
class IntProColTest
: public AverageTestBase,
public ::testing::WithParamInterface<IntProColParam> {
public:
IntProColTest() : AverageTestBase(GET_PARAM(0), 1), sum_asm_(0), sum_c_(0) {
asm_func_ = GET_PARAM(1);
c_func_ = GET_PARAM(2);
}
protected:
void RunComparison() {
ASM_REGISTER_STATE_CHECK(sum_c_ = c_func_(source_data_, width_));
ASM_REGISTER_STATE_CHECK(sum_asm_ = asm_func_(source_data_, width_));
EXPECT_EQ(sum_c_, sum_asm_) << "Output mismatch";
}
private:
IntProColFunc asm_func_;
IntProColFunc c_func_;
int16_t sum_asm_;
int16_t sum_c_;
};
typedef int (*SatdFunc)(const int16_t *coeffs, int length);
typedef std::tr1::tuple<int, SatdFunc> SatdTestParam;
class SatdTest
: public ::testing::Test,
public ::testing::WithParamInterface<SatdTestParam> {
protected:
virtual void SetUp() {
satd_size_ = GET_PARAM(0);
satd_func_ = GET_PARAM(1);
rnd_.Reset(ACMRandom::DeterministicSeed());
src_ = reinterpret_cast<int16_t*>(
vpx_memalign(16, sizeof(*src_) * satd_size_));
ASSERT_TRUE(src_ != NULL);
}
virtual void TearDown() {
libvpx_test::ClearSystemState();
vpx_free(src_);
}
void FillConstant(const int16_t val) {
for (int i = 0; i < satd_size_; ++i) src_[i] = val;
}
void FillRandom() {
for (int i = 0; i < satd_size_; ++i) src_[i] = rnd_.Rand16();
}
void Check(const int expected) {
int total;
ASM_REGISTER_STATE_CHECK(total = satd_func_(src_, satd_size_));
EXPECT_EQ(expected, total);
}
int satd_size_;
private:
int16_t *src_;
SatdFunc satd_func_;
ACMRandom rnd_;
};
uint8_t* AverageTestBase::source_data_ = NULL;
TEST_P(AverageTest, MinValue) {
FillConstant(0);
CheckAverages();
}
TEST_P(AverageTest, MaxValue) {
FillConstant(255);
CheckAverages();
}
TEST_P(AverageTest, Random) {
// The reference frame, but not the source frame, may be unaligned for
// certain types of searches.
for (int i = 0; i < 1000; i++) {
FillRandom();
CheckAverages();
}
}
TEST_P(IntProRowTest, MinValue) {
FillConstant(0);
RunComparison();
}
TEST_P(IntProRowTest, MaxValue) {
FillConstant(255);
RunComparison();
}
TEST_P(IntProRowTest, Random) {
FillRandom();
RunComparison();
}
TEST_P(IntProColTest, MinValue) {
FillConstant(0);
RunComparison();
}
TEST_P(IntProColTest, MaxValue) {
FillConstant(255);
RunComparison();
}
TEST_P(IntProColTest, Random) {
FillRandom();
RunComparison();
}
TEST_P(SatdTest, MinValue) {
const int kMin = -32640;
const int expected = -kMin * satd_size_;
FillConstant(kMin);
Check(expected);
}
TEST_P(SatdTest, MaxValue) {
const int kMax = 32640;
const int expected = kMax * satd_size_;
FillConstant(kMax);
Check(expected);
}
TEST_P(SatdTest, Random) {
int expected;
switch (satd_size_) {
case 16: expected = 205298; break;
case 64: expected = 1113950; break;
case 256: expected = 4268415; break;
case 1024: expected = 16954082; break;
default:
FAIL() << "Invalid satd size (" << satd_size_
<< ") valid: 16/64/256/1024";
}
FillRandom();
Check(expected);
}
using std::tr1::make_tuple;
INSTANTIATE_TEST_CASE_P(
C, AverageTest,
::testing::Values(
make_tuple(16, 16, 1, 8, &vpx_avg_8x8_c),
make_tuple(16, 16, 1, 4, &vpx_avg_4x4_c)));
INSTANTIATE_TEST_CASE_P(
C, SatdTest,
::testing::Values(
make_tuple(16, &vpx_satd_c),
make_tuple(64, &vpx_satd_c),
make_tuple(256, &vpx_satd_c),
make_tuple(1024, &vpx_satd_c)));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(
SSE2, AverageTest,
::testing::Values(
make_tuple(16, 16, 0, 8, &vpx_avg_8x8_sse2),
make_tuple(16, 16, 5, 8, &vpx_avg_8x8_sse2),
make_tuple(32, 32, 15, 8, &vpx_avg_8x8_sse2),
make_tuple(16, 16, 0, 4, &vpx_avg_4x4_sse2),
make_tuple(16, 16, 5, 4, &vpx_avg_4x4_sse2),
make_tuple(32, 32, 15, 4, &vpx_avg_4x4_sse2)));
INSTANTIATE_TEST_CASE_P(
SSE2, IntProRowTest, ::testing::Values(
make_tuple(16, &vpx_int_pro_row_sse2, &vpx_int_pro_row_c),
make_tuple(32, &vpx_int_pro_row_sse2, &vpx_int_pro_row_c),
make_tuple(64, &vpx_int_pro_row_sse2, &vpx_int_pro_row_c)));
INSTANTIATE_TEST_CASE_P(
SSE2, IntProColTest, ::testing::Values(
make_tuple(16, &vpx_int_pro_col_sse2, &vpx_int_pro_col_c),
make_tuple(32, &vpx_int_pro_col_sse2, &vpx_int_pro_col_c),
make_tuple(64, &vpx_int_pro_col_sse2, &vpx_int_pro_col_c)));
INSTANTIATE_TEST_CASE_P(
SSE2, SatdTest,
::testing::Values(
make_tuple(16, &vpx_satd_sse2),
make_tuple(64, &vpx_satd_sse2),
make_tuple(256, &vpx_satd_sse2),
make_tuple(1024, &vpx_satd_sse2)));
#endif
#if HAVE_NEON
INSTANTIATE_TEST_CASE_P(
NEON, AverageTest,
::testing::Values(
make_tuple(16, 16, 0, 8, &vpx_avg_8x8_neon),
make_tuple(16, 16, 5, 8, &vpx_avg_8x8_neon),
make_tuple(32, 32, 15, 8, &vpx_avg_8x8_neon),
make_tuple(16, 16, 0, 4, &vpx_avg_4x4_neon),
make_tuple(16, 16, 5, 4, &vpx_avg_4x4_neon),
make_tuple(32, 32, 15, 4, &vpx_avg_4x4_neon)));
INSTANTIATE_TEST_CASE_P(
NEON, IntProRowTest, ::testing::Values(
make_tuple(16, &vpx_int_pro_row_neon, &vpx_int_pro_row_c),
make_tuple(32, &vpx_int_pro_row_neon, &vpx_int_pro_row_c),
make_tuple(64, &vpx_int_pro_row_neon, &vpx_int_pro_row_c)));
INSTANTIATE_TEST_CASE_P(
NEON, IntProColTest, ::testing::Values(
make_tuple(16, &vpx_int_pro_col_neon, &vpx_int_pro_col_c),
make_tuple(32, &vpx_int_pro_col_neon, &vpx_int_pro_col_c),
make_tuple(64, &vpx_int_pro_col_neon, &vpx_int_pro_col_c)));
INSTANTIATE_TEST_CASE_P(
NEON, SatdTest,
::testing::Values(
make_tuple(16, &vpx_satd_neon),
make_tuple(64, &vpx_satd_neon),
make_tuple(256, &vpx_satd_neon),
make_tuple(1024, &vpx_satd_neon)));
#endif
#if HAVE_MSA
INSTANTIATE_TEST_CASE_P(
MSA, AverageTest,
::testing::Values(
make_tuple(16, 16, 0, 8, &vpx_avg_8x8_msa),
make_tuple(16, 16, 5, 8, &vpx_avg_8x8_msa),
make_tuple(32, 32, 15, 8, &vpx_avg_8x8_msa),
make_tuple(16, 16, 0, 4, &vpx_avg_4x4_msa),
make_tuple(16, 16, 5, 4, &vpx_avg_4x4_msa),
make_tuple(32, 32, 15, 4, &vpx_avg_4x4_msa)));
#endif
} // namespace

View File

@@ -1,367 +0,0 @@
/*
* Copyright (c) 2016 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 <math.h>
#include <stdlib.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/register_state_check.h"
#include "test/function_equivalence_test.h"
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "./vp10_rtcd.h"
#include "vp10/common/enums.h"
#include "vpx_dsp/blend.h"
using libvpx_test::FunctionEquivalenceTest;
namespace {
template<typename F, typename T>
class BlendA64Mask1DTest : public FunctionEquivalenceTest<F> {
public:
static const int kIterations = 10000;
static const int kMaxWidth = MAX_SB_SIZE * 5; // * 5 to cover longer strides
static const int kMaxHeight = MAX_SB_SIZE;
static const int kBufSize = kMaxWidth * kMaxHeight;
static const int kMaxMaskWidth = 2 * MAX_SB_SIZE;
static const int kMaxMaskSize = kMaxMaskWidth;
virtual ~BlendA64Mask1DTest() {}
virtual void Execute(const T *p_src0, const T *p_src1) = 0;
void Common() {
w_ = 1 << this->rng_(MAX_SB_SIZE_LOG2 + 1);
h_ = 1 << this->rng_(MAX_SB_SIZE_LOG2 + 1);
dst_offset_ = this->rng_(33);
dst_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
src0_offset_ = this->rng_(33);
src0_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
src1_offset_ = this->rng_(33);
src1_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
T *p_src0;
T *p_src1;
switch (this->rng_(3)) {
case 0: // Separate sources
p_src0 = src0_;
p_src1 = src1_;
break;
case 1: // src0 == dst
p_src0 = dst_tst_;
src0_stride_ = dst_stride_;
src0_offset_ = dst_offset_;
p_src1 = src1_;
break;
case 2: // src1 == dst
p_src0 = src0_;
p_src1 = dst_tst_;
src1_stride_ = dst_stride_;
src1_offset_ = dst_offset_;
break;
default:
FAIL();
}
Execute(p_src0, p_src1);
for (int r = 0 ; r < h_ ; ++r) {
for (int c = 0 ; c < w_ ; ++c) {
ASSERT_EQ(dst_ref_[dst_offset_ + r * dst_stride_ + c],
dst_tst_[dst_offset_ + r * dst_stride_ + c]);
}
}
}
T dst_ref_[kBufSize];
T dst_tst_[kBufSize];
size_t dst_stride_;
size_t dst_offset_;
T src0_[kBufSize];
size_t src0_stride_;
size_t src0_offset_;
T src1_[kBufSize];
size_t src1_stride_;
size_t src1_offset_;
uint8_t mask_[kMaxMaskSize];
int w_;
int h_;
};
//////////////////////////////////////////////////////////////////////////////
// 8 bit version
//////////////////////////////////////////////////////////////////////////////
typedef void (*F8B)(uint8_t *dst, uint32_t dst_stride,
const uint8_t *src0, uint32_t src0_stride,
const uint8_t *src1, uint32_t src1_stride,
const uint8_t *mask, int h, int w);
typedef libvpx_test::FuncParam<F8B> TestFuncs;
class BlendA64Mask1DTest8B : public BlendA64Mask1DTest<F8B, uint8_t> {
protected:
void Execute(const uint8_t *p_src0, const uint8_t *p_src1) {
params_.ref_func(dst_ref_ + dst_offset_, dst_stride_,
p_src0 + src0_offset_, src0_stride_,
p_src1 + src1_offset_, src1_stride_, mask_, h_, w_);
ASM_REGISTER_STATE_CHECK(
params_.tst_func(dst_tst_ + dst_offset_, dst_stride_,
p_src0 + src0_offset_, src0_stride_,
p_src1 + src1_offset_, src1_stride_, mask_, h_, w_));
}
};
TEST_P(BlendA64Mask1DTest8B, RandomValues) {
for (int iter = 0 ; iter < kIterations && !HasFatalFailure(); ++iter) {
for (int i = 0 ; i < kBufSize ; ++i) {
dst_ref_[i] = rng_.Rand8();
dst_tst_[i] = rng_.Rand8();
src0_[i] = rng_.Rand8();
src1_[i] = rng_.Rand8();
}
for (int i = 0 ; i < kMaxMaskSize ; ++i)
mask_[i] = rng_(VPX_BLEND_A64_MAX_ALPHA + 1);
Common();
}
}
TEST_P(BlendA64Mask1DTest8B, ExtremeValues) {
for (int iter = 0 ; iter < kIterations && !HasFatalFailure(); ++iter) {
for (int i = 0 ; i < kBufSize ; ++i) {
dst_ref_[i] = rng_(2) + 254;
dst_tst_[i] = rng_(2) + 254;
src0_[i] = rng_(2) + 254;
src1_[i] = rng_(2) + 254;
}
for (int i = 0 ; i < kMaxMaskSize ; ++i)
mask_[i] = rng_(2) + VPX_BLEND_A64_MAX_ALPHA - 1;
Common();
}
}
static void blend_a64_hmask_ref(
uint8_t *dst, uint32_t dst_stride,
const uint8_t *src0, uint32_t src0_stride,
const uint8_t *src1, uint32_t src1_stride,
const uint8_t *mask, int h, int w) {
uint8_t mask2d[BlendA64Mask1DTest8B::kMaxMaskSize]
[BlendA64Mask1DTest8B::kMaxMaskSize];
for (int row = 0 ; row < h ; ++row)
for (int col = 0 ; col < w ; ++col)
mask2d[row][col] = mask[col];
vpx_blend_a64_mask_c(dst, dst_stride,
src0, src0_stride,
src1, src1_stride,
&mask2d[0][0], BlendA64Mask1DTest8B::kMaxMaskSize,
h, w, 0, 0);
}
static void blend_a64_vmask_ref(
uint8_t *dst, uint32_t dst_stride,
const uint8_t *src0, uint32_t src0_stride,
const uint8_t *src1, uint32_t src1_stride,
const uint8_t *mask, int h, int w) {
uint8_t mask2d[BlendA64Mask1DTest8B::kMaxMaskSize]
[BlendA64Mask1DTest8B::kMaxMaskSize];
for (int row = 0 ; row < h ; ++row)
for (int col = 0 ; col < w ; ++col)
mask2d[row][col] = mask[row];
vpx_blend_a64_mask_c(dst, dst_stride,
src0, src0_stride,
src1, src1_stride,
&mask2d[0][0], BlendA64Mask1DTest8B::kMaxMaskSize,
h, w, 0, 0);
}
INSTANTIATE_TEST_CASE_P(
C, BlendA64Mask1DTest8B,
::testing::Values(TestFuncs(blend_a64_hmask_ref, vpx_blend_a64_hmask_c),
TestFuncs(blend_a64_vmask_ref, vpx_blend_a64_vmask_c)));
#if HAVE_SSE4_1
INSTANTIATE_TEST_CASE_P(
SSE4_1, BlendA64Mask1DTest8B,
::testing::Values(
TestFuncs(blend_a64_hmask_ref, vpx_blend_a64_hmask_sse4_1),
TestFuncs(blend_a64_vmask_ref, vpx_blend_a64_vmask_sse4_1)));
#endif // HAVE_SSE4_1
#if CONFIG_VPX_HIGHBITDEPTH
//////////////////////////////////////////////////////////////////////////////
// High bit-depth version
//////////////////////////////////////////////////////////////////////////////
typedef void (*FHBD)(uint8_t *dst, uint32_t dst_stride,
const uint8_t *src0, uint32_t src0_stride,
const uint8_t *src1, uint32_t src1_stride,
const uint8_t *mask, int h, int w, int bd);
typedef libvpx_test::FuncParam<FHBD> TestFuncsHBD;
class BlendA64Mask1DTestHBD : public BlendA64Mask1DTest<FHBD, uint16_t> {
protected:
void Execute(const uint16_t *p_src0, const uint16_t *p_src1) {
params_.ref_func(CONVERT_TO_BYTEPTR(dst_ref_ + dst_offset_), dst_stride_,
CONVERT_TO_BYTEPTR(p_src0 + src0_offset_), src0_stride_,
CONVERT_TO_BYTEPTR(p_src1 + src1_offset_), src1_stride_,
mask_, h_, w_, bit_depth_);
ASM_REGISTER_STATE_CHECK(params_.tst_func(
CONVERT_TO_BYTEPTR(dst_tst_ + dst_offset_), dst_stride_,
CONVERT_TO_BYTEPTR(p_src0 + src0_offset_), src0_stride_,
CONVERT_TO_BYTEPTR(p_src1 + src1_offset_), src1_stride_,
mask_, h_, w_, bit_depth_));
}
int bit_depth_;
};
TEST_P(BlendA64Mask1DTestHBD, RandomValues) {
for (int iter = 0 ; iter < kIterations && !HasFatalFailure(); ++iter) {
switch (rng_(3)) {
case 0:
bit_depth_ = 8;
break;
case 1:
bit_depth_ = 10;
break;
default:
bit_depth_ = 12;
break;
}
const int hi = 1 << bit_depth_;
for (int i = 0 ; i < kBufSize ; ++i) {
dst_ref_[i] = rng_(hi);
dst_tst_[i] = rng_(hi);
src0_[i] = rng_(hi);
src1_[i] = rng_(hi);
}
for (int i = 0 ; i < kMaxMaskSize ; ++i)
mask_[i] = rng_(VPX_BLEND_A64_MAX_ALPHA + 1);
Common();
}
}
TEST_P(BlendA64Mask1DTestHBD, ExtremeValues) {
for (int iter = 0 ; iter < 1000 && !HasFatalFailure(); ++iter) {
switch (rng_(3)) {
case 0:
bit_depth_ = 8;
break;
case 1:
bit_depth_ = 10;
break;
default:
bit_depth_ = 12;
break;
}
const int hi = 1 << bit_depth_;
const int lo = hi - 2;
for (int i = 0 ; i < kBufSize ; ++i) {
dst_ref_[i] = rng_(hi - lo) + lo;
dst_tst_[i] = rng_(hi - lo) + lo;
src0_[i] = rng_(hi - lo) + lo;
src1_[i] = rng_(hi - lo) + lo;
}
for (int i = 0 ; i < kMaxMaskSize ; ++i)
mask_[i] = rng_(2) + VPX_BLEND_A64_MAX_ALPHA - 1;
Common();
}
}
static void highbd_blend_a64_hmask_ref(
uint8_t *dst, uint32_t dst_stride,
const uint8_t *src0, uint32_t src0_stride,
const uint8_t *src1, uint32_t src1_stride,
const uint8_t *mask, int h, int w, int bd) {
uint8_t mask2d[BlendA64Mask1DTestHBD::kMaxMaskSize]
[BlendA64Mask1DTestHBD::kMaxMaskSize];
for (int row = 0 ; row < h ; ++row)
for (int col = 0 ; col < w ; ++col)
mask2d[row][col] = mask[col];
vpx_highbd_blend_a64_mask_c(dst, dst_stride,
src0, src0_stride,
src1, src1_stride,
&mask2d[0][0],
BlendA64Mask1DTestHBD::kMaxMaskSize,
h, w, 0, 0, bd);
}
static void highbd_blend_a64_vmask_ref(
uint8_t *dst, uint32_t dst_stride,
const uint8_t *src0, uint32_t src0_stride,
const uint8_t *src1, uint32_t src1_stride,
const uint8_t *mask, int h, int w, int bd) {
uint8_t mask2d[BlendA64Mask1DTestHBD::kMaxMaskSize]
[BlendA64Mask1DTestHBD::kMaxMaskSize];
for (int row = 0 ; row < h ; ++row)
for (int col = 0 ; col < w ; ++col)
mask2d[row][col] = mask[row];
vpx_highbd_blend_a64_mask_c(dst, dst_stride,
src0, src0_stride,
src1, src1_stride,
&mask2d[0][0],
BlendA64Mask1DTestHBD::kMaxMaskSize,
h, w, 0, 0, bd);
}
INSTANTIATE_TEST_CASE_P(
C, BlendA64Mask1DTestHBD,
::testing::Values(
TestFuncsHBD(highbd_blend_a64_hmask_ref, vpx_highbd_blend_a64_hmask_c),
TestFuncsHBD(highbd_blend_a64_vmask_ref, vpx_highbd_blend_a64_vmask_c)));
#if HAVE_SSE4_1
INSTANTIATE_TEST_CASE_P(
SSE4_1, BlendA64Mask1DTestHBD,
::testing::Values(
TestFuncsHBD(highbd_blend_a64_hmask_ref,
vpx_highbd_blend_a64_hmask_sse4_1),
TestFuncsHBD(highbd_blend_a64_vmask_ref,
vpx_highbd_blend_a64_vmask_sse4_1)));
#endif // HAVE_SSE4_1
#endif // CONFIG_VPX_HIGHBITDEPTH
} // namespace

View File

@@ -1,288 +0,0 @@
/*
* Copyright (c) 2016 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 <math.h>
#include <stdlib.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/register_state_check.h"
#include "test/function_equivalence_test.h"
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
#include "./vp10_rtcd.h"
#include "vp10/common/enums.h"
#include "vpx_dsp/blend.h"
using libvpx_test::FunctionEquivalenceTest;
namespace {
template<typename F, typename T>
class BlendA64MaskTest : public FunctionEquivalenceTest<F> {
protected:
static const int kIterations = 10000;
static const int kMaxWidth = MAX_SB_SIZE * 5; // * 5 to cover longer strides
static const int kMaxHeight = MAX_SB_SIZE;
static const int kBufSize = kMaxWidth * kMaxHeight;
static const int kMaxMaskWidth = 2 * MAX_SB_SIZE;
static const int kMaxMaskSize = kMaxMaskWidth * kMaxMaskWidth;
virtual ~BlendA64MaskTest() {}
virtual void Execute(const T *p_src0, const T *p_src1) = 0;
void Common() {
w_ = 1 << this->rng_(MAX_SB_SIZE_LOG2 + 1);
h_ = 1 << this->rng_(MAX_SB_SIZE_LOG2 + 1);
subx_ = this->rng_(2);
suby_ = this->rng_(2);
dst_offset_ = this->rng_(33);
dst_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
src0_offset_ = this->rng_(33);
src0_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
src1_offset_ = this->rng_(33);
src1_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
mask_stride_ = this->rng_(kMaxWidth + 1 - w_ * (subx_ ? 2 : 1)) +
w_ * (subx_ ? 2 : 1);
T *p_src0;
T *p_src1;
switch (this->rng_(3)) {
case 0: // Separate sources
p_src0 = src0_;
p_src1 = src1_;
break;
case 1: // src0 == dst
p_src0 = dst_tst_;
src0_stride_ = dst_stride_;
src0_offset_ = dst_offset_;
p_src1 = src1_;
break;
case 2: // src1 == dst
p_src0 = src0_;
p_src1 = dst_tst_;
src1_stride_ = dst_stride_;
src1_offset_ = dst_offset_;
break;
default:
FAIL();
}
Execute(p_src0, p_src1);
for (int r = 0 ; r < h_ ; ++r) {
for (int c = 0 ; c < w_ ; ++c) {
ASSERT_EQ(dst_ref_[dst_offset_ + r * dst_stride_ + c],
dst_tst_[dst_offset_ + r * dst_stride_ + c]);
}
}
}
T dst_ref_[kBufSize];
T dst_tst_[kBufSize];
size_t dst_stride_;
size_t dst_offset_;
T src0_[kBufSize];
size_t src0_stride_;
size_t src0_offset_;
T src1_[kBufSize];
size_t src1_stride_;
size_t src1_offset_;
uint8_t mask_[kMaxMaskSize];
size_t mask_stride_;
int w_;
int h_;
bool suby_;
bool subx_;
};
//////////////////////////////////////////////////////////////////////////////
// 8 bit version
//////////////////////////////////////////////////////////////////////////////
typedef void (*F8B)(uint8_t *dst, uint32_t dst_stride,
const uint8_t *src0, uint32_t src0_stride,
const uint8_t *src1, uint32_t src1_stride,
const uint8_t *mask, uint32_t mask_stride,
int h, int w, int suby, int subx);
typedef libvpx_test::FuncParam<F8B> TestFuncs;
class BlendA64MaskTest8B : public BlendA64MaskTest<F8B, uint8_t> {
protected:
void Execute(const uint8_t *p_src0, const uint8_t *p_src1) {
params_.ref_func(dst_ref_ + dst_offset_, dst_stride_,
p_src0 + src0_offset_, src0_stride_,
p_src1 + src1_offset_, src1_stride_,
mask_, kMaxMaskWidth, h_, w_, suby_, subx_);
ASM_REGISTER_STATE_CHECK(
params_.tst_func(dst_tst_ + dst_offset_, dst_stride_,
p_src0 + src0_offset_, src0_stride_,
p_src1 + src1_offset_, src1_stride_,
mask_, kMaxMaskWidth, h_, w_, suby_, subx_));
}
};
TEST_P(BlendA64MaskTest8B, RandomValues) {
for (int iter = 0 ; iter < kIterations && !HasFatalFailure(); ++iter) {
for (int i = 0 ; i < kBufSize ; ++i) {
dst_ref_[i] = rng_.Rand8();
dst_tst_[i] = rng_.Rand8();
src0_[i] = rng_.Rand8();
src1_[i] = rng_.Rand8();
}
for (int i = 0 ; i < kMaxMaskSize ; ++i)
mask_[i] = rng_(VPX_BLEND_A64_MAX_ALPHA + 1);
Common();
}
}
TEST_P(BlendA64MaskTest8B, ExtremeValues) {
for (int iter = 0 ; iter < kIterations && !HasFatalFailure(); ++iter) {
for (int i = 0 ; i < kBufSize ; ++i) {
dst_ref_[i] = rng_(2) + 254;
dst_tst_[i] = rng_(2) + 254;
src0_[i] = rng_(2) + 254;
src1_[i] = rng_(2) + 254;
}
for (int i = 0 ; i < kMaxMaskSize ; ++i)
mask_[i] = rng_(2) + VPX_BLEND_A64_MAX_ALPHA - 1;
Common();
}
}
#if HAVE_SSE4_1
INSTANTIATE_TEST_CASE_P(
SSE4_1_C_COMPARE, BlendA64MaskTest8B,
::testing::Values(
TestFuncs(vpx_blend_a64_mask_c, vpx_blend_a64_mask_sse4_1)));
#endif // HAVE_SSE4_1
#if CONFIG_VPX_HIGHBITDEPTH
//////////////////////////////////////////////////////////////////////////////
// High bit-depth version
//////////////////////////////////////////////////////////////////////////////
typedef void (*FHBD)(uint8_t *dst, uint32_t dst_stride,
const uint8_t *src0, uint32_t src0_stride,
const uint8_t *src1, uint32_t src1_stride,
const uint8_t *mask, uint32_t mask_stride,
int h, int w, int suby, int subx, int bd);
typedef libvpx_test::FuncParam<FHBD> TestFuncsHBD;
class BlendA64MaskTestHBD : public BlendA64MaskTest<FHBD, uint16_t> {
protected:
void Execute(const uint16_t *p_src0, const uint16_t *p_src1) {
params_.ref_func(CONVERT_TO_BYTEPTR(dst_ref_ + dst_offset_), dst_stride_,
CONVERT_TO_BYTEPTR(p_src0 + src0_offset_), src0_stride_,
CONVERT_TO_BYTEPTR(p_src1 + src1_offset_), src1_stride_,
mask_, kMaxMaskWidth, h_, w_, suby_, subx_, bit_depth_);
ASM_REGISTER_STATE_CHECK(params_.tst_func(
CONVERT_TO_BYTEPTR(dst_tst_ + dst_offset_), dst_stride_,
CONVERT_TO_BYTEPTR(p_src0 + src0_offset_), src0_stride_,
CONVERT_TO_BYTEPTR(p_src1 + src1_offset_), src1_stride_,
mask_, kMaxMaskWidth, h_, w_, suby_, subx_, bit_depth_));
}
int bit_depth_;
};
TEST_P(BlendA64MaskTestHBD, RandomValues) {
for (int iter = 0 ; iter < kIterations && !HasFatalFailure(); ++iter) {
switch (rng_(3)) {
case 0:
bit_depth_ = 8;
break;
case 1:
bit_depth_ = 10;
break;
default:
bit_depth_ = 12;
break;
}
const int hi = 1 << bit_depth_;
for (int i = 0 ; i < kBufSize ; ++i) {
dst_ref_[i] = rng_(hi);
dst_tst_[i] = rng_(hi);
src0_[i] = rng_(hi);
src1_[i] = rng_(hi);
}
for (int i = 0 ; i < kMaxMaskSize ; ++i)
mask_[i] = rng_(VPX_BLEND_A64_MAX_ALPHA + 1);
Common();
}
}
TEST_P(BlendA64MaskTestHBD, ExtremeValues) {
for (int iter = 0 ; iter < 1000 && !HasFatalFailure(); ++iter) {
switch (rng_(3)) {
case 0:
bit_depth_ = 8;
break;
case 1:
bit_depth_ = 10;
break;
default:
bit_depth_ = 12;
break;
}
const int hi = 1 << bit_depth_;
const int lo = hi - 2;
for (int i = 0 ; i < kBufSize ; ++i) {
dst_ref_[i] = rng_(hi - lo) + lo;
dst_tst_[i] = rng_(hi - lo) + lo;
src0_[i] = rng_(hi - lo) + lo;
src1_[i] = rng_(hi - lo) + lo;
}
for (int i = 0 ; i < kMaxMaskSize ; ++i)
mask_[i] = rng_(2) + VPX_BLEND_A64_MAX_ALPHA - 1;
Common();
}
}
#if HAVE_SSE4_1
INSTANTIATE_TEST_CASE_P(
SSE4_1_C_COMPARE, BlendA64MaskTestHBD,
::testing::Values(
TestFuncsHBD(vpx_highbd_blend_a64_mask_c,
vpx_highbd_blend_a64_mask_sse4_1)));
#endif // HAVE_SSE4_1
#endif // CONFIG_VPX_HIGHBITDEPTH
} // namespace

View File

@@ -52,7 +52,7 @@ TEST_P(BordersTest, TestEncodeHighBitrate) {
// extend into the border and test the border condition. // extend into the border and test the border condition.
cfg_.g_lag_in_frames = 25; cfg_.g_lag_in_frames = 25;
cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_minsection_pct = 5;
cfg_.rc_2pass_vbr_maxsection_pct = 2000; cfg_.rc_2pass_vbr_minsection_pct = 2000;
cfg_.rc_target_bitrate = 2000; cfg_.rc_target_bitrate = 2000;
cfg_.rc_max_quantizer = 10; cfg_.rc_max_quantizer = 10;
@@ -78,6 +78,6 @@ TEST_P(BordersTest, TestLowBitrate) {
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
VP10_INSTANTIATE_TEST_CASE(BordersTest, ::testing::Values( VP9_INSTANTIATE_TEST_CASE(BordersTest, ::testing::Values(
::libvpx_test::kTwoPassGood)); ::libvpx_test::kTwoPassGood));
} // namespace } // namespace

View File

@@ -13,10 +13,10 @@
#include "./vpx_config.h" #include "./vpx_config.h"
#include "vpx/vpx_decoder.h" #include "vpx/vpx_decoder.h"
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#if CONFIG_VP10_ENCODER #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#endif #endif
#if CONFIG_VP10_DECODER #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
#include "vpx/vp8dx.h" #include "vpx/vp8dx.h"
#endif #endif
@@ -35,11 +35,6 @@ class CodecFactory {
virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg, virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
unsigned long deadline) const = 0; unsigned long deadline) const = 0;
virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
const vpx_codec_flags_t flags,
unsigned long deadline) // NOLINT(runtime/int)
const = 0;
virtual Encoder* CreateEncoder(vpx_codec_enc_cfg_t cfg, virtual Encoder* CreateEncoder(vpx_codec_enc_cfg_t cfg,
unsigned long deadline, unsigned long deadline,
const unsigned long init_flags, const unsigned long init_flags,
@@ -69,58 +64,48 @@ class CodecTestWith3Params : public ::testing::TestWithParam<
}; };
/* /*
* VP10 Codec Definitions * VP8 Codec Definitions
*/ */
#if CONFIG_VP10 #if CONFIG_VP8
class VP10Decoder : public Decoder { class VP8Decoder : public Decoder {
public: public:
VP10Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline) VP8Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline)
: Decoder(cfg, deadline) {} : Decoder(cfg, deadline) {}
VP10Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag,
unsigned long deadline) // NOLINT
: Decoder(cfg, flag, deadline) {}
protected: protected:
virtual vpx_codec_iface_t* CodecInterface() const { virtual vpx_codec_iface_t* CodecInterface() const {
#if CONFIG_VP10_DECODER #if CONFIG_VP8_DECODER
return &vpx_codec_vp10_dx_algo; return &vpx_codec_vp8_dx_algo;
#else #else
return NULL; return NULL;
#endif #endif
} }
}; };
class VP10Encoder : public Encoder { class VP8Encoder : public Encoder {
public: public:
VP10Encoder(vpx_codec_enc_cfg_t cfg, unsigned long deadline, VP8Encoder(vpx_codec_enc_cfg_t cfg, unsigned long deadline,
const unsigned long init_flags, TwopassStatsStore *stats) const unsigned long init_flags, TwopassStatsStore *stats)
: Encoder(cfg, deadline, init_flags, stats) {} : Encoder(cfg, deadline, init_flags, stats) {}
protected: protected:
virtual vpx_codec_iface_t* CodecInterface() const { virtual vpx_codec_iface_t* CodecInterface() const {
#if CONFIG_VP10_ENCODER #if CONFIG_VP8_ENCODER
return &vpx_codec_vp10_cx_algo; return &vpx_codec_vp8_cx_algo;
#else #else
return NULL; return NULL;
#endif #endif
} }
}; };
class VP10CodecFactory : public CodecFactory { class VP8CodecFactory : public CodecFactory {
public: public:
VP10CodecFactory() : CodecFactory() {} VP8CodecFactory() : CodecFactory() {}
virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg, virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
unsigned long deadline) const { unsigned long deadline) const {
return CreateDecoder(cfg, 0, deadline); #if CONFIG_VP8_DECODER
} return new VP8Decoder(cfg, deadline);
virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
const vpx_codec_flags_t flags,
unsigned long deadline) const { // NOLINT
#if CONFIG_VP10_DECODER
return new VP10Decoder(cfg, flags, deadline);
#else #else
return NULL; return NULL;
#endif #endif
@@ -130,8 +115,8 @@ class VP10CodecFactory : public CodecFactory {
unsigned long deadline, unsigned long deadline,
const unsigned long init_flags, const unsigned long init_flags,
TwopassStatsStore *stats) const { TwopassStatsStore *stats) const {
#if CONFIG_VP10_ENCODER #if CONFIG_VP8_ENCODER
return new VP10Encoder(cfg, deadline, init_flags, stats); return new VP8Encoder(cfg, deadline, init_flags, stats);
#else #else
return NULL; return NULL;
#endif #endif
@@ -139,25 +124,109 @@ class VP10CodecFactory : public CodecFactory {
virtual vpx_codec_err_t DefaultEncoderConfig(vpx_codec_enc_cfg_t *cfg, virtual vpx_codec_err_t DefaultEncoderConfig(vpx_codec_enc_cfg_t *cfg,
int usage) const { int usage) const {
#if CONFIG_VP10_ENCODER #if CONFIG_VP8_ENCODER
return vpx_codec_enc_config_default(&vpx_codec_vp10_cx_algo, cfg, usage); return vpx_codec_enc_config_default(&vpx_codec_vp8_cx_algo, cfg, usage);
#else #else
return VPX_CODEC_INCAPABLE; return VPX_CODEC_INCAPABLE;
#endif #endif
} }
}; };
const libvpx_test::VP10CodecFactory kVP10; const libvpx_test::VP8CodecFactory kVP8;
#define VP10_INSTANTIATE_TEST_CASE(test, ...)\ #define VP8_INSTANTIATE_TEST_CASE(test, ...)\
INSTANTIATE_TEST_CASE_P(VP10, test, \ INSTANTIATE_TEST_CASE_P(VP8, test, \
::testing::Combine( \ ::testing::Combine( \
::testing::Values(static_cast<const libvpx_test::CodecFactory*>( \ ::testing::Values(static_cast<const libvpx_test::CodecFactory*>( \
&libvpx_test::kVP10)), \ &libvpx_test::kVP8)), \
__VA_ARGS__)) __VA_ARGS__))
#else #else
#define VP10_INSTANTIATE_TEST_CASE(test, ...) #define VP8_INSTANTIATE_TEST_CASE(test, ...)
#endif // CONFIG_VP10 #endif // CONFIG_VP8
/*
* VP9 Codec Definitions
*/
#if CONFIG_VP9
class VP9Decoder : public Decoder {
public:
VP9Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline)
: Decoder(cfg, deadline) {}
protected:
virtual vpx_codec_iface_t* CodecInterface() const {
#if CONFIG_VP9_DECODER
return &vpx_codec_vp9_dx_algo;
#else
return NULL;
#endif
}
};
class VP9Encoder : public Encoder {
public:
VP9Encoder(vpx_codec_enc_cfg_t cfg, unsigned long deadline,
const unsigned long init_flags, TwopassStatsStore *stats)
: Encoder(cfg, deadline, init_flags, stats) {}
protected:
virtual vpx_codec_iface_t* CodecInterface() const {
#if CONFIG_VP9_ENCODER
return &vpx_codec_vp9_cx_algo;
#else
return NULL;
#endif
}
};
class VP9CodecFactory : public CodecFactory {
public:
VP9CodecFactory() : CodecFactory() {}
virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
unsigned long deadline) const {
#if CONFIG_VP9_DECODER
return new VP9Decoder(cfg, deadline);
#else
return NULL;
#endif
}
virtual Encoder* CreateEncoder(vpx_codec_enc_cfg_t cfg,
unsigned long deadline,
const unsigned long init_flags,
TwopassStatsStore *stats) const {
#if CONFIG_VP9_ENCODER
return new VP9Encoder(cfg, deadline, init_flags, stats);
#else
return NULL;
#endif
}
virtual vpx_codec_err_t DefaultEncoderConfig(vpx_codec_enc_cfg_t *cfg,
int usage) const {
#if CONFIG_VP9_ENCODER
return vpx_codec_enc_config_default(&vpx_codec_vp9_cx_algo, cfg, usage);
#else
return VPX_CODEC_INCAPABLE;
#endif
}
};
const libvpx_test::VP9CodecFactory kVP9;
#define VP9_INSTANTIATE_TEST_CASE(test, ...)\
INSTANTIATE_TEST_CASE_P(VP9, test, \
::testing::Combine( \
::testing::Values(static_cast<const libvpx_test::CodecFactory*>( \
&libvpx_test::kVP9)), \
__VA_ARGS__))
#else
#define VP9_INSTANTIATE_TEST_CASE(test, ...)
#endif // CONFIG_VP9
} // namespace libvpx_test } // namespace libvpx_test
#endif // TEST_CODEC_FACTORY_H_ #endif // TEST_CODEC_FACTORY_H_

60
test/config_test.cc Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2012 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 "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/util.h"
#include "test/video_source.h"
namespace {
class ConfigTest : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected:
ConfigTest() : EncoderTest(GET_PARAM(0)),
frame_count_in_(0), frame_count_out_(0), frame_count_max_(0) {}
virtual ~ConfigTest() {}
virtual void SetUp() {
InitializeConfig();
SetMode(GET_PARAM(1));
}
virtual void BeginPassHook(unsigned int /*pass*/) {
frame_count_in_ = 0;
frame_count_out_ = 0;
}
virtual void PreEncodeFrameHook(libvpx_test::VideoSource* /*video*/) {
++frame_count_in_;
abort_ |= (frame_count_in_ >= frame_count_max_);
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t* /*pkt*/) {
++frame_count_out_;
}
unsigned int frame_count_in_;
unsigned int frame_count_out_;
unsigned int frame_count_max_;
};
TEST_P(ConfigTest, LagIsDisabled) {
frame_count_max_ = 2;
cfg_.g_lag_in_frames = 15;
libvpx_test::DummyVideoSource video;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
EXPECT_EQ(frame_count_in_, frame_count_out_);
}
VP8_INSTANTIATE_TEST_CASE(ConfigTest, ONE_PASS_TEST_MODES);
} // namespace

File diff suppressed because it is too large Load Diff

View File

@@ -7,68 +7,45 @@
* in the file PATENTS. All contributing project authors may * in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include <climits>
#include <vector>
#include "third_party/googletest/src/include/gtest/gtest.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h" #include "test/codec_factory.h"
#include "test/encode_test_driver.h" #include "test/encode_test_driver.h"
#include "test/i420_video_source.h" #include "test/i420_video_source.h"
#include "test/util.h" #include "test/util.h"
#include "test/y4m_video_source.h"
namespace { namespace {
const int kMaxPSNR = 100; class CpuSpeedTest : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<
class CpuSpeedTest libvpx_test::TestMode, int> {
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
protected: protected:
CpuSpeedTest() CpuSpeedTest() : EncoderTest(GET_PARAM(0)) {}
: EncoderTest(GET_PARAM(0)),
encoding_mode_(GET_PARAM(1)),
set_cpu_used_(GET_PARAM(2)),
min_psnr_(kMaxPSNR),
tune_content_(VPX_CONTENT_DEFAULT) {}
virtual ~CpuSpeedTest() {} virtual ~CpuSpeedTest() {}
virtual void SetUp() { virtual void SetUp() {
InitializeConfig(); InitializeConfig();
SetMode(encoding_mode_); SetMode(GET_PARAM(1));
if (encoding_mode_ != ::libvpx_test::kRealTime) { set_cpu_used_ = GET_PARAM(2);
cfg_.g_lag_in_frames = 25;
cfg_.rc_end_usage = VPX_VBR;
} else {
cfg_.g_lag_in_frames = 0;
cfg_.rc_end_usage = VPX_CBR;
}
}
virtual void BeginPassHook(unsigned int /*pass*/) {
min_psnr_ = kMaxPSNR;
} }
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) { ::libvpx_test::Encoder *encoder) {
if (video->frame() == 1) { if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
encoder->Control(VP9E_SET_TUNE_CONTENT, tune_content_);
if (encoding_mode_ != ::libvpx_test::kRealTime) {
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1); encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7); encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
encoder->Control(VP8E_SET_ARNR_STRENGTH, 5); encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
encoder->Control(VP8E_SET_ARNR_TYPE, 3); encoder->Control(VP8E_SET_ARNR_TYPE, 3);
} }
} }
}
virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) { virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
if (pkt->data.psnr.psnr[0] < min_psnr_) if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
min_psnr_ = pkt->data.psnr.psnr[0]; }
} }
::libvpx_test::TestMode encoding_mode_;
int set_cpu_used_; int set_cpu_used_;
double min_psnr_;
int tune_content_;
}; };
TEST_P(CpuSpeedTest, TestQ0) { TEST_P(CpuSpeedTest, TestQ0) {
@@ -76,85 +53,61 @@ TEST_P(CpuSpeedTest, TestQ0) {
// without a mismatch when passing in a very low max q. This pushes // without a mismatch when passing in a very low max q. This pushes
// the encoder to producing lots of big partitions which will likely // the encoder to producing lots of big partitions which will likely
// extend into the border and test the border condition. // extend into the border and test the border condition.
cfg_.g_lag_in_frames = 25;
cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_minsection_pct = 5;
cfg_.rc_2pass_vbr_maxsection_pct = 2000; cfg_.rc_2pass_vbr_minsection_pct = 2000;
cfg_.rc_target_bitrate = 400; cfg_.rc_target_bitrate = 400;
cfg_.rc_max_quantizer = 0; cfg_.rc_max_quantizer = 0;
cfg_.rc_min_quantizer = 0; cfg_.rc_min_quantizer = 0;
::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0, ::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
10); 20);
init_flags_ = VPX_CODEC_USE_PSNR;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
EXPECT_GE(min_psnr_, kMaxPSNR);
}
TEST_P(CpuSpeedTest, TestScreencastQ0) {
::libvpx_test::Y4mVideoSource video("screendata.y4m", 0, 10);
cfg_.g_timebase = video.timebase();
cfg_.rc_2pass_vbr_minsection_pct = 5;
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
cfg_.rc_target_bitrate = 400;
cfg_.rc_max_quantizer = 0;
cfg_.rc_min_quantizer = 0;
init_flags_ = VPX_CODEC_USE_PSNR;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
EXPECT_GE(min_psnr_, kMaxPSNR);
}
TEST_P(CpuSpeedTest, TestTuneScreen) {
::libvpx_test::Y4mVideoSource video("screendata.y4m", 0, 10);
cfg_.g_timebase = video.timebase();
cfg_.rc_2pass_vbr_minsection_pct = 5;
cfg_.rc_2pass_vbr_minsection_pct = 2000;
cfg_.rc_target_bitrate = 2000;
cfg_.rc_max_quantizer = 63;
cfg_.rc_min_quantizer = 0;
tune_content_ = VPX_CONTENT_SCREEN;
init_flags_ = VPX_CODEC_USE_PSNR;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
TEST_P(CpuSpeedTest, TestEncodeHighBitrate) { TEST_P(CpuSpeedTest, TestEncodeHighBitrate) {
// Validate that this non multiple of 64 wide clip encodes and decodes // Validate that this non multiple of 64 wide clip encodes and decodes
// without a mismatch when passing in a very low max q. This pushes // without a mismatch when passing in a very low max q. This pushes
// the encoder to producing lots of big partitions which will likely // the encoder to producing lots of big partitions which will likely
// extend into the border and test the border condition. // extend into the border and test the border condition.
cfg_.g_lag_in_frames = 25;
cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_minsection_pct = 5;
cfg_.rc_2pass_vbr_maxsection_pct = 2000; cfg_.rc_2pass_vbr_minsection_pct = 2000;
cfg_.rc_target_bitrate = 12000; cfg_.rc_target_bitrate = 12000;
cfg_.rc_max_quantizer = 10; cfg_.rc_max_quantizer = 10;
cfg_.rc_min_quantizer = 0; cfg_.rc_min_quantizer = 0;
::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0, ::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
10); 20);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
TEST_P(CpuSpeedTest, TestLowBitrate) { TEST_P(CpuSpeedTest, TestLowBitrate) {
// Validate that this clip encodes and decodes without a mismatch // Validate that this clip encodes and decodes without a mismatch
// when passing in a very high min q. This pushes the encoder to producing // when passing in a very high min q. This pushes the encoder to producing
// lots of small partitions which might will test the other condition. // lots of small partitions which might will test the other condition.
cfg_.g_lag_in_frames = 25;
cfg_.rc_2pass_vbr_minsection_pct = 5; cfg_.rc_2pass_vbr_minsection_pct = 5;
cfg_.rc_2pass_vbr_maxsection_pct = 2000; cfg_.rc_2pass_vbr_minsection_pct = 2000;
cfg_.rc_target_bitrate = 200; cfg_.rc_target_bitrate = 200;
cfg_.rc_min_quantizer = 40; cfg_.rc_min_quantizer = 40;
::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0, ::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
10); 20);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
VP10_INSTANTIATE_TEST_CASE( using std::tr1::make_tuple;
#define VP9_FACTORY \
static_cast<const libvpx_test::CodecFactory*> (&libvpx_test::kVP9)
VP9_INSTANTIATE_TEST_CASE(
CpuSpeedTest, CpuSpeedTest,
::testing::Values(::libvpx_test::kTwoPassGood, ::libvpx_test::kOnePassGood), ::testing::Values(::libvpx_test::kTwoPassGood, ::libvpx_test::kOnePassGood),
::testing::Range(0, 3)); ::testing::Range(0, 8));
} // namespace } // namespace

108
test/cq_test.cc Normal file
View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2012 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 <cmath>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/util.h"
namespace {
// CQ level range: [kCQLevelMin, kCQLevelMax).
const int kCQLevelMin = 4;
const int kCQLevelMax = 63;
const int kCQLevelStep = 8;
const unsigned int kCQTargetBitrate = 2000;
class CQTest : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<int> {
protected:
CQTest() : EncoderTest(GET_PARAM(0)), cq_level_(GET_PARAM(1)) {
init_flags_ = VPX_CODEC_USE_PSNR;
}
virtual ~CQTest() {}
virtual void SetUp() {
InitializeConfig();
SetMode(libvpx_test::kTwoPassGood);
}
virtual void BeginPassHook(unsigned int /*pass*/) {
file_size_ = 0;
psnr_ = 0.0;
n_frames_ = 0;
}
virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
libvpx_test::Encoder *encoder) {
if (video->frame() == 1) {
if (cfg_.rc_end_usage == VPX_CQ) {
encoder->Control(VP8E_SET_CQ_LEVEL, cq_level_);
}
encoder->Control(VP8E_SET_CPUUSED, 3);
}
}
virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
psnr_ += pow(10.0, pkt->data.psnr.psnr[0] / 10.0);
n_frames_++;
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
file_size_ += pkt->data.frame.sz;
}
double GetLinearPSNROverBitrate() const {
double avg_psnr = log10(psnr_ / n_frames_) * 10.0;
return pow(10.0, avg_psnr / 10.0) / file_size_;
}
size_t file_size() const { return file_size_; }
int n_frames() const { return n_frames_; }
private:
int cq_level_;
size_t file_size_;
double psnr_;
int n_frames_;
};
unsigned int prev_actual_bitrate = kCQTargetBitrate;
TEST_P(CQTest, LinearPSNRIsHigherForCQLevel) {
const vpx_rational timebase = { 33333333, 1000000000 };
cfg_.g_timebase = timebase;
cfg_.rc_target_bitrate = kCQTargetBitrate;
cfg_.g_lag_in_frames = 25;
cfg_.rc_end_usage = VPX_CQ;
libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
timebase.den, timebase.num, 0, 30);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
const double cq_psnr_lin = GetLinearPSNROverBitrate();
const unsigned int cq_actual_bitrate =
static_cast<unsigned int>(file_size()) * 8 * 30 / (n_frames() * 1000);
EXPECT_LE(cq_actual_bitrate, kCQTargetBitrate);
EXPECT_LE(cq_actual_bitrate, prev_actual_bitrate);
prev_actual_bitrate = cq_actual_bitrate;
// try targeting the approximate same bitrate with VBR mode
cfg_.rc_end_usage = VPX_VBR;
cfg_.rc_target_bitrate = cq_actual_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
const double vbr_psnr_lin = GetLinearPSNROverBitrate();
EXPECT_GE(cq_psnr_lin, vbr_psnr_lin);
}
VP8_INSTANTIATE_TEST_CASE(CQTest,
::testing::Range(kCQLevelMin, kCQLevelMax,
kCQLevelStep));
} // namespace

View File

@@ -1,77 +0,0 @@
#!/bin/sh
##
## Copyright (c) 2016 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 file tests the libvpx cx_set_ref example. To add new tests to this
## file, do the following:
## 1. Write a shell function (this is your test).
## 2. Add the function to cx_set_ref_tests (on a new line).
##
. $(dirname $0)/tools_common.sh
# Environment check: $YUV_RAW_INPUT is required.
cx_set_ref_verify_environment() {
if [ ! -e "${YUV_RAW_INPUT}" ]; then
echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
return 1
fi
}
# Runs cx_set_ref and updates the reference frame before encoding frame 90.
# $1 is the codec name.
vpx_set_ref() {
local codec="$1"
local encoder="${LIBVPX_BIN_PATH}/vpxcx_set_ref${VPX_TEST_EXE_SUFFIX}"
if [ "$codec" = "vp8" ]; then
encoder="${LIBVPX_BIN_PATH}/vp8cx_set_ref${VPX_TEST_EXE_SUFFIX}"
fi
local output_file="${VPX_TEST_OUTPUT_DIR}/${codec}cx_set_ref_${codec}.ivf"
local ref_frame_num=90
if [ ! -x "${encoder}" ]; then
elog "${encoder} does not exist or is not executable."
return 1
fi
if [ "$codec" = "vp8" ]; then
eval "${VPX_TEST_PREFIX}" "${encoder}" "${YUV_RAW_INPUT_WIDTH}" \
"${YUV_RAW_INPUT_HEIGHT}" "${YUV_RAW_INPUT}" "${output_file}" \
"${ref_frame_num}" ${devnull}
else
eval "${VPX_TEST_PREFIX}" "${encoder}" "${codec}" "${YUV_RAW_INPUT_WIDTH}" \
"${YUV_RAW_INPUT_HEIGHT}" "${YUV_RAW_INPUT}" "${output_file}" \
"${ref_frame_num}" ${devnull}
fi
[ -e "${output_file}" ] || return 1
}
cx_set_ref_vp8() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_set_ref vp8 || return 1
fi
}
cx_set_ref_vp9() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_set_ref vp9 || return 1
fi
}
cx_set_ref_vp10() {
if [ "$(vp10_encode_available)" = "yes" ]; then
vpx_set_ref vp10 || return 1
fi
}
cx_set_ref_tests="cx_set_ref_vp8 cx_set_ref_vp9 cx_set_ref_vp10"
run_tests cx_set_ref_verify_environment "${cx_set_ref_tests}"

View File

@@ -14,7 +14,6 @@
#include "test/i420_video_source.h" #include "test/i420_video_source.h"
#include "test/util.h" #include "test/util.h"
#include "test/y4m_video_source.h" #include "test/y4m_video_source.h"
#include "vpx/vpx_codec.h"
namespace { namespace {
@@ -39,25 +38,10 @@ class DatarateTestLarge : public ::libvpx_test::EncoderTest,
first_drop_ = 0; first_drop_ = 0;
bits_total_ = 0; bits_total_ = 0;
duration_ = 0.0; duration_ = 0.0;
denoiser_offon_test_ = 0;
denoiser_offon_period_ = -1;
} }
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) { ::libvpx_test::Encoder *encoder) {
if (video->frame() == 0)
encoder->Control(VP8E_SET_NOISE_SENSITIVITY, denoiser_on_);
if (denoiser_offon_test_) {
ASSERT_GT(denoiser_offon_period_, 0)
<< "denoiser_offon_period_ is not positive.";
if ((video->frame() + 1) % denoiser_offon_period_ == 0) {
// Flip denoiser_on_ periodically
denoiser_on_ ^= 1;
}
encoder->Control(VP8E_SET_NOISE_SENSITIVITY, denoiser_on_);
}
const vpx_rational_t tb = video->timebase(); const vpx_rational_t tb = video->timebase();
timebase_ = static_cast<double>(tb.num) / tb.den; timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0; duration_ = 0;
@@ -90,7 +74,7 @@ class DatarateTestLarge : public ::libvpx_test::EncoderTest,
<< pkt->data.frame.pts; << pkt->data.frame.pts;
} }
const int64_t frame_size_in_bits = pkt->data.frame.sz * 8; const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
// Subtract from the buffer the bits associated with a played back frame. // Subtract from the buffer the bits associated with a played back frame.
bits_in_buffer_model_ -= frame_size_in_bits; bits_in_buffer_model_ -= frame_size_in_bits;
@@ -135,15 +119,10 @@ class DatarateTestLarge : public ::libvpx_test::EncoderTest,
double duration_; double duration_;
double file_datarate_; double file_datarate_;
double effective_datarate_; double effective_datarate_;
int64_t bits_in_last_frame_; size_t bits_in_last_frame_;
int denoiser_on_;
int denoiser_offon_test_;
int denoiser_offon_period_;
}; };
TEST_P(DatarateTestLarge, BasicBufferModel) { TEST_P(DatarateTestLarge, BasicBufferModel) {
denoiser_on_ = 0;
cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_initial_sz = 500;
cfg_.rc_dropframe_thresh = 1; cfg_.rc_dropframe_thresh = 1;
cfg_.rc_max_quantizer = 56; cfg_.rc_max_quantizer = 56;
@@ -175,7 +154,6 @@ TEST_P(DatarateTestLarge, BasicBufferModel) {
} }
TEST_P(DatarateTestLarge, ChangingDropFrameThresh) { TEST_P(DatarateTestLarge, ChangingDropFrameThresh) {
denoiser_on_ = 0;
cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_initial_sz = 500;
cfg_.rc_max_quantizer = 36; cfg_.rc_max_quantizer = 36;
cfg_.rc_end_usage = VPX_CBR; cfg_.rc_end_usage = VPX_CBR;
@@ -225,14 +203,10 @@ class DatarateTestVP9Large : public ::libvpx_test::EncoderTest,
tot_frame_number_ = 0; tot_frame_number_ = 0;
first_drop_ = 0; first_drop_ = 0;
num_drops_ = 0; num_drops_ = 0;
// Denoiser is off by default.
denoiser_on_ = 0;
// For testing up to 3 layers. // For testing up to 3 layers.
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
bits_total_[i] = 0; bits_total_[i] = 0;
} }
denoiser_offon_test_ = 0;
denoiser_offon_period_ = -1;
} }
// //
@@ -300,31 +274,22 @@ class DatarateTestVP9Large : public ::libvpx_test::EncoderTest,
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) { ::libvpx_test::Encoder *encoder) {
if (video->frame() == 0) if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
if (denoiser_offon_test_) {
ASSERT_GT(denoiser_offon_period_, 0)
<< "denoiser_offon_period_ is not positive.";
if ((video->frame() + 1) % denoiser_offon_period_ == 0) {
// Flip denoiser_on_ periodically
denoiser_on_ ^= 1;
} }
}
encoder->Control(VP9E_SET_NOISE_SENSITIVITY, denoiser_on_);
if (cfg_.ts_number_layers > 1) { if (cfg_.ts_number_layers > 1) {
if (video->frame() == 0) { if (video->frame() == 1) {
encoder->Control(VP9E_SET_SVC, 1); encoder->Control(VP9E_SET_SVC, 1);
} }
vpx_svc_layer_id_t layer_id; vpx_svc_layer_id_t layer_id = {0, 0};
layer_id.spatial_layer_id = 0; layer_id.spatial_layer_id = 0;
frame_flags_ = SetFrameFlags(video->frame(), cfg_.ts_number_layers); frame_flags_ = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
layer_id.temporal_layer_id = SetLayerId(video->frame(), layer_id.temporal_layer_id = SetLayerId(video->frame(),
cfg_.ts_number_layers); cfg_.ts_number_layers);
if (video->frame() > 0) {
encoder->Control(VP9E_SET_SVC_LAYER_ID, &layer_id); encoder->Control(VP9E_SET_SVC_LAYER_ID, &layer_id);
} }
}
const vpx_rational_t tb = video->timebase(); const vpx_rational_t tb = video->timebase();
timebase_ = static_cast<double>(tb.num) / tb.den; timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0; duration_ = 0;
@@ -392,33 +357,9 @@ class DatarateTestVP9Large : public ::libvpx_test::EncoderTest,
int64_t bits_in_buffer_model_; int64_t bits_in_buffer_model_;
vpx_codec_pts_t first_drop_; vpx_codec_pts_t first_drop_;
int num_drops_; int num_drops_;
int denoiser_on_;
int denoiser_offon_test_;
int denoiser_offon_period_;
}; };
// Check basic rate targeting for VBR mode. // Check basic rate targeting,
TEST_P(DatarateTestVP9Large, BasicRateTargetingVBR) {
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.g_error_resilient = 0;
cfg_.rc_end_usage = VPX_VBR;
cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 300);
for (int i = 400; i <= 800; i += 400) {
cfg_.rc_target_bitrate = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.75)
<< " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.25)
<< " The datarate for the file is greater than target by too much!";
}
}
// Check basic rate targeting for CBR,
TEST_P(DatarateTestVP9Large, BasicRateTargeting) { TEST_P(DatarateTestVP9Large, BasicRateTargeting) {
cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500; cfg_.rc_buf_optimal_sz = 500;
@@ -442,7 +383,7 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting) {
} }
} }
// Check basic rate targeting for CBR. // Check basic rate targeting,
TEST_P(DatarateTestVP9Large, BasicRateTargeting444) { TEST_P(DatarateTestVP9Large, BasicRateTargeting444) {
::libvpx_test::Y4mVideoSource video("rush_hour_444.y4m", 0, 140); ::libvpx_test::Y4mVideoSource video("rush_hour_444.y4m", 0, 140);
@@ -487,9 +428,6 @@ TEST_P(DatarateTestVP9Large, ChangingDropFrameThresh) {
cfg_.rc_end_usage = VPX_CBR; cfg_.rc_end_usage = VPX_CBR;
cfg_.rc_target_bitrate = 200; cfg_.rc_target_bitrate = 200;
cfg_.g_lag_in_frames = 0; cfg_.g_lag_in_frames = 0;
// TODO(marpan): Investigate datarate target failures with a smaller keyframe
// interval (128).
cfg_.kf_max_dist = 9999;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140); 30, 1, 0, 140);
@@ -509,7 +447,7 @@ TEST_P(DatarateTestVP9Large, ChangingDropFrameThresh) {
<< " The first dropped frame for drop_thresh " << i << " The first dropped frame for drop_thresh " << i
<< " > first dropped frame for drop_thresh " << " > first dropped frame for drop_thresh "
<< i - kDropFrameThreshTestStep; << i - kDropFrameThreshTestStep;
ASSERT_GE(num_drops_, last_num_drops * 0.85) ASSERT_GE(num_drops_, last_num_drops)
<< " The number of dropped frames for drop_thresh " << i << " The number of dropped frames for drop_thresh " << i
<< " < number of dropped frames for drop_thresh " << " < number of dropped frames for drop_thresh "
<< i - kDropFrameThreshTestStep; << i - kDropFrameThreshTestStep;
@@ -535,25 +473,20 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting2TemporalLayers) {
cfg_.ts_rate_decimator[0] = 2; cfg_.ts_rate_decimator[0] = 2;
cfg_.ts_rate_decimator[1] = 1; cfg_.ts_rate_decimator[1] = 1;
cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
if (deadline_ == VPX_DL_REALTIME)
cfg_.g_error_resilient = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200); 30, 1, 0, 200);
for (int i = 200; i <= 800; i += 200) { for (int i = 200; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i; cfg_.rc_target_bitrate = i;
ResetModel(); ResetModel();
// 60-40 bitrate allocation for 2 temporal layers. // 60-40 bitrate allocation for 2 temporal layers.
cfg_.layer_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100; cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.layer_target_bitrate[1] = cfg_.rc_target_bitrate; cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) { for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
ASSERT_GE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 0.85) ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
<< " The datarate for the file is lower than target by too much, " << " The datarate for the file is lower than target by too much, "
"for layer: " << j; "for layer: " << j;
ASSERT_LE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 1.15) ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
<< " The datarate for the file is greater than target by too much, " << " The datarate for the file is greater than target by too much, "
"for layer: " << j; "for layer: " << j;
} }
@@ -578,27 +511,25 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayers) {
cfg_.ts_rate_decimator[1] = 2; cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1; cfg_.ts_rate_decimator[2] = 1;
cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200); 30, 1, 0, 200);
for (int i = 200; i <= 800; i += 200) { for (int i = 200; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i; cfg_.rc_target_bitrate = i;
ResetModel(); ResetModel();
// 40-20-40 bitrate allocation for 3 temporal layers. // 40-20-40 bitrate allocation for 3 temporal layers.
cfg_.layer_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100; cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
cfg_.layer_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100; cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.layer_target_bitrate[2] = cfg_.rc_target_bitrate; cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) { for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
// TODO(yaowu): Work out more stable rc control strategy and // TODO(yaowu): Work out more stable rc control strategy and
// Adjust the thresholds to be tighter than .75. // Adjust the thresholds to be tighter than .75.
ASSERT_GE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 0.75) ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.75)
<< " The datarate for the file is lower than target by too much, " << " The datarate for the file is lower than target by too much, "
"for layer: " << j; "for layer: " << j;
// TODO(yaowu): Work out more stable rc control strategy and // TODO(yaowu): Work out more stable rc control strategy and
// Adjust the thresholds to be tighter than 1.25. // Adjust the thresholds to be tighter than 1.25.
ASSERT_LE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 1.25) ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.25)
<< " The datarate for the file is greater than target by too much, " << " The datarate for the file is greater than target by too much, "
"for layer: " << j; "for layer: " << j;
} }
@@ -626,413 +557,32 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayersFrameDropping) {
cfg_.ts_rate_decimator[1] = 2; cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1; cfg_.ts_rate_decimator[2] = 1;
cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200); 30, 1, 0, 200);
cfg_.rc_target_bitrate = 200; cfg_.rc_target_bitrate = 200;
ResetModel(); ResetModel();
// 40-20-40 bitrate allocation for 3 temporal layers. // 40-20-40 bitrate allocation for 3 temporal layers.
cfg_.layer_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100; cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
cfg_.layer_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100; cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.layer_target_bitrate[2] = cfg_.rc_target_bitrate; cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) { for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
ASSERT_GE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 0.85) ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
<< " The datarate for the file is lower than target by too much, " << " The datarate for the file is lower than target by too much, "
"for layer: " << j; "for layer: " << j;
ASSERT_LE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 1.15) ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
<< " The datarate for the file is greater than target by too much, " << " The datarate for the file is greater than target by too much, "
"for layer: " << j; "for layer: " << j;
// Expect some frame drops in this test: for this 200 frames test, // Expect some frame drops in this test: for this 200 frames test,
// expect at least 10% and not more than 60% drops. // expect at least 10% and not more than 60% drops.
ASSERT_GE(num_drops_, 20); ASSERT_GE(num_drops_, 20);
ASSERT_LE(num_drops_, 130); ASSERT_LE(num_drops_, 120);
} }
} }
class DatarateOnePassCbrSvc : public ::libvpx_test::EncoderTest, VP8_INSTANTIATE_TEST_CASE(DatarateTestLarge, ALL_TEST_MODES);
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> { VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9Large,
public: ::testing::Values(::libvpx_test::kOnePassGood,
DatarateOnePassCbrSvc() : EncoderTest(GET_PARAM(0)) {} ::libvpx_test::kRealTime),
virtual ~DatarateOnePassCbrSvc() {} ::testing::Range(2, 7));
protected:
virtual void SetUp() {
InitializeConfig();
SetMode(GET_PARAM(1));
speed_setting_ = GET_PARAM(2);
ResetModel();
}
virtual void ResetModel() {
last_pts_ = 0;
bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz;
frame_number_ = 0;
first_drop_ = 0;
bits_total_ = 0;
duration_ = 0.0;
mismatch_psnr_ = 0.0;
mismatch_nframes_ = 0;
}
virtual void BeginPassHook(unsigned int /*pass*/) {
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 0) {
int i;
for (i = 0; i < VPX_MAX_LAYERS; ++i) {
svc_params_.max_quantizers[i] = 63;
svc_params_.min_quantizers[i] = 0;
}
encoder->Control(VP9E_SET_SVC, 1);
encoder->Control(VP9E_SET_SVC_PARAMETERS, &svc_params_);
encoder->Control(VP8E_SET_CPUUSED, speed_setting_);
encoder->Control(VP9E_SET_TILE_COLUMNS, 0);
encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 300);
encoder->Control(VP9E_SET_TILE_COLUMNS, (cfg_.g_threads >> 1));
}
const vpx_rational_t tb = video->timebase();
timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0;
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
if (last_pts_ == 0)
duration = 1;
bits_in_buffer_model_ += static_cast<int64_t>(
duration * timebase_ * cfg_.rc_target_bitrate * 1000);
const bool key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY)
? true: false;
if (!key_frame) {
ASSERT_GE(bits_in_buffer_model_, 0) << "Buffer Underrun at frame "
<< pkt->data.frame.pts;
}
const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
bits_in_buffer_model_ -= frame_size_in_bits;
bits_total_ += frame_size_in_bits;
if (!first_drop_ && duration > 1)
first_drop_ = last_pts_ + 1;
last_pts_ = pkt->data.frame.pts;
bits_in_last_frame_ = frame_size_in_bits;
++frame_number_;
}
virtual void EndPassHook(void) {
if (bits_total_) {
const double file_size_in_kb = bits_total_ / 1000.; // bits per kilobit
duration_ = (last_pts_ + 1) * timebase_;
file_datarate_ = file_size_in_kb / duration_;
}
}
virtual void MismatchHook(const vpx_image_t *img1,
const vpx_image_t *img2) {
double mismatch_psnr = compute_psnr(img1, img2);
mismatch_psnr_ += mismatch_psnr;
++mismatch_nframes_;
}
unsigned int GetMismatchFrames() {
return mismatch_nframes_;
}
vpx_codec_pts_t last_pts_;
int64_t bits_in_buffer_model_;
double timebase_;
int frame_number_;
vpx_codec_pts_t first_drop_;
int64_t bits_total_;
double duration_;
double file_datarate_;
size_t bits_in_last_frame_;
vpx_svc_extra_cfg_t svc_params_;
int speed_setting_;
double mismatch_psnr_;
int mismatch_nframes_;
};
static void assign_layer_bitrates(vpx_codec_enc_cfg_t *const enc_cfg,
const vpx_svc_extra_cfg_t *svc_params,
int spatial_layers,
int temporal_layers,
int temporal_layering_mode) {
int sl, spatial_layer_target;
float total = 0;
float alloc_ratio[VPX_MAX_LAYERS] = {0};
for (sl = 0; sl < spatial_layers; ++sl) {
if (svc_params->scaling_factor_den[sl] > 0) {
alloc_ratio[sl] = (float)(svc_params->scaling_factor_num[sl] *
1.0 / svc_params->scaling_factor_den[sl]);
total += alloc_ratio[sl];
}
}
for (sl = 0; sl < spatial_layers; ++sl) {
enc_cfg->ss_target_bitrate[sl] = spatial_layer_target =
(unsigned int)(enc_cfg->rc_target_bitrate *
alloc_ratio[sl] / total);
const int index = sl * temporal_layers;
if (temporal_layering_mode == 3) {
enc_cfg->layer_target_bitrate[index] =
spatial_layer_target >> 1;
enc_cfg->layer_target_bitrate[index + 1] =
(spatial_layer_target >> 1) + (spatial_layer_target >> 2);
enc_cfg->layer_target_bitrate[index + 2] =
spatial_layer_target;
} else if (temporal_layering_mode == 2) {
enc_cfg->layer_target_bitrate[index] =
spatial_layer_target * 2 / 3;
enc_cfg->layer_target_bitrate[index + 1] =
spatial_layer_target;
}
}
}
// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and
// 3 temporal layers. Run CIF clip with 1 thread.
TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.ss_number_layers = 2;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.g_error_resilient = 1;
cfg_.g_threads = 1;
cfg_.temporal_layering_mode = 3;
svc_params_.scaling_factor_num[0] = 144;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 288;
svc_params_.scaling_factor_den[1] = 288;
cfg_.rc_dropframe_thresh = 10;
cfg_.kf_max_dist = 9999;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
// TODO(wonkap/marpan): Check that effective_datarate for each layer hits the
// layer target_bitrate.
for (int i = 200; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15)
<< " The datarate for the file is lower than the target by too much!";
EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
}
// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 3
// temporal layers. Run CIF clip with 1 thread, and few short key frame periods.
TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayersSmallKf) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.ss_number_layers = 2;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.g_error_resilient = 1;
cfg_.g_threads = 1;
cfg_.temporal_layering_mode = 3;
svc_params_.scaling_factor_num[0] = 144;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 288;
svc_params_.scaling_factor_den[1] = 288;
cfg_.rc_dropframe_thresh = 10;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
cfg_.rc_target_bitrate = 400;
// For this 3 temporal layer case, pattern repeats every 4 frames, so choose
// 4 key neighboring key frame periods (so key frame will land on 0-2-1-2).
for (int j = 64; j <= 67; j++) {
cfg_.kf_max_dist = j;
ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15)
<< " The datarate for the file is lower than the target by too much!";
EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
}
// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and
// 3 temporal layers. Run HD clip with 4 threads.
TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SpatialLayers4threads) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.ss_number_layers = 2;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.g_error_resilient = 1;
cfg_.g_threads = 4;
cfg_.temporal_layering_mode = 3;
svc_params_.scaling_factor_num[0] = 144;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 288;
svc_params_.scaling_factor_den[1] = 288;
cfg_.rc_dropframe_thresh = 10;
cfg_.kf_max_dist = 9999;
::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720,
30, 1, 0, 300);
cfg_.rc_target_bitrate = 800;
ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15)
<< " The datarate for the file is lower than the target by too much!";
EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and
// 3 temporal layers. Run CIF clip with 1 thread.
TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayers) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.ss_number_layers = 3;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.g_error_resilient = 1;
cfg_.g_threads = 1;
cfg_.temporal_layering_mode = 3;
svc_params_.scaling_factor_num[0] = 72;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 144;
svc_params_.scaling_factor_den[1] = 288;
svc_params_.scaling_factor_num[2] = 288;
svc_params_.scaling_factor_den[2] = 288;
cfg_.rc_dropframe_thresh = 10;
cfg_.kf_max_dist = 9999;
::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720,
30, 1, 0, 300);
cfg_.rc_target_bitrate = 800;
ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22)
<< " The datarate for the file is lower than the target by too much!";
EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and 3
// temporal layers. Run CIF clip with 1 thread, and few short key frame periods.
TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayersSmallKf) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.ss_number_layers = 3;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.g_error_resilient = 1;
cfg_.g_threads = 1;
cfg_.temporal_layering_mode = 3;
svc_params_.scaling_factor_num[0] = 72;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 144;
svc_params_.scaling_factor_den[1] = 288;
svc_params_.scaling_factor_num[2] = 288;
svc_params_.scaling_factor_den[2] = 288;
cfg_.rc_dropframe_thresh = 10;
::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720,
30, 1, 0, 300);
cfg_.rc_target_bitrate = 800;
// For this 3 temporal layer case, pattern repeats every 4 frames, so choose
// 4 key neighboring key frame periods (so key frame will land on 0-2-1-2).
for (int j = 32; j <= 35; j++) {
cfg_.kf_max_dist = j;
ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.30)
<< " The datarate for the file is lower than the target by too much!";
EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
}
// Check basic rate targeting for 1 pass CBR SVC: 3 spatial layers and
// 3 temporal layers. Run HD clip with 4 threads.
TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SpatialLayers4threads) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.ss_number_layers = 3;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.g_error_resilient = 1;
cfg_.g_threads = 4;
cfg_.temporal_layering_mode = 3;
svc_params_.scaling_factor_num[0] = 72;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 144;
svc_params_.scaling_factor_den[1] = 288;
svc_params_.scaling_factor_num[2] = 288;
svc_params_.scaling_factor_den[2] = 288;
cfg_.rc_dropframe_thresh = 10;
cfg_.kf_max_dist = 9999;
::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720,
30, 1, 0, 300);
cfg_.rc_target_bitrate = 800;
ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22)
<< " The datarate for the file is lower than the target by too much!";
EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
}
/* VP10 does not support multiple layers yet.
VP10_INSTANTIATE_TEST_CASE(DatarateOnePassCbrSvc,
::testing::Values(::libvpx_test::kRealTime),
::testing::Range(5, 8));
*/
} // namespace } // namespace

View File

@@ -13,25 +13,57 @@
#include <string.h> #include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vp10_rtcd.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h" #include "test/acm_random.h"
#include "test/clear_system_state.h" #include "test/clear_system_state.h"
#include "test/register_state_check.h" #include "test/register_state_check.h"
#include "test/util.h" #include "test/util.h"
#include "vp10/common/entropy.h"
#include "vp10/common/scan.h" #include "./vp9_rtcd.h"
#include "vpx/vpx_codec.h" #include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_integer.h" #include "vpx/vpx_integer.h"
#include "vpx_ports/mem.h"
#include "vpx_ports/msvc.h" // for round() extern "C" {
void vp9_idct16x16_256_add_c(const int16_t *input, uint8_t *output, int pitch);
}
using libvpx_test::ACMRandom; using libvpx_test::ACMRandom;
namespace { namespace {
#ifdef _MSC_VER
static int round(double x) {
if (x < 0)
return static_cast<int>(ceil(x - 0.5));
else
return static_cast<int>(floor(x + 0.5));
}
#endif
const int kNumCoeffs = 256; const int kNumCoeffs = 256;
const double PI = 3.1415926535898;
void reference2_16x16_idct_2d(double *input, double *output) {
double x;
for (int l = 0; l < 16; ++l) {
for (int k = 0; k < 16; ++k) {
double s = 0;
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 16; ++j) {
x = cos(PI * j * (l + 0.5) / 16.0) *
cos(PI * i * (k + 0.5) / 16.0) *
input[i * 16 + j] / 256;
if (i != 0)
x *= sqrt(2.0);
if (j != 0)
x *= sqrt(2.0);
s += x;
}
}
output[k*16+l] = s;
}
}
}
const double C1 = 0.995184726672197; const double C1 = 0.995184726672197;
const double C2 = 0.98078528040323; const double C2 = 0.98078528040323;
const double C3 = 0.956940335732209; const double C3 = 0.956940335732209;
@@ -226,100 +258,40 @@ void reference_16x16_dct_2d(int16_t input[256], double output[256]) {
} }
} }
typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride); typedef void (*fdct_t)(const int16_t *in, int16_t *out, int stride);
typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride); typedef void (*idct_t)(const int16_t *in, uint8_t *out, int stride);
typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride, typedef void (*fht_t) (const int16_t *in, int16_t *out, int stride,
int tx_type); int tx_type);
typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, typedef void (*iht_t) (const int16_t *in, uint8_t *out, int stride,
int tx_type); int tx_type);
typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct16x16Param; typedef std::tr1::tuple<fdct_t, idct_t, int> dct_16x16_param_t;
typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht16x16Param; typedef std::tr1::tuple<fht_t, iht_t, int> ht_16x16_param_t;
typedef std::tr1::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t>
Idct16x16Param;
void fdct16x16_ref(const int16_t *in, tran_low_t *out, int stride, void fdct16x16_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
int /*tx_type*/) { vp9_fdct16x16_c(in, out, stride);
vpx_fdct16x16_c(in, out, stride);
} }
void idct16x16_ref(const tran_low_t *in, uint8_t *dest, int stride, void idct16x16_ref(const int16_t *in, uint8_t *dest, int stride, int tx_type) {
int /*tx_type*/) { vp9_idct16x16_256_add_c(in, dest, stride);
vpx_idct16x16_256_add_c(in, dest, stride);
} }
void fht16x16_ref(const int16_t *in, tran_low_t *out, int stride, void fht16x16_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
int tx_type) { vp9_fht16x16_c(in, out, stride, tx_type);
vp10_fht16x16_c(in, out, stride, tx_type);
} }
void iht16x16_ref(const tran_low_t *in, uint8_t *dest, int stride, void iht16x16_ref(const int16_t *in, uint8_t *dest, int stride, int tx_type) {
int tx_type) { vp9_iht16x16_256_add_c(in, dest, stride, tx_type);
vp10_iht16x16_256_add_c(in, dest, stride, tx_type);
} }
#if CONFIG_VPX_HIGHBITDEPTH
void idct16x16_10(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_256_add_c(in, out, stride, 10);
}
void idct16x16_12(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_256_add_c(in, out, stride, 12);
}
void idct16x16_10_ref(const tran_low_t *in, uint8_t *out, int stride,
int tx_type) {
idct16x16_10(in, out, stride);
}
void idct16x16_12_ref(const tran_low_t *in, uint8_t *out, int stride,
int tx_type) {
idct16x16_12(in, out, stride);
}
void iht16x16_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp10_highbd_iht16x16_256_add_c(in, out, stride, tx_type, 10);
}
void iht16x16_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp10_highbd_iht16x16_256_add_c(in, out, stride, tx_type, 12);
}
#if HAVE_SSE2
void idct16x16_10_add_10_c(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_10_add_c(in, out, stride, 10);
}
void idct16x16_10_add_12_c(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_10_add_c(in, out, stride, 12);
}
void idct16x16_256_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_256_add_sse2(in, out, stride, 10);
}
void idct16x16_256_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_256_add_sse2(in, out, stride, 12);
}
void idct16x16_10_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_10_add_sse2(in, out, stride, 10);
}
void idct16x16_10_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_10_add_sse2(in, out, stride, 12);
}
#endif // HAVE_SSE2
#endif // CONFIG_VPX_HIGHBITDEPTH
class Trans16x16TestBase { class Trans16x16TestBase {
public: public:
virtual ~Trans16x16TestBase() {} virtual ~Trans16x16TestBase() {}
protected: protected:
virtual void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) = 0; virtual void RunFwdTxfm(int16_t *in, int16_t *out, int stride) = 0;
virtual void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) = 0; virtual void RunInvTxfm(int16_t *out, uint8_t *dst, int stride) = 0;
void RunAccuracyCheck() { void RunAccuracyCheck() {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
@@ -327,49 +299,24 @@ class Trans16x16TestBase {
int64_t total_error = 0; int64_t total_error = 0;
const int count_test_block = 10000; const int count_test_block = 10000;
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
DECLARE_ALIGNED(16, int16_t, test_input_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, test_temp_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]);
#endif
// Initialize a test block with input range [-mask_, mask_]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
if (bit_depth_ == VPX_BITS_8) {
src[j] = rnd.Rand8(); src[j] = rnd.Rand8();
dst[j] = rnd.Rand8(); dst[j] = rnd.Rand8();
test_input_block[j] = src[j] - dst[j]; test_input_block[j] = src[j] - dst[j];
#if CONFIG_VPX_HIGHBITDEPTH
} else {
src16[j] = rnd.Rand16() & mask_;
dst16[j] = rnd.Rand16() & mask_;
test_input_block[j] = src16[j] - dst16[j];
#endif
}
} }
ASM_REGISTER_STATE_CHECK(RunFwdTxfm(test_input_block, REGISTER_STATE_CHECK(RunFwdTxfm(test_input_block,
test_temp_block, pitch_)); test_temp_block, pitch_));
if (bit_depth_ == VPX_BITS_8) { REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_));
ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, dst, pitch_));
#if CONFIG_VPX_HIGHBITDEPTH
} else {
ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif
}
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VPX_HIGHBITDEPTH const uint32_t diff = dst[j] - src[j];
const int32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
const int32_t diff = dst[j] - src[j];
#endif
const uint32_t error = diff * diff; const uint32_t error = diff * diff;
if (max_error < error) if (max_error < error)
max_error = error; max_error = error;
@@ -377,27 +324,27 @@ class Trans16x16TestBase {
} }
} }
EXPECT_GE(1u << 2 * (bit_depth_ - 8), max_error) EXPECT_GE(1u, max_error)
<< "Error: 16x16 FHT/IHT has an individual round trip error > 1"; << "Error: 16x16 FHT/IHT has an individual round trip error > 1";
EXPECT_GE(count_test_block << 2 * (bit_depth_ - 8), total_error) EXPECT_GE(count_test_block , total_error)
<< "Error: 16x16 FHT/IHT has average round trip error > 1 per block"; << "Error: 16x16 FHT/IHT has average round trip error > 1 per block";
} }
void RunCoeffCheck() { void RunCoeffCheck() {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 1000; const int count_test_block = 1000;
DECLARE_ALIGNED(16, int16_t, input_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, input_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_ref_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, output_block, kNumCoeffs);
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
input_block[j] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_); input_block[j] = rnd.Rand8() - rnd.Rand8();
fwd_txfm_ref(input_block, output_ref_block, pitch_, tx_type_); fwd_txfm_ref(input_block, output_ref_block, pitch_, tx_type_);
ASM_REGISTER_STATE_CHECK(RunFwdTxfm(input_block, output_block, pitch_)); REGISTER_STATE_CHECK(RunFwdTxfm(input_block, output_block, pitch_));
// The minimum quant value is 4. // The minimum quant value is 4.
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
@@ -408,31 +355,33 @@ class Trans16x16TestBase {
void RunMemCheck() { void RunMemCheck() {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 1000; const int count_test_block = 1000;
DECLARE_ALIGNED(16, int16_t, input_extreme_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, input_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_ref_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, input_extreme_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, output_block, kNumCoeffs);
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
input_extreme_block[j] = rnd.Rand8() % 2 ? mask_ : -mask_; input_block[j] = rnd.Rand8() - rnd.Rand8();
input_extreme_block[j] = rnd.Rand8() % 2 ? 255 : -255;
} }
if (i == 0) { if (i == 0) {
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = mask_; input_extreme_block[j] = 255;
} else if (i == 1) { } else if (i == 1) {
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = -mask_; input_extreme_block[j] = -255;
} }
fwd_txfm_ref(input_extreme_block, output_ref_block, pitch_, tx_type_); fwd_txfm_ref(input_extreme_block, output_ref_block, pitch_, tx_type_);
ASM_REGISTER_STATE_CHECK(RunFwdTxfm(input_extreme_block, REGISTER_STATE_CHECK(RunFwdTxfm(input_extreme_block,
output_block, pitch_)); output_block, pitch_));
// The minimum quant value is 4. // The minimum quant value is 4.
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
EXPECT_EQ(output_block[j], output_ref_block[j]); EXPECT_EQ(output_block[j], output_ref_block[j]);
EXPECT_GE(4 * DCT_MAX_VALUE << (bit_depth_ - 8), abs(output_block[j])) EXPECT_GE(4 * DCT_MAX_VALUE, abs(output_block[j]))
<< "Error: 16x16 FDCT has coefficient larger than 4*DCT_MAX_VALUE"; << "Error: 16x16 FDCT has coefficient larger than 4*DCT_MAX_VALUE";
} }
} }
@@ -440,116 +389,71 @@ class Trans16x16TestBase {
void RunQuantCheck(int dc_thred, int ac_thred) { void RunQuantCheck(int dc_thred, int ac_thred) {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 100000; const int count_test_block = 1000;
DECLARE_ALIGNED(16, int16_t, input_extreme_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, input_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_ref_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, input_extreme_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, ref[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, ref, kNumCoeffs);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, ref16[kNumCoeffs]);
#endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
input_extreme_block[j] = rnd.Rand8() % 2 ? mask_ : -mask_; input_block[j] = rnd.Rand8() - rnd.Rand8();
input_extreme_block[j] = rnd.Rand8() % 2 ? 255 : -255;
} }
if (i == 0) if (i == 0)
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = mask_; input_extreme_block[j] = 255;
if (i == 1) if (i == 1)
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = -mask_; input_extreme_block[j] = -255;
fwd_txfm_ref(input_extreme_block, output_ref_block, pitch_, tx_type_); fwd_txfm_ref(input_extreme_block, output_ref_block, pitch_, tx_type_);
// clear reconstructed pixel buffers // clear reconstructed pixel buffers
memset(dst, 0, kNumCoeffs * sizeof(uint8_t)); vpx_memset(dst, 0, kNumCoeffs * sizeof(uint8_t));
memset(ref, 0, kNumCoeffs * sizeof(uint8_t)); vpx_memset(ref, 0, kNumCoeffs * sizeof(uint8_t));
#if CONFIG_VPX_HIGHBITDEPTH
memset(dst16, 0, kNumCoeffs * sizeof(uint16_t));
memset(ref16, 0, kNumCoeffs * sizeof(uint16_t));
#endif
// quantization with maximum allowed step sizes // quantization with maximum allowed step sizes
output_ref_block[0] = (output_ref_block[0] / dc_thred) * dc_thred; output_ref_block[0] = (output_ref_block[0] / dc_thred) * dc_thred;
for (int j = 1; j < kNumCoeffs; ++j) for (int j = 1; j < kNumCoeffs; ++j)
output_ref_block[j] = (output_ref_block[j] / ac_thred) * ac_thred; output_ref_block[j] = (output_ref_block[j] / ac_thred) * ac_thred;
if (bit_depth_ == VPX_BITS_8) {
inv_txfm_ref(output_ref_block, ref, pitch_, tx_type_); inv_txfm_ref(output_ref_block, ref, pitch_, tx_type_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(output_ref_block, dst, pitch_)); REGISTER_STATE_CHECK(RunInvTxfm(output_ref_block, dst, pitch_));
#if CONFIG_VPX_HIGHBITDEPTH
} else {
inv_txfm_ref(output_ref_block, CONVERT_TO_BYTEPTR(ref16), pitch_,
tx_type_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(output_ref_block,
CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif
}
if (bit_depth_ == VPX_BITS_8) {
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
EXPECT_EQ(ref[j], dst[j]); EXPECT_EQ(ref[j], dst[j]);
#if CONFIG_VPX_HIGHBITDEPTH
} else {
for (int j = 0; j < kNumCoeffs; ++j)
EXPECT_EQ(ref16[j], dst16[j]);
#endif
}
} }
} }
void RunInvAccuracyCheck() { void RunInvAccuracyCheck() {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 1000; const int count_test_block = 1000;
DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, in, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, coeff, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]);
#endif // CONFIG_VPX_HIGHBITDEPTH
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
double out_r[kNumCoeffs]; double out_r[kNumCoeffs];
// Initialize a test block with input range [-255, 255]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
if (bit_depth_ == VPX_BITS_8) {
src[j] = rnd.Rand8(); src[j] = rnd.Rand8();
dst[j] = rnd.Rand8(); dst[j] = rnd.Rand8();
in[j] = src[j] - dst[j]; in[j] = src[j] - dst[j];
#if CONFIG_VPX_HIGHBITDEPTH
} else {
src16[j] = rnd.Rand16() & mask_;
dst16[j] = rnd.Rand16() & mask_;
in[j] = src16[j] - dst16[j];
#endif // CONFIG_VPX_HIGHBITDEPTH
}
} }
reference_16x16_dct_2d(in, out_r); reference_16x16_dct_2d(in, out_r);
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
coeff[j] = static_cast<tran_low_t>(round(out_r[j])); coeff[j] = round(out_r[j]);
if (bit_depth_ == VPX_BITS_8) { REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, 16));
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, 16));
#if CONFIG_VPX_HIGHBITDEPTH
} else {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
16));
#endif // CONFIG_VPX_HIGHBITDEPTH
}
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VPX_HIGHBITDEPTH
const uint32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
const uint32_t diff = dst[j] - src[j]; const uint32_t diff = dst[j] - src[j];
#endif // CONFIG_VPX_HIGHBITDEPTH
const uint32_t error = diff * diff; const uint32_t error = diff * diff;
EXPECT_GE(1u, error) EXPECT_GE(1u, error)
<< "Error: 16x16 IDCT has error " << error << "Error: 16x16 IDCT has error " << error
@@ -557,75 +461,15 @@ class Trans16x16TestBase {
} }
} }
} }
void CompareInvReference(IdctFunc ref_txfm, int thresh) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 10000;
const int eob = 10;
const int16_t *scan = vp10_default_scan_orders[TX_16X16].scan;
DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]);
DECLARE_ALIGNED(16, uint8_t, ref[kNumCoeffs]);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, ref16[kNumCoeffs]);
#endif // CONFIG_VPX_HIGHBITDEPTH
for (int i = 0; i < count_test_block; ++i) {
for (int j = 0; j < kNumCoeffs; ++j) {
if (j < eob) {
// Random values less than the threshold, either positive or negative
coeff[scan[j]] = rnd(thresh) * (1 - 2 * (i % 2));
} else {
coeff[scan[j]] = 0;
}
if (bit_depth_ == VPX_BITS_8) {
dst[j] = 0;
ref[j] = 0;
#if CONFIG_VPX_HIGHBITDEPTH
} else {
dst16[j] = 0;
ref16[j] = 0;
#endif // CONFIG_VPX_HIGHBITDEPTH
}
}
if (bit_depth_ == VPX_BITS_8) {
ref_txfm(coeff, ref, pitch_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
} else {
#if CONFIG_VPX_HIGHBITDEPTH
ref_txfm(coeff, CONVERT_TO_BYTEPTR(ref16), pitch_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
pitch_));
#endif // CONFIG_VPX_HIGHBITDEPTH
}
for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VPX_HIGHBITDEPTH
const uint32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - ref[j] : dst16[j] - ref16[j];
#else
const uint32_t diff = dst[j] - ref[j];
#endif // CONFIG_VPX_HIGHBITDEPTH
const uint32_t error = diff * diff;
EXPECT_EQ(0u, error)
<< "Error: 16x16 IDCT Comparison has error " << error
<< " at index " << j;
}
}
}
int pitch_; int pitch_;
int tx_type_; int tx_type_;
vpx_bit_depth_t bit_depth_; fht_t fwd_txfm_ref;
int mask_; iht_t inv_txfm_ref;
FhtFunc fwd_txfm_ref;
IhtFunc inv_txfm_ref;
}; };
class Trans16x16DCT class Trans16x16DCT
: public Trans16x16TestBase, : public Trans16x16TestBase,
public ::testing::TestWithParam<Dct16x16Param> { public ::testing::TestWithParam<dct_16x16_param_t> {
public: public:
virtual ~Trans16x16DCT() {} virtual ~Trans16x16DCT() {}
@@ -633,39 +477,22 @@ class Trans16x16DCT
fwd_txfm_ = GET_PARAM(0); fwd_txfm_ = GET_PARAM(0);
inv_txfm_ = GET_PARAM(1); inv_txfm_ = GET_PARAM(1);
tx_type_ = GET_PARAM(2); tx_type_ = GET_PARAM(2);
bit_depth_ = GET_PARAM(3);
pitch_ = 16; pitch_ = 16;
fwd_txfm_ref = fdct16x16_ref; fwd_txfm_ref = fdct16x16_ref;
inv_txfm_ref = idct16x16_ref; inv_txfm_ref = idct16x16_ref;
mask_ = (1 << bit_depth_) - 1;
#if CONFIG_VPX_HIGHBITDEPTH
switch (bit_depth_) {
case VPX_BITS_10:
inv_txfm_ref = idct16x16_10_ref;
break;
case VPX_BITS_12:
inv_txfm_ref = idct16x16_12_ref;
break;
default:
inv_txfm_ref = idct16x16_ref;
break;
}
#else
inv_txfm_ref = idct16x16_ref;
#endif
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected: protected:
void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) { void RunFwdTxfm(int16_t *in, int16_t *out, int stride) {
fwd_txfm_(in, out, stride); fwd_txfm_(in, out, stride);
} }
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { void RunInvTxfm(int16_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride); inv_txfm_(out, dst, stride);
} }
FdctFunc fwd_txfm_; fdct_t fwd_txfm_;
IdctFunc inv_txfm_; idct_t inv_txfm_;
}; };
TEST_P(Trans16x16DCT, AccuracyCheck) { TEST_P(Trans16x16DCT, AccuracyCheck) {
@@ -692,7 +519,7 @@ TEST_P(Trans16x16DCT, InvAccuracyCheck) {
class Trans16x16HT class Trans16x16HT
: public Trans16x16TestBase, : public Trans16x16TestBase,
public ::testing::TestWithParam<Ht16x16Param> { public ::testing::TestWithParam<ht_16x16_param_t> {
public: public:
virtual ~Trans16x16HT() {} virtual ~Trans16x16HT() {}
@@ -700,39 +527,22 @@ class Trans16x16HT
fwd_txfm_ = GET_PARAM(0); fwd_txfm_ = GET_PARAM(0);
inv_txfm_ = GET_PARAM(1); inv_txfm_ = GET_PARAM(1);
tx_type_ = GET_PARAM(2); tx_type_ = GET_PARAM(2);
bit_depth_ = GET_PARAM(3);
pitch_ = 16; pitch_ = 16;
fwd_txfm_ref = fht16x16_ref; fwd_txfm_ref = fht16x16_ref;
inv_txfm_ref = iht16x16_ref; inv_txfm_ref = iht16x16_ref;
mask_ = (1 << bit_depth_) - 1;
#if CONFIG_VPX_HIGHBITDEPTH
switch (bit_depth_) {
case VPX_BITS_10:
inv_txfm_ref = iht16x16_10;
break;
case VPX_BITS_12:
inv_txfm_ref = iht16x16_12;
break;
default:
inv_txfm_ref = iht16x16_ref;
break;
}
#else
inv_txfm_ref = iht16x16_ref;
#endif
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected: protected:
void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) { void RunFwdTxfm(int16_t *in, int16_t *out, int stride) {
fwd_txfm_(in, out, stride, tx_type_); fwd_txfm_(in, out, stride, tx_type_);
} }
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { void RunInvTxfm(int16_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride, tx_type_); inv_txfm_(out, dst, stride, tx_type_);
} }
FhtFunc fwd_txfm_; fht_t fwd_txfm_;
IhtFunc inv_txfm_; iht_t inv_txfm_;
}; };
TEST_P(Trans16x16HT, AccuracyCheck) { TEST_P(Trans16x16HT, AccuracyCheck) {
@@ -750,243 +560,50 @@ TEST_P(Trans16x16HT, MemCheck) {
TEST_P(Trans16x16HT, QuantCheck) { TEST_P(Trans16x16HT, QuantCheck) {
// The encoder skips any non-DC intra prediction modes, // The encoder skips any non-DC intra prediction modes,
// when the quantization step size goes beyond 988. // when the quantization step size goes beyond 988.
RunQuantCheck(429, 729); RunQuantCheck(549, 988);
}
class InvTrans16x16DCT
: public Trans16x16TestBase,
public ::testing::TestWithParam<Idct16x16Param> {
public:
virtual ~InvTrans16x16DCT() {}
virtual void SetUp() {
ref_txfm_ = GET_PARAM(0);
inv_txfm_ = GET_PARAM(1);
thresh_ = GET_PARAM(2);
bit_depth_ = GET_PARAM(3);
pitch_ = 16;
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) {}
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride);
}
IdctFunc ref_txfm_;
IdctFunc inv_txfm_;
int thresh_;
};
TEST_P(InvTrans16x16DCT, CompareReference) {
CompareInvReference(ref_txfm_, thresh_);
}
class PartialTrans16x16Test
: public ::testing::TestWithParam<
std::tr1::tuple<FdctFunc, vpx_bit_depth_t> > {
public:
virtual ~PartialTrans16x16Test() {}
virtual void SetUp() {
fwd_txfm_ = GET_PARAM(0);
bit_depth_ = GET_PARAM(1);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
vpx_bit_depth_t bit_depth_;
FdctFunc fwd_txfm_;
};
TEST_P(PartialTrans16x16Test, Extremes) {
#if CONFIG_VPX_HIGHBITDEPTH
const int16_t maxval =
static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
#else
const int16_t maxval = 255;
#endif
const int minval = -maxval;
DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
for (int i = 0; i < kNumCoeffs; ++i) input[i] = maxval;
output[0] = 0;
ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 16));
EXPECT_EQ((maxval * kNumCoeffs) >> 1, output[0]);
for (int i = 0; i < kNumCoeffs; ++i) input[i] = minval;
output[0] = 0;
ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 16));
EXPECT_EQ((minval * kNumCoeffs) >> 1, output[0]);
}
TEST_P(PartialTrans16x16Test, Random) {
#if CONFIG_VPX_HIGHBITDEPTH
const int16_t maxval =
static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
#else
const int16_t maxval = 255;
#endif
DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
ACMRandom rnd(ACMRandom::DeterministicSeed());
int sum = 0;
for (int i = 0; i < kNumCoeffs; ++i) {
const int val = (i & 1) ? -rnd(maxval + 1) : rnd(maxval + 1);
input[i] = val;
sum += val;
}
output[0] = 0;
ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 16));
EXPECT_EQ(sum >> 1, output[0]);
} }
using std::tr1::make_tuple; using std::tr1::make_tuple;
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, Trans16x16DCT, C, Trans16x16DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_highbd_fdct16x16_c, &idct16x16_10, 0, VPX_BITS_10), make_tuple(&vp9_fdct16x16_c, &vp9_idct16x16_256_add_c, 0)));
make_tuple(&vpx_highbd_fdct16x16_c, &idct16x16_12, 0, VPX_BITS_12),
make_tuple(&vpx_fdct16x16_c, &vpx_idct16x16_256_add_c, 0, VPX_BITS_8)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans16x16DCT,
::testing::Values(
make_tuple(&vpx_fdct16x16_c, &vpx_idct16x16_256_add_c, 0, VPX_BITS_8)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, Trans16x16HT, C, Trans16x16HT,
::testing::Values( ::testing::Values(
make_tuple(&vp10_highbd_fht16x16_c, &iht16x16_10, 0, VPX_BITS_10), make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 0),
make_tuple(&vp10_highbd_fht16x16_c, &iht16x16_10, 1, VPX_BITS_10), make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 1),
make_tuple(&vp10_highbd_fht16x16_c, &iht16x16_10, 2, VPX_BITS_10), make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 2),
make_tuple(&vp10_highbd_fht16x16_c, &iht16x16_10, 3, VPX_BITS_10), make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 3)));
make_tuple(&vp10_highbd_fht16x16_c, &iht16x16_12, 0, VPX_BITS_12),
make_tuple(&vp10_highbd_fht16x16_c, &iht16x16_12, 1, VPX_BITS_12),
make_tuple(&vp10_highbd_fht16x16_c, &iht16x16_12, 2, VPX_BITS_12),
make_tuple(&vp10_highbd_fht16x16_c, &iht16x16_12, 3, VPX_BITS_12),
make_tuple(&vp10_fht16x16_c, &vp10_iht16x16_256_add_c, 0, VPX_BITS_8),
make_tuple(&vp10_fht16x16_c, &vp10_iht16x16_256_add_c, 1, VPX_BITS_8),
make_tuple(&vp10_fht16x16_c, &vp10_iht16x16_256_add_c, 2, VPX_BITS_8),
make_tuple(&vp10_fht16x16_c, &vp10_iht16x16_256_add_c, 3, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
C, PartialTrans16x16Test,
::testing::Values(make_tuple(&vpx_highbd_fdct16x16_1_c, VPX_BITS_8),
make_tuple(&vpx_highbd_fdct16x16_1_c, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct16x16_1_c, VPX_BITS_12)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans16x16HT,
::testing::Values(
make_tuple(&vp10_fht16x16_c, &vp10_iht16x16_256_add_c, 0, VPX_BITS_8),
make_tuple(&vp10_fht16x16_c, &vp10_iht16x16_256_add_c, 1, VPX_BITS_8),
make_tuple(&vp10_fht16x16_c, &vp10_iht16x16_256_add_c, 2, VPX_BITS_8),
make_tuple(&vp10_fht16x16_c, &vp10_iht16x16_256_add_c, 3, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(C, PartialTrans16x16Test,
::testing::Values(make_tuple(&vpx_fdct16x16_1_c,
VPX_BITS_8)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#if HAVE_NEON_ASM && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_NEON_ASM
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
NEON, Trans16x16DCT, NEON, Trans16x16DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct16x16_c, make_tuple(&vp9_fdct16x16_c,
&vpx_idct16x16_256_add_neon, 0, VPX_BITS_8))); &vp9_idct16x16_256_add_neon, 0)));
#endif #endif
#if HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSE2
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16DCT, SSE2, Trans16x16DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct16x16_sse2, make_tuple(&vp9_fdct16x16_sse2,
&vpx_idct16x16_256_add_sse2, 0, VPX_BITS_8))); &vp9_idct16x16_256_add_sse2, 0)));
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16HT, SSE2, Trans16x16HT,
::testing::Values( ::testing::Values(
make_tuple(&vp10_fht16x16_sse2, &vp10_iht16x16_256_add_sse2, 0, make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 0),
VPX_BITS_8), make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 1),
make_tuple(&vp10_fht16x16_sse2, &vp10_iht16x16_256_add_sse2, 1, make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 2),
VPX_BITS_8), make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 3)));
make_tuple(&vp10_fht16x16_sse2, &vp10_iht16x16_256_add_sse2, 2, #endif
VPX_BITS_8),
make_tuple(&vp10_fht16x16_sse2, &vp10_iht16x16_256_add_sse2, 3,
VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans16x16Test,
::testing::Values(make_tuple(&vpx_fdct16x16_1_sse2,
VPX_BITS_8)));
#endif // HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSSE3
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16DCT, SSSE3, Trans16x16DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_highbd_fdct16x16_sse2, make_tuple(&vp9_fdct16x16_c, &vp9_idct16x16_256_add_ssse3, 0)));
&idct16x16_10, 0, VPX_BITS_10), #endif
make_tuple(&vpx_highbd_fdct16x16_c,
&idct16x16_256_add_10_sse2, 0, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct16x16_sse2,
&idct16x16_12, 0, VPX_BITS_12),
make_tuple(&vpx_highbd_fdct16x16_c,
&idct16x16_256_add_12_sse2, 0, VPX_BITS_12),
make_tuple(&vpx_fdct16x16_sse2,
&vpx_idct16x16_256_add_c, 0, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16HT,
::testing::Values(
make_tuple(&vp10_fht16x16_sse2,
&vp10_iht16x16_256_add_c, 0, VPX_BITS_8),
make_tuple(&vp10_fht16x16_sse2,
&vp10_iht16x16_256_add_c, 1, VPX_BITS_8),
make_tuple(&vp10_fht16x16_sse2,
&vp10_iht16x16_256_add_c, 2, VPX_BITS_8),
make_tuple(&vp10_fht16x16_sse2, &vp10_iht16x16_256_add_c, 3,
VPX_BITS_8)));
// Optimizations take effect at a threshold of 3155, so we use a value close to
// that to test both branches.
INSTANTIATE_TEST_CASE_P(
SSE2, InvTrans16x16DCT,
::testing::Values(
make_tuple(&idct16x16_10_add_10_c,
&idct16x16_10_add_10_sse2, 3167, VPX_BITS_10),
make_tuple(&idct16x16_10,
&idct16x16_256_add_10_sse2, 3167, VPX_BITS_10),
make_tuple(&idct16x16_10_add_12_c,
&idct16x16_10_add_12_sse2, 3167, VPX_BITS_12),
make_tuple(&idct16x16_12,
&idct16x16_256_add_12_sse2, 3167, VPX_BITS_12)));
INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans16x16Test,
::testing::Values(make_tuple(&vpx_fdct16x16_1_sse2,
VPX_BITS_8)));
#endif // HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
MSA, Trans16x16DCT,
::testing::Values(
make_tuple(&vpx_fdct16x16_msa,
&vpx_idct16x16_256_add_msa, 0, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
MSA, Trans16x16HT,
::testing::Values(
make_tuple(&vp10_fht16x16_msa,
&vp10_iht16x16_256_add_msa, 0, VPX_BITS_8),
make_tuple(&vp10_fht16x16_msa,
&vp10_iht16x16_256_add_msa, 1, VPX_BITS_8),
make_tuple(&vp10_fht16x16_msa,
&vp10_iht16x16_256_add_msa, 2, VPX_BITS_8),
make_tuple(&vp10_fht16x16_msa,
&vp10_iht16x16_256_add_msa, 3, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(MSA, PartialTrans16x16Test,
::testing::Values(make_tuple(&vpx_fdct16x16_1_msa,
VPX_BITS_8)));
#endif // HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace } // namespace

View File

@@ -13,27 +13,31 @@
#include <string.h> #include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vp10_rtcd.h"
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h" #include "test/acm_random.h"
#include "test/clear_system_state.h" #include "test/clear_system_state.h"
#include "test/register_state_check.h" #include "test/register_state_check.h"
#include "test/util.h" #include "test/util.h"
#include "vp10/common/entropy.h"
#include "vpx/vpx_codec.h" #include "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_integer.h" #include "vpx/vpx_integer.h"
#include "vpx_ports/mem.h"
#include "vpx_ports/msvc.h" // for round()
using libvpx_test::ACMRandom; using libvpx_test::ACMRandom;
namespace { namespace {
#ifdef _MSC_VER
static int round(double x) {
if (x < 0)
return static_cast<int>(ceil(x - 0.5));
else
return static_cast<int>(floor(x + 0.5));
}
#endif
const int kNumCoeffs = 1024; const int kNumCoeffs = 1024;
const double kPi = 3.141592653589793238462643383279502884; const double kPi = 3.141592653589793238462643383279502884;
void reference_32x32_dct_1d(const double in[32], double out[32]) { void reference_32x32_dct_1d(const double in[32], double out[32], int stride) {
const double kInvSqrt2 = 0.707106781186547524400844362104; const double kInvSqrt2 = 0.707106781186547524400844362104;
for (int k = 0; k < 32; k++) { for (int k = 0; k < 32; k++) {
out[k] = 0.0; out[k] = 0.0;
@@ -51,7 +55,7 @@ void reference_32x32_dct_2d(const int16_t input[kNumCoeffs],
double temp_in[32], temp_out[32]; double temp_in[32], temp_out[32];
for (int j = 0; j < 32; ++j) for (int j = 0; j < 32; ++j)
temp_in[j] = input[j*32 + i]; temp_in[j] = input[j*32 + i];
reference_32x32_dct_1d(temp_in, temp_out); reference_32x32_dct_1d(temp_in, temp_out, 1);
for (int j = 0; j < 32; ++j) for (int j = 0; j < 32; ++j)
output[j * 32 + i] = temp_out[j]; output[j * 32 + i] = temp_out[j];
} }
@@ -60,30 +64,19 @@ void reference_32x32_dct_2d(const int16_t input[kNumCoeffs],
double temp_in[32], temp_out[32]; double temp_in[32], temp_out[32];
for (int j = 0; j < 32; ++j) for (int j = 0; j < 32; ++j)
temp_in[j] = output[j + i*32]; temp_in[j] = output[j + i*32];
reference_32x32_dct_1d(temp_in, temp_out); reference_32x32_dct_1d(temp_in, temp_out, 1);
// Scale by some magic number // Scale by some magic number
for (int j = 0; j < 32; ++j) for (int j = 0; j < 32; ++j)
output[j + i * 32] = temp_out[j] / 4; output[j + i * 32] = temp_out[j] / 4;
} }
} }
typedef void (*FwdTxfmFunc)(const int16_t *in, tran_low_t *out, int stride); typedef void (*fwd_txfm_t)(const int16_t *in, int16_t *out, int stride);
typedef void (*InvTxfmFunc)(const tran_low_t *in, uint8_t *out, int stride); typedef void (*inv_txfm_t)(const int16_t *in, uint8_t *out, int stride);
typedef std::tr1::tuple<FwdTxfmFunc, InvTxfmFunc, int, vpx_bit_depth_t> typedef std::tr1::tuple<fwd_txfm_t, inv_txfm_t, int> trans_32x32_param_t;
Trans32x32Param;
#if CONFIG_VPX_HIGHBITDEPTH class Trans32x32Test : public ::testing::TestWithParam<trans_32x32_param_t> {
void idct32x32_10(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct32x32_1024_add_c(in, out, stride, 10);
}
void idct32x32_12(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct32x32_1024_add_c(in, out, stride, 12);
}
#endif // CONFIG_VPX_HIGHBITDEPTH
class Trans32x32Test : public ::testing::TestWithParam<Trans32x32Param> {
public: public:
virtual ~Trans32x32Test() {} virtual ~Trans32x32Test() {}
virtual void SetUp() { virtual void SetUp() {
@@ -91,67 +84,39 @@ class Trans32x32Test : public ::testing::TestWithParam<Trans32x32Param> {
inv_txfm_ = GET_PARAM(1); inv_txfm_ = GET_PARAM(1);
version_ = GET_PARAM(2); // 0: high precision forward transform version_ = GET_PARAM(2); // 0: high precision forward transform
// 1: low precision version for rd loop // 1: low precision version for rd loop
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected: protected:
int version_; int version_;
vpx_bit_depth_t bit_depth_; fwd_txfm_t fwd_txfm_;
int mask_; inv_txfm_t inv_txfm_;
FwdTxfmFunc fwd_txfm_;
InvTxfmFunc inv_txfm_;
}; };
TEST_P(Trans32x32Test, AccuracyCheck) { TEST_P(Trans32x32Test, AccuracyCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
uint32_t max_error = 0; uint32_t max_error = 0;
int64_t total_error = 0; int64_t total_error = 0;
const int count_test_block = 10000; const int count_test_block = 1000;
DECLARE_ALIGNED(16, int16_t, test_input_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, test_temp_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]);
#endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
if (bit_depth_ == VPX_BITS_8) {
src[j] = rnd.Rand8(); src[j] = rnd.Rand8();
dst[j] = rnd.Rand8(); dst[j] = rnd.Rand8();
test_input_block[j] = src[j] - dst[j]; test_input_block[j] = src[j] - dst[j];
#if CONFIG_VPX_HIGHBITDEPTH
} else {
src16[j] = rnd.Rand16() & mask_;
dst16[j] = rnd.Rand16() & mask_;
test_input_block[j] = src16[j] - dst16[j];
#endif
}
} }
ASM_REGISTER_STATE_CHECK(fwd_txfm_(test_input_block, test_temp_block, 32)); REGISTER_STATE_CHECK(fwd_txfm_(test_input_block, test_temp_block, 32));
if (bit_depth_ == VPX_BITS_8) { REGISTER_STATE_CHECK(inv_txfm_(test_temp_block, dst, 32));
ASM_REGISTER_STATE_CHECK(inv_txfm_(test_temp_block, dst, 32));
#if CONFIG_VPX_HIGHBITDEPTH
} else {
ASM_REGISTER_STATE_CHECK(inv_txfm_(test_temp_block,
CONVERT_TO_BYTEPTR(dst16), 32));
#endif
}
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VPX_HIGHBITDEPTH const uint32_t diff = dst[j] - src[j];
const int32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
const int32_t diff = dst[j] - src[j];
#endif
const uint32_t error = diff * diff; const uint32_t error = diff * diff;
if (max_error < error) if (max_error < error)
max_error = error; max_error = error;
@@ -164,10 +129,10 @@ TEST_P(Trans32x32Test, AccuracyCheck) {
total_error /= 45; total_error /= 45;
} }
EXPECT_GE(1u << 2 * (bit_depth_ - 8), max_error) EXPECT_GE(1u, max_error)
<< "Error: 32x32 FDCT/IDCT has an individual round-trip error > 1"; << "Error: 32x32 FDCT/IDCT has an individual round-trip error > 1";
EXPECT_GE(count_test_block << 2 * (bit_depth_ - 8), total_error) EXPECT_GE(count_test_block, total_error)
<< "Error: 32x32 FDCT/IDCT has average round-trip error > 1 per block"; << "Error: 32x32 FDCT/IDCT has average round-trip error > 1 per block";
} }
@@ -175,17 +140,17 @@ TEST_P(Trans32x32Test, CoeffCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 1000; const int count_test_block = 1000;
DECLARE_ALIGNED(16, int16_t, input_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, input_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_ref_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, output_block, kNumCoeffs);
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
input_block[j] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_); input_block[j] = rnd.Rand8() - rnd.Rand8();
const int stride = 32; const int stride = 32;
vpx_fdct32x32_c(input_block, output_ref_block, stride); vp9_fdct32x32_c(input_block, output_ref_block, stride);
ASM_REGISTER_STATE_CHECK(fwd_txfm_(input_block, output_block, stride)); REGISTER_STATE_CHECK(fwd_txfm_(input_block, output_block, stride));
if (version_ == 0) { if (version_ == 0) {
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
@@ -203,27 +168,28 @@ TEST_P(Trans32x32Test, MemCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 2000; const int count_test_block = 2000;
DECLARE_ALIGNED(16, int16_t, input_extreme_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, input_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_ref_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, input_extreme_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, output_block, kNumCoeffs);
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
input_extreme_block[j] = rnd.Rand8() & 1 ? mask_ : -mask_; input_block[j] = rnd.Rand8() - rnd.Rand8();
input_extreme_block[j] = rnd.Rand8() & 1 ? 255 : -255;
} }
if (i == 0) { if (i == 0) {
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = mask_; input_extreme_block[j] = 255;
} else if (i == 1) { } else if (i == 1) {
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = -mask_; input_extreme_block[j] = -255;
} }
const int stride = 32; const int stride = 32;
vpx_fdct32x32_c(input_extreme_block, output_ref_block, stride); vp9_fdct32x32_c(input_extreme_block, output_ref_block, stride);
ASM_REGISTER_STATE_CHECK( REGISTER_STATE_CHECK(fwd_txfm_(input_extreme_block, output_block, stride));
fwd_txfm_(input_extreme_block, output_block, stride));
// The minimum quant value is 4. // The minimum quant value is 4.
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
@@ -234,9 +200,9 @@ TEST_P(Trans32x32Test, MemCheck) {
EXPECT_GE(6, abs(output_block[j] - output_ref_block[j])) EXPECT_GE(6, abs(output_block[j] - output_ref_block[j]))
<< "Error: 32x32 FDCT rd has mismatched coefficients"; << "Error: 32x32 FDCT rd has mismatched coefficients";
} }
EXPECT_GE(4 * DCT_MAX_VALUE << (bit_depth_ - 8), abs(output_ref_block[j])) EXPECT_GE(4 * DCT_MAX_VALUE, abs(output_ref_block[j]))
<< "Error: 32x32 FDCT C has coefficient larger than 4*DCT_MAX_VALUE"; << "Error: 32x32 FDCT C has coefficient larger than 4*DCT_MAX_VALUE";
EXPECT_GE(4 * DCT_MAX_VALUE << (bit_depth_ - 8), abs(output_block[j])) EXPECT_GE(4 * DCT_MAX_VALUE, abs(output_block[j]))
<< "Error: 32x32 FDCT has coefficient larger than " << "Error: 32x32 FDCT has coefficient larger than "
<< "4*DCT_MAX_VALUE"; << "4*DCT_MAX_VALUE";
} }
@@ -246,50 +212,27 @@ TEST_P(Trans32x32Test, MemCheck) {
TEST_P(Trans32x32Test, InverseAccuracy) { TEST_P(Trans32x32Test, InverseAccuracy) {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 1000; const int count_test_block = 1000;
DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, in, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, int16_t, coeff, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]);
#endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
double out_r[kNumCoeffs]; double out_r[kNumCoeffs];
// Initialize a test block with input range [-255, 255] // Initialize a test block with input range [-255, 255]
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
if (bit_depth_ == VPX_BITS_8) {
src[j] = rnd.Rand8(); src[j] = rnd.Rand8();
dst[j] = rnd.Rand8(); dst[j] = rnd.Rand8();
in[j] = src[j] - dst[j]; in[j] = src[j] - dst[j];
#if CONFIG_VPX_HIGHBITDEPTH
} else {
src16[j] = rnd.Rand16() & mask_;
dst16[j] = rnd.Rand16() & mask_;
in[j] = src16[j] - dst16[j];
#endif
}
} }
reference_32x32_dct_2d(in, out_r); reference_32x32_dct_2d(in, out_r);
for (int j = 0; j < kNumCoeffs; ++j) for (int j = 0; j < kNumCoeffs; ++j)
coeff[j] = static_cast<tran_low_t>(round(out_r[j])); coeff[j] = round(out_r[j]);
if (bit_depth_ == VPX_BITS_8) { REGISTER_STATE_CHECK(inv_txfm_(coeff, dst, 32));
ASM_REGISTER_STATE_CHECK(inv_txfm_(coeff, dst, 32));
#if CONFIG_VPX_HIGHBITDEPTH
} else {
ASM_REGISTER_STATE_CHECK(inv_txfm_(coeff, CONVERT_TO_BYTEPTR(dst16), 32));
#endif
}
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VPX_HIGHBITDEPTH
const int diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
const int diff = dst[j] - src[j]; const int diff = dst[j] - src[j];
#endif
const int error = diff * diff; const int error = diff * diff;
EXPECT_GE(1, error) EXPECT_GE(1, error)
<< "Error: 32x32 IDCT has error " << error << "Error: 32x32 IDCT has error " << error
@@ -298,165 +241,41 @@ TEST_P(Trans32x32Test, InverseAccuracy) {
} }
} }
class PartialTrans32x32Test
: public ::testing::TestWithParam<
std::tr1::tuple<FwdTxfmFunc, vpx_bit_depth_t> > {
public:
virtual ~PartialTrans32x32Test() {}
virtual void SetUp() {
fwd_txfm_ = GET_PARAM(0);
bit_depth_ = GET_PARAM(1);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
vpx_bit_depth_t bit_depth_;
FwdTxfmFunc fwd_txfm_;
};
TEST_P(PartialTrans32x32Test, Extremes) {
#if CONFIG_VPX_HIGHBITDEPTH
const int16_t maxval =
static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
#else
const int16_t maxval = 255;
#endif
const int minval = -maxval;
DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
for (int i = 0; i < kNumCoeffs; ++i) input[i] = maxval;
output[0] = 0;
ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 32));
EXPECT_EQ((maxval * kNumCoeffs) >> 3, output[0]);
for (int i = 0; i < kNumCoeffs; ++i) input[i] = minval;
output[0] = 0;
ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 32));
EXPECT_EQ((minval * kNumCoeffs) >> 3, output[0]);
}
TEST_P(PartialTrans32x32Test, Random) {
#if CONFIG_VPX_HIGHBITDEPTH
const int16_t maxval =
static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
#else
const int16_t maxval = 255;
#endif
DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
ACMRandom rnd(ACMRandom::DeterministicSeed());
int sum = 0;
for (int i = 0; i < kNumCoeffs; ++i) {
const int val = (i & 1) ? -rnd(maxval + 1) : rnd(maxval + 1);
input[i] = val;
sum += val;
}
output[0] = 0;
ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 32));
EXPECT_EQ(sum >> 3, output[0]);
}
using std::tr1::make_tuple; using std::tr1::make_tuple;
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, Trans32x32Test, C, Trans32x32Test,
::testing::Values( ::testing::Values(
make_tuple(&vpx_highbd_fdct32x32_c, make_tuple(&vp9_fdct32x32_c, &vp9_idct32x32_1024_add_c, 0),
&idct32x32_10, 0, VPX_BITS_10), make_tuple(&vp9_fdct32x32_rd_c, &vp9_idct32x32_1024_add_c, 1)));
make_tuple(&vpx_highbd_fdct32x32_rd_c,
&idct32x32_10, 1, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct32x32_c,
&idct32x32_12, 0, VPX_BITS_12),
make_tuple(&vpx_highbd_fdct32x32_rd_c,
&idct32x32_12, 1, VPX_BITS_12),
make_tuple(&vpx_fdct32x32_c,
&vpx_idct32x32_1024_add_c, 0, VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_c,
&vpx_idct32x32_1024_add_c, 1, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
C, PartialTrans32x32Test,
::testing::Values(make_tuple(&vpx_highbd_fdct32x32_1_c, VPX_BITS_8),
make_tuple(&vpx_highbd_fdct32x32_1_c, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct32x32_1_c, VPX_BITS_12)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans32x32Test,
::testing::Values(
make_tuple(&vpx_fdct32x32_c,
&vpx_idct32x32_1024_add_c, 0, VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_c,
&vpx_idct32x32_1024_add_c, 1, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(C, PartialTrans32x32Test,
::testing::Values(make_tuple(&vpx_fdct32x32_1_c,
VPX_BITS_8)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#if HAVE_NEON && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_NEON_ASM
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
NEON, Trans32x32Test, NEON, Trans32x32Test,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct32x32_c, make_tuple(&vp9_fdct32x32_c,
&vpx_idct32x32_1024_add_neon, 0, VPX_BITS_8), &vp9_idct32x32_1024_add_neon, 0),
make_tuple(&vpx_fdct32x32_rd_c, make_tuple(&vp9_fdct32x32_rd_c,
&vpx_idct32x32_1024_add_neon, 1, VPX_BITS_8))); &vp9_idct32x32_1024_add_neon, 1)));
#endif // HAVE_NEON && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #endif
#if HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSE2
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans32x32Test, SSE2, Trans32x32Test,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct32x32_sse2, make_tuple(&vp9_fdct32x32_sse2,
&vpx_idct32x32_1024_add_sse2, 0, VPX_BITS_8), &vp9_idct32x32_1024_add_sse2, 0),
make_tuple(&vpx_fdct32x32_rd_sse2, make_tuple(&vp9_fdct32x32_rd_sse2,
&vpx_idct32x32_1024_add_sse2, 1, VPX_BITS_8))); &vp9_idct32x32_1024_add_sse2, 1)));
INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans32x32Test, #endif
::testing::Values(make_tuple(&vpx_fdct32x32_1_sse2,
VPX_BITS_8)));
#endif // HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_AVX2
INSTANTIATE_TEST_CASE_P(
SSE2, Trans32x32Test,
::testing::Values(
make_tuple(&vpx_highbd_fdct32x32_sse2, &idct32x32_10, 0, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct32x32_rd_sse2, &idct32x32_10, 1,
VPX_BITS_10),
make_tuple(&vpx_highbd_fdct32x32_sse2, &idct32x32_12, 0, VPX_BITS_12),
make_tuple(&vpx_highbd_fdct32x32_rd_sse2, &idct32x32_12, 1,
VPX_BITS_12),
make_tuple(&vpx_fdct32x32_sse2, &vpx_idct32x32_1024_add_c, 0,
VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_sse2, &vpx_idct32x32_1024_add_c, 1,
VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans32x32Test,
::testing::Values(make_tuple(&vpx_fdct32x32_1_sse2,
VPX_BITS_8)));
#endif // HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_AVX2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
AVX2, Trans32x32Test, AVX2, Trans32x32Test,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct32x32_avx2, make_tuple(&vp9_fdct32x32_avx2,
&vpx_idct32x32_1024_add_sse2, 0, VPX_BITS_8), &vp9_idct32x32_1024_add_sse2, 0),
make_tuple(&vpx_fdct32x32_rd_avx2, make_tuple(&vp9_fdct32x32_rd_avx2,
&vpx_idct32x32_1024_add_sse2, 1, VPX_BITS_8))); &vp9_idct32x32_1024_add_sse2, 1)));
#endif // HAVE_AVX2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #endif
#if HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
MSA, Trans32x32Test,
::testing::Values(
make_tuple(&vpx_fdct32x32_msa,
&vpx_idct32x32_1024_add_msa, 0, VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_msa,
&vpx_idct32x32_1024_add_msa, 1, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(MSA, PartialTrans32x32Test,
::testing::Values(make_tuple(&vpx_fdct32x32_1_msa,
VPX_BITS_8)));
#endif // HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace } // namespace

View File

@@ -1,58 +0,0 @@
/*
* Copyright (c) 2014 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 "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "test/ivf_video_source.h"
#include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h"
namespace {
#define NELEMENTS(x) static_cast<int>(sizeof(x) / sizeof(x[0]))
TEST(DecodeAPI, InvalidParams) {
static const vpx_codec_iface_t *kCodecs[] = {
#if CONFIG_VP10_DECODER
&vpx_codec_vp10_dx_algo,
#endif
};
uint8_t buf[1] = {0};
vpx_codec_ctx_t dec;
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_dec_init(NULL, NULL, NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_dec_init(&dec, NULL, NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_decode(NULL, NULL, 0, NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_decode(NULL, buf, 0, NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_decode(NULL, buf, NELEMENTS(buf), NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_decode(NULL, NULL, NELEMENTS(buf), NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_destroy(NULL));
EXPECT_TRUE(vpx_codec_error(NULL) != NULL);
for (int i = 0; i < NELEMENTS(kCodecs); ++i) {
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_dec_init(NULL, kCodecs[i], NULL, 0));
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_dec_init(&dec, kCodecs[i], NULL, 0));
EXPECT_EQ(VPX_CODEC_UNSUP_BITSTREAM,
vpx_codec_decode(&dec, buf, NELEMENTS(buf), NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_decode(&dec, NULL, NELEMENTS(buf), NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_decode(&dec, buf, 0, NULL, 0));
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_destroy(&dec));
}
}
} // namespace

View File

@@ -8,17 +8,13 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include <string>
#include "test/codec_factory.h" #include "test/codec_factory.h"
#include "test/decode_test_driver.h" #include "test/decode_test_driver.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/ivf_video_source.h" #include "test/ivf_video_source.h"
#include "test/md5_helper.h" #include "test/md5_helper.h"
#include "test/util.h" #include "test/util.h"
#include "test/webm_video_source.h" #include "test/webm_video_source.h"
#include "vpx_ports/vpx_timer.h" #include "vpx_ports/vpx_timer.h"
#include "./ivfenc.h"
#include "./vpx_version.h" #include "./vpx_version.h"
using std::tr1::make_tuple; using std::tr1::make_tuple;
@@ -28,16 +24,14 @@ namespace {
#define VIDEO_NAME 0 #define VIDEO_NAME 0
#define THREADS 1 #define THREADS 1
const int kMaxPsnr = 100;
const double kUsecsInSec = 1000000.0; const double kUsecsInSec = 1000000.0;
const char kNewEncodeOutputFile[] = "new_encode.ivf";
/* /*
DecodePerfTest takes a tuple of filename + number of threads to decode with DecodePerfTest takes a tuple of filename + number of threads to decode with
*/ */
typedef std::tr1::tuple<const char *, unsigned> DecodePerfParam; typedef std::tr1::tuple<const char *, unsigned> decode_perf_param_t;
const DecodePerfParam kVP9DecodePerfVectors[] = { const decode_perf_param_t kVP9DecodePerfVectors[] = {
make_tuple("vp90-2-bbb_426x240_tile_1x1_180kbps.webm", 1), make_tuple("vp90-2-bbb_426x240_tile_1x1_180kbps.webm", 1),
make_tuple("vp90-2-bbb_640x360_tile_1x2_337kbps.webm", 2), make_tuple("vp90-2-bbb_640x360_tile_1x2_337kbps.webm", 2),
make_tuple("vp90-2-bbb_854x480_tile_1x2_651kbps.webm", 2), make_tuple("vp90-2-bbb_854x480_tile_1x2_651kbps.webm", 2),
@@ -53,9 +47,7 @@ const DecodePerfParam kVP9DecodePerfVectors[] = {
make_tuple("vp90-2-tos_426x178_tile_1x1_181kbps.webm", 1), make_tuple("vp90-2-tos_426x178_tile_1x1_181kbps.webm", 1),
make_tuple("vp90-2-tos_640x266_tile_1x2_336kbps.webm", 2), make_tuple("vp90-2-tos_640x266_tile_1x2_336kbps.webm", 2),
make_tuple("vp90-2-tos_854x356_tile_1x2_656kbps.webm", 2), make_tuple("vp90-2-tos_854x356_tile_1x2_656kbps.webm", 2),
make_tuple("vp90-2-tos_854x356_tile_1x2_fpm_546kbps.webm", 2),
make_tuple("vp90-2-tos_1280x534_tile_1x4_1306kbps.webm", 4), make_tuple("vp90-2-tos_1280x534_tile_1x4_1306kbps.webm", 4),
make_tuple("vp90-2-tos_1280x534_tile_1x4_fpm_952kbps.webm", 4),
make_tuple("vp90-2-tos_1920x800_tile_1x4_fpm_2335kbps.webm", 4), make_tuple("vp90-2-tos_1920x800_tile_1x4_fpm_2335kbps.webm", 4),
}; };
@@ -70,7 +62,7 @@ const DecodePerfParam kVP9DecodePerfVectors[] = {
power/temp/min max frame decode times/etc power/temp/min max frame decode times/etc
*/ */
class DecodePerfTest : public ::testing::TestWithParam<DecodePerfParam> { class DecodePerfTest : public ::testing::TestWithParam<decode_perf_param_t> {
}; };
TEST_P(DecodePerfTest, PerfTest) { TEST_P(DecodePerfTest, PerfTest) {
@@ -80,7 +72,7 @@ TEST_P(DecodePerfTest, PerfTest) {
libvpx_test::WebMVideoSource video(video_name); libvpx_test::WebMVideoSource video(video_name);
video.Init(); video.Init();
vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t(); vpx_codec_dec_cfg_t cfg = {0};
cfg.threads = threads; cfg.threads = threads;
libvpx_test::VP9Decoder decoder(cfg, 0); libvpx_test::VP9Decoder decoder(cfg, 0);
@@ -98,7 +90,6 @@ TEST_P(DecodePerfTest, PerfTest) {
const double fps = double(frames) / elapsed_secs; const double fps = double(frames) / elapsed_secs;
printf("{\n"); printf("{\n");
printf("\t\"type\" : \"decode_perf_test\",\n");
printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP); printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
printf("\t\"videoName\" : \"%s\",\n", video_name); printf("\t\"videoName\" : \"%s\",\n", video_name);
printf("\t\"threadCount\" : %u,\n", threads); printf("\t\"threadCount\" : %u,\n", threads);
@@ -111,163 +102,4 @@ TEST_P(DecodePerfTest, PerfTest) {
INSTANTIATE_TEST_CASE_P(VP9, DecodePerfTest, INSTANTIATE_TEST_CASE_P(VP9, DecodePerfTest,
::testing::ValuesIn(kVP9DecodePerfVectors)); ::testing::ValuesIn(kVP9DecodePerfVectors));
class VP9NewEncodeDecodePerfTest :
public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected:
VP9NewEncodeDecodePerfTest()
: EncoderTest(GET_PARAM(0)),
encoding_mode_(GET_PARAM(1)),
speed_(0),
outfile_(0),
out_frames_(0) {
}
virtual ~VP9NewEncodeDecodePerfTest() {}
virtual void SetUp() {
InitializeConfig();
SetMode(encoding_mode_);
cfg_.g_lag_in_frames = 25;
cfg_.rc_min_quantizer = 2;
cfg_.rc_max_quantizer = 56;
cfg_.rc_dropframe_thresh = 0;
cfg_.rc_undershoot_pct = 50;
cfg_.rc_overshoot_pct = 50;
cfg_.rc_buf_sz = 1000;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 600;
cfg_.rc_resize_allowed = 0;
cfg_.rc_end_usage = VPX_VBR;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, speed_);
encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
encoder->Control(VP9E_SET_TILE_COLUMNS, 2);
}
}
virtual void BeginPassHook(unsigned int /*pass*/) {
const std::string data_path = getenv("LIBVPX_TEST_DATA_PATH");
const std::string path_to_source = data_path + "/" + kNewEncodeOutputFile;
outfile_ = fopen(path_to_source.c_str(), "wb");
ASSERT_TRUE(outfile_ != NULL);
}
virtual void EndPassHook() {
if (outfile_ != NULL) {
if (!fseek(outfile_, 0, SEEK_SET))
ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);
fclose(outfile_);
outfile_ = NULL;
}
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
++out_frames_;
// Write initial file header if first frame.
if (pkt->data.frame.pts == 0)
ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);
// Write frame header and data.
ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz);
ASSERT_EQ(fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_),
pkt->data.frame.sz);
}
virtual bool DoDecode() { return false; }
void set_speed(unsigned int speed) {
speed_ = speed;
}
private:
libvpx_test::TestMode encoding_mode_;
uint32_t speed_;
FILE *outfile_;
uint32_t out_frames_;
};
struct EncodePerfTestVideo {
EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
uint32_t bitrate_, int frames_)
: name(name_),
width(width_),
height(height_),
bitrate(bitrate_),
frames(frames_) {}
const char *name;
uint32_t width;
uint32_t height;
uint32_t bitrate;
int frames;
};
const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
};
TEST_P(VP9NewEncodeDecodePerfTest, PerfTest) {
SetUp();
// TODO(JBB): Make this work by going through the set of given files.
const int i = 0;
const vpx_rational timebase = { 33333333, 1000000000 };
cfg_.g_timebase = timebase;
cfg_.rc_target_bitrate = kVP9EncodePerfTestVectors[i].bitrate;
init_flags_ = VPX_CODEC_USE_PSNR;
const char *video_name = kVP9EncodePerfTestVectors[i].name;
libvpx_test::I420VideoSource video(
video_name,
kVP9EncodePerfTestVectors[i].width,
kVP9EncodePerfTestVectors[i].height,
timebase.den, timebase.num, 0,
kVP9EncodePerfTestVectors[i].frames);
set_speed(2);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
const uint32_t threads = 4;
libvpx_test::IVFVideoSource decode_video(kNewEncodeOutputFile);
decode_video.Init();
vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
cfg.threads = threads;
libvpx_test::VP9Decoder decoder(cfg, 0);
vpx_usec_timer t;
vpx_usec_timer_start(&t);
for (decode_video.Begin(); decode_video.cxdata() != NULL;
decode_video.Next()) {
decoder.DecodeFrame(decode_video.cxdata(), decode_video.frame_size());
}
vpx_usec_timer_mark(&t);
const double elapsed_secs =
static_cast<double>(vpx_usec_timer_elapsed(&t)) / kUsecsInSec;
const unsigned decode_frames = decode_video.frame_number();
const double fps = static_cast<double>(decode_frames) / elapsed_secs;
printf("{\n");
printf("\t\"type\" : \"decode_perf_test\",\n");
printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
printf("\t\"videoName\" : \"%s\",\n", kNewEncodeOutputFile);
printf("\t\"threadCount\" : %u,\n", threads);
printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
printf("\t\"totalFrames\" : %u,\n", decode_frames);
printf("\t\"framesPerSecond\" : %f\n", fps);
printf("}\n");
}
VP10_INSTANTIATE_TEST_CASE(
VP9NewEncodeDecodePerfTest, ::testing::Values(::libvpx_test::kTwoPassGood));
} // namespace } // namespace

View File

@@ -7,101 +7,35 @@
* in the file PATENTS. All contributing project authors may * in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h" #include "test/codec_factory.h"
#include "test/decode_test_driver.h" #include "test/decode_test_driver.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/register_state_check.h" #include "test/register_state_check.h"
#include "test/video_source.h" #include "test/video_source.h"
namespace libvpx_test { namespace libvpx_test {
const char kVP8Name[] = "WebM Project VP8";
const char kVP10Name[] = "WebM Project VP10";
vpx_codec_err_t Decoder::PeekStream(const uint8_t *cxdata, size_t size,
vpx_codec_stream_info_t *stream_info) {
return vpx_codec_peek_stream_info(CodecInterface(),
cxdata, static_cast<unsigned int>(size),
stream_info);
}
vpx_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size) { vpx_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size) {
return DecodeFrame(cxdata, size, NULL);
}
vpx_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size,
void *user_priv) {
vpx_codec_err_t res_dec; vpx_codec_err_t res_dec;
InitOnce(); InitOnce();
API_REGISTER_STATE_CHECK( REGISTER_STATE_CHECK(
res_dec = vpx_codec_decode(&decoder_, res_dec = vpx_codec_decode(&decoder_,
cxdata, static_cast<unsigned int>(size), cxdata, static_cast<unsigned int>(size),
user_priv, 0)); NULL, 0));
return res_dec; return res_dec;
} }
bool Decoder::IsVP8() const { void DecoderTest::RunLoop(CompressedVideoSource *video) {
const char *codec_name = GetDecoderName(); vpx_codec_dec_cfg_t dec_cfg = {0};
return strncmp(kVP8Name, codec_name, sizeof(kVP8Name) - 1) == 0; Decoder* const decoder = codec_->CreateDecoder(dec_cfg, 0);
}
bool Decoder::IsVP10() const {
const char *codec_name = GetDecoderName();
return strncmp(kVP10Name, codec_name, sizeof(kVP10Name) - 1) == 0;
}
void DecoderTest::HandlePeekResult(Decoder *const decoder,
CompressedVideoSource *video,
const vpx_codec_err_t res_peek) {
const bool is_vp8 = decoder->IsVP8();
if (is_vp8) {
/* Vp8's implementation of PeekStream returns an error if the frame you
* pass it is not a keyframe, so we only expect VPX_CODEC_OK on the first
* frame, which must be a keyframe. */
if (video->frame_number() == 0)
ASSERT_EQ(VPX_CODEC_OK, res_peek) << "Peek return failed: "
<< vpx_codec_err_to_string(res_peek);
} else {
/* The Vp9 implementation of PeekStream returns an error only if the
* data passed to it isn't a valid Vp9 chunk. */
ASSERT_EQ(VPX_CODEC_OK, res_peek) << "Peek return failed: "
<< vpx_codec_err_to_string(res_peek);
}
}
void DecoderTest::RunLoop(CompressedVideoSource *video,
const vpx_codec_dec_cfg_t &dec_cfg) {
Decoder* const decoder = codec_->CreateDecoder(dec_cfg, flags_, 0);
ASSERT_TRUE(decoder != NULL); ASSERT_TRUE(decoder != NULL);
bool end_of_file = false;
// Decode frames. // Decode frames.
for (video->Begin(); !::testing::Test::HasFailure() && !end_of_file; for (video->Begin(); video->cxdata(); video->Next()) {
video->Next()) {
PreDecodeFrameHook(*video, decoder); PreDecodeFrameHook(*video, decoder);
vpx_codec_stream_info_t stream_info;
stream_info.sz = sizeof(stream_info);
if (video->cxdata() != NULL) {
const vpx_codec_err_t res_peek = decoder->PeekStream(video->cxdata(),
video->frame_size(),
&stream_info);
HandlePeekResult(decoder, video, res_peek);
ASSERT_FALSE(::testing::Test::HasFailure());
vpx_codec_err_t res_dec = decoder->DecodeFrame(video->cxdata(), vpx_codec_err_t res_dec = decoder->DecodeFrame(video->cxdata(),
video->frame_size()); video->frame_size());
if (!HandleDecodeResult(res_dec, *video, decoder))
break;
} else {
// Signal end of the file to the decoder.
const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0);
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError(); ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
end_of_file = true;
}
DxDataIterator dec_iter = decoder->GetDxData(); DxDataIterator dec_iter = decoder->GetDxData();
const vpx_image_t *img = NULL; const vpx_image_t *img = NULL;
@@ -110,20 +44,7 @@ void DecoderTest::RunLoop(CompressedVideoSource *video,
while ((img = dec_iter.Next())) while ((img = dec_iter.Next()))
DecompressedFrameHook(*img, video->frame_number()); DecompressedFrameHook(*img, video->frame_number());
} }
delete decoder; delete decoder;
} }
void DecoderTest::RunLoop(CompressedVideoSource *video) {
vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t();
RunLoop(video, dec_cfg);
}
void DecoderTest::set_cfg(const vpx_codec_dec_cfg_t &dec_cfg) {
memcpy(&cfg_, &dec_cfg, sizeof(cfg_));
}
void DecoderTest::set_flags(const vpx_codec_flags_t flags) {
flags_ = flags;
}
} // namespace libvpx_test } // namespace libvpx_test

View File

@@ -41,13 +41,7 @@ class DxDataIterator {
class Decoder { class Decoder {
public: public:
Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline) Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline)
: cfg_(cfg), flags_(0), deadline_(deadline), init_done_(false) { : cfg_(cfg), deadline_(deadline), init_done_(false) {
memset(&decoder_, 0, sizeof(decoder_));
}
Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag,
unsigned long deadline) // NOLINT
: cfg_(cfg), flags_(flag), deadline_(deadline), init_done_(false) {
memset(&decoder_, 0, sizeof(decoder_)); memset(&decoder_, 0, sizeof(decoder_));
} }
@@ -55,14 +49,8 @@ class Decoder {
vpx_codec_destroy(&decoder_); vpx_codec_destroy(&decoder_);
} }
vpx_codec_err_t PeekStream(const uint8_t *cxdata, size_t size,
vpx_codec_stream_info_t *stream_info);
vpx_codec_err_t DecodeFrame(const uint8_t *cxdata, size_t size); vpx_codec_err_t DecodeFrame(const uint8_t *cxdata, size_t size);
vpx_codec_err_t DecodeFrame(const uint8_t *cxdata, size_t size,
void *user_priv);
DxDataIterator GetDxData() { DxDataIterator GetDxData() {
return DxDataIterator(&decoder_); return DxDataIterator(&decoder_);
} }
@@ -72,7 +60,9 @@ class Decoder {
} }
void Control(int ctrl_id, int arg) { void Control(int ctrl_id, int arg) {
Control(ctrl_id, arg, VPX_CODEC_OK); InitOnce();
const vpx_codec_err_t res = vpx_codec_control_(&decoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError();
} }
void Control(int ctrl_id, const void *arg) { void Control(int ctrl_id, const void *arg) {
@@ -81,12 +71,6 @@ class Decoder {
ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError(); ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError();
} }
void Control(int ctrl_id, int arg, vpx_codec_err_t expected_value) {
InitOnce();
const vpx_codec_err_t res = vpx_codec_control_(&decoder_, ctrl_id, arg);
ASSERT_EQ(expected_value, res) << DecodeError();
}
const char* DecodeError() { const char* DecodeError() {
const char *detail = vpx_codec_error_detail(&decoder_); const char *detail = vpx_codec_error_detail(&decoder_);
return detail ? detail : vpx_codec_error(&decoder_); return detail ? detail : vpx_codec_error(&decoder_);
@@ -101,18 +85,6 @@ class Decoder {
&decoder_, cb_get, cb_release, user_priv); &decoder_, cb_get, cb_release, user_priv);
} }
const char* GetDecoderName() const {
return vpx_codec_iface_name(CodecInterface());
}
bool IsVP8() const;
bool IsVP10() const;
vpx_codec_ctx_t * GetDecoder() {
return &decoder_;
}
protected: protected:
virtual vpx_codec_iface_t* CodecInterface() const = 0; virtual vpx_codec_iface_t* CodecInterface() const = 0;
@@ -120,7 +92,7 @@ class Decoder {
if (!init_done_) { if (!init_done_) {
const vpx_codec_err_t res = vpx_codec_dec_init(&decoder_, const vpx_codec_err_t res = vpx_codec_dec_init(&decoder_,
CodecInterface(), CodecInterface(),
&cfg_, flags_); &cfg_, 0);
ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError(); ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError();
init_done_ = true; init_done_ = true;
} }
@@ -128,7 +100,6 @@ class Decoder {
vpx_codec_ctx_t decoder_; vpx_codec_ctx_t decoder_;
vpx_codec_dec_cfg_t cfg_; vpx_codec_dec_cfg_t cfg_;
vpx_codec_flags_t flags_;
unsigned int deadline_; unsigned int deadline_;
bool init_done_; bool init_done_;
}; };
@@ -138,44 +109,21 @@ class DecoderTest {
public: public:
// Main decoding loop // Main decoding loop
virtual void RunLoop(CompressedVideoSource *video); virtual void RunLoop(CompressedVideoSource *video);
virtual void RunLoop(CompressedVideoSource *video,
const vpx_codec_dec_cfg_t &dec_cfg);
virtual void set_cfg(const vpx_codec_dec_cfg_t &dec_cfg);
virtual void set_flags(const vpx_codec_flags_t flags);
// Hook to be called before decompressing every frame. // Hook to be called before decompressing every frame.
virtual void PreDecodeFrameHook(const CompressedVideoSource& /*video*/, virtual void PreDecodeFrameHook(const CompressedVideoSource& video,
Decoder* /*decoder*/) {} Decoder *decoder) {}
// Hook to be called to handle decode result. Return true to continue.
virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
const CompressedVideoSource& /*video*/,
Decoder *decoder) {
EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
return VPX_CODEC_OK == res_dec;
}
// Hook to be called on every decompressed frame. // Hook to be called on every decompressed frame.
virtual void DecompressedFrameHook(const vpx_image_t& /*img*/, virtual void DecompressedFrameHook(const vpx_image_t& img,
const unsigned int /*frame_number*/) {} const unsigned int frame_number) {}
// Hook to be called on peek result
virtual void HandlePeekResult(Decoder* const decoder,
CompressedVideoSource *video,
const vpx_codec_err_t res_peek);
protected: protected:
explicit DecoderTest(const CodecFactory *codec) explicit DecoderTest(const CodecFactory *codec) : codec_(codec) {}
: codec_(codec),
cfg_(),
flags_(0) {}
virtual ~DecoderTest() {} virtual ~DecoderTest() {}
const CodecFactory *codec_; const CodecFactory *codec_;
vpx_codec_dec_cfg_t cfg_;
vpx_codec_flags_t flags_;
}; };
} // namespace libvpx_test } // namespace libvpx_test

View File

@@ -34,18 +34,14 @@ decode_to_md5() {
local expected_md5="$3" local expected_md5="$3"
local output_file="${VPX_TEST_OUTPUT_DIR}/decode_to_md5_${codec}" local output_file="${VPX_TEST_OUTPUT_DIR}/decode_to_md5_${codec}"
if [ ! -x "${decoder}" ]; then [ -x "${decoder}" ] || return 1
elog "${decoder} does not exist or is not executable."
return 1
fi
eval "${VPX_TEST_PREFIX}" "${decoder}" "${input_file}" "${output_file}" \ eval "${decoder}" "${input_file}" "${output_file}" ${devnull}
${devnull}
[ -e "${output_file}" ] || return 1 [ -e "${output_file}" ] || return 1
local md5_last_frame="$(tail -n1 "${output_file}" | awk '{print $1}')" local md5_last_frame=$(tail -n1 "${output_file}")
local actual_md5="$(echo "${md5_last_frame}" | awk '{print $1}')" local actual_md5=$(echo "${md5_last_frame% *}" | tr -d [:space:])
[ "${actual_md5}" = "${expected_md5}" ] || return 1 [ "${actual_md5}" = "${expected_md5}" ] || return 1
} }

View File

@@ -34,13 +34,9 @@ decode_with_drops() {
local output_file="${VPX_TEST_OUTPUT_DIR}/decode_with_drops_${codec}" local output_file="${VPX_TEST_OUTPUT_DIR}/decode_with_drops_${codec}"
local drop_mode="$3" local drop_mode="$3"
if [ ! -x "${decoder}" ]; then [ -x "${decoder}" ] || return 1
elog "${decoder} does not exist or is not executable."
return 1
fi
eval "${VPX_TEST_PREFIX}" "${decoder}" "${input_file}" "${output_file}" \ eval "${decoder}" "${input_file}" "${output_file}" "${drop_mode}" ${devnull}
"${drop_mode}" ${devnull}
[ -e "${output_file}" ] || return 1 [ -e "${output_file}" ] || return 1
} }

View File

@@ -1,100 +0,0 @@
/*
* Copyright (c) 2014 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 <math.h>
#include <stdlib.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "vpx_scale/yv12config.h"
#include "vpx/vpx_integer.h"
#include "vp10/common/reconinter.h"
#include "vp10/encoder/context_tree.h"
#include "vp10/encoder/denoiser.h"
using libvpx_test::ACMRandom;
namespace {
const int kNumPixels = 64 * 64;
class VP9DenoiserTest : public ::testing::TestWithParam<BLOCK_SIZE> {
public:
virtual ~VP9DenoiserTest() {}
virtual void SetUp() {
bs_ = GetParam();
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
BLOCK_SIZE bs_;
};
TEST_P(VP9DenoiserTest, BitexactCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 4000;
// Allocate the space for input and output,
// where sig_block is the block to be denoised,
// mc_avg_block is the denoised reference block,
// avg_block_c is the denoised result from C code,
// avg_block_sse2 is the denoised result from SSE2 code.
DECLARE_ALIGNED(16, uint8_t, sig_block[kNumPixels]);
DECLARE_ALIGNED(16, uint8_t, mc_avg_block[kNumPixels]);
DECLARE_ALIGNED(16, uint8_t, avg_block_c[kNumPixels]);
DECLARE_ALIGNED(16, uint8_t, avg_block_sse2[kNumPixels]);
for (int i = 0; i < count_test_block; ++i) {
// Generate random motion magnitude, 20% of which exceed the threshold.
const int motion_magnitude_random =
rnd.Rand8() % static_cast<int>(MOTION_MAGNITUDE_THRESHOLD * 1.2);
// Initialize a test block with random number in range [0, 255].
for (int j = 0; j < kNumPixels; ++j) {
int temp = 0;
sig_block[j] = rnd.Rand8();
// The pixels in mc_avg_block are generated by adding a random
// number in range [-19, 19] to corresponding pixels in sig_block.
temp = sig_block[j] + ((rnd.Rand8() % 2 == 0) ? -1 : 1) *
(rnd.Rand8() % 20);
// Clip.
mc_avg_block[j] = (temp < 0) ? 0 : ((temp > 255) ? 255 : temp);
}
ASM_REGISTER_STATE_CHECK(vp9_denoiser_filter_c(
sig_block, 64, mc_avg_block, 64, avg_block_c,
64, 0, bs_, motion_magnitude_random));
ASM_REGISTER_STATE_CHECK(vp9_denoiser_filter_sse2(
sig_block, 64, mc_avg_block, 64, avg_block_sse2,
64, 0, bs_, motion_magnitude_random));
// Test bitexactness.
for (int h = 0; h < (4 << b_height_log2_lookup[bs_]); ++h) {
for (int w = 0; w < (4 << b_width_log2_lookup[bs_]); ++w) {
EXPECT_EQ(avg_block_c[h * 64 + w], avg_block_sse2[h * 64 + w]);
}
}
}
}
// Test for all block size.
INSTANTIATE_TEST_CASE_P(
SSE2, VP9DenoiserTest,
::testing::Values(BLOCK_8X8, BLOCK_8X16, BLOCK_16X8, BLOCK_16X16,
BLOCK_16X32, BLOCK_32X16, BLOCK_32X32, BLOCK_32X64,
BLOCK_64X32, BLOCK_64X64));
} // namespace

View File

@@ -1,62 +0,0 @@
/*
* Copyright (c) 2016 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 "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
namespace {
#define NELEMENTS(x) static_cast<int>(sizeof(x) / sizeof(x[0]))
TEST(EncodeAPI, InvalidParams) {
static const vpx_codec_iface_t *kCodecs[] = {
#if CONFIG_VP10_ENCODER
&vpx_codec_vp10_cx_algo,
#endif
};
uint8_t buf[1] = {0};
vpx_image_t img;
vpx_codec_ctx_t enc;
vpx_codec_enc_cfg_t cfg;
EXPECT_EQ(&img, vpx_img_wrap(&img, VPX_IMG_FMT_I420, 1, 1, 1, buf));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_enc_init(NULL, NULL, NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_enc_init(&enc, NULL, NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_encode(NULL, NULL, 0, 0, 0, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_encode(NULL, &img, 0, 0, 0, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, vpx_codec_destroy(NULL));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_enc_config_default(NULL, NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_enc_config_default(NULL, &cfg, 0));
EXPECT_TRUE(vpx_codec_error(NULL) != NULL);
for (int i = 0; i < NELEMENTS(kCodecs); ++i) {
SCOPED_TRACE(vpx_codec_iface_name(kCodecs[i]));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_enc_init(NULL, kCodecs[i], NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_enc_init(&enc, kCodecs[i], NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_enc_config_default(kCodecs[i], &cfg, 1));
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_enc_config_default(kCodecs[i], &cfg, 0));
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_enc_init(&enc, kCodecs[i], &cfg, 0));
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_encode(&enc, NULL, 0, 0, 0, 0));
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_destroy(&enc));
}
}
} // namespace

View File

@@ -1,202 +0,0 @@
/*
* Copyright (c) 2014 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 <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "./vpx_version.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "vpx_ports/vpx_timer.h"
namespace {
const int kMaxPsnr = 100;
const double kUsecsInSec = 1000000.0;
struct EncodePerfTestVideo {
EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
uint32_t bitrate_, int frames_)
: name(name_),
width(width_),
height(height_),
bitrate(bitrate_),
frames(frames_) {}
const char *name;
uint32_t width;
uint32_t height;
uint32_t bitrate;
int frames;
};
const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
EncodePerfTestVideo("desktop_640_360_30.yuv", 640, 360, 200, 2484),
EncodePerfTestVideo("kirland_640_480_30.yuv", 640, 480, 200, 300),
EncodePerfTestVideo("macmarcomoving_640_480_30.yuv", 640, 480, 200, 987),
EncodePerfTestVideo("macmarcostationary_640_480_30.yuv", 640, 480, 200, 718),
EncodePerfTestVideo("niklas_640_480_30.yuv", 640, 480, 200, 471),
EncodePerfTestVideo("tacomanarrows_640_480_30.yuv", 640, 480, 200, 300),
EncodePerfTestVideo("tacomasmallcameramovement_640_480_30.yuv",
640, 480, 200, 300),
EncodePerfTestVideo("thaloundeskmtg_640_480_30.yuv", 640, 480, 200, 300),
EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
};
const int kEncodePerfTestSpeeds[] = { 5, 6, 7, 8 };
const int kEncodePerfTestThreads[] = { 1, 2, 4 };
#define NELEMENTS(x) (sizeof((x)) / sizeof((x)[0]))
class VP9EncodePerfTest
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected:
VP9EncodePerfTest()
: EncoderTest(GET_PARAM(0)),
min_psnr_(kMaxPsnr),
nframes_(0),
encoding_mode_(GET_PARAM(1)),
speed_(0),
threads_(1) {}
virtual ~VP9EncodePerfTest() {}
virtual void SetUp() {
InitializeConfig();
SetMode(encoding_mode_);
cfg_.g_lag_in_frames = 0;
cfg_.rc_min_quantizer = 2;
cfg_.rc_max_quantizer = 56;
cfg_.rc_dropframe_thresh = 0;
cfg_.rc_undershoot_pct = 50;
cfg_.rc_overshoot_pct = 50;
cfg_.rc_buf_sz = 1000;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 600;
cfg_.rc_resize_allowed = 0;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_error_resilient = 1;
cfg_.g_threads = threads_;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 0) {
const int log2_tile_columns = 3;
encoder->Control(VP8E_SET_CPUUSED, speed_);
encoder->Control(VP9E_SET_TILE_COLUMNS, log2_tile_columns);
encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 0);
}
}
virtual void BeginPassHook(unsigned int /*pass*/) {
min_psnr_ = kMaxPsnr;
nframes_ = 0;
}
virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
if (pkt->data.psnr.psnr[0] < min_psnr_) {
min_psnr_= pkt->data.psnr.psnr[0];
}
}
// for performance reasons don't decode
virtual bool DoDecode() { return 0; }
double min_psnr() const {
return min_psnr_;
}
void set_speed(unsigned int speed) {
speed_ = speed;
}
void set_threads(unsigned int threads) {
threads_ = threads;
}
private:
double min_psnr_;
unsigned int nframes_;
libvpx_test::TestMode encoding_mode_;
unsigned speed_;
unsigned int threads_;
};
TEST_P(VP9EncodePerfTest, PerfTest) {
for (size_t i = 0; i < NELEMENTS(kVP9EncodePerfTestVectors); ++i) {
for (size_t j = 0; j < NELEMENTS(kEncodePerfTestSpeeds); ++j) {
for (size_t k = 0; k < NELEMENTS(kEncodePerfTestThreads); ++k) {
if (kVP9EncodePerfTestVectors[i].width < 512 &&
kEncodePerfTestThreads[k] > 1)
continue;
else if (kVP9EncodePerfTestVectors[i].width < 1024 &&
kEncodePerfTestThreads[k] > 2)
continue;
set_threads(kEncodePerfTestThreads[k]);
SetUp();
const vpx_rational timebase = { 33333333, 1000000000 };
cfg_.g_timebase = timebase;
cfg_.rc_target_bitrate = kVP9EncodePerfTestVectors[i].bitrate;
init_flags_ = VPX_CODEC_USE_PSNR;
const unsigned frames = kVP9EncodePerfTestVectors[i].frames;
const char *video_name = kVP9EncodePerfTestVectors[i].name;
libvpx_test::I420VideoSource video(
video_name,
kVP9EncodePerfTestVectors[i].width,
kVP9EncodePerfTestVectors[i].height,
timebase.den, timebase.num, 0,
kVP9EncodePerfTestVectors[i].frames);
set_speed(kEncodePerfTestSpeeds[j]);
vpx_usec_timer t;
vpx_usec_timer_start(&t);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
vpx_usec_timer_mark(&t);
const double elapsed_secs = vpx_usec_timer_elapsed(&t) / kUsecsInSec;
const double fps = frames / elapsed_secs;
const double minimum_psnr = min_psnr();
std::string display_name(video_name);
if (kEncodePerfTestThreads[k] > 1) {
char thread_count[32];
snprintf(thread_count, sizeof(thread_count), "_t-%d",
kEncodePerfTestThreads[k]);
display_name += thread_count;
}
printf("{\n");
printf("\t\"type\" : \"encode_perf_test\",\n");
printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
printf("\t\"videoName\" : \"%s\",\n", display_name.c_str());
printf("\t\"encodeTimeSecs\" : %f,\n", elapsed_secs);
printf("\t\"totalFrames\" : %u,\n", frames);
printf("\t\"framesPerSecond\" : %f,\n", fps);
printf("\t\"minPsnr\" : %f,\n", minimum_psnr);
printf("\t\"speed\" : %d,\n", kEncodePerfTestSpeeds[j]);
printf("\t\"threads\" : %d\n", kEncodePerfTestThreads[k]);
printf("}\n");
}
}
}
}
VP10_INSTANTIATE_TEST_CASE(
VP9EncodePerfTest, ::testing::Values(::libvpx_test::kRealTime));
} // namespace

View File

@@ -8,50 +8,15 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h" #include "./vpx_config.h"
#include "vpx_ports/mem.h"
#include "test/codec_factory.h" #include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/encode_test_driver.h" #include "test/encode_test_driver.h"
#include "test/decode_test_driver.h"
#include "test/register_state_check.h" #include "test/register_state_check.h"
#include "test/video_source.h" #include "test/video_source.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
namespace libvpx_test { namespace libvpx_test {
void Encoder::InitEncoder(VideoSource *video) {
vpx_codec_err_t res;
const vpx_image_t *img = video->img();
if (video->img() && !encoder_.priv) {
cfg_.g_w = img->d_w;
cfg_.g_h = img->d_h;
cfg_.g_timebase = video->timebase();
cfg_.rc_twopass_stats_in = stats_->buf();
res = vpx_codec_enc_init(&encoder_, CodecInterface(), &cfg_,
init_flags_);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
#if CONFIG_VP10_ENCODER
if (CodecInterface() == &vpx_codec_vp10_cx_algo) {
// Default to 1 tile column for VP10. With CONFIG_EXT_TILE, the
// default is already the largest possible tile size
#if !CONFIG_EXT_TILE
const int log2_tile_columns = 0;
res = vpx_codec_control_(&encoder_, VP9E_SET_TILE_COLUMNS,
log2_tile_columns);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
#endif // !CONFIG_EXT_TILE
} else
#endif
{
}
}
}
void Encoder::EncodeFrame(VideoSource *video, const unsigned long frame_flags) { void Encoder::EncodeFrame(VideoSource *video, const unsigned long frame_flags) {
if (video->img()) if (video->img())
EncodeFrameInternal(*video, frame_flags); EncodeFrameInternal(*video, frame_flags);
@@ -74,6 +39,17 @@ void Encoder::EncodeFrameInternal(const VideoSource &video,
vpx_codec_err_t res; vpx_codec_err_t res;
const vpx_image_t *img = video.img(); const vpx_image_t *img = video.img();
// Handle first frame initialization
if (!encoder_.priv) {
cfg_.g_w = img->d_w;
cfg_.g_h = img->d_h;
cfg_.g_timebase = video.timebase();
cfg_.rc_twopass_stats_in = stats_->buf();
res = vpx_codec_enc_init(&encoder_, CodecInterface(), &cfg_,
init_flags_);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
// Handle frame resizing // Handle frame resizing
if (cfg_.g_w != img->d_w || cfg_.g_h != img->d_h) { if (cfg_.g_w != img->d_w || cfg_.g_h != img->d_h) {
cfg_.g_w = img->d_w; cfg_.g_w = img->d_w;
@@ -83,8 +59,9 @@ void Encoder::EncodeFrameInternal(const VideoSource &video,
} }
// Encode the frame // Encode the frame
API_REGISTER_STATE_CHECK( REGISTER_STATE_CHECK(
res = vpx_codec_encode(&encoder_, img, video.pts(), video.duration(), res = vpx_codec_encode(&encoder_,
video.img(), video.pts(), video.duration(),
frame_flags, deadline_)); frame_flags, deadline_));
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
@@ -92,15 +69,11 @@ void Encoder::EncodeFrameInternal(const VideoSource &video,
void Encoder::Flush() { void Encoder::Flush() {
const vpx_codec_err_t res = vpx_codec_encode(&encoder_, NULL, 0, 0, 0, const vpx_codec_err_t res = vpx_codec_encode(&encoder_, NULL, 0, 0, 0,
deadline_); deadline_);
if (!encoder_.priv)
ASSERT_EQ(VPX_CODEC_ERROR, res) << EncoderError();
else
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
void EncoderTest::InitializeConfig() { void EncoderTest::InitializeConfig() {
const vpx_codec_err_t res = codec_->DefaultEncoderConfig(&cfg_, 0); const vpx_codec_err_t res = codec_->DefaultEncoderConfig(&cfg_, 0);
dec_cfg_ = vpx_codec_dec_cfg_t();
ASSERT_EQ(VPX_CODEC_OK, res); ASSERT_EQ(VPX_CODEC_OK, res);
} }
@@ -129,124 +102,41 @@ void EncoderTest::SetMode(TestMode mode) {
else else
passes_ = 1; passes_ = 1;
} }
static bool compare_plane(const uint8_t *const buf1, const int stride1,
const uint8_t *const buf2, const int stride2,
const int w, const int h,
int *const mismatch_row,
int *const mismatch_col,
int *const mismatch_pix1,
int *const mismatch_pix2) {
int r, c;
for (r = 0; r < h; ++r) {
for (c = 0; c < w; ++c) {
const int pix1 = buf1[r * stride1 + c];
const int pix2 = buf2[r * stride2 + c];
if (pix1 != pix2) {
if (mismatch_row != NULL)
*mismatch_row = r;
if (mismatch_col != NULL)
*mismatch_col = c;
if (mismatch_pix1 != NULL)
*mismatch_pix1 = pix1;
if (mismatch_pix2 != NULL)
*mismatch_pix2 = pix2;
return false;
}
}
}
return true;
}
// The function should return "true" most of the time, therefore no early // The function should return "true" most of the time, therefore no early
// break-out is implemented within the match checking process. // break-out is implemented within the match checking process.
static bool compare_img(const vpx_image_t *img1, static bool compare_img(const vpx_image_t *img1,
const vpx_image_t *img2, const vpx_image_t *img2) {
int *const mismatch_row, bool match = (img1->fmt == img2->fmt) &&
int *const mismatch_col, (img1->d_w == img2->d_w) &&
int *const mismatch_plane, (img1->d_h == img2->d_h);
int *const mismatch_pix1,
int *const mismatch_pix2) {
const unsigned int w_y = img1->d_w; const unsigned int width_y = img1->d_w;
const unsigned int h_y = img1->d_h; const unsigned int height_y = img1->d_h;
const unsigned int w_uv = ROUND_POWER_OF_TWO(w_y, img1->x_chroma_shift); unsigned int i;
const unsigned int h_uv = ROUND_POWER_OF_TWO(h_y, img1->y_chroma_shift); for (i = 0; i < height_y; ++i)
match = (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y],
if (img1->fmt != img2->fmt img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y],
|| img1->cs != img2->cs width_y) == 0) && match;
|| img1->d_w != img2->d_w const unsigned int width_uv = (img1->d_w + 1) >> 1;
|| img1->d_h != img2->d_h) { const unsigned int height_uv = (img1->d_h + 1) >> 1;
if (mismatch_row != NULL) for (i = 0; i < height_uv; ++i)
*mismatch_row = -1; match = (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U],
if (mismatch_col != NULL) img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U],
*mismatch_col = -1; width_uv) == 0) && match;
return false; for (i = 0; i < height_uv; ++i)
} match = (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V],
img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V],
if (!compare_plane(img1->planes[VPX_PLANE_Y], img1->stride[VPX_PLANE_Y], width_uv) == 0) && match;
img2->planes[VPX_PLANE_Y], img2->stride[VPX_PLANE_Y], return match;
w_y, h_y,
mismatch_row, mismatch_col,
mismatch_pix1, mismatch_pix2)) {
if (mismatch_plane != NULL)
*mismatch_plane = VPX_PLANE_Y;
return false;
}
if (!compare_plane(img1->planes[VPX_PLANE_U], img1->stride[VPX_PLANE_U],
img2->planes[VPX_PLANE_U], img2->stride[VPX_PLANE_U],
w_uv, h_uv,
mismatch_row, mismatch_col,
mismatch_pix1, mismatch_pix2)) {
if (mismatch_plane != NULL)
*mismatch_plane = VPX_PLANE_U;
return false;
}
if (!compare_plane(img1->planes[VPX_PLANE_V], img1->stride[VPX_PLANE_V],
img2->planes[VPX_PLANE_V], img2->stride[VPX_PLANE_V],
w_uv, h_uv,
mismatch_row, mismatch_col,
mismatch_pix1, mismatch_pix2)) {
if (mismatch_plane != NULL)
*mismatch_plane = VPX_PLANE_U;
return false;
}
return true;
} }
void EncoderTest::MismatchHook(const vpx_image_t* img_enc, void EncoderTest::MismatchHook(const vpx_image_t *img1,
const vpx_image_t* img_dec) { const vpx_image_t *img2) {
int mismatch_row = 0; ASSERT_TRUE(0) << "Encode/Decode mismatch found";
int mismatch_col = 0;
int mismatch_plane = 0;
int mismatch_pix_enc = 0;
int mismatch_pix_dec = 0;
ASSERT_FALSE(compare_img(img_enc, img_dec,
&mismatch_row, &mismatch_col,
&mismatch_plane,
&mismatch_pix_enc,
&mismatch_pix_dec));
GTEST_FAIL()
<< "Encode/Decode mismatch found:"
<< std::endl
<< " pixel value enc/dec: " << mismatch_pix_enc << "/" << mismatch_pix_dec
<< std::endl
<< " plane: " << mismatch_plane
<< std::endl
<< " row/col: " << mismatch_row << "/" << mismatch_col
<< std::endl;
} }
void EncoderTest::RunLoop(VideoSource *video) { void EncoderTest::RunLoop(VideoSource *video) {
vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t(); vpx_codec_dec_cfg_t dec_cfg = {0};
stats_.Reset(); stats_.Reset();
@@ -262,36 +152,16 @@ void EncoderTest::RunLoop(VideoSource *video) {
cfg_.g_pass = VPX_RC_LAST_PASS; cfg_.g_pass = VPX_RC_LAST_PASS;
BeginPassHook(pass); BeginPassHook(pass);
testing::internal::scoped_ptr<Encoder> encoder( Encoder* const encoder = codec_->CreateEncoder(cfg_, deadline_, init_flags_,
codec_->CreateEncoder(cfg_, deadline_, init_flags_, &stats_)); &stats_);
ASSERT_TRUE(encoder.get() != NULL); ASSERT_TRUE(encoder != NULL);
Decoder* const decoder = codec_->CreateDecoder(dec_cfg, 0);
ASSERT_NO_FATAL_FAILURE(video->Begin());
encoder->InitEncoder(video);
ASSERT_FALSE(::testing::Test::HasFatalFailure());
unsigned long dec_init_flags = 0; // NOLINT
// Use fragment decoder if encoder outputs partitions.
// NOTE: fragment decoder and partition encoder are only supported by VP8.
if (init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION)
dec_init_flags |= VPX_CODEC_USE_INPUT_FRAGMENTS;
testing::internal::scoped_ptr<Decoder> decoder(
codec_->CreateDecoder(dec_cfg, dec_init_flags, 0));
#if CONFIG_VP10 && CONFIG_EXT_TILE
if (decoder->IsVP10()) {
// Set dec_cfg.tile_row = -1 and dec_cfg.tile_col = -1 so that the whole
// frame is decoded.
decoder->Control(VP10_SET_DECODE_TILE_ROW, -1);
decoder->Control(VP10_SET_DECODE_TILE_COL, -1);
}
#endif
bool again; bool again;
for (again = true; again; video->Next()) { for (again = true, video->Begin(); again; video->Next()) {
again = (video->img() != NULL); again = (video->img() != NULL);
PreEncodeFrameHook(video); PreEncodeFrameHook(video);
PreEncodeFrameHook(video, encoder.get()); PreEncodeFrameHook(video, encoder);
encoder->EncodeFrame(video, frame_flags_); encoder->EncodeFrame(video, frame_flags_);
CxDataIterator iter = encoder->GetCxData(); CxDataIterator iter = encoder->GetCxData();
@@ -304,13 +174,10 @@ void EncoderTest::RunLoop(VideoSource *video) {
switch (pkt->kind) { switch (pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT: case VPX_CODEC_CX_FRAME_PKT:
has_cxdata = true; has_cxdata = true;
if (decoder.get() != NULL && DoDecode()) { if (decoder && DoDecode()) {
vpx_codec_err_t res_dec = decoder->DecodeFrame( vpx_codec_err_t res_dec = decoder->DecodeFrame(
(const uint8_t*)pkt->data.frame.buf, pkt->data.frame.sz); (const uint8_t*)pkt->data.frame.buf, pkt->data.frame.sz);
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
if (!HandleDecodeResult(res_dec, *video, decoder.get()))
break;
has_dxdata = true; has_dxdata = true;
} }
ASSERT_GE(pkt->data.frame.pts, last_pts_); ASSERT_GE(pkt->data.frame.pts, last_pts_);
@@ -327,20 +194,12 @@ void EncoderTest::RunLoop(VideoSource *video) {
} }
} }
// Flush the decoder when there are no more fragments.
if ((init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION) && has_dxdata) {
const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0);
if (!HandleDecodeResult(res_dec, *video, decoder.get()))
break;
}
if (has_dxdata && has_cxdata) { if (has_dxdata && has_cxdata) {
const vpx_image_t *img_enc = encoder->GetPreviewFrame(); const vpx_image_t *img_enc = encoder->GetPreviewFrame();
DxDataIterator dec_iter = decoder->GetDxData(); DxDataIterator dec_iter = decoder->GetDxData();
const vpx_image_t *img_dec = dec_iter.Next(); const vpx_image_t *img_dec = dec_iter.Next();
if (img_enc && img_dec) { if (img_enc && img_dec) {
const bool res = compare_img(img_enc, img_dec, const bool res = compare_img(img_enc, img_dec);
NULL, NULL, NULL, NULL, NULL);
if (!res) { // Mismatch if (!res) { // Mismatch
MismatchHook(img_enc, img_dec); MismatchHook(img_enc, img_dec);
} }
@@ -354,6 +213,10 @@ void EncoderTest::RunLoop(VideoSource *video) {
EndPassHook(); EndPassHook();
if (decoder)
delete decoder;
delete encoder;
if (!Continue()) if (!Continue())
break; break;
} }

View File

@@ -13,13 +13,12 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h" #include "./vpx_config.h"
#if CONFIG_VP10_ENCODER #include "third_party/googletest/src/include/gtest/gtest.h"
#include "vpx/vpx_encoder.h"
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#endif #endif
#include "vpx/vpx_encoder.h"
namespace libvpx_test { namespace libvpx_test {
@@ -105,8 +104,6 @@ class Encoder {
return CxDataIterator(&encoder_); return CxDataIterator(&encoder_);
} }
void InitEncoder(VideoSource *video);
const vpx_image_t *GetPreviewFrame() { const vpx_image_t *GetPreviewFrame() {
return vpx_codec_get_preview_frame(&encoder_); return vpx_codec_get_preview_frame(&encoder_);
} }
@@ -124,11 +121,6 @@ class Encoder {
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
void Control(int ctrl_id, int *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
void Control(int ctrl_id, struct vpx_scaling_mode *arg) { void Control(int ctrl_id, struct vpx_scaling_mode *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg); const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
@@ -139,23 +131,13 @@ class Encoder {
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
void Control(int ctrl_id, struct vpx_svc_parameters *arg) { #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
#if CONFIG_VP10_ENCODER
void Control(int ctrl_id, vpx_active_map_t *arg) { void Control(int ctrl_id, vpx_active_map_t *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg); const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
#endif #endif
void Config(const vpx_codec_enc_cfg_t *cfg) {
const vpx_codec_err_t res = vpx_codec_enc_config_set(&encoder_, cfg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
cfg_ = *cfg;
}
void set_deadline(unsigned long deadline) { void set_deadline(unsigned long deadline) {
deadline_ = deadline; deadline_ = deadline;
} }
@@ -193,10 +175,7 @@ class EncoderTest {
protected: protected:
explicit EncoderTest(const CodecFactory *codec) explicit EncoderTest(const CodecFactory *codec)
: codec_(codec), abort_(false), init_flags_(0), frame_flags_(0), : codec_(codec), abort_(false), init_flags_(0), frame_flags_(0),
last_pts_(0) { last_pts_(0) {}
// Default to 1 thread.
cfg_.g_threads = 1;
}
virtual ~EncoderTest() {} virtual ~EncoderTest() {}
@@ -206,30 +185,24 @@ class EncoderTest {
// Map the TestMode enum to the deadline_ and passes_ variables. // Map the TestMode enum to the deadline_ and passes_ variables.
void SetMode(TestMode mode); void SetMode(TestMode mode);
// Set encoder flag.
void set_init_flags(unsigned long flag) { // NOLINT(runtime/int)
init_flags_ = flag;
}
// Main loop // Main loop
virtual void RunLoop(VideoSource *video); virtual void RunLoop(VideoSource *video);
// Hook to be called at the beginning of a pass. // Hook to be called at the beginning of a pass.
virtual void BeginPassHook(unsigned int /*pass*/) {} virtual void BeginPassHook(unsigned int pass) {}
// Hook to be called at the end of a pass. // Hook to be called at the end of a pass.
virtual void EndPassHook() {} virtual void EndPassHook() {}
// Hook to be called before encoding a frame. // Hook to be called before encoding a frame.
virtual void PreEncodeFrameHook(VideoSource* /*video*/) {} virtual void PreEncodeFrameHook(VideoSource *video) {}
virtual void PreEncodeFrameHook(VideoSource* /*video*/, virtual void PreEncodeFrameHook(VideoSource *video, Encoder *encoder) {}
Encoder* /*encoder*/) {}
// Hook to be called on every compressed data packet. // Hook to be called on every compressed data packet.
virtual void FramePktHook(const vpx_codec_cx_pkt_t* /*pkt*/) {} virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {}
// Hook to be called on every PSNR packet. // Hook to be called on every PSNR packet.
virtual void PSNRPktHook(const vpx_codec_cx_pkt_t* /*pkt*/) {} virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {}
// Hook to determine whether the encode loop should continue. // Hook to determine whether the encode loop should continue.
virtual bool Continue() const { virtual bool Continue() const {
@@ -245,26 +218,17 @@ class EncoderTest {
const vpx_image_t *img2); const vpx_image_t *img2);
// Hook to be called on every decompressed frame. // Hook to be called on every decompressed frame.
virtual void DecompressedFrameHook(const vpx_image_t& /*img*/, virtual void DecompressedFrameHook(const vpx_image_t& img,
vpx_codec_pts_t /*pts*/) {} vpx_codec_pts_t pts) {}
// Hook to be called to handle decode result. Return true to continue.
virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
const VideoSource& /*video*/,
Decoder *decoder) {
EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
return VPX_CODEC_OK == res_dec;
}
// Hook that can modify the encoder's output data // Hook that can modify the encoder's output data
virtual const vpx_codec_cx_pkt_t *MutateEncoderOutputHook( virtual const vpx_codec_cx_pkt_t * MutateEncoderOutputHook(
const vpx_codec_cx_pkt_t *pkt) { const vpx_codec_cx_pkt_t *pkt) {
return pkt; return pkt;
} }
bool abort_; bool abort_;
vpx_codec_enc_cfg_t cfg_; vpx_codec_enc_cfg_t cfg_;
vpx_codec_dec_cfg_t dec_cfg_;
unsigned int passes_; unsigned int passes_;
unsigned long deadline_; unsigned long deadline_;
TwopassStatsStore stats_; TwopassStatsStore stats_;

View File

@@ -1,149 +0,0 @@
/*
* Copyright (c) 2014 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 "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "vp10/vp10_dx_iface.c"
namespace {
const int kCpuUsed = 2;
struct EncodePerfTestVideo {
const char *name;
uint32_t width;
uint32_t height;
uint32_t bitrate;
int frames;
};
const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
{"niklas_1280_720_30.y4m", 1280, 720, 600, 10},
};
struct EncodeParameters {
int32_t tile_rows;
int32_t tile_cols;
int32_t lossless;
int32_t error_resilient;
int32_t frame_parallel;
vpx_color_range_t color_range;
vpx_color_space_t cs;
int render_size[2];
// TODO(JBB): quantizers / bitrate
};
const EncodeParameters kVP9EncodeParameterSet[] = {
{0, 0, 0, 1, 0, VPX_CR_STUDIO_RANGE, VPX_CS_BT_601, { 0, 0 }},
{0, 0, 0, 0, 0, VPX_CR_FULL_RANGE, VPX_CS_BT_709, { 0, 0 }},
{0, 0, 1, 0, 0, VPX_CR_FULL_RANGE, VPX_CS_BT_2020, { 0, 0 }},
{0, 2, 0, 0, 1, VPX_CR_STUDIO_RANGE, VPX_CS_UNKNOWN, { 640, 480 }},
// TODO(JBB): Test profiles (requires more work).
};
class VpxEncoderParmsGetToDecoder
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<EncodeParameters,
EncodePerfTestVideo> {
protected:
VpxEncoderParmsGetToDecoder()
: EncoderTest(GET_PARAM(0)), encode_parms(GET_PARAM(1)) {}
virtual ~VpxEncoderParmsGetToDecoder() {}
virtual void SetUp() {
InitializeConfig();
SetMode(::libvpx_test::kTwoPassGood);
cfg_.g_lag_in_frames = 25;
cfg_.g_error_resilient = encode_parms.error_resilient;
dec_cfg_.threads = 4;
test_video_ = GET_PARAM(2);
cfg_.rc_target_bitrate = test_video_.bitrate;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 1) {
encoder->Control(VP9E_SET_COLOR_SPACE, encode_parms.cs);
encoder->Control(VP9E_SET_COLOR_RANGE, encode_parms.color_range);
encoder->Control(VP9E_SET_LOSSLESS, encode_parms.lossless);
encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING,
encode_parms.frame_parallel);
encoder->Control(VP9E_SET_TILE_ROWS, encode_parms.tile_rows);
encoder->Control(VP9E_SET_TILE_COLUMNS, encode_parms.tile_cols);
encoder->Control(VP8E_SET_CPUUSED, kCpuUsed);
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
encoder->Control(VP8E_SET_ARNR_TYPE, 3);
if (encode_parms.render_size[0] > 0 && encode_parms.render_size[1] > 0)
encoder->Control(VP9E_SET_RENDER_SIZE, encode_parms.render_size);
}
}
virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
const libvpx_test::VideoSource & /*video*/,
libvpx_test::Decoder *decoder) {
vpx_codec_ctx_t *const vp9_decoder = decoder->GetDecoder();
vpx_codec_alg_priv_t *const priv =
reinterpret_cast<vpx_codec_alg_priv_t *>(vp9_decoder->priv);
FrameWorkerData *const worker_data =
reinterpret_cast<FrameWorkerData *>(priv->frame_workers[0].data1);
VP10_COMMON *const common = &worker_data->pbi->common;
if (encode_parms.lossless) {
EXPECT_EQ(0, common->base_qindex);
EXPECT_EQ(0, common->y_dc_delta_q);
EXPECT_EQ(0, common->uv_dc_delta_q);
EXPECT_EQ(0, common->uv_ac_delta_q);
EXPECT_EQ(ONLY_4X4, common->tx_mode);
}
EXPECT_EQ(encode_parms.error_resilient, common->error_resilient_mode);
if (encode_parms.error_resilient) {
EXPECT_EQ(0, common->use_prev_frame_mvs);
}
EXPECT_EQ(encode_parms.color_range, common->color_range);
EXPECT_EQ(encode_parms.cs, common->color_space);
if (encode_parms.render_size[0] > 0 && encode_parms.render_size[1] > 0) {
EXPECT_EQ(encode_parms.render_size[0], common->render_width);
EXPECT_EQ(encode_parms.render_size[1], common->render_height);
}
EXPECT_EQ(encode_parms.tile_cols, common->log2_tile_cols);
EXPECT_EQ(encode_parms.tile_rows, common->log2_tile_rows);
EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
return VPX_CODEC_OK == res_dec;
}
EncodePerfTestVideo test_video_;
private:
EncodeParameters encode_parms;
};
TEST_P(VpxEncoderParmsGetToDecoder, BitstreamParms) {
init_flags_ = VPX_CODEC_USE_PSNR;
libvpx_test::VideoSource *const video =
new libvpx_test::Y4mVideoSource(test_video_.name, 0, test_video_.frames);
ASSERT_TRUE(video != NULL);
ASSERT_NO_FATAL_FAILURE(RunLoop(video));
delete video;
}
VP10_INSTANTIATE_TEST_CASE(VpxEncoderParmsGetToDecoder,
::testing::ValuesIn(kVP9EncodeParameterSet),
::testing::ValuesIn(kVP9EncodePerfTestVectors));
} // namespace

View File

@@ -1,210 +0,0 @@
/*
* Copyright (c) 2014 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 "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "test/yuv_video_source.h"
namespace {
const unsigned int kWidth = 160;
const unsigned int kHeight = 90;
const unsigned int kFramerate = 50;
const unsigned int kFrames = 10;
const int kBitrate = 500;
// List of psnr thresholds for speed settings 0-7 and 5 encoding modes
const double kPsnrThreshold[][5] = {
// Note:
// VP10 HBD average PSNR is slightly lower than VP9.
// We make two cases here to enable the testing and
// guard picture quality.
#if CONFIG_VP10_ENCODER && CONFIG_VPX_HIGHBITDEPTH
{ 36.0, 37.0, 37.0, 37.0, 37.0 },
{ 31.0, 36.0, 36.0, 36.0, 36.0 },
{ 31.0, 35.0, 35.0, 35.0, 35.0 },
{ 31.0, 34.0, 34.0, 34.0, 34.0 },
{ 31.0, 33.0, 33.0, 33.0, 33.0 },
{ 31.0, 32.0, 32.0, 32.0, 32.0 },
{ 30.0, 31.0, 31.0, 31.0, 31.0 },
{ 29.0, 30.0, 30.0, 30.0, 30.0 },
#else
{ 36.0, 37.0, 37.0, 37.0, 37.0 },
{ 35.0, 36.0, 36.0, 36.0, 36.0 },
{ 34.0, 35.0, 35.0, 35.0, 35.0 },
{ 33.0, 34.0, 34.0, 34.0, 34.0 },
{ 32.0, 33.0, 33.0, 33.0, 33.0 },
{ 31.0, 32.0, 32.0, 32.0, 32.0 },
{ 30.0, 31.0, 31.0, 31.0, 31.0 },
{ 29.0, 30.0, 30.0, 30.0, 30.0 },
#endif // CONFIG_VPX_HIGHBITDEPTH && CONFIG_VP10_ENCODER
};
typedef struct {
const char *filename;
unsigned int input_bit_depth;
vpx_img_fmt fmt;
vpx_bit_depth_t bit_depth;
unsigned int profile;
} TestVideoParam;
const TestVideoParam kTestVectors[] = {
{"park_joy_90p_8_420.y4m", 8, VPX_IMG_FMT_I420, VPX_BITS_8, 0},
{"park_joy_90p_8_422.y4m", 8, VPX_IMG_FMT_I422, VPX_BITS_8, 1},
{"park_joy_90p_8_444.y4m", 8, VPX_IMG_FMT_I444, VPX_BITS_8, 1},
{"park_joy_90p_8_440.yuv", 8, VPX_IMG_FMT_I440, VPX_BITS_8, 1},
#if CONFIG_VPX_HIGHBITDEPTH
{"park_joy_90p_10_420.y4m", 10, VPX_IMG_FMT_I42016, VPX_BITS_10, 2},
{"park_joy_90p_10_422.y4m", 10, VPX_IMG_FMT_I42216, VPX_BITS_10, 3},
{"park_joy_90p_10_444.y4m", 10, VPX_IMG_FMT_I44416, VPX_BITS_10, 3},
{"park_joy_90p_10_440.yuv", 10, VPX_IMG_FMT_I44016, VPX_BITS_10, 3},
{"park_joy_90p_12_420.y4m", 12, VPX_IMG_FMT_I42016, VPX_BITS_12, 2},
{"park_joy_90p_12_422.y4m", 12, VPX_IMG_FMT_I42216, VPX_BITS_12, 3},
{"park_joy_90p_12_444.y4m", 12, VPX_IMG_FMT_I44416, VPX_BITS_12, 3},
{"park_joy_90p_12_440.yuv", 12, VPX_IMG_FMT_I44016, VPX_BITS_12, 3},
#endif // CONFIG_VPX_HIGHBITDEPTH
};
// Encoding modes tested
const libvpx_test::TestMode kEncodingModeVectors[] = {
::libvpx_test::kTwoPassGood,
::libvpx_test::kOnePassGood,
::libvpx_test::kRealTime,
};
// Speed settings tested
const int kCpuUsedVectors[] = {1, 2, 3, 5, 6};
int is_extension_y4m(const char *filename) {
const char *dot = strrchr(filename, '.');
if (!dot || dot == filename)
return 0;
else
return !strcmp(dot, ".y4m");
}
class EndToEndTestLarge
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith3Params<libvpx_test::TestMode, \
TestVideoParam, int> {
protected:
EndToEndTestLarge()
: EncoderTest(GET_PARAM(0)),
test_video_param_(GET_PARAM(2)),
cpu_used_(GET_PARAM(3)),
psnr_(0.0),
nframes_(0),
encoding_mode_(GET_PARAM(1)) {
}
virtual ~EndToEndTestLarge() {}
virtual void SetUp() {
InitializeConfig();
SetMode(encoding_mode_);
if (encoding_mode_ != ::libvpx_test::kRealTime) {
cfg_.g_lag_in_frames = 5;
cfg_.rc_end_usage = VPX_VBR;
} else {
cfg_.g_lag_in_frames = 0;
cfg_.rc_end_usage = VPX_CBR;
cfg_.rc_buf_sz = 1000;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 600;
}
dec_cfg_.threads = 4;
}
virtual void BeginPassHook(unsigned int) {
psnr_ = 0.0;
nframes_ = 0;
}
virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
psnr_ += pkt->data.psnr.psnr[0];
nframes_++;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 1) {
encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
encoder->Control(VP9E_SET_TILE_COLUMNS, 4);
encoder->Control(VP8E_SET_CPUUSED, cpu_used_);
// Test screen coding tools at cpu_used = 1 && encoding mode is two-pass.
if (cpu_used_ == 1 && encoding_mode_ == ::libvpx_test::kTwoPassGood)
encoder->Control(VP9E_SET_TUNE_CONTENT, VPX_CONTENT_SCREEN);
else
encoder->Control(VP9E_SET_TUNE_CONTENT, VPX_CONTENT_DEFAULT);
if (encoding_mode_ != ::libvpx_test::kRealTime) {
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
encoder->Control(VP8E_SET_ARNR_TYPE, 3);
}
}
}
double GetAveragePsnr() const {
if (nframes_)
return psnr_ / nframes_;
return 0.0;
}
double GetPsnrThreshold() {
return kPsnrThreshold[cpu_used_][encoding_mode_];
}
TestVideoParam test_video_param_;
int cpu_used_;
private:
double psnr_;
unsigned int nframes_;
libvpx_test::TestMode encoding_mode_;
};
TEST_P(EndToEndTestLarge, EndtoEndPSNRTest) {
cfg_.rc_target_bitrate = kBitrate;
cfg_.g_error_resilient = 0;
cfg_.g_profile = test_video_param_.profile;
cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
cfg_.g_bit_depth = test_video_param_.bit_depth;
init_flags_ = VPX_CODEC_USE_PSNR;
if (cfg_.g_bit_depth > 8)
init_flags_ |= VPX_CODEC_USE_HIGHBITDEPTH;
libvpx_test::VideoSource *video;
if (is_extension_y4m(test_video_param_.filename)) {
video = new libvpx_test::Y4mVideoSource(test_video_param_.filename,
0, kFrames);
} else {
video = new libvpx_test::YUVVideoSource(test_video_param_.filename,
test_video_param_.fmt,
kWidth, kHeight,
kFramerate, 1, 0, kFrames);
}
ASSERT_NO_FATAL_FAILURE(RunLoop(video));
const double psnr = GetAveragePsnr();
EXPECT_GT(psnr, GetPsnrThreshold());
delete(video);
}
VP10_INSTANTIATE_TEST_CASE(
EndToEndTestLarge,
::testing::ValuesIn(kEncodingModeVectors),
::testing::ValuesIn(kTestVectors),
::testing::ValuesIn(kCpuUsedVectors));
} // namespace

View File

@@ -1,175 +0,0 @@
/*
* Copyright (c) 2014 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 <cmath>
#include <cstdlib>
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "./vp10_rtcd.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "vp10/common/entropy.h"
#include "vpx/vpx_codec.h"
#include "vpx/vpx_integer.h"
using libvpx_test::ACMRandom;
namespace {
#if CONFIG_VPX_HIGHBITDEPTH
const int kNumIterations = 1000;
typedef int64_t (*ErrorBlockFunc)(const tran_low_t *coeff,
const tran_low_t *dqcoeff,
intptr_t block_size,
int64_t *ssz, int bps);
typedef std::tr1::tuple<ErrorBlockFunc, ErrorBlockFunc, vpx_bit_depth_t>
ErrorBlockParam;
class ErrorBlockTest
: public ::testing::TestWithParam<ErrorBlockParam> {
public:
virtual ~ErrorBlockTest() {}
virtual void SetUp() {
error_block_op_ = GET_PARAM(0);
ref_error_block_op_ = GET_PARAM(1);
bit_depth_ = GET_PARAM(2);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
vpx_bit_depth_t bit_depth_;
ErrorBlockFunc error_block_op_;
ErrorBlockFunc ref_error_block_op_;
};
TEST_P(ErrorBlockTest, OperationCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
int err_count_total = 0;
int first_failure = -1;
intptr_t block_size;
int64_t ssz;
int64_t ret;
int64_t ref_ssz;
int64_t ref_ret;
const int msb = bit_depth_ + 8 - 1;
for (int i = 0; i < kNumIterations; ++i) {
int err_count = 0;
block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64
for (int j = 0; j < block_size; j++) {
// coeff and dqcoeff will always have at least the same sign, and this
// can be used for optimization, so generate test input precisely.
if (rnd(2)) {
// Positive number
coeff[j] = rnd(1 << msb);
dqcoeff[j] = rnd(1 << msb);
} else {
// Negative number
coeff[j] = -rnd(1 << msb);
dqcoeff[j] = -rnd(1 << msb);
}
}
ref_ret = ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz,
bit_depth_);
ASM_REGISTER_STATE_CHECK(ret = error_block_op_(coeff, dqcoeff, block_size,
&ssz, bit_depth_));
err_count += (ref_ret != ret) | (ref_ssz != ssz);
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Error Block Test, C output doesn't match optimized output. "
<< "First failed at test case " << first_failure;
}
TEST_P(ErrorBlockTest, ExtremeValues) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
int err_count_total = 0;
int first_failure = -1;
intptr_t block_size;
int64_t ssz;
int64_t ret;
int64_t ref_ssz;
int64_t ref_ret;
const int msb = bit_depth_ + 8 - 1;
int max_val = ((1 << msb) - 1);
for (int i = 0; i < kNumIterations; ++i) {
int err_count = 0;
int k = (i / 9) % 9;
// Change the maximum coeff value, to test different bit boundaries
if ( k == 8 && (i % 9) == 0 ) {
max_val >>= 1;
}
block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64
for (int j = 0; j < block_size; j++) {
if (k < 4) {
// Test at positive maximum values
coeff[j] = k % 2 ? max_val : 0;
dqcoeff[j] = (k >> 1) % 2 ? max_val : 0;
} else if (k < 8) {
// Test at negative maximum values
coeff[j] = k % 2 ? -max_val : 0;
dqcoeff[j] = (k >> 1) % 2 ? -max_val : 0;
} else {
if (rnd(2)) {
// Positive number
coeff[j] = rnd(1 << 14);
dqcoeff[j] = rnd(1 << 14);
} else {
// Negative number
coeff[j] = -rnd(1 << 14);
dqcoeff[j] = -rnd(1 << 14);
}
}
}
ref_ret = ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz,
bit_depth_);
ASM_REGISTER_STATE_CHECK(ret = error_block_op_(coeff, dqcoeff, block_size,
&ssz, bit_depth_));
err_count += (ref_ret != ret) | (ref_ssz != ssz);
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Error Block Test, C output doesn't match optimized output. "
<< "First failed at test case " << first_failure;
}
#if HAVE_SSE2 || HAVE_AVX
using std::tr1::make_tuple;
INSTANTIATE_TEST_CASE_P(
SSE2, ErrorBlockTest,
::testing::Values(
make_tuple(&vp10_highbd_block_error_sse2,
&vp10_highbd_block_error_c, VPX_BITS_10),
make_tuple(&vp10_highbd_block_error_sse2,
&vp10_highbd_block_error_c, VPX_BITS_12),
make_tuple(&vp10_highbd_block_error_sse2,
&vp10_highbd_block_error_c, VPX_BITS_8)));
#endif // HAVE_SSE2
#endif // CONFIG_VPX_HIGHBITDEPTH
} // namespace

View File

@@ -20,11 +20,10 @@ const int kMaxErrorFrames = 12;
const int kMaxDroppableFrames = 12; const int kMaxDroppableFrames = 12;
class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest, class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, bool> { public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected: protected:
ErrorResilienceTestLarge() ErrorResilienceTestLarge()
: EncoderTest(GET_PARAM(0)), : EncoderTest(GET_PARAM(0)),
svc_support_(GET_PARAM(2)),
psnr_(0.0), psnr_(0.0),
nframes_(0), nframes_(0),
mismatch_psnr_(0.0), mismatch_psnr_(0.0),
@@ -38,7 +37,6 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest,
void Reset() { void Reset() {
error_nframes_ = 0; error_nframes_ = 0;
droppable_nframes_ = 0; droppable_nframes_ = 0;
pattern_switch_ = 0;
} }
virtual void SetUp() { virtual void SetUp() {
@@ -58,69 +56,15 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest,
nframes_++; nframes_++;
} }
// virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video) {
// Frame flags and layer id for temporal layers.
// For two layers, test pattern is:
// 1 3
// 0 2 .....
// LAST is updated on base/layer 0, GOLDEN updated on layer 1.
// Non-zero pattern_switch parameter means pattern will switch to
// not using LAST for frame_num >= pattern_switch.
int SetFrameFlags(int frame_num,
int num_temp_layers,
int pattern_switch) {
int frame_flags = 0;
if (num_temp_layers == 2) {
if (frame_num % 2 == 0) {
if (frame_num < pattern_switch || pattern_switch == 0) {
// Layer 0: predict from LAST and ARF, update LAST.
frame_flags = VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF;
} else {
// Layer 0: predict from GF and ARF, update GF.
frame_flags = VP8_EFLAG_NO_REF_LAST |
VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ARF;
}
} else {
if (frame_num < pattern_switch || pattern_switch == 0) {
// Layer 1: predict from L, GF, and ARF, update GF.
frame_flags = VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_LAST;
} else {
// Layer 1: predict from GF and ARF, update GF.
frame_flags = VP8_EFLAG_NO_REF_LAST |
VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ARF;
}
}
}
return frame_flags;
}
virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
::libvpx_test::Encoder * /*encoder*/) {
frame_flags_ &= ~(VP8_EFLAG_NO_UPD_LAST | frame_flags_ &= ~(VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF); VP8_EFLAG_NO_UPD_ARF);
// For temporal layer case.
if (cfg_.ts_number_layers > 1) {
frame_flags_ = SetFrameFlags(video->frame(),
cfg_.ts_number_layers,
pattern_switch_);
for (unsigned int i = 0; i < droppable_nframes_; ++i) {
if (droppable_frames_[i] == video->frame()) {
std::cout << "Encoding droppable frame: "
<< droppable_frames_[i] << "\n";
}
}
} else {
if (droppable_nframes_ > 0 && if (droppable_nframes_ > 0 &&
(cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) { (cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) {
for (unsigned int i = 0; i < droppable_nframes_; ++i) { for (unsigned int i = 0; i < droppable_nframes_; ++i) {
if (droppable_frames_[i] == video->frame()) { if (droppable_frames_[i] == video->frame()) {
std::cout << "Encoding droppable frame: " std::cout << " Encoding droppable frame: "
<< droppable_frames_[i] << "\n"; << droppable_frames_[i] << "\n";
frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST | frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_GF |
@@ -130,7 +74,6 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest,
} }
} }
} }
}
double GetAveragePsnr() const { double GetAveragePsnr() const {
if (nframes_) if (nframes_)
@@ -164,7 +107,6 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest,
mismatch_psnr_ += mismatch_psnr; mismatch_psnr_ += mismatch_psnr;
++mismatch_nframes_; ++mismatch_nframes_;
// std::cout << "Mismatch frame psnr: " << mismatch_psnr << "\n"; // std::cout << "Mismatch frame psnr: " << mismatch_psnr << "\n";
::libvpx_test::EncoderTest::MismatchHook(img1, img2);
} }
void SetErrorFrames(int num, unsigned int *list) { void SetErrorFrames(int num, unsigned int *list) {
@@ -191,18 +133,11 @@ class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest,
return mismatch_nframes_; return mismatch_nframes_;
} }
void SetPatternSwitch(int frame_switch) {
pattern_switch_ = frame_switch;
}
bool svc_support_;
private: private:
double psnr_; double psnr_;
unsigned int nframes_; unsigned int nframes_;
unsigned int error_nframes_; unsigned int error_nframes_;
unsigned int droppable_nframes_; unsigned int droppable_nframes_;
unsigned int pattern_switch_;
double mismatch_psnr_; double mismatch_psnr_;
unsigned int mismatch_nframes_; unsigned int mismatch_nframes_;
unsigned int error_frames_[kMaxErrorFrames]; unsigned int error_frames_[kMaxErrorFrames];
@@ -301,297 +236,7 @@ TEST_P(ErrorResilienceTestLarge, DropFramesWithoutRecovery) {
#endif #endif
} }
// Check for successful decoding and no encoder/decoder mismatch VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES);
// if we lose (i.e., drop before decoding) the enhancement layer frames for a VP9_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES);
// two layer temporal pattern. The base layer does not predict from the top
// layer, so successful decoding is expected.
TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) {
// This test doesn't run if SVC is not supported.
if (!svc_support_)
return;
const vpx_rational timebase = { 33333333, 1000000000 };
cfg_.g_timebase = timebase;
cfg_.rc_target_bitrate = 500;
cfg_.g_lag_in_frames = 0;
cfg_.rc_end_usage = VPX_CBR;
// 2 Temporal layers, no spatial layers, CBR mode.
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 2;
cfg_.ts_rate_decimator[0] = 2;
cfg_.ts_rate_decimator[1] = 1;
cfg_.ts_periodicity = 2;
cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
init_flags_ = VPX_CODEC_USE_PSNR;
libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
timebase.den, timebase.num, 0, 40);
// Error resilient mode ON.
cfg_.g_error_resilient = 1;
cfg_.kf_mode = VPX_KF_DISABLED;
SetPatternSwitch(0);
// The odd frames are the enhancement layer for 2 layer pattern, so set
// those frames as droppable. Drop the last 7 frames.
unsigned int num_droppable_frames = 7;
unsigned int droppable_frame_list[] = {27, 29, 31, 33, 35, 37, 39};
SetDroppableFrames(num_droppable_frames, droppable_frame_list);
SetErrorFrames(num_droppable_frames, droppable_frame_list);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// Test that no mismatches have been found
std::cout << " Mismatch frames: "
<< GetMismatchFrames() << "\n";
EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
// Reset previously set of error/droppable frames.
Reset();
}
// Check for successful decoding and no encoder/decoder mismatch
// for a two layer temporal pattern, where at some point in the
// sequence, the LAST ref is not used anymore.
TEST_P(ErrorResilienceTestLarge, 2LayersNoRefLast) {
// This test doesn't run if SVC is not supported.
if (!svc_support_)
return;
const vpx_rational timebase = { 33333333, 1000000000 };
cfg_.g_timebase = timebase;
cfg_.rc_target_bitrate = 500;
cfg_.g_lag_in_frames = 0;
cfg_.rc_end_usage = VPX_CBR;
// 2 Temporal layers, no spatial layers, CBR mode.
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 2;
cfg_.ts_rate_decimator[0] = 2;
cfg_.ts_rate_decimator[1] = 1;
cfg_.ts_periodicity = 2;
cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
init_flags_ = VPX_CODEC_USE_PSNR;
libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
timebase.den, timebase.num, 0, 100);
// Error resilient mode ON.
cfg_.g_error_resilient = 1;
cfg_.kf_mode = VPX_KF_DISABLED;
SetPatternSwitch(60);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// Test that no mismatches have been found
std::cout << " Mismatch frames: "
<< GetMismatchFrames() << "\n";
EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
// Reset previously set of error/droppable frames.
Reset();
}
class ErrorResilienceTestLargeCodecControls : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected:
ErrorResilienceTestLargeCodecControls()
: EncoderTest(GET_PARAM(0)),
encoding_mode_(GET_PARAM(1)) {
Reset();
}
virtual ~ErrorResilienceTestLargeCodecControls() {}
void Reset() {
last_pts_ = 0;
tot_frame_number_ = 0;
// For testing up to 3 layers.
for (int i = 0; i < 3; ++i) {
bits_total_[i] = 0;
}
duration_ = 0.0;
}
virtual void SetUp() {
InitializeConfig();
SetMode(encoding_mode_);
}
//
// Frame flags and layer id for temporal layers.
//
// For two layers, test pattern is:
// 1 3
// 0 2 .....
// For three layers, test pattern is:
// 1 3 5 7
// 2 6
// 0 4 ....
// LAST is always update on base/layer 0, GOLDEN is updated on layer 1,
// and ALTREF is updated on top layer for 3 layer pattern.
int SetFrameFlags(int frame_num, int num_temp_layers) {
int frame_flags = 0;
if (num_temp_layers == 2) {
if (frame_num % 2 == 0) {
// Layer 0: predict from L and ARF, update L.
frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF;
} else {
// Layer 1: predict from L, G and ARF, and update G.
frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ENTROPY;
}
} else if (num_temp_layers == 3) {
if (frame_num % 4 == 0) {
// Layer 0: predict from L, update L.
frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
} else if ((frame_num - 2) % 4 == 0) {
// Layer 1: predict from L, G, update G.
frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_REF_ARF;
} else if ((frame_num - 1) % 2 == 0) {
// Layer 2: predict from L, G, ARF; update ARG.
frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
}
}
return frame_flags;
}
int SetLayerId(int frame_num, int num_temp_layers) {
int layer_id = 0;
if (num_temp_layers == 2) {
if (frame_num % 2 == 0) {
layer_id = 0;
} else {
layer_id = 1;
}
} else if (num_temp_layers == 3) {
if (frame_num % 4 == 0) {
layer_id = 0;
} else if ((frame_num - 2) % 4 == 0) {
layer_id = 1;
} else if ((frame_num - 1) % 2 == 0) {
layer_id = 2;
}
}
return layer_id;
}
virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
libvpx_test::Encoder *encoder) {
if (cfg_.ts_number_layers > 1) {
int layer_id = SetLayerId(video->frame(), cfg_.ts_number_layers);
int frame_flags = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
if (video->frame() > 0) {
encoder->Control(VP8E_SET_TEMPORAL_LAYER_ID, layer_id);
encoder->Control(VP8E_SET_FRAME_FLAGS, frame_flags);
}
const vpx_rational_t tb = video->timebase();
timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0;
return;
}
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
// Time since last timestamp = duration.
vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
if (duration > 1) {
// Update counter for total number of frames (#frames input to encoder).
// Needed for setting the proper layer_id below.
tot_frame_number_ += static_cast<int>(duration - 1);
}
int layer = SetLayerId(tot_frame_number_, cfg_.ts_number_layers);
const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
// Update the total encoded bits. For temporal layers, update the cumulative
// encoded bits per layer.
for (int i = layer; i < static_cast<int>(cfg_.ts_number_layers); ++i) {
bits_total_[i] += frame_size_in_bits;
}
// Update the most recent pts.
last_pts_ = pkt->data.frame.pts;
++tot_frame_number_;
}
virtual void EndPassHook(void) {
duration_ = (last_pts_ + 1) * timebase_;
if (cfg_.ts_number_layers > 1) {
for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers);
++layer) {
if (bits_total_[layer]) {
// Effective file datarate:
effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_;
}
}
}
}
double effective_datarate_[3];
private:
libvpx_test::TestMode encoding_mode_;
vpx_codec_pts_t last_pts_;
double timebase_;
int64_t bits_total_[3];
double duration_;
int tot_frame_number_;
};
// Check two codec controls used for:
// (1) for setting temporal layer id, and (2) for settings encoder flags.
// This test invokes those controls for each frame, and verifies encoder/decoder
// mismatch and basic rate control response.
// TODO(marpan): Maybe move this test to datarate_test.cc.
TEST_P(ErrorResilienceTestLargeCodecControls, CodecControl3TemporalLayers) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_min_quantizer = 2;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_CBR;
cfg_.rc_dropframe_thresh = 1;
cfg_.g_lag_in_frames = 0;
cfg_.kf_mode = VPX_KF_DISABLED;
cfg_.g_error_resilient = 1;
// 3 Temporal layers. Framerate decimation (4, 2, 1).
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.ts_periodicity = 4;
cfg_.ts_layer_id[0] = 0;
cfg_.ts_layer_id[1] = 2;
cfg_.ts_layer_id[2] = 1;
cfg_.ts_layer_id[3] = 2;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
for (int i = 200; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i;
Reset();
// 40-20-40 bitrate allocation for 3 temporal layers.
cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.75)
<< " The datarate for the file is lower than target by too much, "
"for layer: " << j;
ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.25)
<< " The datarate for the file is greater than target by too much, "
"for layer: " << j;
}
}
}
// SVC-related tests don't run for VP10 since SVC is not supported.
VP10_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES,
::testing::Values(false));
} // namespace } // namespace

View File

@@ -1,192 +0,0 @@
/*
* Copyright (c) 2014 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 <string>
#include <vector>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/md5_helper.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
namespace {
class VPxEncoderThreadTest
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
protected:
VPxEncoderThreadTest()
: EncoderTest(GET_PARAM(0)),
encoder_initialized_(false),
encoding_mode_(GET_PARAM(1)),
set_cpu_used_(GET_PARAM(2)) {
init_flags_ = VPX_CODEC_USE_PSNR;
vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
cfg.w = 1280;
cfg.h = 720;
decoder_ = codec_->CreateDecoder(cfg, 0);
#if CONFIG_VP10 && CONFIG_EXT_TILE
if (decoder_->IsVP10()) {
decoder_->Control(VP10_SET_DECODE_TILE_ROW, -1);
decoder_->Control(VP10_SET_DECODE_TILE_COL, -1);
}
#endif
size_enc_.clear();
md5_dec_.clear();
md5_enc_.clear();
}
virtual ~VPxEncoderThreadTest() {
delete decoder_;
}
virtual void SetUp() {
InitializeConfig();
SetMode(encoding_mode_);
if (encoding_mode_ != ::libvpx_test::kRealTime) {
cfg_.g_lag_in_frames = 3;
cfg_.rc_end_usage = VPX_VBR;
cfg_.rc_2pass_vbr_minsection_pct = 5;
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
} else {
cfg_.g_lag_in_frames = 0;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_error_resilient = 1;
}
cfg_.rc_max_quantizer = 56;
cfg_.rc_min_quantizer = 0;
}
virtual void BeginPassHook(unsigned int /*pass*/) {
encoder_initialized_ = false;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource * /*video*/,
::libvpx_test::Encoder *encoder) {
if (!encoder_initialized_) {
#if CONFIG_VP10 && CONFIG_EXT_TILE
encoder->Control(VP9E_SET_TILE_COLUMNS, 1);
if (codec_ == &libvpx_test::kVP10) {
// TODO(geza): Start using multiple tile rows when the multi-threaded
// encoder can handle them
encoder->Control(VP9E_SET_TILE_ROWS, 32);
} else {
encoder->Control(VP9E_SET_TILE_ROWS, 0);
}
#else
// Encode 4 tile columns.
encoder->Control(VP9E_SET_TILE_COLUMNS, 2);
encoder->Control(VP9E_SET_TILE_ROWS, 0);
#endif // CONFIG_VP10 && CONFIG_EXT_TILE
encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
if (encoding_mode_ != ::libvpx_test::kRealTime) {
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
encoder->Control(VP8E_SET_ARNR_TYPE, 3);
} else {
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 0);
encoder->Control(VP9E_SET_AQ_MODE, 3);
}
encoder_initialized_ = true;
}
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
size_enc_.push_back(pkt->data.frame.sz);
::libvpx_test::MD5 md5_enc;
md5_enc.Add(reinterpret_cast<uint8_t*>(pkt->data.frame.buf),
pkt->data.frame.sz);
md5_enc_.push_back(md5_enc.Get());
const vpx_codec_err_t res = decoder_->DecodeFrame(
reinterpret_cast<uint8_t*>(pkt->data.frame.buf), pkt->data.frame.sz);
if (res != VPX_CODEC_OK) {
abort_ = true;
ASSERT_EQ(VPX_CODEC_OK, res);
}
const vpx_image_t *img = decoder_->GetDxData().Next();
if (img) {
::libvpx_test::MD5 md5_res;
md5_res.Add(img);
md5_dec_.push_back(md5_res.Get());
}
}
void DoTest() {
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 15, 18);
cfg_.rc_target_bitrate = 1000;
// Encode using single thread.
cfg_.g_threads = 1;
init_flags_ = VPX_CODEC_USE_PSNR;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
std::vector<size_t> single_thr_size_enc;
std::vector<std::string> single_thr_md5_enc;
std::vector<std::string> single_thr_md5_dec;
single_thr_size_enc = size_enc_;
single_thr_md5_enc = md5_enc_;
single_thr_md5_dec = md5_dec_;
size_enc_.clear();
md5_enc_.clear();
md5_dec_.clear();
// Encode using multiple threads.
cfg_.g_threads = 4;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
std::vector<size_t> multi_thr_size_enc;
std::vector<std::string> multi_thr_md5_enc;
std::vector<std::string> multi_thr_md5_dec;
multi_thr_size_enc = size_enc_;
multi_thr_md5_enc = md5_enc_;
multi_thr_md5_dec = md5_dec_;
size_enc_.clear();
md5_enc_.clear();
md5_dec_.clear();
// Check that the vectors are equal.
ASSERT_EQ(single_thr_size_enc, multi_thr_size_enc);
ASSERT_EQ(single_thr_md5_enc, multi_thr_md5_enc);
ASSERT_EQ(single_thr_md5_dec, multi_thr_md5_dec);
}
bool encoder_initialized_;
::libvpx_test::TestMode encoding_mode_;
int set_cpu_used_;
::libvpx_test::Decoder *decoder_;
std::vector<size_t> size_enc_;
std::vector<std::string> md5_enc_;
std::vector<std::string> md5_dec_;
};
TEST_P(VPxEncoderThreadTest, EncoderResultTest) {
DoTest();
}
class VPxEncoderThreadTestLarge : public VPxEncoderThreadTest {};
TEST_P(VPxEncoderThreadTestLarge, EncoderResultTest) {
DoTest();
}
VP10_INSTANTIATE_TEST_CASE(
VPxEncoderThreadTest,
::testing::Values(::libvpx_test::kTwoPassGood, ::libvpx_test::kOnePassGood),
::testing::Range(3, 9));
VP10_INSTANTIATE_TEST_CASE(
VPxEncoderThreadTestLarge,
::testing::Values(::libvpx_test::kTwoPassGood, ::libvpx_test::kOnePassGood),
::testing::Range(1, 3));
} // namespace

View File

@@ -15,7 +15,7 @@
example_tests=$(ls $(dirname $0)/*.sh) example_tests=$(ls $(dirname $0)/*.sh)
# List of script names to exclude. # List of script names to exclude.
exclude_list="examples tools_common" exclude_list="examples vpxdec vpxenc tools_common"
# Filter out the scripts in $exclude_list. # Filter out the scripts in $exclude_list.
for word in ${exclude_list}; do for word in ${exclude_list}; do

View File

@@ -0,0 +1,481 @@
/*
* Copyright (c) 2014 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 <string>
#include "./vpx_config.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/ivf_video_source.h"
#include "test/md5_helper.h"
#include "test/test_vectors.h"
#include "test/util.h"
#if CONFIG_WEBM_IO
#include "test/webm_video_source.h"
#endif
namespace {
const int kVideoNameParam = 1;
const char kVP9TestFile[] = "vp90-2-02-size-lf-1920x1080.webm";
struct ExternalFrameBuffer {
uint8_t *data;
size_t size;
int in_use;
};
// Class to manipulate a list of external frame buffers.
class ExternalFrameBufferList {
public:
ExternalFrameBufferList()
: num_buffers_(0),
ext_fb_list_(NULL) {}
virtual ~ExternalFrameBufferList() {
for (int i = 0; i < num_buffers_; ++i) {
delete [] ext_fb_list_[i].data;
}
delete [] ext_fb_list_;
}
// Creates the list to hold the external buffers. Returns true on success.
bool CreateBufferList(int num_buffers) {
if (num_buffers < 0)
return false;
num_buffers_ = num_buffers;
ext_fb_list_ = new ExternalFrameBuffer[num_buffers_];
EXPECT_TRUE(ext_fb_list_ != NULL);
memset(ext_fb_list_, 0, sizeof(ext_fb_list_[0]) * num_buffers_);
return true;
}
// Searches the frame buffer list for a free frame buffer. Makes sure
// that the frame buffer is at least |min_size| in bytes. Marks that the
// frame buffer is in use by libvpx. Finally sets |fb| to point to the
// external frame buffer. Returns < 0 on an error.
int GetFreeFrameBuffer(size_t min_size, vpx_codec_frame_buffer_t *fb) {
EXPECT_TRUE(fb != NULL);
const int idx = FindFreeBufferIndex();
if (idx == num_buffers_)
return -1;
if (ext_fb_list_[idx].size < min_size) {
delete [] ext_fb_list_[idx].data;
ext_fb_list_[idx].data = new uint8_t[min_size];
ext_fb_list_[idx].size = min_size;
}
SetFrameBuffer(idx, fb);
return 0;
}
// Test function that will not allocate any data for the frame buffer.
// Returns < 0 on an error.
int GetZeroFrameBuffer(size_t min_size, vpx_codec_frame_buffer_t *fb) {
EXPECT_TRUE(fb != NULL);
const int idx = FindFreeBufferIndex();
if (idx == num_buffers_)
return -1;
if (ext_fb_list_[idx].size < min_size) {
delete [] ext_fb_list_[idx].data;
ext_fb_list_[idx].data = NULL;
ext_fb_list_[idx].size = min_size;
}
SetFrameBuffer(idx, fb);
return 0;
}
// Marks the external frame buffer that |fb| is pointing too as free.
// Returns < 0 on an error.
int ReturnFrameBuffer(vpx_codec_frame_buffer_t *fb) {
EXPECT_TRUE(fb != NULL);
ExternalFrameBuffer *const ext_fb =
reinterpret_cast<ExternalFrameBuffer*>(fb->priv);
EXPECT_TRUE(ext_fb != NULL);
EXPECT_EQ(1, ext_fb->in_use);
ext_fb->in_use = 0;
return 0;
}
// Checks that the ximage data is contained within the external frame buffer
// private data passed back in the ximage.
void CheckXImageFrameBuffer(const vpx_image_t *img) {
if (img->fb_priv != NULL) {
const struct ExternalFrameBuffer *const ext_fb =
reinterpret_cast<ExternalFrameBuffer*>(img->fb_priv);
ASSERT_TRUE(img->planes[0] >= ext_fb->data &&
img->planes[0] < (ext_fb->data + ext_fb->size));
}
}
private:
// Returns the index of the first free frame buffer. Returns |num_buffers_|
// if there are no free frame buffers.
int FindFreeBufferIndex() {
int i;
// Find a free frame buffer.
for (i = 0; i < num_buffers_; ++i) {
if (!ext_fb_list_[i].in_use)
break;
}
return i;
}
// Sets |fb| to an external frame buffer. idx is the index into the frame
// buffer list.
void SetFrameBuffer(int idx, vpx_codec_frame_buffer_t *fb) {
ASSERT_TRUE(fb != NULL);
fb->data = ext_fb_list_[idx].data;
fb->size = ext_fb_list_[idx].size;
ASSERT_EQ(0, ext_fb_list_[idx].in_use);
ext_fb_list_[idx].in_use = 1;
fb->priv = &ext_fb_list_[idx];
}
int num_buffers_;
ExternalFrameBuffer *ext_fb_list_;
};
// Callback used by libvpx to request the application to return a frame
// buffer of at least |min_size| in bytes.
int get_vp9_frame_buffer(void *user_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list =
reinterpret_cast<ExternalFrameBufferList*>(user_priv);
return fb_list->GetFreeFrameBuffer(min_size, fb);
}
// Callback used by libvpx to tell the application that |fb| is not needed
// anymore.
int release_vp9_frame_buffer(void *user_priv,
vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list =
reinterpret_cast<ExternalFrameBufferList*>(user_priv);
return fb_list->ReturnFrameBuffer(fb);
}
// Callback will not allocate data for frame buffer.
int get_vp9_zero_frame_buffer(void *user_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list =
reinterpret_cast<ExternalFrameBufferList*>(user_priv);
return fb_list->GetZeroFrameBuffer(min_size, fb);
}
// Callback will allocate one less byte than |min_size|.
int get_vp9_one_less_byte_frame_buffer(void *user_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list =
reinterpret_cast<ExternalFrameBufferList*>(user_priv);
return fb_list->GetFreeFrameBuffer(min_size - 1, fb);
}
// Callback will not release the external frame buffer.
int do_not_release_vp9_frame_buffer(void *user_priv,
vpx_codec_frame_buffer_t *fb) {
(void)user_priv;
(void)fb;
return 0;
}
// Class for testing passing in external frame buffers to libvpx.
class ExternalFrameBufferMD5Test
: public ::libvpx_test::DecoderTest,
public ::libvpx_test::CodecTestWithParam<const char*> {
protected:
ExternalFrameBufferMD5Test()
: DecoderTest(GET_PARAM(::libvpx_test::kCodecFactoryParam)),
md5_file_(NULL),
num_buffers_(0) {}
virtual ~ExternalFrameBufferMD5Test() {
if (md5_file_ != NULL)
fclose(md5_file_);
}
virtual void PreDecodeFrameHook(
const libvpx_test::CompressedVideoSource &video,
libvpx_test::Decoder *decoder) {
if (num_buffers_ > 0 && video.frame_number() == 0) {
// Have libvpx use frame buffers we create.
ASSERT_TRUE(fb_list_.CreateBufferList(num_buffers_));
ASSERT_EQ(VPX_CODEC_OK,
decoder->SetFrameBufferFunctions(
GetVP9FrameBuffer, ReleaseVP9FrameBuffer, this));
}
}
void OpenMD5File(const std::string &md5_file_name_) {
md5_file_ = libvpx_test::OpenTestDataFile(md5_file_name_);
ASSERT_TRUE(md5_file_ != NULL) << "Md5 file open failed. Filename: "
<< md5_file_name_;
}
virtual void DecompressedFrameHook(const vpx_image_t &img,
const unsigned int frame_number) {
ASSERT_TRUE(md5_file_ != NULL);
char expected_md5[33];
char junk[128];
// Read correct md5 checksums.
const int res = fscanf(md5_file_, "%s %s", expected_md5, junk);
ASSERT_NE(EOF, res) << "Read md5 data failed";
expected_md5[32] = '\0';
::libvpx_test::MD5 md5_res;
md5_res.Add(&img);
const char *const actual_md5 = md5_res.Get();
// Check md5 match.
ASSERT_STREQ(expected_md5, actual_md5)
<< "Md5 checksums don't match: frame number = " << frame_number;
}
// Callback to get a free external frame buffer. Return value < 0 is an
// error.
static int GetVP9FrameBuffer(void *user_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferMD5Test *const md5Test =
reinterpret_cast<ExternalFrameBufferMD5Test*>(user_priv);
return md5Test->fb_list_.GetFreeFrameBuffer(min_size, fb);
}
// Callback to release an external frame buffer. Return value < 0 is an
// error.
static int ReleaseVP9FrameBuffer(void *user_priv,
vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferMD5Test *const md5Test =
reinterpret_cast<ExternalFrameBufferMD5Test*>(user_priv);
return md5Test->fb_list_.ReturnFrameBuffer(fb);
}
void set_num_buffers(int num_buffers) { num_buffers_ = num_buffers; }
int num_buffers() const { return num_buffers_; }
private:
FILE *md5_file_;
int num_buffers_;
ExternalFrameBufferList fb_list_;
};
#if CONFIG_WEBM_IO
// Class for testing passing in external frame buffers to libvpx.
class ExternalFrameBufferTest : public ::testing::Test {
protected:
ExternalFrameBufferTest()
: video_(NULL),
decoder_(NULL),
num_buffers_(0) {}
virtual void SetUp() {
video_ = new libvpx_test::WebMVideoSource(kVP9TestFile);
ASSERT_TRUE(video_ != NULL);
video_->Init();
video_->Begin();
vpx_codec_dec_cfg_t cfg = {0};
decoder_ = new libvpx_test::VP9Decoder(cfg, 0);
ASSERT_TRUE(decoder_ != NULL);
}
virtual void TearDown() {
delete decoder_;
delete video_;
}
// Passes the external frame buffer information to libvpx.
vpx_codec_err_t SetFrameBufferFunctions(
int num_buffers,
vpx_get_frame_buffer_cb_fn_t cb_get,
vpx_release_frame_buffer_cb_fn_t cb_release) {
if (num_buffers > 0) {
num_buffers_ = num_buffers;
EXPECT_TRUE(fb_list_.CreateBufferList(num_buffers_));
}
return decoder_->SetFrameBufferFunctions(cb_get, cb_release, &fb_list_);
}
vpx_codec_err_t DecodeOneFrame() {
const vpx_codec_err_t res =
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
CheckDecodedFrames();
if (res == VPX_CODEC_OK)
video_->Next();
return res;
}
vpx_codec_err_t DecodeRemainingFrames() {
for (; video_->cxdata() != NULL; video_->Next()) {
const vpx_codec_err_t res =
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
if (res != VPX_CODEC_OK)
return res;
CheckDecodedFrames();
}
return VPX_CODEC_OK;
}
private:
void CheckDecodedFrames() {
libvpx_test::DxDataIterator dec_iter = decoder_->GetDxData();
const vpx_image_t *img = NULL;
// Get decompressed data
while ((img = dec_iter.Next()) != NULL) {
fb_list_.CheckXImageFrameBuffer(img);
}
}
libvpx_test::WebMVideoSource *video_;
libvpx_test::VP9Decoder *decoder_;
int num_buffers_;
ExternalFrameBufferList fb_list_;
};
#endif // CONFIG_WEBM_IO
// This test runs through the set of test vectors, and decodes them.
// Libvpx will call into the application to allocate a frame buffer when
// needed. The md5 checksums are computed for each frame in the video file.
// If md5 checksums match the correct md5 data, then the test is passed.
// Otherwise, the test failed.
TEST_P(ExternalFrameBufferMD5Test, ExtFBMD5Match) {
const std::string filename = GET_PARAM(kVideoNameParam);
libvpx_test::CompressedVideoSource *video = NULL;
// Number of buffers equals #VP9_MAXIMUM_REF_BUFFERS +
// #VPX_MAXIMUM_WORK_BUFFERS + four jitter buffers.
const int jitter_buffers = 4;
const int num_buffers =
VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS + jitter_buffers;
set_num_buffers(num_buffers);
#if CONFIG_VP8_DECODER
// Tell compiler we are not using kVP8TestVectors.
(void)libvpx_test::kVP8TestVectors;
#endif
// Open compressed video file.
if (filename.substr(filename.length() - 3, 3) == "ivf") {
video = new libvpx_test::IVFVideoSource(filename);
} else {
#if CONFIG_WEBM_IO
video = new libvpx_test::WebMVideoSource(filename);
#else
fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
filename.c_str());
return;
#endif
}
ASSERT_TRUE(video != NULL);
video->Init();
// Construct md5 file name.
const std::string md5_filename = filename + ".md5";
OpenMD5File(md5_filename);
// Decode frame, and check the md5 matching.
ASSERT_NO_FATAL_FAILURE(RunLoop(video));
delete video;
}
#if CONFIG_WEBM_IO
TEST_F(ExternalFrameBufferTest, MinFrameBuffers) {
// Minimum number of external frame buffers for VP9 is
// #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS.
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
ASSERT_EQ(VPX_CODEC_OK,
SetFrameBufferFunctions(
num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames());
}
TEST_F(ExternalFrameBufferTest, EightJitterBuffers) {
// Number of buffers equals #VP9_MAXIMUM_REF_BUFFERS +
// #VPX_MAXIMUM_WORK_BUFFERS + eight jitter buffers.
const int jitter_buffers = 8;
const int num_buffers =
VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS + jitter_buffers;
ASSERT_EQ(VPX_CODEC_OK,
SetFrameBufferFunctions(
num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames());
}
TEST_F(ExternalFrameBufferTest, NotEnoughBuffers) {
// Minimum number of external frame buffers for VP9 is
// #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS. Most files will
// only use 5 frame buffers at one time.
const int num_buffers = 2;
ASSERT_EQ(VPX_CODEC_OK,
SetFrameBufferFunctions(
num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_OK, DecodeOneFrame());
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeRemainingFrames());
}
TEST_F(ExternalFrameBufferTest, NoRelease) {
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
ASSERT_EQ(VPX_CODEC_OK,
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer,
do_not_release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_OK, DecodeOneFrame());
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeRemainingFrames());
}
TEST_F(ExternalFrameBufferTest, NullRealloc) {
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
ASSERT_EQ(VPX_CODEC_OK,
SetFrameBufferFunctions(num_buffers, get_vp9_zero_frame_buffer,
release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeOneFrame());
}
TEST_F(ExternalFrameBufferTest, ReallocOneLessByte) {
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
ASSERT_EQ(VPX_CODEC_OK,
SetFrameBufferFunctions(
num_buffers, get_vp9_one_less_byte_frame_buffer,
release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeOneFrame());
}
TEST_F(ExternalFrameBufferTest, NullGetFunction) {
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
ASSERT_EQ(VPX_CODEC_INVALID_PARAM,
SetFrameBufferFunctions(num_buffers, NULL,
release_vp9_frame_buffer));
}
TEST_F(ExternalFrameBufferTest, NullReleaseFunction) {
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
ASSERT_EQ(VPX_CODEC_INVALID_PARAM,
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer, NULL));
}
TEST_F(ExternalFrameBufferTest, SetAfterDecode) {
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
ASSERT_EQ(VPX_CODEC_OK, DecodeOneFrame());
ASSERT_EQ(VPX_CODEC_ERROR,
SetFrameBufferFunctions(
num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
}
#endif // CONFIG_WEBM_IO
VP9_INSTANTIATE_TEST_CASE(ExternalFrameBufferMD5Test,
::testing::ValuesIn(libvpx_test::kVP9TestVectors,
libvpx_test::kVP9TestVectors +
libvpx_test::kNumVP9TestVectors));
} // namespace

View File

@@ -13,87 +13,188 @@
#include <string.h> #include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vp10_rtcd.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h" #include "test/acm_random.h"
#include "test/clear_system_state.h" #include "test/clear_system_state.h"
#include "test/register_state_check.h" #include "test/register_state_check.h"
#include "test/transform_test_base.h"
#include "test/util.h" #include "test/util.h"
#include "vp10/common/entropy.h"
#include "vpx/vpx_codec.h" #include "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_integer.h" #include "vpx/vpx_integer.h"
#include "vpx_ports/mem.h"
extern "C" {
void vp9_idct4x4_16_add_c(const int16_t *input, uint8_t *output, int pitch);
}
using libvpx_test::ACMRandom; using libvpx_test::ACMRandom;
namespace { namespace {
typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride); const int kNumCoeffs = 16;
typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride); typedef void (*fdct_t)(const int16_t *in, int16_t *out, int stride);
typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, typedef void (*idct_t)(const int16_t *in, uint8_t *out, int stride);
typedef void (*fht_t) (const int16_t *in, int16_t *out, int stride,
int tx_type);
typedef void (*iht_t) (const int16_t *in, uint8_t *out, int stride,
int tx_type); int tx_type);
using libvpx_test::FhtFunc;
typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t, int> typedef std::tr1::tuple<fdct_t, idct_t, int> dct_4x4_param_t;
Dct4x4Param; typedef std::tr1::tuple<fht_t, iht_t, int> ht_4x4_param_t;
typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t, int>
Ht4x4Param;
void fdct4x4_ref(const int16_t *in, tran_low_t *out, int stride, void fdct4x4_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
int /*tx_type*/) { vp9_fdct4x4_c(in, out, stride);
vpx_fdct4x4_c(in, out, stride);
} }
void fht4x4_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) { void fht4x4_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
vp10_fht4x4_c(in, out, stride, tx_type); vp9_fht4x4_c(in, out, stride, tx_type);
} }
void fwht4x4_ref(const int16_t *in, tran_low_t *out, int stride, void fwht4x4_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
int /*tx_type*/) { vp9_fwht4x4_c(in, out, stride);
vp10_fwht4x4_c(in, out, stride);
} }
#if CONFIG_VPX_HIGHBITDEPTH class Trans4x4TestBase {
void idct4x4_10(const tran_low_t *in, uint8_t *out, int stride) { public:
vpx_highbd_idct4x4_16_add_c(in, out, stride, 10); virtual ~Trans4x4TestBase() {}
}
void idct4x4_12(const tran_low_t *in, uint8_t *out, int stride) { protected:
vpx_highbd_idct4x4_16_add_c(in, out, stride, 12); virtual void RunFwdTxfm(const int16_t *in, int16_t *out, int stride) = 0;
}
void iht4x4_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) { virtual void RunInvTxfm(const int16_t *out, uint8_t *dst, int stride) = 0;
vp10_highbd_iht4x4_16_add_c(in, out, stride, tx_type, 10);
}
void iht4x4_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) { void RunAccuracyCheck(int limit) {
vp10_highbd_iht4x4_16_add_c(in, out, stride, tx_type, 12); ACMRandom rnd(ACMRandom::DeterministicSeed());
} uint32_t max_error = 0;
int64_t total_error = 0;
const int count_test_block = 10000;
for (int i = 0; i < count_test_block; ++i) {
DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
void iwht4x4_10(const tran_low_t *in, uint8_t *out, int stride) { // Initialize a test block with input range [-255, 255].
vpx_highbd_iwht4x4_16_add_c(in, out, stride, 10); for (int j = 0; j < kNumCoeffs; ++j) {
} src[j] = rnd.Rand8();
dst[j] = rnd.Rand8();
test_input_block[j] = src[j] - dst[j];
}
void iwht4x4_12(const tran_low_t *in, uint8_t *out, int stride) { REGISTER_STATE_CHECK(RunFwdTxfm(test_input_block,
vpx_highbd_iwht4x4_16_add_c(in, out, stride, 12); test_temp_block, pitch_));
} REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_));
#if HAVE_SSE2 for (int j = 0; j < kNumCoeffs; ++j) {
void idct4x4_10_sse2(const tran_low_t *in, uint8_t *out, int stride) { const uint32_t diff = dst[j] - src[j];
vpx_highbd_idct4x4_16_add_sse2(in, out, stride, 10); const uint32_t error = diff * diff;
} if (max_error < error)
max_error = error;
total_error += error;
}
}
void idct4x4_12_sse2(const tran_low_t *in, uint8_t *out, int stride) { EXPECT_GE(static_cast<uint32_t>(limit), max_error)
vpx_highbd_idct4x4_16_add_sse2(in, out, stride, 12); << "Error: 4x4 FHT/IHT has an individual round trip error > "
} << limit;
#endif // HAVE_SSE2
#endif // CONFIG_VPX_HIGHBITDEPTH
EXPECT_GE(count_test_block * limit, total_error)
<< "Error: 4x4 FHT/IHT has average round trip error > " << limit
<< " per block";
}
void RunCoeffCheck() {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 5000;
DECLARE_ALIGNED_ARRAY(16, int16_t, input_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, output_block, kNumCoeffs);
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j)
input_block[j] = rnd.Rand8() - rnd.Rand8();
fwd_txfm_ref(input_block, output_ref_block, pitch_, tx_type_);
REGISTER_STATE_CHECK(RunFwdTxfm(input_block, output_block, pitch_));
// The minimum quant value is 4.
for (int j = 0; j < kNumCoeffs; ++j)
EXPECT_EQ(output_block[j], output_ref_block[j]);
}
}
void RunMemCheck() {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 5000;
DECLARE_ALIGNED_ARRAY(16, int16_t, input_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, input_extreme_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, output_block, kNumCoeffs);
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) {
input_block[j] = rnd.Rand8() - rnd.Rand8();
input_extreme_block[j] = rnd.Rand8() % 2 ? 255 : -255;
}
if (i == 0) {
for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = 255;
} else if (i == 1) {
for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = -255;
}
fwd_txfm_ref(input_extreme_block, output_ref_block, pitch_, tx_type_);
REGISTER_STATE_CHECK(RunFwdTxfm(input_extreme_block,
output_block, pitch_));
// The minimum quant value is 4.
for (int j = 0; j < kNumCoeffs; ++j) {
EXPECT_EQ(output_block[j], output_ref_block[j]);
EXPECT_GE(4 * DCT_MAX_VALUE, abs(output_block[j]))
<< "Error: 16x16 FDCT has coefficient larger than 4*DCT_MAX_VALUE";
}
}
}
void RunInvAccuracyCheck(int limit) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 1000;
DECLARE_ALIGNED_ARRAY(16, int16_t, in, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, int16_t, coeff, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) {
src[j] = rnd.Rand8();
dst[j] = rnd.Rand8();
in[j] = src[j] - dst[j];
}
fwd_txfm_ref(in, coeff, pitch_, tx_type_);
REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
for (int j = 0; j < kNumCoeffs; ++j) {
const uint32_t diff = dst[j] - src[j];
const uint32_t error = diff * diff;
EXPECT_GE(static_cast<uint32_t>(limit), error)
<< "Error: 4x4 IDCT has error " << error
<< " at index " << j;
}
}
}
int pitch_;
int tx_type_;
fht_t fwd_txfm_ref;
};
class Trans4x4DCT class Trans4x4DCT
: public libvpx_test::TransformTestBase, : public Trans4x4TestBase,
public ::testing::TestWithParam<Dct4x4Param> { public ::testing::TestWithParam<dct_4x4_param_t> {
public: public:
virtual ~Trans4x4DCT() {} virtual ~Trans4x4DCT() {}
@@ -103,22 +204,19 @@ class Trans4x4DCT
tx_type_ = GET_PARAM(2); tx_type_ = GET_PARAM(2);
pitch_ = 4; pitch_ = 4;
fwd_txfm_ref = fdct4x4_ref; fwd_txfm_ref = fdct4x4_ref;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
num_coeffs_ = GET_PARAM(4);
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected: protected:
void RunFwdTxfm(const int16_t *in, tran_low_t *out, int stride) { void RunFwdTxfm(const int16_t *in, int16_t *out, int stride) {
fwd_txfm_(in, out, stride); fwd_txfm_(in, out, stride);
} }
void RunInvTxfm(const tran_low_t *out, uint8_t *dst, int stride) { void RunInvTxfm(const int16_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride); inv_txfm_(out, dst, stride);
} }
FdctFunc fwd_txfm_; fdct_t fwd_txfm_;
IdctFunc inv_txfm_; idct_t inv_txfm_;
}; };
TEST_P(Trans4x4DCT, AccuracyCheck) { TEST_P(Trans4x4DCT, AccuracyCheck) {
@@ -138,8 +236,8 @@ TEST_P(Trans4x4DCT, InvAccuracyCheck) {
} }
class Trans4x4HT class Trans4x4HT
: public libvpx_test::TransformTestBase, : public Trans4x4TestBase,
public ::testing::TestWithParam<Ht4x4Param> { public ::testing::TestWithParam<ht_4x4_param_t> {
public: public:
virtual ~Trans4x4HT() {} virtual ~Trans4x4HT() {}
@@ -149,23 +247,20 @@ class Trans4x4HT
tx_type_ = GET_PARAM(2); tx_type_ = GET_PARAM(2);
pitch_ = 4; pitch_ = 4;
fwd_txfm_ref = fht4x4_ref; fwd_txfm_ref = fht4x4_ref;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
num_coeffs_ = GET_PARAM(4);
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected: protected:
void RunFwdTxfm(const int16_t *in, tran_low_t *out, int stride) { void RunFwdTxfm(const int16_t *in, int16_t *out, int stride) {
fwd_txfm_(in, out, stride, tx_type_); fwd_txfm_(in, out, stride, tx_type_);
} }
void RunInvTxfm(const tran_low_t *out, uint8_t *dst, int stride) { void RunInvTxfm(const int16_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride, tx_type_); inv_txfm_(out, dst, stride, tx_type_);
} }
FhtFunc fwd_txfm_; fht_t fwd_txfm_;
IhtFunc inv_txfm_; iht_t inv_txfm_;
}; };
TEST_P(Trans4x4HT, AccuracyCheck) { TEST_P(Trans4x4HT, AccuracyCheck) {
@@ -185,8 +280,8 @@ TEST_P(Trans4x4HT, InvAccuracyCheck) {
} }
class Trans4x4WHT class Trans4x4WHT
: public libvpx_test::TransformTestBase, : public Trans4x4TestBase,
public ::testing::TestWithParam<Dct4x4Param> { public ::testing::TestWithParam<dct_4x4_param_t> {
public: public:
virtual ~Trans4x4WHT() {} virtual ~Trans4x4WHT() {}
@@ -196,22 +291,19 @@ class Trans4x4WHT
tx_type_ = GET_PARAM(2); tx_type_ = GET_PARAM(2);
pitch_ = 4; pitch_ = 4;
fwd_txfm_ref = fwht4x4_ref; fwd_txfm_ref = fwht4x4_ref;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
num_coeffs_ = GET_PARAM(4);
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected: protected:
void RunFwdTxfm(const int16_t *in, tran_low_t *out, int stride) { void RunFwdTxfm(const int16_t *in, int16_t *out, int stride) {
fwd_txfm_(in, out, stride); fwd_txfm_(in, out, stride);
} }
void RunInvTxfm(const tran_low_t *out, uint8_t *dst, int stride) { void RunInvTxfm(const int16_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride); inv_txfm_(out, dst, stride);
} }
FdctFunc fwd_txfm_; fdct_t fwd_txfm_;
IdctFunc inv_txfm_; idct_t inv_txfm_;
}; };
TEST_P(Trans4x4WHT, AccuracyCheck) { TEST_P(Trans4x4WHT, AccuracyCheck) {
@@ -231,155 +323,57 @@ TEST_P(Trans4x4WHT, InvAccuracyCheck) {
} }
using std::tr1::make_tuple; using std::tr1::make_tuple;
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, Trans4x4DCT, C, Trans4x4DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_highbd_fdct4x4_c, &idct4x4_10, 0, VPX_BITS_10, 16), make_tuple(&vp9_fdct4x4_c, &vp9_idct4x4_16_add_c, 0)));
make_tuple(&vpx_highbd_fdct4x4_c, &idct4x4_12, 0, VPX_BITS_12, 16),
make_tuple(&vpx_fdct4x4_c, &vpx_idct4x4_16_add_c, 0, VPX_BITS_8, 16)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans4x4DCT,
::testing::Values(
make_tuple(&vpx_fdct4x4_c, &vpx_idct4x4_16_add_c, 0, VPX_BITS_8, 16)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, Trans4x4HT, C, Trans4x4HT,
::testing::Values( ::testing::Values(
make_tuple(&vp10_highbd_fht4x4_c, &iht4x4_10, 0, VPX_BITS_10, 16), make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 0),
make_tuple(&vp10_highbd_fht4x4_c, &iht4x4_10, 1, VPX_BITS_10, 16), make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 1),
make_tuple(&vp10_highbd_fht4x4_c, &iht4x4_10, 2, VPX_BITS_10, 16), make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 2),
make_tuple(&vp10_highbd_fht4x4_c, &iht4x4_10, 3, VPX_BITS_10, 16), make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 3)));
make_tuple(&vp10_highbd_fht4x4_c, &iht4x4_12, 0, VPX_BITS_12, 16),
make_tuple(&vp10_highbd_fht4x4_c, &iht4x4_12, 1, VPX_BITS_12, 16),
make_tuple(&vp10_highbd_fht4x4_c, &iht4x4_12, 2, VPX_BITS_12, 16),
make_tuple(&vp10_highbd_fht4x4_c, &iht4x4_12, 3, VPX_BITS_12, 16),
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_c, 0, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_c, 1, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_c, 2, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_c, 3, VPX_BITS_8, 16)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans4x4HT,
::testing::Values(
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_c, 0, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_c, 1, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_c, 2, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_c, 3, VPX_BITS_8, 16)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, Trans4x4WHT, C, Trans4x4WHT,
::testing::Values( ::testing::Values(
make_tuple(&vp10_highbd_fwht4x4_c, &iwht4x4_10, 0, VPX_BITS_10, 16), make_tuple(&vp9_fwht4x4_c, &vp9_iwht4x4_16_add_c, 0)));
make_tuple(&vp10_highbd_fwht4x4_c, &iwht4x4_12, 0, VPX_BITS_12, 16),
make_tuple(&vp10_fwht4x4_c, &vpx_iwht4x4_16_add_c, 0, VPX_BITS_8, 16)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans4x4WHT,
::testing::Values(
make_tuple(&vp10_fwht4x4_c, &vpx_iwht4x4_16_add_c, 0, VPX_BITS_8, 16)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#if HAVE_NEON_ASM && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_NEON_ASM
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
NEON, Trans4x4DCT, NEON, Trans4x4DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct4x4_c, make_tuple(&vp9_fdct4x4_c,
&vpx_idct4x4_16_add_neon, 0, VPX_BITS_8, 16))); &vp9_idct4x4_16_add_neon, 0)));
#endif // HAVE_NEON_ASM && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_NEON && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
NEON, Trans4x4HT, DISABLED_NEON, Trans4x4HT,
::testing::Values( ::testing::Values(
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_neon, make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_neon, 0),
0, VPX_BITS_8, 16), make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_neon, 1),
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_neon, make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_neon, 2),
1, VPX_BITS_8, 16), make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_neon, 3)));
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_neon,
2, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_c, &vp10_iht4x4_16_add_neon,
3, VPX_BITS_8, 16)));
#endif // HAVE_NEON && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4WHT,
::testing::Values(
make_tuple(&vp10_fwht4x4_c, &vpx_iwht4x4_16_add_c,
0, VPX_BITS_8, 16),
make_tuple(&vp10_fwht4x4_c, &vpx_iwht4x4_16_add_sse2,
0, VPX_BITS_8, 16)));
#endif #endif
#if HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if CONFIG_USE_X86INC && HAVE_MMX
INSTANTIATE_TEST_CASE_P(
MMX, Trans4x4WHT,
::testing::Values(
make_tuple(&vp9_fwht4x4_mmx, &vp9_iwht4x4_16_add_c, 0)));
#endif
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4DCT, SSE2, Trans4x4DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct4x4_sse2, make_tuple(&vp9_fdct4x4_sse2,
&vpx_idct4x4_16_add_sse2, 0, VPX_BITS_8, 16))); &vp9_idct4x4_16_add_sse2, 0)));
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4HT, SSE2, Trans4x4HT,
::testing::Values( ::testing::Values(
make_tuple(&vp10_fht4x4_sse2, &vp10_iht4x4_16_add_sse2, 0, make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 0),
VPX_BITS_8, 16), make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 1),
make_tuple(&vp10_fht4x4_sse2, &vp10_iht4x4_16_add_sse2, 1, make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 2),
VPX_BITS_8, 16), make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 3)));
make_tuple(&vp10_fht4x4_sse2, &vp10_iht4x4_16_add_sse2, 2, #endif
VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_sse2, &vp10_iht4x4_16_add_sse2, 3,
VPX_BITS_8, 16)));
#endif // HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4DCT,
::testing::Values(
make_tuple(&vpx_highbd_fdct4x4_c, &idct4x4_10_sse2, 0,
VPX_BITS_10, 16),
make_tuple(&vpx_highbd_fdct4x4_sse2, &idct4x4_10_sse2, 0,
VPX_BITS_10, 16),
make_tuple(&vpx_highbd_fdct4x4_c, &idct4x4_12_sse2, 0,
VPX_BITS_12, 16),
make_tuple(&vpx_highbd_fdct4x4_sse2, &idct4x4_12_sse2, 0,
VPX_BITS_12, 16),
make_tuple(&vpx_fdct4x4_sse2, &vpx_idct4x4_16_add_c, 0,
VPX_BITS_8, 16)));
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4HT,
::testing::Values(
make_tuple(&vp10_fht4x4_sse2, &vp10_iht4x4_16_add_c,
0, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_sse2, &vp10_iht4x4_16_add_c,
1, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_sse2, &vp10_iht4x4_16_add_c,
2, VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_sse2, &vp10_iht4x4_16_add_c,
3, VPX_BITS_8, 16)));
#endif // HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
MSA, Trans4x4DCT,
::testing::Values(
make_tuple(&vpx_fdct4x4_msa, &vpx_idct4x4_16_add_msa, 0,
VPX_BITS_8, 16)));
INSTANTIATE_TEST_CASE_P(
MSA, Trans4x4HT,
::testing::Values(
make_tuple(&vp10_fht4x4_msa, &vp10_iht4x4_16_add_msa, 0,
VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_msa, &vp10_iht4x4_16_add_msa, 1,
VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_msa, &vp10_iht4x4_16_add_msa, 2,
VPX_BITS_8, 16),
make_tuple(&vp10_fht4x4_msa, &vp10_iht4x4_16_add_msa, 3,
VPX_BITS_8, 16)));
#endif // HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace } // namespace

View File

@@ -13,141 +13,52 @@
#include <string.h> #include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vp10_rtcd.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h" #include "test/acm_random.h"
#include "test/clear_system_state.h" #include "test/clear_system_state.h"
#include "test/register_state_check.h" #include "test/register_state_check.h"
#include "test/util.h" #include "test/util.h"
#include "vp10/common/entropy.h"
#include "vp10/common/scan.h" #include "./vp9_rtcd.h"
#include "vpx/vpx_codec.h" #include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_integer.h" #include "vpx/vpx_integer.h"
#include "vpx_ports/mem.h"
extern "C" {
void vp9_idct8x8_64_add_c(const int16_t *input, uint8_t *output, int pitch);
}
using libvpx_test::ACMRandom; using libvpx_test::ACMRandom;
namespace { namespace {
typedef void (*fdct_t)(const int16_t *in, int16_t *out, int stride);
const int kNumCoeffs = 64; typedef void (*idct_t)(const int16_t *in, uint8_t *out, int stride);
const double kPi = 3.141592653589793238462643383279502884; typedef void (*fht_t) (const int16_t *in, int16_t *out, int stride,
const int kSignBiasMaxDiff255 = 1500;
const int kSignBiasMaxDiff15 = 10000;
typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride);
typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride);
typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride,
int tx_type); int tx_type);
typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, typedef void (*iht_t) (const int16_t *in, uint8_t *out, int stride,
int tx_type); int tx_type);
typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct8x8Param; typedef std::tr1::tuple<fdct_t, idct_t, int> dct_8x8_param_t;
typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht8x8Param; typedef std::tr1::tuple<fht_t, iht_t, int> ht_8x8_param_t;
typedef std::tr1::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t> Idct8x8Param;
void reference_8x8_dct_1d(const double in[8], double out[8]) { void fdct8x8_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
const double kInvSqrt2 = 0.707106781186547524400844362104; vp9_fdct8x8_c(in, out, stride);
for (int k = 0; k < 8; k++) {
out[k] = 0.0;
for (int n = 0; n < 8; n++)
out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 16.0);
if (k == 0)
out[k] = out[k] * kInvSqrt2;
}
} }
void reference_8x8_dct_2d(const int16_t input[kNumCoeffs], void fht8x8_ref(const int16_t *in, int16_t *out, int stride, int tx_type) {
double output[kNumCoeffs]) { vp9_fht8x8_c(in, out, stride, tx_type);
// First transform columns
for (int i = 0; i < 8; ++i) {
double temp_in[8], temp_out[8];
for (int j = 0; j < 8; ++j)
temp_in[j] = input[j*8 + i];
reference_8x8_dct_1d(temp_in, temp_out);
for (int j = 0; j < 8; ++j)
output[j * 8 + i] = temp_out[j];
}
// Then transform rows
for (int i = 0; i < 8; ++i) {
double temp_in[8], temp_out[8];
for (int j = 0; j < 8; ++j)
temp_in[j] = output[j + i*8];
reference_8x8_dct_1d(temp_in, temp_out);
// Scale by some magic number
for (int j = 0; j < 8; ++j)
output[j + i * 8] = temp_out[j] * 2;
}
} }
void fdct8x8_ref(const int16_t *in, tran_low_t *out, int stride,
int /*tx_type*/) {
vpx_fdct8x8_c(in, out, stride);
}
void fht8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) {
vp10_fht8x8_c(in, out, stride, tx_type);
}
#if CONFIG_VPX_HIGHBITDEPTH
void idct8x8_10(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_64_add_c(in, out, stride, 10);
}
void idct8x8_12(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_64_add_c(in, out, stride, 12);
}
void iht8x8_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp10_highbd_iht8x8_64_add_c(in, out, stride, tx_type, 10);
}
void iht8x8_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp10_highbd_iht8x8_64_add_c(in, out, stride, tx_type, 12);
}
#if HAVE_SSE2
void idct8x8_10_add_10_c(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_10_add_c(in, out, stride, 10);
}
void idct8x8_10_add_12_c(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_10_add_c(in, out, stride, 12);
}
void idct8x8_10_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_10_add_sse2(in, out, stride, 10);
}
void idct8x8_10_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_10_add_sse2(in, out, stride, 12);
}
void idct8x8_64_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_64_add_sse2(in, out, stride, 10);
}
void idct8x8_64_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_64_add_sse2(in, out, stride, 12);
}
#endif // HAVE_SSE2
#endif // CONFIG_VPX_HIGHBITDEPTH
class FwdTrans8x8TestBase { class FwdTrans8x8TestBase {
public: public:
virtual ~FwdTrans8x8TestBase() {} virtual ~FwdTrans8x8TestBase() {}
protected: protected:
virtual void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) = 0; virtual void RunFwdTxfm(int16_t *in, int16_t *out, int stride) = 0;
virtual void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) = 0; virtual void RunInvTxfm(int16_t *out, uint8_t *dst, int stride) = 0;
void RunSignBiasCheck() { void RunSignBiasCheck() {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED(16, int16_t, test_input_block[64]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64);
DECLARE_ALIGNED(16, tran_low_t, test_output_block[64]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_output_block, 64);
int count_sign_block[64][2]; int count_sign_block[64][2];
const int count_test_block = 100000; const int count_test_block = 100000;
@@ -156,9 +67,8 @@ class FwdTrans8x8TestBase {
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-255, 255]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < 64; ++j) for (int j = 0; j < 64; ++j)
test_input_block[j] = ((rnd.Rand16() >> (16 - bit_depth_)) & mask_) - test_input_block[j] = rnd.Rand8() - rnd.Rand8();
((rnd.Rand16() >> (16 - bit_depth_)) & mask_); REGISTER_STATE_CHECK(
ASM_REGISTER_STATE_CHECK(
RunFwdTxfm(test_input_block, test_output_block, pitch_)); RunFwdTxfm(test_input_block, test_output_block, pitch_));
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
@@ -171,8 +81,8 @@ class FwdTrans8x8TestBase {
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]); const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
const int max_diff = kSignBiasMaxDiff255; const int max_diff = 1125;
EXPECT_LT(diff, max_diff << (bit_depth_ - 8)) EXPECT_LT(diff, max_diff)
<< "Error: 8x8 FDCT/FHT has a sign bias > " << "Error: 8x8 FDCT/FHT has a sign bias > "
<< 1. * max_diff / count_test_block * 100 << "%" << 1. * max_diff / count_test_block * 100 << "%"
<< " for input range [-255, 255] at index " << j << " for input range [-255, 255] at index " << j
@@ -184,11 +94,10 @@ class FwdTrans8x8TestBase {
memset(count_sign_block, 0, sizeof(count_sign_block)); memset(count_sign_block, 0, sizeof(count_sign_block));
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_ / 16, mask_ / 16]. // Initialize a test block with input range [-15, 15].
for (int j = 0; j < 64; ++j) for (int j = 0; j < 64; ++j)
test_input_block[j] = ((rnd.Rand16() & mask_) >> 4) - test_input_block[j] = (rnd.Rand8() >> 4) - (rnd.Rand8() >> 4);
((rnd.Rand16() & mask_) >> 4); REGISTER_STATE_CHECK(
ASM_REGISTER_STATE_CHECK(
RunFwdTxfm(test_input_block, test_output_block, pitch_)); RunFwdTxfm(test_input_block, test_output_block, pitch_));
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
@@ -201,9 +110,9 @@ class FwdTrans8x8TestBase {
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]); const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]);
const int max_diff = kSignBiasMaxDiff15; const int max_diff = 10000;
EXPECT_LT(diff, max_diff << (bit_depth_ - 8)) EXPECT_LT(diff, max_diff)
<< "Error: 8x8 FDCT/FHT has a sign bias > " << "Error: 4x4 FDCT/FHT has a sign bias > "
<< 1. * max_diff / count_test_block * 100 << "%" << 1. * max_diff / count_test_block * 100 << "%"
<< " for input range [-15, 15] at index " << j << " for input range [-15, 15] at index " << j
<< " count0: " << count_sign_block[j][0] << " count0: " << count_sign_block[j][0]
@@ -217,32 +126,20 @@ class FwdTrans8x8TestBase {
int max_error = 0; int max_error = 0;
int total_error = 0; int total_error = 0;
const int count_test_block = 100000; const int count_test_block = 100000;
DECLARE_ALIGNED(16, int16_t, test_input_block[64]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64);
DECLARE_ALIGNED(16, tran_low_t, test_temp_block[64]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, 64);
DECLARE_ALIGNED(16, uint8_t, dst[64]); DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, 64);
DECLARE_ALIGNED(16, uint8_t, src[64]); DECLARE_ALIGNED_ARRAY(16, uint8_t, src, 64);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[64]);
DECLARE_ALIGNED(16, uint16_t, src16[64]);
#endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
if (bit_depth_ == VPX_BITS_8) {
src[j] = rnd.Rand8(); src[j] = rnd.Rand8();
dst[j] = rnd.Rand8(); dst[j] = rnd.Rand8();
test_input_block[j] = src[j] - dst[j]; test_input_block[j] = src[j] - dst[j];
#if CONFIG_VPX_HIGHBITDEPTH
} else {
src16[j] = rnd.Rand16() & mask_;
dst16[j] = rnd.Rand16() & mask_;
test_input_block[j] = src16[j] - dst16[j];
#endif
}
} }
ASM_REGISTER_STATE_CHECK( REGISTER_STATE_CHECK(
RunFwdTxfm(test_input_block, test_temp_block, pitch_)); RunFwdTxfm(test_input_block, test_temp_block, pitch_));
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
if (test_temp_block[j] > 0) { if (test_temp_block[j] > 0) {
@@ -255,23 +152,11 @@ class FwdTrans8x8TestBase {
test_temp_block[j] *= 4; test_temp_block[j] *= 4;
} }
} }
if (bit_depth_ == VPX_BITS_8) { REGISTER_STATE_CHECK(
ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, dst, pitch_)); RunInvTxfm(test_temp_block, dst, pitch_));
#if CONFIG_VPX_HIGHBITDEPTH
} else {
ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif
}
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
#if CONFIG_VPX_HIGHBITDEPTH
const int diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
const int diff = dst[j] - src[j]; const int diff = dst[j] - src[j];
#endif
const int error = diff * diff; const int error = diff * diff;
if (max_error < error) if (max_error < error)
max_error = error; max_error = error;
@@ -279,11 +164,11 @@ class FwdTrans8x8TestBase {
} }
} }
EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error) EXPECT_GE(1, max_error)
<< "Error: 8x8 FDCT/IDCT or FHT/IHT has an individual" << "Error: 8x8 FDCT/IDCT or FHT/IHT has an individual"
<< " roundtrip error > 1"; << " roundtrip error > 1";
EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8))/5, total_error) EXPECT_GE(count_test_block/5, total_error)
<< "Error: 8x8 FDCT/IDCT or FHT/IHT has average roundtrip " << "Error: 8x8 FDCT/IDCT or FHT/IHT has average roundtrip "
<< "error > 1/5 per block"; << "error > 1/5 per block";
} }
@@ -294,20 +179,15 @@ class FwdTrans8x8TestBase {
int total_error = 0; int total_error = 0;
int total_coeff_error = 0; int total_coeff_error = 0;
const int count_test_block = 100000; const int count_test_block = 100000;
DECLARE_ALIGNED(16, int16_t, test_input_block[64]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64);
DECLARE_ALIGNED(16, tran_low_t, test_temp_block[64]); DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, 64);
DECLARE_ALIGNED(16, tran_low_t, ref_temp_block[64]); DECLARE_ALIGNED_ARRAY(16, int16_t, ref_temp_block, 64);
DECLARE_ALIGNED(16, uint8_t, dst[64]); DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, 64);
DECLARE_ALIGNED(16, uint8_t, src[64]); DECLARE_ALIGNED_ARRAY(16, uint8_t, src, 64);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[64]);
DECLARE_ALIGNED(16, uint16_t, src16[64]);
#endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_]. // Initialize a test block with input range [-255, 255].
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
if (bit_depth_ == VPX_BITS_8) {
if (i == 0) { if (i == 0) {
src[j] = 255; src[j] = 255;
dst[j] = 0; dst[j] = 0;
@@ -318,45 +198,19 @@ class FwdTrans8x8TestBase {
src[j] = rnd.Rand8() % 2 ? 255 : 0; src[j] = rnd.Rand8() % 2 ? 255 : 0;
dst[j] = rnd.Rand8() % 2 ? 255 : 0; dst[j] = rnd.Rand8() % 2 ? 255 : 0;
} }
test_input_block[j] = src[j] - dst[j]; test_input_block[j] = src[j] - dst[j];
#if CONFIG_VPX_HIGHBITDEPTH
} else {
if (i == 0) {
src16[j] = mask_;
dst16[j] = 0;
} else if (i == 1) {
src16[j] = 0;
dst16[j] = mask_;
} else {
src16[j] = rnd.Rand8() % 2 ? mask_ : 0;
dst16[j] = rnd.Rand8() % 2 ? mask_ : 0;
}
test_input_block[j] = src16[j] - dst16[j];
#endif
}
} }
ASM_REGISTER_STATE_CHECK( REGISTER_STATE_CHECK(
RunFwdTxfm(test_input_block, test_temp_block, pitch_)); RunFwdTxfm(test_input_block, test_temp_block, pitch_));
ASM_REGISTER_STATE_CHECK( REGISTER_STATE_CHECK(
fwd_txfm_ref(test_input_block, ref_temp_block, pitch_, tx_type_)); fwd_txfm_ref(test_input_block, ref_temp_block, pitch_, tx_type_));
if (bit_depth_ == VPX_BITS_8) { REGISTER_STATE_CHECK(
ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, dst, pitch_)); RunInvTxfm(test_temp_block, dst, pitch_));
#if CONFIG_VPX_HIGHBITDEPTH
} else {
ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif
}
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
#if CONFIG_VPX_HIGHBITDEPTH
const int diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
const int diff = dst[j] - src[j]; const int diff = dst[j] - src[j];
#endif
const int error = diff * diff; const int error = diff * diff;
if (max_error < error) if (max_error < error)
max_error = error; max_error = error;
@@ -366,11 +220,11 @@ class FwdTrans8x8TestBase {
total_coeff_error += abs(coeff_diff); total_coeff_error += abs(coeff_diff);
} }
EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error) EXPECT_GE(1, max_error)
<< "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has" << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has"
<< "an individual roundtrip error > 1"; << "an individual roundtrip error > 1";
EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8))/5, total_error) EXPECT_GE(count_test_block/5, total_error)
<< "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has average" << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has average"
<< " roundtrip error > 1/5 per block"; << " roundtrip error > 1/5 per block";
@@ -380,159 +234,14 @@ class FwdTrans8x8TestBase {
} }
} }
void RunInvAccuracyCheck() {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 1000;
DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]);
DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]);
DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
#endif
for (int i = 0; i < count_test_block; ++i) {
double out_r[kNumCoeffs];
// Initialize a test block with input range [-255, 255].
for (int j = 0; j < kNumCoeffs; ++j) {
if (bit_depth_ == VPX_BITS_8) {
src[j] = rnd.Rand8() % 2 ? 255 : 0;
dst[j] = src[j] > 0 ? 0 : 255;
in[j] = src[j] - dst[j];
#if CONFIG_VPX_HIGHBITDEPTH
} else {
src16[j] = rnd.Rand8() % 2 ? mask_ : 0;
dst16[j] = src16[j] > 0 ? 0 : mask_;
in[j] = src16[j] - dst16[j];
#endif
}
}
reference_8x8_dct_2d(in, out_r);
for (int j = 0; j < kNumCoeffs; ++j)
coeff[j] = static_cast<tran_low_t>(round(out_r[j]));
if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
#if CONFIG_VPX_HIGHBITDEPTH
} else {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
pitch_));
#endif
}
for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VPX_HIGHBITDEPTH
const int diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else
const int diff = dst[j] - src[j];
#endif
const uint32_t error = diff * diff;
EXPECT_GE(1u << 2 * (bit_depth_ - 8), error)
<< "Error: 8x8 IDCT has error " << error
<< " at index " << j;
}
}
}
void RunFwdAccuracyCheck() {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 1000;
DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]);
DECLARE_ALIGNED(16, tran_low_t, coeff_r[kNumCoeffs]);
DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
for (int i = 0; i < count_test_block; ++i) {
double out_r[kNumCoeffs];
// Initialize a test block with input range [-mask_, mask_].
for (int j = 0; j < kNumCoeffs; ++j)
in[j] = rnd.Rand8() % 2 == 0 ? mask_ : -mask_;
RunFwdTxfm(in, coeff, pitch_);
reference_8x8_dct_2d(in, out_r);
for (int j = 0; j < kNumCoeffs; ++j)
coeff_r[j] = static_cast<tran_low_t>(round(out_r[j]));
for (int j = 0; j < kNumCoeffs; ++j) {
const int32_t diff = coeff[j] - coeff_r[j];
const uint32_t error = diff * diff;
EXPECT_GE(9u << 2 * (bit_depth_ - 8), error)
<< "Error: 8x8 DCT has error " << error
<< " at index " << j;
}
}
}
void CompareInvReference(IdctFunc ref_txfm, int thresh) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 10000;
const int eob = 12;
DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]);
DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]);
DECLARE_ALIGNED(16, uint8_t, ref[kNumCoeffs]);
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, ref16[kNumCoeffs]);
#endif
const int16_t *scan = vp10_default_scan_orders[TX_8X8].scan;
for (int i = 0; i < count_test_block; ++i) {
for (int j = 0; j < kNumCoeffs; ++j) {
if (j < eob) {
// Random values less than the threshold, either positive or negative
coeff[scan[j]] = rnd(thresh) * (1-2*(i%2));
} else {
coeff[scan[j]] = 0;
}
if (bit_depth_ == VPX_BITS_8) {
dst[j] = 0;
ref[j] = 0;
#if CONFIG_VPX_HIGHBITDEPTH
} else {
dst16[j] = 0;
ref16[j] = 0;
#endif
}
}
if (bit_depth_ == VPX_BITS_8) {
ref_txfm(coeff, ref, pitch_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
#if CONFIG_VPX_HIGHBITDEPTH
} else {
ref_txfm(coeff, CONVERT_TO_BYTEPTR(ref16), pitch_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
pitch_));
#endif
}
for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VPX_HIGHBITDEPTH
const int diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - ref[j] : dst16[j] - ref16[j];
#else
const int diff = dst[j] - ref[j];
#endif
const uint32_t error = diff * diff;
EXPECT_EQ(0u, error)
<< "Error: 8x8 IDCT has error " << error
<< " at index " << j;
}
}
}
int pitch_; int pitch_;
int tx_type_; int tx_type_;
FhtFunc fwd_txfm_ref; fht_t fwd_txfm_ref;
vpx_bit_depth_t bit_depth_;
int mask_;
}; };
class FwdTrans8x8DCT class FwdTrans8x8DCT
: public FwdTrans8x8TestBase, : public FwdTrans8x8TestBase,
public ::testing::TestWithParam<Dct8x8Param> { public ::testing::TestWithParam<dct_8x8_param_t> {
public: public:
virtual ~FwdTrans8x8DCT() {} virtual ~FwdTrans8x8DCT() {}
@@ -542,22 +251,20 @@ class FwdTrans8x8DCT
tx_type_ = GET_PARAM(2); tx_type_ = GET_PARAM(2);
pitch_ = 8; pitch_ = 8;
fwd_txfm_ref = fdct8x8_ref; fwd_txfm_ref = fdct8x8_ref;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected: protected:
void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) { void RunFwdTxfm(int16_t *in, int16_t *out, int stride) {
fwd_txfm_(in, out, stride); fwd_txfm_(in, out, stride);
} }
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { void RunInvTxfm(int16_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride); inv_txfm_(out, dst, stride);
} }
FdctFunc fwd_txfm_; fdct_t fwd_txfm_;
IdctFunc inv_txfm_; idct_t inv_txfm_;
}; };
TEST_P(FwdTrans8x8DCT, SignBiasCheck) { TEST_P(FwdTrans8x8DCT, SignBiasCheck) {
@@ -572,17 +279,9 @@ TEST_P(FwdTrans8x8DCT, ExtremalCheck) {
RunExtremalCheck(); RunExtremalCheck();
} }
TEST_P(FwdTrans8x8DCT, FwdAccuracyCheck) {
RunFwdAccuracyCheck();
}
TEST_P(FwdTrans8x8DCT, InvAccuracyCheck) {
RunInvAccuracyCheck();
}
class FwdTrans8x8HT class FwdTrans8x8HT
: public FwdTrans8x8TestBase, : public FwdTrans8x8TestBase,
public ::testing::TestWithParam<Ht8x8Param> { public ::testing::TestWithParam<ht_8x8_param_t> {
public: public:
virtual ~FwdTrans8x8HT() {} virtual ~FwdTrans8x8HT() {}
@@ -592,22 +291,20 @@ class FwdTrans8x8HT
tx_type_ = GET_PARAM(2); tx_type_ = GET_PARAM(2);
pitch_ = 8; pitch_ = 8;
fwd_txfm_ref = fht8x8_ref; fwd_txfm_ref = fht8x8_ref;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected: protected:
void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) { void RunFwdTxfm(int16_t *in, int16_t *out, int stride) {
fwd_txfm_(in, out, stride, tx_type_); fwd_txfm_(in, out, stride, tx_type_);
} }
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { void RunInvTxfm(int16_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride, tx_type_); inv_txfm_(out, dst, stride, tx_type_);
} }
FhtFunc fwd_txfm_; fht_t fwd_txfm_;
IhtFunc inv_txfm_; iht_t inv_txfm_;
}; };
TEST_P(FwdTrans8x8HT, SignBiasCheck) { TEST_P(FwdTrans8x8HT, SignBiasCheck) {
@@ -622,174 +319,52 @@ TEST_P(FwdTrans8x8HT, ExtremalCheck) {
RunExtremalCheck(); RunExtremalCheck();
} }
class InvTrans8x8DCT
: public FwdTrans8x8TestBase,
public ::testing::TestWithParam<Idct8x8Param> {
public:
virtual ~InvTrans8x8DCT() {}
virtual void SetUp() {
ref_txfm_ = GET_PARAM(0);
inv_txfm_ = GET_PARAM(1);
thresh_ = GET_PARAM(2);
pitch_ = 8;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride);
}
void RunFwdTxfm(int16_t * /*out*/, tran_low_t * /*dst*/, int /*stride*/) {}
IdctFunc ref_txfm_;
IdctFunc inv_txfm_;
int thresh_;
};
TEST_P(InvTrans8x8DCT, CompareReference) {
CompareInvReference(ref_txfm_, thresh_);
}
using std::tr1::make_tuple; using std::tr1::make_tuple;
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, FwdTrans8x8DCT, C, FwdTrans8x8DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct8x8_c, &vpx_idct8x8_64_add_c, 0, VPX_BITS_8), make_tuple(&vp9_fdct8x8_c, &vp9_idct8x8_64_add_c, 0)));
make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_10, 0, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_12, 0, VPX_BITS_12)));
#else
INSTANTIATE_TEST_CASE_P(
C, FwdTrans8x8DCT,
::testing::Values(
make_tuple(&vpx_fdct8x8_c, &vpx_idct8x8_64_add_c, 0, VPX_BITS_8)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, FwdTrans8x8HT, C, FwdTrans8x8HT,
::testing::Values( ::testing::Values(
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 0, VPX_BITS_8), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 0),
make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_10, 0, VPX_BITS_10), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 1),
make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_10, 1, VPX_BITS_10), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2),
make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_10, 2, VPX_BITS_10), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3)));
make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_10, 3, VPX_BITS_10),
make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_12, 0, VPX_BITS_12),
make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_12, 1, VPX_BITS_12),
make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_12, 2, VPX_BITS_12),
make_tuple(&vp10_highbd_fht8x8_c, &iht8x8_12, 3, VPX_BITS_12),
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 1, VPX_BITS_8),
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 2, VPX_BITS_8),
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 3, VPX_BITS_8)));
#else
INSTANTIATE_TEST_CASE_P(
C, FwdTrans8x8HT,
::testing::Values(
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 0, VPX_BITS_8),
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 1, VPX_BITS_8),
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 2, VPX_BITS_8),
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_c, 3, VPX_BITS_8)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#if HAVE_NEON_ASM && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_NEON_ASM
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
NEON, FwdTrans8x8DCT, NEON, FwdTrans8x8DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct8x8_neon, &vpx_idct8x8_64_add_neon, 0, make_tuple(&vp9_fdct8x8_c, &vp9_idct8x8_64_add_neon, 0)));
VPX_BITS_8)));
#endif // HAVE_NEON_ASM && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_NEON && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
NEON, FwdTrans8x8HT, DISABLED_NEON, FwdTrans8x8HT,
::testing::Values( ::testing::Values(
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_neon, 0, VPX_BITS_8), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 0),
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_neon, 1, VPX_BITS_8), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 1),
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_neon, 2, VPX_BITS_8), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 2),
make_tuple(&vp10_fht8x8_c, &vp10_iht8x8_64_add_neon, 3, VPX_BITS_8))); make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 3)));
#endif // HAVE_NEON && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #endif
#if HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSE2
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, FwdTrans8x8DCT, SSE2, FwdTrans8x8DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct8x8_sse2, &vpx_idct8x8_64_add_sse2, 0, make_tuple(&vp9_fdct8x8_sse2, &vp9_idct8x8_64_add_sse2, 0)));
VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, FwdTrans8x8HT, SSE2, FwdTrans8x8HT,
::testing::Values( ::testing::Values(
make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_sse2, make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 0),
0, VPX_BITS_8), make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 1),
make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_sse2, make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 2),
1, VPX_BITS_8), make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 3)));
make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_sse2, #endif
2, VPX_BITS_8),
make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_sse2,
3, VPX_BITS_8)));
#endif // HAVE_SSE2 && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSSE3 && ARCH_X86_64
INSTANTIATE_TEST_CASE_P(
SSE2, FwdTrans8x8DCT,
::testing::Values(
make_tuple(&vpx_fdct8x8_sse2, &vpx_idct8x8_64_add_c, 0, VPX_BITS_8),
make_tuple(&vpx_highbd_fdct8x8_c,
&idct8x8_64_add_10_sse2, 12, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct8x8_sse2,
&idct8x8_64_add_10_sse2, 12, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct8x8_c,
&idct8x8_64_add_12_sse2, 12, VPX_BITS_12),
make_tuple(&vpx_highbd_fdct8x8_sse2,
&idct8x8_64_add_12_sse2, 12, VPX_BITS_12)));
INSTANTIATE_TEST_CASE_P(
SSE2, FwdTrans8x8HT,
::testing::Values(
make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_c, 0, VPX_BITS_8),
make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_c, 1, VPX_BITS_8),
make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_c, 2, VPX_BITS_8),
make_tuple(&vp10_fht8x8_sse2, &vp10_iht8x8_64_add_c, 3, VPX_BITS_8)));
// Optimizations take effect at a threshold of 6201, so we use a value close to
// that to test both branches.
INSTANTIATE_TEST_CASE_P(
SSE2, InvTrans8x8DCT,
::testing::Values(
make_tuple(&idct8x8_10_add_10_c,
&idct8x8_10_add_10_sse2, 6225, VPX_BITS_10),
make_tuple(&idct8x8_10,
&idct8x8_64_add_10_sse2, 6225, VPX_BITS_10),
make_tuple(&idct8x8_10_add_12_c,
&idct8x8_10_add_12_sse2, 6225, VPX_BITS_12),
make_tuple(&idct8x8_12,
&idct8x8_64_add_12_sse2, 6225, VPX_BITS_12)));
#endif // HAVE_SSE2 && CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSSE3 && ARCH_X86_64 && \
!CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSSE3, FwdTrans8x8DCT, SSSE3, FwdTrans8x8DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_fdct8x8_ssse3, &vpx_idct8x8_64_add_ssse3, 0, make_tuple(&vp9_fdct8x8_ssse3, &vp9_idct8x8_64_add_ssse3, 0)));
VPX_BITS_8)));
#endif #endif
#if HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
MSA, FwdTrans8x8DCT,
::testing::Values(
make_tuple(&vpx_fdct8x8_msa, &vpx_idct8x8_64_add_msa, 0, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
MSA, FwdTrans8x8HT,
::testing::Values(
make_tuple(&vp10_fht8x8_msa, &vp10_iht8x8_64_add_msa, 0, VPX_BITS_8),
make_tuple(&vp10_fht8x8_msa, &vp10_iht8x8_64_add_msa, 1, VPX_BITS_8),
make_tuple(&vp10_fht8x8_msa, &vp10_iht8x8_64_add_msa, 2, VPX_BITS_8),
make_tuple(&vp10_fht8x8_msa, &vp10_iht8x8_64_add_msa, 3, VPX_BITS_8)));
#endif // HAVE_MSA && !CONFIG_VPX_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace } // namespace

View File

@@ -1,96 +0,0 @@
/*
* Copyright (c) 2014 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 "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/video_source.h"
namespace {
class VP9FrameSizeTestsLarge
: public ::libvpx_test::EncoderTest,
public ::testing::Test {
protected:
VP9FrameSizeTestsLarge() : EncoderTest(&::libvpx_test::kVP10),
expected_res_(VPX_CODEC_OK) {}
virtual ~VP9FrameSizeTestsLarge() {}
virtual void SetUp() {
InitializeConfig();
SetMode(::libvpx_test::kRealTime);
}
virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
const libvpx_test::VideoSource& /*video*/,
libvpx_test::Decoder *decoder) {
EXPECT_EQ(expected_res_, res_dec) << decoder->DecodeError();
return !::testing::Test::HasFailure();
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, 7);
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
encoder->Control(VP8E_SET_ARNR_TYPE, 3);
}
}
int expected_res_;
};
TEST_F(VP9FrameSizeTestsLarge, TestInvalidSizes) {
::libvpx_test::RandomVideoSource video;
#if CONFIG_SIZE_LIMIT
video.SetSize(DECODE_WIDTH_LIMIT + 16, DECODE_HEIGHT_LIMIT + 16);
video.set_limit(2);
expected_res_ = VPX_CODEC_CORRUPT_FRAME;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
#endif
}
TEST_F(VP9FrameSizeTestsLarge, ValidSizes) {
::libvpx_test::RandomVideoSource video;
#if CONFIG_SIZE_LIMIT
video.SetSize(DECODE_WIDTH_LIMIT, DECODE_HEIGHT_LIMIT);
video.set_limit(2);
expected_res_ = VPX_CODEC_OK;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
#else
// This test produces a pretty large single frame allocation, (roughly
// 25 megabits). The encoder allocates a good number of these frames
// one for each lag in frames (for 2 pass), and then one for each possible
// reference buffer (8) - we can end up with up to 30 buffers of roughly this
// size or almost 1 gig of memory.
// In total the allocations will exceed 2GiB which may cause a failure with
// mingw + wine, use a smaller size in that case.
#if defined(_WIN32) && !defined(_WIN64) || defined(__OS2__)
video.SetSize(4096, 3072);
#else
video.SetSize(4096, 4096);
#endif
video.set_limit(2);
expected_res_ = VPX_CODEC_OK;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
#endif
}
TEST_F(VP9FrameSizeTestsLarge, OneByOneVideo) {
::libvpx_test::RandomVideoSource video;
video.SetSize(1, 1);
video.set_limit(2);
expected_res_ = VPX_CODEC_OK;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
} // namespace

View File

@@ -1,65 +0,0 @@
/*
* Copyright (c) 2016 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 TEST_FUNCTION_EQUIVALENCE_TEST_H_
#define TEST_FUNCTION_EQUIVALENCE_TEST_H_
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/util.h"
using libvpx_test::ACMRandom;
namespace libvpx_test {
// Base class for tests that compare 2 implementations of the same function
// for equivalence. The template parameter should be pointer to a function
// that is being tested.
//
// The test takes a 3-parameters encapsulating struct 'FuncParam', containing:
// - Pointer to reference function
// - Pointer to tested function
// - Integer bit depth (default to 0).
//
// These values are then accessible in the tests as member of params_:
// params_.ref_func, params_.tst_func, and params_.bit_depth.
//
template <typename T>
struct FuncParam {
FuncParam(T ref = NULL, T tst = NULL, int bit_depth = 0)
: ref_func(ref), tst_func(tst), bit_depth(bit_depth) {}
T ref_func;
T tst_func;
int bit_depth;
};
template <typename T>
class FunctionEquivalenceTest : public ::testing::TestWithParam<FuncParam<T> > {
public:
FunctionEquivalenceTest() : rng_(ACMRandom::DeterministicSeed()) {}
virtual ~FunctionEquivalenceTest() {}
virtual void SetUp() {
params_ = this->GetParam();
}
virtual void TearDown() {
libvpx_test::ClearSystemState();
}
protected:
ACMRandom rng_;
FuncParam<T> params_;
};
} // namespace libvpx_test
#endif // TEST_FUNCTION_EQUIVALENCE_TEST_H_

View File

@@ -1,220 +0,0 @@
/*
* Copyright (c) 2016 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 <algorithm>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h"
#include "test/register_state_check.h"
namespace {
using ::libvpx_test::ACMRandom;
typedef void (*HadamardFunc)(const int16_t *a, int a_stride, int16_t *b);
void hadamard_loop(const int16_t *a, int a_stride, int16_t *out) {
int16_t b[8];
for (int i = 0; i < 8; i += 2) {
b[i + 0] = a[i * a_stride] + a[(i + 1) * a_stride];
b[i + 1] = a[i * a_stride] - a[(i + 1) * a_stride];
}
int16_t c[8];
for (int i = 0; i < 8; i += 4) {
c[i + 0] = b[i + 0] + b[i + 2];
c[i + 1] = b[i + 1] + b[i + 3];
c[i + 2] = b[i + 0] - b[i + 2];
c[i + 3] = b[i + 1] - b[i + 3];
}
out[0] = c[0] + c[4];
out[7] = c[1] + c[5];
out[3] = c[2] + c[6];
out[4] = c[3] + c[7];
out[2] = c[0] - c[4];
out[6] = c[1] - c[5];
out[1] = c[2] - c[6];
out[5] = c[3] - c[7];
}
void reference_hadamard8x8(const int16_t *a, int a_stride, int16_t *b) {
int16_t buf[64];
for (int i = 0; i < 8; ++i) {
hadamard_loop(a + i, a_stride, buf + i * 8);
}
for (int i = 0; i < 8; ++i) {
hadamard_loop(buf + i, 8, b + i * 8);
}
}
void reference_hadamard16x16(const int16_t *a, int a_stride, int16_t *b) {
/* The source is a 16x16 block. The destination is rearranged to 8x32.
* Input is 9 bit. */
reference_hadamard8x8(a + 0 + 0 * a_stride, a_stride, b + 0);
reference_hadamard8x8(a + 8 + 0 * a_stride, a_stride, b + 64);
reference_hadamard8x8(a + 0 + 8 * a_stride, a_stride, b + 128);
reference_hadamard8x8(a + 8 + 8 * a_stride, a_stride, b + 192);
/* Overlay the 8x8 blocks and combine. */
for (int i = 0; i < 64; ++i) {
/* 8x8 steps the range up to 15 bits. */
const int16_t a0 = b[0];
const int16_t a1 = b[64];
const int16_t a2 = b[128];
const int16_t a3 = b[192];
/* Prevent the result from escaping int16_t. */
const int16_t b0 = (a0 + a1) >> 1;
const int16_t b1 = (a0 - a1) >> 1;
const int16_t b2 = (a2 + a3) >> 1;
const int16_t b3 = (a2 - a3) >> 1;
/* Store a 16 bit value. */
b[ 0] = b0 + b2;
b[ 64] = b1 + b3;
b[128] = b0 - b2;
b[192] = b1 - b3;
++b;
}
}
class HadamardTestBase : public ::testing::TestWithParam<HadamardFunc> {
public:
virtual void SetUp() {
h_func_ = GetParam();
rnd_.Reset(ACMRandom::DeterministicSeed());
}
protected:
HadamardFunc h_func_;
ACMRandom rnd_;
};
class Hadamard8x8Test : public HadamardTestBase {};
TEST_P(Hadamard8x8Test, CompareReferenceRandom) {
DECLARE_ALIGNED(16, int16_t, a[64]);
DECLARE_ALIGNED(16, int16_t, b[64]);
int16_t b_ref[64];
for (int i = 0; i < 64; ++i) {
a[i] = rnd_.Rand9Signed();
}
memset(b, 0, sizeof(b));
memset(b_ref, 0, sizeof(b_ref));
reference_hadamard8x8(a, 8, b_ref);
ASM_REGISTER_STATE_CHECK(h_func_(a, 8, b));
// The order of the output is not important. Sort before checking.
std::sort(b, b + 64);
std::sort(b_ref, b_ref + 64);
EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b)));
}
TEST_P(Hadamard8x8Test, VaryStride) {
DECLARE_ALIGNED(16, int16_t, a[64 * 8]);
DECLARE_ALIGNED(16, int16_t, b[64]);
int16_t b_ref[64];
for (int i = 0; i < 64 * 8; ++i) {
a[i] = rnd_.Rand9Signed();
}
for (int i = 8; i < 64; i += 8) {
memset(b, 0, sizeof(b));
memset(b_ref, 0, sizeof(b_ref));
reference_hadamard8x8(a, i, b_ref);
ASM_REGISTER_STATE_CHECK(h_func_(a, i, b));
// The order of the output is not important. Sort before checking.
std::sort(b, b + 64);
std::sort(b_ref, b_ref + 64);
EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b)));
}
}
INSTANTIATE_TEST_CASE_P(C, Hadamard8x8Test,
::testing::Values(&vpx_hadamard_8x8_c));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(SSE2, Hadamard8x8Test,
::testing::Values(&vpx_hadamard_8x8_sse2));
#endif // HAVE_SSE2
#if HAVE_SSSE3 && ARCH_X86_64
INSTANTIATE_TEST_CASE_P(SSSE3, Hadamard8x8Test,
::testing::Values(&vpx_hadamard_8x8_ssse3));
#endif // HAVE_SSSE3 && ARCH_X86_64
#if HAVE_NEON
INSTANTIATE_TEST_CASE_P(NEON, Hadamard8x8Test,
::testing::Values(&vpx_hadamard_8x8_neon));
#endif // HAVE_NEON
class Hadamard16x16Test : public HadamardTestBase {};
TEST_P(Hadamard16x16Test, CompareReferenceRandom) {
DECLARE_ALIGNED(16, int16_t, a[16 * 16]);
DECLARE_ALIGNED(16, int16_t, b[16 * 16]);
int16_t b_ref[16 * 16];
for (int i = 0; i < 16 * 16; ++i) {
a[i] = rnd_.Rand9Signed();
}
memset(b, 0, sizeof(b));
memset(b_ref, 0, sizeof(b_ref));
reference_hadamard16x16(a, 16, b_ref);
ASM_REGISTER_STATE_CHECK(h_func_(a, 16, b));
// The order of the output is not important. Sort before checking.
std::sort(b, b + 16 * 16);
std::sort(b_ref, b_ref + 16 * 16);
EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b)));
}
TEST_P(Hadamard16x16Test, VaryStride) {
DECLARE_ALIGNED(16, int16_t, a[16 * 16 * 8]);
DECLARE_ALIGNED(16, int16_t, b[16 * 16]);
int16_t b_ref[16 * 16];
for (int i = 0; i < 16 * 16 * 8; ++i) {
a[i] = rnd_.Rand9Signed();
}
for (int i = 8; i < 64; i += 8) {
memset(b, 0, sizeof(b));
memset(b_ref, 0, sizeof(b_ref));
reference_hadamard16x16(a, i, b_ref);
ASM_REGISTER_STATE_CHECK(h_func_(a, i, b));
// The order of the output is not important. Sort before checking.
std::sort(b, b + 16 * 16);
std::sort(b_ref, b_ref + 16 * 16);
EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b)));
}
}
INSTANTIATE_TEST_CASE_P(C, Hadamard16x16Test,
::testing::Values(&vpx_hadamard_16x16_c));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(SSE2, Hadamard16x16Test,
::testing::Values(&vpx_hadamard_16x16_sse2));
#endif // HAVE_SSE2
#if HAVE_NEON
INSTANTIATE_TEST_CASE_P(NEON, Hadamard16x16Test,
::testing::Values(&vpx_hadamard_16x16_neon));
#endif // HAVE_NEON
} // namespace

View File

@@ -1,251 +0,0 @@
/*
* Copyright (c) 2016 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 <math.h>
#include <stdlib.h>
#include <new>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/acm_random.h"
#include "test/util.h"
#include "./vpx_config.h"
#include "vpx_dsp/psnr.h"
#include "vpx_dsp/ssim.h"
#include "vpx_ports/mem.h"
#include "vpx_ports/msvc.h"
#include "vpx_scale/yv12config.h"
using libvpx_test::ACMRandom;
namespace {
typedef double (*LBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest);
typedef double (*HBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest,
uint32_t in_bd, uint32_t bd);
double compute_hbd_psnr(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest,
uint32_t in_bd, uint32_t bd) {
PSNR_STATS psnr;
vpx_calc_highbd_psnr(source, dest, &psnr, bd, in_bd);
return psnr.psnr[0];
}
double compute_psnr(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest) {
PSNR_STATS psnr;
vpx_calc_psnr(source, dest, &psnr);
return psnr.psnr[0];
}
double compute_hbd_psnrhvs(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest,
uint32_t in_bd, uint32_t bd) {
double tempy, tempu, tempv;
return vpx_psnrhvs(source, dest,
&tempy, &tempu, &tempv, bd, in_bd);
}
double compute_psnrhvs(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest) {
double tempy, tempu, tempv;
return vpx_psnrhvs(source, dest,
&tempy, &tempu, &tempv, 8, 8);
}
double compute_hbd_fastssim(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest,
uint32_t in_bd, uint32_t bd) {
double tempy, tempu, tempv;
return vpx_calc_fastssim(source, dest,
&tempy, &tempu, &tempv, bd, in_bd);
}
double compute_fastssim(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest) {
double tempy, tempu, tempv;
return vpx_calc_fastssim(source, dest,
&tempy, &tempu, &tempv, 8, 8);
}
double compute_hbd_vpxssim(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest,
uint32_t in_bd, uint32_t bd) {
double ssim, weight;
ssim = vpx_highbd_calc_ssim(source, dest, &weight, bd, in_bd);
return 100 * pow(ssim / weight, 8.0);
}
double compute_vpxssim(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest) {
double ssim, weight;
ssim = vpx_calc_ssim(source, dest, &weight);
return 100 * pow(ssim / weight, 8.0);
}
class HBDMetricsTestBase {
public:
virtual ~HBDMetricsTestBase() {}
protected:
void RunAccuracyCheck() {
const int width = 1920;
const int height = 1080;
int i = 0;
const uint8_t kPixFiller = 128;
YV12_BUFFER_CONFIG lbd_src, lbd_dst;
YV12_BUFFER_CONFIG hbd_src, hbd_dst;
ACMRandom rnd(ACMRandom::DeterministicSeed());
double lbd_db, hbd_db;
memset(&lbd_src, 0, sizeof(lbd_src));
memset(&lbd_dst, 0, sizeof(lbd_dst));
memset(&hbd_src, 0, sizeof(hbd_src));
memset(&hbd_dst, 0, sizeof(hbd_dst));
vpx_alloc_frame_buffer(&lbd_src, width, height, 1, 1, 0, 32, 16);
vpx_alloc_frame_buffer(&lbd_dst, width, height, 1, 1, 0, 32, 16);
vpx_alloc_frame_buffer(&hbd_src, width, height, 1, 1, 1, 32, 16);
vpx_alloc_frame_buffer(&hbd_dst, width, height, 1, 1, 1, 32, 16);
memset(lbd_src.buffer_alloc, kPixFiller, lbd_src.buffer_alloc_sz);
while (i < lbd_src.buffer_alloc_sz) {
uint16_t spel, dpel;
spel = lbd_src.buffer_alloc[i];
// Create some distortion for dst buffer.
dpel = rnd.Rand8();
lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
((uint16_t*)(hbd_src.buffer_alloc))[i] = spel << (bit_depth_ - 8);
((uint16_t*)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
i++;
}
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
i = 0;
while (i < lbd_src.buffer_alloc_sz) {
uint16_t dpel;
// Create some small distortion for dst buffer.
dpel = 120 + (rnd.Rand8() >> 4);
lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
((uint16_t*)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
i++;
}
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
i = 0;
while (i < lbd_src.buffer_alloc_sz) {
uint16_t dpel;
// Create some small distortion for dst buffer.
dpel = 126 + (rnd.Rand8() >> 6);
lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
((uint16_t*)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
i++;
}
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
vpx_free_frame_buffer(&lbd_src);
vpx_free_frame_buffer(&lbd_dst);
vpx_free_frame_buffer(&hbd_src);
vpx_free_frame_buffer(&hbd_dst);
}
int input_bit_depth_;
int bit_depth_;
double threshold_;
LBDMetricFunc lbd_metric_;
HBDMetricFunc hbd_metric_;
};
typedef std::tr1::tuple<LBDMetricFunc,
HBDMetricFunc, int, int, double> MetricTestTParam;
class HBDMetricsTest
: public HBDMetricsTestBase,
public ::testing::TestWithParam<MetricTestTParam> {
public:
virtual void SetUp() {
lbd_metric_ = GET_PARAM(0);
hbd_metric_ = GET_PARAM(1);
input_bit_depth_ = GET_PARAM(2);
bit_depth_ = GET_PARAM(3);
threshold_ = GET_PARAM(4);
}
virtual void TearDown() {}
};
TEST_P(HBDMetricsTest, RunAccuracyCheck) {
RunAccuracyCheck();
}
// Allow small variation due to floating point operations.
static const double kSsim_thresh = 0.001;
// Allow some additional errors accumulated in floating point operations.
static const double kFSsim_thresh = 0.03;
// Allow some extra variation due to rounding error accumulated in dct.
static const double kPhvs_thresh = 0.3;
INSTANTIATE_TEST_CASE_P(
VPXSSIM, HBDMetricsTest,
::testing::Values(
MetricTestTParam(&compute_vpxssim, &compute_hbd_vpxssim, 8, 10,
kSsim_thresh),
MetricTestTParam(&compute_vpxssim, &compute_hbd_vpxssim, 10, 10,
kPhvs_thresh),
MetricTestTParam(&compute_vpxssim, &compute_hbd_vpxssim, 8, 12,
kSsim_thresh),
MetricTestTParam(&compute_vpxssim, &compute_hbd_vpxssim, 12, 12,
kPhvs_thresh)));
INSTANTIATE_TEST_CASE_P(
FASTSSIM, HBDMetricsTest,
::testing::Values(
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 8, 10,
kFSsim_thresh),
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 10, 10,
kFSsim_thresh),
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 8, 12,
kFSsim_thresh),
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 12, 12,
kFSsim_thresh)));
INSTANTIATE_TEST_CASE_P(
PSNRHVS, HBDMetricsTest,
::testing::Values(
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 8, 10,
kPhvs_thresh),
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 10, 10,
kPhvs_thresh),
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 8, 12,
kPhvs_thresh),
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs, 12, 12,
kPhvs_thresh)));
INSTANTIATE_TEST_CASE_P(
PSNR, HBDMetricsTest,
::testing::Values(
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 10,
kPhvs_thresh),
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 10, 10,
kPhvs_thresh),
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 12,
kPhvs_thresh),
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 12, 12,
kPhvs_thresh)));
} // namespace

View File

@@ -13,22 +13,104 @@
#include <cstdlib> #include <cstdlib>
#include <string> #include <string>
#include "test/yuv_video_source.h" #include "test/video_source.h"
namespace libvpx_test { namespace libvpx_test {
// This class extends VideoSource to allow parsing of raw yv12 // This class extends VideoSource to allow parsing of raw yv12
// so that we can do actual file encodes. // so that we can do actual file encodes.
class I420VideoSource : public YUVVideoSource { class I420VideoSource : public VideoSource {
public: public:
I420VideoSource(const std::string &file_name, I420VideoSource(const std::string &file_name,
unsigned int width, unsigned int height, unsigned int width, unsigned int height,
int rate_numerator, int rate_denominator, int rate_numerator, int rate_denominator,
unsigned int start, int limit) unsigned int start, int limit)
: YUVVideoSource(file_name, VPX_IMG_FMT_I420, : file_name_(file_name),
width, height, input_file_(NULL),
rate_numerator, rate_denominator, img_(NULL),
start, limit) {} start_(start),
limit_(limit),
frame_(0),
width_(0),
height_(0),
framerate_numerator_(rate_numerator),
framerate_denominator_(rate_denominator) {
// This initializes raw_sz_, width_, height_ and allocates an img.
SetSize(width, height);
}
virtual ~I420VideoSource() {
vpx_img_free(img_);
if (input_file_)
fclose(input_file_);
}
virtual void Begin() {
if (input_file_)
fclose(input_file_);
input_file_ = OpenTestDataFile(file_name_);
ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: "
<< file_name_;
if (start_) {
fseek(input_file_, static_cast<unsigned>(raw_sz_) * start_, SEEK_SET);
}
frame_ = start_;
FillFrame();
}
virtual void Next() {
++frame_;
FillFrame();
}
virtual vpx_image_t *img() const { return (frame_ < limit_) ? img_ : NULL; }
// Models a stream where Timebase = 1/FPS, so pts == frame.
virtual vpx_codec_pts_t pts() const { return frame_; }
virtual unsigned long duration() const { return 1; }
virtual vpx_rational_t timebase() const {
const vpx_rational_t t = { framerate_denominator_, framerate_numerator_ };
return t;
}
virtual unsigned int frame() const { return frame_; }
virtual unsigned int limit() const { return limit_; }
void SetSize(unsigned int width, unsigned int height) {
if (width != width_ || height != height_) {
vpx_img_free(img_);
img_ = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, width, height, 1);
ASSERT_TRUE(img_ != NULL);
width_ = width;
height_ = height;
raw_sz_ = width * height * 3 / 2;
}
}
virtual void FillFrame() {
ASSERT_TRUE(input_file_ != NULL);
// Read a frame from input_file.
if (fread(img_->img_data, raw_sz_, 1, input_file_) == 0) {
limit_ = frame_;
}
}
protected:
std::string file_name_;
FILE *input_file_;
vpx_image_t *img_;
size_t raw_sz_;
unsigned int start_;
unsigned int limit_;
unsigned int frame_;
unsigned int width_;
unsigned int height_;
int framerate_numerator_;
int framerate_denominator_;
}; };
} // namespace libvpx_test } // namespace libvpx_test

View File

@@ -14,15 +14,24 @@
#include "third_party/googletest/src/include/gtest/gtest.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_dsp_rtcd.h" #include "./vp9_rtcd.h"
#include "test/acm_random.h" #include "test/acm_random.h"
#include "vpx/vpx_integer.h" #include "vpx/vpx_integer.h"
#include "vpx_ports/msvc.h" // for round()
using libvpx_test::ACMRandom; using libvpx_test::ACMRandom;
namespace { namespace {
#ifdef _MSC_VER
static int round(double x) {
if (x < 0)
return static_cast<int>(ceil(x - 0.5));
else
return static_cast<int>(floor(x + 0.5));
}
#endif
void reference_dct_1d(double input[8], double output[8]) { void reference_dct_1d(double input[8], double output[8]) {
const double kPi = 3.141592653589793238462643383279502884; const double kPi = 3.141592653589793238462643383279502884;
const double kInvSqrt2 = 0.707106781186547524400844362104; const double kInvSqrt2 = 0.707106781186547524400844362104;
@@ -59,12 +68,48 @@ void reference_dct_2d(int16_t input[64], double output[64]) {
output[i] *= 2; output[i] *= 2;
} }
void reference_idct_1d(double input[8], double output[8]) {
const double kPi = 3.141592653589793238462643383279502884;
const double kSqrt2 = 1.414213562373095048801688724209698;
for (int k = 0; k < 8; k++) {
output[k] = 0.0;
for (int n = 0; n < 8; n++) {
output[k] += input[n]*cos(kPi*(2*k+1)*n/16.0);
if (n == 0)
output[k] = output[k]/kSqrt2;
}
}
}
void reference_idct_2d(double input[64], int16_t output[64]) {
double out[64], out2[64];
// First transform rows
for (int i = 0; i < 8; ++i) {
double temp_in[8], temp_out[8];
for (int j = 0; j < 8; ++j)
temp_in[j] = input[j + i*8];
reference_idct_1d(temp_in, temp_out);
for (int j = 0; j < 8; ++j)
out[j + i*8] = temp_out[j];
}
// Then transform columns
for (int i = 0; i < 8; ++i) {
double temp_in[8], temp_out[8];
for (int j = 0; j < 8; ++j)
temp_in[j] = out[j*8 + i];
reference_idct_1d(temp_in, temp_out);
for (int j = 0; j < 8; ++j)
out2[j*8 + i] = temp_out[j];
}
for (int i = 0; i < 64; ++i)
output[i] = round(out2[i]/32);
}
TEST(VP9Idct8x8Test, AccuracyCheck) { TEST(VP9Idct8x8Test, AccuracyCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 10000; const int count_test_block = 10000;
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
int16_t input[64]; int16_t input[64], coeff[64];
tran_low_t coeff[64];
double output_r[64]; double output_r[64];
uint8_t dst[64], src[64]; uint8_t dst[64], src[64];
@@ -78,8 +123,8 @@ TEST(VP9Idct8x8Test, AccuracyCheck) {
reference_dct_2d(input, output_r); reference_dct_2d(input, output_r);
for (int j = 0; j < 64; ++j) for (int j = 0; j < 64; ++j)
coeff[j] = static_cast<tran_low_t>(round(output_r[j])); coeff[j] = round(output_r[j]);
vpx_idct8x8_64_add_c(coeff, dst, 8); vp9_idct8x8_64_add_c(coeff, dst, 8);
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j) {
const int diff = dst[j] - src[j]; const int diff = dst[j] - src[j];
const int error = diff * diff; const int error = diff * diff;

View File

@@ -9,18 +9,18 @@
*/ */
#include "./vpx_config.h" #include "./vpx_config.h"
#include "./vp8_rtcd.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/clear_system_state.h" #include "test/clear_system_state.h"
#include "test/register_state_check.h" #include "test/register_state_check.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "vpx/vpx_integer.h" #include "vpx/vpx_integer.h"
typedef void (*IdctFunc)(int16_t *input, unsigned char *pred_ptr, typedef void (*idct_fn_t)(int16_t *input, unsigned char *pred_ptr,
int pred_stride, unsigned char *dst_ptr, int pred_stride, unsigned char *dst_ptr,
int dst_stride); int dst_stride);
namespace { namespace {
class IDCTTest : public ::testing::TestWithParam<IdctFunc> { class IDCTTest : public ::testing::TestWithParam<idct_fn_t> {
protected: protected:
virtual void SetUp() { virtual void SetUp() {
int i; int i;
@@ -33,7 +33,7 @@ class IDCTTest : public ::testing::TestWithParam<IdctFunc> {
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() { libvpx_test::ClearSystemState(); }
IdctFunc UUT; idct_fn_t UUT;
int16_t input[16]; int16_t input[16];
unsigned char output[256]; unsigned char output[256];
unsigned char predict[256]; unsigned char predict[256];
@@ -52,7 +52,7 @@ TEST_P(IDCTTest, TestGuardBlocks) {
TEST_P(IDCTTest, TestAllZeros) { TEST_P(IDCTTest, TestAllZeros) {
int i; int i;
ASM_REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16)); REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16));
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if ((i & 0xF) < 4 && i < 64) if ((i & 0xF) < 4 && i < 64)
@@ -65,7 +65,7 @@ TEST_P(IDCTTest, TestAllOnes) {
int i; int i;
input[0] = 4; input[0] = 4;
ASM_REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16)); REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16));
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if ((i & 0xF) < 4 && i < 64) if ((i & 0xF) < 4 && i < 64)
@@ -79,7 +79,7 @@ TEST_P(IDCTTest, TestAddOne) {
for (i = 0; i < 256; i++) predict[i] = i; for (i = 0; i < 256; i++) predict[i] = i;
input[0] = 4; input[0] = 4;
ASM_REGISTER_STATE_CHECK(UUT(input, predict, 16, output, 16)); REGISTER_STATE_CHECK(UUT(input, predict, 16, output, 16));
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if ((i & 0xF) < 4 && i < 64) if ((i & 0xF) < 4 && i < 64)
@@ -93,7 +93,7 @@ TEST_P(IDCTTest, TestWithData) {
for (i = 0; i < 16; i++) input[i] = i; for (i = 0; i < 16; i++) input[i] = i;
ASM_REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16)); REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16));
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if ((i & 0xF) > 3 || i > 63) if ((i & 0xF) > 3 || i > 63)
@@ -113,8 +113,4 @@ INSTANTIATE_TEST_CASE_P(C, IDCTTest, ::testing::Values(vp8_short_idct4x4llm_c));
INSTANTIATE_TEST_CASE_P(MMX, IDCTTest, INSTANTIATE_TEST_CASE_P(MMX, IDCTTest,
::testing::Values(vp8_short_idct4x4llm_mmx)); ::testing::Values(vp8_short_idct4x4llm_mmx));
#endif #endif
#if HAVE_MSA
INSTANTIATE_TEST_CASE_P(MSA, IDCTTest,
::testing::Values(vp8_short_idct4x4llm_msa));
#endif
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved. * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
* *
* Use of this source code is governed by a BSD-style license * 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 * that can be found in the LICENSE file in the root of the source
@@ -8,205 +8,379 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h" #include <string.h>
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h" #include "test/acm_random.h"
#include "test/clear_system_state.h" #include "test/clear_system_state.h"
#include "test/register_state_check.h" #include "test/register_state_check.h"
#include "test/util.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "vp10/common/blockd.h"
#include "vp10/common/pred_common.h" #include "./vpx_config.h"
#include "./vp8_rtcd.h"
#include "vp8/common/blockd.h"
#include "vpx_mem/vpx_mem.h" #include "vpx_mem/vpx_mem.h"
namespace { namespace {
using libvpx_test::ACMRandom; using libvpx_test::ACMRandom;
const int count_test_block = 100000; class IntraPredBase {
public:
virtual ~IntraPredBase() { libvpx_test::ClearSystemState(); }
typedef void (*IntraPred)(uint16_t* dst, ptrdiff_t stride, protected:
const uint16_t* above, const uint16_t* left, void SetupMacroblock(MACROBLOCKD *mbptr,
int bps); MODE_INFO *miptr,
uint8_t *data,
int block_size,
int stride,
int num_planes) {
mbptr_ = mbptr;
miptr_ = miptr;
mbptr_->up_available = 1;
mbptr_->left_available = 1;
mbptr_->mode_info_context = miptr_;
stride_ = stride;
block_size_ = block_size;
num_planes_ = num_planes;
for (int p = 0; p < num_planes; p++)
data_ptr_[p] = data + stride * (block_size + 1) * p +
stride + block_size;
}
struct IntraPredFunc { void FillRandom() {
IntraPredFunc(IntraPred pred = NULL, IntraPred ref = NULL, // Fill edges with random data
int block_size_value = 0, int bit_depth_value = 0) ACMRandom rnd(ACMRandom::DeterministicSeed());
: pred_fn(pred), ref_fn(ref), for (int p = 0; p < num_planes_; p++) {
block_size(block_size_value), bit_depth(bit_depth_value) {} for (int x = -1 ; x <= block_size_; x++)
data_ptr_[p][x - stride_] = rnd.Rand8();
for (int y = 0; y < block_size_; y++)
data_ptr_[p][y * stride_ - 1] = rnd.Rand8();
}
}
IntraPred pred_fn; virtual void Predict(MB_PREDICTION_MODE mode) = 0;
IntraPred ref_fn;
int block_size; void SetLeftUnavailable() {
int bit_depth; mbptr_->left_available = 0;
for (int p = 0; p < num_planes_; p++)
for (int i = -1; i < block_size_; ++i)
data_ptr_[p][stride_ * i - 1] = 129;
}
void SetTopUnavailable() {
mbptr_->up_available = 0;
for (int p = 0; p < num_planes_; p++)
memset(&data_ptr_[p][-1 - stride_], 127, block_size_ + 2);
}
void SetTopLeftUnavailable() {
SetLeftUnavailable();
SetTopUnavailable();
}
int BlockSizeLog2Min1() const {
switch (block_size_) {
case 16:
return 3;
case 8:
return 2;
default:
return 0;
}
}
// check DC prediction output against a reference
void CheckDCPrediction() const {
for (int p = 0; p < num_planes_; p++) {
// calculate expected DC
int expected;
if (mbptr_->up_available || mbptr_->left_available) {
int sum = 0, shift = BlockSizeLog2Min1() + mbptr_->up_available +
mbptr_->left_available;
if (mbptr_->up_available)
for (int x = 0; x < block_size_; x++)
sum += data_ptr_[p][x - stride_];
if (mbptr_->left_available)
for (int y = 0; y < block_size_; y++)
sum += data_ptr_[p][y * stride_ - 1];
expected = (sum + (1 << (shift - 1))) >> shift;
} else {
expected = 0x80;
}
// check that all subsequent lines are equal to the first
for (int y = 1; y < block_size_; ++y)
ASSERT_EQ(0, memcmp(data_ptr_[p], &data_ptr_[p][y * stride_],
block_size_));
// within the first line, ensure that each pixel has the same value
for (int x = 1; x < block_size_; ++x)
ASSERT_EQ(data_ptr_[p][0], data_ptr_[p][x]);
// now ensure that that pixel has the expected (DC) value
ASSERT_EQ(expected, data_ptr_[p][0]);
}
}
// check V prediction output against a reference
void CheckVPrediction() const {
// check that all lines equal the top border
for (int p = 0; p < num_planes_; p++)
for (int y = 0; y < block_size_; y++)
ASSERT_EQ(0, memcmp(&data_ptr_[p][-stride_],
&data_ptr_[p][y * stride_], block_size_));
}
// check H prediction output against a reference
void CheckHPrediction() const {
// for each line, ensure that each pixel is equal to the left border
for (int p = 0; p < num_planes_; p++)
for (int y = 0; y < block_size_; y++)
for (int x = 0; x < block_size_; x++)
ASSERT_EQ(data_ptr_[p][-1 + y * stride_],
data_ptr_[p][x + y * stride_]);
}
static int ClipByte(int value) {
if (value > 255)
return 255;
else if (value < 0)
return 0;
return value;
}
// check TM prediction output against a reference
void CheckTMPrediction() const {
for (int p = 0; p < num_planes_; p++)
for (int y = 0; y < block_size_; y++)
for (int x = 0; x < block_size_; x++) {
const int expected = ClipByte(data_ptr_[p][x - stride_]
+ data_ptr_[p][stride_ * y - 1]
- data_ptr_[p][-1 - stride_]);
ASSERT_EQ(expected, data_ptr_[p][y * stride_ + x]);
}
}
// Actual test
void RunTest() {
{
SCOPED_TRACE("DC_PRED");
FillRandom();
Predict(DC_PRED);
CheckDCPrediction();
}
{
SCOPED_TRACE("DC_PRED LEFT");
FillRandom();
SetLeftUnavailable();
Predict(DC_PRED);
CheckDCPrediction();
}
{
SCOPED_TRACE("DC_PRED TOP");
FillRandom();
SetTopUnavailable();
Predict(DC_PRED);
CheckDCPrediction();
}
{
SCOPED_TRACE("DC_PRED TOP_LEFT");
FillRandom();
SetTopLeftUnavailable();
Predict(DC_PRED);
CheckDCPrediction();
}
{
SCOPED_TRACE("H_PRED");
FillRandom();
Predict(H_PRED);
CheckHPrediction();
}
{
SCOPED_TRACE("V_PRED");
FillRandom();
Predict(V_PRED);
CheckVPrediction();
}
{
SCOPED_TRACE("TM_PRED");
FillRandom();
Predict(TM_PRED);
CheckTMPrediction();
}
}
MACROBLOCKD *mbptr_;
MODE_INFO *miptr_;
uint8_t *data_ptr_[2]; // in the case of Y, only [0] is used
int stride_;
int block_size_;
int num_planes_;
}; };
class VP9IntraPredTest : public ::testing::TestWithParam<IntraPredFunc> { typedef void (*intra_pred_y_fn_t)(MACROBLOCKD *x,
uint8_t *yabove_row,
uint8_t *yleft,
int left_stride,
uint8_t *ypred_ptr,
int y_stride);
class IntraPredYTest
: public IntraPredBase,
public ::testing::TestWithParam<intra_pred_y_fn_t> {
public: public:
void RunTest(uint16_t* left_col, uint16_t* above_data, static void SetUpTestCase() {
uint16_t* dst, uint16_t* ref_dst) { mb_ = reinterpret_cast<MACROBLOCKD*>(
ACMRandom rnd(ACMRandom::DeterministicSeed()); vpx_memalign(32, sizeof(MACROBLOCKD)));
const int block_size = params_.block_size; mi_ = reinterpret_cast<MODE_INFO*>(
above_row_ = above_data + 16; vpx_memalign(32, sizeof(MODE_INFO)));
left_col_ = left_col; data_array_ = reinterpret_cast<uint8_t*>(
dst_ = dst; vpx_memalign(kDataAlignment, kDataBufferSize));
ref_dst_ = ref_dst;
int error_count = 0;
for (int i = 0; i < count_test_block; ++i) {
// Fill edges with random data, try first with saturated values.
for (int x = -1; x <= block_size * 2; x++) {
if (i == 0) {
above_row_[x] = mask_;
} else {
above_row_[x] = rnd.Rand16() & mask_;
} }
}
for (int y = 0; y < block_size; y++) { static void TearDownTestCase() {
if (i == 0) { vpx_free(data_array_);
left_col_[y] = mask_; vpx_free(mi_);
} else { vpx_free(mb_);
left_col_[y] = rnd.Rand16() & mask_; data_array_ = NULL;
}
}
Predict();
CheckPrediction(i, &error_count);
}
ASSERT_EQ(0, error_count);
} }
protected: protected:
static const int kBlockSize = 16;
static const int kDataAlignment = 16;
static const int kStride = kBlockSize * 3;
// We use 48 so that the data pointer of the first pixel in each row of
// each macroblock is 16-byte aligned, and this gives us access to the
// top-left and top-right corner pixels belonging to the top-left/right
// macroblocks.
// We use 17 lines so we have one line above us for top-prediction.
static const int kDataBufferSize = kStride * (kBlockSize + 1);
virtual void SetUp() { virtual void SetUp() {
params_ = GetParam(); pred_fn_ = GetParam();
stride_ = params_.block_size * 3; SetupMacroblock(mb_, mi_, data_array_, kBlockSize, kStride, 1);
mask_ = (1 << params_.bit_depth) - 1;
} }
void Predict() { virtual void Predict(MB_PREDICTION_MODE mode) {
const int bit_depth = params_.bit_depth; mbptr_->mode_info_context->mbmi.mode = mode;
params_.ref_fn(ref_dst_, stride_, above_row_, left_col_, bit_depth); REGISTER_STATE_CHECK(pred_fn_(mbptr_,
ASM_REGISTER_STATE_CHECK(params_.pred_fn(dst_, stride_, data_ptr_[0] - kStride,
above_row_, left_col_, bit_depth)); data_ptr_[0] - 1, kStride,
data_ptr_[0], kStride));
} }
void CheckPrediction(int test_case_number, int *error_count) const { intra_pred_y_fn_t pred_fn_;
// For each pixel ensure that the calculated value is the same as reference. static uint8_t* data_array_;
const int block_size = params_.block_size; static MACROBLOCKD * mb_;
for (int y = 0; y < block_size; y++) { static MODE_INFO *mi_;
for (int x = 0; x < block_size; x++) {
*error_count += ref_dst_[x + y * stride_] != dst_[x + y * stride_];
if (*error_count == 1) {
ASSERT_EQ(ref_dst_[x + y * stride_], dst_[x + y * stride_])
<< " Failed on Test Case Number "<< test_case_number;
}
}
}
}
uint16_t *above_row_;
uint16_t *left_col_;
uint16_t *dst_;
uint16_t *ref_dst_;
ptrdiff_t stride_;
int mask_;
IntraPredFunc params_;
}; };
TEST_P(VP9IntraPredTest, IntraPredTests) { MACROBLOCKD* IntraPredYTest::mb_ = NULL;
// max block size is 32 MODE_INFO* IntraPredYTest::mi_ = NULL;
DECLARE_ALIGNED(16, uint16_t, left_col[2*32]); uint8_t* IntraPredYTest::data_array_ = NULL;
DECLARE_ALIGNED(16, uint16_t, above_data[2*32+32]);
DECLARE_ALIGNED(16, uint16_t, dst[3 * 32 * 32]); TEST_P(IntraPredYTest, IntraPredTests) {
DECLARE_ALIGNED(16, uint16_t, ref_dst[3 * 32 * 32]); RunTest();
RunTest(left_col, above_data, dst, ref_dst);
} }
INSTANTIATE_TEST_CASE_P(C, IntraPredYTest,
::testing::Values(
vp8_build_intra_predictors_mby_s_c));
#if HAVE_SSE2 #if HAVE_SSE2
#if CONFIG_VPX_HIGHBITDEPTH INSTANTIATE_TEST_CASE_P(SSE2, IntraPredYTest,
INSTANTIATE_TEST_CASE_P(SSE2_TO_C_8, VP9IntraPredTest,
::testing::Values( ::testing::Values(
IntraPredFunc(&vpx_highbd_dc_predictor_32x32_sse2, vp8_build_intra_predictors_mby_s_sse2));
&vpx_highbd_dc_predictor_32x32_c, 32, 8), #endif
IntraPredFunc(&vpx_highbd_tm_predictor_16x16_sse2, #if HAVE_SSSE3
&vpx_highbd_tm_predictor_16x16_c, 16, 8), INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredYTest,
IntraPredFunc(&vpx_highbd_tm_predictor_32x32_sse2,
&vpx_highbd_tm_predictor_32x32_c, 32, 8),
IntraPredFunc(&vpx_highbd_dc_predictor_4x4_sse2,
&vpx_highbd_dc_predictor_4x4_c, 4, 8),
IntraPredFunc(&vpx_highbd_dc_predictor_8x8_sse2,
&vpx_highbd_dc_predictor_8x8_c, 8, 8),
IntraPredFunc(&vpx_highbd_dc_predictor_16x16_sse2,
&vpx_highbd_dc_predictor_16x16_c, 16, 8),
IntraPredFunc(&vpx_highbd_v_predictor_4x4_sse2,
&vpx_highbd_v_predictor_4x4_c, 4, 8),
IntraPredFunc(&vpx_highbd_v_predictor_8x8_sse2,
&vpx_highbd_v_predictor_8x8_c, 8, 8),
IntraPredFunc(&vpx_highbd_v_predictor_16x16_sse2,
&vpx_highbd_v_predictor_16x16_c, 16, 8),
IntraPredFunc(&vpx_highbd_v_predictor_32x32_sse2,
&vpx_highbd_v_predictor_32x32_c, 32, 8),
IntraPredFunc(&vpx_highbd_tm_predictor_4x4_sse2,
&vpx_highbd_tm_predictor_4x4_c, 4, 8),
IntraPredFunc(&vpx_highbd_tm_predictor_8x8_sse2,
&vpx_highbd_tm_predictor_8x8_c, 8, 8)));
INSTANTIATE_TEST_CASE_P(SSE2_TO_C_10, VP9IntraPredTest,
::testing::Values( ::testing::Values(
IntraPredFunc(&vpx_highbd_dc_predictor_32x32_sse2, vp8_build_intra_predictors_mby_s_ssse3));
&vpx_highbd_dc_predictor_32x32_c, 32, 10), #endif
IntraPredFunc(&vpx_highbd_tm_predictor_16x16_sse2,
&vpx_highbd_tm_predictor_16x16_c, 16, 10),
IntraPredFunc(&vpx_highbd_tm_predictor_32x32_sse2,
&vpx_highbd_tm_predictor_32x32_c, 32, 10),
IntraPredFunc(&vpx_highbd_dc_predictor_4x4_sse2,
&vpx_highbd_dc_predictor_4x4_c, 4, 10),
IntraPredFunc(&vpx_highbd_dc_predictor_8x8_sse2,
&vpx_highbd_dc_predictor_8x8_c, 8, 10),
IntraPredFunc(&vpx_highbd_dc_predictor_16x16_sse2,
&vpx_highbd_dc_predictor_16x16_c, 16, 10),
IntraPredFunc(&vpx_highbd_v_predictor_4x4_sse2,
&vpx_highbd_v_predictor_4x4_c, 4, 10),
IntraPredFunc(&vpx_highbd_v_predictor_8x8_sse2,
&vpx_highbd_v_predictor_8x8_c, 8, 10),
IntraPredFunc(&vpx_highbd_v_predictor_16x16_sse2,
&vpx_highbd_v_predictor_16x16_c, 16, 10),
IntraPredFunc(&vpx_highbd_v_predictor_32x32_sse2,
&vpx_highbd_v_predictor_32x32_c, 32, 10),
IntraPredFunc(&vpx_highbd_tm_predictor_4x4_sse2,
&vpx_highbd_tm_predictor_4x4_c, 4, 10),
IntraPredFunc(&vpx_highbd_tm_predictor_8x8_sse2,
&vpx_highbd_tm_predictor_8x8_c, 8, 10)));
INSTANTIATE_TEST_CASE_P(SSE2_TO_C_12, VP9IntraPredTest, typedef void (*intra_pred_uv_fn_t)(MACROBLOCKD *x,
uint8_t *uabove_row,
uint8_t *vabove_row,
uint8_t *uleft,
uint8_t *vleft,
int left_stride,
uint8_t *upred_ptr,
uint8_t *vpred_ptr,
int pred_stride);
class IntraPredUVTest
: public IntraPredBase,
public ::testing::TestWithParam<intra_pred_uv_fn_t> {
public:
static void SetUpTestCase() {
mb_ = reinterpret_cast<MACROBLOCKD*>(
vpx_memalign(32, sizeof(MACROBLOCKD)));
mi_ = reinterpret_cast<MODE_INFO*>(
vpx_memalign(32, sizeof(MODE_INFO)));
data_array_ = reinterpret_cast<uint8_t*>(
vpx_memalign(kDataAlignment, kDataBufferSize));
}
static void TearDownTestCase() {
vpx_free(data_array_);
vpx_free(mi_);
vpx_free(mb_);
data_array_ = NULL;
}
protected:
static const int kBlockSize = 8;
static const int kDataAlignment = 8;
static const int kStride = kBlockSize * 3;
// We use 24 so that the data pointer of the first pixel in each row of
// each macroblock is 8-byte aligned, and this gives us access to the
// top-left and top-right corner pixels belonging to the top-left/right
// macroblocks.
// We use 9 lines so we have one line above us for top-prediction.
// [0] = U, [1] = V
static const int kDataBufferSize = 2 * kStride * (kBlockSize + 1);
virtual void SetUp() {
pred_fn_ = GetParam();
SetupMacroblock(mb_, mi_, data_array_, kBlockSize, kStride, 2);
}
virtual void Predict(MB_PREDICTION_MODE mode) {
mbptr_->mode_info_context->mbmi.uv_mode = mode;
pred_fn_(mbptr_, data_ptr_[0] - kStride, data_ptr_[1] - kStride,
data_ptr_[0] - 1, data_ptr_[1] - 1, kStride,
data_ptr_[0], data_ptr_[1], kStride);
}
intra_pred_uv_fn_t pred_fn_;
// We use 24 so that the data pointer of the first pixel in each row of
// each macroblock is 8-byte aligned, and this gives us access to the
// top-left and top-right corner pixels belonging to the top-left/right
// macroblocks.
// We use 9 lines so we have one line above us for top-prediction.
// [0] = U, [1] = V
static uint8_t* data_array_;
static MACROBLOCKD* mb_;
static MODE_INFO* mi_;
};
MACROBLOCKD* IntraPredUVTest::mb_ = NULL;
MODE_INFO* IntraPredUVTest::mi_ = NULL;
uint8_t* IntraPredUVTest::data_array_ = NULL;
TEST_P(IntraPredUVTest, IntraPredTests) {
RunTest();
}
INSTANTIATE_TEST_CASE_P(C, IntraPredUVTest,
::testing::Values( ::testing::Values(
IntraPredFunc(&vpx_highbd_dc_predictor_32x32_sse2, vp8_build_intra_predictors_mbuv_s_c));
&vpx_highbd_dc_predictor_32x32_c, 32, 12), #if HAVE_SSE2
IntraPredFunc(&vpx_highbd_tm_predictor_16x16_sse2, INSTANTIATE_TEST_CASE_P(SSE2, IntraPredUVTest,
&vpx_highbd_tm_predictor_16x16_c, 16, 12), ::testing::Values(
IntraPredFunc(&vpx_highbd_tm_predictor_32x32_sse2, vp8_build_intra_predictors_mbuv_s_sse2));
&vpx_highbd_tm_predictor_32x32_c, 32, 12), #endif
IntraPredFunc(&vpx_highbd_dc_predictor_4x4_sse2, #if HAVE_SSSE3
&vpx_highbd_dc_predictor_4x4_c, 4, 12), INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredUVTest,
IntraPredFunc(&vpx_highbd_dc_predictor_8x8_sse2, ::testing::Values(
&vpx_highbd_dc_predictor_8x8_c, 8, 12), vp8_build_intra_predictors_mbuv_s_ssse3));
IntraPredFunc(&vpx_highbd_dc_predictor_16x16_sse2, #endif
&vpx_highbd_dc_predictor_16x16_c, 16, 12),
IntraPredFunc(&vpx_highbd_v_predictor_4x4_sse2,
&vpx_highbd_v_predictor_4x4_c, 4, 12),
IntraPredFunc(&vpx_highbd_v_predictor_8x8_sse2,
&vpx_highbd_v_predictor_8x8_c, 8, 12),
IntraPredFunc(&vpx_highbd_v_predictor_16x16_sse2,
&vpx_highbd_v_predictor_16x16_c, 16, 12),
IntraPredFunc(&vpx_highbd_v_predictor_32x32_sse2,
&vpx_highbd_v_predictor_32x32_c, 32, 12),
IntraPredFunc(&vpx_highbd_tm_predictor_4x4_sse2,
&vpx_highbd_tm_predictor_4x4_c, 4, 12),
IntraPredFunc(&vpx_highbd_tm_predictor_8x8_sse2,
&vpx_highbd_tm_predictor_8x8_c, 8, 12)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#endif // HAVE_SSE2
} // namespace } // namespace

145
test/keyframe_test.cc Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2012 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 <climits>
#include <vector>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/util.h"
namespace {
class KeyframeTest : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected:
KeyframeTest() : EncoderTest(GET_PARAM(0)) {}
virtual ~KeyframeTest() {}
virtual void SetUp() {
InitializeConfig();
SetMode(GET_PARAM(1));
kf_count_ = 0;
kf_count_max_ = INT_MAX;
kf_do_force_kf_ = false;
set_cpu_used_ = 0;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (kf_do_force_kf_)
frame_flags_ = (video->frame() % 3) ? 0 : VPX_EFLAG_FORCE_KF;
if (set_cpu_used_ && video->frame() == 1)
encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
kf_pts_list_.push_back(pkt->data.frame.pts);
kf_count_++;
abort_ |= kf_count_ > kf_count_max_;
}
}
bool kf_do_force_kf_;
int kf_count_;
int kf_count_max_;
std::vector<vpx_codec_pts_t> kf_pts_list_;
int set_cpu_used_;
};
TEST_P(KeyframeTest, TestRandomVideoSource) {
// Validate that encoding the RandomVideoSource produces multiple keyframes.
// This validates the results of the TestDisableKeyframes test.
kf_count_max_ = 2; // early exit successful tests.
::libvpx_test::RandomVideoSource video;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// In realtime mode - auto placed keyframes are exceedingly rare, don't
// bother with this check if(GetParam() > 0)
if (GET_PARAM(1) > 0)
EXPECT_GT(kf_count_, 1);
}
TEST_P(KeyframeTest, TestDisableKeyframes) {
cfg_.kf_mode = VPX_KF_DISABLED;
kf_count_max_ = 1; // early exit failed tests.
::libvpx_test::RandomVideoSource video;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
EXPECT_EQ(1, kf_count_);
}
TEST_P(KeyframeTest, TestForceKeyframe) {
cfg_.kf_mode = VPX_KF_DISABLED;
kf_do_force_kf_ = true;
::libvpx_test::DummyVideoSource video;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// verify that every third frame is a keyframe.
for (std::vector<vpx_codec_pts_t>::const_iterator iter = kf_pts_list_.begin();
iter != kf_pts_list_.end(); ++iter) {
ASSERT_EQ(0, *iter % 3) << "Unexpected keyframe at frame " << *iter;
}
}
TEST_P(KeyframeTest, TestKeyframeMaxDistance) {
cfg_.kf_max_dist = 25;
::libvpx_test::DummyVideoSource video;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// verify that keyframe interval matches kf_max_dist
for (std::vector<vpx_codec_pts_t>::const_iterator iter = kf_pts_list_.begin();
iter != kf_pts_list_.end(); ++iter) {
ASSERT_EQ(0, *iter % 25) << "Unexpected keyframe at frame " << *iter;
}
}
TEST_P(KeyframeTest, TestAutoKeyframe) {
cfg_.kf_mode = VPX_KF_AUTO;
kf_do_force_kf_ = false;
// Force a deterministic speed step in Real Time mode, as the faster modes
// may not produce a keyframe like we expect. This is necessary when running
// on very slow environments (like Valgrind). The step -11 was determined
// experimentally as the fastest mode that still throws the keyframe.
if (deadline_ == VPX_DL_REALTIME)
set_cpu_used_ = -11;
// This clip has a cut scene every 30 frames -> Frame 0, 30, 60, 90, 120.
// I check only the first 40 frames to make sure there's a keyframe at frame
// 0 and 30.
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 40);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// In realtime mode - auto placed keyframes are exceedingly rare, don't
// bother with this check
if (GET_PARAM(1) > 0)
EXPECT_EQ(2u, kf_pts_list_.size()) << " Not the right number of keyframes ";
// Verify that keyframes match the file keyframes in the file.
for (std::vector<vpx_codec_pts_t>::const_iterator iter = kf_pts_list_.begin();
iter != kf_pts_list_.end(); ++iter) {
if (deadline_ == VPX_DL_REALTIME && *iter > 0)
EXPECT_EQ(0, (*iter - 1) % 30) << "Unexpected keyframe at frame "
<< *iter;
else
EXPECT_EQ(0, *iter % 30) << "Unexpected keyframe at frame " << *iter;
}
}
VP8_INSTANTIATE_TEST_CASE(KeyframeTest, ALL_TEST_MODES);
} // namespace

View File

@@ -1,119 +0,0 @@
/*
* Copyright (c) 2016 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 "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/util.h"
namespace {
class LevelTest
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
protected:
LevelTest()
: EncoderTest(GET_PARAM(0)),
encoding_mode_(GET_PARAM(1)),
cpu_used_(GET_PARAM(2)),
min_gf_internal_(24),
target_level_(0),
level_(0) {}
virtual ~LevelTest() {}
virtual void SetUp() {
InitializeConfig();
SetMode(encoding_mode_);
if (encoding_mode_ != ::libvpx_test::kRealTime) {
cfg_.g_lag_in_frames = 25;
cfg_.rc_end_usage = VPX_VBR;
} else {
cfg_.g_lag_in_frames = 0;
cfg_.rc_end_usage = VPX_CBR;
}
cfg_.rc_2pass_vbr_minsection_pct = 5;
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
cfg_.rc_target_bitrate = 400;
cfg_.rc_max_quantizer = 63;
cfg_.rc_min_quantizer = 0;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 0) {
encoder->Control(VP8E_SET_CPUUSED, cpu_used_);
encoder->Control(VP9E_SET_TARGET_LEVEL, target_level_);
encoder->Control(VP9E_SET_MIN_GF_INTERVAL, min_gf_internal_);
if (encoding_mode_ != ::libvpx_test::kRealTime) {
encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
encoder->Control(VP8E_SET_ARNR_TYPE, 3);
}
}
encoder->Control(VP9E_GET_LEVEL, &level_);
ASSERT_LE(level_, 51);
ASSERT_GE(level_, 0);
}
::libvpx_test::TestMode encoding_mode_;
int cpu_used_;
int min_gf_internal_;
int target_level_;
int level_;
};
// Test for keeping level stats only
TEST_P(LevelTest, TestTargetLevel0) {
::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
40);
target_level_ = 0;
min_gf_internal_ = 4;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_EQ(11, level_);
cfg_.rc_target_bitrate = 1600;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_EQ(20, level_);
}
// Test for level control being turned off
TEST_P(LevelTest, TestTargetLevel255) {
::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
30);
target_level_ = 255;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
TEST_P(LevelTest, TestTargetLevelApi) {
::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0, 1);
static const vpx_codec_iface_t *codec = &vpx_codec_vp9_cx_algo;
vpx_codec_ctx_t enc;
vpx_codec_enc_cfg_t cfg;
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_enc_config_default(codec, &cfg, 0));
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_enc_init(&enc, codec, &cfg, 0));
for (int level = 0; level <= 256; ++level) {
if (level == 10 || level == 11 || level == 20 || level == 21 ||
level == 30 || level == 31 || level == 40 || level == 41 ||
level == 50 || level == 51 || level == 52 || level == 60 ||
level == 61 || level == 62 || level == 0 || level == 255)
EXPECT_EQ(VPX_CODEC_OK,
vpx_codec_control(&enc, VP9E_SET_TARGET_LEVEL, level));
else
EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_control(&enc, VP9E_SET_TARGET_LEVEL, level));
}
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_destroy(&enc));
}
VP9_INSTANTIATE_TEST_CASE(LevelTest,
::testing::Values(::libvpx_test::kTwoPassGood,
::libvpx_test::kOnePassGood),
::testing::Range(0, 9));
} // namespace

View File

@@ -1,672 +0,0 @@
/*
* Copyright (c) 2014 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 <cmath>
#include <cstdlib>
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "vp10/common/entropy.h"
#include "vp10/common/loopfilter.h"
#include "vpx/vpx_integer.h"
using libvpx_test::ACMRandom;
namespace {
// Horizontally and Vertically need 32x32: 8 Coeffs preceeding filtered section
// 16 Coefs within filtered section
// 8 Coeffs following filtered section
const int kNumCoeffs = 1024;
const int number_of_iterations = 10000;
#if CONFIG_VPX_HIGHBITDEPTH
typedef void (*loop_op_t)(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int bd);
typedef void (*dual_loop_op_t)(uint16_t *s, int p, const uint8_t *blimit0,
const uint8_t *limit0, const uint8_t *thresh0,
const uint8_t *blimit1, const uint8_t *limit1,
const uint8_t *thresh1, int bd);
#else
typedef void (*loop_op_t)(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh);
typedef void (*dual_loop_op_t)(uint8_t *s, int p, const uint8_t *blimit0,
const uint8_t *limit0, const uint8_t *thresh0,
const uint8_t *blimit1, const uint8_t *limit1,
const uint8_t *thresh1);
#endif // CONFIG_VPX_HIGHBITDEPTH
typedef std::tr1::tuple<loop_op_t, loop_op_t, int> loop8_param_t;
typedef std::tr1::tuple<dual_loop_op_t, dual_loop_op_t, int> dualloop8_param_t;
class Loop8Test6Param : public ::testing::TestWithParam<loop8_param_t> {
public:
virtual ~Loop8Test6Param() {}
virtual void SetUp() {
loopfilter_op_ = GET_PARAM(0);
ref_loopfilter_op_ = GET_PARAM(1);
bit_depth_ = GET_PARAM(2);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
int bit_depth_;
int mask_;
loop_op_t loopfilter_op_;
loop_op_t ref_loopfilter_op_;
};
class Loop8Test9Param : public ::testing::TestWithParam<dualloop8_param_t> {
public:
virtual ~Loop8Test9Param() {}
virtual void SetUp() {
loopfilter_op_ = GET_PARAM(0);
ref_loopfilter_op_ = GET_PARAM(1);
bit_depth_ = GET_PARAM(2);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
int bit_depth_;
int mask_;
dual_loop_op_t loopfilter_op_;
dual_loop_op_t ref_loopfilter_op_;
};
TEST_P(Loop8Test6Param, OperationCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = number_of_iterations;
#if CONFIG_VPX_HIGHBITDEPTH
int32_t bd = bit_depth_;
DECLARE_ALIGNED(16, uint16_t, s[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, ref_s[kNumCoeffs]);
#else
DECLARE_ALIGNED(8, uint8_t, s[kNumCoeffs]);
DECLARE_ALIGNED(8, uint8_t, ref_s[kNumCoeffs]);
#endif // CONFIG_VPX_HIGHBITDEPTH
int err_count_total = 0;
int first_failure = -1;
for (int i = 0; i < count_test_block; ++i) {
int err_count = 0;
uint8_t tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
DECLARE_ALIGNED(16, const uint8_t, blimit[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
DECLARE_ALIGNED(16, const uint8_t, limit[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
DECLARE_ALIGNED(16, const uint8_t, thresh[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
int32_t p = kNumCoeffs/32;
uint16_t tmp_s[kNumCoeffs];
int j = 0;
while (j < kNumCoeffs) {
uint8_t val = rnd.Rand8();
if (val & 0x80) { // 50% chance to choose a new value.
tmp_s[j] = rnd.Rand16();
j++;
} else { // 50% chance to repeat previous value in row X times
int k = 0;
while (k++ < ((val & 0x1f) + 1) && j < kNumCoeffs) {
if (j < 1) {
tmp_s[j] = rnd.Rand16();
} else if (val & 0x20) { // Increment by an value within the limit
tmp_s[j] = (tmp_s[j - 1] + (*limit - 1));
} else { // Decrement by an value within the limit
tmp_s[j] = (tmp_s[j - 1] - (*limit - 1));
}
j++;
}
}
}
for (j = 0; j < kNumCoeffs; j++) {
if (i % 2) {
s[j] = tmp_s[j] & mask_;
} else {
s[j] = tmp_s[p * (j % p) + j / p] & mask_;
}
ref_s[j] = s[j];
}
#if CONFIG_VPX_HIGHBITDEPTH
ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit, limit, thresh, bd);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh, bd));
#else
ref_loopfilter_op_(ref_s+8+p*8, p, blimit, limit, thresh);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh));
#endif // CONFIG_VPX_HIGHBITDEPTH
for (int j = 0; j < kNumCoeffs; ++j) {
err_count += ref_s[j] != s[j];
}
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Loop8Test6Param, C output doesn't match SSE2 "
"loopfilter output. "
<< "First failed at test case " << first_failure;
}
TEST_P(Loop8Test6Param, ValueCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = number_of_iterations;
#if CONFIG_VPX_HIGHBITDEPTH
const int32_t bd = bit_depth_;
DECLARE_ALIGNED(16, uint16_t, s[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, ref_s[kNumCoeffs]);
#else
DECLARE_ALIGNED(8, uint8_t, s[kNumCoeffs]);
DECLARE_ALIGNED(8, uint8_t, ref_s[kNumCoeffs]);
#endif // CONFIG_VPX_HIGHBITDEPTH
int err_count_total = 0;
int first_failure = -1;
// NOTE: The code in vp9_loopfilter.c:update_sharpness computes mblim as a
// function of sharpness_lvl and the loopfilter lvl as:
// block_inside_limit = lvl >> ((sharpness_lvl > 0) + (sharpness_lvl > 4));
// ...
// memset(lfi->lfthr[lvl].mblim, (2 * (lvl + 2) + block_inside_limit),
// SIMD_WIDTH);
// This means that the largest value for mblim will occur when sharpness_lvl
// is equal to 0, and lvl is equal to its greatest value (MAX_LOOP_FILTER).
// In this case block_inside_limit will be equal to MAX_LOOP_FILTER and
// therefore mblim will be equal to (2 * (lvl + 2) + block_inside_limit) =
// 2 * (MAX_LOOP_FILTER + 2) + MAX_LOOP_FILTER = 3 * MAX_LOOP_FILTER + 4
for (int i = 0; i < count_test_block; ++i) {
int err_count = 0;
uint8_t tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
DECLARE_ALIGNED(16, const uint8_t, blimit[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
DECLARE_ALIGNED(16, const uint8_t, limit[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
DECLARE_ALIGNED(16, const uint8_t, thresh[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
int32_t p = kNumCoeffs / 32;
for (int j = 0; j < kNumCoeffs; ++j) {
s[j] = rnd.Rand16() & mask_;
ref_s[j] = s[j];
}
#if CONFIG_VPX_HIGHBITDEPTH
ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit, limit, thresh, bd);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh, bd));
#else
ref_loopfilter_op_(ref_s+8+p*8, p, blimit, limit, thresh);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh));
#endif // CONFIG_VPX_HIGHBITDEPTH
for (int j = 0; j < kNumCoeffs; ++j) {
err_count += ref_s[j] != s[j];
}
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Loop8Test6Param, C output doesn't match SSE2 "
"loopfilter output. "
<< "First failed at test case " << first_failure;
}
TEST_P(Loop8Test9Param, OperationCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = number_of_iterations;
#if CONFIG_VPX_HIGHBITDEPTH
const int32_t bd = bit_depth_;
DECLARE_ALIGNED(16, uint16_t, s[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, ref_s[kNumCoeffs]);
#else
DECLARE_ALIGNED(8, uint8_t, s[kNumCoeffs]);
DECLARE_ALIGNED(8, uint8_t, ref_s[kNumCoeffs]);
#endif // CONFIG_VPX_HIGHBITDEPTH
int err_count_total = 0;
int first_failure = -1;
for (int i = 0; i < count_test_block; ++i) {
int err_count = 0;
uint8_t tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
DECLARE_ALIGNED(16, const uint8_t, blimit0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
DECLARE_ALIGNED(16, const uint8_t, limit0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
DECLARE_ALIGNED(16, const uint8_t, thresh0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
DECLARE_ALIGNED(16, const uint8_t, blimit1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
DECLARE_ALIGNED(16, const uint8_t, limit1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
DECLARE_ALIGNED(16, const uint8_t, thresh1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
int32_t p = kNumCoeffs / 32;
uint16_t tmp_s[kNumCoeffs];
int j = 0;
const uint8_t limit = *limit0 < *limit1 ? *limit0 : *limit1;
while (j < kNumCoeffs) {
uint8_t val = rnd.Rand8();
if (val & 0x80) { // 50% chance to choose a new value.
tmp_s[j] = rnd.Rand16();
j++;
} else { // 50% chance to repeat previous value in row X times.
int k = 0;
while (k++ < ((val & 0x1f) + 1) && j < kNumCoeffs) {
if (j < 1) {
tmp_s[j] = rnd.Rand16();
} else if (val & 0x20) { // Increment by a value within the limit.
tmp_s[j] = (tmp_s[j - 1] + (limit - 1));
} else { // Decrement by an value within the limit.
tmp_s[j] = (tmp_s[j - 1] - (limit - 1));
}
j++;
}
}
}
for (j = 0; j < kNumCoeffs; j++) {
if (i % 2) {
s[j] = tmp_s[j] & mask_;
} else {
s[j] = tmp_s[p * (j % p) + j / p] & mask_;
}
ref_s[j] = s[j];
}
#if CONFIG_VPX_HIGHBITDEPTH
ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0,
blimit1, limit1, thresh1, bd);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit0, limit0, thresh0,
blimit1, limit1, thresh1, bd));
#else
ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0,
blimit1, limit1, thresh1);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit0, limit0, thresh0,
blimit1, limit1, thresh1));
#endif // CONFIG_VPX_HIGHBITDEPTH
for (int j = 0; j < kNumCoeffs; ++j) {
err_count += ref_s[j] != s[j];
}
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Loop8Test9Param, C output doesn't match SSE2 "
"loopfilter output. "
<< "First failed at test case " << first_failure;
}
TEST_P(Loop8Test9Param, ValueCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = number_of_iterations;
#if CONFIG_VPX_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, s[kNumCoeffs]);
DECLARE_ALIGNED(16, uint16_t, ref_s[kNumCoeffs]);
#else
DECLARE_ALIGNED(8, uint8_t, s[kNumCoeffs]);
DECLARE_ALIGNED(8, uint8_t, ref_s[kNumCoeffs]);
#endif // CONFIG_VPX_HIGHBITDEPTH
int err_count_total = 0;
int first_failure = -1;
for (int i = 0; i < count_test_block; ++i) {
int err_count = 0;
uint8_t tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
DECLARE_ALIGNED(16, const uint8_t, blimit0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
DECLARE_ALIGNED(16, const uint8_t, limit0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
DECLARE_ALIGNED(16, const uint8_t, thresh0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = static_cast<uint8_t>(rnd(3 * MAX_LOOP_FILTER + 4));
DECLARE_ALIGNED(16, const uint8_t, blimit1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = static_cast<uint8_t>(rnd(MAX_LOOP_FILTER));
DECLARE_ALIGNED(16, const uint8_t, limit1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
DECLARE_ALIGNED(16, const uint8_t, thresh1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
int32_t p = kNumCoeffs / 32; // TODO(pdlf) can we have non-square here?
for (int j = 0; j < kNumCoeffs; ++j) {
s[j] = rnd.Rand16() & mask_;
ref_s[j] = s[j];
}
#if CONFIG_VPX_HIGHBITDEPTH
const int32_t bd = bit_depth_;
ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0,
blimit1, limit1, thresh1, bd);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit0, limit0,
thresh0, blimit1, limit1, thresh1, bd));
#else
ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0,
blimit1, limit1, thresh1);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit0, limit0, thresh0,
blimit1, limit1, thresh1));
#endif // CONFIG_VPX_HIGHBITDEPTH
for (int j = 0; j < kNumCoeffs; ++j) {
err_count += ref_s[j] != s[j];
}
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Loop8Test9Param, C output doesn't match SSE2"
"loopfilter output. "
<< "First failed at test case " << first_failure;
}
using std::tr1::make_tuple;
#if HAVE_SSE2
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
SSE2, Loop8Test6Param,
::testing::Values(
make_tuple(&vpx_highbd_lpf_horizontal_4_sse2,
&vpx_highbd_lpf_horizontal_4_c, 8),
make_tuple(&vpx_highbd_lpf_vertical_4_sse2,
&vpx_highbd_lpf_vertical_4_c, 8),
make_tuple(&vpx_highbd_lpf_horizontal_8_sse2,
&vpx_highbd_lpf_horizontal_8_c, 8),
make_tuple(&vpx_highbd_lpf_horizontal_edge_8_sse2,
&vpx_highbd_lpf_horizontal_edge_8_c, 8),
make_tuple(&vpx_highbd_lpf_horizontal_edge_16_sse2,
&vpx_highbd_lpf_horizontal_edge_16_c, 8),
make_tuple(&vpx_highbd_lpf_vertical_8_sse2,
&vpx_highbd_lpf_vertical_8_c, 8),
make_tuple(&vpx_highbd_lpf_vertical_16_sse2,
&vpx_highbd_lpf_vertical_16_c, 8),
make_tuple(&vpx_highbd_lpf_horizontal_4_sse2,
&vpx_highbd_lpf_horizontal_4_c, 10),
make_tuple(&vpx_highbd_lpf_vertical_4_sse2,
&vpx_highbd_lpf_vertical_4_c, 10),
make_tuple(&vpx_highbd_lpf_horizontal_8_sse2,
&vpx_highbd_lpf_horizontal_8_c, 10),
make_tuple(&vpx_highbd_lpf_horizontal_edge_8_sse2,
&vpx_highbd_lpf_horizontal_edge_8_c, 10),
make_tuple(&vpx_highbd_lpf_horizontal_edge_16_sse2,
&vpx_highbd_lpf_horizontal_edge_16_c, 10),
make_tuple(&vpx_highbd_lpf_vertical_8_sse2,
&vpx_highbd_lpf_vertical_8_c, 10),
make_tuple(&vpx_highbd_lpf_vertical_16_sse2,
&vpx_highbd_lpf_vertical_16_c, 10),
make_tuple(&vpx_highbd_lpf_horizontal_4_sse2,
&vpx_highbd_lpf_horizontal_4_c, 12),
make_tuple(&vpx_highbd_lpf_vertical_4_sse2,
&vpx_highbd_lpf_vertical_4_c, 12),
make_tuple(&vpx_highbd_lpf_horizontal_8_sse2,
&vpx_highbd_lpf_horizontal_8_c, 12),
make_tuple(&vpx_highbd_lpf_horizontal_edge_8_sse2,
&vpx_highbd_lpf_horizontal_edge_8_c, 12),
make_tuple(&vpx_highbd_lpf_horizontal_edge_16_sse2,
&vpx_highbd_lpf_horizontal_edge_16_c, 12),
make_tuple(&vpx_highbd_lpf_vertical_8_sse2,
&vpx_highbd_lpf_vertical_8_c, 12),
make_tuple(&vpx_highbd_lpf_vertical_16_sse2,
&vpx_highbd_lpf_vertical_16_c, 12),
make_tuple(&vpx_highbd_lpf_vertical_16_dual_sse2,
&vpx_highbd_lpf_vertical_16_dual_c, 8),
make_tuple(&vpx_highbd_lpf_vertical_16_dual_sse2,
&vpx_highbd_lpf_vertical_16_dual_c, 10),
make_tuple(&vpx_highbd_lpf_vertical_16_dual_sse2,
&vpx_highbd_lpf_vertical_16_dual_c, 12)));
#else
INSTANTIATE_TEST_CASE_P(
SSE2, Loop8Test6Param,
::testing::Values(
make_tuple(&vpx_lpf_horizontal_4_sse2,
&vpx_lpf_horizontal_4_c, 8),
make_tuple(&vpx_lpf_horizontal_8_sse2,
&vpx_lpf_horizontal_8_c, 8),
make_tuple(&vpx_lpf_horizontal_edge_8_sse2,
&vpx_lpf_horizontal_edge_8_c, 8),
make_tuple(&vpx_lpf_horizontal_edge_16_sse2,
&vpx_lpf_horizontal_edge_16_c, 8),
make_tuple(&vpx_lpf_vertical_4_sse2,
&vpx_lpf_vertical_4_c, 8),
make_tuple(&vpx_lpf_vertical_8_sse2,
&vpx_lpf_vertical_8_c, 8),
make_tuple(&vpx_lpf_vertical_16_sse2,
&vpx_lpf_vertical_16_c, 8),
make_tuple(&vpx_lpf_vertical_16_dual_sse2,
&vpx_lpf_vertical_16_dual_c, 8)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#endif
#if HAVE_AVX2 && (!CONFIG_VPX_HIGHBITDEPTH)
INSTANTIATE_TEST_CASE_P(
AVX2, Loop8Test6Param,
::testing::Values(
make_tuple(&vpx_lpf_horizontal_edge_8_avx2,
&vpx_lpf_horizontal_edge_8_c, 8),
make_tuple(&vpx_lpf_horizontal_edge_16_avx2,
&vpx_lpf_horizontal_edge_16_c, 8)));
#endif
#if HAVE_SSE2
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
SSE2, Loop8Test9Param,
::testing::Values(
make_tuple(&vpx_highbd_lpf_horizontal_4_dual_sse2,
&vpx_highbd_lpf_horizontal_4_dual_c, 8),
make_tuple(&vpx_highbd_lpf_horizontal_8_dual_sse2,
&vpx_highbd_lpf_horizontal_8_dual_c, 8),
make_tuple(&vpx_highbd_lpf_vertical_4_dual_sse2,
&vpx_highbd_lpf_vertical_4_dual_c, 8),
make_tuple(&vpx_highbd_lpf_vertical_8_dual_sse2,
&vpx_highbd_lpf_vertical_8_dual_c, 8),
make_tuple(&vpx_highbd_lpf_horizontal_4_dual_sse2,
&vpx_highbd_lpf_horizontal_4_dual_c, 10),
make_tuple(&vpx_highbd_lpf_horizontal_8_dual_sse2,
&vpx_highbd_lpf_horizontal_8_dual_c, 10),
make_tuple(&vpx_highbd_lpf_vertical_4_dual_sse2,
&vpx_highbd_lpf_vertical_4_dual_c, 10),
make_tuple(&vpx_highbd_lpf_vertical_8_dual_sse2,
&vpx_highbd_lpf_vertical_8_dual_c, 10),
make_tuple(&vpx_highbd_lpf_horizontal_4_dual_sse2,
&vpx_highbd_lpf_horizontal_4_dual_c, 12),
make_tuple(&vpx_highbd_lpf_horizontal_8_dual_sse2,
&vpx_highbd_lpf_horizontal_8_dual_c, 12),
make_tuple(&vpx_highbd_lpf_vertical_4_dual_sse2,
&vpx_highbd_lpf_vertical_4_dual_c, 12),
make_tuple(&vpx_highbd_lpf_vertical_8_dual_sse2,
&vpx_highbd_lpf_vertical_8_dual_c, 12)));
#else
INSTANTIATE_TEST_CASE_P(
SSE2, Loop8Test9Param,
::testing::Values(
make_tuple(&vpx_lpf_horizontal_4_dual_sse2,
&vpx_lpf_horizontal_4_dual_c, 8),
make_tuple(&vpx_lpf_horizontal_8_dual_sse2,
&vpx_lpf_horizontal_8_dual_c, 8),
make_tuple(&vpx_lpf_vertical_4_dual_sse2,
&vpx_lpf_vertical_4_dual_c, 8),
make_tuple(&vpx_lpf_vertical_8_dual_sse2,
&vpx_lpf_vertical_8_dual_c, 8)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#endif
#if HAVE_NEON
#if CONFIG_VPX_HIGHBITDEPTH
// No neon high bitdepth functions.
#else
INSTANTIATE_TEST_CASE_P(
NEON, Loop8Test6Param,
::testing::Values(
#if HAVE_NEON_ASM
// Using #if inside the macro is unsupported on MSVS but the tests are not
// currently built for MSVS with ARM and NEON.
make_tuple(&vpx_lpf_horizontal_edge_8_neon,
&vpx_lpf_horizontal_edge_8_c, 8),
make_tuple(&vpx_lpf_horizontal_edge_16_neon,
&vpx_lpf_horizontal_edge_16_c, 8),
make_tuple(&vpx_lpf_vertical_16_neon,
&vpx_lpf_vertical_16_c, 8),
make_tuple(&vpx_lpf_vertical_16_dual_neon,
&vpx_lpf_vertical_16_dual_c, 8),
#endif // HAVE_NEON_ASM
make_tuple(&vpx_lpf_horizontal_8_neon,
&vpx_lpf_horizontal_8_c, 8),
make_tuple(&vpx_lpf_vertical_8_neon,
&vpx_lpf_vertical_8_c, 8),
make_tuple(&vpx_lpf_horizontal_4_neon,
&vpx_lpf_horizontal_4_c, 8),
make_tuple(&vpx_lpf_vertical_4_neon,
&vpx_lpf_vertical_4_c, 8)));
INSTANTIATE_TEST_CASE_P(
NEON, Loop8Test9Param,
::testing::Values(
#if HAVE_NEON_ASM
make_tuple(&vpx_lpf_horizontal_8_dual_neon,
&vpx_lpf_horizontal_8_dual_c, 8),
make_tuple(&vpx_lpf_vertical_8_dual_neon,
&vpx_lpf_vertical_8_dual_c, 8),
#endif // HAVE_NEON_ASM
make_tuple(&vpx_lpf_horizontal_4_dual_neon,
&vpx_lpf_horizontal_4_dual_c, 8),
make_tuple(&vpx_lpf_vertical_4_dual_neon,
&vpx_lpf_vertical_4_dual_c, 8)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#endif // HAVE_NEON
#if HAVE_DSPR2 && !CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
DSPR2, Loop8Test6Param,
::testing::Values(
make_tuple(&vpx_lpf_horizontal_4_dspr2,
&vpx_lpf_horizontal_4_c, 8),
make_tuple(&vpx_lpf_horizontal_8_dspr2,
&vpx_lpf_horizontal_8_c, 8),
make_tuple(&vpx_lpf_horizontal_edge_8,
&vpx_lpf_horizontal_edge_8, 8),
make_tuple(&vpx_lpf_horizontal_edge_16,
&vpx_lpf_horizontal_edge_16, 8),
make_tuple(&vpx_lpf_vertical_4_dspr2,
&vpx_lpf_vertical_4_c, 8),
make_tuple(&vpx_lpf_vertical_8_dspr2,
&vpx_lpf_vertical_8_c, 8),
make_tuple(&vpx_lpf_vertical_16_dspr2,
&vpx_lpf_vertical_16_c, 8),
make_tuple(&vpx_lpf_vertical_16_dual_dspr2,
&vpx_lpf_vertical_16_dual_c, 8)));
INSTANTIATE_TEST_CASE_P(
DSPR2, Loop8Test9Param,
::testing::Values(
make_tuple(&vpx_lpf_horizontal_4_dual_dspr2,
&vpx_lpf_horizontal_4_dual_c, 8),
make_tuple(&vpx_lpf_horizontal_8_dual_dspr2,
&vpx_lpf_horizontal_8_dual_c, 8),
make_tuple(&vpx_lpf_vertical_4_dual_dspr2,
&vpx_lpf_vertical_4_dual_c, 8),
make_tuple(&vpx_lpf_vertical_8_dual_dspr2,
&vpx_lpf_vertical_8_dual_c, 8)));
#endif // HAVE_DSPR2 && !CONFIG_VPX_HIGHBITDEPTH
#if HAVE_MSA && (!CONFIG_VPX_HIGHBITDEPTH)
INSTANTIATE_TEST_CASE_P(
MSA, Loop8Test6Param,
::testing::Values(
make_tuple(&vpx_lpf_horizontal_4_msa,
&vpx_lpf_horizontal_4_c, 8),
make_tuple(&vpx_lpf_horizontal_8_msa,
&vpx_lpf_horizontal_8_c, 8),
make_tuple(&vpx_lpf_horizontal_edge_8_msa,
&vpx_lpf_horizontal_edge_8_c, 8),
make_tuple(&vpx_lpf_horizontal_edge_16_msa,
&vpx_lpf_horizontal_edge_16_c, 8),
make_tuple(&vpx_lpf_vertical_4_msa,
&vpx_lpf_vertical_4_c, 8),
make_tuple(&vpx_lpf_vertical_8_msa,
&vpx_lpf_vertical_8_c, 8),
make_tuple(&vpx_lpf_vertical_16_msa,
&vpx_lpf_vertical_16_c, 8)));
INSTANTIATE_TEST_CASE_P(
MSA, Loop8Test9Param,
::testing::Values(
make_tuple(&vpx_lpf_horizontal_4_dual_msa,
&vpx_lpf_horizontal_4_dual_c, 8),
make_tuple(&vpx_lpf_horizontal_8_dual_msa,
&vpx_lpf_horizontal_8_dual_c, 8),
make_tuple(&vpx_lpf_vertical_4_dual_msa,
&vpx_lpf_vertical_4_dual_c, 8),
make_tuple(&vpx_lpf_vertical_8_dual_msa,
&vpx_lpf_vertical_8_dual_c, 8)));
#endif // HAVE_MSA && (!CONFIG_VPX_HIGHBITDEPTH)
} // namespace

View File

@@ -1,225 +0,0 @@
/*
* Copyright (c) 2015 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 <math.h>
#include <stdlib.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
#include "vpx/vpx_integer.h"
using libvpx_test::ACMRandom;
namespace {
const int number_of_iterations = 500;
typedef unsigned int (*MaskedSADFunc)(const uint8_t *a, int a_stride,
const uint8_t *b, int b_stride,
const uint8_t *m, int m_stride);
typedef std::tr1::tuple<MaskedSADFunc, MaskedSADFunc> MaskedSADParam;
class MaskedSADTest : public ::testing::TestWithParam<MaskedSADParam> {
public:
virtual ~MaskedSADTest() {}
virtual void SetUp() {
maskedSAD_op_ = GET_PARAM(0);
ref_maskedSAD_op_ = GET_PARAM(1);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
MaskedSADFunc maskedSAD_op_;
MaskedSADFunc ref_maskedSAD_op_;
};
TEST_P(MaskedSADTest, OperationCheck) {
unsigned int ref_ret, ret;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED(16, uint8_t, src_ptr[MAX_SB_SIZE*MAX_SB_SIZE]);
DECLARE_ALIGNED(16, uint8_t, ref_ptr[MAX_SB_SIZE*MAX_SB_SIZE]);
DECLARE_ALIGNED(16, uint8_t, msk_ptr[MAX_SB_SIZE*MAX_SB_SIZE]);
int err_count = 0;
int first_failure = -1;
int src_stride = MAX_SB_SIZE;
int ref_stride = MAX_SB_SIZE;
int msk_stride = MAX_SB_SIZE;
for (int i = 0; i < number_of_iterations; ++i) {
for (int j = 0; j < MAX_SB_SIZE*MAX_SB_SIZE; j++) {
src_ptr[j] = rnd.Rand8();
ref_ptr[j] = rnd.Rand8();
msk_ptr[j] = ((rnd.Rand8()&0x7f) > 64) ? rnd.Rand8()&0x3f : 64;
assert(msk_ptr[j] <= 64);
}
ref_ret = ref_maskedSAD_op_(src_ptr, src_stride, ref_ptr, ref_stride,
msk_ptr, msk_stride);
ASM_REGISTER_STATE_CHECK(ret = maskedSAD_op_(src_ptr, src_stride,
ref_ptr, ref_stride,
msk_ptr, msk_stride));
if (ret != ref_ret) {
err_count++;
if (first_failure == -1)
first_failure = i;
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked SAD Test, C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure;
}
#if CONFIG_VPX_HIGHBITDEPTH
typedef unsigned int (*HighbdMaskedSADFunc)(const uint8_t *a, int a_stride,
const uint8_t *b, int b_stride,
const uint8_t *m, int m_stride);
typedef std::tr1::tuple<HighbdMaskedSADFunc, HighbdMaskedSADFunc>
HighbdMaskedSADParam;
class HighbdMaskedSADTest : public ::testing::
TestWithParam<HighbdMaskedSADParam> {
public:
virtual ~HighbdMaskedSADTest() {}
virtual void SetUp() {
maskedSAD_op_ = GET_PARAM(0);
ref_maskedSAD_op_ = GET_PARAM(1);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
HighbdMaskedSADFunc maskedSAD_op_;
HighbdMaskedSADFunc ref_maskedSAD_op_;
};
TEST_P(HighbdMaskedSADTest, OperationCheck) {
unsigned int ref_ret, ret;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED(16, uint16_t, src_ptr[MAX_SB_SIZE*MAX_SB_SIZE]);
DECLARE_ALIGNED(16, uint16_t, ref_ptr[MAX_SB_SIZE*MAX_SB_SIZE]);
DECLARE_ALIGNED(16, uint8_t, msk_ptr[MAX_SB_SIZE*MAX_SB_SIZE]);
uint8_t* src8_ptr = CONVERT_TO_BYTEPTR(src_ptr);
uint8_t* ref8_ptr = CONVERT_TO_BYTEPTR(ref_ptr);
int err_count = 0;
int first_failure = -1;
int src_stride = MAX_SB_SIZE;
int ref_stride = MAX_SB_SIZE;
int msk_stride = MAX_SB_SIZE;
for (int i = 0; i < number_of_iterations; ++i) {
for (int j = 0; j < MAX_SB_SIZE*MAX_SB_SIZE; j++) {
src_ptr[j] = rnd.Rand16()&0xfff;
ref_ptr[j] = rnd.Rand16()&0xfff;
msk_ptr[j] = ((rnd.Rand8()&0x7f) > 64) ? rnd.Rand8()&0x3f : 64;
}
ref_ret = ref_maskedSAD_op_(src8_ptr, src_stride, ref8_ptr, ref_stride,
msk_ptr, msk_stride);
ASM_REGISTER_STATE_CHECK(ret = maskedSAD_op_(src8_ptr, src_stride,
ref8_ptr, ref_stride,
msk_ptr, msk_stride));
if (ret != ref_ret) {
err_count++;
if (first_failure == -1)
first_failure = i;
}
}
EXPECT_EQ(0, err_count)
<< "Error: High BD Masked SAD Test, C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure;
}
#endif // CONFIG_VPX_HIGHBITDEPTH
using std::tr1::make_tuple;
#if HAVE_SSSE3
INSTANTIATE_TEST_CASE_P(
SSSE3_C_COMPARE, MaskedSADTest,
::testing::Values(
#if CONFIG_EXT_PARTITION
make_tuple(&vpx_masked_sad128x128_ssse3,
&vpx_masked_sad128x128_c),
make_tuple(&vpx_masked_sad128x64_ssse3,
&vpx_masked_sad128x64_c),
make_tuple(&vpx_masked_sad64x128_ssse3,
&vpx_masked_sad64x128_c),
#endif // CONFIG_EXT_PARTITION
make_tuple(&vpx_masked_sad64x64_ssse3,
&vpx_masked_sad64x64_c),
make_tuple(&vpx_masked_sad64x32_ssse3,
&vpx_masked_sad64x32_c),
make_tuple(&vpx_masked_sad32x64_ssse3,
&vpx_masked_sad32x64_c),
make_tuple(&vpx_masked_sad32x32_ssse3,
&vpx_masked_sad32x32_c),
make_tuple(&vpx_masked_sad32x16_ssse3,
&vpx_masked_sad32x16_c),
make_tuple(&vpx_masked_sad16x32_ssse3,
&vpx_masked_sad16x32_c),
make_tuple(&vpx_masked_sad16x16_ssse3,
&vpx_masked_sad16x16_c),
make_tuple(&vpx_masked_sad16x8_ssse3,
&vpx_masked_sad16x8_c),
make_tuple(&vpx_masked_sad8x16_ssse3,
&vpx_masked_sad8x16_c),
make_tuple(&vpx_masked_sad8x8_ssse3,
&vpx_masked_sad8x8_c),
make_tuple(&vpx_masked_sad8x4_ssse3,
&vpx_masked_sad8x4_c),
make_tuple(&vpx_masked_sad4x8_ssse3,
&vpx_masked_sad4x8_c),
make_tuple(&vpx_masked_sad4x4_ssse3,
&vpx_masked_sad4x4_c)));
#if CONFIG_VPX_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
SSSE3_C_COMPARE, HighbdMaskedSADTest,
::testing::Values(
#if CONFIG_EXT_PARTITION
make_tuple(&vpx_highbd_masked_sad128x128_ssse3,
&vpx_highbd_masked_sad128x128_c),
make_tuple(&vpx_highbd_masked_sad128x64_ssse3,
&vpx_highbd_masked_sad128x64_c),
make_tuple(&vpx_highbd_masked_sad64x128_ssse3,
&vpx_highbd_masked_sad64x128_c),
#endif // CONFIG_EXT_PARTITION
make_tuple(&vpx_highbd_masked_sad64x64_ssse3,
&vpx_highbd_masked_sad64x64_c),
make_tuple(&vpx_highbd_masked_sad64x32_ssse3,
&vpx_highbd_masked_sad64x32_c),
make_tuple(&vpx_highbd_masked_sad32x64_ssse3,
&vpx_highbd_masked_sad32x64_c),
make_tuple(&vpx_highbd_masked_sad32x32_ssse3,
&vpx_highbd_masked_sad32x32_c),
make_tuple(&vpx_highbd_masked_sad32x16_ssse3,
&vpx_highbd_masked_sad32x16_c),
make_tuple(&vpx_highbd_masked_sad16x32_ssse3,
&vpx_highbd_masked_sad16x32_c),
make_tuple(&vpx_highbd_masked_sad16x16_ssse3,
&vpx_highbd_masked_sad16x16_c),
make_tuple(&vpx_highbd_masked_sad16x8_ssse3,
&vpx_highbd_masked_sad16x8_c),
make_tuple(&vpx_highbd_masked_sad8x16_ssse3,
&vpx_highbd_masked_sad8x16_c),
make_tuple(&vpx_highbd_masked_sad8x8_ssse3,
&vpx_highbd_masked_sad8x8_c),
make_tuple(&vpx_highbd_masked_sad8x4_ssse3,
&vpx_highbd_masked_sad8x4_c),
make_tuple(&vpx_highbd_masked_sad4x8_ssse3,
&vpx_highbd_masked_sad4x8_c),
make_tuple(&vpx_highbd_masked_sad4x4_ssse3,
&vpx_highbd_masked_sad4x4_c)));
#endif // CONFIG_VPX_HIGHBITDEPTH
#endif // HAVE_SSSE3
} // namespace

Some files were not shown because too many files have changed in this diff Show More