Compare commits

..

1 Commits

Author SHA1 Message Date
hkuang
5504b39f5e Remove a line.
Change-Id: I2965d25efafeee487b4de75fddfa22e4907525ed
2015-05-01 11:09:30 -07:00
1178 changed files with 213552 additions and 266195 deletions

View File

@ -1,109 +0,0 @@
---
Language: Cpp
# BasedOnStyle: Google
# Generated with clang-format 5.0.0
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeCategories:
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never
...

12
.gitignore vendored
View File

@ -30,17 +30,14 @@
/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/vp9cx_set_ref /examples/vp9_spatial_scalable_encoder
/examples/vp9_lossless_encoder /examples/vpx_temporal_scalable_patterns
/examples/vp9_spatial_svc_encoder
/examples/vpx_temporal_svc_encoder
/ivfdec /ivfdec
/ivfdec.dox /ivfdec.dox
/ivfenc /ivfenc
@ -48,17 +45,12 @@
/libvpx.so* /libvpx.so*
/libvpx.ver /libvpx.ver
/samples.dox /samples.dox
/test_intra_pred_speed
/test_libvpx /test_libvpx
/tools.dox
/tools/*.dox
/tools/tiny_ssim
/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,42 +1,26 @@
Adrian Grange <agrange@google.com> Adrian Grange <agrange@google.com>
Aex Converse <aconverse@google.com> Alex Converse <aconverse@google.com> <alex.converse@gmail.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> Alpha Lam <hclam@google.com> <hclam@chromium.org>
Chris Cunningham <chcunningham@chromium.org>
Daniele Castagna <dcastagna@chromium.org> <dcastagna@google.com>
Deb Mukherjee <debargha@google.com> Deb Mukherjee <debargha@google.com>
Erik Niemeyer <erik.a.niemeyer@intel.com> <erik.a.niemeyer@gmail.com> Erik Niemeyer <erik.a.niemeyer@intel.com> <erik.a.niemeyer@gmail.com>
Guillaume Martres <gmartres@google.com> <smarter3@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>
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@chromium.org>
John Koleszar <jkoleszar@google.com> John Koleszar <jkoleszar@google.com>
Joshua Litt <joshualitt@google.com> <joshualitt@chromium.org> Joshua Litt <joshualitt@google.com> <joshualitt@chromium.org>
Marco Paniconi <marpan@google.com> Marco Paniconi <marpan@google.com>
Marco Paniconi <marpan@google.com> <marpan@chromium.org> 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> Paul Wilkins <paulwilkins@google.com>
Peter Boström <pbos@chromium.org> <pbos@google.com>
Peter de Rivaz <peter.derivaz@gmail.com>
Peter de Rivaz <peter.derivaz@gmail.com> <peter.derivaz@argondesign.com>
Ralph Giles <giles@xiph.org> <giles@entropywave.com> Ralph Giles <giles@xiph.org> <giles@entropywave.com>
Ralph Giles <giles@xiph.org> <giles@mozilla.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>
Shiyou Yin <yinshiyou-hf@loongson.cn>
Tamar Levy <tamar.levy@intel.com> Tamar Levy <tamar.levy@intel.com>
Tamar Levy <tamar.levy@intel.com> <levytamar82@gmail.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> <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>
Urvang Joshi <urvang@google.com> <urvang@chromium.org>
Yaowu Xu <yaowu@google.com> <adam@xuyaowu.com>
Yaowu Xu <yaowu@google.com> <yaowu@xuyaowu.com> Yaowu Xu <yaowu@google.com> <yaowu@xuyaowu.com>
Yaowu Xu <yaowu@google.com> <Yaowu Xu>

53
AUTHORS
View File

@ -3,13 +3,11 @@
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>
Aleksey Vasenev <margtu-fivt@ya.ru>
Alexander Potapenko <glider@google.com>
Alexander Voronov <avoronov@graphics.cs.msu.ru> Alexander Voronov <avoronov@graphics.cs.msu.ru>
Alexandra Hájková <alexandra.khirnova@gmail.com> Alex Converse <aconverse@google.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>
@ -17,80 +15,58 @@ 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 Lewis <andrewlewis@google.com>
Andrew Russell <anrussell@google.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> Charles 'Buck' Krasic <ckrasic@google.com>
Cheng Chen <chengchen@google.com>
chm <chm@rock-chips.com> chm <chm@rock-chips.com>
Chris Cunningham <chcunningham@chromium.org>
Christian Duvivier <cduvivier@google.com> Christian Duvivier <cduvivier@google.com>
Daniele Castagna <dcastagna@chromium.org>
Daniel Kang <ddkang@google.com> Daniel Kang <ddkang@google.com>
Deb Mukherjee <debargha@google.com> Deb Mukherjee <debargha@google.com>
Deepa K G <deepa.kg@ittiam.com>
Dim Temp <dimtemp0@gmail.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>
Ehsan Akhgari <ehsan.akhgari@gmail.com> Ehsan Akhgari <ehsan.akhgari@gmail.com>
Erik Niemeyer <erik.a.niemeyer@intel.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>
Gabriel Marin <gmx@chromium.org>
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> Gordana Cmiljanovic <gordana.cmiljanovic@imgtec.com>
Gregor Jasny <gjasny@gmail.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> Hanno Böck <hanno@hboeck.de>
Han Shen <shenhan@google.com>
Henrik Lundin <hlundin@google.com> Henrik Lundin <hlundin@google.com>
Hui Su <huisu@google.com> Hui Su <huisu@google.com>
Ivan Krasin <krasin@chromium.org>
Ivan Maltz <ivanmaltz@google.com> Ivan Maltz <ivanmaltz@google.com>
Jacek Caban <cjacek@gmail.com> Jacek Caban <cjacek@gmail.com>
Jacky Chen <jackychen@google.com> JackyChen <jackychen@google.com>
James Berry <jamesberry@google.com> James Berry <jamesberry@google.com>
James Yu <james.yu@linaro.org> James Yu <james.yu@linaro.org>
James Zern <jzern@google.com> James Zern <jzern@google.com>
Jan Gerber <j@mailb.org> 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>
Jean-Yves Avenard <jyavenard@mozilla.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>
Jerome Jiang <jianj@google.com>
Jia Jia <jia.jia@linaro.org> Jia Jia <jia.jia@linaro.org>
Jian Zhou <zhoujian@google.com>
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> 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> 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>
Kaustubh Raste <kaustubh.raste@imgtec.com>
KO Myung-Hun <komh@chollian.net> KO Myung-Hun <komh@chollian.net>
Kyle Siefring <kylesiefring@gmail.com>
Lawrence Velázquez <larryv@macports.org> Lawrence Velázquez <larryv@macports.org>
Linfeng Zhang <linfengz@google.com>
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>
@ -104,13 +80,8 @@ 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>
Min Chen <chenm003@gmail.com>
Minghai Shang <minghai@google.com> Minghai Shang <minghai@google.com>
Min Ye <yeemmi@google.com>
Moriyoshi Koizumi <mozo@mozo.jp>
Morton Jonuschat <yabawock@gmail.com> Morton Jonuschat <yabawock@gmail.com>
Nathan E. Egge <negge@mozilla.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>
@ -118,34 +89,23 @@ 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> Pengchong Jin <pengchong@google.com>
Peter Boström <pbos@chromium.org>
Peter Collingbourne <pcc@chromium.org>
Peter de Rivaz <peter.derivaz@gmail.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>
Rafael de Lucena Valle <rafaeldelucena@gmail.com>
Rahul Chaudhry <rahulchaudhry@google.com>
Ralph Giles <giles@xiph.org> Ralph Giles <giles@xiph.org>
Ranjit Kumar Tulabandu <ranjit.tulabandu@ittiam.com>
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> Rui Ueyama <ruiu@google.com>
Sami Pietilä <samipietila@google.com> Sami Pietilä <samipietila@google.com>
Sarah Parker <sarahparker@google.com>
Sasi Inguva <isasi@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> Sean McGovern <gseanmcg@gmail.com>
Sergey Kolomenkin <kolomenkin@gmail.com>
Sergey Ulanov <sergeyu@chromium.org> Sergey Ulanov <sergeyu@chromium.org>
Shimon Doodkin <helpmepro1@gmail.com> Shimon Doodkin <helpmepro1@gmail.com>
Shiyou Yin <yinshiyou-hf@loongson.cn>
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>
Sylvestre Ledru <sylvestre@mozilla.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>
@ -155,15 +115,10 @@ Thijs Vermeir <thijsvermeir@gmail.com>
Tim Kopp <tkopp@google.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>
Tristan Matthews <le.businessman@gmail.com>
Urvang Joshi <urvang@google.com>
Vignesh Venkatasubramanian <vigneshv@google.com> Vignesh Venkatasubramanian <vigneshv@google.com>
Vlad Tsyrklevich <vtsyrklevich@chromium.org>
Yaowu Xu <yaowu@google.com> Yaowu Xu <yaowu@google.com>
Yi Luo <luoyi@google.com>
Yongzhe Wang <yongzhe@google.com> Yongzhe Wang <yongzhe@google.com>
Yunqing Wang <yunqingwang@google.com> Yunqing Wang <yunqingwang@google.com>
Yury Gitman <yuryg@google.com>
Zoe Liu <zoeliu@google.com> Zoe Liu <zoeliu@google.com>
Google Inc. Google Inc.
The Mozilla Foundation The Mozilla Foundation

View File

@ -1,91 +1,3 @@
2017-01-04 v1.7.0 "Mandarin Duck"
This release focused on high bit depth performance (10/12 bit) and vp9
encoding improvements.
- Upgrading:
This release is ABI incompatible due to new vp9 encoder features.
Frame parallel decoding for vp9 has been removed.
- Enhancements:
vp9 encoding supports additional threads with --row-mt. This can be greater
than the number of tiles.
Two new vp9 encoder options have been added:
--corpus-complexity
--tune-content=film
Additional tooling for respecting the vp9 "level" profiles has been added.
- Bug fixes:
A variety of fuzzing issues.
vp8 threading fix for ARM.
Codec control VP9_SET_SKIP_LOOP_FILTER fixed.
Reject invalid multi resolution configurations.
2017-01-09 v1.6.1 "Long Tailed Duck"
This release improves upon the VP9 encoder and speeds up the encoding and
decoding processes.
- Upgrading:
This release is ABI compatible with 1.6.0.
- Enhancements:
Faster VP9 encoding and decoding.
High bit depth builds now provide similar speed for 8 bit encode and decode
for x86 targets. Other platforms and higher bit depth improvements are in
progress.
- Bug Fixes:
A variety of fuzzing issues.
2016-07-20 v1.6.0 "Khaki Campbell Duck"
This release improves upon the VP9 encoder and speeds up the encoding and
decoding processes.
- Upgrading:
This release is ABI incompatible with 1.5.0 due to a new 'color_range' enum
in vpx_image and some minor changes to the VP8_COMP structure.
The default key frame interval for VP9 has changed from 128 to 9999.
- Enhancement:
A core focus has been performance for low end Intel processors. SSSE3
instructions such as 'pshufb' have been avoided and instructions have been
reordered to better accommodate the more constrained pipelines.
As a result, devices based on Celeron processors have seen substantial
decoding improvements. From Indian Runner Duck to Javan Whistling Duck,
decoding speed improved between 10 and 30%. Between Javan Whistling Duck
and Khaki Campbell Duck, it improved another 10 to 15%.
While Celeron benefited most, Core-i5 also improved 5% and 10% between the
respective releases.
Realtime performance for WebRTC for both speed and quality has received a
lot of attention.
- Bug Fixes:
A number of fuzzing issues, found variously by Mozilla, Chromium and others,
have been fixed and we strongly recommend updating.
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" 2015-04-03 v1.4.0 "Indian Runner Duck"
This release includes significant improvements to the VP9 codec. This release includes significant improvements to the VP9 codec.

86
README
View File

@ -1,4 +1,4 @@
README - 24 January 2018 README - 23 March 2015
Welcome to the WebM VP8/VP9 Codec SDK! Welcome to the WebM VP8/VP9 Codec SDK!
@ -9,26 +9,22 @@ COMPILING THE APPLICATIONS/LIBRARIES:
1. Prerequisites 1. Prerequisites
* All x86 targets require the Yasm[1] assembler be installed[2]. * All x86 targets require the Yasm[1] assembler be installed.
* All Windows builds require that Cygwin[3] be installed. * All Windows builds require that Cygwin[2] be installed.
* Building the documentation requires Doxygen[4]. If you do not * Building the documentation requires Doxygen[3]. If you do not
have this package, the install-docs option will be disabled. have this package, the install-docs option will be disabled.
* Downloading the data for the unit tests requires curl[5] and sha1sum. * Downloading the data for the unit tests requires curl[4] and sha1sum.
sha1sum is provided via the GNU coreutils, installed by default on sha1sum is provided via the GNU coreutils, installed by default on
many *nix platforms, as well as MinGW and Cygwin. If coreutils is not many *nix platforms, as well as MinGW and Cygwin. If coreutils is not
available, a compatible version of sha1sum can be built from available, a compatible version of sha1sum can be built from
source[6]. These requirements are optional if not running the unit source[5]. These requirements are optional if not running the unit
tests. tests.
[1]: http://www.tortall.net/projects/yasm [1]: http://www.tortall.net/projects/yasm
[2]: For Visual Studio the base yasm binary (not vsyasm) should be in the [2]: http://www.cygwin.com
PATH for Visual Studio. For VS2017 it is sufficient to rename [3]: http://www.doxygen.org
yasm-<version>-<arch>.exe to yasm.exe and place it in: [4]: http://curl.haxx.se
Program Files (x86)/Microsoft Visual Studio/2017/<level>/Common7/Tools/ [5]: http://www.microbrew.org/tools/md5sha1sum/
[3]: http://www.cygwin.com
[4]: http://www.doxygen.org
[5]: http://curl.haxx.se
[6]: http://www.microbrew.org/tools/md5sha1sum/
2. Out-of-tree builds 2. Out-of-tree builds
Out of tree builds are a supported method of building the application. For Out of tree builds are a supported method of building the application. For
@ -45,24 +41,17 @@ COMPILING THE APPLICATIONS/LIBRARIES:
used to get a list of supported options: used to get a list of supported options:
$ ../libvpx/configure --help $ ../libvpx/configure --help
4. Compiler analyzers 4. Cross development
Compilers have added sanitizers which instrument binaries with information
about address calculation, memory usage, threading, undefined behavior, and
other common errors. To simplify building libvpx with some of these features
use tools/set_analyzer_env.sh before running configure. It will set the
compiler and necessary flags for building as well as environment variables
read by the analyzer when testing the binaries.
$ source ../libvpx/tools/set_analyzer_env.sh address
5. Cross development
For cross development, the most notable option is the --target option. The For cross development, the most notable option is the --target option. The
most up-to-date list of supported targets can be found at the bottom of the most up-to-date list of supported targets can be found at the bottom of the
--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:
arm64-android-gcc armv6-darwin-gcc
armv6-linux-rvct
armv6-linux-gcc
armv6-none-rvct
arm64-darwin-gcc arm64-darwin-gcc
arm64-linux-gcc
armv7-android-gcc armv7-android-gcc
armv7-darwin-gcc armv7-darwin-gcc
armv7-linux-rvct armv7-linux-rvct
@ -70,14 +59,9 @@ 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
armv7-win32-vs15
armv7s-darwin-gcc armv7s-darwin-gcc
armv8-linux-gcc
mips32-linux-gcc mips32-linux-gcc
mips64-linux-gcc mips64-linux-gcc
ppc64-linux-gcc
ppc64le-linux-gcc
sparc-solaris-gcc sparc-solaris-gcc
x86-android-gcc x86-android-gcc
x86-darwin8-gcc x86-darwin8-gcc
@ -89,38 +73,41 @@ COMPILING THE APPLICATIONS/LIBRARIES:
x86-darwin12-gcc x86-darwin12-gcc
x86-darwin13-gcc x86-darwin13-gcc
x86-darwin14-gcc x86-darwin14-gcc
x86-darwin15-gcc
x86-darwin16-gcc
x86-iphonesimulator-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-win32-vs15
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-darwin14-gcc
x86_64-darwin15-gcc
x86_64-darwin16-gcc
x86_64-iphonesimulator-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
x86_64-win64-vs15 universal-darwin9-gcc
universal-darwin10-gcc
universal-darwin11-gcc
universal-darwin12-gcc
universal-darwin13-gcc
universal-darwin14-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,
@ -136,7 +123,7 @@ COMPILING THE APPLICATIONS/LIBRARIES:
environment variables: CC, AR, LD, AS, STRIP, NM. Additional flags can be environment variables: CC, AR, LD, AS, STRIP, NM. Additional flags can be
passed to these executables with CFLAGS, LDFLAGS, and ASFLAGS. passed to these executables with CFLAGS, LDFLAGS, and ASFLAGS.
6. Configuration errors 5. Configuration errors
If the configuration step fails, the first step is to look in the error log. If the configuration step fails, the first step is to look in the error log.
This defaults to config.log. This should give a good indication of what went This defaults to config.log. This should give a good indication of what went
wrong. If not, contact us for support. wrong. If not, contact us for support.
@ -149,22 +136,7 @@ VP8/VP9 TEST VECTORS:
$ ./configure --enable-unit-tests $ ./configure --enable-unit-tests
$ LIBVPX_TEST_DATA_PATH=../libvpx-test-data make testdata $ LIBVPX_TEST_DATA_PATH=../libvpx-test-data make testdata
CODE STYLE:
The coding style used by this project is enforced with clang-format using the
configuration contained in the .clang-format file in the root of the
repository.
Before pushing changes for review you can format your code with:
# Apply clang-format to modified .c, .h and .cc files
$ clang-format -i --style=file \
$(git diff --name-only --diff-filter=ACMR '*.[hc]' '*.cc')
Check the .clang-format file for the version used to generate it if there is
any difference between your local formatting and the review system.
See also: http://clang.llvm.org/docs/ClangFormat.html
SUPPORT SUPPORT
This library is an open source project supported by its community. Please This library is an open source project supported by its community. Please
email webm-discuss@webmproject.org for help. please email webm-discuss@webmproject.org for help.

131
args.c
View File

@ -8,13 +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 <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include "args.h" #include "args.h"
#include "vpx/vpx_integer.h" #ifdef _MSC_VER
#include "vpx_ports/msvc.h" #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));
@ -22,36 +24,42 @@ extern void die(const char *fmt, ...) __attribute__((noreturn));
extern void die(const char *fmt, ...); extern void die(const char *fmt, ...);
#endif #endif
struct arg arg_init(char **argv) { struct arg arg_init(char **argv) {
struct arg a; struct arg a;
a.argv = argv; a.argv = argv;
a.argv_step = 1; a.argv_step = 1;
a.name = NULL; a.name = NULL;
a.val = NULL; a.val = NULL;
a.def = NULL; a.def = NULL;
return a; return a;
} }
int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) { int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) {
struct arg arg; struct arg arg;
if (!argv[0] || argv[0][0] != '-') return 0; if (!argv[0] || argv[0][0] != '-')
return 0;
arg = arg_init(argv); arg = arg_init(argv);
if (def->short_name && strlen(arg.argv[0]) == strlen(def->short_name) + 1 && if (def->short_name
!strcmp(arg.argv[0] + 1, def->short_name)) { && strlen(arg.argv[0]) == strlen(def->short_name) + 1
&& !strcmp(arg.argv[0] + 1, def->short_name)) {
arg.name = arg.argv[0] + 1; arg.name = arg.argv[0] + 1;
arg.val = def->has_val ? arg.argv[1] : NULL; arg.val = def->has_val ? arg.argv[1] : NULL;
arg.argv_step = def->has_val ? 2 : 1; arg.argv_step = def->has_val ? 2 : 1;
} else if (def->long_name) { } else if (def->long_name) {
const size_t name_len = strlen(def->long_name); const size_t name_len = strlen(def->long_name);
if (strlen(arg.argv[0]) >= name_len + 2 && arg.argv[0][1] == '-' && if (strlen(arg.argv[0]) >= name_len + 2
!strncmp(arg.argv[0] + 2, def->long_name, name_len) && && arg.argv[0][1] == '-'
(arg.argv[0][name_len + 2] == '=' || && !strncmp(arg.argv[0] + 2, def->long_name, name_len)
arg.argv[0][name_len + 2] == '\0')) { && (arg.argv[0][name_len + 2] == '='
|| arg.argv[0][name_len + 2] == '\0')) {
arg.name = arg.argv[0] + 2; arg.name = arg.argv[0] + 2;
arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL; arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL;
arg.argv_step = 1; arg.argv_step = 1;
@ -64,7 +72,8 @@ int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) {
if (arg.name && arg.val && !def->has_val) if (arg.name && arg.val && !def->has_val)
die("Error: option %s requires no argument.\n", arg.name); die("Error: option %s requires no argument.\n", arg.name);
if (arg.name && (arg.val || !def->has_val)) { if (arg.name
&& (arg.val || !def->has_val)) {
arg.def = def; arg.def = def;
*arg_ = arg; *arg_ = arg;
return 1; return 1;
@ -73,12 +82,15 @@ int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) {
return 0; return 0;
} }
const char *arg_next(struct arg *arg) { const char *arg_next(struct arg *arg) {
if (arg->argv[0]) arg->argv += arg->argv_step; if (arg->argv[0])
arg->argv += arg->argv_step;
return *arg->argv; return *arg->argv;
} }
char **argv_dup(int argc, const char **argv) { char **argv_dup(int argc, const char **argv) {
char **new_argv = malloc((argc + 1) * sizeof(*argv)); char **new_argv = malloc((argc + 1) * sizeof(*argv));
@ -87,8 +99,9 @@ char **argv_dup(int argc, const char **argv) {
return new_argv; return new_argv;
} }
void arg_show_usage(FILE *fp, const struct arg_def *const *defs) { void arg_show_usage(FILE *fp, const struct arg_def *const *defs) {
char option_text[40] = { 0 }; char option_text[40] = {0};
for (; *defs; defs++) { for (; *defs; defs++) {
const struct arg_def *def = *defs; const struct arg_def *def = *defs;
@ -98,12 +111,15 @@ void arg_show_usage(FILE *fp, const struct arg_def *const *defs) {
if (def->short_name && def->long_name) { if (def->short_name && def->long_name) {
char *comma = def->has_val ? "," : ", "; char *comma = def->has_val ? "," : ", ";
snprintf(option_text, 37, "-%s%s%s --%s%6s", def->short_name, short_val, snprintf(option_text, 37, "-%s%s%s --%s%6s",
comma, def->long_name, long_val); def->short_name, short_val, comma,
def->long_name, long_val);
} else if (def->short_name) } else if (def->short_name)
snprintf(option_text, 37, "-%s%s", def->short_name, short_val); snprintf(option_text, 37, "-%s%s",
def->short_name, short_val);
else if (def->long_name) else if (def->long_name)
snprintf(option_text, 37, " --%s%s", def->long_name, long_val); snprintf(option_text, 37, " --%s%s",
def->long_name, long_val);
fprintf(fp, " %-37s\t%s\n", option_text, def->desc); fprintf(fp, " %-37s\t%s\n", option_text, def->desc);
@ -113,103 +129,110 @@ void arg_show_usage(FILE *fp, const struct arg_def *const *defs) {
fprintf(fp, " %-37s\t ", ""); fprintf(fp, " %-37s\t ", "");
for (listptr = def->enums; listptr->name; listptr++) for (listptr = def->enums; listptr->name; listptr++)
fprintf(fp, "%s%s", listptr->name, listptr[1].name ? ", " : "\n"); fprintf(fp, "%s%s", listptr->name,
listptr[1].name ? ", " : "\n");
} }
} }
} }
unsigned int arg_parse_uint(const struct arg *arg) {
uint32_t rawval;
char *endptr;
rawval = (uint32_t)strtoul(arg->val, &endptr, 10); unsigned int arg_parse_uint(const struct arg *arg) {
long int rawval;
char *endptr;
rawval = strtol(arg->val, &endptr, 10);
if (arg->val[0] != '\0' && endptr[0] == '\0') { if (arg->val[0] != '\0' && endptr[0] == '\0') {
if (rawval <= UINT_MAX) return rawval; if (rawval >= 0 && rawval <= UINT_MAX)
return rawval;
die("Option %s: Value %ld out of range for unsigned int\n", arg->name, die("Option %s: Value %ld out of range for unsigned int\n",
rawval); arg->name, rawval);
} }
die("Option %s: Invalid character '%c'\n", arg->name, *endptr); die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
return 0; return 0;
} }
int arg_parse_int(const struct arg *arg) { int arg_parse_int(const struct arg *arg) {
int32_t rawval; long int rawval;
char *endptr; char *endptr;
rawval = (int32_t)strtol(arg->val, &endptr, 10); rawval = strtol(arg->val, &endptr, 10);
if (arg->val[0] != '\0' && endptr[0] == '\0') { if (arg->val[0] != '\0' && endptr[0] == '\0') {
if (rawval >= INT_MIN && rawval <= INT_MAX) return (int)rawval; if (rawval >= INT_MIN && rawval <= INT_MAX)
return rawval;
die("Option %s: Value %ld out of range for signed int\n", arg->name, die("Option %s: Value %ld out of range for signed int\n",
rawval); arg->name, rawval);
} }
die("Option %s: Invalid character '%c'\n", arg->name, *endptr); die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
return 0; return 0;
} }
struct vpx_rational { struct vpx_rational {
int num; /**< fraction numerator */ int num; /**< fraction numerator */
int den; /**< fraction denominator */ int den; /**< fraction denominator */
}; };
struct vpx_rational arg_parse_rational(const struct arg *arg) { struct vpx_rational arg_parse_rational(const struct arg *arg) {
long int rawval; long int rawval;
char *endptr; char *endptr;
struct vpx_rational rat; struct vpx_rational rat;
/* parse numerator */ /* parse numerator */
rawval = strtol(arg->val, &endptr, 10); rawval = strtol(arg->val, &endptr, 10);
if (arg->val[0] != '\0' && endptr[0] == '/') { if (arg->val[0] != '\0' && endptr[0] == '/') {
if (rawval >= INT_MIN && rawval <= INT_MAX) if (rawval >= INT_MIN && rawval <= INT_MAX)
rat.num = (int)rawval; rat.num = rawval;
else else die("Option %s: Value %ld out of range for signed int\n",
die("Option %s: Value %ld out of range for signed int\n", arg->name, arg->name, rawval);
rawval); } else die("Option %s: Expected / at '%c'\n", arg->name, *endptr);
} else
die("Option %s: Expected / at '%c'\n", arg->name, *endptr);
/* parse denominator */ /* parse denominator */
rawval = strtol(endptr + 1, &endptr, 10); rawval = strtol(endptr + 1, &endptr, 10);
if (arg->val[0] != '\0' && endptr[0] == '\0') { if (arg->val[0] != '\0' && endptr[0] == '\0') {
if (rawval >= INT_MIN && rawval <= INT_MAX) if (rawval >= INT_MIN && rawval <= INT_MAX)
rat.den = (int)rawval; rat.den = rawval;
else else die("Option %s: Value %ld out of range for signed int\n",
die("Option %s: Value %ld out of range for signed int\n", arg->name, arg->name, rawval);
rawval); } else die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
} else
die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
return rat; return rat;
} }
int arg_parse_enum(const struct arg *arg) { int arg_parse_enum(const struct arg *arg) {
const struct arg_enum_list *listptr; const struct arg_enum_list *listptr;
long int rawval; long int rawval;
char *endptr; char *endptr;
/* First see if the value can be parsed as a raw value */ /* First see if the value can be parsed as a raw value */
rawval = strtol(arg->val, &endptr, 10); rawval = strtol(arg->val, &endptr, 10);
if (arg->val[0] != '\0' && endptr[0] == '\0') { if (arg->val[0] != '\0' && endptr[0] == '\0') {
/* Got a raw value, make sure it's valid */ /* Got a raw value, make sure it's valid */
for (listptr = arg->def->enums; listptr->name; listptr++) for (listptr = arg->def->enums; listptr->name; listptr++)
if (listptr->val == rawval) return (int)rawval; if (listptr->val == rawval)
return rawval;
} }
/* Next see if it can be parsed as a string */ /* Next see if it can be parsed as a string */
for (listptr = arg->def->enums; listptr->name; listptr++) for (listptr = arg->def->enums; listptr->name; listptr++)
if (!strcmp(arg->val, listptr->name)) return listptr->val; if (!strcmp(arg->val, listptr->name))
return listptr->val;
die("Option %s: Invalid value '%s'\n", arg->name, arg->val); die("Option %s: Invalid value '%s'\n", arg->name, arg->val);
return 0; return 0;
} }
int arg_parse_enum_or_int(const struct arg *arg) { int arg_parse_enum_or_int(const struct arg *arg) {
if (arg->def->enums) return arg_parse_enum(arg); if (arg->def->enums)
return arg_parse_enum(arg);
return arg_parse_int(arg); return arg_parse_int(arg);
} }

27
args.h
View File

@ -8,6 +8,7 @@
* 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.
*/ */
#ifndef ARGS_H_ #ifndef ARGS_H_
#define ARGS_H_ #define ARGS_H_
#include <stdio.h> #include <stdio.h>
@ -17,33 +18,29 @@ extern "C" {
#endif #endif
struct arg { struct arg {
char **argv; char **argv;
const char *name; const char *name;
const char *val; const char *val;
unsigned int argv_step; unsigned int argv_step;
const struct arg_def *def; const struct arg_def *def;
}; };
struct arg_enum_list { struct arg_enum_list {
const char *name; const char *name;
int val; int val;
}; };
#define ARG_ENUM_LIST_END \ #define ARG_ENUM_LIST_END {0}
{ 0 }
typedef struct arg_def { typedef struct arg_def {
const char *short_name; const char *short_name;
const char *long_name; const char *long_name;
int has_val; int has_val;
const char *desc; const char *desc;
const struct arg_enum_list *enums; const struct arg_enum_list *enums;
} arg_def_t; } arg_def_t;
#define ARG_DEF(s, l, v, d) \ #define ARG_DEF(s,l,v,d) {s,l,v,d, NULL}
{ s, l, v, d, NULL } #define ARG_DEF_ENUM(s,l,v,d,e) {s,l,v,d,e}
#define ARG_DEF_ENUM(s, l, v, d, e) \ #define ARG_DEF_LIST_END {0}
{ s, l, v, d, e }
#define ARG_DEF_LIST_END \
{ 0 }
struct arg arg_init(char **argv); struct arg arg_init(char **argv);
int arg_match(struct arg *arg_, const struct arg_def *def, char **argv); int arg_match(struct arg *arg_, const struct arg_def *def, char **argv);

2
build/.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
*-vs8/*.rules -crlf
*-msvs/*.rules -crlf

1
build/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
x86*-win32-vs*

View File

@ -29,6 +29,11 @@
# include $(CLEAR_VARS) # include $(CLEAR_VARS)
# include jni/libvpx/build/make/Android.mk # include jni/libvpx/build/make/Android.mk
# #
# There are currently two TARGET_ARCH_ABI targets for ARM.
# armeabi and armeabi-v7a. armeabi-v7a is selected by creating an
# Application.mk in the jni directory that contains:
# APP_ABI := armeabi-v7a
#
# By default libvpx will detect at runtime the existance of NEON extension. # By default libvpx will detect at runtime the existance of NEON extension.
# For this we import the 'cpufeatures' module from the NDK sources. # For this we import the 'cpufeatures' module from the NDK sources.
# libvpx can also be configured without this runtime detection method. # libvpx can also be configured without this runtime detection method.
@ -37,49 +42,31 @@
# --disable-neon-asm # --disable-neon-asm
# will remove any NEON dependency. # will remove any NEON dependency.
# To change to building armeabi, run ./libvpx/configure again, but with
# --target=armv6-android-gcc and modify the Application.mk file to
# 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.
# #
# Alternatively, building the examples and unit tests can be accomplished in the
# following way:
#
# Create a standalone toolchain from the NDK:
# https://developer.android.com/ndk/guides/standalone_toolchain.html
#
# For example - to test on arm64 devices with clang:
# $NDK/build/tools/make_standalone_toolchain.py \
# --arch arm64 --install-dir=/tmp/my-android-toolchain
# export PATH=/tmp/my-android-toolchain/bin:$PATH
# CROSS=aarch64-linux-android- CC=clang CXX=clang++ /path/to/libvpx/configure \
# --target=arm64-android-gcc
#
# Push the resulting binaries to a device and run them:
# adb push test_libvpx /data/tmp/test_libvpx
# adb shell /data/tmp/test_libvpx --gtest_filter=\*Sixtap\*
#
# Make sure to push the test data as well and set LIBVPX_TEST_DATA
CONFIG_DIR := $(LOCAL_PATH)/ CONFIG_DIR := $(LOCAL_PATH)/
LIBVPX_PATH := $(LOCAL_PATH)/libvpx LIBVPX_PATH := $(LOCAL_PATH)/libvpx
ASM_CNV_PATH_LOCAL := $(TARGET_ARCH_ABI)/ads2gas ASM_CNV_PATH_LOCAL := $(TARGET_ARCH_ABI)/ads2gas
ASM_CNV_PATH := $(LOCAL_PATH)/$(ASM_CNV_PATH_LOCAL) ASM_CNV_PATH := $(LOCAL_PATH)/$(ASM_CNV_PATH_LOCAL)
ifneq ($(V),1)
qexec := @
endif
# Use the makefiles generated by upstream configure to determine which files to # Use the makefiles generated by upstream configure to determine which files to
# build. Also set any architecture-specific flags. # build. Also set any architecture-specific flags.
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) 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)
include $(CONFIG_DIR)libs-armv6-android-gcc.mk
LOCAL_ARM_MODE := arm
else ifeq ($(TARGET_ARCH_ABI),arm64-v8a) else ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
include $(CONFIG_DIR)libs-arm64-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
@ -104,10 +91,10 @@ 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)
.PRECIOUS: %.asm.S .PRECIOUS: %.asm.s
$(ASM_CNV_PATH)/libvpx/%.asm.S: $(LIBVPX_PATH)/%.asm $(ASM_CNV_PATH)/libvpx/%.asm.s: $(LIBVPX_PATH)/%.asm
$(qexec)mkdir -p $(dir $@) @mkdir -p $(dir $@)
$(qexec)$(CONFIG_DIR)$(ASM_CONVERSION) <$< > $@ @$(CONFIG_DIR)$(ASM_CONVERSION) <$< > $@
# For building *_rtcd.h, which have rules in libs.mk # For building *_rtcd.h, which have rules in libs.mk
TGT_ISA:=$(word 1, $(subst -, ,$(TOOLCHAIN))) TGT_ISA:=$(word 1, $(subst -, ,$(TOOLCHAIN)))
@ -135,7 +122,7 @@ endif
# Pull out assembly files, splitting NEON from the rest. This is # Pull out assembly files, splitting NEON from the rest. This is
# done to specify that the NEON assembly files use NEON assembler flags. # done to specify that the NEON assembly files use NEON assembler flags.
# x86 assembly matches %.asm, arm matches %.asm.S # x86 assembly matches %.asm, arm matches %.asm.s
# x86: # x86:
@ -143,44 +130,31 @@ CODEC_SRCS_ASM_X86 = $(filter %.asm, $(CODEC_SRCS_UNIQUE))
LOCAL_SRC_FILES += $(foreach file, $(CODEC_SRCS_ASM_X86), libvpx/$(file)) LOCAL_SRC_FILES += $(foreach file, $(CODEC_SRCS_ASM_X86), libvpx/$(file))
# arm: # arm:
CODEC_SRCS_ASM_ARM_ALL = $(filter %.asm.S, $(CODEC_SRCS_UNIQUE)) CODEC_SRCS_ASM_ARM_ALL = $(filter %.asm.s, $(CODEC_SRCS_UNIQUE))
CODEC_SRCS_ASM_ARM = $(foreach v, \ CODEC_SRCS_ASM_ARM = $(foreach v, \
$(CODEC_SRCS_ASM_ARM_ALL), \ $(CODEC_SRCS_ASM_ARM_ALL), \
$(if $(findstring neon,$(v)),,$(v))) $(if $(findstring neon,$(v)),,$(v)))
CODEC_SRCS_ASM_ADS2GAS = $(patsubst %.S, \ CODEC_SRCS_ASM_ADS2GAS = $(patsubst %.s, \
$(ASM_CNV_PATH_LOCAL)/libvpx/%.S, \ $(ASM_CNV_PATH_LOCAL)/libvpx/%.s, \
$(CODEC_SRCS_ASM_ARM)) $(CODEC_SRCS_ASM_ARM))
LOCAL_SRC_FILES += $(CODEC_SRCS_ASM_ADS2GAS) LOCAL_SRC_FILES += $(CODEC_SRCS_ASM_ADS2GAS)
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
ASM_INCLUDES := vpx_dsp/arm/idct_neon.asm.S
CODEC_SRCS_ASM_NEON = $(foreach v, \ CODEC_SRCS_ASM_NEON = $(foreach v, \
$(CODEC_SRCS_ASM_ARM_ALL),\ $(CODEC_SRCS_ASM_ARM_ALL),\
$(if $(findstring neon,$(v)),$(v),)) $(if $(findstring neon,$(v)),$(v),))
CODEC_SRCS_ASM_NEON := $(filter-out $(addprefix %, $(ASM_INCLUDES)), \ CODEC_SRCS_ASM_NEON_ADS2GAS = $(patsubst %.s, \
$(CODEC_SRCS_ASM_NEON)) $(ASM_CNV_PATH_LOCAL)/libvpx/%.s, \
CODEC_SRCS_ASM_NEON_ADS2GAS = $(patsubst %.S, \
$(ASM_CNV_PATH_LOCAL)/libvpx/%.S, \
$(CODEC_SRCS_ASM_NEON)) $(CODEC_SRCS_ASM_NEON))
LOCAL_SRC_FILES += $(patsubst %.S, \ LOCAL_SRC_FILES += $(patsubst %.s, \
%.S.neon, \ %.s.neon, \
$(CODEC_SRCS_ASM_NEON_ADS2GAS)) $(CODEC_SRCS_ASM_NEON_ADS2GAS))
NEON_ASM_TARGETS = $(patsubst %.S, \
$(ASM_CNV_PATH)/libvpx/%.S, \
$(CODEC_SRCS_ASM_NEON))
# add a dependency to the full path to the ads2gas output to ensure the
# includes are converted first.
ifneq ($(strip $(NEON_ASM_TARGETS)),)
$(NEON_ASM_TARGETS): $(addprefix $(ASM_CNV_PATH)/libvpx/, $(ASM_INCLUDES))
endif
endif endif
LOCAL_CFLAGS += \ LOCAL_CFLAGS += \
-DHAVE_CONFIG_H=vpx_config.h \ -DHAVE_CONFIG_H=vpx_config.h \
-I$(LIBVPX_PATH) \ -I$(LIBVPX_PATH) \
-I$(ASM_CNV_PATH) \ -I$(ASM_CNV_PATH)
-I$(ASM_CNV_PATH)/libvpx
LOCAL_MODULE := libvpx LOCAL_MODULE := libvpx
@ -189,40 +163,31 @@ ifeq ($(CONFIG_RUNTIME_CPU_DETECT),yes)
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
rtcd_dep_template_SRCS := $(addprefix $(LOCAL_PATH)/, $(LOCAL_SRC_FILES))
rtcd_dep_template_SRCS := $$(rtcd_dep_template_SRCS:.neon=)
ifeq ($(CONFIG_VP8), yes) ifeq ($(CONFIG_VP8), yes)
$$(rtcd_dep_template_SRCS): vp8_rtcd.h $(foreach file, $(LOCAL_SRC_FILES), $(LOCAL_PATH)/$(file)): vp8_rtcd.h
endif endif
ifeq ($(CONFIG_VP9), yes) ifeq ($(CONFIG_VP9), yes)
$$(rtcd_dep_template_SRCS): vp9_rtcd.h $(foreach file, $(LOCAL_SRC_FILES), $(LOCAL_PATH)/$(file)): vp9_rtcd.h
endif endif
$$(rtcd_dep_template_SRCS): vpx_scale_rtcd.h $(foreach file, $(LOCAL_SRC_FILES), $(LOCAL_PATH)/$(file)): vpx_scale_rtcd.h
$$(rtcd_dep_template_SRCS): vpx_dsp_rtcd.h
rtcd_dep_template_CONFIG_ASM_ABIS := x86 x86_64 armeabi-v7a ifeq ($(TARGET_ARCH_ABI),x86)
ifneq ($$(findstring $(TARGET_ARCH_ABI),$$(rtcd_dep_template_CONFIG_ASM_ABIS)),) $(foreach file, $(LOCAL_SRC_FILES), $(LOCAL_PATH)/$(file)): vpx_config.asm
$$(rtcd_dep_template_SRCS): vpx_config.asm
endif endif
endef
$(eval $(call rtcd_dep_template))
.PHONY: clean .PHONY: clean
clean: clean:
@echo "Clean: ads2gas files [$(TARGET_ARCH_ABI)]" @echo "Clean: ads2gas files [$(TARGET_ARCH_ABI)]"
$(qexec)$(RM) $(CODEC_SRCS_ASM_ADS2GAS) $(CODEC_SRCS_ASM_NEON_ADS2GAS) @$(RM) $(CODEC_SRCS_ASM_ADS2GAS) $(CODEC_SRCS_ASM_NEON_ADS2GAS)
$(qexec)$(RM) -r $(ASM_CNV_PATH) @$(RM) -r $(ASM_CNV_PATH)
$(qexec)$(RM) $(CLEAN-OBJS) @$(RM) $(CLEAN-OBJS)
ifeq ($(ENABLE_SHARED),1) ifeq ($(ENABLE_SHARED),1)
LOCAL_CFLAGS += -fPIC
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)
else else
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
endif endif
ifeq ($(CONFIG_RUNTIME_CPU_DETECT),yes) ifeq ($(CONFIG_RUNTIME_CPU_DETECT),yes)
$(call import-module,android/cpufeatures) $(call import-module,cpufeatures)
endif endif

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)
@ -90,7 +91,7 @@ all:
.PHONY: clean .PHONY: clean
clean:: clean::
rm -f $(OBJS-yes) $(OBJS-yes:.o=.d) $(OBJS-yes:.asm.S.o=.asm.S) rm -f $(OBJS-yes) $(OBJS-yes:.o=.d) $(OBJS-yes:.asm.s.o=.asm.s)
rm -f $(CLEAN-OBJS) rm -f $(CLEAN-OBJS)
.PHONY: clean .PHONY: clean
@ -115,36 +116,28 @@ 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 # Add compiler flags for intrinsic files
ifeq ($(TOOLCHAIN), x86-os2-gcc) ifeq ($(TOOLCHAIN), x86-os2-gcc)
CFLAGS += -mstackrealign STACKREALIGN=-mstackrealign
else
STACKREALIGN=
endif endif
# x86[_64]
$(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 $(STACKREALIGN)
$(BUILD_PFX)%_sse2.c.o: CFLAGS += -msse2 $(BUILD_PFX)%_sse2.c.o: CFLAGS += -msse2 $(STACKREALIGN)
$(BUILD_PFX)%_sse3.c.d: CFLAGS += -msse3 $(BUILD_PFX)%_sse3.c.d: CFLAGS += -msse3 $(STACKREALIGN)
$(BUILD_PFX)%_sse3.c.o: CFLAGS += -msse3 $(BUILD_PFX)%_sse3.c.o: CFLAGS += -msse3 $(STACKREALIGN)
$(BUILD_PFX)%_ssse3.c.d: CFLAGS += -mssse3 $(BUILD_PFX)%_ssse3.c.d: CFLAGS += -mssse3 $(STACKREALIGN)
$(BUILD_PFX)%_ssse3.c.o: CFLAGS += -mssse3 $(BUILD_PFX)%_ssse3.c.o: CFLAGS += -mssse3 $(STACKREALIGN)
$(BUILD_PFX)%_sse4.c.d: CFLAGS += -msse4.1 $(BUILD_PFX)%_sse4.c.d: CFLAGS += -msse4.1 $(STACKREALIGN)
$(BUILD_PFX)%_sse4.c.o: CFLAGS += -msse4.1 $(BUILD_PFX)%_sse4.c.o: CFLAGS += -msse4.1 $(STACKREALIGN)
$(BUILD_PFX)%_avx.c.d: CFLAGS += -mavx $(BUILD_PFX)%_avx.c.d: CFLAGS += -mavx $(STACKREALIGN)
$(BUILD_PFX)%_avx.c.o: CFLAGS += -mavx $(BUILD_PFX)%_avx.c.o: CFLAGS += -mavx $(STACKREALIGN)
$(BUILD_PFX)%_avx2.c.d: CFLAGS += -mavx2 $(BUILD_PFX)%_avx2.c.d: CFLAGS += -mavx2 $(STACKREALIGN)
$(BUILD_PFX)%_avx2.c.o: CFLAGS += -mavx2 $(BUILD_PFX)%_avx2.c.o: CFLAGS += -mavx2 $(STACKREALIGN)
$(BUILD_PFX)%_avx512.c.d: CFLAGS += -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl
$(BUILD_PFX)%_avx512.c.o: CFLAGS += -mavx512f -mavx512cd -mavx512bw -mavx512dq -mavx512vl
# POWER
$(BUILD_PFX)%_vsx.c.d: CFLAGS += -maltivec -mvsx
$(BUILD_PFX)%_vsx.c.o: CFLAGS += -maltivec -mvsx
$(BUILD_PFX)%.c.d: %.c $(BUILD_PFX)%.c.d: %.c
$(if $(quiet),@echo " [DEP] $@") $(if $(quiet),@echo " [DEP] $@")
@ -187,13 +180,13 @@ $(BUILD_PFX)%.asm.o: %.asm
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@)) $(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
$(if $(quiet),@echo " [DEP] $@") $(if $(quiet),@echo " [DEP] $@")
$(qexec)mkdir -p $(dir $@) $(qexec)mkdir -p $(dir $@)
$(qexec)$(SRC_PATH_BARE)/build/make/gen_asm_deps.sh \ $(qexec)$(SRC_PATH_BARE)/build/make/gen_asm_deps.sh \
--build-pfx=$(BUILD_PFX) --depfile=$@ $(ASFLAGS) $< > $@ --build-pfx=$(BUILD_PFX) --depfile=$@ $(ASFLAGS) $< > $@
$(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)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
$(qexec)$(AS) $(ASFLAGS) -o $@ $< $(qexec)$(AS) $(ASFLAGS) -o $@ $<
@ -205,8 +198,8 @@ $(BUILD_PFX)%.c.S: %.c
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@)) $(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
$(qexec)$(CC) -S $(CFLAGS) -o $@ $< $(qexec)$(CC) -S $(CFLAGS) -o $@ $<
.PRECIOUS: %.asm.S .PRECIOUS: %.asm.s
$(BUILD_PFX)%.asm.S: %.asm $(BUILD_PFX)%.asm.s: %.asm
$(if $(quiet),@echo " [ASM CONVERSION] $@") $(if $(quiet),@echo " [ASM CONVERSION] $@")
$(qexec)mkdir -p $(dir $@) $(qexec)mkdir -p $(dir $@)
$(qexec)$(ASM_CONVERSION) <$< >$@ $(qexec)$(ASM_CONVERSION) <$< >$@
@ -290,7 +283,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
@ -320,15 +313,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
@ -389,7 +385,6 @@ LIBS=$(call enabled,LIBS)
$(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.$(SO_VERSION_MAJOR).$(SO_VERSION_MINOR).$(SO_VERSION_PATCH),$(LIBS)),$(eval $(call so_template,$(lib))))
$(foreach lib,$(filter %$(SO_VERSION_MAJOR).dylib,$(LIBS)),$(eval $(call dl_template,$(lib)))) $(foreach lib,$(filter %$(SO_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)
@ -425,6 +420,7 @@ 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
@ -455,5 +451,3 @@ all: $(BUILD_TARGETS)
install:: $(INSTALL_TARGETS) install:: $(INSTALL_TARGETS)
dist: $(INSTALL_TARGETS) dist: $(INSTALL_TARGETS)
test:: test::
.SUFFIXES: # Delete default suffix rules

View File

@ -23,11 +23,9 @@ use lib $FindBin::Bin;
use thumb; use thumb;
my $thumb = 0; my $thumb = 0;
my $elf = 1;
foreach my $arg (@ARGV) { foreach my $arg (@ARGV) {
$thumb = 1 if ($arg eq "-thumb"); $thumb = 1 if ($arg eq "-thumb");
$elf = 0 if ($arg eq "-noelf");
} }
print "@ This file was created from a .asm file\n"; print "@ This file was created from a .asm file\n";
@ -140,13 +138,17 @@ while (<STDIN>)
s/DCD(.*)/.long $1/; s/DCD(.*)/.long $1/;
s/DCB(.*)/.byte $1/; s/DCB(.*)/.byte $1/;
# RN to .req
if (s/RN\s+([Rr]\d+|lr)/.req $1/)
{
print;
print "$comment_sub$comment\n" if defined $comment;
next;
}
# Make function visible to linker, and make additional symbol with # Make function visible to linker, and make additional symbol with
# prepended underscore # prepended underscore
if ($elf) { s/EXPORT\s+\|([\$\w]*)\|/.global $1 \n\t.type $1, function/;
s/EXPORT\s+\|([\$\w]*)\|/.global $1 \n\t.type $1, function/;
} else {
s/EXPORT\s+\|([\$\w]*)\|/.global $1/;
}
s/IMPORT\s+\|([\$\w]*)\|/.global $1/; s/IMPORT\s+\|([\$\w]*)\|/.global $1/;
s/EXPORT\s+([\$\w]*)/.global $1/; s/EXPORT\s+([\$\w]*)/.global $1/;
@ -187,16 +189,11 @@ while (<STDIN>)
# eabi_attributes numerical equivalents can be found in the # eabi_attributes numerical equivalents can be found in the
# "ARM IHI 0045C" document. # "ARM IHI 0045C" document.
if ($elf) { # REQUIRE8 Stack is required to be 8-byte aligned
# REQUIRE8 Stack is required to be 8-byte aligned s/\sREQUIRE8/.eabi_attribute 24, 1 \@Tag_ABI_align_needed/g;
s/\sREQUIRE8/.eabi_attribute 24, 1 \@Tag_ABI_align_needed/g;
# PRESERVE8 Stack 8-byte align is preserved # PRESERVE8 Stack 8-byte align is preserved
s/\sPRESERVE8/.eabi_attribute 25, 1 \@Tag_ABI_align_preserved/g; s/\sPRESERVE8/.eabi_attribute 25, 1 \@Tag_ABI_align_preserved/g;
} else {
s/\sREQUIRE8//;
s/\sPRESERVE8//;
}
# Use PROC and ENDP to give the symbols a .size directive. # Use PROC and ENDP to give the symbols a .size directive.
# This makes them show up properly in debugging tools like gdb and valgrind. # This makes them show up properly in debugging tools like gdb and valgrind.
@ -213,7 +210,7 @@ while (<STDIN>)
my $proc; my $proc;
s/\bENDP\b/@ $&/; s/\bENDP\b/@ $&/;
$proc = pop(@proc_stack); $proc = pop(@proc_stack);
$_ = "\t.size $proc, .-$proc".$_ if ($proc and $elf); $_ = "\t.size $proc, .-$proc".$_ if ($proc);
} }
# EQU directive # EQU directive
@ -236,4 +233,4 @@ while (<STDIN>)
} }
# Mark that this object doesn't need an executable stack. # Mark that this object doesn't need an executable stack.
printf ("\t.section\t.note.GNU-stack,\"\",\%\%progbits\n") if $elf; printf ("\t.section\t.note.GNU-stack,\"\",\%\%progbits\n");

View File

@ -18,6 +18,12 @@
# Usage: cat inputfile | perl ads2gas_apple.pl > outputfile # Usage: cat inputfile | perl ads2gas_apple.pl > outputfile
# #
my $chromium = 0;
foreach my $arg (@ARGV) {
$chromium = 1 if ($arg eq "-chromium");
}
print "@ This file was created from a .asm file\n"; print "@ This file was created from a .asm file\n";
print "@ using the ads2gas_apple.pl script.\n\n"; print "@ using the ads2gas_apple.pl script.\n\n";
print "\t.set WIDE_REFERENCE, 0\n"; print "\t.set WIDE_REFERENCE, 0\n";
@ -120,6 +126,18 @@ while (<STDIN>)
s/DCD(.*)/.long $1/; s/DCD(.*)/.long $1/;
s/DCB(.*)/.byte $1/; s/DCB(.*)/.byte $1/;
# Build a hash of all the register - alias pairs.
if (s/(.*)RN(.*)/$1 .req $2/g)
{
$register_aliases{trim($1)} = trim($2);
next;
}
while (($key, $value) = each(%register_aliases))
{
s/\b$key\b/$value/g;
}
# Make function visible to linker, and make additional symbol with # Make function visible to linker, and make additional symbol with
# prepended underscore # prepended underscore
s/EXPORT\s+\|([\$\w]*)\|/.globl _$1\n\t.globl $1/; s/EXPORT\s+\|([\$\w]*)\|/.globl _$1\n\t.globl $1/;
@ -200,5 +218,18 @@ while (<STDIN>)
s/\bMEND\b/.endm/; # No need to tell it where to stop assembling s/\bMEND\b/.endm/; # No need to tell it where to stop assembling
next if /^\s*END\s*$/; next if /^\s*END\s*$/;
# Clang used by Chromium differs slightly from clang in XCode in what it
# will accept in the assembly.
if ($chromium) {
s/qsubaddx/qsax/i;
s/qaddsubx/qasx/i;
s/ldrneb/ldrbne/i;
s/ldrneh/ldrhne/i;
s/(vqshrun\.s16 .*, \#)0$/${1}8/i;
# http://llvm.org/bugs/show_bug.cgi?id=16022
s/\.include/#include/;
}
print; print;
} }

View File

@ -73,7 +73,6 @@ Build options:
--target=TARGET target platform tuple [generic-gnu] --target=TARGET target platform tuple [generic-gnu]
--cpu=CPU optimize for a specific cpu rather than a family --cpu=CPU optimize for a specific cpu rather than a family
--extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [$CFLAGS] --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [$CFLAGS]
--extra-cxxflags=ECXXFLAGS add ECXXFLAGS to CXXFLAGS [$CXXFLAGS]
${toggle_extra_warnings} emit harmless warnings (always non-fatal) ${toggle_extra_warnings} emit harmless warnings (always non-fatal)
${toggle_werror} treat warnings as errors, if possible ${toggle_werror} treat warnings as errors, if possible
(not available with all compilers) (not available with all compilers)
@ -185,7 +184,6 @@ add_extralibs() {
# #
# Boolean Manipulation Functions # Boolean Manipulation Functions
# #
enable_feature(){ enable_feature(){
set_all yes $* set_all yes $*
} }
@ -202,24 +200,6 @@ disabled(){
eval test "x\$$1" = "xno" eval test "x\$$1" = "xno"
} }
enable_codec(){
enabled "${1}" || echo " enabling ${1}"
enable_feature "${1}"
is_in "${1}" vp8 vp9 && enable_feature "${1}_encoder" "${1}_decoder"
}
disable_codec(){
disabled "${1}" || echo " disabling ${1}"
disable_feature "${1}"
is_in "${1}" vp8 vp9 && disable_feature "${1}_encoder" "${1}_decoder"
}
# Iterates through positional parameters, checks to confirm the parameter has
# not been explicitly (force) disabled, and enables the setting controlled by
# the parameter when the setting is not disabled.
# Note: Does NOT alter RTCD generation options ($RTCD_OPTIONS).
soft_enable() { soft_enable() {
for var in $*; do for var in $*; do
if ! disabled $var; then if ! disabled $var; then
@ -229,10 +209,6 @@ soft_enable() {
done done
} }
# Iterates through positional parameters, checks to confirm the parameter has
# not been explicitly (force) enabled, and disables the setting controlled by
# the parameter when the setting is not enabled.
# Note: Does NOT alter RTCD generation options ($RTCD_OPTIONS).
soft_disable() { soft_disable() {
for var in $*; do for var in $*; do
if ! enabled $var; then if ! enabled $var; then
@ -361,10 +337,6 @@ check_add_cflags() {
check_cflags "$@" && add_cflags_only "$@" check_cflags "$@" && add_cflags_only "$@"
} }
check_add_cxxflags() {
check_cxxflags "$@" && add_cxxflags_only "$@"
}
check_add_asflags() { check_add_asflags() {
log add_asflags "$@" log add_asflags "$@"
add_asflags "$@" add_asflags "$@"
@ -403,23 +375,6 @@ check_gcc_machine_option() {
fi fi
} }
# tests for -m$2, -m$3, -m$4... toggling the feature given in $1.
check_gcc_machine_options() {
feature="$1"
shift
flags="-m$1"
shift
for opt in $*; do
flags="$flags -m$opt"
done
if enabled gcc && ! disabled "$feature" && ! check_cflags $flags; then
RTCD_OPTIONS="${RTCD_OPTIONS}--disable-$feature "
else
soft_enable "$feature"
fi
}
write_common_config_banner() { write_common_config_banner() {
print_webm_license config.mk "##" "" print_webm_license config.mk "##" ""
echo '# This file automatically generated by configure. Do not edit!' >> config.mk echo '# This file automatically generated by configure. Do not edit!' >> config.mk
@ -435,7 +390,7 @@ write_common_config_banner() {
write_common_config_targets() { write_common_config_targets() {
for t in ${all_targets}; do for t in ${all_targets}; do
if enabled ${t}; then if enabled ${t}; then
if enabled child; then if enabled universal || enabled child; then
fwrite config.mk "ALL_TARGETS += ${t}-${toolchain}" fwrite config.mk "ALL_TARGETS += ${t}-${toolchain}"
else else
fwrite config.mk "ALL_TARGETS += ${t}" fwrite config.mk "ALL_TARGETS += ${t}"
@ -473,7 +428,7 @@ NM=${NM}
CFLAGS = ${CFLAGS} CFLAGS = ${CFLAGS}
CXXFLAGS = ${CXXFLAGS} CXXFLAGS = ${CXXFLAGS}
ARFLAGS = -crs\$(if \$(quiet),,v) ARFLAGS = -rus\$(if \$(quiet),c,v)
LDFLAGS = ${LDFLAGS} LDFLAGS = ${LDFLAGS}
ASFLAGS = ${ASFLAGS} ASFLAGS = ${ASFLAGS}
extralibs = ${extralibs} extralibs = ${extralibs}
@ -548,25 +503,24 @@ process_common_cmdline() {
--extra-cflags=*) --extra-cflags=*)
extra_cflags="${optval}" extra_cflags="${optval}"
;; ;;
--extra-cxxflags=*)
extra_cxxflags="${optval}"
;;
--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} ${ARCH_EXT_LIST}; then if echo "${ARCH_EXT_LIST}" | grep "^ *$option\$" >/dev/null; then
[ $action = "disable" ] && RTCD_OPTIONS="${RTCD_OPTIONS}--disable-${option} " [ $action = "disable" ] && RTCD_OPTIONS="${RTCD_OPTIONS}--disable-${option} "
elif [ $action = "disable" ] && ! disabled $option ; then elif [ $action = "disable" ] && ! disabled $option ; then
is_in ${option} ${CMDLINE_SELECT} || die_unknown $opt echo "${CMDLINE_SELECT}" | grep "^ *$option\$" >/dev/null ||
die_unknown $opt
log_echo " disabling $option" log_echo " disabling $option"
elif [ $action = "enable" ] && ! enabled $option ; then elif [ $action = "enable" ] && ! enabled $option ; then
is_in ${option} ${CMDLINE_SELECT} || die_unknown $opt echo "${CMDLINE_SELECT}" | grep "^ *$option\$" >/dev/null ||
die_unknown $opt
log_echo " enabling $option" log_echo " enabling $option"
fi fi
${action}_feature $option ${action}_feature $option
;; ;;
--require-?*) --require-?*)
eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'` eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'`
if is_in ${option} ${ARCH_EXT_LIST}; then if echo "${ARCH_EXT_LIST}" none | grep "^ *$option\$" >/dev/null; then
RTCD_OPTIONS="${RTCD_OPTIONS}${opt} " RTCD_OPTIONS="${RTCD_OPTIONS}${opt} "
else else
die_unknown $opt die_unknown $opt
@ -652,7 +606,7 @@ setup_gnu_toolchain() {
AS=${AS:-${CROSS}as} AS=${AS:-${CROSS}as}
STRIP=${STRIP:-${CROSS}strip} STRIP=${STRIP:-${CROSS}strip}
NM=${NM:-${CROSS}nm} NM=${NM:-${CROSS}nm}
AS_SFX=.S AS_SFX=.s
EXE_SFX= EXE_SFX=
} }
@ -663,40 +617,16 @@ show_darwin_sdk_path() {
xcodebuild -sdk $1 -version Path 2>/dev/null xcodebuild -sdk $1 -version Path 2>/dev/null
} }
# Print the major version number of the Darwin SDK specified by $1.
show_darwin_sdk_major_version() {
xcrun --sdk $1 --show-sdk-version 2>/dev/null | cut -d. -f1
}
# Print the Xcode version.
show_xcode_version() {
xcodebuild -version | head -n1 | cut -d' ' -f2
}
# Fails when Xcode version is less than 6.3.
check_xcode_minimum_version() {
xcode_major=$(show_xcode_version | cut -f1 -d.)
xcode_minor=$(show_xcode_version | cut -f2 -d.)
xcode_min_major=6
xcode_min_minor=3
if [ ${xcode_major} -lt ${xcode_min_major} ]; then
return 1
fi
if [ ${xcode_major} -eq ${xcode_min_major} ] \
&& [ ${xcode_minor} -lt ${xcode_min_minor} ]; then
return 1
fi
}
process_common_toolchain() { process_common_toolchain() {
if [ -z "$toolchain" ]; then if [ -z "$toolchain" ]; then
gcctarget="${CHOST:-$(gcc -dumpmachine 2> /dev/null)}" gcctarget="${CHOST:-$(gcc -dumpmachine 2> /dev/null)}"
# detect tgt_isa # detect tgt_isa
case "$gcctarget" in case "$gcctarget" in
aarch64*) armv6*)
tgt_isa=arm64 tgt_isa=armv6
;; ;;
armv7*-hardfloat* | armv7*-gnueabihf | arm-*-gnueabihf) armv7*-hardfloat*)
tgt_isa=armv7 tgt_isa=armv7
float_abi=hard float_abi=hard
;; ;;
@ -713,22 +643,18 @@ process_common_toolchain() {
*sparc*) *sparc*)
tgt_isa=sparc tgt_isa=sparc
;; ;;
power*64*-*)
tgt_isa=ppc64
;;
power*)
tgt_isa=ppc
;;
*mips64el*)
tgt_isa=mips64
;;
*mips32el*)
tgt_isa=mips32
;;
esac esac
# detect tgt_os # detect tgt_os
case "$gcctarget" in case "$gcctarget" in
*darwin8*)
tgt_isa=universal
tgt_os=darwin8
;;
*darwin9*)
tgt_isa=universal
tgt_os=darwin9
;;
*darwin10*) *darwin10*)
tgt_isa=x86_64 tgt_isa=x86_64
tgt_os=darwin10 tgt_os=darwin10
@ -749,24 +675,9 @@ process_common_toolchain() {
tgt_isa=x86_64 tgt_isa=x86_64
tgt_os=darwin14 tgt_os=darwin14
;; ;;
*darwin15*)
tgt_isa=x86_64
tgt_os=darwin15
;;
*darwin16*)
tgt_isa=x86_64
tgt_os=darwin16
;;
*darwin17*)
tgt_isa=x86_64
tgt_os=darwin17
;;
x86_64*mingw32*) x86_64*mingw32*)
tgt_os=win64 tgt_os=win64
;; ;;
x86_64*cygwin*)
tgt_os=win64
;;
*mingw32*|*cygwin*) *mingw32*|*cygwin*)
[ -z "$tgt_isa" ] && tgt_isa=x86 [ -z "$tgt_isa" ] && tgt_isa=x86
tgt_os=win32 tgt_os=win32
@ -814,36 +725,18 @@ process_common_toolchain() {
mips*) mips*)
enable_feature mips enable_feature mips
;; ;;
ppc*)
enable_feature ppc
;;
esac esac
# PIC is probably what we want when building shared libs # PIC is probably what we want when building shared libs
enabled shared && soft_enable pic enabled shared && soft_enable pic
# Minimum iOS version for all target platforms (darwin and iphonesimulator). # Minimum iOS version for all target platforms (darwin and iphonesimulator).
# Shared library framework builds are only possible on iOS 8 and later. IOS_VERSION_MIN="6.0"
if enabled shared; then
IOS_VERSION_OPTIONS="--enable-shared"
IOS_VERSION_MIN="8.0"
else
IOS_VERSION_OPTIONS=""
IOS_VERSION_MIN="6.0"
fi
# Handle darwin variants. Newer SDKs allow targeting older # Handle darwin variants. Newer SDKs allow targeting older
# platforms, so use the newest one available. # platforms, so use the newest one available.
case ${toolchain} in case ${toolchain} in
arm*-darwin*) *-darwin*)
add_cflags "-miphoneos-version-min=${IOS_VERSION_MIN}"
iphoneos_sdk_dir="$(show_darwin_sdk_path iphoneos)"
if [ -d "${iphoneos_sdk_dir}" ]; then
add_cflags "-isysroot ${iphoneos_sdk_dir}"
add_ldflags "-isysroot ${iphoneos_sdk_dir}"
fi
;;
x86*-darwin*)
osx_sdk_dir="$(show_darwin_sdk_path macosx)" osx_sdk_dir="$(show_darwin_sdk_path macosx)"
if [ -d "${osx_sdk_dir}" ]; then if [ -d "${osx_sdk_dir}" ]; then
add_cflags "-isysroot ${osx_sdk_dir}" add_cflags "-isysroot ${osx_sdk_dir}"
@ -881,18 +774,6 @@ process_common_toolchain() {
add_cflags "-mmacosx-version-min=10.10" add_cflags "-mmacosx-version-min=10.10"
add_ldflags "-mmacosx-version-min=10.10" add_ldflags "-mmacosx-version-min=10.10"
;; ;;
*-darwin15-*)
add_cflags "-mmacosx-version-min=10.11"
add_ldflags "-mmacosx-version-min=10.11"
;;
*-darwin16-*)
add_cflags "-mmacosx-version-min=10.12"
add_ldflags "-mmacosx-version-min=10.12"
;;
*-darwin17-*)
add_cflags "-mmacosx-version-min=10.13"
add_ldflags "-mmacosx-version-min=10.13"
;;
*-iphonesimulator-*) *-iphonesimulator-*)
add_cflags "-miphoneos-version-min=${IOS_VERSION_MIN}" add_cflags "-miphoneos-version-min=${IOS_VERSION_MIN}"
add_ldflags "-miphoneos-version-min=${IOS_VERSION_MIN}" add_ldflags "-miphoneos-version-min=${IOS_VERSION_MIN}"
@ -908,6 +789,7 @@ process_common_toolchain() {
case ${toolchain} in case ${toolchain} in
sparc-solaris-*) sparc-solaris-*)
add_extralibs -lposix4 add_extralibs -lposix4
disable_feature fast_unaligned
;; ;;
*-solaris-*) *-solaris-*)
add_extralibs -lposix4 add_extralibs -lposix4
@ -930,6 +812,12 @@ process_common_toolchain() {
if disabled neon && enabled neon_asm; then if disabled neon && enabled neon_asm; then
die "Disabling neon while keeping neon-asm is not supported" die "Disabling neon while keeping neon-asm is not supported"
fi fi
soft_enable media
soft_enable fast_unaligned
;;
armv6)
soft_enable media
soft_enable fast_unaligned
;; ;;
esac esac
@ -937,10 +825,12 @@ process_common_toolchain() {
case ${tgt_cc} in case ${tgt_cc} in
gcc) gcc)
CROSS=${CROSS:-arm-none-linux-gnueabi-}
link_with_cc=gcc link_with_cc=gcc
setup_gnu_toolchain setup_gnu_toolchain
arch_int=${tgt_isa##armv} arch_int=${tgt_isa##armv}
arch_int=${arch_int%%te} arch_int=${arch_int%%te}
check_add_asflags --defsym ARCHITECTURE=${arch_int}
tune_cflags="-mtune=" tune_cflags="-mtune="
if [ ${tgt_isa} = "armv7" ] || [ ${tgt_isa} = "armv7s" ]; then if [ ${tgt_isa} = "armv7" ] || [ ${tgt_isa} = "armv7s" ]; then
if [ -z "${float_abi}" ]; then if [ -z "${float_abi}" ]; then
@ -957,9 +847,6 @@ EOF
check_add_cflags -mfpu=neon #-ftree-vectorize check_add_cflags -mfpu=neon #-ftree-vectorize
check_add_asflags -mfpu=neon check_add_asflags -mfpu=neon
fi fi
elif [ ${tgt_isa} = "arm64" ] || [ ${tgt_isa} = "armv8" ]; then
check_add_cflags -march=armv8-a
check_add_asflags -march=armv8-a
else else
check_add_cflags -march=${tgt_isa} check_add_cflags -march=${tgt_isa}
check_add_asflags -march=${tgt_isa} check_add_asflags -march=${tgt_isa}
@ -967,19 +854,6 @@ EOF
enabled debug && add_asflags -g enabled debug && add_asflags -g
asm_conversion_cmd="${source_path}/build/make/ads2gas.pl" asm_conversion_cmd="${source_path}/build/make/ads2gas.pl"
case ${tgt_os} in
win*)
asm_conversion_cmd="$asm_conversion_cmd -noelf"
AS="$CC -c"
EXE_SFX=.exe
enable_feature thumb
;;
*)
check_add_asflags --defsym ARCHITECTURE=${arch_int}
;;
esac
if enabled thumb; then if enabled thumb; then
asm_conversion_cmd="$asm_conversion_cmd -thumb" asm_conversion_cmd="$asm_conversion_cmd -thumb"
check_add_cflags -mthumb check_add_cflags -mthumb
@ -988,7 +862,7 @@ EOF
;; ;;
vs*) vs*)
asm_conversion_cmd="${source_path}/build/make/ads2armasm_ms.pl" asm_conversion_cmd="${source_path}/build/make/ads2armasm_ms.pl"
AS_SFX=.S AS_SFX=.s
msvs_arch_dir=arm-msvs msvs_arch_dir=arm-msvs
disable_feature multithread disable_feature multithread
disable_feature unit_tests disable_feature unit_tests
@ -998,7 +872,6 @@ EOF
# only "AppContainerApplication" which requires an AppxManifest. # only "AppContainerApplication" which requires an AppxManifest.
# Therefore disable the examples, just build the library. # Therefore disable the examples, just build the library.
disable_feature examples disable_feature examples
disable_feature tools
fi fi
;; ;;
rvct) rvct)
@ -1041,50 +914,41 @@ EOF
;; ;;
android*) android*)
if [ -n "${sdk_path}" ]; then SDK_PATH=${sdk_path}
SDK_PATH=${sdk_path} COMPILER_LOCATION=`find "${SDK_PATH}" \
COMPILER_LOCATION=`find "${SDK_PATH}" \ -name "arm-linux-androideabi-gcc*" -print -quit`
-name "arm-linux-androideabi-gcc*" -print -quit` TOOLCHAIN_PATH=${COMPILER_LOCATION%/*}/arm-linux-androideabi-
TOOLCHAIN_PATH=${COMPILER_LOCATION%/*}/arm-linux-androideabi- CC=${TOOLCHAIN_PATH}gcc
CC=${TOOLCHAIN_PATH}gcc CXX=${TOOLCHAIN_PATH}g++
CXX=${TOOLCHAIN_PATH}g++ AR=${TOOLCHAIN_PATH}ar
AR=${TOOLCHAIN_PATH}ar LD=${TOOLCHAIN_PATH}gcc
LD=${TOOLCHAIN_PATH}gcc AS=${TOOLCHAIN_PATH}as
AS=${TOOLCHAIN_PATH}as STRIP=${TOOLCHAIN_PATH}strip
STRIP=${TOOLCHAIN_PATH}strip NM=${TOOLCHAIN_PATH}nm
NM=${TOOLCHAIN_PATH}nm
if [ -z "${alt_libc}" ]; then if [ -z "${alt_libc}" ]; then
alt_libc=`find "${SDK_PATH}" -name arch-arm -print | \ alt_libc=`find "${SDK_PATH}" -name arch-arm -print | \
awk '{n = split($0,a,"/"); \ awk '{n = split($0,a,"/"); \
split(a[n-1],b,"-"); \ split(a[n-1],b,"-"); \
print $0 " " b[2]}' | \ print $0 " " b[2]}' | \
sort -g -k 2 | \ sort -g -k 2 | \
awk '{ print $1 }' | tail -1` awk '{ print $1 }' | tail -1`
fi fi
if [ -d "${alt_libc}" ]; then add_cflags "--sysroot=${alt_libc}"
add_cflags "--sysroot=${alt_libc}" add_ldflags "--sysroot=${alt_libc}"
add_ldflags "--sysroot=${alt_libc}"
fi
# linker flag that routes around a CPU bug in some # linker flag that routes around a CPU bug in some
# Cortex-A8 implementations (NDK Dev Guide) # Cortex-A8 implementations (NDK Dev Guide)
add_ldflags "-Wl,--fix-cortex-a8" add_ldflags "-Wl,--fix-cortex-a8"
enable_feature pic enable_feature pic
soft_enable realtime_only soft_enable realtime_only
if [ ${tgt_isa} = "armv7" ]; then if [ ${tgt_isa} = "armv7" ]; then
soft_enable runtime_cpu_detect soft_enable runtime_cpu_detect
fi fi
if enabled runtime_cpu_detect; then if enabled runtime_cpu_detect; then
add_cflags "-I${SDK_PATH}/sources/android/cpufeatures" add_cflags "-I${SDK_PATH}/sources/android/cpufeatures"
fi
else
echo "Assuming standalone build with NDK toolchain."
echo "See build/make/Android.mk for details."
check_add_ldflags -static
soft_enable unit_tests
fi fi
;; ;;
@ -1097,8 +961,19 @@ EOF
STRIP="$(${XCRUN_FIND} strip)" STRIP="$(${XCRUN_FIND} strip)"
NM="$(${XCRUN_FIND} nm)" NM="$(${XCRUN_FIND} nm)"
RANLIB="$(${XCRUN_FIND} ranlib)" RANLIB="$(${XCRUN_FIND} ranlib)"
AS_SFX=.S AS_SFX=.s
LD="${CXX:-$(${XCRUN_FIND} ld)}"
# Special handling of ld for armv6 because libclang_rt.ios.a does
# not contain armv6 support in Apple's clang package:
# Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn).
# TODO(tomfinegan): Remove this. Our minimum iOS version (6.0)
# renders support for armv6 unnecessary because the 3GS and up
# support neon.
if [ "${tgt_isa}" = "armv6" ]; then
LD="$(${XCRUN_FIND} ld)"
else
LD="${CXX:-$(${XCRUN_FIND} ld)}"
fi
# ASFLAGS is written here instead of using check_add_asflags # ASFLAGS is written here instead of using check_add_asflags
# because we need to overwrite all of ASFLAGS and purge the # because we need to overwrite all of ASFLAGS and purge the
@ -1124,26 +999,7 @@ EOF
[ -d "${try_dir}" ] && add_ldflags -L"${try_dir}" [ -d "${try_dir}" ] && add_ldflags -L"${try_dir}"
done done
case ${tgt_isa} in
armv7|armv7s|armv8|arm64)
if enabled neon && ! check_xcode_minimum_version; then
soft_disable neon
log_echo " neon disabled: upgrade Xcode (need v6.3+)."
if enabled neon_asm; then
soft_disable neon_asm
log_echo " neon_asm disabled: upgrade Xcode (need v6.3+)."
fi
fi
;;
esac
asm_conversion_cmd="${source_path}/build/make/ads2gas_apple.pl" asm_conversion_cmd="${source_path}/build/make/ads2gas_apple.pl"
if [ "$(show_darwin_sdk_major_version iphoneos)" -gt 8 ]; then
check_add_cflags -fembed-bitcode
check_add_asflags -fembed-bitcode
check_add_ldflags -fembed-bitcode
fi
;; ;;
linux*) linux*)
@ -1151,7 +1007,7 @@ EOF
if enabled rvct; then if enabled rvct; then
# Check if we have CodeSourcery GCC in PATH. Needed for # Check if we have CodeSourcery GCC in PATH. Needed for
# libraries # libraries
which arm-none-linux-gnueabi-gcc 2>&- || \ hash arm-none-linux-gnueabi-gcc 2>&- || \
die "Couldn't find CodeSourcery GCC from PATH" die "Couldn't find CodeSourcery GCC from PATH"
# Use armcc as a linker to enable translation of # Use armcc as a linker to enable translation of
@ -1177,6 +1033,7 @@ EOF
tune_cflags="-mtune=" tune_cflags="-mtune="
if enabled dspr2; then if enabled dspr2; then
check_add_cflags -mips32r2 -mdspr2 check_add_cflags -mips32r2 -mdspr2
disable_feature fast_unaligned
fi fi
if enabled runtime_cpu_detect; then if enabled runtime_cpu_detect; then
@ -1186,13 +1043,13 @@ EOF
if [ -n "${tune_cpu}" ]; then if [ -n "${tune_cpu}" ]; then
case ${tune_cpu} in case ${tune_cpu} in
p5600) p5600)
check_add_cflags -mips32r5 -mload-store-pairs check_add_cflags -mips32r5 -funroll-loops -mload-store-pairs
check_add_cflags -msched-weight -mhard-float -mfp64 check_add_cflags -msched-weight -mhard-float -mfp64
check_add_asflags -mips32r5 -mhard-float -mfp64 check_add_asflags -mips32r5 -mhard-float -mfp64
check_add_ldflags -mfp64 check_add_ldflags -mfp64
;; ;;
i6400|p6600) i6400)
check_add_cflags -mips64r6 -mabi=64 -msched-weight check_add_cflags -mips64r6 -mabi=64 -funroll-loops -msched-weight
check_add_cflags -mload-store-pairs -mhard-float -mfp64 check_add_cflags -mload-store-pairs -mhard-float -mfp64
check_add_asflags -mips64r6 -mabi=64 -mhard-float -mfp64 check_add_asflags -mips64r6 -mabi=64 -mhard-float -mfp64
check_add_ldflags -mips64r6 -mabi=64 -mfp64 check_add_ldflags -mips64r6 -mabi=64 -mfp64
@ -1203,28 +1060,17 @@ EOF
add_cflags -mmsa add_cflags -mmsa
add_asflags -mmsa add_asflags -mmsa
add_ldflags -mmsa add_ldflags -mmsa
fi
fi
if enabled mmi; then disable_feature fast_unaligned
tgt_isa=loongson3a fi
check_add_ldflags -march=loongson3a
fi fi
check_add_cflags -march=${tgt_isa} check_add_cflags -march=${tgt_isa}
check_add_asflags -march=${tgt_isa} check_add_asflags -march=${tgt_isa}
check_add_asflags -KPIC check_add_asflags -KPIC
;; ;;
ppc*)
link_with_cc=gcc
setup_gnu_toolchain
check_gcc_machine_option "vsx"
;;
x86*) x86*)
case ${tgt_os} in case ${tgt_os} in
android)
soft_enable realtime_only
;;
win*) win*)
enabled gcc && add_cflags -fno-common enabled gcc && add_cflags -fno-common
;; ;;
@ -1232,12 +1078,10 @@ EOF
CC=${CC:-${CROSS}gcc} CC=${CC:-${CROSS}gcc}
CXX=${CXX:-${CROSS}g++} CXX=${CXX:-${CROSS}g++}
LD=${LD:-${CROSS}gcc} LD=${LD:-${CROSS}gcc}
CROSS=${CROSS-g} CROSS=${CROSS:-g}
;; ;;
os2) os2)
disable_feature pic
AS=${AS:-nasm} AS=${AS:-nasm}
add_ldflags -Zhigh-mem
;; ;;
esac esac
@ -1277,13 +1121,6 @@ EOF
AS=msvs AS=msvs
msvs_arch_dir=x86-msvs msvs_arch_dir=x86-msvs
vc_version=${tgt_cc##vs} vc_version=${tgt_cc##vs}
case $vc_version in
7|8|9|10|11|12|13|14)
echo "${tgt_cc} does not support avx512, disabling....."
RTCD_OPTIONS="${RTCD_OPTIONS}--disable-avx512 "
soft_disable avx512
;;
esac
case $vc_version in case $vc_version in
7|8|9|10) 7|8|9|10)
echo "${tgt_cc} does not support avx/avx2, disabling....." echo "${tgt_cc} does not support avx/avx2, disabling....."
@ -1292,12 +1129,6 @@ EOF
soft_disable avx2 soft_disable avx2
;; ;;
esac esac
case $vc_version in
7|8|9)
echo "${tgt_cc} omits stdint.h, disabling webm-io..."
soft_disable webm_io
;;
esac
;; ;;
esac esac
@ -1318,47 +1149,33 @@ EOF
soft_enable runtime_cpu_detect soft_enable runtime_cpu_detect
# We can't use 'check_cflags' until the compiler is configured and CC is # We can't use 'check_cflags' until the compiler is configured and CC is
# populated. # populated.
for ext in ${ARCH_EXT_LIST_X86}; do check_gcc_machine_option mmx
# disable higher order extensions to simplify asm dependencies check_gcc_machine_option sse
if [ "$disable_exts" = "yes" ]; then check_gcc_machine_option sse2
if ! disabled $ext; then check_gcc_machine_option sse3
RTCD_OPTIONS="${RTCD_OPTIONS}--disable-${ext} " check_gcc_machine_option ssse3
disable_feature $ext check_gcc_machine_option sse4 sse4_1
fi check_gcc_machine_option avx
elif disabled $ext; then check_gcc_machine_option avx2
disable_exts="yes"
else
if [ "$ext" = "avx512" ]; then
check_gcc_machine_options $ext avx512f avx512cd avx512bw avx512dq avx512vl
else
# use the shortened version for the flag: sse4_1 -> sse4
check_gcc_machine_option ${ext%_*} $ext
fi
fi
done
if enabled external_build; then case "${AS}" in
log_echo " skipping assembler detection" auto|"")
else which nasm >/dev/null 2>&1 && AS=nasm
case "${AS}" in which yasm >/dev/null 2>&1 && AS=yasm
auto|"") if [ "${AS}" = nasm ] ; then
which nasm >/dev/null 2>&1 && AS=nasm # Apple ships version 0.98 of nasm through at least Xcode 6. Revisit
which yasm >/dev/null 2>&1 && AS=yasm # this check if they start shipping a compatible version.
if [ "${AS}" = nasm ] ; then apple=`nasm -v | grep "Apple"`
# Apple ships version 0.98 of nasm through at least Xcode 6. Revisit [ -n "${apple}" ] \
# this check if they start shipping a compatible version. && echo "Unsupported version of nasm: ${apple}" \
apple=`nasm -v | grep "Apple"` && AS=""
[ -n "${apple}" ] \ fi
&& echo "Unsupported version of nasm: ${apple}" \ [ "${AS}" = auto ] || [ -z "${AS}" ] \
&& AS="" && die "Neither yasm nor nasm have been found"
fi ;;
[ "${AS}" = auto ] || [ -z "${AS}" ] \ esac
&& die "Neither yasm nor nasm have been found." \ log_echo " using $AS"
"See the prerequisites section in the README for more info." [ "${AS##*/}" = nasm ] && add_asflags -Ox
;;
esac
log_echo " using $AS"
fi
AS_SFX=.asm AS_SFX=.asm
case ${tgt_os} in case ${tgt_os} in
win32) win32)
@ -1367,7 +1184,7 @@ EOF
EXE_SFX=.exe EXE_SFX=.exe
;; ;;
win64) win64)
add_asflags -f win64 add_asflags -f x64
enabled debug && add_asflags -g cv8 enabled debug && add_asflags -g cv8
EXE_SFX=.exe EXE_SFX=.exe
;; ;;
@ -1393,14 +1210,6 @@ EOF
enabled x86 && sim_arch="-arch i386" || sim_arch="-arch x86_64" enabled x86 && sim_arch="-arch i386" || sim_arch="-arch x86_64"
add_cflags ${sim_arch} add_cflags ${sim_arch}
add_ldflags ${sim_arch} add_ldflags ${sim_arch}
if [ "$(disabled external_build)" ] &&
[ "$(show_darwin_sdk_major_version iphonesimulator)" -gt 8 ]; then
# yasm v1.3.0 doesn't know what -fembed-bitcode means, so turning it
# on is pointless (unless building a C-only lib). Warn the user, but
# do nothing here.
log "Warning: Bitcode embed disabled for simulator targets."
fi
;; ;;
os2) os2)
add_asflags -f aout add_asflags -f aout
@ -1412,7 +1221,7 @@ EOF
;; ;;
esac esac
;; ;;
*-gcc|generic-gnu) universal*|*-gcc|generic-gnu)
link_with_cc=gcc link_with_cc=gcc
enable_feature gcc enable_feature gcc
setup_gnu_toolchain setup_gnu_toolchain
@ -1453,6 +1262,10 @@ EOF
fi fi
fi fi
if [ "${tgt_isa}" = "x86_64" ] || [ "${tgt_isa}" = "x86" ]; then
soft_enable use_x86inc
fi
# Position Independent Code (PIC) support, for building relocatable # Position Independent Code (PIC) support, for building relocatable
# shared objects # shared objects
enabled gcc && enabled pic && check_add_cflags -fPIC enabled gcc && enabled pic && check_add_cflags -fPIC
@ -1482,7 +1295,6 @@ EOF
*-win*-vs*) *-win*-vs*)
;; ;;
*-android-gcc) *-android-gcc)
# bionic includes basic pthread functionality, obviating -lpthread.
;; ;;
*) *)
check_header pthread.h && add_extralibs -lpthread check_header pthread.h && add_extralibs -lpthread
@ -1502,10 +1314,6 @@ EOF
echo "msa optimizations are available only for little endian platforms" echo "msa optimizations are available only for little endian platforms"
disable_feature msa disable_feature msa
fi fi
if enabled mmi; then
echo "mmi optimizations are available only for little endian platforms"
disable_feature mmi
fi
fi fi
;; ;;
esac esac
@ -1515,6 +1323,12 @@ EOF
add_cflags -D_LARGEFILE_SOURCE add_cflags -D_LARGEFILE_SOURCE
add_cflags -D_FILE_OFFSET_BITS=64 add_cflags -D_FILE_OFFSET_BITS=64
fi fi
# 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
} }
process_toolchain() { process_toolchain() {

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

@ -0,0 +1,486 @@
#!/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")
src_path_bare=${src_path_bare%/}
;;
--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##-I}
opt=$(fix_path "$opt")
opt="${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 win64 ${yasmincs} &quot;\$(InputPath)&quot;"
asm_Release_cmdline="yasm -Xvc -f win64 ${yasmincs} &quot;\$(InputPath)&quot;"
;;
x86*)
platforms[0]="Win32"
asm_Debug_cmdline="yasm -Xvc -g cv8 -f win32 ${yasmincs} &quot;\$(InputPath)&quot;"
asm_Release_cmdline="yasm -Xvc -f win32 ${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
vpx)
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
*)
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
vpx)
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
*)
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,15) 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
local name=`grep RootNamespace "$file" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'` if [ "$sfx" = "vcproj" ]; then
local guid=`grep ProjectGuid "$file" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'` 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 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"
cur_config_list=`grep -B1 'Label="Configuration"' $file | if [ "$sfx" = "vcproj" ]; then
grep Condition | cut -d\' -f4` cur_config_list=`grep -A1 '<Configuration' $file |
grep Name | cut -d\" -f2`
else
cur_config_list=`grep -B1 'Label="Configuration"' $file |
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|15) [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,14 +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="12.00" esac
sln_vers_str="Visual Studio 2015" case "${vs_ver:-8}" in
[789])
sfx=vcproj
;; ;;
15) sln_vers="12.00" 10|11|12)
sln_vers_str="Visual Studio 2017" 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,15) 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
@ -82,7 +82,7 @@ generate_filter() {
| sed -e "s,$src_path_bare,," \ | sed -e "s,$src_path_bare,," \
-e 's/^[\./]\+//g' -e 's,[:/ ],_,g') -e 's/^[\./]\+//g' -e 's,[:/ ],_,g')
if ([ "$pat" == "asm" ] || [ "$pat" == "s" ] || [ "$pat" == "S" ]) && $asm_use_custom_step; then if ([ "$pat" == "asm" ] || [ "$pat" == "s" ]) && $asm_use_custom_step; then
# Avoid object file name collisions, i.e. vpx_config.c and # Avoid object file name collisions, i.e. vpx_config.c and
# vpx_config.asm produce the same object file without # vpx_config.asm produce the same object file without
# this additional suffix. # this additional suffix.
@ -168,7 +168,7 @@ for opt in "$@"; do
--ver=*) --ver=*)
vs_ver="$optval" vs_ver="$optval"
case "$optval" in case "$optval" in
10|11|12|14|15) 10|11|12)
;; ;;
*) die Unrecognized Visual Studio Version in $opt *) die Unrecognized Visual Studio Version in $opt
;; ;;
@ -203,7 +203,7 @@ for opt in "$@"; do
# The paths in file_list are fixed outside of the loop. # The paths in file_list are fixed outside of the loop.
file_list[${#file_list[@]}]="$opt" file_list[${#file_list[@]}]="$opt"
case "$opt" in case "$opt" in
*.asm|*.[Ss]) uses_asm=true *.asm|*.s) uses_asm=true
;; ;;
esac esac
;; ;;
@ -211,14 +211,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|15) 10|11|12)
asm_use_custom_step=$uses_asm asm_use_custom_step=$uses_asm
;; ;;
esac esac
@ -263,8 +263,8 @@ case "$target" in
;; ;;
arm*) arm*)
platforms[0]="ARM" platforms[0]="ARM"
asm_Debug_cmdline="armasm -nologo -oldit &quot;%(FullPath)&quot;" asm_Debug_cmdline="armasm -nologo &quot;%(FullPath)&quot;"
asm_Release_cmdline="armasm -nologo -oldit &quot;%(FullPath)&quot;" asm_Release_cmdline="armasm -nologo &quot;%(FullPath)&quot;"
;; ;;
*) die "Unsupported target $target!" *) die "Unsupported target $target!"
;; ;;
@ -344,12 +344,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
if [ "$vs_ver" = "15" ]; then
tag_content PlatformToolset v141
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
@ -455,7 +449,7 @@ generate_vcxproj() {
done done
open_tag ItemGroup open_tag ItemGroup
generate_filter "Source Files" "c;cc;cpp;def;odl;idl;hpj;bat;asm;asmx;s;S" generate_filter "Source Files" "c;cc;cpp;def;odl;idl;hpj;bat;asm;asmx;s"
close_tag ItemGroup close_tag ItemGroup
open_tag ItemGroup open_tag ItemGroup
generate_filter "Header Files" "h;hm;inl;inc;xsd" generate_filter "Header Files" "h;hm;inl;inc;xsd"

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

@ -24,44 +24,32 @@ CONFIGURE_ARGS="--disable-docs
--disable-unit-tests" --disable-unit-tests"
DIST_DIR="_dist" DIST_DIR="_dist"
FRAMEWORK_DIR="VPX.framework" FRAMEWORK_DIR="VPX.framework"
FRAMEWORK_LIB="VPX.framework/VPX"
HEADER_DIR="${FRAMEWORK_DIR}/Headers/vpx" HEADER_DIR="${FRAMEWORK_DIR}/Headers/vpx"
MAKE_JOBS=1
SCRIPT_DIR=$(dirname "$0") SCRIPT_DIR=$(dirname "$0")
LIBVPX_SOURCE_DIR=$(cd ${SCRIPT_DIR}/../..; pwd) LIBVPX_SOURCE_DIR=$(cd ${SCRIPT_DIR}/../..; pwd)
LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo) LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
ORIG_PWD="$(pwd)" ORIG_PWD="$(pwd)"
ARM_TARGETS="arm64-darwin-gcc TARGETS="arm64-darwin-gcc
armv7-darwin-gcc armv7-darwin-gcc
armv7s-darwin-gcc" armv7s-darwin-gcc
SIM_TARGETS="x86-iphonesimulator-gcc x86-iphonesimulator-gcc
x86_64-iphonesimulator-gcc" x86_64-iphonesimulator-gcc"
OSX_TARGETS="x86-darwin16-gcc
x86_64-darwin16-gcc"
TARGETS="${ARM_TARGETS} ${SIM_TARGETS}"
# Configures for the target specified by $1, and invokes make with the dist # Configures for the target specified by $1, and invokes make with the dist
# target using $DIST_DIR as the distribution output directory. # target using $DIST_DIR as the distribution output directory.
build_target() { build_target() {
local target="$1" local target="$1"
local old_pwd="$(pwd)" local old_pwd="$(pwd)"
local target_specific_flags=""
vlog "***Building target: ${target}***" vlog "***Building target: ${target}***"
case "${target}" in
x86-*)
target_specific_flags="--enable-pic"
vlog "Enabled PIC for ${target}"
;;
esac
mkdir "${target}" mkdir "${target}"
cd "${target}" cd "${target}"
eval "${LIBVPX_SOURCE_DIR}/configure" --target="${target}" \ eval "${LIBVPX_SOURCE_DIR}/configure" --target="${target}" \
${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS} ${target_specific_flags} \ ${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS} ${devnull}
${devnull}
export DIST_DIR export DIST_DIR
eval make dist ${devnull} eval make -j ${MAKE_JOBS} dist ${devnull}
cd "${old_pwd}" cd "${old_pwd}"
vlog "***Done building target: ${target}***" vlog "***Done building target: ${target}***"
@ -138,44 +126,6 @@ create_vpx_framework_config_shim() {
printf "#endif // ${include_guard}" >> "${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 # Configures and builds each target specified by $1, and then builds
# VPX.framework. # VPX.framework.
build_framework() { build_framework() {
@ -196,12 +146,7 @@ build_framework() {
for target in ${targets}; do for target in ${targets}; do
build_target "${target}" build_target "${target}"
target_dist_dir="${BUILD_ROOT}/${target}/${DIST_DIR}" target_dist_dir="${BUILD_ROOT}/${target}/${DIST_DIR}"
if [ "${ENABLE_SHARED}" = "yes" ]; then lib_list="${lib_list} ${target_dist_dir}/lib/libvpx.a"
local suffix="dylib"
else
local suffix="a"
fi
lib_list="${lib_list} ${target_dist_dir}/lib/libvpx.${suffix}"
done done
cd "${ORIG_PWD}" cd "${ORIG_PWD}"
@ -220,25 +165,13 @@ build_framework() {
# Copy in vpx_version.h. # Copy in vpx_version.h.
cp -p "${BUILD_ROOT}/${target}/vpx_version.h" "${HEADER_DIR}" cp -p "${BUILD_ROOT}/${target}/vpx_version.h" "${HEADER_DIR}"
if [ "${ENABLE_SHARED}" = "yes" ]; then vlog "Created fat library ${FRAMEWORK_DIR}/VPX containing:"
# 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 for lib in ${lib_list}; do
vlog " $(echo ${lib} | awk -F / '{print $2, $NF}')" vlog " $(echo ${lib} | awk -F / '{print $2, $NF}')"
done done
# TODO(tomfinegan): Verify that expected targets are included within
# VPX.framework/VPX via lipo -info.
} }
# Trap function. Cleans up the subtree used to build all targets contained in # Trap function. Cleans up the subtree used to build all targets contained in
@ -256,30 +189,16 @@ cleanup() {
fi fi
} }
print_list() {
local indent="$1"
shift
local list="$@"
for entry in ${list}; do
echo "${indent}${entry}"
done
}
iosbuild_usage() { iosbuild_usage() {
cat << EOF cat << EOF
Usage: ${0##*/} [arguments] Usage: ${0##*/} [arguments]
--help: Display this message and exit. --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. --extra-configure-args <args>: Extra args to pass when configuring libvpx.
--macosx: Uses darwin16 targets instead of iphonesimulator targets for x86 --jobs: Number of make jobs.
and x86_64. Allows linking to framework when builds target MacOSX
instead of iOS.
--preserve-build-output: Do not delete the build directory. --preserve-build-output: Do not delete the build directory.
--show-build-output: Show output from each library build. --show-build-output: Show output from each library build.
--targets <targets>: Override default target list. Defaults: --targets <targets>: Override default target list. Defaults:
$(print_list " " ${TARGETS}) ${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 --verbose: Output information about the environment and each stage of the
build. build.
EOF EOF
@ -308,8 +227,9 @@ while [ -n "$1" ]; do
iosbuild_usage iosbuild_usage
exit exit
;; ;;
--enable-shared) --jobs)
ENABLE_SHARED=yes MAKE_JOBS="$2"
shift
;; ;;
--preserve-build-output) --preserve-build-output)
PRESERVE_BUILD_OUTPUT=yes PRESERVE_BUILD_OUTPUT=yes
@ -317,16 +237,10 @@ while [ -n "$1" ]; do
--show-build-output) --show-build-output)
devnull= devnull=
;; ;;
--test-link)
EXTRA_CONFIGURE_ARGS="${EXTRA_CONFIGURE_ARGS} --enable-examples"
;;
--targets) --targets)
TARGETS="$2" TARGETS="$2"
shift shift
;; ;;
--macosx)
TARGETS="${ARM_TARGETS} ${OSX_TARGETS}"
;;
--verbose) --verbose)
VERBOSE=yes VERBOSE=yes
;; ;;
@ -338,21 +252,6 @@ while [ -n "$1" ]; do
shift shift
done 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 if [ "${VERBOSE}" = "yes" ]; then
cat << EOF cat << EOF
BUILD_ROOT=${BUILD_ROOT} BUILD_ROOT=${BUILD_ROOT}
@ -360,24 +259,16 @@ cat << EOF
CONFIGURE_ARGS=${CONFIGURE_ARGS} CONFIGURE_ARGS=${CONFIGURE_ARGS}
EXTRA_CONFIGURE_ARGS=${EXTRA_CONFIGURE_ARGS} EXTRA_CONFIGURE_ARGS=${EXTRA_CONFIGURE_ARGS}
FRAMEWORK_DIR=${FRAMEWORK_DIR} FRAMEWORK_DIR=${FRAMEWORK_DIR}
FRAMEWORK_LIB=${FRAMEWORK_LIB}
HEADER_DIR=${HEADER_DIR} HEADER_DIR=${HEADER_DIR}
MAKE_JOBS=${MAKE_JOBS}
PRESERVE_BUILD_OUTPUT=${PRESERVE_BUILD_OUTPUT}
LIBVPX_SOURCE_DIR=${LIBVPX_SOURCE_DIR} LIBVPX_SOURCE_DIR=${LIBVPX_SOURCE_DIR}
LIPO=${LIPO} LIPO=${LIPO}
MAKEFLAGS=${MAKEFLAGS}
ORIG_PWD=${ORIG_PWD} ORIG_PWD=${ORIG_PWD}
PRESERVE_BUILD_OUTPUT=${PRESERVE_BUILD_OUTPUT} TARGETS="${TARGETS}"
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 EOF
fi fi
build_framework "${TARGETS}" build_framework "${TARGETS}"
echo "Successfully built '${FRAMEWORK_DIR}' for:" echo "Successfully built '${FRAMEWORK_DIR}' for:"
print_list "" ${TARGETS} echo " ${TARGETS}"

View File

@ -39,21 +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() {
if [ "${FIXPATH}" = "echo_path" ] ; then # TODO(jzern): this could be more generic and take the array as a param.
# When used with echo_path, fix_file_list is a no-op. Avoid warning about files=$(fix_path "${file_list[@]}")
# unsupported 'declare -n' when it is not important.
return 0
elif [ "${BASH_VERSINFO}" -lt 4 ] ; then
echo "Cygwin path conversion has failed. Please use a version of bash"
echo "which supports nameref (-n), introduced in bash 4.3"
return 1
fi
declare -n array_ref=$1
files=$(fix_path "${array_ref[@]}")
local IFS=$'\n' local IFS=$'\n'
array_ref=($files) file_list=($files)
} }
generate_uuid() { generate_uuid() {

View File

@ -1,13 +1,4 @@
#!/usr/bin/env perl #!/usr/bin/env perl
##
## Copyright (c) 2017 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.
##
no strict 'refs'; no strict 'refs';
use warnings; use warnings;
@ -209,7 +200,6 @@ sub filter {
sub common_top() { sub common_top() {
my $include_guard = uc($opts{sym})."_H_"; my $include_guard = uc($opts{sym})."_H_";
print <<EOF; print <<EOF;
// This file is generated. Do not edit.
#ifndef ${include_guard} #ifndef ${include_guard}
#define ${include_guard} #define ${include_guard}
@ -329,46 +319,15 @@ EOF
print <<EOF; print <<EOF;
#if HAVE_DSPR2 #if HAVE_DSPR2
void vpx_dsputil_static_init();
#if CONFIG_VP8 #if CONFIG_VP8
void dsputil_static_init(); void dsputil_static_init();
#endif
vpx_dsputil_static_init();
#if CONFIG_VP8
dsputil_static_init(); dsputil_static_init();
#endif #endif
#if CONFIG_VP9
void vp9_dsputil_static_init();
vp9_dsputil_static_init();
#endif #endif
}
#endif #endif
EOF
common_bottom;
}
sub ppc() {
determine_indirection("c", @ALL_ARCHS);
# Assign the helper variable for each enabled extension
foreach my $opt (@ALL_ARCHS) {
my $opt_uc = uc $opt;
eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
}
common_top;
print <<EOF;
#include "vpx_config.h"
#ifdef RTCD_C
#include "vpx_ports/ppc.h"
static void setup_rtcd_internal(void)
{
int flags = ppc_simd_caps();
(void)flags;
EOF
set_function_pointers("c", @ALL_ARCHS);
print <<EOF;
} }
#endif #endif
EOF EOF
@ -401,10 +360,10 @@ EOF
&require("c"); &require("c");
if ($opts{arch} eq 'x86') { if ($opts{arch} eq 'x86') {
@ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2 avx512/); @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2/);
x86; x86;
} elsif ($opts{arch} eq 'x86_64') { } elsif ($opts{arch} eq 'x86_64') {
@ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2 avx512/); @ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2/);
@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;
@ -421,22 +380,20 @@ if ($opts{arch} eq 'x86') {
@ALL_ARCHS = filter("$opts{arch}", qw/msa/); @ALL_ARCHS = filter("$opts{arch}", qw/msa/);
last; last;
} }
if (/HAVE_MMI=yes/) {
@ALL_ARCHS = filter("$opts{arch}", qw/mmi/);
last;
}
} }
close CONFIG_FILE; close CONFIG_FILE;
mips; mips;
} elsif ($opts{arch} eq 'armv6') {
@ALL_ARCHS = filter(qw/media/);
arm;
} elsif ($opts{arch} =~ /armv7\w?/) { } elsif ($opts{arch} =~ /armv7\w?/) {
@ALL_ARCHS = filter(qw/neon_asm neon/); @ALL_ARCHS = filter(qw/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' || $opts{arch} eq 'arm64' ) {
@ALL_ARCHS = filter(qw/neon/); @ALL_ARCHS = filter(qw/neon/);
arm; arm;
} elsif ($opts{arch} =~ /^ppc/ ) {
@ALL_ARCHS = filter(qw/vsx/);
ppc;
} else { } else {
unoptimized; unoptimized;
} }

View File

@ -54,6 +54,13 @@ sub FixThumbInstructions($$)
# "addne r0, r0, r2". # "addne r0, r0, r2".
s/^(\s*)((ldr|str)(ne)?[bhd]?)(\s+)(\w+),(\s*\w+,)?\s*\[(\w+)\],\s*(\w+)/$1$2$5$6,$7 [$8]\n$1add$4$5$8, $8, $9/g; s/^(\s*)((ldr|str)(ne)?[bhd]?)(\s+)(\w+),(\s*\w+,)?\s*\[(\w+)\],\s*(\w+)/$1$2$5$6,$7 [$8]\n$1add$4$5$8, $8, $9/g;
# Convert a conditional addition to the pc register into a series of
# instructions. This converts "addlt pc, pc, r3, lsl #2" into
# "itttt lt", "movlt.n r12, pc", "addlt.w r12, #12",
# "addlt.w r12, r12, r3, lsl #2", "movlt.n pc, r12".
# This assumes that r12 is free at this point.
s/^(\s*)addlt(\s+)pc,\s*pc,\s*(\w+),\s*lsl\s*#(\d+)/$1itttt$2lt\n$1movlt.n$2r12, pc\n$1addlt.w$2r12, #12\n$1addlt.w$2r12, r12, $3, lsl #($4-$branch_shift_offset)\n$1movlt.n$2pc, r12/g;
# Convert "mov pc, lr" into "bx lr", since the former only works # Convert "mov pc, lr" into "bx lr", since the former only works
# for switching from arm to thumb (and only in armv7), but not # for switching from arm to thumb (and only in armv7), but not
# from thumb to arm. # from thumb to arm.

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
@ -60,7 +59,6 @@ if [ ${bare} ]; then
echo "${changelog_version}${git_version_id}" > $$.tmp echo "${changelog_version}${git_version_id}" > $$.tmp
else else
cat<<EOF>$$.tmp cat<<EOF>$$.tmp
// This file is generated. Do not edit.
#define VERSION_MAJOR $major_version #define VERSION_MAJOR $major_version
#define VERSION_MINOR $minor_version #define VERSION_MINOR $minor_version
#define VERSION_PATCH $patch_version #define VERSION_PATCH $patch_version

View File

@ -1,4 +0,0 @@
# This file is used by git cl to get repository specific information.
GERRIT_HOST: True
CODE_REVIEW_SERVER: chromium-review.googlesource.com
GERRIT_SQUASH_UPLOADS: False

268
configure vendored
View File

@ -22,7 +22,6 @@ show_help(){
Advanced options: Advanced options:
${toggle_libs} libraries ${toggle_libs} libraries
${toggle_examples} examples ${toggle_examples} examples
${toggle_tools} tools
${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
@ -32,13 +31,12 @@ Advanced options:
--size-limit=WxH max size to allow in the decoder --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_vp9_highbitdepth} use VP9 high bit depth (10/12) profiles ${toggle_vp9_highbitdepth} use VP9 high bit depth (10/12) profiles
${toggle_better_hw_compatibility}
enable encoder to produce streams with better
hardware decoder compatibility
${toggle_vp8} VP8 codec support ${toggle_vp8} VP8 codec support
${toggle_vp9} VP9 codec support ${toggle_vp9} VP9 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)
@ -98,26 +96,21 @@ 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-android-gcc" all_platforms="${all_platforms} armv6-darwin-gcc"
all_platforms="${all_platforms} armv6-linux-rvct"
all_platforms="${all_platforms} armv6-linux-gcc"
all_platforms="${all_platforms} armv6-none-rvct"
all_platforms="${all_platforms} arm64-darwin-gcc" all_platforms="${all_platforms} arm64-darwin-gcc"
all_platforms="${all_platforms} arm64-linux-gcc"
all_platforms="${all_platforms} arm64-win64-gcc"
all_platforms="${all_platforms} armv7-android-gcc" #neon Cortex-A8 all_platforms="${all_platforms} armv7-android-gcc" #neon Cortex-A8
all_platforms="${all_platforms} armv7-darwin-gcc" #neon Cortex-A8 all_platforms="${all_platforms} armv7-darwin-gcc" #neon Cortex-A8
all_platforms="${all_platforms} armv7-linux-rvct" #neon Cortex-A8 all_platforms="${all_platforms} armv7-linux-rvct" #neon Cortex-A8
all_platforms="${all_platforms} armv7-linux-gcc" #neon Cortex-A8 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-gcc"
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} armv7-win32-vs15"
all_platforms="${all_platforms} armv7s-darwin-gcc" 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} mips64-linux-gcc"
all_platforms="${all_platforms} ppc64-linux-gcc"
all_platforms="${all_platforms} ppc64le-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"
@ -129,59 +122,57 @@ 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-darwin14-gcc"
all_platforms="${all_platforms} x86-darwin15-gcc"
all_platforms="${all_platforms} x86-darwin16-gcc"
all_platforms="${all_platforms} x86-darwin17-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-win32-vs15"
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-darwin14-gcc"
all_platforms="${all_platforms} x86_64-darwin15-gcc"
all_platforms="${all_platforms} x86_64-darwin16-gcc"
all_platforms="${all_platforms} x86_64-darwin17-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} x86_64-win64-vs15" 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} universal-darwin14-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
# note that these should be in dependency order for now. # note that these should be in dependency order for now.
all_targets="libs examples tools docs" all_targets="libs examples docs"
# all targets available are enabled, by default. # all targets available are enabled, by default.
for t in ${all_targets}; do for t in ${all_targets}; do
[ -f "${source_path}/${t}.mk" ] && enable_feature ${t} [ -f "${source_path}/${t}.mk" ] && enable_feature ${t}
done done
if ! diff --version >/dev/null; then
die "diff missing: Try installing diffutils via your package manager."
fi
if ! perl --version >/dev/null; then if ! perl --version >/dev/null; then
die "Perl is required to build" die "Perl is required to build"
fi fi
if [ "`cd \"${source_path}\" && pwd`" != "`pwd`" ]; then if [ "`cd \"${source_path}\" && pwd`" != "`pwd`" ]; then
# test to see if source_path already configured # test to see if source_path already configured
if [ -f "${source_path}/vpx_config.h" ]; then if [ -f "${source_path}/vpx_config.h" ]; then
@ -202,10 +193,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}/vp8" ] || disable_codec vp8
[ -d "${source_path}/vp9" ] || disable_codec vp9
# 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.
@ -216,46 +203,47 @@ enable_feature install_libs
enable_feature static enable_feature static
enable_feature optimizations enable_feature optimizations
enable_feature dependency_tracking 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
vp8_encoder for d in vp8 vp9; do
vp8_decoder [ -d "${source_path}/${d}" ] && disable_feature alt_tree_layout;
vp9_encoder done
vp9_decoder
" if ! enabled alt_tree_layout; then
CODEC_FAMILIES=" # development environment
vp8 [ -d "${source_path}/vp8" ] && CODECS="${CODECS} vp8_encoder vp8_decoder"
vp9 [ -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
ppc
" "
ARCH_EXT_LIST_X86="
mmx
sse
sse2
sse3
ssse3
sse4_1
avx
avx2
avx512
"
ARCH_EXT_LIST_LOONGSON="
mmi
"
ARCH_EXT_LIST=" ARCH_EXT_LIST="
edsp
media
neon neon
neon_asm neon_asm
@ -264,19 +252,26 @@ ARCH_EXT_LIST="
msa msa
mips64 mips64
${ARCH_EXT_LIST_X86} mmx
sse
vsx sse2
sse3
${ARCH_EXT_LIST_LOONGSON} ssse3
sse4_1
avx
avx2
" "
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="
spatial_svc
fp_mb_stats fp_mb_stats
emulate_hardware emulate_hardware
" "
@ -287,6 +282,7 @@ CONFIG_LIST="
install_bins install_bins
install_libs install_libs
install_srcs install_srcs
use_x86inc
debug debug
gprof gprof
gcov gcov
@ -298,6 +294,7 @@ CONFIG_LIST="
codec_srcs codec_srcs
debug_libs debug_libs
fast_unaligned
dequant_tokens dequant_tokens
dc_recon dc_recon
@ -330,10 +327,8 @@ CONFIG_LIST="
vp9_temporal_denoising vp9_temporal_denoising
coefficient_range_checking coefficient_range_checking
vp9_highbitdepth vp9_highbitdepth
better_hw_compatibility
experimental experimental
size_limit size_limit
always_adjust_bpm
${EXPERIMENT_LIST} ${EXPERIMENT_LIST}
" "
CMDLINE_SELECT=" CMDLINE_SELECT="
@ -349,6 +344,7 @@ CMDLINE_SELECT="
gprof gprof
gcov gcov
pic pic
use_x86inc
optimizations optimizations
ccache ccache
runtime_cpu_detect runtime_cpu_detect
@ -356,11 +352,11 @@ CMDLINE_SELECT="
libs libs
examples examples
tools
docs docs
libc libc
as as
size_limit size_limit
fast_unaligned
codec_srcs codec_srcs
debug_libs debug_libs
@ -390,29 +386,23 @@ CMDLINE_SELECT="
temporal_denoising temporal_denoising
vp9_temporal_denoising vp9_temporal_denoising
coefficient_range_checking coefficient_range_checking
better_hw_compatibility
vp9_highbitdepth vp9_highbitdepth
experimental experimental
always_adjust_bpm
" "
process_cmdline() { 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
@ -426,6 +416,14 @@ process_cmdline() {
post_process_cmdline() { post_process_cmdline() {
c="" 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
@ -443,8 +441,22 @@ 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
# 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="" cf=""
@ -503,7 +515,7 @@ EOF
# #
# Write makefiles for all enabled targets # Write makefiles for all enabled targets
# #
for tgt in libs examples tools docs solution; do for tgt in libs examples docs solution; do
tgt_fn="$tgt-$toolchain.mk" tgt_fn="$tgt-$toolchain.mk"
if enabled $tgt; then if enabled $tgt; then
@ -520,18 +532,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."
@ -558,12 +565,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
@ -579,7 +590,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
@ -588,37 +601,47 @@ EOF
process_toolchain() { process_toolchain() {
process_common_toolchain process_common_toolchain
# Handle universal binaries for this architecture
case $toolchain in
universal-darwin*)
darwin_ver=${tgt_os##darwin}
# 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
check_add_cflags -Wall check_add_cflags -Wall
check_add_cflags -Wdeclaration-after-statement check_add_cflags -Wdeclaration-after-statement
check_add_cflags -Wdisabled-optimization check_add_cflags -Wdisabled-optimization
check_add_cflags -Wfloat-conversion
check_add_cflags -Wparentheses-equality
check_add_cflags -Wpointer-arith check_add_cflags -Wpointer-arith
check_add_cflags -Wtype-limits check_add_cflags -Wtype-limits
check_add_cflags -Wcast-qual check_add_cflags -Wcast-qual
check_add_cflags -Wvla check_add_cflags -Wvla
check_add_cflags -Wimplicit-function-declaration check_add_cflags -Wimplicit-function-declaration
check_add_cflags -Wuninitialized check_add_cflags -Wuninitialized
check_add_cflags -Wunused check_add_cflags -Wunused-variable
# -Wextra has some tricky cases. Rather than fix them all now, get the case ${CC} in
# flag for as many files as possible and fix the remaining issues *clang*)
# piecemeal. # libvpx and/or clang have issues with aliasing:
# https://bugs.chromium.org/p/webm/issues/detail?id=1069 # https://code.google.com/p/webm/issues/detail?id=603
check_add_cflags -Wextra # work around them until they are fixed
# check_add_cflags also adds to cxxflags. gtest does not do well with check_add_cflags -fno-strict-aliasing
# these flags so add them explicitly to CFLAGS only. ;;
check_cflags -Wundef && add_cflags_only -Wundef *) check_add_cflags -Wunused-but-set-variable ;;
check_cflags -Wframe-larger-than=52000 && \ esac
add_cflags_only -Wframe-larger-than=52000 enabled extra_warnings || check_add_cflags -Wno-unused-function
if enabled mips || [ -z "${INLINE}" ]; then
enabled extra_warnings || check_add_cflags -Wno-unused-function
fi
# Avoid this warning for third_party C++ sources. Some reorganization
# would be needed to apply this only to test/*.cc.
check_cflags -Wshorten-64-to-32 && add_cflags_only -Wshorten-64-to-32
fi fi
if enabled icc; then if enabled icc; then
@ -666,16 +689,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}
VCPROJ_SFX=vcxproj case $vs_version in
gen_vcproj_cmd=${source_path}/build/make/gen_msvs_vcxproj.sh [789])
enabled werror && gen_vcproj_cmd="${gen_vcproj_cmd} --enable-werror" VCPROJ_SFX=vcproj
gen_vcproj_cmd=${source_path}/build/make/gen_msvs_proj.sh
;;
10|11|12)
VCPROJ_SFX=vcxproj
gen_vcproj_cmd=${source_path}/build/make/gen_msvs_vcxproj.sh
enabled werror && gen_vcproj_cmd="${gen_vcproj_cmd} --enable-werror"
;;
esac
all_targets="${all_targets} solution" all_targets="${all_targets} solution"
INLINE="__inline" INLINE="__forceinline"
;; ;;
esac esac
# Other toolchain specific defaults # Other toolchain specific defaults
case $toolchain in x86*) soft_enable postproc;; esac case $toolchain in x86*|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"
@ -729,16 +760,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
} }
@ -749,7 +770,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

@ -22,44 +22,33 @@ 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_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_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 +56,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
@ -76,11 +64,8 @@ vpxdec.SRCS += tools_common.c tools_common.h
vpxdec.SRCS += y4menc.c y4menc.h vpxdec.SRCS += y4menc.c y4menc.h
ifeq ($(CONFIG_LIBYUV),yes) ifeq ($(CONFIG_LIBYUV),yes)
vpxdec.SRCS += $(LIBYUV_SRCS) vpxdec.SRCS += $(LIBYUV_SRCS)
$(BUILD_PFX)third_party/libyuv/%.cc.o: CXXFLAGS += -Wno-unused-parameter
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
@ -95,31 +80,28 @@ 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 EXAMPLES-$(CONFIG_VP9_ENCODER) += vp9_spatial_svc_encoder.c
vp9_spatial_svc_encoder.SRCS += args.c args.h vp9_spatial_svc_encoder.SRCS += args.c args.h
vp9_spatial_svc_encoder.SRCS += ivfenc.c ivfenc.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 += tools_common.c tools_common.h
vp9_spatial_svc_encoder.SRCS += video_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 += video_writer.h video_writer.c
vp9_spatial_svc_encoder.SRCS += vpx_ports/msvc.h vp9_spatial_svc_encoder.SRCS += vpxstats.c vpxstats.h
vp9_spatial_svc_encoder.SRCS += vpxstats.c vpxstats.h vp9_spatial_svc_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D
vp9_spatial_svc_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D vp9_spatial_svc_encoder.DESCRIPTION = VP9 Spatial SVC Encoder
vp9_spatial_svc_encoder.DESCRIPTION = VP9 Spatial SVC Encoder endif
ifneq ($(CONFIG_SHARED),yes) ifneq ($(CONFIG_SHARED),yes)
EXAMPLES-$(CONFIG_VP9_ENCODER) += resize_util.c EXAMPLES-$(CONFIG_VP9_ENCODER) += resize_util.c
@ -130,7 +112,6 @@ 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_DECODERS) += simple_decoder.c
@ -141,7 +122,6 @@ 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) += postproc.c EXAMPLES-$(CONFIG_DECODERS) += postproc.c
postproc.SRCS += ivfdec.h ivfdec.c postproc.SRCS += ivfdec.h ivfdec.c
@ -150,7 +130,6 @@ postproc.SRCS += video_common.h
postproc.SRCS += video_reader.h video_reader.c postproc.SRCS += video_reader.h video_reader.c
postproc.SRCS += vpx_ports/mem_ops.h postproc.SRCS += vpx_ports/mem_ops.h
postproc.SRCS += vpx_ports/mem_ops_aligned.h postproc.SRCS += vpx_ports/mem_ops_aligned.h
postproc.SRCS += vpx_ports/msvc.h
postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7 postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7
postproc.DESCRIPTION = Decoder postprocessor control postproc.DESCRIPTION = Decoder postprocessor control
EXAMPLES-$(CONFIG_DECODERS) += decode_to_md5.c EXAMPLES-$(CONFIG_DECODERS) += decode_to_md5.c
@ -161,7 +140,6 @@ 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_ENCODERS) += simple_encoder.c
@ -169,7 +147,6 @@ 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_VP9_ENCODER) += vp9_lossless_encoder.c EXAMPLES-$(CONFIG_VP9_ENCODER) += vp9_lossless_encoder.c
@ -177,7 +154,6 @@ vp9_lossless_encoder.SRCS += ivfenc.h ivfenc.c
vp9_lossless_encoder.SRCS += tools_common.h tools_common.c vp9_lossless_encoder.SRCS += tools_common.h tools_common.c
vp9_lossless_encoder.SRCS += video_common.h vp9_lossless_encoder.SRCS += video_common.h
vp9_lossless_encoder.SRCS += video_writer.h video_writer.c vp9_lossless_encoder.SRCS += video_writer.h video_writer.c
vp9_lossless_encoder.SRCS += vpx_ports/msvc.h
vp9_lossless_encoder.GUID = B63C7C88-5348-46DC-A5A6-CC151EF93366 vp9_lossless_encoder.GUID = B63C7C88-5348-46DC-A5A6-CC151EF93366
vp9_lossless_encoder.DESCRIPTION = Simplified lossless VP9 encoder vp9_lossless_encoder.DESCRIPTION = Simplified lossless VP9 encoder
EXAMPLES-$(CONFIG_ENCODERS) += twopass_encoder.c EXAMPLES-$(CONFIG_ENCODERS) += twopass_encoder.c
@ -185,7 +161,6 @@ 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 EXAMPLES-$(CONFIG_DECODERS) += decode_with_drops.c
@ -195,7 +170,6 @@ 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
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
@ -203,7 +177,6 @@ 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 EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c
@ -211,21 +184,9 @@ vp8cx_set_ref.SRCS += ivfenc.h ivfenc.c
vp8cx_set_ref.SRCS += tools_common.h tools_common.c vp8cx_set_ref.SRCS += tools_common.h tools_common.c
vp8cx_set_ref.SRCS += video_common.h vp8cx_set_ref.SRCS += video_common.h
vp8cx_set_ref.SRCS += video_writer.h video_writer.c vp8cx_set_ref.SRCS += video_writer.h video_writer.c
vp8cx_set_ref.SRCS += vpx_ports/msvc.h
vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A
vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame
ifeq ($(CONFIG_VP9_ENCODER),yes)
ifeq ($(CONFIG_DECODERS),yes)
EXAMPLES-yes += vp9cx_set_ref.c
vp9cx_set_ref.SRCS += ivfenc.h ivfenc.c
vp9cx_set_ref.SRCS += tools_common.h tools_common.c
vp9cx_set_ref.SRCS += video_common.h
vp9cx_set_ref.SRCS += video_writer.h video_writer.c
vp9cx_set_ref.GUID = 65D7F14A-2EE6-4293-B958-AB5107A03B55
vp9cx_set_ref.DESCRIPTION = VP9 set encoder reference frame
endif
endif
ifeq ($(CONFIG_MULTI_RES_ENCODING),yes) ifeq ($(CONFIG_MULTI_RES_ENCODING),yes)
ifeq ($(CONFIG_LIBYUV),yes) ifeq ($(CONFIG_LIBYUV),yes)
@ -233,7 +194,6 @@ EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8_multi_resolution_encoder.c
vp8_multi_resolution_encoder.SRCS += ivfenc.h ivfenc.c vp8_multi_resolution_encoder.SRCS += ivfenc.h ivfenc.c
vp8_multi_resolution_encoder.SRCS += tools_common.h tools_common.c vp8_multi_resolution_encoder.SRCS += tools_common.h tools_common.c
vp8_multi_resolution_encoder.SRCS += video_writer.h video_writer.c vp8_multi_resolution_encoder.SRCS += video_writer.h video_writer.c
vp8_multi_resolution_encoder.SRCS += vpx_ports/msvc.h
vp8_multi_resolution_encoder.SRCS += $(LIBYUV_SRCS) vp8_multi_resolution_encoder.SRCS += $(LIBYUV_SRCS)
vp8_multi_resolution_encoder.GUID = 04f8738e-63c8-423b-90fa-7c2703a374de vp8_multi_resolution_encoder.GUID = 04f8738e-63c8-423b-90fa-7c2703a374de
vp8_multi_resolution_encoder.DESCRIPTION = VP8 Multiple-resolution Encoding vp8_multi_resolution_encoder.DESCRIPTION = VP8 Multiple-resolution Encoding
@ -294,6 +254,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)
@ -301,28 +269,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.
@ -350,8 +314,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)=)\

View File

@ -65,12 +65,13 @@ static void get_image_md5(const vpx_image_t *img, unsigned char digest[16]) {
static void print_md5(FILE *stream, unsigned char digest[16]) { static void print_md5(FILE *stream, unsigned char digest[16]) {
int i; int i;
for (i = 0; i < 16; ++i) fprintf(stream, "%02x", digest[i]); for (i = 0; i < 16; ++i)
fprintf(stream, "%02x", digest[i]);
} }
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);
} }
@ -85,10 +86,12 @@ int main(int argc, char **argv) {
exec_name = argv[0]; exec_name = argv[0];
if (argc != 3) die("Invalid number of arguments."); if (argc != 3)
die("Invalid number of arguments.");
reader = vpx_video_reader_open(argv[1]); reader = vpx_video_reader_open(argv[1]);
if (!reader) die("Failed to open %s for reading.", argv[1]); if (!reader)
die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb"))) if (!(outfile = fopen(argv[2], "wb")))
die("Failed to open %s for writing.", argv[2]); die("Failed to open %s for writing.", argv[2]);
@ -96,7 +99,8 @@ int main(int argc, char **argv) {
info = vpx_video_reader_get_info(reader); info = vpx_video_reader_get_info(reader);
decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc); decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc);
if (!decoder) die("Unknown input codec."); if (!decoder)
die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface()));
@ -107,8 +111,8 @@ int main(int argc, char **argv) {
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL; vpx_image_t *img = NULL;
size_t frame_size = 0; size_t frame_size = 0;
const unsigned char *frame = const unsigned char *frame = vpx_video_reader_get_frame(reader,
vpx_video_reader_get_frame(reader, &frame_size); &frame_size);
if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0)) if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0))
die_codec(&codec, "Failed to decode frame"); die_codec(&codec, "Failed to decode frame");
@ -117,13 +121,14 @@ int main(int argc, char **argv) {
get_image_md5(img, digest); get_image_md5(img, digest);
print_md5(outfile, digest); print_md5(outfile, digest);
fprintf(outfile, " img-%dx%d-%04d.i420\n", img->d_w, img->d_h, fprintf(outfile, " img-%dx%d-%04d.i420\n",
++frame_cnt); img->d_w, img->d_h, ++frame_cnt);
} }
} }
printf("Processed %d frames.\n", frame_cnt); printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
vpx_video_reader_close(reader); vpx_video_reader_close(reader);

View File

@ -65,7 +65,7 @@
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);
} }
@ -84,16 +84,18 @@ int main(int argc, char **argv) {
exec_name = argv[0]; exec_name = argv[0];
if (argc != 4) die("Invalid number of arguments."); if (argc != 4)
die("Invalid number of arguments.");
reader = vpx_video_reader_open(argv[1]); reader = vpx_video_reader_open(argv[1]);
if (!reader) die("Failed to open %s for reading.", argv[1]); if (!reader)
die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb"))) if (!(outfile = fopen(argv[2], "wb")))
die("Failed to open %s for writing.", argv[2]); die("Failed to open %s for writing.", argv[2]);
n = (int)strtol(argv[3], &nptr, 0); n = strtol(argv[3], &nptr, 0);
m = (int)strtol(nptr + 1, NULL, 0); m = strtol(nptr + 1, NULL, 0);
is_range = (*nptr == '-'); is_range = (*nptr == '-');
if (!n || !m || (*nptr != '-' && *nptr != '/')) if (!n || !m || (*nptr != '-' && *nptr != '/'))
die("Couldn't parse pattern %s.\n", argv[3]); die("Couldn't parse pattern %s.\n", argv[3]);
@ -101,7 +103,8 @@ int main(int argc, char **argv) {
info = vpx_video_reader_get_info(reader); info = vpx_video_reader_get_info(reader);
decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc); decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc);
if (!decoder) die("Unknown input codec."); if (!decoder)
die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface()));
@ -113,8 +116,8 @@ int main(int argc, char **argv) {
vpx_image_t *img = NULL; vpx_image_t *img = NULL;
size_t frame_size = 0; size_t frame_size = 0;
int skip; int skip;
const unsigned char *frame = const unsigned char *frame = vpx_video_reader_get_frame(reader,
vpx_video_reader_get_frame(reader, &frame_size); &frame_size);
if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0)) if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0))
die_codec(&codec, "Failed to decode frame."); die_codec(&codec, "Failed to decode frame.");
@ -136,7 +139,8 @@ int main(int argc, char **argv) {
} }
printf("Processed %d frames.\n", frame_cnt); printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); 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", printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
info->frame_width, info->frame_height, argv[2]); info->frame_width, info->frame_height, argv[2]);

View File

@ -52,7 +52,7 @@
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);
} }
@ -68,10 +68,12 @@ int main(int argc, char **argv) {
exec_name = argv[0]; exec_name = argv[0];
if (argc != 3) die("Invalid number of arguments."); if (argc != 3)
die("Invalid number of arguments.");
reader = vpx_video_reader_open(argv[1]); reader = vpx_video_reader_open(argv[1]);
if (!reader) die("Failed to open %s for reading.", argv[1]); if (!reader)
die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb"))) if (!(outfile = fopen(argv[2], "wb")))
die("Failed to open %s for writing", argv[2]); die("Failed to open %s for writing", argv[2]);
@ -79,7 +81,8 @@ int main(int argc, char **argv) {
info = vpx_video_reader_get_info(reader); info = vpx_video_reader_get_info(reader);
decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc); decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc);
if (!decoder) die("Unknown input codec."); if (!decoder)
die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface()));
@ -88,25 +91,26 @@ int main(int argc, char **argv) {
if (res == VPX_CODEC_INCAPABLE) if (res == VPX_CODEC_INCAPABLE)
die_codec(&codec, "Postproc not supported by this decoder."); die_codec(&codec, "Postproc not supported by this decoder.");
if (res) die_codec(&codec, "Failed to initialize decoder."); if (res)
die_codec(&codec, "Failed to initialize decoder.");
while (vpx_video_reader_read_frame(reader)) { while (vpx_video_reader_read_frame(reader)) {
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL; vpx_image_t *img = NULL;
size_t frame_size = 0; size_t frame_size = 0;
const unsigned char *frame = const unsigned char *frame = vpx_video_reader_get_frame(reader,
vpx_video_reader_get_frame(reader, &frame_size); &frame_size);
++frame_cnt; ++frame_cnt;
if (frame_cnt % 30 == 1) { if (frame_cnt % 30 == 1) {
vp8_postproc_cfg_t pp = { 0, 0, 0 }; vp8_postproc_cfg_t pp = {0, 0, 0};
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp)) if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
die_codec(&codec, "Failed to turn off postproc."); die_codec(&codec, "Failed to turn off postproc.");
} else if (frame_cnt % 30 == 16) { } else if (frame_cnt % 30 == 16) {
vp8_postproc_cfg_t pp = { VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE, 4, vp8_postproc_cfg_t pp = {VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE,
0 }; 4, 0};
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp)) if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
die_codec(&codec, "Failed to turn on postproc."); die_codec(&codec, "Failed to turn on postproc.");
}; };
@ -121,7 +125,8 @@ int main(int argc, char **argv) {
} }
printf("Processed %d frames.\n", frame_cnt); printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); 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", printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
info->frame_width, info->frame_height, argv[2]); info->frame_width, info->frame_height, argv[2]);

View File

@ -15,7 +15,6 @@
#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 const char *exec_name = NULL;
@ -27,15 +26,17 @@ static void usage() {
printf("<output_yuv> [<frames>]\n"); printf("<output_yuv> [<frames>]\n");
} }
void usage_exit(void) { void usage_exit() {
usage(); usage();
exit(EXIT_FAILURE); 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) x = strchr(v, 'X'); if (x == NULL)
if (x == NULL) return 0; x = strchr(v, 'X');
if (x == NULL)
return 0;
*width = atoi(v); *width = atoi(v);
*height = atoi(&x[1]); *height = atoi(&x[1]);
if (*width <= 0 || *height <= 0) if (*width <= 0 || *height <= 0)
@ -91,25 +92,30 @@ int main(int argc, char *argv[]) {
else else
frames = INT_MAX; frames = INT_MAX;
printf("Input size: %dx%d\n", width, height); printf("Input size: %dx%d\n",
printf("Target size: %dx%d, Frames: ", target_width, target_height); width, height);
printf("Target size: %dx%d, Frames: ",
target_width, target_height);
if (frames == INT_MAX) if (frames == INT_MAX)
printf("All\n"); printf("All\n");
else else
printf("%d\n", frames); printf("%d\n", frames);
inbuf = (uint8_t *)malloc(width * height * 3 / 2); inbuf = (uint8_t*)malloc(width * height * 3 / 2);
outbuf = (uint8_t *)malloc(target_width * target_height * 3 / 2); outbuf = (uint8_t*)malloc(target_width * target_height * 3 / 2);
inbuf_u = inbuf + width * height; inbuf_u = inbuf + width * height;
inbuf_v = inbuf_u + width * height / 4; inbuf_v = inbuf_u + width * height / 4;
outbuf_u = outbuf + target_width * target_height; outbuf_u = outbuf + target_width * target_height;
outbuf_v = outbuf_u + target_width * target_height / 4; outbuf_v = outbuf_u + target_width * target_height / 4;
f = 0; f = 0;
while (f < frames) { while (f < frames) {
if (fread(inbuf, width * height * 3 / 2, 1, fpin) != 1) break; if (fread(inbuf, width * height * 3 / 2, 1, fpin) != 1)
vp9_resize_frame420(inbuf, width, inbuf_u, inbuf_v, width / 2, height, break;
width, outbuf, target_width, outbuf_u, outbuf_v, vp9_resize_frame420(inbuf, width, inbuf_u, inbuf_v, width / 2,
target_width / 2, target_height, target_width); height, width,
outbuf, target_width, outbuf_u, outbuf_v,
target_width / 2,
target_height, target_width);
fwrite(outbuf, target_width * target_height * 3 / 2, 1, fpout); fwrite(outbuf, target_width * target_height * 3 / 2, 1, fpout);
f++; f++;
} }

View File

@ -8,6 +8,7 @@
* 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.
*/ */
// VP8 Set Active and ROI Maps // VP8 Set Active and ROI Maps
// =========================== // ===========================
// //
@ -54,7 +55,7 @@
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);
@ -85,7 +86,8 @@ static void set_roi_map(const vpx_codec_enc_cfg_t *cfg,
roi.static_threshold[3] = 0; roi.static_threshold[3] = 0;
roi.roi_map = (uint8_t *)malloc(roi.rows * roi.cols); roi.roi_map = (uint8_t *)malloc(roi.rows * roi.cols);
for (i = 0; i < roi.rows * roi.cols; ++i) roi.roi_map[i] = i % 4; for (i = 0; i < roi.rows * roi.cols; ++i)
roi.roi_map[i] = i % 4;
if (vpx_codec_control(codec, VP8E_SET_ROI_MAP, &roi)) if (vpx_codec_control(codec, VP8E_SET_ROI_MAP, &roi))
die_codec(codec, "Failed to set ROI map"); die_codec(codec, "Failed to set ROI map");
@ -96,13 +98,14 @@ static void set_roi_map(const vpx_codec_enc_cfg_t *cfg,
static void set_active_map(const vpx_codec_enc_cfg_t *cfg, static void set_active_map(const vpx_codec_enc_cfg_t *cfg,
vpx_codec_ctx_t *codec) { vpx_codec_ctx_t *codec) {
unsigned int i; unsigned int i;
vpx_active_map_t map = { 0, 0, 0 }; vpx_active_map_t map = {0, 0, 0};
map.rows = (cfg->g_h + 15) / 16; map.rows = (cfg->g_h + 15) / 16;
map.cols = (cfg->g_w + 15) / 16; map.cols = (cfg->g_w + 15) / 16;
map.active_map = (uint8_t *)malloc(map.rows * map.cols); map.active_map = (uint8_t *)malloc(map.rows * map.cols);
for (i = 0; i < map.rows * map.cols; ++i) map.active_map[i] = i % 2; for (i = 0; i < map.rows * map.cols; ++i)
map.active_map[i] = i % 2;
if (vpx_codec_control(codec, VP8E_SET_ACTIVEMAP, &map)) if (vpx_codec_control(codec, VP8E_SET_ACTIVEMAP, &map))
die_codec(codec, "Failed to set active map"); die_codec(codec, "Failed to set active map");
@ -112,7 +115,7 @@ static void set_active_map(const vpx_codec_enc_cfg_t *cfg,
static void unset_active_map(const vpx_codec_enc_cfg_t *cfg, static void unset_active_map(const vpx_codec_enc_cfg_t *cfg,
vpx_codec_ctx_t *codec) { vpx_codec_ctx_t *codec) {
vpx_active_map_t map = { 0, 0, 0 }; vpx_active_map_t map = {0, 0, 0};
map.rows = (cfg->g_h + 15) / 16; map.rows = (cfg->g_h + 15) / 16;
map.cols = (cfg->g_w + 15) / 16; map.cols = (cfg->g_w + 15) / 16;
@ -122,21 +125,25 @@ 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, vpx_image_t *img, static int encode_frame(vpx_codec_ctx_t *codec,
int frame_index, VpxVideoWriter *writer) { vpx_image_t *img,
int frame_index,
VpxVideoWriter *writer) {
int got_pkts = 0; 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 = const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, 0,
vpx_codec_encode(codec, img, frame_index, 1, 0, VPX_DL_GOOD_QUALITY); VPX_DL_GOOD_QUALITY);
if (res != VPX_CODEC_OK) die_codec(codec, "Failed to encode frame"); if (res != VPX_CODEC_OK)
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; 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, pkt->data.frame.buf, if (!vpx_video_writer_write_frame(writer,
pkt->data.frame.buf,
pkt->data.frame.sz, pkt->data.frame.sz,
pkt->data.frame.pts)) { pkt->data.frame.pts)) {
die_codec(codec, "Failed to write compressed frame"); die_codec(codec, "Failed to write compressed frame");
@ -160,11 +167,12 @@ int main(int argc, char **argv) {
VpxVideoInfo info; VpxVideoInfo info;
VpxVideoWriter *writer = NULL; VpxVideoWriter *writer = NULL;
const VpxInterface *encoder = NULL; const VpxInterface *encoder = NULL;
const int fps = 2; // TODO(dkovalev) add command line argument const int fps = 2; // TODO(dkovalev) add command line argument
const double bits_per_pixel_per_frame = 0.067; const double bits_per_pixel_per_frame = 0.067;
exec_name = argv[0]; exec_name = argv[0];
if (argc != 6) die("Invalid number of arguments"); if (argc != 6)
die("Invalid number of arguments");
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
@ -174,36 +182,40 @@ int main(int argc, char **argv) {
} }
assert(encoder != NULL); assert(encoder != NULL);
info.codec_fourcc = encoder->fourcc; info.codec_fourcc = encoder->fourcc;
info.frame_width = (int)strtol(argv[2], NULL, 0); info.frame_width = strtol(argv[2], NULL, 0);
info.frame_height = (int)strtol(argv[3], NULL, 0); info.frame_height = strtol(argv[3], NULL, 0);
info.time_base.numerator = 1; info.time_base.numerator = 1;
info.time_base.denominator = fps; info.time_base.denominator = fps;
if (info.frame_width <= 0 || info.frame_height <= 0 || if (info.frame_width <= 0 ||
(info.frame_width % 2) != 0 || (info.frame_height % 2) != 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); die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
} }
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width, if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
info.frame_height, 1)) { info.frame_height, 1)) {
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->codec_interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
if (res) die_codec(&codec, "Failed to get default codec config."); if (res)
die_codec(&codec, "Failed to get default codec config.");
cfg.g_w = info.frame_width; cfg.g_w = info.frame_width;
cfg.g_h = info.frame_height; cfg.g_h = info.frame_height;
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 = cfg.rc_target_bitrate = (unsigned int)(bits_per_pixel_per_frame * cfg.g_w *
(unsigned int)(bits_per_pixel_per_frame * cfg.g_w * cfg.g_h * fps / 1000); cfg.g_h * fps / 1000);
cfg.g_lag_in_frames = 0; cfg.g_lag_in_frames = 0;
writer = vpx_video_writer_open(argv[5], kContainerIVF, &info); writer = vpx_video_writer_open(argv[5], kContainerIVF, &info);
if (!writer) die("Failed to open %s for writing.", argv[5]); if (!writer)
die("Failed to open %s for writing.", argv[5]);
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]);
@ -227,15 +239,15 @@ int main(int argc, char **argv) {
} }
// Flush encoder. // Flush encoder.
while (encode_frame(&codec, NULL, -1, writer)) { 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);
vpx_img_free(&raw); vpx_img_free(&raw);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
vpx_video_writer_close(writer); vpx_video_writer_close(writer);

View File

@ -8,6 +8,7 @@
* 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.
*/ */
// Simple Decoder // Simple Decoder
// ============== // ==============
// //
@ -87,7 +88,7 @@
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,10 +103,12 @@ int main(int argc, char **argv) {
exec_name = argv[0]; exec_name = argv[0];
if (argc != 3) die("Invalid number of arguments."); if (argc != 3)
die("Invalid number of arguments.");
reader = vpx_video_reader_open(argv[1]); reader = vpx_video_reader_open(argv[1]);
if (!reader) die("Failed to open %s for reading.", argv[1]); if (!reader)
die("Failed to open %s for reading.", argv[1]);
if (!(outfile = fopen(argv[2], "wb"))) if (!(outfile = fopen(argv[2], "wb")))
die("Failed to open %s for writing.", argv[2]); die("Failed to open %s for writing.", argv[2]);
@ -113,7 +116,8 @@ int main(int argc, char **argv) {
info = vpx_video_reader_get_info(reader); info = vpx_video_reader_get_info(reader);
decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc); decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc);
if (!decoder) die("Unknown input codec."); if (!decoder)
die("Unknown input codec.");
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface()));
@ -124,8 +128,8 @@ int main(int argc, char **argv) {
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
vpx_image_t *img = NULL; vpx_image_t *img = NULL;
size_t frame_size = 0; size_t frame_size = 0;
const unsigned char *frame = const unsigned char *frame = vpx_video_reader_get_frame(reader,
vpx_video_reader_get_frame(reader, &frame_size); &frame_size);
if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0)) if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0))
die_codec(&codec, "Failed to decode frame."); die_codec(&codec, "Failed to decode frame.");
@ -136,7 +140,8 @@ int main(int argc, char **argv) {
} }
printf("Processed %d frames.\n", frame_cnt); printf("Processed %d frames.\n", frame_cnt);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); 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", printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
info->frame_width, info->frame_height, argv[2]); info->frame_width, info->frame_height, argv[2]);

View File

@ -106,30 +106,35 @@
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, vpx_image_t *img, static int encode_frame(vpx_codec_ctx_t *codec,
int frame_index, int flags, VpxVideoWriter *writer) { vpx_image_t *img,
int frame_index,
int flags,
VpxVideoWriter *writer) {
int got_pkts = 0; 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 = const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1,
vpx_codec_encode(codec, img, frame_index, 1, flags, VPX_DL_GOOD_QUALITY); flags, VPX_DL_GOOD_QUALITY);
if (res != VPX_CODEC_OK) die_codec(codec, "Failed to encode frame"); if (res != VPX_CODEC_OK)
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; 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, pkt->data.frame.buf, if (!vpx_video_writer_write_frame(writer,
pkt->data.frame.buf,
pkt->data.frame.sz, pkt->data.frame.sz,
pkt->data.frame.pts)) { pkt->data.frame.pts)) {
die_codec(codec, "Failed to write compressed frame"); die_codec(codec, "Failed to write compressed frame");
@ -142,7 +147,6 @@ static int encode_frame(vpx_codec_ctx_t *codec, vpx_image_t *img,
return got_pkts; 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;
@ -150,14 +154,15 @@ int main(int argc, char **argv) {
int frame_count = 0; int frame_count = 0;
vpx_image_t raw; vpx_image_t raw;
vpx_codec_err_t res; vpx_codec_err_t res;
VpxVideoInfo info = { 0, 0, 0, { 0, 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;
@ -167,7 +172,8 @@ int main(int argc, char **argv) {
exec_name = argv[0]; exec_name = argv[0];
if (argc != 9) die("Invalid number of arguments"); if (argc < 7)
die("Invalid number of arguments");
codec_arg = argv[1]; codec_arg = argv[1];
width_arg = argv[2]; width_arg = argv[2];
@ -175,44 +181,49 @@ 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 = (int)strtol(argv[8], NULL, 0);
encoder = get_vpx_encoder_by_name(codec_arg); encoder = get_vpx_encoder_by_name(codec_arg);
if (!encoder) die("Unsupported codec."); if (!encoder)
die("Unsupported codec.");
info.codec_fourcc = encoder->fourcc; info.codec_fourcc = encoder->fourcc;
info.frame_width = (int)strtol(width_arg, NULL, 0); info.frame_width = strtol(width_arg, NULL, 0);
info.frame_height = (int)strtol(height_arg, NULL, 0); info.frame_height = strtol(height_arg, NULL, 0);
info.time_base.numerator = 1; info.time_base.numerator = 1;
info.time_base.denominator = fps; info.time_base.denominator = fps;
if (info.frame_width <= 0 || info.frame_height <= 0 || if (info.frame_width <= 0 ||
(info.frame_width % 2) != 0 || (info.frame_height % 2) != 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); die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
} }
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width, if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
info.frame_height, 1)) { info.frame_height, 1)) {
die("Failed to allocate image."); die("Failed to allocate image.");
} }
keyframe_interval = (int)strtol(keyframe_interval_arg, NULL, 0); keyframe_interval = strtol(keyframe_interval_arg, NULL, 0);
if (keyframe_interval < 0) die("Invalid keyframe interval value."); if (keyframe_interval < 0)
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->codec_interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
if (res) die_codec(&codec, "Failed to get default codec config."); if (res)
die_codec(&codec, "Failed to get default codec config.");
cfg.g_w = info.frame_width; cfg.g_w = info.frame_width;
cfg.g_h = info.frame_height; cfg.g_h = info.frame_height;
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 = (vpx_codec_er_flags_t)strtoul(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) die("Failed to open %s for writing.", outfile_arg); if (!writer)
die("Failed to open %s for writing.", outfile_arg);
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);
@ -226,20 +237,18 @@ int main(int argc, char **argv) {
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;
} }
// Flush encoder. // Flush encoder.
while (encode_frame(&codec, NULL, -1, 0, writer)) { while (encode_frame(&codec, NULL, -1, 0, writer)) {};
}
printf("\n"); printf("\n");
fclose(infile); fclose(infile);
printf("Processed %d frames.\n", frame_count); printf("Processed %d frames.\n", frame_count);
vpx_img_free(&raw); vpx_img_free(&raw);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
vpx_video_writer_close(writer); vpx_video_writer_close(writer);

View File

@ -58,24 +58,26 @@
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, const vpx_image_t *img, static int get_frame_stats(vpx_codec_ctx_t *ctx,
vpx_codec_pts_t pts, unsigned int duration, const vpx_image_t *img,
vpx_enc_frame_flags_t flags, unsigned int deadline, vpx_codec_pts_t pts,
unsigned int duration,
vpx_enc_frame_flags_t flags,
unsigned int deadline,
vpx_fixed_buf_t *stats) { vpx_fixed_buf_t *stats) {
int got_pkts = 0; 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 = const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
vpx_codec_encode(ctx, img, pts, duration, flags, deadline); deadline);
if (res != VPX_CODEC_OK) die_codec(ctx, "Failed to get frame stats."); if (res != VPX_CODEC_OK)
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; got_pkts = 1;
@ -92,16 +94,20 @@ static int get_frame_stats(vpx_codec_ctx_t *ctx, const vpx_image_t *img,
return got_pkts; return got_pkts;
} }
static int encode_frame(vpx_codec_ctx_t *ctx, const vpx_image_t *img, static int encode_frame(vpx_codec_ctx_t *ctx,
vpx_codec_pts_t pts, unsigned int duration, const vpx_image_t *img,
vpx_enc_frame_flags_t flags, unsigned int deadline, vpx_codec_pts_t pts,
unsigned int duration,
vpx_enc_frame_flags_t flags,
unsigned int deadline,
VpxVideoWriter *writer) { VpxVideoWriter *writer) {
int got_pkts = 0; 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 = const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
vpx_codec_encode(ctx, img, pts, duration, flags, deadline); deadline);
if (res != VPX_CODEC_OK) die_codec(ctx, "Failed to encode frame."); if (res != VPX_CODEC_OK)
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; got_pkts = 1;
@ -109,8 +115,8 @@ static int encode_frame(vpx_codec_ctx_t *ctx, const vpx_image_t *img,
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, pkt->data.frame.buf, if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
pkt->data.frame.sz, pkt->data.frame.sz,
pkt->data.frame.pts)) pkt->data.frame.pts))
die_codec(ctx, "Failed to write compressed frame."); die_codec(ctx, "Failed to write compressed frame.");
printf(keyframe ? "K" : "."); printf(keyframe ? "K" : ".");
fflush(stdout); fflush(stdout);
@ -120,12 +126,13 @@ static int encode_frame(vpx_codec_ctx_t *ctx, const vpx_image_t *img,
return got_pkts; return got_pkts;
} }
static vpx_fixed_buf_t pass0(vpx_image_t *raw, FILE *infile, static vpx_fixed_buf_t pass0(vpx_image_t *raw,
FILE *infile,
const VpxInterface *encoder, const VpxInterface *encoder,
const vpx_codec_enc_cfg_t *cfg, int max_frames) { const vpx_codec_enc_cfg_t *cfg) {
vpx_codec_ctx_t codec; vpx_codec_ctx_t codec;
int frame_count = 0; int frame_count = 0;
vpx_fixed_buf_t stats = { NULL, 0 }; vpx_fixed_buf_t stats = {NULL, 0};
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0)) if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0))
die_codec(&codec, "Failed to initialize encoder"); die_codec(&codec, "Failed to initialize encoder");
@ -135,33 +142,37 @@ static vpx_fixed_buf_t pass0(vpx_image_t *raw, FILE *infile,
++frame_count; ++frame_count;
get_frame_stats(&codec, raw, frame_count, 1, 0, VPX_DL_GOOD_QUALITY, get_frame_stats(&codec, raw, frame_count, 1, 0, VPX_DL_GOOD_QUALITY,
&stats); &stats);
if (max_frames > 0 && frame_count >= max_frames) break;
} }
// Flush encoder. // Flush encoder.
while (get_frame_stats(&codec, NULL, frame_count, 1, 0, VPX_DL_GOOD_QUALITY, while (get_frame_stats(&codec, NULL, frame_count, 1, 0,
&stats)) { VPX_DL_GOOD_QUALITY, &stats)) {}
}
printf("Pass 0 complete. Processed %d frames.\n", frame_count); printf("Pass 0 complete. Processed %d frames.\n", frame_count);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
return stats; return stats;
} }
static void pass1(vpx_image_t *raw, FILE *infile, const char *outfile_name, static void pass1(vpx_image_t *raw,
const VpxInterface *encoder, const vpx_codec_enc_cfg_t *cfg, FILE *infile,
int max_frames) { const char *outfile_name,
VpxVideoInfo info = { encoder->fourcc, const VpxInterface *encoder,
cfg->g_w, const vpx_codec_enc_cfg_t *cfg) {
cfg->g_h, VpxVideoInfo info = {
{ cfg->g_timebase.num, cfg->g_timebase.den } }; encoder->fourcc,
cfg->g_w,
cfg->g_h,
{cfg->g_timebase.num, cfg->g_timebase.den}
};
VpxVideoWriter *writer = NULL; VpxVideoWriter *writer = NULL;
vpx_codec_ctx_t codec; vpx_codec_ctx_t codec;
int frame_count = 0; int frame_count = 0;
writer = vpx_video_writer_open(outfile_name, kContainerIVF, &info); writer = vpx_video_writer_open(outfile_name, kContainerIVF, &info);
if (!writer) die("Failed to open %s for writing", outfile_name); if (!writer)
die("Failed to open %s for writing", outfile_name);
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0)) if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0))
die_codec(&codec, "Failed to initialize encoder"); die_codec(&codec, "Failed to initialize encoder");
@ -170,17 +181,15 @@ static void pass1(vpx_image_t *raw, FILE *infile, const char *outfile_name,
while (vpx_img_read(raw, infile)) { while (vpx_img_read(raw, infile)) {
++frame_count; ++frame_count;
encode_frame(&codec, raw, frame_count, 1, 0, VPX_DL_GOOD_QUALITY, writer); encode_frame(&codec, raw, frame_count, 1, 0, VPX_DL_GOOD_QUALITY, writer);
if (max_frames > 0 && frame_count >= max_frames) break;
} }
// Flush encoder. // Flush encoder.
while (encode_frame(&codec, NULL, -1, 1, 0, VPX_DL_GOOD_QUALITY, writer)) { while (encode_frame(&codec, NULL, -1, 1, 0, VPX_DL_GOOD_QUALITY, writer)) {}
}
printf("\n"); printf("\n");
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
vpx_video_writer_close(writer); vpx_video_writer_close(writer);
@ -197,27 +206,26 @@ int main(int argc, char **argv) {
vpx_fixed_buf_t stats; vpx_fixed_buf_t stats;
const VpxInterface *encoder = NULL; const VpxInterface *encoder = NULL;
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];
const char *const width_arg = argv[2]; const char *const width_arg = argv[2];
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) die("Invalid number of arguments."); if (argc != 6)
die("Invalid number of arguments.");
max_frames = (int)strtol(argv[6], NULL, 0);
encoder = get_vpx_encoder_by_name(codec_arg); encoder = get_vpx_encoder_by_name(codec_arg);
if (!encoder) die("Unsupported codec."); if (!encoder)
die("Unsupported codec.");
w = (int)strtol(width_arg, NULL, 0); w = strtol(width_arg, NULL, 0);
h = (int)strtol(height_arg, NULL, 0); h = strtol(height_arg, NULL, 0);
if (w <= 0 || h <= 0 || (w % 2) != 0 || (h % 2) != 0) if (w <= 0 || h <= 0 || (w % 2) != 0 || (h % 2) != 0)
die("Invalid frame size: %dx%d", w, h); die("Invalid frame size: %dx%d", w, h);
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, w, h, 1)) if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, w, h, 1))
@ -227,7 +235,8 @@ int main(int argc, char **argv) {
// Configuration // Configuration
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
if (res) die_codec(&codec, "Failed to get default codec config."); if (res)
die_codec(&codec, "Failed to get default codec config.");
cfg.g_w = w; cfg.g_w = w;
cfg.g_h = h; cfg.g_h = h;
@ -240,13 +249,13 @@ int main(int argc, char **argv) {
// Pass 0 // Pass 0
cfg.g_pass = VPX_RC_FIRST_PASS; cfg.g_pass = VPX_RC_FIRST_PASS;
stats = pass0(&raw, infile, encoder, &cfg, max_frames); stats = pass0(&raw, infile, encoder, &cfg);
// Pass 1 // Pass 1
rewind(infile); rewind(infile);
cfg.g_pass = VPX_RC_LAST_PASS; cfg.g_pass = VPX_RC_LAST_PASS;
cfg.rc_twopass_stats_in = stats; cfg.rc_twopass_stats_in = stats;
pass1(&raw, infile, outfile_arg, encoder, &cfg, max_frames); pass1(&raw, infile, outfile_arg, encoder, &cfg);
free(stats.buf); free(stats.buf);
vpx_img_free(&raw); vpx_img_free(&raw);

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@
* 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.
*/ */
// VP8 Set Reference Frame // VP8 Set Reference Frame
// ======================= // =======================
// //
@ -51,34 +52,37 @@
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "vp8/common/common.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, vpx_image_t *img, static int encode_frame(vpx_codec_ctx_t *codec,
int frame_index, VpxVideoWriter *writer) { vpx_image_t *img,
int frame_index,
VpxVideoWriter *writer) {
int got_pkts = 0; 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 = const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, 0,
vpx_codec_encode(codec, img, frame_index, 1, 0, VPX_DL_GOOD_QUALITY); VPX_DL_GOOD_QUALITY);
if (res != VPX_CODEC_OK) die_codec(codec, "Failed to encode frame"); if (res != VPX_CODEC_OK)
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; 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, pkt->data.frame.buf, if (!vpx_video_writer_write_frame(writer,
pkt->data.frame.buf,
pkt->data.frame.sz, pkt->data.frame.sz,
pkt->data.frame.pts)) { pkt->data.frame.pts)) {
die_codec(codec, "Failed to write compressed frame"); die_codec(codec, "Failed to write compressed frame");
@ -94,53 +98,55 @@ static int encode_frame(vpx_codec_ctx_t *codec, vpx_image_t *img,
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 = {0};
vpx_codec_enc_cfg_t cfg; vpx_codec_enc_cfg_t cfg = {0};
int frame_count = 0; int frame_count = 0;
vpx_image_t raw; vpx_image_t raw;
vpx_codec_err_t res; vpx_codec_err_t res;
VpxVideoInfo info; VpxVideoInfo info = {0};
VpxVideoWriter *writer = NULL; VpxVideoWriter *writer = NULL;
const VpxInterface *encoder = NULL; const VpxInterface *encoder = NULL;
int update_frame_num = 0; int update_frame_num = 0;
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
vp8_zero(codec);
vp8_zero(cfg);
vp8_zero(info);
exec_name = argv[0]; exec_name = argv[0];
if (argc != 6) die("Invalid number of arguments"); if (argc != 6)
die("Invalid number of arguments");
// TODO(dkovalev): add vp9 support and rename the file accordingly // TODO(dkovalev): add vp9 support and rename the file accordingly
encoder = get_vpx_encoder_by_name("vp8"); encoder = get_vpx_encoder_by_name("vp8");
if (!encoder) die("Unsupported codec."); if (!encoder)
die("Unsupported codec.");
update_frame_num = atoi(argv[5]); update_frame_num = atoi(argv[5]);
if (!update_frame_num) die("Couldn't parse frame number '%s'\n", argv[5]); if (!update_frame_num)
die("Couldn't parse frame number '%s'\n", argv[5]);
info.codec_fourcc = encoder->fourcc; info.codec_fourcc = encoder->fourcc;
info.frame_width = (int)strtol(argv[1], NULL, 0); info.frame_width = strtol(argv[1], NULL, 0);
info.frame_height = (int)strtol(argv[2], NULL, 0); info.frame_height = strtol(argv[2], NULL, 0);
info.time_base.numerator = 1; info.time_base.numerator = 1;
info.time_base.denominator = fps; info.time_base.denominator = fps;
if (info.frame_width <= 0 || info.frame_height <= 0 || if (info.frame_width <= 0 ||
(info.frame_width % 2) != 0 || (info.frame_height % 2) != 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); die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
} }
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width, if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
info.frame_height, 1)) { info.frame_height, 1)) {
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->codec_interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
if (res) die_codec(&codec, "Failed to get default codec config."); if (res)
die_codec(&codec, "Failed to get default codec config.");
cfg.g_w = info.frame_width; cfg.g_w = info.frame_width;
cfg.g_h = info.frame_height; cfg.g_h = info.frame_height;
@ -149,7 +155,8 @@ int main(int argc, char **argv) {
cfg.rc_target_bitrate = bitrate; cfg.rc_target_bitrate = bitrate;
writer = vpx_video_writer_open(argv[4], kContainerIVF, &info); writer = vpx_video_writer_open(argv[4], kContainerIVF, &info);
if (!writer) die("Failed to open %s for writing.", argv[4]); if (!writer)
die("Failed to open %s for writing.", argv[4]);
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]);
@ -171,15 +178,15 @@ int main(int argc, char **argv) {
} }
// Flush encoder. // Flush encoder.
while (encode_frame(&codec, NULL, -1, writer)) { 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);
vpx_img_free(&raw); vpx_img_free(&raw);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
vpx_video_writer_close(writer); vpx_video_writer_close(writer);

View File

@ -14,36 +14,39 @@
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#include "vp9/common/vp9_common.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, "vp9_lossless_encoder: Example demonstrating VP9 lossless "
"vp9_lossless_encoder: Example demonstrating VP9 lossless " "encoding feature. Supports raw input only.\n");
"encoding feature. Supports raw input only.\n");
fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile>\n", exec_name); fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile>\n", exec_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
static int encode_frame(vpx_codec_ctx_t *codec, vpx_image_t *img, static int encode_frame(vpx_codec_ctx_t *codec,
int frame_index, int flags, VpxVideoWriter *writer) { vpx_image_t *img,
int frame_index,
int flags,
VpxVideoWriter *writer) {
int got_pkts = 0; 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 = const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1,
vpx_codec_encode(codec, img, frame_index, 1, flags, VPX_DL_GOOD_QUALITY); flags, VPX_DL_GOOD_QUALITY);
if (res != VPX_CODEC_OK) die_codec(codec, "Failed to encode frame"); if (res != VPX_CODEC_OK)
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; 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, pkt->data.frame.buf, if (!vpx_video_writer_write_frame(writer,
pkt->data.frame.buf,
pkt->data.frame.sz, pkt->data.frame.sz,
pkt->data.frame.pts)) { pkt->data.frame.pts)) {
die_codec(codec, "Failed to write compressed frame"); die_codec(codec, "Failed to write compressed frame");
@ -63,40 +66,43 @@ int main(int argc, char **argv) {
int frame_count = 0; int frame_count = 0;
vpx_image_t raw; vpx_image_t raw;
vpx_codec_err_t res; vpx_codec_err_t res;
VpxVideoInfo info; 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;
vp9_zero(info);
exec_name = argv[0]; exec_name = argv[0];
if (argc < 5) die("Invalid number of arguments"); if (argc < 5)
die("Invalid number of arguments");
encoder = get_vpx_encoder_by_name("vp9"); encoder = get_vpx_encoder_by_name("vp9");
if (!encoder) die("Unsupported codec."); if (!encoder)
die("Unsupported codec.");
info.codec_fourcc = encoder->fourcc; info.codec_fourcc = encoder->fourcc;
info.frame_width = (int)strtol(argv[1], NULL, 0); info.frame_width = strtol(argv[1], NULL, 0);
info.frame_height = (int)strtol(argv[2], NULL, 0); info.frame_height = strtol(argv[2], NULL, 0);
info.time_base.numerator = 1; info.time_base.numerator = 1;
info.time_base.denominator = fps; info.time_base.denominator = fps;
if (info.frame_width <= 0 || info.frame_height <= 0 || if (info.frame_width <= 0 ||
(info.frame_width % 2) != 0 || (info.frame_height % 2) != 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); die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
} }
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width, if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
info.frame_height, 1)) { info.frame_height, 1)) {
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->codec_interface()));
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
if (res) die_codec(&codec, "Failed to get default codec config."); if (res)
die_codec(&codec, "Failed to get default codec config.");
cfg.g_w = info.frame_width; cfg.g_w = info.frame_width;
cfg.g_h = info.frame_height; cfg.g_h = info.frame_height;
@ -104,7 +110,8 @@ int main(int argc, char **argv) {
cfg.g_timebase.den = info.time_base.denominator; cfg.g_timebase.den = info.time_base.denominator;
writer = vpx_video_writer_open(argv[4], kContainerIVF, &info); writer = vpx_video_writer_open(argv[4], kContainerIVF, &info);
if (!writer) die("Failed to open %s for writing.", argv[4]); if (!writer)
die("Failed to open %s for writing.", argv[4]);
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]);
@ -121,15 +128,15 @@ int main(int argc, char **argv) {
} }
// Flush encoder. // Flush encoder.
while (encode_frame(&codec, NULL, -1, 0, writer)) { while (encode_frame(&codec, NULL, -1, 0, writer)) {}
}
printf("\n"); printf("\n");
fclose(infile); fclose(infile);
printf("Processed %d frames.\n", frame_count); printf("Processed %d frames.\n", frame_count);
vpx_img_free(&raw); vpx_img_free(&raw);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec.");
vpx_video_writer_close(writer); vpx_video_writer_close(writer);

View File

@ -14,7 +14,6 @@
* that benefit from a scalable bitstream. * that benefit from a scalable bitstream.
*/ */
#include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -24,24 +23,15 @@
#include "../tools_common.h" #include "../tools_common.h"
#include "../video_writer.h" #include "../video_writer.h"
#include "../vpx_ports/vpx_timer.h"
#include "vpx/svc_context.h" #include "vpx/svc_context.h"
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "../vpxstats.h" #include "../vpxstats.h"
#include "vp9/encoder/vp9_encoder.h"
#define OUTPUT_RC_STATS 1
static const arg_def_t skip_frames_arg = static const arg_def_t skip_frames_arg =
ARG_DEF("s", "skip-frames", 1, "input frames to skip"); ARG_DEF("s", "skip-frames", 1, "input frames to skip");
static const arg_def_t frames_arg = static const arg_def_t frames_arg =
ARG_DEF("f", "frames", 1, "number of frames to encode"); ARG_DEF("f", "frames", 1, "number of frames to encode");
static const arg_def_t threads_arg =
ARG_DEF("th", "threads", 1, "number of threads to use");
#if OUTPUT_RC_STATS
static const arg_def_t output_rc_stats_arg =
ARG_DEF("rcstat", "output_rc_stats", 1, "output rc stats");
#endif
static const arg_def_t width_arg = ARG_DEF("w", "width", 1, "source width"); 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 height_arg = ARG_DEF("h", "height", 1, "source height");
static const arg_def_t timebase_arg = static const arg_def_t timebase_arg =
@ -52,10 +42,6 @@ static const arg_def_t spatial_layers_arg =
ARG_DEF("sl", "spatial-layers", 1, "number of spatial SVC layers"); ARG_DEF("sl", "spatial-layers", 1, "number of spatial SVC layers");
static const arg_def_t temporal_layers_arg = static const arg_def_t temporal_layers_arg =
ARG_DEF("tl", "temporal-layers", 1, "number of temporal SVC layers"); ARG_DEF("tl", "temporal-layers", 1, "number of temporal SVC layers");
static const arg_def_t temporal_layering_mode_arg =
ARG_DEF("tlm", "temporal-layering-mode", 1,
"temporal layering scheme."
"VP9E_TEMPORAL_LAYERING_MODE");
static const arg_def_t kf_dist_arg = static const arg_def_t kf_dist_arg =
ARG_DEF("k", "kf-dist", 1, "number of frames between keyframes"); ARG_DEF("k", "kf-dist", 1, "number of frames between keyframes");
static const arg_def_t scale_factors_arg = static const arg_def_t scale_factors_arg =
@ -75,59 +61,36 @@ static const arg_def_t min_bitrate_arg =
static const arg_def_t max_bitrate_arg = static const arg_def_t max_bitrate_arg =
ARG_DEF(NULL, "max-bitrate", 1, "Maximum bitrate"); ARG_DEF(NULL, "max-bitrate", 1, "Maximum bitrate");
static const arg_def_t lag_in_frame_arg = static const arg_def_t lag_in_frame_arg =
ARG_DEF(NULL, "lag-in-frames", 1, ARG_DEF(NULL, "lag-in-frames", 1, "Number of frame to input before "
"Number of frame to input before " "generating any outputs");
"generating any outputs");
static const arg_def_t rc_end_usage_arg = static const arg_def_t rc_end_usage_arg =
ARG_DEF(NULL, "rc-end-usage", 1, "0 - 3: VBR, CBR, CQ, Q"); ARG_DEF(NULL, "rc-end-usage", 1, "0 - 3: VBR, CBR, CQ, Q");
static const arg_def_t speed_arg =
ARG_DEF("sp", "speed", 1, "speed configuration");
static const arg_def_t aqmode_arg =
ARG_DEF("aq", "aqmode", 1, "aq-mode off/on");
static const arg_def_t bitrates_arg =
ARG_DEF("bl", "bitrates", 1, "bitrates[sl * num_tl + tl]");
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
static const struct arg_enum_list bitdepth_enum[] = { static const struct arg_enum_list bitdepth_enum[] = {
{ "8", VPX_BITS_8 }, { "10", VPX_BITS_10 }, { "12", VPX_BITS_12 }, { NULL, 0 } {"8", VPX_BITS_8},
{"10", VPX_BITS_10},
{"12", VPX_BITS_12},
{NULL, 0}
}; };
static const arg_def_t bitdepth_arg = ARG_DEF_ENUM( static const arg_def_t bitdepth_arg =
"d", "bit-depth", 1, "Bit depth for codec 8, 10 or 12. ", bitdepth_enum); ARG_DEF_ENUM("d", "bit-depth", 1, "Bit depth for codec 8, 10 or 12. ",
bitdepth_enum);
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
static const arg_def_t *svc_args[] = { &frames_arg,
&width_arg,
&height_arg,
&timebase_arg,
&bitrate_arg,
&skip_frames_arg,
&spatial_layers_arg,
&kf_dist_arg,
&scale_factors_arg,
&passes_arg,
&pass_arg,
&fpf_name_arg,
&min_q_arg,
&max_q_arg,
&min_bitrate_arg,
&max_bitrate_arg,
&temporal_layers_arg,
&temporal_layering_mode_arg,
&lag_in_frame_arg,
&threads_arg,
&aqmode_arg,
#if OUTPUT_RC_STATS
&output_rc_stats_arg,
#endif
static const arg_def_t *svc_args[] = {
&frames_arg, &width_arg, &height_arg,
&timebase_arg, &bitrate_arg, &skip_frames_arg, &spatial_layers_arg,
&kf_dist_arg, &scale_factors_arg, &passes_arg, &pass_arg,
&fpf_name_arg, &min_q_arg, &max_q_arg, &min_bitrate_arg,
&max_bitrate_arg, &temporal_layers_arg, &lag_in_frame_arg,
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
&bitdepth_arg, &bitdepth_arg,
#endif #endif
&speed_arg, &rc_end_usage_arg, NULL
&rc_end_usage_arg, };
&bitrates_arg,
NULL };
static const uint32_t default_frames_to_skip = 0; static const uint32_t default_frames_to_skip = 0;
static const uint32_t default_frames_to_code = 60 * 60; static const uint32_t default_frames_to_code = 60 * 60;
@ -139,10 +102,6 @@ static const uint32_t default_bitrate = 1000;
static const uint32_t default_spatial_layers = 5; static const uint32_t default_spatial_layers = 5;
static const uint32_t default_temporal_layers = 1; static const uint32_t default_temporal_layers = 1;
static const uint32_t default_kf_dist = 100; static const uint32_t default_kf_dist = 100;
static const uint32_t default_temporal_layering_mode = 0;
static const uint32_t default_output_rc_stats = 0;
static const int32_t default_speed = -1; // -1 means use library default.
static const uint32_t default_threads = 0; // zero means use library default.
typedef struct { typedef struct {
const char *input_filename; const char *input_filename;
@ -157,7 +116,7 @@ typedef struct {
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { void usage_exit() {
fprintf(stderr, "Usage: %s <options> input_filename output_filename\n", fprintf(stderr, "Usage: %s <options> input_filename output_filename\n",
exec_name); exec_name);
fprintf(stderr, "Options:\n"); fprintf(stderr, "Options:\n");
@ -168,7 +127,7 @@ void usage_exit(void) {
static void parse_command_line(int argc, const char **argv_, static void parse_command_line(int argc, const char **argv_,
AppInput *app_input, SvcContext *svc_ctx, AppInput *app_input, SvcContext *svc_ctx,
vpx_codec_enc_cfg_t *enc_cfg) { vpx_codec_enc_cfg_t *enc_cfg) {
struct arg arg; struct arg arg = {0};
char **argv = NULL; char **argv = NULL;
char **argi = NULL; char **argi = NULL;
char **argj = NULL; char **argj = NULL;
@ -178,18 +137,12 @@ static void parse_command_line(int argc, const char **argv_,
const char *fpf_file_name = NULL; const char *fpf_file_name = NULL;
unsigned int min_bitrate = 0; unsigned int min_bitrate = 0;
unsigned int max_bitrate = 0; unsigned int max_bitrate = 0;
char string_options[1024] = { 0 }; char string_options[1024] = {0};
// initialize SvcContext with parameters that will be passed to vpx_svc_init // initialize SvcContext with parameters that will be passed to vpx_svc_init
svc_ctx->log_level = SVC_LOG_DEBUG; svc_ctx->log_level = SVC_LOG_DEBUG;
svc_ctx->spatial_layers = default_spatial_layers; svc_ctx->spatial_layers = default_spatial_layers;
svc_ctx->temporal_layers = default_temporal_layers; svc_ctx->temporal_layers = default_temporal_layers;
svc_ctx->temporal_layering_mode = default_temporal_layering_mode;
#if OUTPUT_RC_STATS
svc_ctx->output_rc_stat = default_output_rc_stats;
#endif
svc_ctx->speed = default_speed;
svc_ctx->threads = default_threads;
// start with default encoder configuration // start with default encoder configuration
res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0); res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0);
@ -231,31 +184,12 @@ static void parse_command_line(int argc, const char **argv_,
svc_ctx->spatial_layers = arg_parse_uint(&arg); svc_ctx->spatial_layers = arg_parse_uint(&arg);
} else if (arg_match(&arg, &temporal_layers_arg, argi)) { } else if (arg_match(&arg, &temporal_layers_arg, argi)) {
svc_ctx->temporal_layers = arg_parse_uint(&arg); svc_ctx->temporal_layers = arg_parse_uint(&arg);
#if OUTPUT_RC_STATS
} else if (arg_match(&arg, &output_rc_stats_arg, argi)) {
svc_ctx->output_rc_stat = arg_parse_uint(&arg);
#endif
} else if (arg_match(&arg, &speed_arg, argi)) {
svc_ctx->speed = arg_parse_uint(&arg);
} else if (arg_match(&arg, &aqmode_arg, argi)) {
svc_ctx->aqmode = arg_parse_uint(&arg);
} else if (arg_match(&arg, &threads_arg, argi)) {
svc_ctx->threads = arg_parse_uint(&arg);
} else if (arg_match(&arg, &temporal_layering_mode_arg, argi)) {
svc_ctx->temporal_layering_mode = enc_cfg->temporal_layering_mode =
arg_parse_int(&arg);
if (svc_ctx->temporal_layering_mode) {
enc_cfg->g_error_resilient = 1;
}
} else if (arg_match(&arg, &kf_dist_arg, argi)) { } else if (arg_match(&arg, &kf_dist_arg, argi)) {
enc_cfg->kf_min_dist = arg_parse_uint(&arg); enc_cfg->kf_min_dist = arg_parse_uint(&arg);
enc_cfg->kf_max_dist = enc_cfg->kf_min_dist; enc_cfg->kf_max_dist = enc_cfg->kf_min_dist;
} else if (arg_match(&arg, &scale_factors_arg, argi)) { } else if (arg_match(&arg, &scale_factors_arg, argi)) {
snprintf(string_options, sizeof(string_options), "%s scale-factors=%s", snprintf(string_options, sizeof(string_options), "%s scale-factors=%s",
string_options, arg.val); string_options, arg.val);
} else if (arg_match(&arg, &bitrates_arg, argi)) {
snprintf(string_options, sizeof(string_options), "%s bitrates=%s",
string_options, arg.val);
} else if (arg_match(&arg, &passes_arg, argi)) { } else if (arg_match(&arg, &passes_arg, argi)) {
passes = arg_parse_uint(&arg); passes = arg_parse_uint(&arg);
if (passes < 1 || passes > 2) { if (passes < 1 || passes > 2) {
@ -294,7 +228,7 @@ static void parse_command_line(int argc, const char **argv_,
enc_cfg->g_input_bit_depth = 10; enc_cfg->g_input_bit_depth = 10;
enc_cfg->g_profile = 2; enc_cfg->g_profile = 2;
break; break;
case VPX_BITS_12: case VPX_BITS_12:
enc_cfg->g_input_bit_depth = 12; enc_cfg->g_input_bit_depth = 12;
enc_cfg->g_profile = 2; enc_cfg->g_profile = 2;
break; break;
@ -376,249 +310,16 @@ static void parse_command_line(int argc, const char **argv_,
"num: %d, den: %d, bitrate: %d,\n" "num: %d, den: %d, bitrate: %d,\n"
"gop size: %d\n", "gop size: %d\n",
vpx_codec_iface_name(vpx_codec_vp9_cx()), app_input->frames_to_code, vpx_codec_iface_name(vpx_codec_vp9_cx()), app_input->frames_to_code,
app_input->frames_to_skip, svc_ctx->spatial_layers, enc_cfg->g_w, app_input->frames_to_skip,
enc_cfg->g_h, enc_cfg->g_timebase.num, enc_cfg->g_timebase.den, 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); enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist);
} }
#if OUTPUT_RC_STATS
// For rate control encoding stats.
struct RateControlStats {
// Number of input frames per layer.
int layer_input_frames[VPX_MAX_LAYERS];
// Total (cumulative) number of encoded frames per layer.
int layer_tot_enc_frames[VPX_MAX_LAYERS];
// Number of encoded non-key frames per layer.
int layer_enc_frames[VPX_MAX_LAYERS];
// Framerate per layer (cumulative).
double layer_framerate[VPX_MAX_LAYERS];
// Target average frame size per layer (per-frame-bandwidth per layer).
double layer_pfb[VPX_MAX_LAYERS];
// Actual average frame size per layer.
double layer_avg_frame_size[VPX_MAX_LAYERS];
// Average rate mismatch per layer (|target - actual| / target).
double layer_avg_rate_mismatch[VPX_MAX_LAYERS];
// Actual encoding bitrate per layer (cumulative).
double layer_encoding_bitrate[VPX_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-time encoding bitrate.
int window_size;
// Number of window measurements.
int window_count;
};
// Note: these rate control stats assume only 1 key frame in the
// sequence (i.e., first frame only).
static void set_rate_control_stats(struct RateControlStats *rc,
vpx_codec_enc_cfg_t *cfg) {
unsigned int sl, tl;
// Set the layer (cumulative) framerate and the target layer (non-cumulative)
// per-frame-bandwidth, for the rate control encoding stats below.
const double framerate = cfg->g_timebase.den / cfg->g_timebase.num;
for (sl = 0; sl < cfg->ss_number_layers; ++sl) {
for (tl = 0; tl < cfg->ts_number_layers; ++tl) {
const int layer = sl * cfg->ts_number_layers + tl;
if (cfg->ts_number_layers == 1)
rc->layer_framerate[layer] = framerate;
else
rc->layer_framerate[layer] = framerate / cfg->ts_rate_decimator[tl];
if (tl > 0) {
rc->layer_pfb[layer] =
1000.0 *
(cfg->layer_target_bitrate[layer] -
cfg->layer_target_bitrate[layer - 1]) /
(rc->layer_framerate[layer] - rc->layer_framerate[layer - 1]);
} else {
rc->layer_pfb[layer] = 1000.0 * cfg->layer_target_bitrate[layer] /
rc->layer_framerate[layer];
}
rc->layer_input_frames[layer] = 0;
rc->layer_enc_frames[layer] = 0;
rc->layer_tot_enc_frames[layer] = 0;
rc->layer_encoding_bitrate[layer] = 0.0;
rc->layer_avg_frame_size[layer] = 0.0;
rc->layer_avg_rate_mismatch[layer] = 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 RateControlStats *rc,
vpx_codec_enc_cfg_t *cfg,
int frame_cnt) {
unsigned int sl, tl;
double perc_fluctuation = 0.0;
int tot_num_frames = 0;
printf("Total number of processed frames: %d\n\n", frame_cnt - 1);
printf("Rate control layer stats for sl%d tl%d layer(s):\n\n",
cfg->ss_number_layers, cfg->ts_number_layers);
for (sl = 0; sl < cfg->ss_number_layers; ++sl) {
tot_num_frames = 0;
for (tl = 0; tl < cfg->ts_number_layers; ++tl) {
const int layer = sl * cfg->ts_number_layers + tl;
const int num_dropped =
(tl > 0)
? (rc->layer_input_frames[layer] - rc->layer_enc_frames[layer])
: (rc->layer_input_frames[layer] - rc->layer_enc_frames[layer] -
1);
tot_num_frames += rc->layer_input_frames[layer];
rc->layer_encoding_bitrate[layer] = 0.001 * rc->layer_framerate[layer] *
rc->layer_encoding_bitrate[layer] /
tot_num_frames;
rc->layer_avg_frame_size[layer] =
rc->layer_avg_frame_size[layer] / rc->layer_enc_frames[layer];
rc->layer_avg_rate_mismatch[layer] = 100.0 *
rc->layer_avg_rate_mismatch[layer] /
rc->layer_enc_frames[layer];
printf("For layer#: sl%d tl%d \n", sl, tl);
printf("Bitrate (target vs actual): %d %f.0 kbps\n",
cfg->layer_target_bitrate[layer],
rc->layer_encoding_bitrate[layer]);
printf("Average frame size (target vs actual): %f %f bits\n",
rc->layer_pfb[layer], rc->layer_avg_frame_size[layer]);
printf("Average rate_mismatch: %f\n", rc->layer_avg_rate_mismatch[layer]);
printf(
"Number of input frames, encoded (non-key) frames, "
"and percent dropped frames: %d %d %f.0 \n",
rc->layer_input_frames[layer], rc->layer_enc_frames[layer],
100.0 * num_dropped / rc->layer_input_frames[layer]);
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);
printf("Num of input, num of encoded (super) frames: %d %d \n", frame_cnt,
tot_num_frames);
}
vpx_codec_err_t parse_superframe_index(const uint8_t *data, size_t data_sz,
uint64_t sizes[8], int *count) {
// A chunk ending with a byte matching 0xc0 is an invalid chunk unless
// it is a super frame index. If the last byte of real video compression
// data is 0xc0 the encoder must add a 0 byte. If we have the marker but
// not the associated matching marker byte at the front of the index we have
// an invalid bitstream and need to return an error.
uint8_t marker;
marker = *(data + data_sz - 1);
*count = 0;
if ((marker & 0xe0) == 0xc0) {
const uint32_t frames = (marker & 0x7) + 1;
const uint32_t mag = ((marker >> 3) & 0x3) + 1;
const size_t index_sz = 2 + mag * frames;
// This chunk is marked as having a superframe index but doesn't have
// enough data for it, thus it's an invalid superframe index.
if (data_sz < index_sz) return VPX_CODEC_CORRUPT_FRAME;
{
const uint8_t marker2 = *(data + data_sz - index_sz);
// This chunk is marked as having a superframe index but doesn't have
// the matching marker byte at the front of the index therefore it's an
// invalid chunk.
if (marker != marker2) return VPX_CODEC_CORRUPT_FRAME;
}
{
// Found a valid superframe index.
uint32_t i, j;
const uint8_t *x = &data[data_sz - index_sz + 1];
for (i = 0; i < frames; ++i) {
uint32_t this_sz = 0;
for (j = 0; j < mag; ++j) this_sz |= (*x++) << (j * 8);
sizes[i] = this_sz;
}
*count = frames;
}
}
return VPX_CODEC_OK;
}
#endif
// Example pattern for spatial layers and 2 temporal layers used in the
// bypass/flexible mode. The pattern corresponds to the pattern
// VP9E_TEMPORAL_LAYERING_MODE_0101 (temporal_layering_mode == 2) used in
// non-flexible mode.
void set_frame_flags_bypass_mode(int tl, int num_spatial_layers,
int is_key_frame,
vpx_svc_ref_frame_config_t *ref_frame_config) {
int sl;
for (sl = 0; sl < num_spatial_layers; ++sl) {
if (!tl) {
if (!sl) {
ref_frame_config->frame_flags[sl] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF;
} else {
if (is_key_frame) {
ref_frame_config->frame_flags[sl] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
} else {
ref_frame_config->frame_flags[sl] =
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
}
}
} else if (tl == 1) {
if (!sl) {
ref_frame_config->frame_flags[sl] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_GF;
} else {
ref_frame_config->frame_flags[sl] =
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
if (sl == num_spatial_layers - 1)
ref_frame_config->frame_flags[sl] =
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
}
}
if (tl == 0) {
ref_frame_config->lst_fb_idx[sl] = sl;
if (sl) {
if (is_key_frame) {
ref_frame_config->lst_fb_idx[sl] = sl - 1;
ref_frame_config->gld_fb_idx[sl] = sl;
} else {
ref_frame_config->gld_fb_idx[sl] = sl - 1;
}
} else {
ref_frame_config->gld_fb_idx[sl] = 0;
}
ref_frame_config->alt_fb_idx[sl] = 0;
} else if (tl == 1) {
ref_frame_config->lst_fb_idx[sl] = sl;
ref_frame_config->gld_fb_idx[sl] = num_spatial_layers + sl - 1;
ref_frame_config->alt_fb_idx[sl] = num_spatial_layers + sl;
}
}
}
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
AppInput app_input; AppInput app_input = {0};
VpxVideoWriter *writer = NULL; VpxVideoWriter *writer = NULL;
VpxVideoInfo info; VpxVideoInfo info = {0};
vpx_codec_ctx_t codec; vpx_codec_ctx_t codec;
vpx_codec_enc_cfg_t enc_cfg; vpx_codec_enc_cfg_t enc_cfg;
SvcContext svc_ctx; SvcContext svc_ctx;
@ -631,29 +332,16 @@ int main(int argc, const char **argv) {
FILE *infile = NULL; FILE *infile = NULL;
int end_of_stream = 0; int end_of_stream = 0;
int frames_received = 0; int frames_received = 0;
#if OUTPUT_RC_STATS
VpxVideoWriter *outfile[VPX_SS_MAX_LAYERS] = { NULL };
struct RateControlStats rc;
vpx_svc_layer_id_t layer_id;
vpx_svc_ref_frame_config_t ref_frame_config;
unsigned int sl, tl;
double sum_bitrate = 0.0;
double sum_bitrate2 = 0.0;
double framerate = 30.0;
#endif
struct vpx_usec_timer timer;
int64_t cx_time = 0;
memset(&svc_ctx, 0, sizeof(svc_ctx)); memset(&svc_ctx, 0, sizeof(svc_ctx));
memset(&app_input, 0, sizeof(AppInput)); svc_ctx.log_print = 1;
memset(&info, 0, sizeof(VpxVideoInfo));
exec_name = argv[0]; exec_name = argv[0];
parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg); parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg);
// Allocate image buffer // Allocate image buffer
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
if (!vpx_img_alloc(&raw, if (!vpx_img_alloc(&raw, enc_cfg.g_input_bit_depth == 8 ?
enc_cfg.g_input_bit_depth == 8 ? VPX_IMG_FMT_I420 VPX_IMG_FMT_I420 : VPX_IMG_FMT_I42016,
: VPX_IMG_FMT_I42016,
enc_cfg.g_w, enc_cfg.g_h, 32)) { 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); die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h);
} }
@ -671,64 +359,21 @@ int main(int argc, const char **argv) {
VPX_CODEC_OK) VPX_CODEC_OK)
die("Failed to initialize encoder\n"); die("Failed to initialize encoder\n");
#if OUTPUT_RC_STATS
rc.window_count = 1;
rc.window_size = 15; // Silence a static analysis warning.
rc.avg_st_encoding_bitrate = 0.0;
rc.variance_st_encoding_bitrate = 0.0;
if (svc_ctx.output_rc_stat) {
set_rate_control_stats(&rc, &enc_cfg);
framerate = enc_cfg.g_timebase.den / enc_cfg.g_timebase.num;
}
#endif
info.codec_fourcc = VP9_FOURCC; info.codec_fourcc = VP9_FOURCC;
info.time_base.numerator = enc_cfg.g_timebase.num; info.time_base.numerator = enc_cfg.g_timebase.num;
info.time_base.denominator = enc_cfg.g_timebase.den; info.time_base.denominator = enc_cfg.g_timebase.den;
if (!(app_input.passes == 2 && app_input.pass == 1)) { if (!(app_input.passes == 2 && app_input.pass == 1)) {
// We don't save the bitstream for the 1st pass on two pass rate control // We don't save the bitstream for the 1st pass on two pass rate control
writer = writer = vpx_video_writer_open(app_input.output_filename, kContainerIVF,
vpx_video_writer_open(app_input.output_filename, kContainerIVF, &info); &info);
if (!writer) if (!writer)
die("Failed to open %s for writing\n", app_input.output_filename); die("Failed to open %s for writing\n", app_input.output_filename);
} }
#if OUTPUT_RC_STATS
// Write out spatial layer stream.
// TODO(marpan/jianj): allow for writing each spatial and temporal stream.
if (svc_ctx.output_rc_stat) {
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
char file_name[PATH_MAX];
snprintf(file_name, sizeof(file_name), "%s_s%d.ivf",
app_input.output_filename, sl);
outfile[sl] = vpx_video_writer_open(file_name, kContainerIVF, &info);
if (!outfile[sl]) die("Failed to open %s for writing", file_name);
}
}
#endif
// skip initial frames // skip initial frames
for (i = 0; i < app_input.frames_to_skip; ++i) vpx_img_read(&raw, infile); for (i = 0; i < app_input.frames_to_skip; ++i)
vpx_img_read(&raw, infile);
if (svc_ctx.speed != -1)
vpx_codec_control(&codec, VP8E_SET_CPUUSED, svc_ctx.speed);
if (svc_ctx.threads) {
vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, get_msb(svc_ctx.threads));
if (svc_ctx.threads > 1)
vpx_codec_control(&codec, VP9E_SET_ROW_MT, 1);
else
vpx_codec_control(&codec, VP9E_SET_ROW_MT, 0);
}
if (svc_ctx.speed >= 5 && svc_ctx.aqmode == 1)
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
if (svc_ctx.speed >= 5)
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, 900);
vpx_codec_control(&codec, VP9E_SET_SVC_INTER_LAYER_PRED, 0);
vpx_codec_control(&codec, VP9E_SET_NOISE_SENSITIVITY, 0);
// Encode frames // Encode frames
while (!end_of_stream) { while (!end_of_stream) {
@ -740,57 +385,9 @@ int main(int argc, const char **argv) {
end_of_stream = 1; end_of_stream = 1;
} }
// For BYPASS/FLEXIBLE mode, set the frame flags (reference and updates) res = vpx_svc_encode(&svc_ctx, &codec, (end_of_stream ? NULL : &raw),
// and the buffer indices for each spatial layer of the current pts, frame_duration, VPX_DL_GOOD_QUALITY);
// (super)frame to be encoded. The temporal layer_id for the current frame printf("%s", vpx_svc_get_message(&svc_ctx));
// also needs to be set.
// TODO(marpan): Should rename the "VP9E_TEMPORAL_LAYERING_MODE_BYPASS"
// mode to "VP9E_LAYERING_MODE_BYPASS".
if (svc_ctx.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
layer_id.spatial_layer_id = 0;
// Example for 2 temporal layers.
if (frame_cnt % 2 == 0)
layer_id.temporal_layer_id = 0;
else
layer_id.temporal_layer_id = 1;
// Note that we only set the temporal layer_id, since we are calling
// the encode for the whole superframe. The encoder will internally loop
// over all the spatial layers for the current superframe.
vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id);
// TODO(jianj): Fix the parameter passing for "is_key_frame" in
// set_frame_flags_bypass_model() for case of periodic key frames.
set_frame_flags_bypass_mode(layer_id.temporal_layer_id,
svc_ctx.spatial_layers, frame_cnt == 0,
&ref_frame_config);
vpx_codec_control(&codec, VP9E_SET_SVC_REF_FRAME_CONFIG,
&ref_frame_config);
// Keep track of input frames, to account for frame drops in rate control
// stats/metrics.
for (sl = 0; sl < (unsigned int)enc_cfg.ss_number_layers; ++sl) {
++rc.layer_input_frames[sl * enc_cfg.ts_number_layers +
layer_id.temporal_layer_id];
}
} else {
// For the fixed pattern SVC, temporal layer is given by superframe count.
unsigned int tl = 0;
if (enc_cfg.ts_number_layers == 2)
tl = (frame_cnt % 2 != 0);
else if (enc_cfg.ts_number_layers == 3) {
if (frame_cnt % 2 != 0) tl = 2;
if ((frame_cnt > 1) && ((frame_cnt - 2) % 4 == 0)) tl = 1;
}
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl)
++rc.layer_input_frames[sl * enc_cfg.ts_number_layers + tl];
}
vpx_usec_timer_start(&timer);
res = vpx_svc_encode(
&svc_ctx, &codec, (end_of_stream ? NULL : &raw), pts, frame_duration,
svc_ctx.speed >= 5 ? VPX_DL_REALTIME : VPX_DL_GOOD_QUALITY);
vpx_usec_timer_mark(&timer);
cx_time += vpx_usec_timer_elapsed(&timer);
fflush(stdout);
if (res != VPX_CODEC_OK) { if (res != VPX_CODEC_OK) {
die_codec(&codec, "Failed to encode frame"); die_codec(&codec, "Failed to encode frame");
} }
@ -798,125 +395,27 @@ int main(int argc, const char **argv) {
while ((cx_pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) { while ((cx_pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) {
switch (cx_pkt->kind) { switch (cx_pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT: { case VPX_CODEC_CX_FRAME_PKT: {
SvcInternal_t *const si = (SvcInternal_t *)svc_ctx.internal; if (cx_pkt->data.frame.sz > 0)
if (cx_pkt->data.frame.sz > 0) { vpx_video_writer_write_frame(writer,
#if OUTPUT_RC_STATS cx_pkt->data.frame.buf,
uint64_t sizes[8];
uint64_t sizes_parsed[8];
int count = 0;
vp9_zero(sizes);
vp9_zero(sizes_parsed);
#endif
vpx_video_writer_write_frame(writer, cx_pkt->data.frame.buf,
cx_pkt->data.frame.sz, cx_pkt->data.frame.sz,
cx_pkt->data.frame.pts); cx_pkt->data.frame.pts);
#if OUTPUT_RC_STATS
// TODO(marpan): Put this (to line728) in separate function.
if (svc_ctx.output_rc_stat) {
vpx_codec_control(&codec, VP9E_GET_SVC_LAYER_ID, &layer_id);
parse_superframe_index(cx_pkt->data.frame.buf,
cx_pkt->data.frame.sz, sizes_parsed,
&count);
if (enc_cfg.ss_number_layers == 1)
sizes[0] = cx_pkt->data.frame.sz;
if (svc_ctx.temporal_layering_mode !=
VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
int num_layers_encoded = 0;
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
sizes[sl] = 0;
if (cx_pkt->data.frame.spatial_layer_encoded[sl]) {
sizes[sl] = sizes_parsed[num_layers_encoded];
num_layers_encoded++;
}
}
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
unsigned int sl2;
uint64_t tot_size = 0;
for (sl2 = 0; sl2 <= sl; ++sl2) {
if (cx_pkt->data.frame.spatial_layer_encoded[sl2])
tot_size += sizes[sl2];
}
if (tot_size > 0)
vpx_video_writer_write_frame(
outfile[sl], cx_pkt->data.frame.buf, (size_t)(tot_size),
cx_pkt->data.frame.pts);
}
}
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
if (cx_pkt->data.frame.spatial_layer_encoded[sl]) {
for (tl = layer_id.temporal_layer_id;
tl < enc_cfg.ts_number_layers; ++tl) {
const int layer = sl * enc_cfg.ts_number_layers + tl;
++rc.layer_tot_enc_frames[layer];
rc.layer_encoding_bitrate[layer] += 8.0 * sizes[sl];
// Keep count of rate control stats per layer, for non-key
// frames.
if (tl == (unsigned int)layer_id.temporal_layer_id &&
!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY)) {
rc.layer_avg_frame_size[layer] += 8.0 * sizes[sl];
rc.layer_avg_rate_mismatch[layer] +=
fabs(8.0 * sizes[sl] - rc.layer_pfb[layer]) /
rc.layer_pfb[layer];
++rc.layer_enc_frames[layer];
}
}
}
}
// 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 > (unsigned int)rc.window_size) {
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
if (cx_pkt->data.frame.spatial_layer_encoded[sl])
sum_bitrate += 0.001 * 8.0 * sizes[sl] * 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 >
(unsigned int)(rc.window_size + rc.window_size / 2)) {
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
sum_bitrate2 += 0.001 * 8.0 * sizes[sl] * framerate;
}
if (frame_cnt > (unsigned int)(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;
}
}
}
#endif
}
/*
printf("SVC frame: %d, kf: %d, size: %d, pts: %d\n", frames_received, printf("SVC frame: %d, kf: %d, size: %d, pts: %d\n", frames_received,
!!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY), !!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY),
(int)cx_pkt->data.frame.sz, (int)cx_pkt->data.frame.pts); (int)cx_pkt->data.frame.sz, (int)cx_pkt->data.frame.pts);
*/
if (enc_cfg.ss_number_layers == 1 && enc_cfg.ts_number_layers == 1)
si->bytes_sum[0] += (int)cx_pkt->data.frame.sz;
++frames_received; ++frames_received;
break; break;
} }
case VPX_CODEC_STATS_PKT: { case VPX_CODEC_STATS_PKT: {
stats_write(&app_input.rc_stats, cx_pkt->data.twopass_stats.buf, stats_write(&app_input.rc_stats,
cx_pkt->data.twopass_stats.buf,
cx_pkt->data.twopass_stats.sz); cx_pkt->data.twopass_stats.sz);
break; break;
} }
default: { break; } default: {
break;
}
} }
} }
@ -926,41 +425,24 @@ int main(int argc, const char **argv) {
} }
} }
// Compensate for the extra frame count for the bypass mode.
if (svc_ctx.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
const int layer =
sl * enc_cfg.ts_number_layers + layer_id.temporal_layer_id;
--rc.layer_input_frames[layer];
}
}
printf("Processed %d frames\n", frame_cnt); printf("Processed %d frames\n", frame_cnt);
fclose(infile); fclose(infile);
#if OUTPUT_RC_STATS
if (svc_ctx.output_rc_stat) {
printout_rate_control_summary(&rc, &enc_cfg, frame_cnt);
printf("\n");
}
#endif
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); 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 (app_input.passes == 2)
stats_close(&app_input.rc_stats, 1);
if (writer) { if (writer) {
vpx_video_writer_close(writer); vpx_video_writer_close(writer);
} }
#if OUTPUT_RC_STATS
if (svc_ctx.output_rc_stat) {
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
vpx_video_writer_close(outfile[sl]);
}
}
#endif
printf("Frame cnt and encoding time/FPS stats for encoding: %d %f %f \n",
frame_cnt, 1000 * (float)cx_time / (double)(frame_cnt * 1000000),
1000000 * (double)frame_cnt / (double)cx_time);
vpx_img_free(&raw); vpx_img_free(&raw);
// display average size, psnr // display average size, psnr
vpx_svc_dump_statistics(&svc_ctx); printf("%s", vpx_svc_dump_statistics(&svc_ctx));
vpx_svc_release(&svc_ctx); vpx_svc_release(&svc_ctx);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -1,442 +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.
*/
// VP9 Set Reference Frame
// ============================
//
// This is an example demonstrating how to overwrite the VP9 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/vp9cx_set_ref 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 "vp9/common/vp9_common.h"
#include "./tools_common.h"
#include "./video_writer.h"
static const char *exec_name;
void usage_exit() {
fprintf(stderr,
"Usage: %s <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,
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_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, *frame_out, mismatch_seen);
}
return got_pkts;
}
int main(int argc, char **argv) {
FILE *infile = NULL;
// Encoder
vpx_codec_ctx_t ecodec;
vpx_codec_enc_cfg_t cfg;
unsigned int frame_in = 0;
vpx_image_t raw;
vpx_codec_err_t res;
VpxVideoInfo info;
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 *width_arg = NULL;
const char *height_arg = NULL;
const char *infile_arg = NULL;
const char *outfile_arg = NULL;
const char *update_frame_num_arg = NULL;
unsigned int limit = 0;
vp9_zero(ecodec);
vp9_zero(cfg);
vp9_zero(info);
exec_name = argv[0];
if (argc < 6) die("Invalid number of arguments");
width_arg = argv[1];
height_arg = argv[2];
infile_arg = argv[3];
outfile_arg = argv[4];
update_frame_num_arg = argv[5];
encoder = get_vpx_encoder_by_name("vp9");
if (!encoder) die("Unsupported codec.");
update_frame_num = (unsigned int)strtoul(update_frame_num_arg, NULL, 0);
// In VP9, 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", update_frame_num_arg);
}
if (argc > 6) {
limit = (unsigned int)strtoul(argv[6], NULL, 0);
if (update_frame_num > limit)
die("Update frame number couldn't larger than limit\n");
}
info.codec_fourcc = encoder->fourcc;
info.frame_width = (int)strtol(width_arg, NULL, 0);
info.frame_height = (int)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("vp9");
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, &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, 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

@ -22,37 +22,26 @@
#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 "vpx_ports/bitops.h"
#include "../tools_common.h" #include "../tools_common.h"
#include "../video_writer.h" #include "../video_writer.h"
#define ROI_MAP 0
#define zero(Dest) memset(&Dest, 0, sizeof(Dest));
static const char *exec_name; static const char *exec_name;
void usage_exit(void) { exit(EXIT_FAILURE); } void usage_exit() {
exit(EXIT_FAILURE);
}
// Denoiser states for vp8, for temporal denoising. // Denoiser states, for temporal denoising.
enum denoiserStateVp8 { enum denoiserState {
kVp8DenoiserOff, kDenoiserOff,
kVp8DenoiserOnYOnly, kDenoiserOnYOnly,
kVp8DenoiserOnYUV, kDenoiserOnYUV,
kVp8DenoiserOnYUVAggressive, kDenoiserOnYUVAggressive,
kVp8DenoiserOnAdaptive kDenoiserOnAdaptive
}; };
// Denoiser states for vp9, for temporal denoising. static int mode_to_num_layers[12] = {1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3};
enum denoiserStateVp9 {
kVp9DenoiserOff,
kVp9DenoiserOnYOnly,
// For SVC: denoise the top two spatial layers.
kVp9DenoiserOnYTwoSpatialLayers
};
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 {
@ -81,7 +70,6 @@ struct RateControlMetrics {
int window_size; int window_size;
// Number of window measurements. // Number of window measurements.
int window_count; 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
@ -97,14 +85,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] = rc->layer_pfb[0] = 1000.0 * cfg->ts_target_bitrate[0] /
1000.0 * rc->layer_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] = rc->layer_pfb[i] = 1000.0 *
1000.0 * (cfg->ts_target_bitrate[i] - cfg->ts_target_bitrate[i - 1]) /
(rc->layer_target_bitrate[i] - rc->layer_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;
@ -126,31 +113,29 @@ static void printout_rate_control_summary(struct RateControlMetrics *rc,
unsigned int i = 0; unsigned int i = 0;
int tot_num_frames = 0; int tot_num_frames = 0;
double perc_fluctuation = 0.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);
for (i = 0; i < cfg->ts_number_layers; ++i) { for (i = 0; i < cfg->ts_number_layers; ++i) {
const int num_dropped = const int num_dropped = (i > 0) ?
(i > 0) ? (rc->layer_input_frames[i] - rc->layer_enc_frames[i]) (rc->layer_input_frames[i] - rc->layer_enc_frames[i]) :
: (rc->layer_input_frames[i] - rc->layer_enc_frames[i] - 1); (rc->layer_input_frames[i] - rc->layer_enc_frames[i] - 1);
tot_num_frames += rc->layer_input_frames[i]; tot_num_frames += rc->layer_input_frames[i];
rc->layer_encoding_bitrate[i] = 0.001 * rc->layer_framerate[i] * rc->layer_encoding_bitrate[i] = 0.001 * rc->layer_framerate[i] *
rc->layer_encoding_bitrate[i] / rc->layer_encoding_bitrate[i] / tot_num_frames;
tot_num_frames; rc->layer_avg_frame_size[i] = rc->layer_avg_frame_size[i] /
rc->layer_avg_frame_size[i] = rc->layer_enc_frames[i];
rc->layer_avg_frame_size[i] / rc->layer_enc_frames[i]; rc->layer_avg_rate_mismatch[i] = 100.0 * rc->layer_avg_rate_mismatch[i] /
rc->layer_avg_rate_mismatch[i] = rc->layer_enc_frames[i];
100.0 * rc->layer_avg_rate_mismatch[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]);
printf("Average rate_mismatch: %f \n", rc->layer_avg_rate_mismatch[i]); printf("Average rate_mismatch: %f \n", rc->layer_avg_rate_mismatch[i]);
printf( printf("Number of input frames, encoded (non-key) frames, "
"Number of input frames, encoded (non-key) frames, " "and perc dropped frames: %d %d %f \n", rc->layer_input_frames[i],
"and perc dropped frames: %d %d %f \n", rc->layer_enc_frames[i],
rc->layer_input_frames[i], rc->layer_enc_frames[i],
100.0 * num_dropped / rc->layer_input_frames[i]); 100.0 * num_dropped / rc->layer_input_frames[i]);
printf("\n"); printf("\n");
} }
@ -159,84 +144,16 @@ static void printout_rate_control_summary(struct RateControlMetrics *rc,
rc->variance_st_encoding_bitrate / rc->window_count - rc->variance_st_encoding_bitrate / rc->window_count -
(rc->avg_st_encoding_bitrate * rc->avg_st_encoding_bitrate); (rc->avg_st_encoding_bitrate * rc->avg_st_encoding_bitrate);
perc_fluctuation = 100.0 * sqrt(rc->variance_st_encoding_bitrate) / perc_fluctuation = 100.0 * sqrt(rc->variance_st_encoding_bitrate) /
rc->avg_st_encoding_bitrate; rc->avg_st_encoding_bitrate;
printf("Short-time stats, for window of %d frames: \n", rc->window_size); printf("Short-time stats, for window of %d frames: \n",rc->window_size);
printf("Average, rms-variance, and percent-fluct: %f %f %f \n", printf("Average, rms-variance, and percent-fluct: %f %f %f \n",
rc->avg_st_encoding_bitrate, sqrt(rc->variance_st_encoding_bitrate), rc->avg_st_encoding_bitrate,
sqrt(rc->variance_st_encoding_bitrate),
perc_fluctuation); 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");
} }
#if ROI_MAP
static void set_roi_map(const char *enc_name, vpx_codec_enc_cfg_t *cfg,
vpx_roi_map_t *roi) {
unsigned int i, j;
int block_size = 0;
uint8_t is_vp8 = strncmp(enc_name, "vp8", 3) == 0 ? 1 : 0;
uint8_t is_vp9 = strncmp(enc_name, "vp9", 3) == 0 ? 1 : 0;
if (!is_vp8 && !is_vp9) {
die("unsupported codec.");
}
zero(*roi);
block_size = is_vp9 && !is_vp8 ? 8 : 16;
// ROI is based on the segments (4 for vp8, 8 for vp9), smallest unit for
// segment is 16x16 for vp8, 8x8 for vp9.
roi->rows = (cfg->g_h + block_size - 1) / block_size;
roi->cols = (cfg->g_w + block_size - 1) / block_size;
// Applies delta QP on the segment blocks, varies from -63 to 63.
// Setting to negative means lower QP (better quality).
// Below we set delta_q to the extreme (-63) to show strong effect.
// VP8 uses the first 4 segments. VP9 uses all 8 segments.
zero(roi->delta_q);
roi->delta_q[1] = -63;
// Applies delta loopfilter strength on the segment blocks, varies from -63 to
// 63. Setting to positive means stronger loopfilter. VP8 uses the first 4
// segments. VP9 uses all 8 segments.
zero(roi->delta_lf);
if (is_vp8) {
// Applies skip encoding threshold on the segment blocks, varies from 0 to
// UINT_MAX. Larger value means more skipping of encoding is possible.
// This skip threshold only applies on delta frames.
zero(roi->static_threshold);
}
if (is_vp9) {
// Apply skip segment. Setting to 1 means this block will be copied from
// previous frame.
zero(roi->skip);
}
if (is_vp9) {
// Apply ref frame segment.
// -1 : Do not apply this segment.
// 0 : Froce using intra.
// 1 : Force using last.
// 2 : Force using golden.
// 3 : Force using alfref but not used in non-rd pickmode for 0 lag.
memset(roi->ref_frame, -1, sizeof(roi->ref_frame));
roi->ref_frame[1] = 1;
}
// Use 2 states: 1 is center square, 0 is the rest.
roi->roi_map =
(uint8_t *)calloc(roi->rows * roi->cols, sizeof(*roi->roi_map));
for (i = 0; i < roi->rows; ++i) {
for (j = 0; j < roi->cols; ++j) {
if (i > (roi->rows >> 2) && i < ((roi->rows * 3) >> 2) &&
j > (roi->cols >> 2) && j < ((roi->cols * 3) >> 2)) {
roi->roi_map[i * roi->cols + j] = 1;
}
}
}
}
#endif
// Temporal scaling parameters: // Temporal scaling parameters:
// NOTE: The 3 prediction frames cannot be used interchangeably due to // NOTE: The 3 prediction frames cannot be used interchangeably due to
// differences in the way they are handled throughout the code. The // differences in the way they are handled throughout the code. The
@ -249,20 +166,20 @@ static void set_temporal_layer_pattern(int layering_mode,
switch (layering_mode) { switch (layering_mode) {
case 0: { case 0: {
// 1-layer. // 1-layer.
int ids[1] = { 0 }; int ids[1] = {0};
cfg->ts_periodicity = 1; cfg->ts_periodicity = 1;
*flag_periodicity = 1; *flag_periodicity = 1;
cfg->ts_number_layers = 1; cfg->ts_number_layers = 1;
cfg->ts_rate_decimator[0] = 1; cfg->ts_rate_decimator[0] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// Update L only. // Update L only.
layer_flags[0] = layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF |
VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; VP8_EFLAG_NO_UPD_ARF;
break; break;
} }
case 1: { case 1: {
// 2-layers, 2-frame period. // 2-layers, 2-frame period.
int ids[2] = { 0, 1 }; int ids[2] = {0, 1};
cfg->ts_periodicity = 2; cfg->ts_periodicity = 2;
*flag_periodicity = 2; *flag_periodicity = 2;
cfg->ts_number_layers = 2; cfg->ts_number_layers = 2;
@ -271,24 +188,22 @@ static void set_temporal_layer_pattern(int layering_mode,
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
#if 1 #if 1
// 0=L, 1=GF, Intra-layer prediction enabled. // 0=L, 1=GF, Intra-layer prediction enabled.
layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
VP8_EFLAG_NO_REF_ARF;
layer_flags[1] =
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF;
#else
// 0=L, 1=GF, Intra-layer prediction disabled.
layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_REF_ARF;
layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST; VP8_EFLAG_NO_REF_ARF;
#else
// 0=L, 1=GF, Intra-layer prediction disabled.
layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
layer_flags[1] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST;
#endif #endif
break; break;
} }
case 2: { case 2: {
// 2-layers, 3-frame period. // 2-layers, 3-frame period.
int ids[3] = { 0, 1, 1 }; int ids[3] = {0, 1, 1};
cfg->ts_periodicity = 3; cfg->ts_periodicity = 3;
*flag_periodicity = 3; *flag_periodicity = 3;
cfg->ts_number_layers = 2; cfg->ts_number_layers = 2;
@ -296,17 +211,16 @@ static void set_temporal_layer_pattern(int layering_mode,
cfg->ts_rate_decimator[1] = 1; cfg->ts_rate_decimator[1] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, Intra-layer prediction enabled. // 0=L, 1=GF, Intra-layer prediction enabled.
layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
VP8_EFLAG_NO_UPD_ARF; layer_flags[1] =
layer_flags[1] = layer_flags[2] = layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
VP8_EFLAG_NO_UPD_LAST;
break; break;
} }
case 3: { case 3: {
// 3-layers, 6-frame period. // 3-layers, 6-frame period.
int ids[6] = { 0, 2, 2, 1, 2, 2 }; int ids[6] = {0, 2, 2, 1, 2, 2};
cfg->ts_periodicity = 6; cfg->ts_periodicity = 6;
*flag_periodicity = 6; *flag_periodicity = 6;
cfg->ts_number_layers = 3; cfg->ts_number_layers = 3;
@ -315,18 +229,19 @@ static void set_temporal_layer_pattern(int layering_mode,
cfg->ts_rate_decimator[2] = 1; cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled. // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled.
layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
VP8_EFLAG_NO_UPD_ARF; layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
layer_flags[3] = VP8_EFLAG_NO_UPD_LAST;
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; layer_flags[1] =
layer_flags[1] = layer_flags[2] = layer_flags[4] = layer_flags[5] = layer_flags[2] =
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; layer_flags[4] =
layer_flags[5] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
break; break;
} }
case 4: { case 4: {
// 3-layers, 4-frame period. // 3-layers, 4-frame period.
int ids[4] = { 0, 2, 1, 2 }; int ids[4] = {0, 2, 1, 2};
cfg->ts_periodicity = 4; cfg->ts_periodicity = 4;
*flag_periodicity = 4; *flag_periodicity = 4;
cfg->ts_number_layers = 3; cfg->ts_number_layers = 3;
@ -335,41 +250,39 @@ static void set_temporal_layer_pattern(int layering_mode,
cfg->ts_rate_decimator[2] = 1; cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled. // 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled.
layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
VP8_EFLAG_NO_UPD_ARF;
layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
layer_flags[1] = layer_flags[3] = layer_flags[1] =
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ARF; VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
break; break;
} }
case 5: { case 5: {
// 3-layers, 4-frame period. // 3-layers, 4-frame period.
int ids[4] = { 0, 2, 1, 2 }; int ids[4] = {0, 2, 1, 2};
cfg->ts_periodicity = 4; cfg->ts_periodicity = 4;
*flag_periodicity = 4; *flag_periodicity = 4;
cfg->ts_number_layers = 3; cfg->ts_number_layers = 3;
cfg->ts_rate_decimator[0] = 4; cfg->ts_rate_decimator[0] = 4;
cfg->ts_rate_decimator[1] = 2; cfg->ts_rate_decimator[1] = 2;
cfg->ts_rate_decimator[2] = 1; cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1, disabled // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1, disabled
// in layer 2. // in layer 2.
layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
layer_flags[2] =
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
layer_flags[1] = layer_flags[3] =
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF; VP8_EFLAG_NO_UPD_ARF;
layer_flags[1] =
layer_flags[3] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
break; break;
} }
case 6: { case 6: {
// 3-layers, 4-frame period. // 3-layers, 4-frame period.
int ids[4] = { 0, 2, 1, 2 }; int ids[4] = {0, 2, 1, 2};
cfg->ts_periodicity = 4; cfg->ts_periodicity = 4;
*flag_periodicity = 4; *flag_periodicity = 4;
cfg->ts_number_layers = 3; cfg->ts_number_layers = 3;
@ -378,19 +291,18 @@ static void set_temporal_layer_pattern(int layering_mode,
cfg->ts_rate_decimator[2] = 1; cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled. // 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled.
layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
VP8_EFLAG_NO_UPD_ARF; layer_flags[2] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
layer_flags[2] = VP8_EFLAG_NO_UPD_ARF;
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[1] =
layer_flags[1] = layer_flags[3] = layer_flags[3] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
break; break;
} }
case 7: { case 7: {
// NOTE: Probably of academic interest only. // NOTE: Probably of academic interest only.
// 5-layers, 16-frame period. // 5-layers, 16-frame period.
int ids[16] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4 }; int ids[16] = {0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4};
cfg->ts_periodicity = 16; cfg->ts_periodicity = 16;
*flag_periodicity = 16; *flag_periodicity = 16;
cfg->ts_number_layers = 5; cfg->ts_number_layers = 5;
@ -400,21 +312,28 @@ static void set_temporal_layer_pattern(int layering_mode,
cfg->ts_rate_decimator[3] = 2; cfg->ts_rate_decimator[3] = 2;
cfg->ts_rate_decimator[4] = 1; cfg->ts_rate_decimator[4] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
layer_flags[0] = VPX_EFLAG_FORCE_KF; layer_flags[0] = VPX_EFLAG_FORCE_KF;
layer_flags[1] = layer_flags[3] = layer_flags[5] = layer_flags[7] = layer_flags[1] =
layer_flags[9] = layer_flags[11] = layer_flags[13] = layer_flags[15] = layer_flags[3] =
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | layer_flags[5] =
VP8_EFLAG_NO_UPD_ARF; layer_flags[7] =
layer_flags[2] = layer_flags[6] = layer_flags[10] = layer_flags[14] = layer_flags[9] =
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF; layer_flags[11] =
layer_flags[4] = layer_flags[12] = layer_flags[13] =
VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_UPD_ARF; layer_flags[15] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF; VP8_EFLAG_NO_UPD_ARF;
layer_flags[2] =
layer_flags[6] =
layer_flags[10] =
layer_flags[14] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF;
layer_flags[4] =
layer_flags[12] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_UPD_ARF;
layer_flags[8] = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF;
break; break;
} }
case 8: { case 8: {
// 2-layers, with sync point at first frame of layer 1. // 2-layers, with sync point at first frame of layer 1.
int ids[2] = { 0, 1 }; int ids[2] = {0, 1};
cfg->ts_periodicity = 2; cfg->ts_periodicity = 2;
*flag_periodicity = 8; *flag_periodicity = 8;
cfg->ts_number_layers = 2; cfg->ts_number_layers = 2;
@ -426,17 +345,17 @@ static void set_temporal_layer_pattern(int layering_mode,
// key frame. Sync point every 8 frames. // key frame. Sync point every 8 frames.
// Layer 0: predict from L and ARF, update L and G. // Layer 0: predict from L and ARF, update L and G.
layer_flags[0] = layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF; VP8_EFLAG_NO_UPD_ARF;
// Layer 1: sync point: predict from L and ARF, and update G. // Layer 1: sync point: predict from L and ARF, and update G.
layer_flags[1] = layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; VP8_EFLAG_NO_UPD_ARF;
// Layer 0, predict from L and ARF, update L. // Layer 0, predict from L and ARF, update L.
layer_flags[2] = layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; VP8_EFLAG_NO_UPD_ARF;
// Layer 1: predict from L, G and ARF, and update G. // Layer 1: predict from L, G and ARF, and update G.
layer_flags[3] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | layer_flags[3] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ENTROPY; VP8_EFLAG_NO_UPD_ENTROPY;
// Layer 0. // Layer 0.
layer_flags[4] = layer_flags[2]; layer_flags[4] = layer_flags[2];
// Layer 1. // Layer 1.
@ -445,11 +364,11 @@ static void set_temporal_layer_pattern(int layering_mode,
layer_flags[6] = layer_flags[4]; layer_flags[6] = layer_flags[4];
// Layer 1. // Layer 1.
layer_flags[7] = layer_flags[5]; layer_flags[7] = layer_flags[5];
break; break;
} }
case 9: { case 9: {
// 3-layers: Sync points for layer 1 and 2 every 8 frames. // 3-layers: Sync points for layer 1 and 2 every 8 frames.
int ids[4] = { 0, 2, 1, 2 }; int ids[4] = {0, 2, 1, 2};
cfg->ts_periodicity = 4; cfg->ts_periodicity = 4;
*flag_periodicity = 8; *flag_periodicity = 8;
cfg->ts_number_layers = 3; cfg->ts_number_layers = 3;
@ -458,21 +377,20 @@ static void set_temporal_layer_pattern(int layering_mode,
cfg->ts_rate_decimator[2] = 1; cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF. // 0=L, 1=GF, 2=ARF.
layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
VP8_EFLAG_NO_UPD_ARF;
layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | 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[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
layer_flags[3] = layer_flags[5] =
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF; VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
layer_flags[3] =
layer_flags[5] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
layer_flags[6] = layer_flags[6] = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF; VP8_EFLAG_NO_UPD_ARF;
layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_ENTROPY; VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_ENTROPY;
break; break;
} }
case 10: { case 10: {
@ -480,7 +398,7 @@ static void set_temporal_layer_pattern(int layering_mode,
// and is only updated on key frame. // and is only updated on key frame.
// Sync points for layer 1 and 2 every 8 frames. // Sync points for layer 1 and 2 every 8 frames.
int ids[4] = { 0, 2, 1, 2 }; int ids[4] = {0, 2, 1, 2};
cfg->ts_periodicity = 4; cfg->ts_periodicity = 4;
*flag_periodicity = 8; *flag_periodicity = 8;
cfg->ts_number_layers = 3; cfg->ts_number_layers = 3;
@ -490,21 +408,21 @@ static void set_temporal_layer_pattern(int layering_mode,
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF. // 0=L, 1=GF, 2=ARF.
// Layer 0: predict from L and ARF; update L and G. // Layer 0: predict from L and ARF; update L and G.
layer_flags[0] = layer_flags[0] = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_ARF |
VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF; VP8_EFLAG_NO_REF_GF;
// Layer 2: sync point: predict from L and ARF; update none. // Layer 2: sync point: predict from L and ARF; update none.
layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | layer_flags[1] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ENTROPY; VP8_EFLAG_NO_UPD_ENTROPY;
// Layer 1: sync point: predict from L and ARF; update G. // Layer 1: sync point: predict from L and ARF; update G.
layer_flags[2] = layer_flags[2] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; VP8_EFLAG_NO_UPD_LAST;
// Layer 2: predict from L, G, ARF; update none. // Layer 2: predict from L, G, ARF; update none.
layer_flags[3] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | layer_flags[3] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY; VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY;
// Layer 0: predict from L and ARF; update L. // Layer 0: predict from L and ARF; update L.
layer_flags[4] = layer_flags[4] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF; VP8_EFLAG_NO_REF_GF;
// Layer 2: predict from L, G, ARF; update none. // Layer 2: predict from L, G, ARF; update none.
layer_flags[5] = layer_flags[3]; layer_flags[5] = layer_flags[3];
// Layer 1: predict from L, G, ARF; update G. // Layer 1: predict from L, G, ARF; update G.
@ -513,36 +431,11 @@ 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.
int ids[4] = { 0, 2, 1, 2 }; int ids[4] = {0, 2, 1, 2};
cfg->ts_periodicity = 4; cfg->ts_periodicity = 4;
*flag_periodicity = 8; *flag_periodicity = 8;
cfg->ts_number_layers = 3; cfg->ts_number_layers = 3;
@ -552,15 +445,15 @@ static void set_temporal_layer_pattern(int layering_mode,
memcpy(cfg->ts_layer_id, ids, sizeof(ids)); memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF. // 0=L, 1=GF, 2=ARF.
// Layer 0: predict from L and ARF; update L. // Layer 0: predict from L and ARF; update L.
layer_flags[0] = layer_flags[0] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF; VP8_EFLAG_NO_REF_GF;
layer_flags[4] = layer_flags[0]; layer_flags[4] = layer_flags[0];
// Layer 1: predict from L, G, ARF; update G. // Layer 1: predict from L, G, ARF; update G.
layer_flags[2] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; layer_flags[2] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
layer_flags[6] = layer_flags[2]; layer_flags[6] = layer_flags[2];
// Layer 2: predict from L, G, ARF; update none. // Layer 2: predict from L, G, ARF; update none.
layer_flags[1] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | layer_flags[1] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY; VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY;
layer_flags[3] = layer_flags[1]; layer_flags[3] = layer_flags[1];
layer_flags[5] = layer_flags[1]; layer_flags[5] = layer_flags[1];
layer_flags[7] = layer_flags[1]; layer_flags[7] = layer_flags[1];
@ -570,7 +463,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] = {NULL};
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;
@ -578,26 +471,26 @@ int main(int argc, char **argv) {
vpx_codec_err_t res; vpx_codec_err_t res;
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
uint32_t error_resilient = 0;
int speed; int speed;
int frame_avail; int frame_avail;
int got_data; int got_data;
int flags = 0; int flags = 0;
unsigned int i; unsigned int i;
int pts = 0; // PTS starts at 0. int pts = 0; // PTS starts at 0.
int frame_duration = 1; // 1 timebase tick per frame. int frame_duration = 1; // 1 timebase tick per frame.
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 ROI_MAP #if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
vpx_roi_map_t roi; vpx_svc_layer_id_t layer_id = {0, 0};
#else
vpx_svc_layer_id_t layer_id = {0};
#endif #endif
vpx_svc_layer_id_t layer_id = { 0, 0 };
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 = 13; const int min_args_base = 11;
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
vpx_bit_depth_t bit_depth = VPX_BITS_8; vpx_bit_depth_t bit_depth = VPX_BITS_8;
int input_bit_depth = 8; int input_bit_depth = 8;
@ -607,42 +500,37 @@ int main(int argc, char **argv) {
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
double sum_bitrate = 0.0; double sum_bitrate = 0.0;
double sum_bitrate2 = 0.0; double sum_bitrate2 = 0.0;
double framerate = 30.0; double framerate = 30.0;
zero(rc.layer_target_bitrate);
exec_name = argv[0]; exec_name = argv[0];
// Check usage and arguments. // Check usage and arguments.
if (argc < min_args) { if (argc < min_args) {
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
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> " "<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> "
"<error_resilient> <threads> <mode> " "<Rate_0> ... <Rate_nlayers-1> <bit-depth> \n", argv[0]);
"<Rate_0> ... <Rate_nlayers-1> <bit-depth> \n",
argv[0]);
#else #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> " "<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> "
"<error_resilient> <threads> <mode> " "<Rate_0> ... <Rate_nlayers-1> \n", argv[0]);
"<Rate_0> ... <Rate_nlayers-1> \n",
argv[0]);
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
} }
encoder = get_vpx_encoder_by_name(argv[3]); encoder = get_vpx_encoder_by_name(argv[3]);
if (!encoder) die("Unsupported codec."); if (!encoder)
die("Unsupported codec.");
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface())); printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
width = (unsigned int)strtoul(argv[4], NULL, 0); width = strtol(argv[4], NULL, 0);
height = (unsigned int)strtoul(argv[5], NULL, 0); height = strtol(argv[5], NULL, 0);
if (width < 16 || width % 2 || height < 16 || height % 2) { if (width < 16 || width % 2 || height < 16 || height % 2) {
die("Invalid resolution: %d x %d", width, height); die("Invalid resolution: %d x %d", width, height);
} }
layering_mode = (int)strtol(argv[12], 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[12]); die("Invalid layering mode (0..12) %s", argv[10]);
} }
if (argc != min_args + mode_to_num_layers[layering_mode]) { if (argc != min_args + mode_to_num_layers[layering_mode]) {
@ -650,7 +538,7 @@ int main(int argc, char **argv) {
} }
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
switch (strtol(argv[argc - 1], NULL, 0)) { switch (strtol(argv[argc-1], NULL, 0)) {
case 8: case 8:
bit_depth = VPX_BITS_8; bit_depth = VPX_BITS_8;
input_bit_depth = 8; input_bit_depth = 8;
@ -663,11 +551,13 @@ int main(int argc, char **argv) {
bit_depth = VPX_BITS_12; bit_depth = VPX_BITS_12;
input_bit_depth = 12; input_bit_depth = 12;
break; break;
default: die("Invalid bit depth (8, 10, 12) %s", argv[argc - 1]); default:
die("Invalid bit depth (8, 10, 12) %s", argv[argc-1]);
} }
if (!vpx_img_alloc( if (!vpx_img_alloc(&raw,
&raw, bit_depth == VPX_BITS_8 ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_I42016, bit_depth == VPX_BITS_8 ? VPX_IMG_FMT_I420 :
width, height, 32)) { VPX_IMG_FMT_I42016,
width, height, 32)) {
die("Failed to allocate image", width, height); die("Failed to allocate image", width, height);
} }
#else #else
@ -696,63 +586,55 @@ int main(int argc, char **argv) {
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
// Timebase format e.g. 30fps: numerator=1, demoninator = 30. // Timebase format e.g. 30fps: numerator=1, demoninator = 30.
cfg.g_timebase.num = (int)strtol(argv[6], NULL, 0); cfg.g_timebase.num = strtol(argv[6], NULL, 0);
cfg.g_timebase.den = (int)strtol(argv[7], NULL, 0); cfg.g_timebase.den = strtol(argv[7], NULL, 0);
speed = (int)strtol(argv[8], NULL, 0); speed = strtol(argv[8], NULL, 0);
if (speed < 0) { if (speed < 0) {
die("Invalid speed setting: must be positive"); die("Invalid speed setting: must be positive");
} }
for (i = min_args_base; for (i = min_args_base;
(int)i < min_args_base + mode_to_num_layers[layering_mode]; ++i) { (int)i < min_args_base + mode_to_num_layers[layering_mode];
rc.layer_target_bitrate[i - 13] = (int)strtol(argv[i], NULL, 0); ++i) {
if (strncmp(encoder->name, "vp8", 3) == 0) cfg.ts_target_bitrate[i - 11] = strtol(argv[i], NULL, 0);
cfg.ts_target_bitrate[i - 13] = rc.layer_target_bitrate[i - 13];
else if (strncmp(encoder->name, "vp9", 3) == 0)
cfg.layer_target_bitrate[i - 13] = rc.layer_target_bitrate[i - 13];
} }
// Real time parameters. // Real time parameters.
cfg.rc_dropframe_thresh = (unsigned int)strtoul(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; 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 = 600; 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. // Use 1 thread as default.
cfg.g_threads = (unsigned int)strtoul(argv[11], NULL, 0); cfg.g_threads = 1;
error_resilient = (uint32_t)strtoul(argv[10], NULL, 0);
if (error_resilient != 0 && error_resilient != 1) {
die("Invalid value for error resilient (0, 1): %d.", error_resilient);
}
// Enable error resilient mode. // Enable error resilient mode.
cfg.g_error_resilient = error_resilient; cfg.g_error_resilient = 1;
cfg.g_lag_in_frames = 0; cfg.g_lag_in_frames = 0;
cfg.kf_mode = VPX_KF_AUTO; cfg.kf_mode = VPX_KF_AUTO;
// 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,
&cfg,
set_temporal_layer_pattern(layering_mode, &cfg, layer_flags, layer_flags,
&flag_periodicity); &flag_periodicity);
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"))) {
@ -772,14 +654,15 @@ int main(int argc, char **argv) {
snprintf(file_name, sizeof(file_name), "%s_%d.ivf", argv[2], i); snprintf(file_name, sizeof(file_name), "%s_%d.ivf", argv[2], i);
outfile[i] = vpx_video_writer_open(file_name, kContainerIVF, &info); outfile[i] = vpx_video_writer_open(file_name, kContainerIVF, &info);
if (!outfile[i]) die("Failed to open %s for writing", file_name); if (!outfile[i])
die("Failed to open %s for writing", file_name);
assert(outfile[i] != NULL); 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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
if (vpx_codec_enc_init( if (vpx_codec_enc_init(
&codec, encoder->codec_interface(), &cfg, &codec, encoder->codec_interface(), &cfg,
@ -791,48 +674,18 @@ int main(int argc, char **argv) {
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, kVp8DenoiserOff); vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kDenoiserOff);
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1); vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 0);
vpx_codec_control(&codec, VP8E_SET_GF_CBR_BOOST_PCT, 0);
#if ROI_MAP
set_roi_map(encoder->name, &cfg, &roi);
if (vpx_codec_control(&codec, VP8E_SET_ROI_MAP, &roi))
die_codec(&codec, "Failed to set ROI map");
#endif
} 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);
memset(&svc_params, 0, sizeof(svc_params)); vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed); vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0);
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3); vpx_codec_control(&codec, VP9E_SET_NOISE_SENSITIVITY, 0);
vpx_codec_control(&codec, VP9E_SET_GF_CBR_BOOST_PCT, 0); vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 0);
vpx_codec_control(&codec, VP9E_SET_FRAME_PARALLEL_DECODING, 0); vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, (cfg.g_threads >> 1));
vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0); if (vpx_codec_control(&codec, VP9E_SET_SVC, layering_mode > 0 ? 1: 0)) {
vpx_codec_control(&codec, VP9E_SET_NOISE_SENSITIVITY, kVp9DenoiserOff); die_codec(&codec, "Failed to set SVC");
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
vpx_codec_control(&codec, VP9E_SET_TUNE_CONTENT, 0);
vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, get_msb(cfg.g_threads));
#if ROI_MAP
set_roi_map(encoder->name, &cfg, &roi);
if (vpx_codec_control(&codec, VP9E_SET_ROI_MAP, &roi))
die_codec(&codec, "Failed to set ROI map");
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 0);
#endif
// TODO(marpan/jianj): There is an issue with row-mt for low resolutons at
// high speed settings, disable its use for those cases for now.
if (cfg.g_threads > 1 && ((cfg.g_w > 320 && cfg.g_h > 240) || speed < 7))
vpx_codec_control(&codec, VP9E_SET_ROW_MT, 1);
else
vpx_codec_control(&codec, VP9E_SET_ROW_MT, 0);
if (vpx_codec_control(&codec, VP9E_SET_SVC, layering_mode > 0 ? 1 : 0))
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) { if (strncmp(encoder->name, "vp8", 3) == 0) {
vpx_codec_control(&codec, VP8E_SET_SCREEN_CONTENT_MODE, 0); vpx_codec_control(&codec, VP8E_SET_SCREEN_CONTENT_MODE, 0);
@ -842,7 +695,7 @@ int main(int argc, char **argv) {
// 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.
{ {
const int max_intra_size_pct = 1000; const int max_intra_size_pct = 900;
vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT, vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT,
max_intra_size_pct); max_intra_size_pct);
} }
@ -852,8 +705,10 @@ int main(int argc, char **argv) {
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) {
@ -863,12 +718,14 @@ int main(int argc, char **argv) {
layer_id.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; if (layering_mode == 0)
flags = 0;
frame_avail = vpx_img_read(&raw, infile); frame_avail = vpx_img_read(&raw, infile);
if (frame_avail) ++rc.layer_input_frames[layer_id.temporal_layer_id]; if (frame_avail)
++rc.layer_input_frames[layer_id.temporal_layer_id];
vpx_usec_timer_start(&timer); vpx_usec_timer_start(&timer);
if (vpx_codec_encode(&codec, frame_avail ? &raw : NULL, pts, 1, flags, if (vpx_codec_encode(&codec, frame_avail? &raw : NULL, pts, 1, flags,
VPX_DL_REALTIME)) { VPX_DL_REALTIME)) {
die_codec(&codec, "Failed to encode frame"); die_codec(&codec, "Failed to encode frame");
} }
vpx_usec_timer_mark(&timer); vpx_usec_timer_mark(&timer);
@ -878,12 +735,12 @@ int main(int argc, char **argv) {
layer_flags[0] &= ~VPX_EFLAG_FORCE_KF; layer_flags[0] &= ~VPX_EFLAG_FORCE_KF;
} }
got_data = 0; got_data = 0;
while ((pkt = vpx_codec_get_cx_data(&codec, &iter))) { while ( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
got_data = 1; got_data = 1;
switch (pkt->kind) { switch (pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT: case VPX_CODEC_CX_FRAME_PKT:
for (i = cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity]; for (i = cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
i < cfg.ts_number_layers; ++i) { i < cfg.ts_number_layers; ++i) {
vpx_video_writer_write_frame(outfile[i], pkt->data.frame.buf, vpx_video_writer_write_frame(outfile[i], pkt->data.frame.buf,
pkt->data.frame.sz, pts); pkt->data.frame.sz, pts);
++rc.layer_tot_enc_frames[i]; ++rc.layer_tot_enc_frames[i];
@ -926,7 +783,8 @@ int main(int argc, char **argv) {
} }
} }
break; break;
default: break; default:
break;
} }
} }
++frame_cnt; ++frame_cnt;
@ -936,17 +794,17 @@ int main(int argc, char **argv) {
printout_rate_control_summary(&rc, &cfg, frame_cnt); printout_rate_control_summary(&rc, &cfg, frame_cnt);
printf("\n"); printf("\n");
printf("Frame cnt and encoding time/FPS stats for encoding: %d %f %f \n", printf("Frame cnt and encoding time/FPS stats for encoding: %d %f %f \n",
frame_cnt, 1000 * (float)cx_time / (double)(frame_cnt * 1000000), frame_cnt,
1000000 * (double)frame_cnt / (double)cx_time); 1000 * (float)cx_time / (double)(frame_cnt * 1000000),
1000000 * (double)frame_cnt / (double)cx_time);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); if (vpx_codec_destroy(&codec))
die_codec(&codec, "Failed to destroy codec");
// Try to rewrite the output file headers with the actual frame count. // Try to rewrite the output file headers with the actual frame count.
for (i = 0; i < cfg.ts_number_layers; ++i) vpx_video_writer_close(outfile[i]); for (i = 0; i < cfg.ts_number_layers; ++i)
vpx_video_writer_close(outfile[i]);
vpx_img_free(&raw); vpx_img_free(&raw);
#if ROI_MAP
free(roi.roi_map);
#endif
return EXIT_SUCCESS; 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;
@ -46,8 +46,7 @@ int file_is_ivf(struct VpxInputContext *input_ctx) {
is_ivf = 1; is_ivf = 1;
if (mem_get_le16(raw_hdr + 4) != 0) { if (mem_get_le16(raw_hdr + 4) != 0) {
fprintf(stderr, fprintf(stderr, "Error: Unrecognized IVF version! This file may not"
"Error: Unrecognized IVF version! This file may not"
" decode properly."); " decode properly.");
} }
@ -70,13 +69,14 @@ int file_is_ivf(struct VpxInputContext *input_ctx) {
return is_ivf; return is_ivf;
} }
int ivf_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read, int ivf_read_frame(FILE *infile, uint8_t **buffer,
size_t *buffer_size) { size_t *bytes_read, size_t *buffer_size) {
char raw_header[IVF_FRAME_HDR_SZ] = { 0 }; char raw_header[IVF_FRAME_HDR_SZ] = {0};
size_t frame_size = 0; size_t frame_size = 0;
if (fread(raw_header, IVF_FRAME_HDR_SZ, 1, infile) != 1) { if (fread(raw_header, IVF_FRAME_HDR_SZ, 1, infile) != 1) {
if (!feof(infile)) warn("Failed to read frame size\n"); if (!feof(infile))
warn("Failed to read frame size\n");
} else { } else {
frame_size = mem_get_le32(raw_header); frame_size = mem_get_le32(raw_header);

View File

@ -18,11 +18,11 @@ extern "C" {
int file_is_ivf(struct VpxInputContext *input); int file_is_ivf(struct VpxInputContext *input);
int ivf_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read, int ivf_read_frame(FILE *infile, uint8_t **buffer,
size_t *buffer_size); size_t *bytes_read, size_t *buffer_size);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif
#endif // IVFDEC_H_ #endif // IVFDEC_H_

View File

@ -13,8 +13,10 @@
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "vpx_ports/mem_ops.h" #include "vpx_ports/mem_ops.h"
void ivf_write_file_header(FILE *outfile, const struct vpx_codec_enc_cfg *cfg, void ivf_write_file_header(FILE *outfile,
unsigned int fourcc, int frame_cnt) { const struct vpx_codec_enc_cfg *cfg,
unsigned int fourcc,
int frame_cnt) {
char header[32]; char header[32];
header[0] = 'D'; header[0] = 'D';

View File

@ -19,15 +19,17 @@ struct vpx_codec_cx_pkt;
extern "C" { extern "C" {
#endif #endif
void ivf_write_file_header(FILE *outfile, const struct vpx_codec_enc_cfg *cfg, void ivf_write_file_header(FILE *outfile,
uint32_t fourcc, int frame_cnt); const struct vpx_codec_enc_cfg *cfg,
uint32_t fourcc,
int frame_cnt);
void ivf_write_frame_header(FILE *outfile, int64_t pts, size_t frame_size); void ivf_write_frame_header(FILE *outfile, int64_t pts, size_t frame_size);
void ivf_write_frame_size(FILE *outfile, size_t frame_size); void ivf_write_frame_size(FILE *outfile, size_t frame_size);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif
#endif // IVFENC_H_ #endif // IVFENC_H_

View File

@ -943,6 +943,18 @@ GENERATE_XML = NO
XML_OUTPUT = xml XML_OUTPUT = xml
# The XML_SCHEMA tag can be used to specify an XML schema,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_SCHEMA =
# The XML_DTD tag can be used to specify an XML DTD,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will # If the XML_PROGRAMLISTING tag is set to YES Doxygen will
# dump the program listings (including syntax highlighting # dump the program listings (including syntax highlighting
# and cross-referencing information) to the XML output. Note that # and cross-referencing information) to the XML output. Note that

258
libs.mk
View File

@ -12,7 +12,7 @@
# ARM assembly files are written in RVCT-style. We use some make magic to # ARM assembly files are written in RVCT-style. We use some make magic to
# filter those files to allow GCC compilation # filter those files to allow GCC compilation
ifeq ($(ARCH_ARM),yes) ifeq ($(ARCH_ARM),yes)
ASM:=$(if $(filter yes,$(CONFIG_GCC)$(CONFIG_MSVS)),.asm.S,.asm) ASM:=$(if $(filter yes,$(CONFIG_GCC)$(CONFIG_MSVS)),.asm.s,.asm)
else else
ASM:=.asm ASM:=.asm
endif endif
@ -25,7 +25,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 +34,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,13 +54,7 @@ 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))
include $(SRC_PATH_BARE)/vpx_util/vpx_util.mk
CODEC_SRCS-yes += $(addprefix vpx_util/,$(call enabled,UTIL_SRCS))
ifeq ($(CONFIG_VP8),yes)
VP8_PREFIX=vp8/ VP8_PREFIX=vp8/
include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8_common.mk include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8_common.mk
endif endif
@ -76,7 +77,7 @@ ifeq ($(CONFIG_VP8_DECODER),yes)
CODEC_DOC_SECTIONS += vp8 vp8_decoder CODEC_DOC_SECTIONS += vp8 vp8_decoder
endif endif
ifeq ($(CONFIG_VP9),yes) ifneq ($(CONFIG_VP9_ENCODER)$(CONFIG_VP9_DECODER),)
VP9_PREFIX=vp9/ VP9_PREFIX=vp9/
include $(SRC_PATH_BARE)/$(VP9_PREFIX)vp9_common.mk include $(SRC_PATH_BARE)/$(VP9_PREFIX)vp9_common.mk
endif endif
@ -88,7 +89,7 @@ ifeq ($(CONFIG_VP9_ENCODER),yes)
CODEC_EXPORTS-yes += $(addprefix $(VP9_PREFIX),$(VP9_CX_EXPORTS)) CODEC_EXPORTS-yes += $(addprefix $(VP9_PREFIX),$(VP9_CX_EXPORTS))
CODEC_SRCS-yes += $(VP9_PREFIX)vp9cx.mk vpx/vp8.h vpx/vp8cx.h 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-yes += include/vpx/svc_context.h INSTALL-LIBS-$(CONFIG_SPATIAL_SVC) += include/vpx/svc_context.h
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_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
@ -106,6 +107,9 @@ ifeq ($(CONFIG_VP9_DECODER),yes)
CODEC_DOC_SECTIONS += vp9 vp9_decoder CODEC_DOC_SECTIONS += vp9 vp9_decoder
endif endif
VP9_PREFIX=vp9/
$(BUILD_PFX)$(VP9_PREFIX)%.c.o: CFLAGS += -Wextra
ifeq ($(CONFIG_ENCODERS),yes) ifeq ($(CONFIG_ENCODERS),yes)
CODEC_DOC_SECTIONS += encoder CODEC_DOC_SECTIONS += encoder
endif endif
@ -113,12 +117,6 @@ ifeq ($(CONFIG_DECODERS),yes)
CODEC_DOC_SECTIONS += decoder CODEC_DOC_SECTIONS += decoder
endif endif
# Suppress -Wextra warnings in third party code.
$(BUILD_PFX)third_party/googletest/%.cc.o: CXXFLAGS += -Wno-missing-field-initializers
# Suppress -Wextra warnings in first party code pending investigation.
# https://bugs.chromium.org/p/webm/issues/detail?id=1069
$(BUILD_PFX)vp8/encoder/onyx_if.c.o: CFLAGS += -Wno-unknown-warning-option -Wno-clobbered
$(BUILD_PFX)vp8/decoder/onyxd_if.c.o: CFLAGS += -Wno-unknown-warning-option -Wno-clobbered
ifeq ($(CONFIG_MSVS),yes) ifeq ($(CONFIG_MSVS),yes)
CODEC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd) CODEC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd)
@ -139,21 +137,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 INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += third_party/x86inc/x86inc.asm
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += vpx_dsp/x86/bitdepth_conversion_sse2.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
CODEC_EXPORTS-$(CONFIG_VP9_ENCODER) += vpx/exports_spatial_svc
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
@ -186,13 +182,6 @@ libvpx_srcs.txt:
@echo $(CODEC_SRCS) | xargs -n1 echo | LC_ALL=C sort -u > $@ @echo $(CODEC_SRCS) | xargs -n1 echo | LC_ALL=C sort -u > $@
CLEAN-OBJS += libvpx_srcs.txt CLEAN-OBJS += libvpx_srcs.txt
# Assembly files that are included, but don't define symbols themselves.
# Filtered out to avoid Windows build warnings.
ASM_INCLUDES := \
third_party/x86inc/x86inc.asm \
vpx_config.asm \
vpx_ports/x86_abi_support.asm \
vpx_dsp/x86/bitdepth_conversion_sse2.asm \
ifeq ($(CONFIG_EXTERNAL_BUILD),yes) ifeq ($(CONFIG_EXTERNAL_BUILD),yes)
ifeq ($(CONFIG_MSVS),yes) ifeq ($(CONFIG_MSVS),yes)
@ -204,7 +193,12 @@ vpx.def: $(call enabled,CODEC_EXPORTS)
--out=$@ $^ --out=$@ $^
CLEAN-OBJS += vpx.def CLEAN-OBJS += vpx.def
vpx.$(VCPROJ_SFX): VCPROJ_SRCS=$(filter-out $(addprefix %, $(ASM_INCLUDES)), $^) # Assembly files that are included, but don't define symbols themselves.
# Filtered out to avoid Visual Studio build warnings.
ASM_INCLUDES := \
third_party/x86inc/x86inc.asm \
vpx_config.asm \
vpx_ports/x86_abi_support.asm \
vpx.$(VCPROJ_SFX): $(CODEC_SRCS) vpx.def vpx.$(VCPROJ_SFX): $(CODEC_SRCS) vpx.def
@echo " [CREATE] $@" @echo " [CREATE] $@"
@ -218,65 +212,42 @@ vpx.$(VCPROJ_SFX): $(CODEC_SRCS) vpx.def
--ver=$(CONFIG_VS_VERSION) \ --ver=$(CONFIG_VS_VERSION) \
--src-path-bare="$(SRC_PATH_BARE)" \ --src-path-bare="$(SRC_PATH_BARE)" \
--out=$@ $(CFLAGS) \ --out=$@ $(CFLAGS) \
$(filter $(SRC_PATH_BARE)/vp8/%.c, $(VCPROJ_SRCS)) \ $(filter-out $(addprefix %, $(ASM_INCLUDES)), $^) \
$(filter $(SRC_PATH_BARE)/vp8/%.h, $(VCPROJ_SRCS)) \
$(filter $(SRC_PATH_BARE)/vp9/%.c, $(VCPROJ_SRCS)) \
$(filter $(SRC_PATH_BARE)/vp9/%.h, $(VCPROJ_SRCS)) \
$(filter $(SRC_PATH_BARE)/vpx/%, $(VCPROJ_SRCS)) \
$(filter $(SRC_PATH_BARE)/vpx_dsp/%, $(VCPROJ_SRCS)) \
$(filter-out $(addprefix $(SRC_PATH_BARE)/, \
vp8/%.c vp8/%.h vp9/%.c vp9/%.h vpx/% vpx_dsp/%), \
$(VCPROJ_SRCS)) \
--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)
endif endif
else else
LIBVPX_OBJS=$(call objs, $(filter-out $(ASM_INCLUDES), $(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 := 5
BUILD_LIBVPX_SO := $(if $(BUILD_LIBVPX),$(CONFIG_SHARED))
SO_VERSION_MAJOR := 2
SO_VERSION_MINOR := 0 SO_VERSION_MINOR := 0
SO_VERSION_PATCH := 0 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.$(SO_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).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) 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
LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, \ LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, \
libvpx.so libvpx.so.$(SO_VERSION_MAJOR) \ libvpx.so libvpx.so.$(SO_VERSION_MAJOR) \
libvpx.so.$(SO_VERSION_MAJOR).$(SO_VERSION_MINOR)) libvpx.so.$(SO_VERSION_MAJOR).$(SO_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.$(SO_VERSION_MAJOR)
@ -294,19 +265,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) $$@"
@ -322,12 +280,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)' > $@
@ -353,6 +310,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
# #
@ -375,19 +335,13 @@ endif
# #
# Add assembler dependencies for configuration. # Add assembler dependencies for configuration.
# #
$(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
$(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
@ -397,14 +351,10 @@ 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=https://storage.googleapis.com/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] $@"
@ -413,16 +363,8 @@ 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
@echo " [DOWNLOAD] $@" @echo " [DOWNLOAD] $@"
# Attempt to download the file using curl, retrying once if it fails for a $(qexec)trap 'rm -f $@' INT TERM &&\
# partial file (18). curl -L -o $@ $(call libvpx_test_data_url,$(@F))
$(qexec)( \
trap 'rm -f $@' INT TERM; \
curl="curl --retry 1 -L -o $@ $(call libvpx_test_data_url,$(@F))"; \
$$curl; \
case "$$?" in \
18) $$curl -C -;; \
esac \
)
testdata:: $(LIBVPX_TEST_DATA) testdata:: $(LIBVPX_TEST_DATA)
$(qexec)[ -x "$$(which sha1sum)" ] && sha1sum=sha1sum;\ $(qexec)[ -x "$$(which sha1sum)" ] && sha1sum=sha1sum;\
@ -431,10 +373,12 @@ testdata:: $(LIBVPX_TEST_DATA)
if [ -n "$${sha1sum}" ]; then\ if [ -n "$${sha1sum}" ]; then\
set -e;\ set -e;\
echo "Checking test data:";\ echo "Checking test data:";\
for f in $(call enabled,LIBVPX_TEST_DATA); do\ if [ -n "$(LIBVPX_TEST_DATA)" ]; then\
grep $$f $(SRC_PATH_BARE)/test/test-data.sha1 |\ for f in $(call enabled,LIBVPX_TEST_DATA); do\
(cd $(LIBVPX_TEST_DATA_PATH); $${sha1sum} -c);\ grep $$f $(SRC_PATH_BARE)/test/test-data.sha1 |\
done; \ (cd $(LIBVPX_TEST_DATA_PATH); $${sha1sum} -c);\
done; \
fi; \
else\ else\
echo "Skipping test data integrity check, sha1sum not found.";\ echo "Skipping test data integrity check, sha1sum not found.";\
fi fi
@ -471,30 +415,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
@ -505,54 +430,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 ))\
$(LIBVPX_TEST_OBJS) \ $(if $(BUILD_LIBVPX),$(eval $(call linkerxx_template,$(bin),\
-L. -lvpx -lgtest $(extralibs) -lm)) $(LIBVPX_TEST_OBJS) \
-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; \
export GTEST_SHARD_INDEX=$(1); \ for t in $(LIBVPX_TEST_BINS); do \
export GTEST_TOTAL_SHARDS=$(2); \ export GTEST_SHARD_INDEX=$(1); \
$(LIBVPX_TEST_BIN) export GTEST_TOTAL_SHARDS=$(2); \
test_shard.$(1): testdata $$$$t; \
done
.PHONY: test_shard.$(1) .PHONY: test_shard.$(1)
endef endef
@ -597,16 +513,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
@ -624,12 +539,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

@ -20,17 +20,19 @@
* Still in the public domain. * Still in the public domain.
*/ */
#include <string.h> /* for memcpy() */ #include <string.h> /* for memcpy() */
#include "md5_utils.h" #include "md5_utils.h"
static void byteSwap(UWORD32 *buf, unsigned words) { void
byteSwap(UWORD32 *buf, unsigned words) {
md5byte *p; md5byte *p;
/* Only swap bytes for big endian machines */ /* Only swap bytes for big endian machines */
int i = 1; int i = 1;
if (*(char *)&i == 1) return; if (*(char *)&i == 1)
return;
p = (md5byte *)buf; p = (md5byte *)buf;
@ -45,7 +47,8 @@ static void byteSwap(UWORD32 *buf, unsigned words) {
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants. * initialization constants.
*/ */
void MD5Init(struct MD5Context *ctx) { void
MD5Init(struct MD5Context *ctx) {
ctx->buf[0] = 0x67452301; ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89; ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe; ctx->buf[2] = 0x98badcfe;
@ -59,7 +62,8 @@ void MD5Init(struct MD5Context *ctx) {
* Update context to reflect the concatenation of another buffer full * Update context to reflect the concatenation of another buffer full
* of bytes. * of bytes.
*/ */
void MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) { void
MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) {
UWORD32 t; UWORD32 t;
/* Update byte count */ /* Update byte count */
@ -67,9 +71,9 @@ void MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) {
t = ctx->bytes[0]; t = ctx->bytes[0];
if ((ctx->bytes[0] = t + len) < t) if ((ctx->bytes[0] = t + len) < t)
ctx->bytes[1]++; /* Carry from low to high */ ctx->bytes[1]++; /* Carry from low to high */
t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
if (t > len) { if (t > len) {
memcpy((md5byte *)ctx->in + 64 - t, buf, len); memcpy((md5byte *)ctx->in + 64 - t, buf, len);
@ -100,7 +104,8 @@ void MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) {
* Final wrapup - pad to 64-byte boundary with the bit pattern * Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first) * 1 0* (64-bit count of bits processed, MSB-first)
*/ */
void MD5Final(md5byte digest[16], struct MD5Context *ctx) { void
MD5Final(md5byte digest[16], struct MD5Context *ctx) {
int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
md5byte *p = (md5byte *)ctx->in + count; md5byte *p = (md5byte *)ctx->in + count;
@ -110,7 +115,7 @@ void MD5Final(md5byte digest[16], struct MD5Context *ctx) {
/* Bytes of padding needed to make 56 bytes (-8..55) */ /* Bytes of padding needed to make 56 bytes (-8..55) */
count = 56 - 1 - count; count = 56 - 1 - count;
if (count < 0) { /* Padding forces an extra block */ if (count < 0) { /* Padding forces an extra block */
memset(p, 0, count + 8); memset(p, 0, count + 8);
byteSwap(ctx->in, 16); byteSwap(ctx->in, 16);
MD5Transform(ctx->buf, ctx->in); MD5Transform(ctx->buf, ctx->in);
@ -142,27 +147,16 @@ void MD5Final(md5byte digest[16], struct MD5Context *ctx) {
#define F4(x, y, z) (y ^ (x | ~z)) #define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */ /* This is the central step in the MD5 algorithm. */
#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 MD5Transform(UWORD32 buf[4], void
UWORD32 const in[16]) { MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) {
register UWORD32 a, b, c, d; register UWORD32 a, b, c, d;
a = buf[0]; a = buf[0];
@ -244,6 +238,4 @@ VPX_NO_UNSIGNED_OVERFLOW_CHECK void MD5Transform(UWORD32 buf[4],
buf[3] += d; buf[3] += d;
} }
#undef VPX_NO_UNSIGNED_OVERFLOW_CHECK
#endif #endif

View File

@ -37,13 +37,7 @@ struct rate_hist {
struct rate_hist *init_rate_histogram(const vpx_codec_enc_cfg_t *cfg, struct rate_hist *init_rate_histogram(const vpx_codec_enc_cfg_t *cfg,
const vpx_rational_t *fps) { const vpx_rational_t *fps) {
int i; int i;
struct rate_hist *hist = calloc(1, sizeof(*hist)); struct rate_hist *hist = malloc(sizeof(*hist));
if (hist == NULL || cfg == NULL || fps == NULL || fps->num == 0 ||
fps->den == 0) {
destroy_rate_histogram(hist);
return NULL;
}
// Determine the number of samples in the buffer. Use the file's framerate // Determine the number of samples in the buffer. Use the file's framerate
// to determine the number of frames in rc_buf_sz milliseconds, with an // to determine the number of frames in rc_buf_sz milliseconds, with an
@ -51,7 +45,8 @@ struct rate_hist *init_rate_histogram(const vpx_codec_enc_cfg_t *cfg,
hist->samples = cfg->rc_buf_sz * 5 / 4 * fps->num / fps->den / 1000; hist->samples = cfg->rc_buf_sz * 5 / 4 * fps->num / fps->den / 1000;
// prevent division by zero // prevent division by zero
if (hist->samples == 0) hist->samples = 1; if (hist->samples == 0)
hist->samples = 1;
hist->frames = 0; hist->frames = 0;
hist->total = 0; hist->total = 0;
@ -83,20 +78,15 @@ void update_rate_histogram(struct rate_hist *hist,
int64_t avg_bitrate = 0; int64_t avg_bitrate = 0;
int64_t sum_sz = 0; int64_t sum_sz = 0;
const int64_t now = pkt->data.frame.pts * 1000 * const int64_t now = pkt->data.frame.pts * 1000 *
(uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.num /
(uint64_t)cfg->g_timebase.den; (uint64_t)cfg->g_timebase.den;
int idx; int idx = hist->frames++ % hist->samples;
if (hist == NULL || cfg == NULL || pkt == NULL) return;
idx = hist->frames++ % hist->samples;
hist->pts[idx] = now; hist->pts[idx] = now;
hist->sz[idx] = (int)pkt->data.frame.sz; hist->sz[idx] = (int)pkt->data.frame.sz;
if (now < cfg->rc_buf_initial_sz) return; if (now < cfg->rc_buf_initial_sz)
return;
if (!cfg->rc_target_bitrate) return;
then = now; then = now;
@ -105,16 +95,20 @@ void update_rate_histogram(struct rate_hist *hist,
const int i_idx = (i - 1) % hist->samples; const int i_idx = (i - 1) % hist->samples;
then = hist->pts[i_idx]; then = hist->pts[i_idx];
if (now - then > cfg->rc_buf_sz) break; if (now - then > cfg->rc_buf_sz)
break;
sum_sz += hist->sz[i_idx]; sum_sz += hist->sz[i_idx];
} }
if (now == then) return; if (now == then)
return;
avg_bitrate = sum_sz * 8 * 1000 / (now - then); avg_bitrate = sum_sz * 8 * 1000 / (now - then);
idx = (int)(avg_bitrate * (RATE_BINS / 2) / (cfg->rc_target_bitrate * 1000)); idx = (int)(avg_bitrate * (RATE_BINS / 2) / (cfg->rc_target_bitrate * 1000));
if (idx < 0) idx = 0; if (idx < 0)
if (idx > RATE_BINS - 1) idx = RATE_BINS - 1; idx = 0;
if (idx > RATE_BINS - 1)
idx = RATE_BINS - 1;
if (hist->bucket[idx].low > avg_bitrate) if (hist->bucket[idx].low > avg_bitrate)
hist->bucket[idx].low = (int)avg_bitrate; hist->bucket[idx].low = (int)avg_bitrate;
if (hist->bucket[idx].high < avg_bitrate) if (hist->bucket[idx].high < avg_bitrate)
@ -123,22 +117,19 @@ void update_rate_histogram(struct rate_hist *hist,
hist->total++; hist->total++;
} }
static int merge_hist_buckets(struct hist_bucket *bucket, int max_buckets, static int merge_hist_buckets(struct hist_bucket *bucket,
int *num_buckets) { int max_buckets, int *num_buckets) {
int small_bucket = 0, merge_bucket = INT_MAX, big_bucket = 0; int small_bucket = 0, merge_bucket = INT_MAX, big_bucket = 0;
int buckets; int buckets = *num_buckets;
int i; int i;
assert(bucket != NULL);
assert(num_buckets != NULL);
buckets = *num_buckets;
/* Find the extrema for this list of buckets */ /* Find the extrema for this list of buckets */
big_bucket = small_bucket = 0; big_bucket = small_bucket = 0;
for (i = 0; i < buckets; i++) { for (i = 0; i < buckets; i++) {
if (bucket[i].count < bucket[small_bucket].count) small_bucket = i; if (bucket[i].count < bucket[small_bucket].count)
if (bucket[i].count > bucket[big_bucket].count) big_bucket = i; small_bucket = i;
if (bucket[i].count > bucket[big_bucket].count)
big_bucket = i;
} }
/* If we have too many buckets, merge the smallest with an adjacent /* If we have too many buckets, merge the smallest with an adjacent
@ -180,10 +171,13 @@ static int merge_hist_buckets(struct hist_bucket *bucket, int max_buckets,
*/ */
big_bucket = small_bucket = 0; big_bucket = small_bucket = 0;
for (i = 0; i < buckets; i++) { for (i = 0; i < buckets; i++) {
if (i > merge_bucket) bucket[i] = bucket[i + 1]; if (i > merge_bucket)
bucket[i] = bucket[i + 1];
if (bucket[i].count < bucket[small_bucket].count) small_bucket = i; if (bucket[i].count < bucket[small_bucket].count)
if (bucket[i].count > bucket[big_bucket].count) big_bucket = i; small_bucket = i;
if (bucket[i].count > bucket[big_bucket].count)
big_bucket = i;
} }
} }
@ -191,13 +185,11 @@ static int merge_hist_buckets(struct hist_bucket *bucket, int max_buckets,
return bucket[big_bucket].count; return bucket[big_bucket].count;
} }
static void show_histogram(const struct hist_bucket *bucket, int buckets, static void show_histogram(const struct hist_bucket *bucket,
int total, int scale) { int buckets, int total, int scale) {
const char *pat1, *pat2; const char *pat1, *pat2;
int i; int i;
assert(bucket != NULL);
switch ((int)(log(bucket[buckets - 1].high) / log(10)) + 1) { switch ((int)(log(bucket[buckets - 1].high) / log(10)) + 1) {
case 1: case 1:
case 2: case 2:
@ -237,7 +229,8 @@ static void show_histogram(const struct hist_bucket *bucket, int buckets,
pct = (float)(100.0 * bucket[i].count / total); pct = (float)(100.0 * bucket[i].count / total);
len = HIST_BAR_MAX * bucket[i].count / scale; len = HIST_BAR_MAX * bucket[i].count / scale;
if (len < 1) len = 1; if (len < 1)
len = 1;
assert(len <= HIST_BAR_MAX); assert(len <= HIST_BAR_MAX);
if (bucket[i].low == bucket[i].high) if (bucket[i].low == bucket[i].high)
@ -245,7 +238,8 @@ static void show_histogram(const struct hist_bucket *bucket, int buckets,
else else
fprintf(stderr, pat2, bucket[i].low, bucket[i].high); fprintf(stderr, pat2, bucket[i].low, bucket[i].high);
for (j = 0; j < HIST_BAR_MAX; j++) fprintf(stderr, j < len ? "=" : " "); for (j = 0; j < HIST_BAR_MAX; j++)
fprintf(stderr, j < len ? "=" : " ");
fprintf(stderr, "\t%5d (%6.2f%%)\n", bucket[i].count, pct); fprintf(stderr, "\t%5d (%6.2f%%)\n", bucket[i].count, pct);
} }
} }
@ -271,15 +265,14 @@ void show_q_histogram(const int counts[64], int max_buckets) {
show_histogram(bucket, buckets, total, scale); show_histogram(bucket, buckets, total, scale);
} }
void show_rate_histogram(struct rate_hist *hist, const vpx_codec_enc_cfg_t *cfg, void show_rate_histogram(struct rate_hist *hist,
int max_buckets) { const vpx_codec_enc_cfg_t *cfg, int max_buckets) {
int i, scale; int i, scale;
int buckets = 0; int buckets = 0;
if (hist == NULL || cfg == NULL) return;
for (i = 0; i < RATE_BINS; i++) { for (i = 0; i < RATE_BINS; i++) {
if (hist->bucket[i].low == INT_MAX) continue; if (hist->bucket[i].low == INT_MAX)
continue;
hist->bucket[buckets++] = hist->bucket[i]; hist->bucket[buckets++] = hist->bucket[i];
} }

View File

@ -11,10 +11,6 @@
#ifndef TEST_ACM_RANDOM_H_ #ifndef TEST_ACM_RANDOM_H_
#define TEST_ACM_RANDOM_H_ #define TEST_ACM_RANDOM_H_
#include <assert.h>
#include <limits>
#include "third_party/googletest/src/include/gtest/gtest.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "vpx/vpx_integer.h" #include "vpx/vpx_integer.h"
@ -27,19 +23,15 @@ class ACMRandom {
explicit ACMRandom(int seed) : random_(seed) {} explicit ACMRandom(int seed) : random_(seed) {}
void Reset(int seed) { random_.Reseed(seed); } void Reset(int seed) {
random_.Reseed(seed);
}
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 >> 15) & 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);
@ -54,18 +46,17 @@ class ACMRandom {
return r < 128 ? r << 4 : r >> 4; return r < 128 ? r << 4 : r >> 4;
} }
uint32_t RandRange(const uint32_t range) { int PseudoUniform(int range) {
// testing::internal::Random::Generate provides values in the range
// testing::internal::Random::kMaxRange.
assert(range <= testing::internal::Random::kMaxRange);
return random_.Generate(range); return random_.Generate(range);
} }
int PseudoUniform(int range) { return random_.Generate(range); } int operator()(int n) {
return PseudoUniform(n);
}
int operator()(int n) { return PseudoUniform(n); } static int DeterministicSeed(void) {
return 0xbaba;
static int DeterministicSeed(void) { return 0xbaba; } }
private: private:
testing::internal::Random random_; testing::internal::Random random_;

View File

@ -1,128 +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;
::libvpx_test::Y4mVideoSource video("desktop_credits.y4m", 0, 30);
::libvpx_test::Y4mVideoSource video_holder("desktop_credits.y4m", 0, 30);
video_holder.Begin();
y4m_holder_ = &video_holder;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
VP9_INSTANTIATE_TEST_CASE(ActiveMapRefreshTest,
::testing::Values(::libvpx_test::kRealTime),
::testing::Range(5, 6));
} // namespace

View File

@ -39,7 +39,6 @@ class ActiveMapTest
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 = vpx_active_map_t();
/* clang-format off */
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,
@ -51,7 +50,6 @@ class ActiveMapTest
0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0,
}; };
/* clang-format on */
map.cols = (kWidth + 15) / 16; map.cols = (kWidth + 15) / 16;
map.rows = (kHeight + 15) / 16; map.rows = (kHeight + 15) / 16;
ASSERT_EQ(map.cols, 13u); ASSERT_EQ(map.cols, 13u);
@ -79,13 +77,13 @@ TEST_P(ActiveMapTest, Test) {
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, 1, ::libvpx_test::I420VideoSource video("hantro_odd.yuv", kWidth, kHeight, 30,
0, 20); 1, 0, 20);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
VP9_INSTANTIATE_TEST_CASE(ActiveMapTest, VP9_INSTANTIATE_TEST_CASE(ActiveMapTest,
::testing::Values(::libvpx_test::kRealTime), ::testing::Values(::libvpx_test::kRealTime),
::testing::Range(0, 9)); ::testing::Range(0, 6));
} // namespace } // namespace

View File

@ -1,136 +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 {
static const int kNoiseSize = 3072;
// TODO(jimbankoski): make width and height integers not unsigned.
typedef void (*AddNoiseFunc)(uint8_t *start, const int8_t *noise,
int blackclamp, int whiteclamp, int width,
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) {
const int width = 64;
const int height = 64;
const int image_size = width * height;
int8_t noise[kNoiseSize];
const int clamp = vpx_setup_noise(4.4, noise, kNoiseSize);
uint8_t *const s =
reinterpret_cast<uint8_t *>(vpx_calloc(image_size, sizeof(*s)));
ASSERT_TRUE(s != NULL);
memset(s, 99, image_size * sizeof(*s));
ASM_REGISTER_STATE_CHECK(
GetParam()(s, noise, clamp, clamp, 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, clamp, clamp, 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, clamp, clamp, 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) {
const int width = 64;
const int height = 64;
const int image_size = width * height;
int8_t noise[kNoiseSize];
const int clamp = vpx_setup_noise(4.4, noise, kNoiseSize);
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));
ASSERT_TRUE(s != NULL);
ASSERT_TRUE(d != NULL);
memset(s, 99, image_size);
memset(d, 99, image_size);
srand(0);
ASM_REGISTER_STATE_CHECK(
GetParam()(s, noise, clamp, clamp, width, height, width));
srand(0);
ASM_REGISTER_STATE_CHECK(
vpx_plane_add_noise_c(d, noise, clamp, clamp, 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

@ -1,157 +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 "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 AltRefAqSegmentTest
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
protected:
AltRefAqSegmentTest() : EncoderTest(GET_PARAM(0)) {}
virtual ~AltRefAqSegmentTest() {}
virtual void SetUp() {
InitializeConfig();
SetMode(GET_PARAM(1));
set_cpu_used_ = GET_PARAM(2);
aq_mode_ = 0;
alt_ref_aq_mode_ = 0;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
encoder->Control(VP9E_SET_ALT_REF_AQ, alt_ref_aq_mode_);
encoder->Control(VP9E_SET_AQ_MODE, aq_mode_);
encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 100);
}
}
int set_cpu_used_;
int aq_mode_;
int alt_ref_aq_mode_;
};
// Validate that this ALT_REF_AQ/AQ segmentation mode
// (ALT_REF_AQ=0, AQ=0/no_aq)
// encodes and decodes without a mismatch.
TEST_P(AltRefAqSegmentTest, TestNoMisMatchAltRefAQ0) {
cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_VBR;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_target_bitrate = 300;
aq_mode_ = 0;
alt_ref_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 ALT_REF_AQ/AQ segmentation mode
// (ALT_REF_AQ=0, AQ=1/variance_aq)
// encodes and decodes without a mismatch.
TEST_P(AltRefAqSegmentTest, TestNoMisMatchAltRefAQ1) {
cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_VBR;
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;
alt_ref_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 ALT_REF_AQ/AQ segmentation mode
// (ALT_REF_AQ=0, AQ=2/complexity_aq)
// encodes and decodes without a mismatch.
TEST_P(AltRefAqSegmentTest, TestNoMisMatchAltRefAQ2) {
cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_VBR;
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;
alt_ref_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 ALT_REF_AQ/AQ segmentation mode
// (ALT_REF_AQ=0, AQ=3/cyclicrefresh_aq)
// encodes and decodes without a mismatch.
TEST_P(AltRefAqSegmentTest, TestNoMisMatchAltRefAQ3) {
cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_VBR;
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;
alt_ref_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 ALT_REF_AQ/AQ segmentation mode
// (ALT_REF_AQ=0, AQ=4/equator360_aq)
// encodes and decodes without a mismatch.
TEST_P(AltRefAqSegmentTest, TestNoMisMatchAltRefAQ4) {
cfg_.rc_min_quantizer = 8;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_VBR;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_target_bitrate = 300;
aq_mode_ = 4;
alt_ref_aq_mode_ = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 100);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
VP9_INSTANTIATE_TEST_CASE(AltRefAqSegmentTest,
::testing::Values(::libvpx_test::kOnePassGood,
::libvpx_test::kTwoPassGood),
::testing::Range(2, 5));
} // namespace

View File

@ -14,14 +14,12 @@
#include "test/util.h" #include "test/util.h"
namespace { namespace {
#if CONFIG_VP8_ENCODER
// lookahead range: [kLookAheadMin, kLookAheadMax). // lookahead range: [kLookAheadMin, kLookAheadMax).
const int kLookAheadMin = 5; const int kLookAheadMin = 5;
const int kLookAheadMax = 26; const int kLookAheadMax = 26;
class AltRefTest : public ::libvpx_test::EncoderTest, class AltRefTest : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<int> { public ::libvpx_test::CodecTestWithParam<int> {
protected: protected:
AltRefTest() : EncoderTest(GET_PARAM(0)), altref_count_(0) {} AltRefTest() : EncoderTest(GET_PARAM(0)), altref_count_(0) {}
virtual ~AltRefTest() {} virtual ~AltRefTest() {}
@ -31,7 +29,9 @@ class AltRefTest : public ::libvpx_test::EncoderTest,
SetMode(libvpx_test::kTwoPassGood); SetMode(libvpx_test::kTwoPassGood);
} }
virtual void BeginPassHook(unsigned int /*pass*/) { altref_count_ = 0; } virtual void BeginPassHook(unsigned int pass) {
altref_count_ = 0;
}
virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video, virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
libvpx_test::Encoder *encoder) { libvpx_test::Encoder *encoder) {
@ -63,90 +63,7 @@ TEST_P(AltRefTest, MonotonicTimestamps) {
EXPECT_GE(altref_count(), 1); EXPECT_GE(altref_count(), 1);
} }
VP8_INSTANTIATE_TEST_CASE(AltRefTest, VP8_INSTANTIATE_TEST_CASE(AltRefTest,
::testing::Range(kLookAheadMin, kLookAheadMax)); ::testing::Range(kLookAheadMin, kLookAheadMax));
#endif // CONFIG_VP8_ENCODER
class AltRefForcedKeyTestLarge
: public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
protected:
AltRefForcedKeyTestLarge()
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)),
cpu_used_(GET_PARAM(2)), forced_kf_frame_num_(1), frame_num_(0) {}
virtual ~AltRefForcedKeyTestLarge() {}
virtual void SetUp() {
InitializeConfig();
SetMode(encoding_mode_);
cfg_.rc_end_usage = VPX_VBR;
cfg_.g_threads = 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(VP8E_SET_ENABLEAUTOALTREF, 1);
#if CONFIG_VP9_ENCODER
// override test default for tile columns if necessary.
if (GET_PARAM(0) == &libvpx_test::kVP9) {
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) {
if (frame_num_ == forced_kf_frame_num_) {
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 cpu_used_;
unsigned int forced_kf_frame_num_;
unsigned int frame_num_;
};
TEST_P(AltRefForcedKeyTestLarge, Frame1IsKey) {
const vpx_rational timebase = { 1, 30 };
const int lag_values[] = { 3, 15, 25, -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,
timebase.den, timebase.num, 0, 30);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
}
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));
}
}
VP8_INSTANTIATE_TEST_CASE(AltRefForcedKeyTestLarge,
::testing::Values(::libvpx_test::kOnePassGood),
::testing::Range(0, 9));
VP9_INSTANTIATE_TEST_CASE(AltRefForcedKeyTestLarge,
::testing::Values(::libvpx_test::kOnePassGood),
::testing::Range(0, 9));
} // namespace } // namespace

View File

@ -32,7 +32,6 @@ LOCAL_CPP_EXTENSION := .cc
LOCAL_MODULE := gtest LOCAL_MODULE := gtest
LOCAL_C_INCLUDES := $(LOCAL_PATH)/third_party/googletest/src/ LOCAL_C_INCLUDES := $(LOCAL_PATH)/third_party/googletest/src/
LOCAL_C_INCLUDES += $(LOCAL_PATH)/third_party/googletest/src/include/ LOCAL_C_INCLUDES += $(LOCAL_PATH)/third_party/googletest/src/include/
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/third_party/googletest/src/include/
LOCAL_SRC_FILES := ./third_party/googletest/src/src/gtest-all.cc LOCAL_SRC_FILES := ./third_party/googletest/src/src/gtest-all.cc
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
@ -52,6 +51,4 @@ 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

@ -57,7 +57,7 @@ TEST_P(AqSegmentTest, TestNoMisMatchAQ1) {
aq_mode_ = 1; aq_mode_ = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 100); 30, 1, 0, 100);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
@ -77,7 +77,7 @@ TEST_P(AqSegmentTest, TestNoMisMatchAQ2) {
aq_mode_ = 2; aq_mode_ = 2;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 100); 30, 1, 0, 100);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
@ -97,7 +97,7 @@ TEST_P(AqSegmentTest, TestNoMisMatchAQ3) {
aq_mode_ = 3; aq_mode_ = 3;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 100); 30, 1, 0, 100);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }

View File

@ -1,581 +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 "./vp9_rtcd.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"
#include "vpx_ports/vpx_timer.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
static 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);
}
static 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 ::testing::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() {
const int block_size = GET_PARAM(3);
unsigned int expected = 0;
if (block_size == 8) {
expected =
ReferenceAverage8x8(source_data_ + GET_PARAM(2), source_stride_);
} else if (block_size == 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 ::testing::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 ::testing::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 tran_low_t *coeffs, int length);
typedef ::testing::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<tran_low_t *>(
vpx_memalign(16, sizeof(*src_) * satd_size_));
ASSERT_TRUE(src_ != NULL);
}
virtual void TearDown() {
libvpx_test::ClearSystemState();
vpx_free(src_);
}
void FillConstant(const tran_low_t val) {
for (int i = 0; i < satd_size_; ++i) src_[i] = val;
}
void FillRandom() {
for (int i = 0; i < satd_size_; ++i) {
const int16_t tmp = rnd_.Rand16();
src_[i] = (tran_low_t)tmp;
}
}
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:
tran_low_t *src_;
SatdFunc satd_func_;
ACMRandom rnd_;
};
typedef int64_t (*BlockErrorFunc)(const tran_low_t *coeff,
const tran_low_t *dqcoeff, int block_size);
typedef ::testing::tuple<int, BlockErrorFunc> BlockErrorTestFPParam;
class BlockErrorTestFP
: public ::testing::Test,
public ::testing::WithParamInterface<BlockErrorTestFPParam> {
protected:
virtual void SetUp() {
txfm_size_ = GET_PARAM(0);
block_error_func_ = GET_PARAM(1);
rnd_.Reset(ACMRandom::DeterministicSeed());
coeff_ = reinterpret_cast<tran_low_t *>(
vpx_memalign(16, sizeof(*coeff_) * txfm_size_));
dqcoeff_ = reinterpret_cast<tran_low_t *>(
vpx_memalign(16, sizeof(*dqcoeff_) * txfm_size_));
ASSERT_TRUE(coeff_ != NULL);
ASSERT_TRUE(dqcoeff_ != NULL);
}
virtual void TearDown() {
libvpx_test::ClearSystemState();
vpx_free(coeff_);
vpx_free(dqcoeff_);
}
void FillConstant(const tran_low_t coeff_val, const tran_low_t dqcoeff_val) {
for (int i = 0; i < txfm_size_; ++i) coeff_[i] = coeff_val;
for (int i = 0; i < txfm_size_; ++i) dqcoeff_[i] = dqcoeff_val;
}
void FillRandom() {
// Just two fixed seeds
rnd_.Reset(0xb0b9);
for (int i = 0; i < txfm_size_; ++i) coeff_[i] = rnd_.Rand16() >> 1;
rnd_.Reset(0xb0c8);
for (int i = 0; i < txfm_size_; ++i) dqcoeff_[i] = rnd_.Rand16() >> 1;
}
void Check(const int64_t expected) {
int64_t total;
ASM_REGISTER_STATE_CHECK(
total = block_error_func_(coeff_, dqcoeff_, txfm_size_));
EXPECT_EQ(expected, total);
}
int txfm_size_;
private:
tran_low_t *coeff_;
tran_low_t *dqcoeff_;
BlockErrorFunc block_error_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);
}
TEST_P(SatdTest, DISABLED_Speed) {
const int kCountSpeedTestBlock = 20000;
vpx_usec_timer timer;
DECLARE_ALIGNED(16, tran_low_t, coeff[1024]);
const int blocksize = GET_PARAM(0);
vpx_usec_timer_start(&timer);
for (int i = 0; i < kCountSpeedTestBlock; ++i) {
GET_PARAM(1)(coeff, blocksize);
}
vpx_usec_timer_mark(&timer);
const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
printf("blocksize: %4d time: %4d us\n", blocksize, elapsed_time);
}
TEST_P(BlockErrorTestFP, MinValue) {
const int64_t kMin = -32640;
const int64_t expected = kMin * kMin * txfm_size_;
FillConstant(kMin, 0);
Check(expected);
}
TEST_P(BlockErrorTestFP, MaxValue) {
const int64_t kMax = 32640;
const int64_t expected = kMax * kMax * txfm_size_;
FillConstant(kMax, 0);
Check(expected);
}
TEST_P(BlockErrorTestFP, Random) {
int64_t expected;
switch (txfm_size_) {
case 16: expected = 2051681432; break;
case 64: expected = 11075114379; break;
case 256: expected = 44386271116; break;
case 1024: expected = 184774996089; break;
default:
FAIL() << "Invalid satd size (" << txfm_size_
<< ") valid: 16/64/256/1024";
}
FillRandom();
Check(expected);
}
TEST_P(BlockErrorTestFP, DISABLED_Speed) {
const int kCountSpeedTestBlock = 20000;
vpx_usec_timer timer;
DECLARE_ALIGNED(16, tran_low_t, coeff[1024]);
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[1024]);
const int blocksize = GET_PARAM(0);
vpx_usec_timer_start(&timer);
for (int i = 0; i < kCountSpeedTestBlock; ++i) {
GET_PARAM(1)(coeff, dqcoeff, blocksize);
}
vpx_usec_timer_mark(&timer);
const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
printf("blocksize: %4d time: %4d us\n", blocksize, elapsed_time);
}
using ::testing::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)));
INSTANTIATE_TEST_CASE_P(
C, BlockErrorTestFP,
::testing::Values(make_tuple(16, &vp9_block_error_fp_c),
make_tuple(64, &vp9_block_error_fp_c),
make_tuple(256, &vp9_block_error_fp_c),
make_tuple(1024, &vp9_block_error_fp_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)));
INSTANTIATE_TEST_CASE_P(
SSE2, BlockErrorTestFP,
::testing::Values(make_tuple(16, &vp9_block_error_fp_sse2),
make_tuple(64, &vp9_block_error_fp_sse2),
make_tuple(256, &vp9_block_error_fp_sse2),
make_tuple(1024, &vp9_block_error_fp_sse2)));
#endif // HAVE_SSE2
#if HAVE_AVX2
INSTANTIATE_TEST_CASE_P(AVX2, SatdTest,
::testing::Values(make_tuple(16, &vpx_satd_avx2),
make_tuple(64, &vpx_satd_avx2),
make_tuple(256, &vpx_satd_avx2),
make_tuple(1024, &vpx_satd_avx2)));
INSTANTIATE_TEST_CASE_P(
AVX2, BlockErrorTestFP,
::testing::Values(make_tuple(16, &vp9_block_error_fp_avx2),
make_tuple(64, &vp9_block_error_fp_avx2),
make_tuple(256, &vp9_block_error_fp_avx2),
make_tuple(1024, &vp9_block_error_fp_avx2)));
#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)));
// TODO(jianj): Remove the highbitdepth flag once the SIMD functions are
// in place.
#if !CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
NEON, BlockErrorTestFP,
::testing::Values(make_tuple(16, &vp9_block_error_fp_neon),
make_tuple(64, &vp9_block_error_fp_neon),
make_tuple(256, &vp9_block_error_fp_neon),
make_tuple(1024, &vp9_block_error_fp_neon)));
#endif // !CONFIG_VP9_HIGHBITDEPTH
#endif // HAVE_NEON
#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)));
INSTANTIATE_TEST_CASE_P(
MSA, IntProRowTest,
::testing::Values(make_tuple(16, &vpx_int_pro_row_msa, &vpx_int_pro_row_c),
make_tuple(32, &vpx_int_pro_row_msa, &vpx_int_pro_row_c),
make_tuple(64, &vpx_int_pro_row_msa,
&vpx_int_pro_row_c)));
INSTANTIATE_TEST_CASE_P(
MSA, IntProColTest,
::testing::Values(make_tuple(16, &vpx_int_pro_col_msa, &vpx_int_pro_col_c),
make_tuple(32, &vpx_int_pro_col_msa, &vpx_int_pro_col_c),
make_tuple(64, &vpx_int_pro_col_msa,
&vpx_int_pro_col_c)));
// TODO(jingning): Remove the highbitdepth flag once the SIMD functions are
// in place.
#if !CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(MSA, SatdTest,
::testing::Values(make_tuple(16, &vpx_satd_msa),
make_tuple(64, &vpx_satd_msa),
make_tuple(256, &vpx_satd_msa),
make_tuple(1024, &vpx_satd_msa)));
#endif // !CONFIG_VP9_HIGHBITDEPTH
#endif // HAVE_MSA
} // namespace

View File

@ -8,11 +8,10 @@
* 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.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h" #include "./vpx_config.h"
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
@ -23,12 +22,15 @@
#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 "third_party/googletest/src/include/gtest/gtest.h"
#include "vpx_mem/vpx_mem.h" #include "vpx_mem/vpx_mem.h"
extern "C" double vp9_get_blockiness(const unsigned char *img1, int img1_pitch,
const unsigned char *img2, int img2_pitch, extern "C"
int width, int height); double vp9_get_blockiness(const unsigned char *img1, int img1_pitch,
const unsigned char *img2, int img2_pitch,
int width, int height);
using libvpx_test::ACMRandom; using libvpx_test::ACMRandom;
@ -38,9 +40,9 @@ class BlockinessTestBase : public ::testing::Test {
BlockinessTestBase(int width, int height) : width_(width), height_(height) {} BlockinessTestBase(int width, int height) : width_(width), height_(height) {}
static void SetUpTestCase() { static void SetUpTestCase() {
source_data_ = reinterpret_cast<uint8_t *>( source_data_ = reinterpret_cast<uint8_t*>(
vpx_memalign(kDataAlignment, kDataBufferSize)); vpx_memalign(kDataAlignment, kDataBufferSize));
reference_data_ = reinterpret_cast<uint8_t *>( reference_data_ = reinterpret_cast<uint8_t*>(
vpx_memalign(kDataAlignment, kDataBufferSize)); vpx_memalign(kDataAlignment, kDataBufferSize));
} }
@ -51,12 +53,14 @@ class BlockinessTestBase : public ::testing::Test {
reference_data_ = NULL; reference_data_ = NULL;
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() {
libvpx_test::ClearSystemState();
}
protected: protected:
// Handle frames up to 640x480 // Handle frames up to 640x480
static const int kDataAlignment = 16; static const int kDataAlignment = 16;
static const int kDataBufferSize = 640 * 480; static const int kDataBufferSize = 640*480;
virtual void SetUp() { virtual void SetUp() {
source_stride_ = (width_ + 31) & ~31; source_stride_ = (width_ + 31) & ~31;
@ -64,8 +68,8 @@ class BlockinessTestBase : public ::testing::Test {
rnd_.Reset(ACMRandom::DeterministicSeed()); rnd_.Reset(ACMRandom::DeterministicSeed());
} }
void FillConstant(uint8_t *data, int stride, uint8_t fill_constant, int width, void FillConstant(uint8_t *data, int stride, uint8_t fill_constant,
int height) { int width, int height) {
for (int h = 0; h < height; ++h) { for (int h = 0; h < height; ++h) {
for (int w = 0; w < width; ++w) { for (int w = 0; w < width; ++w) {
data[h * stride + w] = fill_constant; data[h * stride + w] = fill_constant;
@ -100,11 +104,10 @@ class BlockinessTestBase : public ::testing::Test {
void FillCheckerboard(uint8_t *data, int stride) { void FillCheckerboard(uint8_t *data, int stride) {
for (int h = 0; h < height_; h += 4) { for (int h = 0; h < height_; h += 4) {
for (int w = 0; w < width_; w += 4) { for (int w = 0; w < width_; w += 4) {
if (((h / 4) ^ (w / 4)) & 1) { if (((h/4) ^ (w/4)) & 1)
FillConstant(data + h * stride + w, stride, 255, 4, 4); FillConstant(data + h * stride + w, stride, 255, 4, 4);
} else { else
FillConstant(data + h * stride + w, stride, 0, 4, 4); FillConstant(data + h * stride + w, stride, 0, 4, 4);
}
} }
} }
} }
@ -132,16 +135,16 @@ class BlockinessTestBase : public ::testing::Test {
} }
} }
int width_, height_; int width_, height_;
static uint8_t *source_data_; static uint8_t* source_data_;
int source_stride_; int source_stride_;
static uint8_t *reference_data_; static uint8_t* reference_data_;
int reference_stride_; int reference_stride_;
ACMRandom rnd_; ACMRandom rnd_;
}; };
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
typedef ::testing::tuple<int, int> BlockinessParam; typedef std::tr1::tuple<int, int> BlockinessParam;
class BlockinessVP9Test class BlockinessVP9Test
: public BlockinessTestBase, : public BlockinessTestBase,
public ::testing::WithParamInterface<BlockinessParam> { public ::testing::WithParamInterface<BlockinessParam> {
@ -149,32 +152,32 @@ class BlockinessVP9Test
BlockinessVP9Test() : BlockinessTestBase(GET_PARAM(0), GET_PARAM(1)) {} BlockinessVP9Test() : BlockinessTestBase(GET_PARAM(0), GET_PARAM(1)) {}
protected: protected:
double GetBlockiness() const { int CheckBlockiness() {
return vp9_get_blockiness(source_data_, source_stride_, reference_data_, return vp9_get_blockiness(source_data_, source_stride_,
reference_stride_, width_, height_); reference_data_, reference_stride_,
width_, height_);
} }
}; };
#endif // CONFIG_VP9_ENCODER #endif // CONFIG_VP9_ENCODER
uint8_t *BlockinessTestBase::source_data_ = NULL; uint8_t* BlockinessTestBase::source_data_ = NULL;
uint8_t *BlockinessTestBase::reference_data_ = NULL; uint8_t* BlockinessTestBase::reference_data_ = NULL;
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
TEST_P(BlockinessVP9Test, SourceBlockierThanReference) { TEST_P(BlockinessVP9Test, SourceBlockierThanReference) {
// Source is blockier than reference. // Source is blockier than reference.
FillRandomBlocky(source_data_, source_stride_); FillRandomBlocky(source_data_, source_stride_);
FillConstant(reference_data_, reference_stride_, 128); FillConstant(reference_data_, reference_stride_, 128);
const double super_blocky = GetBlockiness(); int super_blocky = CheckBlockiness();
EXPECT_DOUBLE_EQ(0.0, super_blocky) EXPECT_EQ(0, super_blocky) << "Blocky source should produce 0 blockiness.";
<< "Blocky source should produce 0 blockiness.";
} }
TEST_P(BlockinessVP9Test, ReferenceBlockierThanSource) { TEST_P(BlockinessVP9Test, ReferenceBlockierThanSource) {
// Source is blockier than reference. // Source is blockier than reference.
FillConstant(source_data_, source_stride_, 128); FillConstant(source_data_, source_stride_, 128);
FillRandomBlocky(reference_data_, reference_stride_); FillRandomBlocky(reference_data_, reference_stride_);
const double super_blocky = GetBlockiness(); int super_blocky = CheckBlockiness();
EXPECT_GT(super_blocky, 0.0) EXPECT_GT(super_blocky, 0.0)
<< "Blocky reference should score high for blockiness."; << "Blocky reference should score high for blockiness.";
@ -184,10 +187,10 @@ TEST_P(BlockinessVP9Test, BlurringDecreasesBlockiness) {
// Source is blockier than reference. // Source is blockier than reference.
FillConstant(source_data_, source_stride_, 128); FillConstant(source_data_, source_stride_, 128);
FillRandomBlocky(reference_data_, reference_stride_); FillRandomBlocky(reference_data_, reference_stride_);
const double super_blocky = GetBlockiness(); int super_blocky = CheckBlockiness();
Blur(reference_data_, reference_stride_, 4); Blur(reference_data_, reference_stride_, 4);
const double less_blocky = GetBlockiness(); int less_blocky = CheckBlockiness();
EXPECT_GT(super_blocky, less_blocky) EXPECT_GT(super_blocky, less_blocky)
<< "A straight blur should decrease blockiness."; << "A straight blur should decrease blockiness.";
@ -198,24 +201,27 @@ TEST_P(BlockinessVP9Test, WorstCaseBlockiness) {
FillConstant(source_data_, source_stride_, 128); FillConstant(source_data_, source_stride_, 128);
FillCheckerboard(reference_data_, reference_stride_); FillCheckerboard(reference_data_, reference_stride_);
const double super_blocky = GetBlockiness(); int super_blocky = CheckBlockiness();
Blur(reference_data_, reference_stride_, 4); Blur(reference_data_, reference_stride_, 4);
const double less_blocky = GetBlockiness(); int less_blocky = CheckBlockiness();
EXPECT_GT(super_blocky, less_blocky) EXPECT_GT(super_blocky, less_blocky)
<< "A straight blur should decrease blockiness."; << "A straight blur should decrease blockiness.";
} }
#endif // CONFIG_VP9_ENCODER #endif // CONFIG_VP9_ENCODER
using ::testing::make_tuple;
using std::tr1::make_tuple;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// C functions // C functions
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
const BlockinessParam c_vp9_tests[] = { const BlockinessParam c_vp9_tests[] = {
make_tuple(320, 240), make_tuple(318, 242), make_tuple(318, 238) make_tuple(320, 240),
make_tuple(318, 242),
make_tuple(318, 238),
}; };
INSTANTIATE_TEST_CASE_P(C, BlockinessVP9Test, ::testing::ValuesIn(c_vp9_tests)); INSTANTIATE_TEST_CASE_P(C, BlockinessVP9Test, ::testing::ValuesIn(c_vp9_tests));
#endif #endif

View File

@ -17,9 +17,8 @@
namespace { namespace {
class BordersTest class BordersTest : public ::libvpx_test::EncoderTest,
: public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected: protected:
BordersTest() : EncoderTest(GET_PARAM(0)) {} BordersTest() : EncoderTest(GET_PARAM(0)) {}
virtual ~BordersTest() {} virtual ~BordersTest() {}
@ -53,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;
@ -79,6 +78,6 @@ TEST_P(BordersTest, TestLowBitrate) {
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
VP9_INSTANTIATE_TEST_CASE(BordersTest, VP9_INSTANTIATE_TEST_CASE(BordersTest, ::testing::Values(
::testing::Values(::libvpx_test::kTwoPassGood)); ::libvpx_test::kTwoPassGood));
} // namespace } // namespace

View File

@ -1,382 +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_BUFFER_H_
#define TEST_BUFFER_H_
#include <stdio.h>
#include <limits>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/acm_random.h"
#include "vpx/vpx_integer.h"
#include "vpx_mem/vpx_mem.h"
namespace libvpx_test {
template <typename T>
class Buffer {
public:
Buffer(int width, int height, int top_padding, int left_padding,
int right_padding, int bottom_padding)
: width_(width), height_(height), top_padding_(top_padding),
left_padding_(left_padding), right_padding_(right_padding),
bottom_padding_(bottom_padding), alignment_(0), padding_value_(0),
stride_(0), raw_size_(0), num_elements_(0), raw_buffer_(NULL) {}
Buffer(int width, int height, int top_padding, int left_padding,
int right_padding, int bottom_padding, unsigned int alignment)
: width_(width), height_(height), top_padding_(top_padding),
left_padding_(left_padding), right_padding_(right_padding),
bottom_padding_(bottom_padding), alignment_(alignment),
padding_value_(0), stride_(0), raw_size_(0), num_elements_(0),
raw_buffer_(NULL) {}
Buffer(int width, int height, int padding)
: width_(width), height_(height), top_padding_(padding),
left_padding_(padding), right_padding_(padding),
bottom_padding_(padding), alignment_(0), padding_value_(0), stride_(0),
raw_size_(0), num_elements_(0), raw_buffer_(NULL) {}
Buffer(int width, int height, int padding, unsigned int alignment)
: width_(width), height_(height), top_padding_(padding),
left_padding_(padding), right_padding_(padding),
bottom_padding_(padding), alignment_(alignment), padding_value_(0),
stride_(0), raw_size_(0), num_elements_(0), raw_buffer_(NULL) {}
~Buffer() {
if (alignment_) {
vpx_free(raw_buffer_);
} else {
delete[] raw_buffer_;
}
}
T *TopLeftPixel() const;
int stride() const { return stride_; }
// Set the buffer (excluding padding) to 'value'.
void Set(const T value);
// Set the buffer (excluding padding) to the output of ACMRandom function
// 'rand_func'.
void Set(ACMRandom *rand_class, T (ACMRandom::*rand_func)());
// Set the buffer (excluding padding) to the output of ACMRandom function
// 'RandRange' with range 'low' to 'high' which typically must be within
// testing::internal::Random::kMaxRange (1u << 31). However, because we want
// to allow negative low (and high) values, it is restricted to INT32_MAX
// here.
void Set(ACMRandom *rand_class, const T low, const T high);
// Copy the contents of Buffer 'a' (excluding padding).
void CopyFrom(const Buffer<T> &a);
void DumpBuffer() const;
// Highlight the differences between two buffers if they are the same size.
void PrintDifference(const Buffer<T> &a) const;
bool HasPadding() const;
// Sets all the values in the buffer to 'padding_value'.
void SetPadding(const T padding_value);
// Checks if all the values (excluding padding) are equal to 'value' if the
// Buffers are the same size.
bool CheckValues(const T value) const;
// Check that padding matches the expected value or there is no padding.
bool CheckPadding() const;
// Compare the non-padding portion of two buffers if they are the same size.
bool CheckValues(const Buffer<T> &a) const;
bool Init() {
if (raw_buffer_ != NULL) return false;
EXPECT_GT(width_, 0);
EXPECT_GT(height_, 0);
EXPECT_GE(top_padding_, 0);
EXPECT_GE(left_padding_, 0);
EXPECT_GE(right_padding_, 0);
EXPECT_GE(bottom_padding_, 0);
stride_ = left_padding_ + width_ + right_padding_;
num_elements_ = stride_ * (top_padding_ + height_ + bottom_padding_);
raw_size_ = num_elements_ * sizeof(T);
if (alignment_) {
EXPECT_GE(alignment_, sizeof(T));
// Ensure alignment of the first value will be preserved.
EXPECT_EQ((left_padding_ * sizeof(T)) % alignment_, 0u);
// Ensure alignment of the subsequent rows will be preserved when there is
// a stride.
if (stride_ != width_) {
EXPECT_EQ((stride_ * sizeof(T)) % alignment_, 0u);
}
raw_buffer_ = reinterpret_cast<T *>(vpx_memalign(alignment_, raw_size_));
} else {
raw_buffer_ = new (std::nothrow) T[num_elements_];
}
EXPECT_TRUE(raw_buffer_ != NULL);
SetPadding(std::numeric_limits<T>::max());
return !::testing::Test::HasFailure();
}
private:
bool BufferSizesMatch(const Buffer<T> &a) const;
const int width_;
const int height_;
const int top_padding_;
const int left_padding_;
const int right_padding_;
const int bottom_padding_;
const unsigned int alignment_;
T padding_value_;
int stride_;
int raw_size_;
int num_elements_;
T *raw_buffer_;
};
template <typename T>
T *Buffer<T>::TopLeftPixel() const {
if (!raw_buffer_) return NULL;
return raw_buffer_ + (top_padding_ * stride_) + left_padding_;
}
template <typename T>
void Buffer<T>::Set(const T value) {
if (!raw_buffer_) return;
T *src = TopLeftPixel();
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < width_; ++width) {
src[width] = value;
}
src += stride_;
}
}
template <typename T>
void Buffer<T>::Set(ACMRandom *rand_class, T (ACMRandom::*rand_func)()) {
if (!raw_buffer_) return;
T *src = TopLeftPixel();
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < width_; ++width) {
src[width] = (*rand_class.*rand_func)();
}
src += stride_;
}
}
template <typename T>
void Buffer<T>::Set(ACMRandom *rand_class, const T low, const T high) {
if (!raw_buffer_) return;
EXPECT_LE(low, high);
EXPECT_LE(static_cast<int64_t>(high) - low,
std::numeric_limits<int32_t>::max());
T *src = TopLeftPixel();
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < width_; ++width) {
// 'low' will be promoted to unsigned given the return type of RandRange.
// Store the value as an int to avoid unsigned overflow warnings when
// 'low' is negative.
const int32_t value =
static_cast<int32_t>((*rand_class).RandRange(high - low));
src[width] = static_cast<T>(value + low);
}
src += stride_;
}
}
template <typename T>
void Buffer<T>::CopyFrom(const Buffer<T> &a) {
if (!raw_buffer_) return;
if (!BufferSizesMatch(a)) return;
T *a_src = a.TopLeftPixel();
T *b_src = this->TopLeftPixel();
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < width_; ++width) {
b_src[width] = a_src[width];
}
a_src += a.stride();
b_src += this->stride();
}
}
template <typename T>
void Buffer<T>::DumpBuffer() const {
if (!raw_buffer_) return;
for (int height = 0; height < height_ + top_padding_ + bottom_padding_;
++height) {
for (int width = 0; width < stride_; ++width) {
printf("%4d", raw_buffer_[height + width * stride_]);
}
printf("\n");
}
}
template <typename T>
bool Buffer<T>::HasPadding() const {
if (!raw_buffer_) return false;
return top_padding_ || left_padding_ || right_padding_ || bottom_padding_;
}
template <typename T>
void Buffer<T>::PrintDifference(const Buffer<T> &a) const {
if (!raw_buffer_) return;
if (!BufferSizesMatch(a)) return;
T *a_src = a.TopLeftPixel();
T *b_src = TopLeftPixel();
printf("This buffer:\n");
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < width_; ++width) {
if (a_src[width] != b_src[width]) {
printf("*%3d", b_src[width]);
} else {
printf("%4d", b_src[width]);
}
}
printf("\n");
a_src += a.stride();
b_src += this->stride();
}
a_src = a.TopLeftPixel();
b_src = TopLeftPixel();
printf("Reference buffer:\n");
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < width_; ++width) {
if (a_src[width] != b_src[width]) {
printf("*%3d", a_src[width]);
} else {
printf("%4d", a_src[width]);
}
}
printf("\n");
a_src += a.stride();
b_src += this->stride();
}
}
template <typename T>
void Buffer<T>::SetPadding(const T padding_value) {
if (!raw_buffer_) return;
padding_value_ = padding_value;
T *src = raw_buffer_;
for (int i = 0; i < num_elements_; ++i) {
src[i] = padding_value;
}
}
template <typename T>
bool Buffer<T>::CheckValues(const T value) const {
if (!raw_buffer_) return false;
T *src = TopLeftPixel();
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < width_; ++width) {
if (value != src[width]) {
return false;
}
}
src += stride_;
}
return true;
}
template <typename T>
bool Buffer<T>::CheckPadding() const {
if (!raw_buffer_) return false;
if (!HasPadding()) return true;
// Top padding.
T const *top = raw_buffer_;
for (int i = 0; i < stride_ * top_padding_; ++i) {
if (padding_value_ != top[i]) {
return false;
}
}
// Left padding.
T const *left = TopLeftPixel() - left_padding_;
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < left_padding_; ++width) {
if (padding_value_ != left[width]) {
return false;
}
}
left += stride_;
}
// Right padding.
T const *right = TopLeftPixel() + width_;
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < right_padding_; ++width) {
if (padding_value_ != right[width]) {
return false;
}
}
right += stride_;
}
// Bottom padding
T const *bottom = raw_buffer_ + (top_padding_ + height_) * stride_;
for (int i = 0; i < stride_ * bottom_padding_; ++i) {
if (padding_value_ != bottom[i]) {
return false;
}
}
return true;
}
template <typename T>
bool Buffer<T>::CheckValues(const Buffer<T> &a) const {
if (!raw_buffer_) return false;
if (!BufferSizesMatch(a)) return false;
T *a_src = a.TopLeftPixel();
T *b_src = this->TopLeftPixel();
for (int height = 0; height < height_; ++height) {
for (int width = 0; width < width_; ++width) {
if (a_src[width] != b_src[width]) {
return false;
}
}
a_src += a.stride();
b_src += this->stride();
}
return true;
}
template <typename T>
bool Buffer<T>::BufferSizesMatch(const Buffer<T> &a) const {
if (!raw_buffer_) return false;
if (a.width_ != this->width_ || a.height_ != this->height_) {
printf(
"Reference buffer of size %dx%d does not match this buffer which is "
"size %dx%d\n",
a.width_, a.height_, this->width_, this->height_);
return false;
}
return true;
}
} // namespace libvpx_test
#endif // TEST_BUFFER_H_

View File

@ -21,14 +21,14 @@
namespace { namespace {
#if CONFIG_WEBM_IO
const int kLegacyByteAlignment = 0; const int kLegacyByteAlignment = 0;
const int kLegacyYPlaneByteAlignment = 32; const int kLegacyYPlaneByteAlignment = 32;
const int kNumPlanesToCheck = 3; const int kNumPlanesToCheck = 3;
const char kVP9TestFile[] = "vp90-2-02-size-lf-1920x1080.webm"; const char kVP9TestFile[] = "vp90-2-02-size-lf-1920x1080.webm";
const char kVP9Md5File[] = "vp90-2-02-size-lf-1920x1080.webm.md5"; const char kVP9Md5File[] = "vp90-2-02-size-lf-1920x1080.webm.md5";
#if CONFIG_WEBM_IO
struct ByteAlignmentTestParam { struct ByteAlignmentTestParam {
int byte_alignment; int byte_alignment;
vpx_codec_err_t expected_value; vpx_codec_err_t expected_value;
@ -36,26 +36,29 @@ struct ByteAlignmentTestParam {
}; };
const ByteAlignmentTestParam kBaTestParams[] = { const ByteAlignmentTestParam kBaTestParams[] = {
{ kLegacyByteAlignment, VPX_CODEC_OK, true }, {kLegacyByteAlignment, VPX_CODEC_OK, true},
{ 32, VPX_CODEC_OK, true }, {32, VPX_CODEC_OK, true},
{ 64, VPX_CODEC_OK, true }, {64, VPX_CODEC_OK, true},
{ 128, VPX_CODEC_OK, true }, {128, VPX_CODEC_OK, true},
{ 256, VPX_CODEC_OK, true }, {256, VPX_CODEC_OK, true},
{ 512, VPX_CODEC_OK, true }, {512, VPX_CODEC_OK, true},
{ 1024, VPX_CODEC_OK, true }, {1024, VPX_CODEC_OK, true},
{ 1, VPX_CODEC_INVALID_PARAM, false }, {1, VPX_CODEC_INVALID_PARAM, false},
{ -2, VPX_CODEC_INVALID_PARAM, false }, {-2, VPX_CODEC_INVALID_PARAM, false},
{ 4, VPX_CODEC_INVALID_PARAM, false }, {4, VPX_CODEC_INVALID_PARAM, false},
{ 16, VPX_CODEC_INVALID_PARAM, false }, {16, VPX_CODEC_INVALID_PARAM, false},
{ 255, VPX_CODEC_INVALID_PARAM, false }, {255, VPX_CODEC_INVALID_PARAM, false},
{ 2048, VPX_CODEC_INVALID_PARAM, false }, {2048, VPX_CODEC_INVALID_PARAM, false},
}; };
// Class for testing byte alignment of reference buffers. // Class for testing byte alignment of reference buffers.
class ByteAlignmentTest class ByteAlignmentTest
: public ::testing::TestWithParam<ByteAlignmentTestParam> { : public ::testing::TestWithParam<ByteAlignmentTestParam> {
protected: protected:
ByteAlignmentTest() : video_(NULL), decoder_(NULL), md5_file_(NULL) {} ByteAlignmentTest()
: video_(NULL),
decoder_(NULL),
md5_file_(NULL) {}
virtual void SetUp() { virtual void SetUp() {
video_ = new libvpx_test::WebMVideoSource(kVP9TestFile); video_ = new libvpx_test::WebMVideoSource(kVP9TestFile);
@ -71,7 +74,8 @@ class ByteAlignmentTest
} }
virtual void TearDown() { virtual void TearDown() {
if (md5_file_ != NULL) fclose(md5_file_); if (md5_file_ != NULL)
fclose(md5_file_);
delete decoder_; delete decoder_;
delete video_; delete video_;
@ -85,7 +89,8 @@ class ByteAlignmentTest
const vpx_codec_err_t res = const vpx_codec_err_t res =
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size()); decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
CheckDecodedFrames(byte_alignment_to_check); CheckDecodedFrames(byte_alignment_to_check);
if (res == VPX_CODEC_OK) video_->Next(); if (res == VPX_CODEC_OK)
video_->Next();
return res; return res;
} }
@ -93,7 +98,8 @@ class ByteAlignmentTest
for (; video_->cxdata() != NULL; video_->Next()) { for (; video_->cxdata() != NULL; video_->Next()) {
const vpx_codec_err_t res = const vpx_codec_err_t res =
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size()); decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
if (res != VPX_CODEC_OK) return res; if (res != VPX_CODEC_OK)
return res;
CheckDecodedFrames(byte_alignment_to_check); CheckDecodedFrames(byte_alignment_to_check);
} }
return VPX_CODEC_OK; return VPX_CODEC_OK;
@ -128,8 +134,8 @@ class ByteAlignmentTest
// TODO(fgalligan): Move the MD5 testing code into another class. // TODO(fgalligan): Move the MD5 testing code into another class.
void OpenMd5File(const std::string &md5_file_name_) { void OpenMd5File(const std::string &md5_file_name_) {
md5_file_ = libvpx_test::OpenTestDataFile(md5_file_name_); md5_file_ = libvpx_test::OpenTestDataFile(md5_file_name_);
ASSERT_TRUE(md5_file_ != NULL) ASSERT_TRUE(md5_file_ != NULL) << "MD5 file open failed. Filename: "
<< "MD5 file open failed. Filename: " << md5_file_name_; << md5_file_name_;
} }
void CheckMd5(const vpx_image_t &img) { void CheckMd5(const vpx_image_t &img) {
@ -157,8 +163,8 @@ class ByteAlignmentTest
TEST_F(ByteAlignmentTest, SwitchByteAlignment) { TEST_F(ByteAlignmentTest, SwitchByteAlignment) {
const int num_elements = 14; const int num_elements = 14;
const int byte_alignments[] = { 0, 32, 64, 128, 256, 512, 1024, const int byte_alignments[] = { 0, 32, 64, 128, 256, 512, 1024,
0, 1024, 32, 512, 64, 256, 128 }; 0, 1024, 32, 512, 64, 256, 128 };
for (int i = 0; i < num_elements; ++i) { for (int i = 0; i < num_elements; ++i) {
SetByteAlignment(byte_alignments[i], VPX_CODEC_OK); SetByteAlignment(byte_alignments[i], VPX_CODEC_OK);
@ -171,9 +177,8 @@ TEST_F(ByteAlignmentTest, SwitchByteAlignment) {
TEST_P(ByteAlignmentTest, TestAlignment) { TEST_P(ByteAlignmentTest, TestAlignment) {
const ByteAlignmentTestParam t = GetParam(); const ByteAlignmentTestParam t = GetParam();
SetByteAlignment(t.byte_alignment, t.expected_value); SetByteAlignment(t.byte_alignment, t.expected_value);
if (t.decode_remaining) { if (t.decode_remaining)
ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames(t.byte_alignment)); ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames(t.byte_alignment));
}
} }
INSTANTIATE_TEST_CASE_P(Alignments, ByteAlignmentTest, INSTANTIATE_TEST_CASE_P(Alignments, ByteAlignmentTest,

View File

@ -11,13 +11,19 @@
#define TEST_CLEAR_SYSTEM_STATE_H_ #define TEST_CLEAR_SYSTEM_STATE_H_
#include "./vpx_config.h" #include "./vpx_config.h"
#include "vpx_ports/system_state.h" #if ARCH_X86 || ARCH_X86_64
# include "vpx_ports/x86.h"
#endif
namespace libvpx_test { namespace libvpx_test {
// Reset system to a known state. This function should be used for all non-API // Reset system to a known state. This function should be used for all non-API
// test cases. // test cases.
inline void ClearSystemState() { vpx_clear_system_state(); } inline void ClearSystemState() {
#if ARCH_X86 || ARCH_X86_64
vpx_reset_mmx_state();
#endif
}
} // namespace libvpx_test } // namespace libvpx_test
#endif // TEST_CLEAR_SYSTEM_STATE_H_ #endif // TEST_CLEAR_SYSTEM_STATE_H_

View File

@ -32,12 +32,15 @@ class CodecFactory {
virtual ~CodecFactory() {} virtual ~CodecFactory() {}
virtual Decoder *CreateDecoder(vpx_codec_dec_cfg_t cfg) const = 0; virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
unsigned long deadline) const = 0;
virtual Decoder *CreateDecoder(vpx_codec_dec_cfg_t cfg, virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
const vpx_codec_flags_t flags) const = 0; 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,
TwopassStatsStore *stats) const = 0; TwopassStatsStore *stats) const = 0;
@ -50,25 +53,20 @@ class CodecFactory {
* to avoid having to include a pointer to the CodecFactory in every test * to avoid having to include a pointer to the CodecFactory in every test
* definition. * definition.
*/ */
template <class T1> template<class T1>
class CodecTestWithParam class CodecTestWithParam : public ::testing::TestWithParam<
: public ::testing::TestWithParam< std::tr1::tuple< const libvpx_test::CodecFactory*, T1 > > {
::testing::tuple<const libvpx_test::CodecFactory *, T1> > {}; };
template <class T1, class T2> template<class T1, class T2>
class CodecTestWith2Params class CodecTestWith2Params : public ::testing::TestWithParam<
: public ::testing::TestWithParam< std::tr1::tuple< const libvpx_test::CodecFactory*, T1, T2 > > {
::testing::tuple<const libvpx_test::CodecFactory *, T1, T2> > {}; };
template <class T1, class T2, class T3> template<class T1, class T2, class T3>
class CodecTestWith3Params class CodecTestWith3Params : public ::testing::TestWithParam<
: public ::testing::TestWithParam< std::tr1::tuple< const libvpx_test::CodecFactory*, T1, T2, T3 > > {
::testing::tuple<const libvpx_test::CodecFactory *, T1, T2, T3> > {}; };
template <class T1, class T2, class T3, class T4>
class CodecTestWith4Params
: public ::testing::TestWithParam< ::testing::tuple<
const libvpx_test::CodecFactory *, T1, T2, T3, T4> > {};
/* /*
* VP8 Codec Definitions * VP8 Codec Definitions
@ -76,13 +74,15 @@ class CodecTestWith4Params
#if CONFIG_VP8 #if CONFIG_VP8
class VP8Decoder : public Decoder { class VP8Decoder : public Decoder {
public: public:
explicit VP8Decoder(vpx_codec_dec_cfg_t cfg) : Decoder(cfg) {} VP8Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline)
: Decoder(cfg, deadline) {}
VP8Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag) VP8Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag,
: Decoder(cfg, 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_VP8_DECODER #if CONFIG_VP8_DECODER
return &vpx_codec_vp8_dx_algo; return &vpx_codec_vp8_dx_algo;
#else #else
@ -98,7 +98,7 @@ class VP8Encoder : public Encoder {
: 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_VP8_ENCODER #if CONFIG_VP8_ENCODER
return &vpx_codec_vp8_cx_algo; return &vpx_codec_vp8_cx_algo;
#else #else
@ -111,32 +111,28 @@ class VP8CodecFactory : public CodecFactory {
public: public:
VP8CodecFactory() : CodecFactory() {} VP8CodecFactory() : CodecFactory() {}
virtual Decoder *CreateDecoder(vpx_codec_dec_cfg_t cfg) const { virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
return CreateDecoder(cfg, 0); unsigned long deadline) const {
return CreateDecoder(cfg, 0, deadline);
} }
virtual Decoder *CreateDecoder(vpx_codec_dec_cfg_t cfg, virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
const vpx_codec_flags_t flags) const { const vpx_codec_flags_t flags,
unsigned long deadline) const { // NOLINT
#if CONFIG_VP8_DECODER #if CONFIG_VP8_DECODER
return new VP8Decoder(cfg, flags); return new VP8Decoder(cfg, flags, deadline);
#else #else
(void)cfg;
(void)flags;
return NULL; return NULL;
#endif #endif
} }
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,
TwopassStatsStore *stats) const { TwopassStatsStore *stats) const {
#if CONFIG_VP8_ENCODER #if CONFIG_VP8_ENCODER
return new VP8Encoder(cfg, deadline, init_flags, stats); return new VP8Encoder(cfg, deadline, init_flags, stats);
#else #else
(void)cfg;
(void)deadline;
(void)init_flags;
(void)stats;
return NULL; return NULL;
#endif #endif
} }
@ -146,8 +142,6 @@ class VP8CodecFactory : public CodecFactory {
#if CONFIG_VP8_ENCODER #if CONFIG_VP8_ENCODER
return vpx_codec_enc_config_default(&vpx_codec_vp8_cx_algo, cfg, usage); return vpx_codec_enc_config_default(&vpx_codec_vp8_cx_algo, cfg, usage);
#else #else
(void)cfg;
(void)usage;
return VPX_CODEC_INCAPABLE; return VPX_CODEC_INCAPABLE;
#endif #endif
} }
@ -155,30 +149,32 @@ class VP8CodecFactory : public CodecFactory {
const libvpx_test::VP8CodecFactory kVP8; const libvpx_test::VP8CodecFactory kVP8;
#define VP8_INSTANTIATE_TEST_CASE(test, ...) \ #define VP8_INSTANTIATE_TEST_CASE(test, ...)\
INSTANTIATE_TEST_CASE_P( \ INSTANTIATE_TEST_CASE_P(VP8, test, \
VP8, test, \ ::testing::Combine( \
::testing::Combine( \ ::testing::Values(static_cast<const libvpx_test::CodecFactory*>( \
::testing::Values(static_cast<const libvpx_test::CodecFactory *>( \ &libvpx_test::kVP8)), \
&libvpx_test::kVP8)), \
__VA_ARGS__)) __VA_ARGS__))
#else #else
#define VP8_INSTANTIATE_TEST_CASE(test, ...) #define VP8_INSTANTIATE_TEST_CASE(test, ...)
#endif // CONFIG_VP8 #endif // CONFIG_VP8
/* /*
* VP9 Codec Definitions * VP9 Codec Definitions
*/ */
#if CONFIG_VP9 #if CONFIG_VP9
class VP9Decoder : public Decoder { class VP9Decoder : public Decoder {
public: public:
explicit VP9Decoder(vpx_codec_dec_cfg_t cfg) : Decoder(cfg) {} VP9Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline)
: Decoder(cfg, deadline) {}
VP9Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag) VP9Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag,
: Decoder(cfg, 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_VP9_DECODER #if CONFIG_VP9_DECODER
return &vpx_codec_vp9_dx_algo; return &vpx_codec_vp9_dx_algo;
#else #else
@ -194,7 +190,7 @@ class VP9Encoder : public Encoder {
: 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_VP9_ENCODER #if CONFIG_VP9_ENCODER
return &vpx_codec_vp9_cx_algo; return &vpx_codec_vp9_cx_algo;
#else #else
@ -207,32 +203,28 @@ class VP9CodecFactory : public CodecFactory {
public: public:
VP9CodecFactory() : CodecFactory() {} VP9CodecFactory() : CodecFactory() {}
virtual Decoder *CreateDecoder(vpx_codec_dec_cfg_t cfg) const { virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
return CreateDecoder(cfg, 0); unsigned long deadline) const {
return CreateDecoder(cfg, 0, deadline);
} }
virtual Decoder *CreateDecoder(vpx_codec_dec_cfg_t cfg, virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg,
const vpx_codec_flags_t flags) const { const vpx_codec_flags_t flags,
unsigned long deadline) const { // NOLINT
#if CONFIG_VP9_DECODER #if CONFIG_VP9_DECODER
return new VP9Decoder(cfg, flags); return new VP9Decoder(cfg, flags, deadline);
#else #else
(void)cfg;
(void)flags;
return NULL; return NULL;
#endif #endif
} }
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,
TwopassStatsStore *stats) const { TwopassStatsStore *stats) const {
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
return new VP9Encoder(cfg, deadline, init_flags, stats); return new VP9Encoder(cfg, deadline, init_flags, stats);
#else #else
(void)cfg;
(void)deadline;
(void)init_flags;
(void)stats;
return NULL; return NULL;
#endif #endif
} }
@ -242,8 +234,6 @@ class VP9CodecFactory : public CodecFactory {
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
return vpx_codec_enc_config_default(&vpx_codec_vp9_cx_algo, cfg, usage); return vpx_codec_enc_config_default(&vpx_codec_vp9_cx_algo, cfg, usage);
#else #else
(void)cfg;
(void)usage;
return VPX_CODEC_INCAPABLE; return VPX_CODEC_INCAPABLE;
#endif #endif
} }
@ -251,16 +241,17 @@ class VP9CodecFactory : public CodecFactory {
const libvpx_test::VP9CodecFactory kVP9; const libvpx_test::VP9CodecFactory kVP9;
#define VP9_INSTANTIATE_TEST_CASE(test, ...) \ #define VP9_INSTANTIATE_TEST_CASE(test, ...)\
INSTANTIATE_TEST_CASE_P( \ INSTANTIATE_TEST_CASE_P(VP9, test, \
VP9, test, \ ::testing::Combine( \
::testing::Combine( \ ::testing::Values(static_cast<const libvpx_test::CodecFactory*>( \
::testing::Values(static_cast<const libvpx_test::CodecFactory *>( \ &libvpx_test::kVP9)), \
&libvpx_test::kVP9)), \
__VA_ARGS__)) __VA_ARGS__))
#else #else
#define VP9_INSTANTIATE_TEST_CASE(test, ...) #define VP9_INSTANTIATE_TEST_CASE(test, ...)
#endif // CONFIG_VP9 #endif // CONFIG_VP9
} // namespace libvpx_test } // namespace libvpx_test
#endif // TEST_CODEC_FACTORY_H_ #endif // TEST_CODEC_FACTORY_H_

View File

@ -1,182 +0,0 @@
/*
* Copyright (c) 2017 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_dsp_rtcd.h"
#include "test/acm_random.h"
#include "test/buffer.h"
#include "test/register_state_check.h"
#include "vpx_ports/vpx_timer.h"
namespace {
using ::libvpx_test::ACMRandom;
using ::libvpx_test::Buffer;
typedef void (*AvgPredFunc)(uint8_t *a, const uint8_t *b, int w, int h,
const uint8_t *c, int c_stride);
uint8_t avg_with_rounding(uint8_t a, uint8_t b) { return (a + b + 1) >> 1; }
void reference_pred(const Buffer<uint8_t> &pred, const Buffer<uint8_t> &ref,
int width, int height, Buffer<uint8_t> *avg) {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
avg->TopLeftPixel()[y * avg->stride() + x] =
avg_with_rounding(pred.TopLeftPixel()[y * pred.stride() + x],
ref.TopLeftPixel()[y * ref.stride() + x]);
}
}
}
class AvgPredTest : public ::testing::TestWithParam<AvgPredFunc> {
public:
virtual void SetUp() {
avg_pred_func_ = GetParam();
rnd_.Reset(ACMRandom::DeterministicSeed());
}
protected:
AvgPredFunc avg_pred_func_;
ACMRandom rnd_;
};
TEST_P(AvgPredTest, SizeCombinations) {
// This is called as part of the sub pixel variance. As such it must be one of
// the variance block sizes.
for (int width_pow = 2; width_pow <= 6; ++width_pow) {
for (int height_pow = width_pow - 1; height_pow <= width_pow + 1;
++height_pow) {
// Don't test 4x2 or 64x128
if (height_pow == 1 || height_pow == 7) continue;
// The sse2 special-cases when ref width == stride, so make sure to test
// it.
for (int ref_padding = 0; ref_padding < 2; ref_padding++) {
const int width = 1 << width_pow;
const int height = 1 << height_pow;
// Only the reference buffer may have a stride not equal to width.
Buffer<uint8_t> ref =
Buffer<uint8_t>(width, height, ref_padding ? 8 : 0);
ASSERT_TRUE(ref.Init());
Buffer<uint8_t> pred = Buffer<uint8_t>(width, height, 0, 16);
ASSERT_TRUE(pred.Init());
Buffer<uint8_t> avg_ref = Buffer<uint8_t>(width, height, 0, 16);
ASSERT_TRUE(avg_ref.Init());
Buffer<uint8_t> avg_chk = Buffer<uint8_t>(width, height, 0, 16);
ASSERT_TRUE(avg_chk.Init());
ref.Set(&rnd_, &ACMRandom::Rand8);
pred.Set(&rnd_, &ACMRandom::Rand8);
reference_pred(pred, ref, width, height, &avg_ref);
ASM_REGISTER_STATE_CHECK(
avg_pred_func_(avg_chk.TopLeftPixel(), pred.TopLeftPixel(), width,
height, ref.TopLeftPixel(), ref.stride()));
EXPECT_TRUE(avg_chk.CheckValues(avg_ref));
if (HasFailure()) {
printf("Width: %d Height: %d\n", width, height);
avg_chk.PrintDifference(avg_ref);
return;
}
}
}
}
}
TEST_P(AvgPredTest, CompareReferenceRandom) {
const int width = 64;
const int height = 32;
Buffer<uint8_t> ref = Buffer<uint8_t>(width, height, 8);
ASSERT_TRUE(ref.Init());
Buffer<uint8_t> pred = Buffer<uint8_t>(width, height, 0, 16);
ASSERT_TRUE(pred.Init());
Buffer<uint8_t> avg_ref = Buffer<uint8_t>(width, height, 0, 16);
ASSERT_TRUE(avg_ref.Init());
Buffer<uint8_t> avg_chk = Buffer<uint8_t>(width, height, 0, 16);
ASSERT_TRUE(avg_chk.Init());
for (int i = 0; i < 500; ++i) {
ref.Set(&rnd_, &ACMRandom::Rand8);
pred.Set(&rnd_, &ACMRandom::Rand8);
reference_pred(pred, ref, width, height, &avg_ref);
ASM_REGISTER_STATE_CHECK(avg_pred_func_(avg_chk.TopLeftPixel(),
pred.TopLeftPixel(), width, height,
ref.TopLeftPixel(), ref.stride()));
EXPECT_TRUE(avg_chk.CheckValues(avg_ref));
if (HasFailure()) {
printf("Width: %d Height: %d\n", width, height);
avg_chk.PrintDifference(avg_ref);
return;
}
}
}
TEST_P(AvgPredTest, DISABLED_Speed) {
for (int width_pow = 2; width_pow <= 6; ++width_pow) {
for (int height_pow = width_pow - 1; height_pow <= width_pow + 1;
++height_pow) {
// Don't test 4x2 or 64x128
if (height_pow == 1 || height_pow == 7) continue;
for (int ref_padding = 0; ref_padding < 2; ref_padding++) {
const int width = 1 << width_pow;
const int height = 1 << height_pow;
Buffer<uint8_t> ref =
Buffer<uint8_t>(width, height, ref_padding ? 8 : 0);
ASSERT_TRUE(ref.Init());
Buffer<uint8_t> pred = Buffer<uint8_t>(width, height, 0, 16);
ASSERT_TRUE(pred.Init());
Buffer<uint8_t> avg = Buffer<uint8_t>(width, height, 0, 16);
ASSERT_TRUE(avg.Init());
ref.Set(&rnd_, &ACMRandom::Rand8);
pred.Set(&rnd_, &ACMRandom::Rand8);
vpx_usec_timer timer;
vpx_usec_timer_start(&timer);
for (int i = 0; i < 10000000 / (width * height); ++i) {
avg_pred_func_(avg.TopLeftPixel(), pred.TopLeftPixel(), width, height,
ref.TopLeftPixel(), ref.stride());
}
vpx_usec_timer_mark(&timer);
const int elapsed_time =
static_cast<int>(vpx_usec_timer_elapsed(&timer));
printf("Average Test (ref_padding: %d) %dx%d time: %5d us\n",
ref_padding, width, height, elapsed_time);
}
}
}
}
INSTANTIATE_TEST_CASE_P(C, AvgPredTest,
::testing::Values(&vpx_comp_avg_pred_c));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(SSE2, AvgPredTest,
::testing::Values(&vpx_comp_avg_pred_sse2));
#endif // HAVE_SSE2
#if HAVE_NEON
INSTANTIATE_TEST_CASE_P(NEON, AvgPredTest,
::testing::Values(&vpx_comp_avg_pred_neon));
#endif // HAVE_NEON
#if HAVE_VSX
INSTANTIATE_TEST_CASE_P(VSX, AvgPredTest,
::testing::Values(&vpx_comp_avg_pred_vsx));
#endif // HAVE_VSX
} // namespace

View File

@ -15,13 +15,11 @@
namespace { namespace {
class ConfigTest class ConfigTest : public ::libvpx_test::EncoderTest,
: public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected: protected:
ConfigTest() ConfigTest() : EncoderTest(GET_PARAM(0)),
: EncoderTest(GET_PARAM(0)), frame_count_in_(0), frame_count_out_(0), frame_count_in_(0), frame_count_out_(0), frame_count_max_(0) {}
frame_count_max_(0) {}
virtual ~ConfigTest() {} virtual ~ConfigTest() {}
virtual void SetUp() { virtual void SetUp() {
@ -34,12 +32,12 @@ class ConfigTest
frame_count_out_ = 0; frame_count_out_ = 0;
} }
virtual void PreEncodeFrameHook(libvpx_test::VideoSource * /*video*/) { virtual void PreEncodeFrameHook(libvpx_test::VideoSource* /*video*/) {
++frame_count_in_; ++frame_count_in_;
abort_ |= (frame_count_in_ >= frame_count_max_); abort_ |= (frame_count_in_ >= frame_count_max_);
} }
virtual void FramePktHook(const vpx_codec_cx_pkt_t * /*pkt*/) { virtual void FramePktHook(const vpx_codec_cx_pkt_t* /*pkt*/) {
++frame_count_out_; ++frame_count_out_;
} }

View File

@ -8,11 +8,10 @@
* 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.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h" #include "./vpx_config.h"
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
@ -23,13 +22,16 @@
#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 "vpx_dsp/ssim.h" #include "third_party/googletest/src/include/gtest/gtest.h"
#include "vp9/encoder/vp9_ssim.h"
#include "vpx_mem/vpx_mem.h" #include "vpx_mem/vpx_mem.h"
extern "C" double vpx_get_ssim_metrics(uint8_t *img1, int img1_pitch, extern "C"
uint8_t *img2, int img2_pitch, int width, double vp9_get_ssim_metrics(uint8_t *img1, int img1_pitch,
int height, Ssimv *sv2, Metrics *m, uint8_t *img2, int img2_pitch,
int do_inconsistency); int width, int height,
Ssimv *sv2, Metrics *m,
int do_inconsistency);
using libvpx_test::ACMRandom; using libvpx_test::ACMRandom;
@ -39,18 +41,20 @@ class ConsistencyTestBase : public ::testing::Test {
ConsistencyTestBase(int width, int height) : width_(width), height_(height) {} ConsistencyTestBase(int width, int height) : width_(width), height_(height) {}
static void SetUpTestCase() { static void SetUpTestCase() {
source_data_[0] = reinterpret_cast<uint8_t *>( source_data_[0] = reinterpret_cast<uint8_t*>(
vpx_memalign(kDataAlignment, kDataBufferSize)); vpx_memalign(kDataAlignment, kDataBufferSize));
reference_data_[0] = reinterpret_cast<uint8_t *>( reference_data_[0] = reinterpret_cast<uint8_t*>(
vpx_memalign(kDataAlignment, kDataBufferSize)); vpx_memalign(kDataAlignment, kDataBufferSize));
source_data_[1] = reinterpret_cast<uint8_t *>( source_data_[1] = reinterpret_cast<uint8_t*>(
vpx_memalign(kDataAlignment, kDataBufferSize)); vpx_memalign(kDataAlignment, kDataBufferSize));
reference_data_[1] = reinterpret_cast<uint8_t *>( reference_data_[1] = reinterpret_cast<uint8_t*>(
vpx_memalign(kDataAlignment, kDataBufferSize)); vpx_memalign(kDataAlignment, kDataBufferSize));
ssim_array_ = new Ssimv[kDataBufferSize / 16]; ssim_array_ = new Ssimv[kDataBufferSize / 16];
} }
static void ClearSsim() { memset(ssim_array_, 0, kDataBufferSize / 16); } static void ClearSsim() {
memset(ssim_array_, 0, kDataBufferSize / 16);
}
static void TearDownTestCase() { static void TearDownTestCase() {
vpx_free(source_data_[0]); vpx_free(source_data_[0]);
source_data_[0] = NULL; source_data_[0] = NULL;
@ -61,15 +65,17 @@ class ConsistencyTestBase : public ::testing::Test {
vpx_free(reference_data_[1]); vpx_free(reference_data_[1]);
reference_data_[1] = NULL; reference_data_[1] = NULL;
delete[] ssim_array_; delete ssim_array_;
} }
virtual void TearDown() { libvpx_test::ClearSystemState(); } virtual void TearDown() {
libvpx_test::ClearSystemState();
}
protected: protected:
// Handle frames up to 640x480 // Handle frames up to 640x480
static const int kDataAlignment = 16; static const int kDataAlignment = 16;
static const int kDataBufferSize = 640 * 480; static const int kDataBufferSize = 640*480;
virtual void SetUp() { virtual void SetUp() {
source_stride_ = (width_ + 31) & ~31; source_stride_ = (width_ + 31) & ~31;
@ -116,9 +122,9 @@ class ConsistencyTestBase : public ::testing::Test {
} }
} }
int width_, height_; int width_, height_;
static uint8_t *source_data_[2]; static uint8_t* source_data_[2];
int source_stride_; int source_stride_;
static uint8_t *reference_data_[2]; static uint8_t* reference_data_[2];
int reference_stride_; int reference_stride_;
static Ssimv *ssim_array_; static Ssimv *ssim_array_;
Metrics metrics_; Metrics metrics_;
@ -127,7 +133,7 @@ class ConsistencyTestBase : public ::testing::Test {
}; };
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
typedef ::testing::tuple<int, int> ConsistencyParam; typedef std::tr1::tuple<int, int> ConsistencyParam;
class ConsistencyVP9Test class ConsistencyVP9Test
: public ConsistencyTestBase, : public ConsistencyTestBase,
public ::testing::WithParamInterface<ConsistencyParam> { public ::testing::WithParamInterface<ConsistencyParam> {
@ -136,17 +142,18 @@ class ConsistencyVP9Test
protected: protected:
double CheckConsistency(int frame) { double CheckConsistency(int frame) {
EXPECT_LT(frame, 2) << "Frame to check has to be less than 2."; EXPECT_LT(frame, 2)<< "Frame to check has to be less than 2.";
return vpx_get_ssim_metrics(source_data_[frame], source_stride_, return
reference_data_[frame], reference_stride_, vp9_get_ssim_metrics(source_data_[frame], source_stride_,
width_, height_, ssim_array_, &metrics_, 1); reference_data_[frame], reference_stride_,
width_, height_, ssim_array_, &metrics_, 1);
} }
}; };
#endif // CONFIG_VP9_ENCODER #endif // CONFIG_VP9_ENCODER
uint8_t *ConsistencyTestBase::source_data_[2] = { NULL, NULL }; uint8_t* ConsistencyTestBase::source_data_[2] = {NULL, NULL};
uint8_t *ConsistencyTestBase::reference_data_[2] = { NULL, NULL }; uint8_t* ConsistencyTestBase::reference_data_[2] = {NULL, NULL};
Ssimv *ConsistencyTestBase::ssim_array_ = NULL; Ssimv* ConsistencyTestBase::ssim_array_ = NULL;
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
TEST_P(ConsistencyVP9Test, ConsistencyIsZero) { TEST_P(ConsistencyVP9Test, ConsistencyIsZero) {
@ -198,14 +205,17 @@ TEST_P(ConsistencyVP9Test, ConsistencyIsZero) {
} }
#endif // CONFIG_VP9_ENCODER #endif // CONFIG_VP9_ENCODER
using ::testing::make_tuple;
using std::tr1::make_tuple;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// C functions // C functions
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
const ConsistencyParam c_vp9_tests[] = { const ConsistencyParam c_vp9_tests[] = {
make_tuple(320, 240), make_tuple(318, 242), make_tuple(318, 238) make_tuple(320, 240),
make_tuple(318, 242),
make_tuple(318, 238),
}; };
INSTANTIATE_TEST_CASE_P(C, ConsistencyVP9Test, INSTANTIATE_TEST_CASE_P(C, ConsistencyVP9Test,
::testing::ValuesIn(c_vp9_tests)); ::testing::ValuesIn(c_vp9_tests));

File diff suppressed because it is too large Load Diff

View File

@ -23,9 +23,10 @@ class CpuSpeedTest
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> { public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
protected: protected:
CpuSpeedTest() CpuSpeedTest()
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)), : EncoderTest(GET_PARAM(0)),
set_cpu_used_(GET_PARAM(2)), min_psnr_(kMaxPSNR), encoding_mode_(GET_PARAM(1)),
tune_content_(VP9E_CONTENT_DEFAULT) {} set_cpu_used_(GET_PARAM(2)),
min_psnr_(kMaxPSNR) {}
virtual ~CpuSpeedTest() {} virtual ~CpuSpeedTest() {}
virtual void SetUp() { virtual void SetUp() {
@ -40,13 +41,14 @@ class CpuSpeedTest
} }
} }
virtual void BeginPassHook(unsigned int /*pass*/) { min_psnr_ = kMaxPSNR; } 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) { 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);
@ -57,13 +59,13 @@ class CpuSpeedTest
} }
virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) { 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]; if (pkt->data.psnr.psnr[0] < min_psnr_)
min_psnr_ = pkt->data.psnr.psnr[0];
} }
::libvpx_test::TestMode encoding_mode_; ::libvpx_test::TestMode encoding_mode_;
int set_cpu_used_; int set_cpu_used_;
double min_psnr_; double min_psnr_;
int tune_content_;
}; };
TEST_P(CpuSpeedTest, TestQ0) { TEST_P(CpuSpeedTest, TestQ0) {
@ -72,7 +74,7 @@ TEST_P(CpuSpeedTest, TestQ0) {
// 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_.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;
@ -90,7 +92,7 @@ TEST_P(CpuSpeedTest, TestScreencastQ0) {
::libvpx_test::Y4mVideoSource video("screendata.y4m", 0, 25); ::libvpx_test::Y4mVideoSource video("screendata.y4m", 0, 25);
cfg_.g_timebase = video.timebase(); cfg_.g_timebase = video.timebase();
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;
@ -101,28 +103,13 @@ TEST_P(CpuSpeedTest, TestScreencastQ0) {
EXPECT_GE(min_psnr_, kMaxPSNR); EXPECT_GE(min_psnr_, kMaxPSNR);
} }
TEST_P(CpuSpeedTest, TestTuneScreen) {
::libvpx_test::Y4mVideoSource video("screendata.y4m", 0, 25);
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_ = VP9E_CONTENT_SCREEN;
init_flags_ = VPX_CODEC_USE_PSNR;
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_.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;
@ -138,7 +125,7 @@ TEST_P(CpuSpeedTest, TestLowBitrate) {
// 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_.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;
@ -148,9 +135,9 @@ TEST_P(CpuSpeedTest, TestLowBitrate) {
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
} }
VP9_INSTANTIATE_TEST_CASE(CpuSpeedTest, VP9_INSTANTIATE_TEST_CASE(
::testing::Values(::libvpx_test::kTwoPassGood, CpuSpeedTest,
::libvpx_test::kOnePassGood, ::testing::Values(::libvpx_test::kTwoPassGood, ::libvpx_test::kOnePassGood,
::libvpx_test::kRealTime), ::libvpx_test::kRealTime),
::testing::Range(0, 9)); ::testing::Range(0, 9));
} // namespace } // namespace

View File

@ -24,12 +24,14 @@ const int kCQLevelStep = 8;
const unsigned int kCQTargetBitrate = 2000; const unsigned int kCQTargetBitrate = 2000;
class CQTest : public ::libvpx_test::EncoderTest, class CQTest : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<int> { public ::libvpx_test::CodecTestWithParam<int> {
public: public:
// maps the cqlevel to the bitrate produced. // maps the cqlevel to the bitrate produced.
typedef std::map<int, uint32_t> BitrateMap; typedef std::map<int, uint32_t> BitrateMap;
static void SetUpTestCase() { bitrates_.clear(); } static void SetUpTestCase() {
bitrates_.clear();
}
static void TearDownTestCase() { static void TearDownTestCase() {
ASSERT_TRUE(!HasFailure()) ASSERT_TRUE(!HasFailure())
@ -126,6 +128,7 @@ TEST_P(CQTest, LinearPSNRIsHigherForCQLevel) {
EXPECT_GE(cq_psnr_lin, vbr_psnr_lin); EXPECT_GE(cq_psnr_lin, vbr_psnr_lin);
} }
VP8_INSTANTIATE_TEST_CASE(CQTest, ::testing::Range(kCQLevelMin, kCQLevelMax, VP8_INSTANTIATE_TEST_CASE(CQTest,
kCQLevelStep)); ::testing::Range(kCQLevelMin, kCQLevelMax,
kCQLevelStep));
} // namespace } // namespace

745
test/datarate_test.cc Normal file
View File

@ -0,0 +1,745 @@
/*
* 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 "./vpx_config.h"
#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"
#include "test/y4m_video_source.h"
namespace {
class DatarateTestLarge : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
public:
DatarateTestLarge() : EncoderTest(GET_PARAM(0)) {}
virtual ~DatarateTestLarge() {}
protected:
virtual void SetUp() {
InitializeConfig();
SetMode(GET_PARAM(1));
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;
denoiser_offon_test_ = 0;
denoiser_offon_period_ = -1;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::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();
timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0;
}
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_;
// TODO(jimbankoski): Remove these lines when the issue:
// http://code.google.com/p/webm/issues/detail?id=496 is fixed.
// For now the codec assumes buffer starts at starting buffer rate
// plus one frame's time.
if (last_pts_ == 0)
duration = 1;
// Add to the buffer the bits we'd expect from a constant bitrate server.
bits_in_buffer_model_ += static_cast<int64_t>(
duration * timebase_ * cfg_.rc_target_bitrate * 1000);
/* Test the buffer model here before subtracting the frame. Do so because
* the way the leaky bucket model works in libvpx is to allow the buffer to
* empty - and then stop showing frames until we've got enough bits to
* show one. As noted in comment below (issue 495), this does not currently
* apply to key frames. For now exclude key frames in condition below. */
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;
// Subtract from the buffer the bits associated with a played back frame.
bits_in_buffer_model_ -= frame_size_in_bits;
// Update the running total of bits for end of test datarate checks.
bits_total_ += frame_size_in_bits;
// If first drop not set and we have a drop set it to this time.
if (!first_drop_ && duration > 1)
first_drop_ = last_pts_ + 1;
// Update the most recent pts.
last_pts_ = pkt->data.frame.pts;
// We update this so that we can calculate the datarate minus the last
// frame encoded in the file.
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_;
// Effective file datarate includes the time spent prebuffering.
effective_datarate_ = (bits_total_ - bits_in_last_frame_) / 1000.0
/ (cfg_.rc_buf_initial_sz / 1000.0 + duration_);
file_datarate_ = file_size_in_kb / duration_;
}
}
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_;
double effective_datarate_;
size_t bits_in_last_frame_;
int denoiser_on_;
int denoiser_offon_test_;
int denoiser_offon_period_;
};
#if CONFIG_TEMPORAL_DENOISING
// Check basic datarate targeting, for a single bitrate, but loop over the
// various denoiser settings.
TEST_P(DatarateTestLarge, DenoiserLevels) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_CBR;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
for (int j = 1; j < 5; ++j) {
// Run over the denoiser levels.
// For the temporal denoiser (#if CONFIG_TEMPORAL_DENOISING) the level j
// refers to the 4 denoiser modes: denoiserYonly, denoiserOnYUV,
// denoiserOnAggressive, and denoiserOnAdaptive.
// For the spatial denoiser (if !CONFIG_TEMPORAL_DENOISING), the level j
// refers to the blur thresholds: 20, 40, 60 80.
// The j = 0 case (denoiser off) is covered in the tests below.
denoiser_on_ = j;
cfg_.rc_target_bitrate = 300;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95)
<< " The datarate for the file exceeds the target!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.3)
<< " The datarate for the file missed the target!";
}
}
// Check basic datarate targeting, for a single bitrate, when denoiser is off
// and on.
TEST_P(DatarateTestLarge, DenoiserOffOn) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_CBR;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 299);
cfg_.rc_target_bitrate = 300;
ResetModel();
// The denoiser is off by default.
denoiser_on_ = 0;
// Set the offon test flag.
denoiser_offon_test_ = 1;
denoiser_offon_period_ = 100;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95)
<< " The datarate for the file exceeds the target!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.3)
<< " The datarate for the file missed the target!";
}
#endif // CONFIG_TEMPORAL_DENOISING
TEST_P(DatarateTestLarge, BasicBufferModel) {
denoiser_on_ = 0;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_CBR;
// 2 pass cbr datarate control has a bug hidden by the small # of
// frames selected in this encode. The problem is that even if the buffer is
// negative we produce a keyframe on a cutscene. Ignoring datarate
// constraints
// TODO(jimbankoski): ( Fix when issue
// http://code.google.com/p/webm/issues/detail?id=495 is addressed. )
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
// There is an issue for low bitrates in real-time mode, where the
// effective_datarate slightly overshoots the target bitrate.
// This is same the issue as noted about (#495).
// TODO(jimbankoski/marpan): Update test to run for lower bitrates (< 100),
// when the issue is resolved.
for (int i = 100; i < 800; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95)
<< " The datarate for the file exceeds the target!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.3)
<< " The datarate for the file missed the target!";
}
}
TEST_P(DatarateTestLarge, ChangingDropFrameThresh) {
denoiser_on_ = 0;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_max_quantizer = 36;
cfg_.rc_end_usage = VPX_CBR;
cfg_.rc_target_bitrate = 200;
cfg_.kf_mode = VPX_KF_DISABLED;
const int frame_count = 40;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, frame_count);
// Here we check that the first dropped frame gets earlier and earlier
// as the drop frame threshold is increased.
const int kDropFrameThreshTestStep = 30;
vpx_codec_pts_t last_drop = frame_count;
for (int i = 1; i < 91; i += kDropFrameThreshTestStep) {
cfg_.rc_dropframe_thresh = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_LE(first_drop_, last_drop)
<< " The first dropped frame for drop_thresh " << i
<< " > first dropped frame for drop_thresh "
<< i - kDropFrameThreshTestStep;
last_drop = first_drop_;
}
}
class DatarateTestVP9Large : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
public:
DatarateTestVP9Large() : EncoderTest(GET_PARAM(0)) {}
protected:
virtual ~DatarateTestVP9Large() {}
virtual void SetUp() {
InitializeConfig();
SetMode(GET_PARAM(1));
set_cpu_used_ = 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;
tot_frame_number_ = 0;
first_drop_ = 0;
num_drops_ = 0;
// Denoiser is off by default.
denoiser_on_ = 0;
// For testing up to 3 layers.
for (int i = 0; i < 3; ++i) {
bits_total_[i] = 0;
}
denoiser_offon_test_ = 0;
denoiser_offon_period_ = -1;
}
//
// 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.
// For this 3 layer example, the 2nd enhancement layer (layer 2) does not
// update any reference frames.
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 and ARF; update L.
frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_REF_GF;
} else if ((frame_num - 2) % 4 == 0) {
// Layer 1: predict from L, G, ARF; update G.
frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
} else if ((frame_num - 1) % 2 == 0) {
// Layer 2: predict from L, G, ARF; update none.
frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
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 (video->frame() == 0)
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 (video->frame() == 0) {
encoder->Control(VP9E_SET_SVC, 1);
}
vpx_svc_layer_id_t layer_id;
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
layer_id.spatial_layer_id = 0;
#endif
frame_flags_ = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
layer_id.temporal_layer_id = SetLayerId(video->frame(),
cfg_.ts_number_layers);
encoder->Control(VP9E_SET_SVC_LAYER_ID, &layer_id);
}
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) {
// Time since last timestamp = duration.
vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
if (duration > 1) {
// If first drop not set and we have a drop set it to this time.
if (!first_drop_)
first_drop_ = last_pts_ + 1;
// Update the number of frame drops.
num_drops_ += static_cast<int>(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);
// Add to the buffer the bits we'd expect from a constant bitrate server.
bits_in_buffer_model_ += static_cast<int64_t>(
duration * timebase_ * cfg_.rc_target_bitrate * 1000);
// Buffer should not go negative.
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;
// 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;
++frame_number_;
++tot_frame_number_;
}
virtual void EndPassHook(void) {
for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers);
++layer) {
duration_ = (last_pts_ + 1) * timebase_;
if (bits_total_[layer]) {
// Effective file datarate:
effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_;
}
}
}
vpx_codec_pts_t last_pts_;
double timebase_;
int frame_number_; // Counter for number of non-dropped/encoded frames.
int tot_frame_number_; // Counter for total number of input frames.
int64_t bits_total_[3];
double duration_;
double effective_datarate_[3];
int set_cpu_used_;
int64_t bits_in_buffer_model_;
vpx_codec_pts_t first_drop_;
int num_drops_;
int denoiser_on_;
int denoiser_offon_test_;
int denoiser_offon_period_;
};
// Check basic rate targeting,
TEST_P(DatarateTestVP9Large, BasicRateTargeting) {
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 = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
for (int i = 150; i < 800; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
<< " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
<< " The datarate for the file is greater than target by too much!";
}
}
// Check basic rate targeting,
TEST_P(DatarateTestVP9Large, BasicRateTargeting444) {
::libvpx_test::Y4mVideoSource video("rush_hour_444.y4m", 0, 140);
cfg_.g_profile = 1;
cfg_.g_timebase = video.timebase();
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 = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
for (int i = 250; i < 900; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(static_cast<double>(cfg_.rc_target_bitrate),
effective_datarate_[0] * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(static_cast<double>(cfg_.rc_target_bitrate),
effective_datarate_[0] * 1.15)
<< " The datarate for the file missed the target!"
<< cfg_.rc_target_bitrate << " "<< effective_datarate_;
}
}
// Check that (1) the first dropped frame gets earlier and earlier
// as the drop frame threshold is increased, and (2) that the total number of
// frame drops does not decrease as we increase frame drop threshold.
// Use a lower qp-max to force some frame drops.
TEST_P(DatarateTestVP9Large, ChangingDropFrameThresh) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_undershoot_pct = 20;
cfg_.rc_undershoot_pct = 20;
cfg_.rc_dropframe_thresh = 10;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 50;
cfg_.rc_end_usage = VPX_CBR;
cfg_.rc_target_bitrate = 200;
cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
const int kDropFrameThreshTestStep = 30;
vpx_codec_pts_t last_drop = 140;
int last_num_drops = 0;
for (int i = 10; i < 100; i += kDropFrameThreshTestStep) {
cfg_.rc_dropframe_thresh = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
<< " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
<< " The datarate for the file is greater than target by too much!";
ASSERT_LE(first_drop_, last_drop)
<< " The first dropped frame for drop_thresh " << i
<< " > first dropped frame for drop_thresh "
<< i - kDropFrameThreshTestStep;
ASSERT_GE(num_drops_, last_num_drops * 0.90)
<< " The number of dropped frames for drop_thresh " << i
<< " < number of dropped frames for drop_thresh "
<< i - kDropFrameThreshTestStep;
last_drop = first_drop_;
last_num_drops = num_drops_;
}
}
// Check basic rate targeting for 2 temporal layers.
TEST_P(DatarateTestVP9Large, BasicRateTargeting2TemporalLayers) {
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 = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
// 2 Temporal layers, no spatial layers: Framerate decimation (2, 1).
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 2;
cfg_.ts_rate_decimator[0] = 2;
cfg_.ts_rate_decimator[1] = 1;
if (deadline_ == VPX_DL_REALTIME)
cfg_.g_error_resilient = 1;
::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;
ResetModel();
// 60-40 bitrate allocation for 2 temporal layers.
cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = 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.85)
<< " 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.15)
<< " The datarate for the file is greater than target by too much, "
"for layer: " << j;
}
}
}
// Check basic rate targeting for 3 temporal layers.
TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayers) {
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 = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
// 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1).
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
::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;
ResetModel();
// 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) {
// TODO(yaowu): Work out more stable rc control strategy and
// Adjust the thresholds to be tighter than .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, "
"for layer: " << j;
// TODO(yaowu): Work out more stable rc control strategy and
// Adjust the thresholds to be tighter than 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, "
"for layer: " << j;
}
}
}
// Check basic rate targeting for 3 temporal layers, with frame dropping.
// Only for one (low) bitrate with lower max_quantizer, and somewhat higher
// frame drop threshold, to force frame dropping.
TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayersFrameDropping) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
// Set frame drop threshold and rc_max_quantizer to force some frame drops.
cfg_.rc_dropframe_thresh = 20;
cfg_.rc_max_quantizer = 45;
cfg_.rc_min_quantizer = 0;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
// 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1).
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
cfg_.rc_target_bitrate = 200;
ResetModel();
// 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.85)
<< " 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.15)
<< " The datarate for the file is greater than target by too much, "
"for layer: " << j;
// Expect some frame drops in this test: for this 200 frames test,
// expect at least 10% and not more than 60% drops.
ASSERT_GE(num_drops_, 20);
ASSERT_LE(num_drops_, 130);
}
}
#if CONFIG_VP9_TEMPORAL_DENOISING
// Check basic datarate targeting, for a single bitrate, when denoiser is on.
TEST_P(DatarateTestVP9Large, DenoiserLevels) {
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_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
// For the temporal denoiser (#if CONFIG_VP9_TEMPORAL_DENOISING),
// there is only one denoiser mode: denoiserYonly(which is 1),
// but may add more modes in the future.
cfg_.rc_target_bitrate = 300;
ResetModel();
// Turn on the denoiser.
denoiser_on_ = 1;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
<< " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
<< " The datarate for the file is greater than target by too much!";
}
// Check basic datarate targeting, for a single bitrate, when denoiser is off
// and on.
TEST_P(DatarateTestVP9Large, DenoiserOffOn) {
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_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 299);
// For the temporal denoiser (#if CONFIG_VP9_TEMPORAL_DENOISING),
// there is only one denoiser mode: denoiserYonly(which is 1),
// but may add more modes in the future.
cfg_.rc_target_bitrate = 300;
ResetModel();
// The denoiser is off by default.
denoiser_on_ = 0;
// Set the offon test flag.
denoiser_offon_test_ = 1;
denoiser_offon_period_ = 100;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
<< " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
<< " The datarate for the file is greater than target by too much!";
}
#endif // CONFIG_VP9_TEMPORAL_DENOISING
VP8_INSTANTIATE_TEST_CASE(DatarateTestLarge, ALL_TEST_MODES);
VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9Large,
::testing::Values(::libvpx_test::kOnePassGood,
::libvpx_test::kRealTime),
::testing::Range(2, 7));
} // namespace

View File

@ -13,25 +13,54 @@
#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 "./vp9_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 "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h" #include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_scan.h"
#include "vpx/vpx_codec.h" #include "vpx/vpx_codec.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 = 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;
@ -54,16 +83,16 @@ void butterfly_16x16_dct_1d(double input[16], double output[16]) {
double temp1, temp2; double temp1, temp2;
// step 1 // step 1
step[0] = input[0] + input[15]; step[ 0] = input[0] + input[15];
step[1] = input[1] + input[14]; step[ 1] = input[1] + input[14];
step[2] = input[2] + input[13]; step[ 2] = input[2] + input[13];
step[3] = input[3] + input[12]; step[ 3] = input[3] + input[12];
step[4] = input[4] + input[11]; step[ 4] = input[4] + input[11];
step[5] = input[5] + input[10]; step[ 5] = input[5] + input[10];
step[6] = input[6] + input[9]; step[ 6] = input[6] + input[ 9];
step[7] = input[7] + input[8]; step[ 7] = input[7] + input[ 8];
step[8] = input[7] - input[8]; step[ 8] = input[7] - input[ 8];
step[9] = input[6] - input[9]; step[ 9] = input[6] - input[ 9];
step[10] = input[5] - input[10]; step[10] = input[5] - input[10];
step[11] = input[4] - input[11]; step[11] = input[4] - input[11];
step[12] = input[3] - input[12]; step[12] = input[3] - input[12];
@ -81,13 +110,13 @@ void butterfly_16x16_dct_1d(double input[16], double output[16]) {
output[6] = step[1] - step[6]; output[6] = step[1] - step[6];
output[7] = step[0] - step[7]; output[7] = step[0] - step[7];
temp1 = step[8] * C7; temp1 = step[ 8] * C7;
temp2 = step[15] * C9; temp2 = step[15] * C9;
output[8] = temp1 + temp2; output[ 8] = temp1 + temp2;
temp1 = step[9] * C11; temp1 = step[ 9] * C11;
temp2 = step[14] * C5; temp2 = step[14] * C5;
output[9] = temp1 - temp2; output[ 9] = temp1 - temp2;
temp1 = step[10] * C3; temp1 = step[10] * C3;
temp2 = step[13] * C13; temp2 = step[13] * C13;
@ -105,40 +134,40 @@ void butterfly_16x16_dct_1d(double input[16], double output[16]) {
temp2 = step[13] * C3; temp2 = step[13] * C3;
output[13] = temp2 - temp1; output[13] = temp2 - temp1;
temp1 = step[9] * C5; temp1 = step[ 9] * C5;
temp2 = step[14] * C11; temp2 = step[14] * C11;
output[14] = temp2 + temp1; output[14] = temp2 + temp1;
temp1 = step[8] * C9; temp1 = step[ 8] * C9;
temp2 = step[15] * C7; temp2 = step[15] * C7;
output[15] = temp2 - temp1; output[15] = temp2 - temp1;
// step 3 // step 3
step[0] = output[0] + output[3]; step[ 0] = output[0] + output[3];
step[1] = output[1] + output[2]; step[ 1] = output[1] + output[2];
step[2] = output[1] - output[2]; step[ 2] = output[1] - output[2];
step[3] = output[0] - output[3]; step[ 3] = output[0] - output[3];
temp1 = output[4] * C14; temp1 = output[4] * C14;
temp2 = output[7] * C2; temp2 = output[7] * C2;
step[4] = temp1 + temp2; step[ 4] = temp1 + temp2;
temp1 = output[5] * C10; temp1 = output[5] * C10;
temp2 = output[6] * C6; temp2 = output[6] * C6;
step[5] = temp1 + temp2; step[ 5] = temp1 + temp2;
temp1 = output[5] * C6; temp1 = output[5] * C6;
temp2 = output[6] * C10; temp2 = output[6] * C10;
step[6] = temp2 - temp1; step[ 6] = temp2 - temp1;
temp1 = output[4] * C2; temp1 = output[4] * C2;
temp2 = output[7] * C14; temp2 = output[7] * C14;
step[7] = temp2 - temp1; step[ 7] = temp2 - temp1;
step[8] = output[8] + output[11]; step[ 8] = output[ 8] + output[11];
step[9] = output[9] + output[10]; step[ 9] = output[ 9] + output[10];
step[10] = output[9] - output[10]; step[10] = output[ 9] - output[10];
step[11] = output[8] - output[11]; step[11] = output[ 8] - output[11];
step[12] = output[12] + output[15]; step[12] = output[12] + output[15];
step[13] = output[13] + output[14]; step[13] = output[13] + output[14];
@ -146,25 +175,25 @@ void butterfly_16x16_dct_1d(double input[16], double output[16]) {
step[15] = output[12] - output[15]; step[15] = output[12] - output[15];
// step 4 // step 4
output[0] = (step[0] + step[1]); output[ 0] = (step[ 0] + step[ 1]);
output[8] = (step[0] - step[1]); output[ 8] = (step[ 0] - step[ 1]);
temp1 = step[2] * C12; temp1 = step[2] * C12;
temp2 = step[3] * C4; temp2 = step[3] * C4;
temp1 = temp1 + temp2; temp1 = temp1 + temp2;
output[4] = 2 * (temp1 * C8); output[ 4] = 2*(temp1 * C8);
temp1 = step[2] * C4; temp1 = step[2] * C4;
temp2 = step[3] * C12; temp2 = step[3] * C12;
temp1 = temp2 - temp1; temp1 = temp2 - temp1;
output[12] = 2 * (temp1 * C8); output[12] = 2 * (temp1 * C8);
output[2] = 2 * ((step[4] + step[5]) * C8); output[ 2] = 2 * ((step[4] + step[ 5]) * C8);
output[14] = 2 * ((step[7] - step[6]) * C8); output[14] = 2 * ((step[7] - step[ 6]) * C8);
temp1 = step[4] - step[5]; temp1 = step[4] - step[5];
temp2 = step[6] + step[7]; temp2 = step[6] + step[7];
output[6] = (temp1 + temp2); output[ 6] = (temp1 + temp2);
output[10] = (temp1 - temp2); output[10] = (temp1 - temp2);
intermediate[8] = step[8] + step[14]; intermediate[8] = step[8] + step[14];
@ -180,18 +209,18 @@ void butterfly_16x16_dct_1d(double input[16], double output[16]) {
temp1 = temp2 + temp1; temp1 = temp2 + temp1;
output[13] = 2 * (temp1 * C8); output[13] = 2 * (temp1 * C8);
output[9] = 2 * ((step[10] + step[11]) * C8); output[ 9] = 2 * ((step[10] + step[11]) * C8);
intermediate[11] = step[10] - step[11]; intermediate[11] = step[10] - step[11];
intermediate[12] = step[12] + step[13]; intermediate[12] = step[12] + step[13];
intermediate[13] = step[12] - step[13]; intermediate[13] = step[12] - step[13];
intermediate[14] = step[8] - step[14]; intermediate[14] = step[ 8] - step[14];
intermediate[15] = step[9] - step[15]; intermediate[15] = step[ 9] - step[15];
output[15] = (intermediate[11] + intermediate[12]); output[15] = (intermediate[11] + intermediate[12]);
output[1] = -(intermediate[11] - intermediate[12]); output[ 1] = -(intermediate[11] - intermediate[12]);
output[7] = 2 * (intermediate[13] * C8); output[ 7] = 2 * (intermediate[13] * C8);
temp1 = intermediate[14] * C12; temp1 = intermediate[14] * C12;
temp2 = intermediate[15] * C4; temp2 = intermediate[15] * C4;
@ -201,24 +230,28 @@ void butterfly_16x16_dct_1d(double input[16], double output[16]) {
temp1 = intermediate[14] * C4; temp1 = intermediate[14] * C4;
temp2 = intermediate[15] * C12; temp2 = intermediate[15] * C12;
temp1 = temp2 + temp1; temp1 = temp2 + temp1;
output[5] = 2 * (temp1 * C8); output[ 5] = 2 * (temp1 * C8);
} }
void reference_16x16_dct_2d(int16_t input[256], double output[256]) { void reference_16x16_dct_2d(int16_t input[256], double output[256]) {
// First transform columns // First transform columns
for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i) {
double temp_in[16], temp_out[16]; double temp_in[16], temp_out[16];
for (int j = 0; j < 16; ++j) temp_in[j] = input[j * 16 + i]; for (int j = 0; j < 16; ++j)
temp_in[j] = input[j * 16 + i];
butterfly_16x16_dct_1d(temp_in, temp_out); butterfly_16x16_dct_1d(temp_in, temp_out);
for (int j = 0; j < 16; ++j) output[j * 16 + i] = temp_out[j]; for (int j = 0; j < 16; ++j)
output[j * 16 + i] = temp_out[j];
} }
// Then transform rows // Then transform rows
for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i) {
double temp_in[16], temp_out[16]; double temp_in[16], temp_out[16];
for (int j = 0; j < 16; ++j) temp_in[j] = output[j + i * 16]; for (int j = 0; j < 16; ++j)
temp_in[j] = output[j + i * 16];
butterfly_16x16_dct_1d(temp_in, temp_out); butterfly_16x16_dct_1d(temp_in, temp_out);
// Scale by some magic number // Scale by some magic number
for (int j = 0; j < 16; ++j) output[j + i * 16] = temp_out[j] / 2; for (int j = 0; j < 16; ++j)
output[j + i * 16] = temp_out[j]/2;
} }
} }
@ -229,23 +262,23 @@ typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride,
typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride,
int tx_type); int tx_type);
typedef ::testing::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct16x16Param;
Dct16x16Param; typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht16x16Param;
typedef ::testing::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht16x16Param; typedef std::tr1::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t>
typedef ::testing::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t>
Idct16x16Param; Idct16x16Param;
void fdct16x16_ref(const int16_t *in, tran_low_t *out, int stride, void fdct16x16_ref(const int16_t *in, tran_low_t *out, int stride,
int /*tx_type*/) { int /*tx_type*/) {
vpx_fdct16x16_c(in, out, stride); vp9_fdct16x16_c(in, out, stride);
} }
void idct16x16_ref(const tran_low_t *in, uint8_t *dest, int stride, void idct16x16_ref(const tran_low_t *in, uint8_t *dest, int stride,
int /*tx_type*/) { int /*tx_type*/) {
vpx_idct16x16_256_add_c(in, dest, stride); vp9_idct16x16_256_add_c(in, dest, stride);
} }
void fht16x16_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) { void fht16x16_ref(const int16_t *in, tran_low_t *out, int stride,
int tx_type) {
vp9_fht16x16_c(in, out, stride, tx_type); vp9_fht16x16_c(in, out, stride, tx_type);
} }
@ -256,54 +289,54 @@ void iht16x16_ref(const tran_low_t *in, uint8_t *dest, int stride,
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
void idct16x16_10(const tran_low_t *in, uint8_t *out, int stride) { void idct16x16_10(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_256_add_c(in, CAST_TO_SHORTPTR(out), stride, 10); vp9_highbd_idct16x16_256_add_c(in, out, stride, 10);
} }
void idct16x16_12(const tran_low_t *in, uint8_t *out, int stride) { void idct16x16_12(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_256_add_c(in, CAST_TO_SHORTPTR(out), stride, 12); vp9_highbd_idct16x16_256_add_c(in, out, stride, 12);
} }
void idct16x16_10_ref(const tran_low_t *in, uint8_t *out, int stride, void idct16x16_10_ref(const tran_low_t *in, uint8_t *out, int stride,
int /*tx_type*/) { int tx_type) {
idct16x16_10(in, out, stride); idct16x16_10(in, out, stride);
} }
void idct16x16_12_ref(const tran_low_t *in, uint8_t *out, int stride, void idct16x16_12_ref(const tran_low_t *in, uint8_t *out, int stride,
int /*tx_type*/) { int tx_type) {
idct16x16_12(in, out, stride); idct16x16_12(in, out, stride);
} }
void iht16x16_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) { void iht16x16_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp9_highbd_iht16x16_256_add_c(in, CAST_TO_SHORTPTR(out), stride, tx_type, 10); vp9_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) { void iht16x16_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp9_highbd_iht16x16_256_add_c(in, CAST_TO_SHORTPTR(out), stride, tx_type, 12); vp9_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) { void idct16x16_10_add_10_c(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_10_add_c(in, CAST_TO_SHORTPTR(out), stride, 10); vp9_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) { void idct16x16_10_add_12_c(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_10_add_c(in, CAST_TO_SHORTPTR(out), stride, 12); vp9_highbd_idct16x16_10_add_c(in, out, stride, 12);
} }
#if HAVE_SSE2
void idct16x16_256_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) { void idct16x16_256_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_256_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 10); vp9_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) { void idct16x16_256_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_256_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 12); vp9_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) { void idct16x16_10_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_10_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 10); vp9_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) { void idct16x16_10_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct16x16_10_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 12); vp9_highbd_idct16x16_10_add_sse2(in, out, stride, 12);
} }
#endif // HAVE_SSE2 #endif // HAVE_SSE2
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
@ -323,13 +356,13 @@ 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, tran_low_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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, kNumCoeffs);
#endif #endif
// Initialize a test block with input range [-mask_, mask_]. // Initialize a test block with input range [-mask_, mask_].
@ -347,31 +380,33 @@ class Trans16x16TestBase {
} }
} }
ASM_REGISTER_STATE_CHECK( ASM_REGISTER_STATE_CHECK(RunFwdTxfm(test_input_block,
RunFwdTxfm(test_input_block, test_temp_block, pitch_)); test_temp_block, pitch_));
if (bit_depth_ == VPX_BITS_8) { if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_)); ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
ASM_REGISTER_STATE_CHECK( ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, CAST_TO_BYTEPTR(dst16), pitch_)); RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif #endif
} }
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
const int32_t diff = const uint32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else #else
const int32_t diff = dst[j] - src[j]; const uint32_t diff = dst[j] - src[j];
#endif #endif
const uint32_t error = diff * diff; const uint32_t error = diff * diff;
if (max_error < error) max_error = error; if (max_error < error)
max_error = error;
total_error += error; total_error += error;
} }
} }
EXPECT_GE(1u << 2 * (bit_depth_ - 8), max_error) EXPECT_GE(1u << 2 * (bit_depth_ - 8), 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 << 2 * (bit_depth_ - 8), total_error)
@ -381,15 +416,14 @@ class Trans16x16TestBase {
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, tran_low_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, tran_low_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 [-mask_, mask_].
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.Rand16() & mask_) - (rnd.Rand16() & mask_);
}
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_)); ASM_REGISTER_STATE_CHECK(RunFwdTxfm(input_block, output_block, pitch_));
@ -403,24 +437,28 @@ 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, tran_low_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, tran_low_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 [-mask_, mask_].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
input_block[j] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_);
input_extreme_block[j] = rnd.Rand8() % 2 ? mask_ : -mask_; input_extreme_block[j] = rnd.Rand8() % 2 ? mask_ : -mask_;
} }
if (i == 0) { if (i == 0) {
for (int j = 0; j < kNumCoeffs; ++j) input_extreme_block[j] = mask_; for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = mask_;
} else if (i == 1) { } else if (i == 1) {
for (int j = 0; j < kNumCoeffs; ++j) input_extreme_block[j] = -mask_; for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = -mask_;
} }
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( ASM_REGISTER_STATE_CHECK(RunFwdTxfm(input_extreme_block,
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) {
@ -434,27 +472,32 @@ 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 = 100000;
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, tran_low_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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED(16, uint16_t, ref16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, ref16, kNumCoeffs);
#endif #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 [-mask_, mask_].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
if (bit_depth_ == VPX_BITS_8)
input_block[j] = rnd.Rand8() - rnd.Rand8();
else
input_block[j] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_);
input_extreme_block[j] = rnd.Rand8() % 2 ? mask_ : -mask_; input_extreme_block[j] = rnd.Rand8() % 2 ? mask_ : -mask_;
} }
if (i == 0) { if (i == 0)
for (int j = 0; j < kNumCoeffs; ++j) input_extreme_block[j] = mask_; for (int j = 0; j < kNumCoeffs; ++j)
} input_extreme_block[j] = mask_;
if (i == 1) { if (i == 1)
for (int j = 0; j < kNumCoeffs; ++j) input_extreme_block[j] = -mask_; for (int j = 0; j < kNumCoeffs; ++j)
} input_extreme_block[j] = -mask_;
fwd_txfm_ref(input_extreme_block, output_ref_block, pitch_, tx_type_); fwd_txfm_ref(input_extreme_block, output_ref_block, pitch_, tx_type_);
@ -468,25 +511,26 @@ class Trans16x16TestBase {
// 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) { 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_)); ASM_REGISTER_STATE_CHECK(RunInvTxfm(output_ref_block, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
inv_txfm_ref(output_ref_block, CAST_TO_BYTEPTR(ref16), pitch_, inv_txfm_ref(output_ref_block, CONVERT_TO_BYTEPTR(ref16), pitch_,
tx_type_); tx_type_);
ASM_REGISTER_STATE_CHECK( ASM_REGISTER_STATE_CHECK(RunInvTxfm(output_ref_block,
RunInvTxfm(output_ref_block, CAST_TO_BYTEPTR(dst16), pitch_)); CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif #endif
} }
if (bit_depth_ == VPX_BITS_8) { if (bit_depth_ == VPX_BITS_8) {
for (int j = 0; j < kNumCoeffs; ++j) EXPECT_EQ(ref[j], dst[j]); for (int j = 0; j < kNumCoeffs; ++j)
EXPECT_EQ(ref[j], dst[j]);
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
for (int j = 0; j < kNumCoeffs; ++j) EXPECT_EQ(ref16[j], dst16[j]); for (int j = 0; j < kNumCoeffs; ++j)
EXPECT_EQ(ref16[j], dst16[j]);
#endif #endif
} }
} }
@ -495,13 +539,13 @@ class Trans16x16TestBase {
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, tran_low_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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, kNumCoeffs);
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
@ -523,15 +567,15 @@ class Trans16x16TestBase {
} }
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] = static_cast<tran_low_t>(round(out_r[j]));
}
if (bit_depth_ == VPX_BITS_8) { if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, 16)); ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, 16));
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CAST_TO_BYTEPTR(dst16), 16)); ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
16));
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
} }
@ -544,7 +588,8 @@ class Trans16x16TestBase {
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_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 << " at index " << j; << "Error: 16x16 IDCT has error " << error
<< " at index " << j;
} }
} }
} }
@ -554,12 +599,12 @@ class Trans16x16TestBase {
const int count_test_block = 10000; const int count_test_block = 10000;
const int eob = 10; const int eob = 10;
const int16_t *scan = vp9_default_scan_orders[TX_16X16].scan; const int16_t *scan = vp9_default_scan_orders[TX_16X16].scan;
DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff, 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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED(16, uint16_t, ref16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, ref16, kNumCoeffs);
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
@ -585,9 +630,9 @@ class Trans16x16TestBase {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_)); ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
} else { } else {
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
ref_txfm(coeff, CAST_TO_BYTEPTR(ref16), pitch_); ref_txfm(coeff, CONVERT_TO_BYTEPTR(ref16), pitch_);
ASM_REGISTER_STATE_CHECK( ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
RunInvTxfm(coeff, CAST_TO_BYTEPTR(dst16), pitch_)); pitch_));
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
} }
@ -599,8 +644,9 @@ class Trans16x16TestBase {
const uint32_t diff = dst[j] - ref[j]; const uint32_t diff = dst[j] - ref[j];
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
const uint32_t error = diff * diff; const uint32_t error = diff * diff;
EXPECT_EQ(0u, error) << "Error: 16x16 IDCT Comparison has error " EXPECT_EQ(0u, error)
<< error << " at index " << j; << "Error: 16x16 IDCT Comparison has error " << error
<< " at index " << j;
} }
} }
} }
@ -613,25 +659,32 @@ class Trans16x16TestBase {
IhtFunc inv_txfm_ref; IhtFunc inv_txfm_ref;
}; };
class Trans16x16DCT : public Trans16x16TestBase, class Trans16x16DCT
public ::testing::TestWithParam<Dct16x16Param> { : public Trans16x16TestBase,
public ::testing::TestWithParam<Dct16x16Param> {
public: public:
virtual ~Trans16x16DCT() {} virtual ~Trans16x16DCT() {}
virtual void SetUp() { virtual void SetUp() {
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); 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; mask_ = (1 << bit_depth_) - 1;
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
switch (bit_depth_) { switch (bit_depth_) {
case VPX_BITS_10: inv_txfm_ref = idct16x16_10_ref; break; case VPX_BITS_10:
case VPX_BITS_12: inv_txfm_ref = idct16x16_12_ref; break; inv_txfm_ref = idct16x16_10_ref;
default: inv_txfm_ref = idct16x16_ref; break; break;
case VPX_BITS_12:
inv_txfm_ref = idct16x16_12_ref;
break;
default:
inv_txfm_ref = idct16x16_ref;
break;
} }
#else #else
inv_txfm_ref = idct16x16_ref; inv_txfm_ref = idct16x16_ref;
@ -651,11 +704,17 @@ class Trans16x16DCT : public Trans16x16TestBase,
IdctFunc inv_txfm_; IdctFunc inv_txfm_;
}; };
TEST_P(Trans16x16DCT, AccuracyCheck) { RunAccuracyCheck(); } TEST_P(Trans16x16DCT, AccuracyCheck) {
RunAccuracyCheck();
}
TEST_P(Trans16x16DCT, CoeffCheck) { RunCoeffCheck(); } TEST_P(Trans16x16DCT, CoeffCheck) {
RunCoeffCheck();
}
TEST_P(Trans16x16DCT, MemCheck) { RunMemCheck(); } TEST_P(Trans16x16DCT, MemCheck) {
RunMemCheck();
}
TEST_P(Trans16x16DCT, QuantCheck) { TEST_P(Trans16x16DCT, QuantCheck) {
// Use maximally allowed quantization step sizes for DC and AC // Use maximally allowed quantization step sizes for DC and AC
@ -663,27 +722,36 @@ TEST_P(Trans16x16DCT, QuantCheck) {
RunQuantCheck(1336, 1828); RunQuantCheck(1336, 1828);
} }
TEST_P(Trans16x16DCT, InvAccuracyCheck) { RunInvAccuracyCheck(); } TEST_P(Trans16x16DCT, InvAccuracyCheck) {
RunInvAccuracyCheck();
}
class Trans16x16HT : public Trans16x16TestBase, class Trans16x16HT
public ::testing::TestWithParam<Ht16x16Param> { : public Trans16x16TestBase,
public ::testing::TestWithParam<Ht16x16Param> {
public: public:
virtual ~Trans16x16HT() {} virtual ~Trans16x16HT() {}
virtual void SetUp() { virtual void SetUp() {
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); 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; mask_ = (1 << bit_depth_) - 1;
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
switch (bit_depth_) { switch (bit_depth_) {
case VPX_BITS_10: inv_txfm_ref = iht16x16_10; break; case VPX_BITS_10:
case VPX_BITS_12: inv_txfm_ref = iht16x16_12; break; inv_txfm_ref = iht16x16_10;
default: inv_txfm_ref = iht16x16_ref; break; break;
case VPX_BITS_12:
inv_txfm_ref = iht16x16_12;
break;
default:
inv_txfm_ref = iht16x16_ref;
break;
} }
#else #else
inv_txfm_ref = iht16x16_ref; inv_txfm_ref = iht16x16_ref;
@ -703,11 +771,17 @@ class Trans16x16HT : public Trans16x16TestBase,
IhtFunc inv_txfm_; IhtFunc inv_txfm_;
}; };
TEST_P(Trans16x16HT, AccuracyCheck) { RunAccuracyCheck(); } TEST_P(Trans16x16HT, AccuracyCheck) {
RunAccuracyCheck();
}
TEST_P(Trans16x16HT, CoeffCheck) { RunCoeffCheck(); } TEST_P(Trans16x16HT, CoeffCheck) {
RunCoeffCheck();
}
TEST_P(Trans16x16HT, MemCheck) { RunMemCheck(); } TEST_P(Trans16x16HT, MemCheck) {
RunMemCheck();
}
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,
@ -715,8 +789,9 @@ TEST_P(Trans16x16HT, QuantCheck) {
RunQuantCheck(429, 729); RunQuantCheck(429, 729);
} }
class InvTrans16x16DCT : public Trans16x16TestBase, class InvTrans16x16DCT
public ::testing::TestWithParam<Idct16x16Param> { : public Trans16x16TestBase,
public ::testing::TestWithParam<Idct16x16Param> {
public: public:
virtual ~InvTrans16x16DCT() {} virtual ~InvTrans16x16DCT() {}
@ -727,11 +802,11 @@ class InvTrans16x16DCT : public Trans16x16TestBase,
bit_depth_ = GET_PARAM(3); bit_depth_ = GET_PARAM(3);
pitch_ = 16; pitch_ = 16;
mask_ = (1 << bit_depth_) - 1; 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, tran_low_t *out, int stride) {}
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride); inv_txfm_(out, dst, stride);
} }
@ -745,20 +820,20 @@ TEST_P(InvTrans16x16DCT, CompareReference) {
CompareInvReference(ref_txfm_, thresh_); CompareInvReference(ref_txfm_, thresh_);
} }
using ::testing::make_tuple; using std::tr1::make_tuple;
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_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_highbd_fdct16x16_c, &idct16x16_10, 0, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct16x16_c, &idct16x16_12, 0, VPX_BITS_12), make_tuple(&vp9_highbd_fdct16x16_c, &idct16x16_12, 0, VPX_BITS_12),
make_tuple(&vpx_fdct16x16_c, &vpx_idct16x16_256_add_c, 0, VPX_BITS_8))); make_tuple(&vp9_fdct16x16_c, &vp9_idct16x16_256_add_c, 0, VPX_BITS_8)));
#else #else
INSTANTIATE_TEST_CASE_P(C, Trans16x16DCT, INSTANTIATE_TEST_CASE_P(
::testing::Values(make_tuple(&vpx_fdct16x16_c, C, Trans16x16DCT,
&vpx_idct16x16_256_add_c, ::testing::Values(
0, VPX_BITS_8))); make_tuple(&vp9_fdct16x16_c, &vp9_idct16x16_256_add_c, 0, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
@ -787,45 +862,58 @@ INSTANTIATE_TEST_CASE_P(
make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 3, VPX_BITS_8))); make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 3, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
#if HAVE_NEON && !CONFIG_EMULATE_HARDWARE #if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
NEON, Trans16x16DCT, NEON, Trans16x16DCT,
::testing::Values(make_tuple(&vpx_fdct16x16_neon, ::testing::Values(
&vpx_idct16x16_256_add_neon, 0, VPX_BITS_8))); make_tuple(&vp9_fdct16x16_c,
#endif // HAVE_NEON && !CONFIG_EMULATE_HARDWARE &vp9_idct16x16_256_add_neon, 0, VPX_BITS_8)));
#endif
#if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16DCT, SSE2, Trans16x16DCT,
::testing::Values(make_tuple(&vpx_fdct16x16_sse2, ::testing::Values(
&vpx_idct16x16_256_add_sse2, 0, VPX_BITS_8))); make_tuple(&vp9_fdct16x16_sse2,
&vp9_idct16x16_256_add_sse2, 0, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16HT, SSE2, Trans16x16HT,
::testing::Values(make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, ::testing::Values(
0, VPX_BITS_8), make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 0,
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, VPX_BITS_8),
1, VPX_BITS_8), make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 1,
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, VPX_BITS_8),
2, VPX_BITS_8), make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 2,
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, VPX_BITS_8),
3, VPX_BITS_8))); make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 3,
VPX_BITS_8)));
#endif // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #endif // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16DCT, SSE2, Trans16x16DCT,
::testing::Values( ::testing::Values(
make_tuple(&vpx_highbd_fdct16x16_sse2, &idct16x16_10, 0, VPX_BITS_10), make_tuple(&vp9_highbd_fdct16x16_sse2,
make_tuple(&vpx_highbd_fdct16x16_c, &idct16x16_256_add_10_sse2, 0, &idct16x16_10, 0, VPX_BITS_10),
VPX_BITS_10), make_tuple(&vp9_highbd_fdct16x16_c,
make_tuple(&vpx_highbd_fdct16x16_sse2, &idct16x16_12, 0, VPX_BITS_12), &idct16x16_256_add_10_sse2, 0, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct16x16_c, &idct16x16_256_add_12_sse2, 0, make_tuple(&vp9_highbd_fdct16x16_sse2,
VPX_BITS_12), &idct16x16_12, 0, VPX_BITS_12),
make_tuple(&vpx_fdct16x16_sse2, &vpx_idct16x16_256_add_c, 0, make_tuple(&vp9_highbd_fdct16x16_c,
VPX_BITS_8))); &idct16x16_256_add_12_sse2, 0, VPX_BITS_12),
make_tuple(&vp9_fdct16x16_sse2,
&vp9_idct16x16_256_add_c, 0, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16HT, SSE2, Trans16x16HT,
::testing::Values( ::testing::Values(
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_10, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_10, 1, VPX_BITS_10),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_10, 2, VPX_BITS_10),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_10, 3, VPX_BITS_10),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_12, 0, VPX_BITS_12),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_12, 1, VPX_BITS_12),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_12, 2, VPX_BITS_12),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_12, 3, VPX_BITS_12),
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 0, VPX_BITS_8), make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 0, VPX_BITS_8),
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 1, VPX_BITS_8), make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 1, VPX_BITS_8),
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 2, VPX_BITS_8), make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 2, VPX_BITS_8),
@ -835,35 +923,14 @@ INSTANTIATE_TEST_CASE_P(
// that to test both branches. // that to test both branches.
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, InvTrans16x16DCT, 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)));
#endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_MSA && !CONFIG_VP9_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( ::testing::Values(
make_tuple(&vp9_fht16x16_msa, &vp9_iht16x16_256_add_msa, 0, VPX_BITS_8), make_tuple(&idct16x16_10_add_10_c,
make_tuple(&vp9_fht16x16_msa, &vp9_iht16x16_256_add_msa, 1, VPX_BITS_8), &idct16x16_10_add_10_sse2, 3167, VPX_BITS_10),
make_tuple(&vp9_fht16x16_msa, &vp9_iht16x16_256_add_msa, 2, VPX_BITS_8), make_tuple(&idct16x16_10,
make_tuple(&vp9_fht16x16_msa, &vp9_iht16x16_256_add_msa, 3, &idct16x16_256_add_10_sse2, 3167, VPX_BITS_10),
VPX_BITS_8))); make_tuple(&idct16x16_10_add_12_c,
#endif // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE &idct16x16_10_add_12_sse2, 3167, VPX_BITS_12),
make_tuple(&idct16x16_12,
#if HAVE_VSX && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE &idct16x16_256_add_12_sse2, 3167, VPX_BITS_12)));
INSTANTIATE_TEST_CASE_P(VSX, Trans16x16DCT, #endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
::testing::Values(make_tuple(&vpx_fdct16x16_c,
&vpx_idct16x16_256_add_vsx,
0, VPX_BITS_8)));
#endif // HAVE_VSX && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace } // namespace

View File

@ -13,23 +13,28 @@
#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 "./vp9_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 "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h" #include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_codec.h" #include "vpx/vpx_codec.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;
@ -37,10 +42,10 @@ void reference_32x32_dct_1d(const double in[32], double out[32]) {
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;
for (int n = 0; n < 32; n++) { for (int n = 0; n < 32; n++)
out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 64.0); out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 64.0);
} if (k == 0)
if (k == 0) out[k] = out[k] * kInvSqrt2; out[k] = out[k] * kInvSqrt2;
} }
} }
@ -49,33 +54,41 @@ void reference_32x32_dct_2d(const int16_t input[kNumCoeffs],
// First transform columns // First transform columns
for (int i = 0; i < 32; ++i) { for (int i = 0; i < 32; ++i) {
double temp_in[32], temp_out[32]; double temp_in[32], temp_out[32];
for (int j = 0; j < 32; ++j) temp_in[j] = input[j * 32 + i]; for (int j = 0; j < 32; ++j)
temp_in[j] = input[j*32 + i];
reference_32x32_dct_1d(temp_in, temp_out); reference_32x32_dct_1d(temp_in, temp_out);
for (int j = 0; j < 32; ++j) output[j * 32 + i] = temp_out[j]; for (int j = 0; j < 32; ++j)
output[j * 32 + i] = temp_out[j];
} }
// Then transform rows // Then transform rows
for (int i = 0; i < 32; ++i) { for (int i = 0; i < 32; ++i) {
double temp_in[32], temp_out[32]; double temp_in[32], temp_out[32];
for (int j = 0; j < 32; ++j) temp_in[j] = output[j + i * 32]; for (int j = 0; j < 32; ++j)
temp_in[j] = output[j + i*32];
reference_32x32_dct_1d(temp_in, temp_out); reference_32x32_dct_1d(temp_in, temp_out);
// Scale by some magic number // Scale by some magic number
for (int j = 0; j < 32; ++j) output[j + i * 32] = temp_out[j] / 4; for (int j = 0; j < 32; ++j)
output[j + i * 32] = temp_out[j] / 4;
} }
} }
typedef void (*FwdTxfmFunc)(const int16_t *in, tran_low_t *out, int stride); typedef void (*FwdTxfmFunc)(const int16_t *in, tran_low_t *out, int stride);
typedef void (*InvTxfmFunc)(const tran_low_t *in, uint8_t *out, int stride); typedef void (*InvTxfmFunc)(const tran_low_t *in, uint8_t *out, int stride);
typedef ::testing::tuple<FwdTxfmFunc, InvTxfmFunc, int, vpx_bit_depth_t> typedef std::tr1::tuple<FwdTxfmFunc, InvTxfmFunc, int, vpx_bit_depth_t>
Trans32x32Param; Trans32x32Param;
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
void idct32x32_8(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct32x32_1024_add_c(in, out, stride, 8);
}
void idct32x32_10(const tran_low_t *in, uint8_t *out, int stride) { void idct32x32_10(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct32x32_1024_add_c(in, CAST_TO_SHORTPTR(out), stride, 10); vp9_highbd_idct32x32_1024_add_c(in, out, stride, 10);
} }
void idct32x32_12(const tran_low_t *in, uint8_t *out, int stride) { void idct32x32_12(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct32x32_1024_add_c(in, CAST_TO_SHORTPTR(out), stride, 12); vp9_highbd_idct32x32_1024_add_c(in, out, stride, 12);
} }
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
@ -85,8 +98,8 @@ class Trans32x32Test : public ::testing::TestWithParam<Trans32x32Param> {
virtual void SetUp() { virtual void SetUp() {
fwd_txfm_ = GET_PARAM(0); fwd_txfm_ = GET_PARAM(0);
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); bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1; mask_ = (1 << bit_depth_) - 1;
} }
@ -106,13 +119,13 @@ TEST_P(Trans32x32Test, AccuracyCheck) {
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 = 10000;
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, tran_low_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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, kNumCoeffs);
#endif #endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
@ -136,20 +149,21 @@ TEST_P(Trans32x32Test, AccuracyCheck) {
ASM_REGISTER_STATE_CHECK(inv_txfm_(test_temp_block, dst, 32)); ASM_REGISTER_STATE_CHECK(inv_txfm_(test_temp_block, dst, 32));
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
ASM_REGISTER_STATE_CHECK( ASM_REGISTER_STATE_CHECK(inv_txfm_(test_temp_block,
inv_txfm_(test_temp_block, CAST_TO_BYTEPTR(dst16), 32)); CONVERT_TO_BYTEPTR(dst16), 32));
#endif #endif
} }
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
const int32_t diff = const uint32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else #else
const int32_t diff = dst[j] - src[j]; const uint32_t diff = dst[j] - src[j];
#endif #endif
const uint32_t error = diff * diff; const uint32_t error = diff * diff;
if (max_error < error) max_error = error; if (max_error < error)
max_error = error;
total_error += error; total_error += error;
} }
} }
@ -170,17 +184,16 @@ 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, tran_low_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, output_block[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, tran_low_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.Rand16() & mask_) - (rnd.Rand16() & mask_);
}
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)); ASM_REGISTER_STATE_CHECK(fwd_txfm_(input_block, output_block, stride));
if (version_ == 0) { if (version_ == 0) {
@ -199,23 +212,27 @@ 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, tran_low_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, tran_low_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 [-mask_, mask_].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
input_block[j] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_);
input_extreme_block[j] = rnd.Rand8() & 1 ? mask_ : -mask_; input_extreme_block[j] = rnd.Rand8() & 1 ? mask_ : -mask_;
} }
if (i == 0) { if (i == 0) {
for (int j = 0; j < kNumCoeffs; ++j) input_extreme_block[j] = mask_; for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = mask_;
} else if (i == 1) { } else if (i == 1) {
for (int j = 0; j < kNumCoeffs; ++j) input_extreme_block[j] = -mask_; for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = -mask_;
} }
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( ASM_REGISTER_STATE_CHECK(
fwd_txfm_(input_extreme_block, output_block, stride)); fwd_txfm_(input_extreme_block, output_block, stride));
@ -240,13 +257,13 @@ 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, tran_low_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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, kNumCoeffs);
#endif #endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
@ -268,14 +285,13 @@ TEST_P(Trans32x32Test, InverseAccuracy) {
} }
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] = static_cast<tran_low_t>(round(out_r[j]));
}
if (bit_depth_ == VPX_BITS_8) { if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(inv_txfm_(coeff, dst, 32)); ASM_REGISTER_STATE_CHECK(inv_txfm_(coeff, dst, 32));
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
ASM_REGISTER_STATE_CHECK(inv_txfm_(coeff, CAST_TO_BYTEPTR(dst16), 32)); ASM_REGISTER_STATE_CHECK(inv_txfm_(coeff, CONVERT_TO_BYTEPTR(dst16), 32));
#endif #endif
} }
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
@ -286,92 +302,84 @@ TEST_P(Trans32x32Test, InverseAccuracy) {
const int diff = dst[j] - src[j]; const int diff = dst[j] - src[j];
#endif #endif
const int error = diff * diff; const int error = diff * diff;
EXPECT_GE(1, error) << "Error: 32x32 IDCT has error " << error EXPECT_GE(1, error)
<< " at index " << j; << "Error: 32x32 IDCT has error " << error
<< " at index " << j;
} }
} }
} }
using ::testing::make_tuple; using std::tr1::make_tuple;
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, Trans32x32Test, C, Trans32x32Test,
::testing::Values( ::testing::Values(
make_tuple(&vpx_highbd_fdct32x32_c, &idct32x32_10, 0, VPX_BITS_10), make_tuple(&vp9_highbd_fdct32x32_c,
make_tuple(&vpx_highbd_fdct32x32_rd_c, &idct32x32_10, 1, VPX_BITS_10), &idct32x32_10, 0, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct32x32_c, &idct32x32_12, 0, VPX_BITS_12), make_tuple(&vp9_highbd_fdct32x32_rd_c,
make_tuple(&vpx_highbd_fdct32x32_rd_c, &idct32x32_12, 1, VPX_BITS_12), &idct32x32_10, 1, VPX_BITS_10),
make_tuple(&vpx_fdct32x32_c, &vpx_idct32x32_1024_add_c, 0, VPX_BITS_8), make_tuple(&vp9_highbd_fdct32x32_c,
make_tuple(&vpx_fdct32x32_rd_c, &vpx_idct32x32_1024_add_c, 1, &idct32x32_12, 0, VPX_BITS_12),
VPX_BITS_8))); make_tuple(&vp9_highbd_fdct32x32_rd_c,
&idct32x32_12, 1, VPX_BITS_12),
make_tuple(&vp9_fdct32x32_c,
&vp9_idct32x32_1024_add_c, 0, VPX_BITS_8),
make_tuple(&vp9_fdct32x32_rd_c,
&vp9_idct32x32_1024_add_c, 1, VPX_BITS_8)));
#else #else
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, Trans32x32Test, C, Trans32x32Test,
::testing::Values(make_tuple(&vpx_fdct32x32_c, &vpx_idct32x32_1024_add_c, 0, ::testing::Values(
VPX_BITS_8), make_tuple(&vp9_fdct32x32_c,
make_tuple(&vpx_fdct32x32_rd_c, &vpx_idct32x32_1024_add_c, &vp9_idct32x32_1024_add_c, 0, VPX_BITS_8),
1, VPX_BITS_8))); make_tuple(&vp9_fdct32x32_rd_c,
&vp9_idct32x32_1024_add_c, 1, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
#if HAVE_NEON && !CONFIG_EMULATE_HARDWARE #if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
NEON, Trans32x32Test, NEON, Trans32x32Test,
::testing::Values(make_tuple(&vpx_fdct32x32_neon, ::testing::Values(
&vpx_idct32x32_1024_add_neon, 0, VPX_BITS_8), make_tuple(&vp9_fdct32x32_c,
make_tuple(&vpx_fdct32x32_rd_neon, &vp9_idct32x32_1024_add_neon, 0, VPX_BITS_8),
&vpx_idct32x32_1024_add_neon, 1, VPX_BITS_8))); make_tuple(&vp9_fdct32x32_rd_c,
#endif // HAVE_NEON && !CONFIG_EMULATE_HARDWARE &vp9_idct32x32_1024_add_neon, 1, VPX_BITS_8)));
#endif // HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans32x32Test, SSE2, Trans32x32Test,
::testing::Values(make_tuple(&vpx_fdct32x32_sse2, ::testing::Values(
&vpx_idct32x32_1024_add_sse2, 0, VPX_BITS_8), make_tuple(&vp9_fdct32x32_sse2,
make_tuple(&vpx_fdct32x32_rd_sse2, &vp9_idct32x32_1024_add_sse2, 0, VPX_BITS_8),
&vpx_idct32x32_1024_add_sse2, 1, VPX_BITS_8))); make_tuple(&vp9_fdct32x32_rd_sse2,
&vp9_idct32x32_1024_add_sse2, 1, VPX_BITS_8)));
#endif // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #endif // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, Trans32x32Test, SSE2, Trans32x32Test,
::testing::Values( ::testing::Values(
make_tuple(&vpx_highbd_fdct32x32_sse2, &idct32x32_10, 0, VPX_BITS_10), make_tuple(&vp9_highbd_fdct32x32_sse2, &idct32x32_10, 0, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct32x32_rd_sse2, &idct32x32_10, 1, make_tuple(&vp9_highbd_fdct32x32_rd_sse2, &idct32x32_10, 1,
VPX_BITS_10), VPX_BITS_10),
make_tuple(&vpx_highbd_fdct32x32_sse2, &idct32x32_12, 0, VPX_BITS_12), make_tuple(&vp9_highbd_fdct32x32_sse2, &idct32x32_12, 0, VPX_BITS_12),
make_tuple(&vpx_highbd_fdct32x32_rd_sse2, &idct32x32_12, 1, make_tuple(&vp9_highbd_fdct32x32_rd_sse2, &idct32x32_12, 1,
VPX_BITS_12), VPX_BITS_12),
make_tuple(&vpx_fdct32x32_sse2, &vpx_idct32x32_1024_add_c, 0, make_tuple(&vp9_fdct32x32_sse2, &vp9_idct32x32_1024_add_c, 0,
VPX_BITS_8), VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_sse2, &vpx_idct32x32_1024_add_c, 1, make_tuple(&vp9_fdct32x32_rd_sse2, &vp9_idct32x32_1024_add_c, 1,
VPX_BITS_8))); VPX_BITS_8)));
#endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
AVX2, Trans32x32Test, AVX2, Trans32x32Test,
::testing::Values(make_tuple(&vpx_fdct32x32_avx2, ::testing::Values(
&vpx_idct32x32_1024_add_sse2, 0, VPX_BITS_8), make_tuple(&vp9_fdct32x32_avx2,
make_tuple(&vpx_fdct32x32_rd_avx2, &vp9_idct32x32_1024_add_sse2, 0, VPX_BITS_8),
&vpx_idct32x32_1024_add_sse2, 1, VPX_BITS_8))); make_tuple(&vp9_fdct32x32_rd_avx2,
&vp9_idct32x32_1024_add_sse2, 1, VPX_BITS_8)));
#endif // HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #endif // HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_MSA && !CONFIG_VP9_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)));
#endif // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_VSX && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
VSX, Trans32x32Test,
::testing::Values(make_tuple(&vpx_fdct32x32_c, &vpx_idct32x32_1024_add_vsx,
0, VPX_BITS_8),
make_tuple(&vpx_fdct32x32_rd_c,
&vpx_idct32x32_1024_add_vsx, 1, VPX_BITS_8)));
#endif // HAVE_VSX && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace } // namespace

View File

@ -1,169 +0,0 @@
/*
* Copyright (c) 2017 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 <limits>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h"
#include "test/buffer.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "vpx/vpx_codec.h"
#include "vpx/vpx_integer.h"
#include "vpx_dsp/vpx_dsp_common.h"
using ::testing::make_tuple;
using ::testing::tuple;
using libvpx_test::ACMRandom;
using libvpx_test::Buffer;
namespace {
typedef void (*PartialFdctFunc)(const int16_t *in, tran_low_t *out, int stride);
typedef tuple<PartialFdctFunc, int /* size */, vpx_bit_depth_t>
PartialFdctParam;
tran_low_t partial_fdct_ref(const Buffer<int16_t> &in, int size) {
int64_t sum = 0;
for (int y = 0; y < size; ++y) {
for (int x = 0; x < size; ++x) {
sum += in.TopLeftPixel()[y * in.stride() + x];
}
}
switch (size) {
case 4: sum *= 2; break;
case 8: /*sum = sum;*/ break;
case 16: sum >>= 1; break;
case 32: sum >>= 3; break;
}
return static_cast<tran_low_t>(sum);
}
class PartialFdctTest : public ::testing::TestWithParam<PartialFdctParam> {
public:
PartialFdctTest() {
fwd_txfm_ = GET_PARAM(0);
size_ = GET_PARAM(1);
bit_depth_ = GET_PARAM(2);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
void RunTest() {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int16_t maxvalue =
clip_pixel_highbd(std::numeric_limits<int16_t>::max(), bit_depth_);
const int16_t minvalue = -maxvalue;
Buffer<int16_t> input_block =
Buffer<int16_t>(size_, size_, 8, size_ == 4 ? 0 : 16);
ASSERT_TRUE(input_block.Init());
Buffer<tran_low_t> output_block = Buffer<tran_low_t>(size_, size_, 0, 16);
ASSERT_TRUE(output_block.Init());
for (int i = 0; i < 100; ++i) {
if (i == 0) {
input_block.Set(maxvalue);
} else if (i == 1) {
input_block.Set(minvalue);
} else {
input_block.Set(&rnd, minvalue, maxvalue);
}
ASM_REGISTER_STATE_CHECK(fwd_txfm_(input_block.TopLeftPixel(),
output_block.TopLeftPixel(),
input_block.stride()));
EXPECT_EQ(partial_fdct_ref(input_block, size_),
output_block.TopLeftPixel()[0]);
}
}
PartialFdctFunc fwd_txfm_;
vpx_bit_depth_t bit_depth_;
int size_;
};
TEST_P(PartialFdctTest, PartialFdctTest) { RunTest(); }
#if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
C, PartialFdctTest,
::testing::Values(make_tuple(&vpx_highbd_fdct32x32_1_c, 32, VPX_BITS_12),
make_tuple(&vpx_highbd_fdct32x32_1_c, 32, VPX_BITS_10),
make_tuple(&vpx_fdct32x32_1_c, 32, VPX_BITS_8),
make_tuple(&vpx_highbd_fdct16x16_1_c, 16, VPX_BITS_12),
make_tuple(&vpx_highbd_fdct16x16_1_c, 16, VPX_BITS_10),
make_tuple(&vpx_fdct16x16_1_c, 16, VPX_BITS_8),
make_tuple(&vpx_highbd_fdct8x8_1_c, 8, VPX_BITS_12),
make_tuple(&vpx_highbd_fdct8x8_1_c, 8, VPX_BITS_10),
make_tuple(&vpx_fdct8x8_1_c, 8, VPX_BITS_8),
make_tuple(&vpx_fdct4x4_1_c, 4, VPX_BITS_8)));
#else
INSTANTIATE_TEST_CASE_P(
C, PartialFdctTest,
::testing::Values(make_tuple(&vpx_fdct32x32_1_c, 32, VPX_BITS_8),
make_tuple(&vpx_fdct16x16_1_c, 16, VPX_BITS_8),
make_tuple(&vpx_fdct8x8_1_c, 8, VPX_BITS_8),
make_tuple(&vpx_fdct4x4_1_c, 4, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(
SSE2, PartialFdctTest,
::testing::Values(make_tuple(&vpx_fdct32x32_1_sse2, 32, VPX_BITS_8),
make_tuple(&vpx_fdct16x16_1_sse2, 16, VPX_BITS_8),
make_tuple(&vpx_fdct8x8_1_sse2, 8, VPX_BITS_8),
make_tuple(&vpx_fdct4x4_1_sse2, 4, VPX_BITS_8)));
#endif // HAVE_SSE2
#if HAVE_NEON
#if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
NEON, PartialFdctTest,
::testing::Values(make_tuple(&vpx_fdct32x32_1_neon, 32, VPX_BITS_8),
make_tuple(&vpx_fdct16x16_1_neon, 16, VPX_BITS_8),
make_tuple(&vpx_fdct8x8_1_neon, 8, VPX_BITS_12),
make_tuple(&vpx_fdct8x8_1_neon, 8, VPX_BITS_10),
make_tuple(&vpx_fdct8x8_1_neon, 8, VPX_BITS_8),
make_tuple(&vpx_fdct4x4_1_neon, 4, VPX_BITS_8)));
#else
INSTANTIATE_TEST_CASE_P(
NEON, PartialFdctTest,
::testing::Values(make_tuple(&vpx_fdct32x32_1_neon, 32, VPX_BITS_8),
make_tuple(&vpx_fdct16x16_1_neon, 16, VPX_BITS_8),
make_tuple(&vpx_fdct8x8_1_neon, 8, VPX_BITS_8),
make_tuple(&vpx_fdct4x4_1_neon, 4, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // HAVE_NEON
#if HAVE_MSA
#if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(MSA, PartialFdctTest,
::testing::Values(make_tuple(&vpx_fdct8x8_1_msa, 8,
VPX_BITS_8)));
#else // !CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
MSA, PartialFdctTest,
::testing::Values(make_tuple(&vpx_fdct32x32_1_msa, 32, VPX_BITS_8),
make_tuple(&vpx_fdct16x16_1_msa, 16, VPX_BITS_8),
make_tuple(&vpx_fdct8x8_1_msa, 8, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // HAVE_MSA
} // namespace

View File

@ -1,728 +0,0 @@
/*
* Copyright (c) 2017 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 "./vp9_rtcd.h"
#include "./vpx_dsp_rtcd.h"
#include "test/acm_random.h"
#include "test/buffer.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_codec.h"
#include "vpx/vpx_integer.h"
#include "vpx_ports/mem.h"
using ::testing::make_tuple;
using ::testing::tuple;
using libvpx_test::ACMRandom;
using libvpx_test::Buffer;
namespace {
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);
typedef void (*FhtFuncRef)(const Buffer<int16_t> &in, Buffer<tran_low_t> *out,
int size, int tx_type);
typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride,
int tx_type);
typedef void (*IhtWithBdFunc)(const tran_low_t *in, uint8_t *out, int stride,
int tx_type, int bd);
template <FdctFunc fn>
void fdct_wrapper(const int16_t *in, tran_low_t *out, int stride, int tx_type) {
(void)tx_type;
fn(in, out, stride);
}
template <IdctFunc fn>
void idct_wrapper(const tran_low_t *in, uint8_t *out, int stride, int tx_type,
int bd) {
(void)tx_type;
(void)bd;
fn(in, out, stride);
}
template <IhtFunc fn>
void iht_wrapper(const tran_low_t *in, uint8_t *out, int stride, int tx_type,
int bd) {
(void)bd;
fn(in, out, stride, tx_type);
}
#if CONFIG_VP9_HIGHBITDEPTH
typedef void (*HighbdIdctFunc)(const tran_low_t *in, uint16_t *out, int stride,
int bd);
typedef void (*HighbdIhtFunc)(const tran_low_t *in, uint16_t *out, int stride,
int tx_type, int bd);
template <HighbdIdctFunc fn>
void highbd_idct_wrapper(const tran_low_t *in, uint8_t *out, int stride,
int tx_type, int bd) {
(void)tx_type;
fn(in, CAST_TO_SHORTPTR(out), stride, bd);
}
template <HighbdIhtFunc fn>
void highbd_iht_wrapper(const tran_low_t *in, uint8_t *out, int stride,
int tx_type, int bd) {
fn(in, CAST_TO_SHORTPTR(out), stride, tx_type, bd);
}
#endif // CONFIG_VP9_HIGHBITDEPTH
struct FuncInfo {
FhtFunc ft_func;
IhtWithBdFunc it_func;
int size;
int pixel_size;
};
/* forward transform, inverse transform, size, transform type, bit depth */
typedef tuple<int, const FuncInfo *, int, vpx_bit_depth_t> DctParam;
void fdct_ref(const Buffer<int16_t> &in, Buffer<tran_low_t> *out, int size,
int /*tx_type*/) {
const int16_t *i = in.TopLeftPixel();
const int i_stride = in.stride();
tran_low_t *o = out->TopLeftPixel();
if (size == 4) {
vpx_fdct4x4_c(i, o, i_stride);
} else if (size == 8) {
vpx_fdct8x8_c(i, o, i_stride);
} else if (size == 16) {
vpx_fdct16x16_c(i, o, i_stride);
} else if (size == 32) {
vpx_fdct32x32_c(i, o, i_stride);
}
}
void fht_ref(const Buffer<int16_t> &in, Buffer<tran_low_t> *out, int size,
int tx_type) {
const int16_t *i = in.TopLeftPixel();
const int i_stride = in.stride();
tran_low_t *o = out->TopLeftPixel();
if (size == 4) {
vp9_fht4x4_c(i, o, i_stride, tx_type);
} else if (size == 8) {
vp9_fht8x8_c(i, o, i_stride, tx_type);
} else if (size == 16) {
vp9_fht16x16_c(i, o, i_stride, tx_type);
}
}
void fwht_ref(const Buffer<int16_t> &in, Buffer<tran_low_t> *out, int size,
int /*tx_type*/) {
ASSERT_EQ(size, 4);
vp9_fwht4x4_c(in.TopLeftPixel(), out->TopLeftPixel(), in.stride());
}
class TransTestBase : public ::testing::TestWithParam<DctParam> {
public:
virtual void SetUp() {
rnd_.Reset(ACMRandom::DeterministicSeed());
const int idx = GET_PARAM(0);
const FuncInfo *func_info = &(GET_PARAM(1)[idx]);
tx_type_ = GET_PARAM(2);
bit_depth_ = GET_PARAM(3);
fwd_txfm_ = func_info->ft_func;
inv_txfm_ = func_info->it_func;
size_ = func_info->size;
pixel_size_ = func_info->pixel_size;
max_pixel_value_ = (1 << bit_depth_) - 1;
// Randomize stride_ to a value less than or equal to 1024
stride_ = rnd_(1024) + 1;
if (stride_ < size_) {
stride_ = size_;
}
// Align stride_ to 16 if it's bigger than 16.
if (stride_ > 16) {
stride_ &= ~15;
}
block_size_ = size_ * stride_;
src_ = reinterpret_cast<uint8_t *>(
vpx_memalign(16, pixel_size_ * block_size_));
ASSERT_TRUE(src_ != NULL);
dst_ = reinterpret_cast<uint8_t *>(
vpx_memalign(16, pixel_size_ * block_size_));
ASSERT_TRUE(dst_ != NULL);
}
virtual void TearDown() {
vpx_free(src_);
src_ = NULL;
vpx_free(dst_);
dst_ = NULL;
libvpx_test::ClearSystemState();
}
void InitMem() {
if (pixel_size_ == 1 && bit_depth_ > VPX_BITS_8) return;
if (pixel_size_ == 1) {
for (int j = 0; j < block_size_; ++j) {
src_[j] = rnd_.Rand16() & max_pixel_value_;
}
for (int j = 0; j < block_size_; ++j) {
dst_[j] = rnd_.Rand16() & max_pixel_value_;
}
} else {
ASSERT_EQ(pixel_size_, 2);
uint16_t *const src = reinterpret_cast<uint16_t *>(src_);
uint16_t *const dst = reinterpret_cast<uint16_t *>(dst_);
for (int j = 0; j < block_size_; ++j) {
src[j] = rnd_.Rand16() & max_pixel_value_;
}
for (int j = 0; j < block_size_; ++j) {
dst[j] = rnd_.Rand16() & max_pixel_value_;
}
}
}
void RunFwdTxfm(const Buffer<int16_t> &in, Buffer<tran_low_t> *out) {
fwd_txfm_(in.TopLeftPixel(), out->TopLeftPixel(), in.stride(), tx_type_);
}
void RunInvTxfm(const Buffer<tran_low_t> &in, uint8_t *out) {
inv_txfm_(in.TopLeftPixel(), out, stride_, tx_type_, bit_depth_);
}
protected:
void RunAccuracyCheck(int limit) {
if (pixel_size_ == 1 && bit_depth_ > VPX_BITS_8) return;
ACMRandom rnd(ACMRandom::DeterministicSeed());
Buffer<int16_t> test_input_block =
Buffer<int16_t>(size_, size_, 8, size_ == 4 ? 0 : 16);
ASSERT_TRUE(test_input_block.Init());
Buffer<tran_low_t> test_temp_block =
Buffer<tran_low_t>(size_, size_, 0, 16);
ASSERT_TRUE(test_temp_block.Init());
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) {
InitMem();
for (int h = 0; h < size_; ++h) {
for (int w = 0; w < size_; ++w) {
if (pixel_size_ == 1) {
test_input_block.TopLeftPixel()[h * test_input_block.stride() + w] =
src_[h * stride_ + w] - dst_[h * stride_ + w];
} else {
ASSERT_EQ(pixel_size_, 2);
const uint16_t *const src = reinterpret_cast<uint16_t *>(src_);
const uint16_t *const dst = reinterpret_cast<uint16_t *>(dst_);
test_input_block.TopLeftPixel()[h * test_input_block.stride() + w] =
src[h * stride_ + w] - dst[h * stride_ + w];
}
}
}
ASM_REGISTER_STATE_CHECK(RunFwdTxfm(test_input_block, &test_temp_block));
ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst_));
for (int h = 0; h < size_; ++h) {
for (int w = 0; w < size_; ++w) {
int diff;
if (pixel_size_ == 1) {
diff = dst_[h * stride_ + w] - src_[h * stride_ + w];
} else {
ASSERT_EQ(pixel_size_, 2);
const uint16_t *const src = reinterpret_cast<uint16_t *>(src_);
const uint16_t *const dst = reinterpret_cast<uint16_t *>(dst_);
diff = dst[h * stride_ + w] - src[h * stride_ + w];
}
const uint32_t error = diff * diff;
if (max_error < error) max_error = error;
total_error += error;
}
}
}
EXPECT_GE(static_cast<uint32_t>(limit), max_error)
<< "Error: " << size_ << "x" << size_
<< " transform/inverse transform has an individual round trip error > "
<< limit;
EXPECT_GE(count_test_block * limit, total_error)
<< "Error: " << size_ << "x" << size_
<< " transform/inverse transform has average round trip error > "
<< limit << " per block";
}
void RunCoeffCheck() {
if (pixel_size_ == 1 && bit_depth_ > VPX_BITS_8) return;
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 5000;
Buffer<int16_t> input_block =
Buffer<int16_t>(size_, size_, 8, size_ == 4 ? 0 : 16);
ASSERT_TRUE(input_block.Init());
Buffer<tran_low_t> output_ref_block = Buffer<tran_low_t>(size_, size_, 0);
ASSERT_TRUE(output_ref_block.Init());
Buffer<tran_low_t> output_block = Buffer<tran_low_t>(size_, size_, 0, 16);
ASSERT_TRUE(output_block.Init());
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-max_pixel_value_,
// max_pixel_value_].
input_block.Set(&rnd, -max_pixel_value_, max_pixel_value_);
fwd_txfm_ref(input_block, &output_ref_block, size_, tx_type_);
ASM_REGISTER_STATE_CHECK(RunFwdTxfm(input_block, &output_block));
// The minimum quant value is 4.
EXPECT_TRUE(output_block.CheckValues(output_ref_block));
if (::testing::Test::HasFailure()) {
printf("Size: %d Transform type: %d\n", size_, tx_type_);
output_block.PrintDifference(output_ref_block);
return;
}
}
}
void RunMemCheck() {
if (pixel_size_ == 1 && bit_depth_ > VPX_BITS_8) return;
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 5000;
Buffer<int16_t> input_extreme_block =
Buffer<int16_t>(size_, size_, 8, size_ == 4 ? 0 : 16);
ASSERT_TRUE(input_extreme_block.Init());
Buffer<tran_low_t> output_ref_block = Buffer<tran_low_t>(size_, size_, 0);
ASSERT_TRUE(output_ref_block.Init());
Buffer<tran_low_t> output_block = Buffer<tran_low_t>(size_, size_, 0, 16);
ASSERT_TRUE(output_block.Init());
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with -max_pixel_value_ or max_pixel_value_.
if (i == 0) {
input_extreme_block.Set(max_pixel_value_);
} else if (i == 1) {
input_extreme_block.Set(-max_pixel_value_);
} else {
for (int h = 0; h < size_; ++h) {
for (int w = 0; w < size_; ++w) {
input_extreme_block
.TopLeftPixel()[h * input_extreme_block.stride() + w] =
rnd.Rand8() % 2 ? max_pixel_value_ : -max_pixel_value_;
}
}
}
fwd_txfm_ref(input_extreme_block, &output_ref_block, size_, tx_type_);
ASM_REGISTER_STATE_CHECK(RunFwdTxfm(input_extreme_block, &output_block));
// The minimum quant value is 4.
EXPECT_TRUE(output_block.CheckValues(output_ref_block));
for (int h = 0; h < size_; ++h) {
for (int w = 0; w < size_; ++w) {
EXPECT_GE(
4 * DCT_MAX_VALUE << (bit_depth_ - 8),
abs(output_block.TopLeftPixel()[h * output_block.stride() + w]))
<< "Error: " << size_ << "x" << size_
<< " transform has coefficient larger than 4*DCT_MAX_VALUE"
<< " at " << w << "," << h;
if (::testing::Test::HasFailure()) {
printf("Size: %d Transform type: %d\n", size_, tx_type_);
output_block.DumpBuffer();
return;
}
}
}
}
}
void RunInvAccuracyCheck(int limit) {
if (pixel_size_ == 1 && bit_depth_ > VPX_BITS_8) return;
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 1000;
Buffer<int16_t> in = Buffer<int16_t>(size_, size_, 4);
ASSERT_TRUE(in.Init());
Buffer<tran_low_t> coeff = Buffer<tran_low_t>(size_, size_, 0, 16);
ASSERT_TRUE(coeff.Init());
Buffer<uint8_t> dst = Buffer<uint8_t>(size_, size_, 0, 16);
ASSERT_TRUE(dst.Init());
Buffer<uint8_t> src = Buffer<uint8_t>(size_, size_, 0);
ASSERT_TRUE(src.Init());
Buffer<uint16_t> dst16 = Buffer<uint16_t>(size_, size_, 0, 16);
ASSERT_TRUE(dst16.Init());
Buffer<uint16_t> src16 = Buffer<uint16_t>(size_, size_, 0);
ASSERT_TRUE(src16.Init());
for (int i = 0; i < count_test_block; ++i) {
InitMem();
// Initialize a test block with input range [-max_pixel_value_,
// max_pixel_value_].
for (int h = 0; h < size_; ++h) {
for (int w = 0; w < size_; ++w) {
if (pixel_size_ == 1) {
in.TopLeftPixel()[h * in.stride() + w] =
src_[h * stride_ + w] - dst_[h * stride_ + w];
} else {
ASSERT_EQ(pixel_size_, 2);
const uint16_t *const src = reinterpret_cast<uint16_t *>(src_);
const uint16_t *const dst = reinterpret_cast<uint16_t *>(dst_);
in.TopLeftPixel()[h * in.stride() + w] =
src[h * stride_ + w] - dst[h * stride_ + w];
}
}
}
fwd_txfm_ref(in, &coeff, size_, tx_type_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst_));
for (int h = 0; h < size_; ++h) {
for (int w = 0; w < size_; ++w) {
int diff;
if (pixel_size_ == 1) {
diff = dst_[h * stride_ + w] - src_[h * stride_ + w];
} else {
ASSERT_EQ(pixel_size_, 2);
const uint16_t *const src = reinterpret_cast<uint16_t *>(src_);
const uint16_t *const dst = reinterpret_cast<uint16_t *>(dst_);
diff = dst[h * stride_ + w] - src[h * stride_ + w];
}
const uint32_t error = diff * diff;
EXPECT_GE(static_cast<uint32_t>(limit), error)
<< "Error: " << size_ << "x" << size_
<< " inverse transform has error " << error << " at " << w << ","
<< h;
if (::testing::Test::HasFailure()) {
printf("Size: %d Transform type: %d\n", size_, tx_type_);
return;
}
}
}
}
}
FhtFunc fwd_txfm_;
FhtFuncRef fwd_txfm_ref;
IhtWithBdFunc inv_txfm_;
ACMRandom rnd_;
uint8_t *src_;
uint8_t *dst_;
vpx_bit_depth_t bit_depth_;
int tx_type_;
int max_pixel_value_;
int size_;
int stride_;
int pixel_size_;
int block_size_;
};
/* -------------------------------------------------------------------------- */
class TransDCT : public TransTestBase {
public:
TransDCT() { fwd_txfm_ref = fdct_ref; }
};
TEST_P(TransDCT, AccuracyCheck) {
int t = 1;
if (size_ == 16 && bit_depth_ > 10 && pixel_size_ == 2) {
t = 2;
} else if (size_ == 32 && bit_depth_ > 10 && pixel_size_ == 2) {
t = 7;
}
RunAccuracyCheck(t);
}
TEST_P(TransDCT, CoeffCheck) { RunCoeffCheck(); }
TEST_P(TransDCT, MemCheck) { RunMemCheck(); }
TEST_P(TransDCT, InvAccuracyCheck) { RunInvAccuracyCheck(1); }
static const FuncInfo dct_c_func_info[] = {
#if CONFIG_VP9_HIGHBITDEPTH
{ &fdct_wrapper<vpx_highbd_fdct4x4_c>,
&highbd_idct_wrapper<vpx_highbd_idct4x4_16_add_c>, 4, 2 },
{ &fdct_wrapper<vpx_highbd_fdct8x8_c>,
&highbd_idct_wrapper<vpx_highbd_idct8x8_64_add_c>, 8, 2 },
{ &fdct_wrapper<vpx_highbd_fdct16x16_c>,
&highbd_idct_wrapper<vpx_highbd_idct16x16_256_add_c>, 16, 2 },
{ &fdct_wrapper<vpx_highbd_fdct32x32_c>,
&highbd_idct_wrapper<vpx_highbd_idct32x32_1024_add_c>, 32, 2 },
#endif
{ &fdct_wrapper<vpx_fdct4x4_c>, &idct_wrapper<vpx_idct4x4_16_add_c>, 4, 1 },
{ &fdct_wrapper<vpx_fdct8x8_c>, &idct_wrapper<vpx_idct8x8_64_add_c>, 8, 1 },
{ &fdct_wrapper<vpx_fdct16x16_c>, &idct_wrapper<vpx_idct16x16_256_add_c>, 16,
1 },
{ &fdct_wrapper<vpx_fdct32x32_c>, &idct_wrapper<vpx_idct32x32_1024_add_c>, 32,
1 }
};
INSTANTIATE_TEST_CASE_P(
C, TransDCT,
::testing::Combine(
::testing::Range(0, static_cast<int>(sizeof(dct_c_func_info) /
sizeof(dct_c_func_info[0]))),
::testing::Values(dct_c_func_info), ::testing::Values(0),
::testing::Values(VPX_BITS_8, VPX_BITS_10, VPX_BITS_12)));
#if !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2
static const FuncInfo dct_sse2_func_info[] = {
#if CONFIG_VP9_HIGHBITDEPTH
{ &fdct_wrapper<vpx_highbd_fdct4x4_sse2>,
&highbd_idct_wrapper<vpx_highbd_idct4x4_16_add_sse2>, 4, 2 },
{ &fdct_wrapper<vpx_highbd_fdct8x8_sse2>,
&highbd_idct_wrapper<vpx_highbd_idct8x8_64_add_sse2>, 8, 2 },
{ &fdct_wrapper<vpx_highbd_fdct16x16_sse2>,
&highbd_idct_wrapper<vpx_highbd_idct16x16_256_add_sse2>, 16, 2 },
{ &fdct_wrapper<vpx_highbd_fdct32x32_sse2>,
&highbd_idct_wrapper<vpx_highbd_idct32x32_1024_add_sse2>, 32, 2 },
#endif
{ &fdct_wrapper<vpx_fdct4x4_sse2>, &idct_wrapper<vpx_idct4x4_16_add_sse2>, 4,
1 },
{ &fdct_wrapper<vpx_fdct8x8_sse2>, &idct_wrapper<vpx_idct8x8_64_add_sse2>, 8,
1 },
{ &fdct_wrapper<vpx_fdct16x16_sse2>,
&idct_wrapper<vpx_idct16x16_256_add_sse2>, 16, 1 },
{ &fdct_wrapper<vpx_fdct32x32_sse2>,
&idct_wrapper<vpx_idct32x32_1024_add_sse2>, 32, 1 }
};
INSTANTIATE_TEST_CASE_P(
SSE2, TransDCT,
::testing::Combine(
::testing::Range(0, static_cast<int>(sizeof(dct_sse2_func_info) /
sizeof(dct_sse2_func_info[0]))),
::testing::Values(dct_sse2_func_info), ::testing::Values(0),
::testing::Values(VPX_BITS_8, VPX_BITS_10, VPX_BITS_12)));
#endif // HAVE_SSE2
#if HAVE_SSSE3 && !CONFIG_VP9_HIGHBITDEPTH && ARCH_X86_64
// vpx_fdct8x8_ssse3 is only available in 64 bit builds.
static const FuncInfo dct_ssse3_func_info = {
&fdct_wrapper<vpx_fdct8x8_ssse3>, &idct_wrapper<vpx_idct8x8_64_add_sse2>, 8, 1
};
// TODO(johannkoenig): high bit depth fdct8x8.
INSTANTIATE_TEST_CASE_P(SSSE3, TransDCT,
::testing::Values(make_tuple(0, &dct_ssse3_func_info, 0,
VPX_BITS_8)));
#endif // HAVE_SSSE3 && !CONFIG_VP9_HIGHBITDEPTH && ARCH_X86_64
#if HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH
static const FuncInfo dct_avx2_func_info = {
&fdct_wrapper<vpx_fdct32x32_avx2>, &idct_wrapper<vpx_idct32x32_1024_add_sse2>,
32, 1
};
// TODO(johannkoenig): high bit depth fdct32x32.
INSTANTIATE_TEST_CASE_P(AVX2, TransDCT,
::testing::Values(make_tuple(0, &dct_avx2_func_info, 0,
VPX_BITS_8)));
#endif // HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH
#if HAVE_NEON
static const FuncInfo dct_neon_func_info[4] = {
{ &fdct_wrapper<vpx_fdct4x4_neon>, &idct_wrapper<vpx_idct4x4_16_add_neon>, 4,
1 },
{ &fdct_wrapper<vpx_fdct8x8_neon>, &idct_wrapper<vpx_idct8x8_64_add_neon>, 8,
1 },
{ &fdct_wrapper<vpx_fdct16x16_neon>,
&idct_wrapper<vpx_idct16x16_256_add_neon>, 16, 1 },
{ &fdct_wrapper<vpx_fdct32x32_neon>,
&idct_wrapper<vpx_idct32x32_1024_add_neon>, 32, 1 }
};
INSTANTIATE_TEST_CASE_P(
NEON, TransDCT,
::testing::Combine(::testing::Range(0, 4),
::testing::Values(dct_neon_func_info),
::testing::Values(0), ::testing::Values(VPX_BITS_8)));
#endif // HAVE_NEON
#if HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH
static const FuncInfo dct_msa_func_info[4] = {
{ &fdct_wrapper<vpx_fdct4x4_msa>, &idct_wrapper<vpx_idct4x4_16_add_msa>, 4,
1 },
{ &fdct_wrapper<vpx_fdct8x8_msa>, &idct_wrapper<vpx_idct8x8_64_add_msa>, 8,
1 },
{ &fdct_wrapper<vpx_fdct16x16_msa>, &idct_wrapper<vpx_idct16x16_256_add_msa>,
16, 1 },
{ &fdct_wrapper<vpx_fdct32x32_msa>, &idct_wrapper<vpx_idct32x32_1024_add_msa>,
32, 1 }
};
INSTANTIATE_TEST_CASE_P(MSA, TransDCT,
::testing::Combine(::testing::Range(0, 4),
::testing::Values(dct_msa_func_info),
::testing::Values(0),
::testing::Values(VPX_BITS_8)));
#endif // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH
#if HAVE_VSX && !CONFIG_VP9_HIGHBITDEPTH
static const FuncInfo dct_vsx_func_info = {
&fdct_wrapper<vpx_fdct4x4_c>, &idct_wrapper<vpx_idct4x4_16_add_vsx>, 4, 1
};
INSTANTIATE_TEST_CASE_P(VSX, TransDCT,
::testing::Values(make_tuple(0, &dct_vsx_func_info, 0,
VPX_BITS_8)));
#endif // HAVE_VSX && !CONFIG_VP9_HIGHBITDEPTH &&
#endif // !CONFIG_EMULATE_HARDWARE
/* -------------------------------------------------------------------------- */
class TransHT : public TransTestBase {
public:
TransHT() { fwd_txfm_ref = fht_ref; }
};
TEST_P(TransHT, AccuracyCheck) {
RunAccuracyCheck(size_ == 16 && bit_depth_ > 10 && pixel_size_ == 2 ? 2 : 1);
}
TEST_P(TransHT, CoeffCheck) { RunCoeffCheck(); }
TEST_P(TransHT, MemCheck) { RunMemCheck(); }
TEST_P(TransHT, InvAccuracyCheck) { RunInvAccuracyCheck(1); }
static const FuncInfo ht_c_func_info[] = {
#if CONFIG_VP9_HIGHBITDEPTH
{ &vp9_highbd_fht4x4_c, &highbd_iht_wrapper<vp9_highbd_iht4x4_16_add_c>, 4,
2 },
{ &vp9_highbd_fht8x8_c, &highbd_iht_wrapper<vp9_highbd_iht8x8_64_add_c>, 8,
2 },
{ &vp9_highbd_fht16x16_c, &highbd_iht_wrapper<vp9_highbd_iht16x16_256_add_c>,
16, 2 },
#endif
{ &vp9_fht4x4_c, &iht_wrapper<vp9_iht4x4_16_add_c>, 4, 1 },
{ &vp9_fht8x8_c, &iht_wrapper<vp9_iht8x8_64_add_c>, 8, 1 },
{ &vp9_fht16x16_c, &iht_wrapper<vp9_iht16x16_256_add_c>, 16, 1 }
};
INSTANTIATE_TEST_CASE_P(
C, TransHT,
::testing::Combine(
::testing::Range(0, static_cast<int>(sizeof(ht_c_func_info) /
sizeof(ht_c_func_info[0]))),
::testing::Values(ht_c_func_info), ::testing::Range(0, 4),
::testing::Values(VPX_BITS_8, VPX_BITS_10, VPX_BITS_12)));
#if !CONFIG_EMULATE_HARDWARE
#if HAVE_NEON
static const FuncInfo ht_neon_func_info[] = {
#if CONFIG_VP9_HIGHBITDEPTH
{ &vp9_highbd_fht4x4_c, &highbd_iht_wrapper<vp9_highbd_iht4x4_16_add_neon>, 4,
2 },
{ &vp9_highbd_fht8x8_c, &highbd_iht_wrapper<vp9_highbd_iht8x8_64_add_neon>, 8,
2 },
{ &vp9_highbd_fht16x16_c,
&highbd_iht_wrapper<vp9_highbd_iht16x16_256_add_neon>, 16, 2 },
#endif
{ &vp9_fht4x4_c, &iht_wrapper<vp9_iht4x4_16_add_neon>, 4, 1 },
{ &vp9_fht8x8_c, &iht_wrapper<vp9_iht8x8_64_add_neon>, 8, 1 },
{ &vp9_fht16x16_c, &iht_wrapper<vp9_iht16x16_256_add_neon>, 16, 1 }
};
INSTANTIATE_TEST_CASE_P(
NEON, TransHT,
::testing::Combine(
::testing::Range(0, static_cast<int>(sizeof(ht_neon_func_info) /
sizeof(ht_neon_func_info[0]))),
::testing::Values(ht_neon_func_info), ::testing::Range(0, 4),
::testing::Values(VPX_BITS_8, VPX_BITS_10, VPX_BITS_12)));
#endif // HAVE_NEON
#if HAVE_SSE2
static const FuncInfo ht_sse2_func_info[3] = {
{ &vp9_fht4x4_sse2, &iht_wrapper<vp9_iht4x4_16_add_sse2>, 4, 1 },
{ &vp9_fht8x8_sse2, &iht_wrapper<vp9_iht8x8_64_add_sse2>, 8, 1 },
{ &vp9_fht16x16_sse2, &iht_wrapper<vp9_iht16x16_256_add_sse2>, 16, 1 }
};
INSTANTIATE_TEST_CASE_P(SSE2, TransHT,
::testing::Combine(::testing::Range(0, 3),
::testing::Values(ht_sse2_func_info),
::testing::Range(0, 4),
::testing::Values(VPX_BITS_8)));
#endif // HAVE_SSE2
#if HAVE_SSE4_1 && CONFIG_VP9_HIGHBITDEPTH
static const FuncInfo ht_sse4_1_func_info[3] = {
{ &vp9_highbd_fht4x4_c, &highbd_iht_wrapper<vp9_highbd_iht4x4_16_add_sse4_1>,
4, 2 },
{ vp9_highbd_fht8x8_c, &highbd_iht_wrapper<vp9_highbd_iht8x8_64_add_sse4_1>,
8, 2 },
{ &vp9_highbd_fht16x16_c,
&highbd_iht_wrapper<vp9_highbd_iht16x16_256_add_sse4_1>, 16, 2 }
};
INSTANTIATE_TEST_CASE_P(
SSE4_1, TransHT,
::testing::Combine(::testing::Range(0, 3),
::testing::Values(ht_sse4_1_func_info),
::testing::Range(0, 4),
::testing::Values(VPX_BITS_8, VPX_BITS_10,
VPX_BITS_12)));
#endif // HAVE_SSE4_1 && CONFIG_VP9_HIGHBITDEPTH
#endif // !CONFIG_EMULATE_HARDWARE
/* -------------------------------------------------------------------------- */
class TransWHT : public TransTestBase {
public:
TransWHT() { fwd_txfm_ref = fwht_ref; }
};
TEST_P(TransWHT, AccuracyCheck) { RunAccuracyCheck(0); }
TEST_P(TransWHT, CoeffCheck) { RunCoeffCheck(); }
TEST_P(TransWHT, MemCheck) { RunMemCheck(); }
TEST_P(TransWHT, InvAccuracyCheck) { RunInvAccuracyCheck(0); }
static const FuncInfo wht_c_func_info[] = {
#if CONFIG_VP9_HIGHBITDEPTH
{ &fdct_wrapper<vp9_highbd_fwht4x4_c>,
&highbd_idct_wrapper<vpx_highbd_iwht4x4_16_add_c>, 4, 2 },
#endif
{ &fdct_wrapper<vp9_fwht4x4_c>, &idct_wrapper<vpx_iwht4x4_16_add_c>, 4, 1 }
};
INSTANTIATE_TEST_CASE_P(
C, TransWHT,
::testing::Combine(
::testing::Range(0, static_cast<int>(sizeof(wht_c_func_info) /
sizeof(wht_c_func_info[0]))),
::testing::Values(wht_c_func_info), ::testing::Values(0),
::testing::Values(VPX_BITS_8, VPX_BITS_10, VPX_BITS_12)));
#if HAVE_SSE2 && !CONFIG_EMULATE_HARDWARE
static const FuncInfo wht_sse2_func_info = {
&fdct_wrapper<vp9_fwht4x4_sse2>, &idct_wrapper<vpx_iwht4x4_16_add_sse2>, 4, 1
};
INSTANTIATE_TEST_CASE_P(SSE2, TransWHT,
::testing::Values(make_tuple(0, &wht_sse2_func_info, 0,
VPX_BITS_8)));
#endif // HAVE_SSE2 && !CONFIG_EMULATE_HARDWARE
} // namespace

View File

@ -7,11 +7,10 @@
* 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 "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "test/ivf_video_source.h" #include "test/ivf_video_source.h"
#include "./vpx_config.h"
#include "vpx/vp8dx.h" #include "vpx/vp8dx.h"
#include "vpx/vpx_decoder.h" #include "vpx/vpx_decoder.h"
@ -28,7 +27,7 @@ TEST(DecodeAPI, InvalidParams) {
&vpx_codec_vp9_dx_algo, &vpx_codec_vp9_dx_algo,
#endif #endif
}; };
uint8_t buf[1] = { 0 }; uint8_t buf[1] = {0};
vpx_codec_ctx_t dec; 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(NULL, NULL, NULL, 0));
@ -51,7 +50,8 @@ TEST(DecodeAPI, InvalidParams) {
vpx_codec_decode(&dec, buf, NELEMENTS(buf), NULL, 0)); vpx_codec_decode(&dec, buf, NELEMENTS(buf), NULL, 0));
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_decode(&dec, NULL, NELEMENTS(buf), NULL, 0)); 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_INVALID_PARAM,
vpx_codec_decode(&dec, buf, 0, NULL, 0));
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_destroy(&dec)); EXPECT_EQ(VPX_CODEC_OK, vpx_codec_destroy(&dec));
} }
@ -76,9 +76,12 @@ TEST(DecodeAPI, OptionalParams) {
// Test VP9 codec controls after a decode error to ensure the code doesn't // Test VP9 codec controls after a decode error to ensure the code doesn't
// misbehave. // misbehave.
void TestVp9Controls(vpx_codec_ctx_t *dec) { void TestVp9Controls(vpx_codec_ctx_t *dec) {
static const int kControls[] = { VP8D_GET_LAST_REF_UPDATES, static const int kControls[] = {
VP8D_GET_FRAME_CORRUPTED, VP8D_GET_LAST_REF_UPDATES,
VP9D_GET_DISPLAY_SIZE, VP9D_GET_FRAME_SIZE }; VP8D_GET_FRAME_CORRUPTED,
VP9D_GET_DISPLAY_SIZE,
VP9D_GET_FRAME_SIZE
};
int val[2]; int val[2];
for (int i = 0; i < NELEMENTS(kControls); ++i) { for (int i = 0; i < NELEMENTS(kControls); ++i) {
@ -87,7 +90,9 @@ void TestVp9Controls(vpx_codec_ctx_t *dec) {
case VP8D_GET_FRAME_CORRUPTED: case VP8D_GET_FRAME_CORRUPTED:
EXPECT_EQ(VPX_CODEC_ERROR, res) << kControls[i]; EXPECT_EQ(VPX_CODEC_ERROR, res) << kControls[i];
break; break;
default: EXPECT_EQ(VPX_CODEC_OK, res) << kControls[i]; break; default:
EXPECT_EQ(VPX_CODEC_OK, res) << kControls[i];
break;
} }
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, EXPECT_EQ(VPX_CODEC_INVALID_PARAM,
vpx_codec_control_(dec, kControls[i], NULL)); vpx_codec_control_(dec, kControls[i], NULL));
@ -124,69 +129,14 @@ TEST(DecodeAPI, Vp9InvalidDecode) {
vpx_codec_ctx_t dec; vpx_codec_ctx_t dec;
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_dec_init(&dec, codec, NULL, 0)); EXPECT_EQ(VPX_CODEC_OK, vpx_codec_dec_init(&dec, codec, NULL, 0));
const uint32_t frame_size = static_cast<uint32_t>(video.frame_size()); const uint32_t frame_size = static_cast<uint32_t>(video.frame_size());
#if CONFIG_VP9_HIGHBITDEPTH
EXPECT_EQ(VPX_CODEC_MEM_ERROR, EXPECT_EQ(VPX_CODEC_MEM_ERROR,
vpx_codec_decode(&dec, video.cxdata(), frame_size, NULL, 0)); vpx_codec_decode(&dec, video.cxdata(), frame_size, NULL, 0));
#else
EXPECT_EQ(VPX_CODEC_UNSUP_BITSTREAM,
vpx_codec_decode(&dec, video.cxdata(), frame_size, NULL, 0));
#endif
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
EXPECT_EQ(NULL, vpx_codec_get_frame(&dec, &iter)); EXPECT_EQ(NULL, vpx_codec_get_frame(&dec, &iter));
TestVp9Controls(&dec); TestVp9Controls(&dec);
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_destroy(&dec)); EXPECT_EQ(VPX_CODEC_OK, vpx_codec_destroy(&dec));
} }
TEST(DecodeAPI, Vp9PeekSI) {
const vpx_codec_iface_t *const codec = &vpx_codec_vp9_dx_algo;
// The first 9 bytes are valid and the rest of the bytes are made up. Until
// size 10, this should return VPX_CODEC_UNSUP_BITSTREAM and after that it
// should return VPX_CODEC_CORRUPT_FRAME.
const uint8_t data[32] = {
0x85, 0xa4, 0xc1, 0xa1, 0x38, 0x81, 0xa3, 0x49, 0x83, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
for (uint32_t data_sz = 1; data_sz <= 32; ++data_sz) {
// Verify behavior of vpx_codec_decode. vpx_codec_decode doesn't even get
// to decoder_peek_si_internal on frames of size < 8.
if (data_sz >= 8) {
vpx_codec_ctx_t dec;
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_dec_init(&dec, codec, NULL, 0));
EXPECT_EQ(
(data_sz < 10) ? VPX_CODEC_UNSUP_BITSTREAM : VPX_CODEC_CORRUPT_FRAME,
vpx_codec_decode(&dec, data, data_sz, NULL, 0));
vpx_codec_iter_t iter = NULL;
EXPECT_EQ(NULL, vpx_codec_get_frame(&dec, &iter));
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_destroy(&dec));
}
// Verify behavior of vpx_codec_peek_stream_info.
vpx_codec_stream_info_t si;
si.sz = sizeof(si);
EXPECT_EQ((data_sz < 10) ? VPX_CODEC_UNSUP_BITSTREAM : VPX_CODEC_OK,
vpx_codec_peek_stream_info(codec, data, data_sz, &si));
}
}
#endif // CONFIG_VP9_DECODER #endif // CONFIG_VP9_DECODER
TEST(DecodeAPI, HighBitDepthCapability) {
// VP8 should not claim VP9 HBD as a capability.
#if CONFIG_VP8_DECODER
const vpx_codec_caps_t vp8_caps = vpx_codec_get_caps(&vpx_codec_vp8_dx_algo);
EXPECT_EQ(vp8_caps & VPX_CODEC_CAP_HIGHBITDEPTH, 0);
#endif
#if CONFIG_VP9_DECODER
const vpx_codec_caps_t vp9_caps = vpx_codec_get_caps(&vpx_codec_vp9_dx_algo);
#if CONFIG_VP9_HIGHBITDEPTH
EXPECT_EQ(vp9_caps & VPX_CODEC_CAP_HIGHBITDEPTH, VPX_CODEC_CAP_HIGHBITDEPTH);
#else
EXPECT_EQ(vp9_caps & VPX_CODEC_CAP_HIGHBITDEPTH, 0);
#endif
#endif
}
} // namespace } // namespace

View File

@ -21,20 +21,21 @@
#include "./ivfenc.h" #include "./ivfenc.h"
#include "./vpx_version.h" #include "./vpx_version.h"
using ::testing::make_tuple; using std::tr1::make_tuple;
namespace { 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"; 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 ::testing::tuple<const char *, unsigned> DecodePerfParam; typedef std::tr1::tuple<const char *, unsigned> DecodePerfParam;
const DecodePerfParam kVP9DecodePerfVectors[] = { const DecodePerfParam kVP9DecodePerfVectors[] = {
make_tuple("vp90-2-bbb_426x240_tile_1x1_180kbps.webm", 1), make_tuple("vp90-2-bbb_426x240_tile_1x1_180kbps.webm", 1),
@ -69,7 +70,8 @@ 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<DecodePerfParam> {
};
TEST_P(DecodePerfTest, PerfTest) { TEST_P(DecodePerfTest, PerfTest) {
const char *const video_name = GET_PARAM(VIDEO_NAME); const char *const video_name = GET_PARAM(VIDEO_NAME);
@ -90,7 +92,8 @@ TEST_P(DecodePerfTest, PerfTest) {
} }
vpx_usec_timer_mark(&t); vpx_usec_timer_mark(&t);
const double elapsed_secs = double(vpx_usec_timer_elapsed(&t)) / kUsecsInSec; const double elapsed_secs = double(vpx_usec_timer_elapsed(&t))
/ kUsecsInSec;
const unsigned frames = video.frame_number(); const unsigned frames = video.frame_number();
const double fps = double(frames) / elapsed_secs; const double fps = double(frames) / elapsed_secs;
@ -108,13 +111,17 @@ TEST_P(DecodePerfTest, PerfTest) {
INSTANTIATE_TEST_CASE_P(VP9, DecodePerfTest, INSTANTIATE_TEST_CASE_P(VP9, DecodePerfTest,
::testing::ValuesIn(kVP9DecodePerfVectors)); ::testing::ValuesIn(kVP9DecodePerfVectors));
class VP9NewEncodeDecodePerfTest class VP9NewEncodeDecodePerfTest :
: public ::libvpx_test::EncoderTest, public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> { public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected: protected:
VP9NewEncodeDecodePerfTest() VP9NewEncodeDecodePerfTest()
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)), speed_(0), : EncoderTest(GET_PARAM(0)),
outfile_(0), out_frames_(0) {} encoding_mode_(GET_PARAM(1)),
speed_(0),
outfile_(0),
out_frames_(0) {
}
virtual ~VP9NewEncodeDecodePerfTest() {} virtual ~VP9NewEncodeDecodePerfTest() {}
@ -153,9 +160,8 @@ class VP9NewEncodeDecodePerfTest
virtual void EndPassHook() { virtual void EndPassHook() {
if (outfile_ != NULL) { if (outfile_ != NULL) {
if (!fseek(outfile_, 0, SEEK_SET)) { if (!fseek(outfile_, 0, SEEK_SET))
ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_); ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);
}
fclose(outfile_); fclose(outfile_);
outfile_ = NULL; outfile_ = NULL;
} }
@ -165,9 +171,8 @@ class VP9NewEncodeDecodePerfTest
++out_frames_; ++out_frames_;
// Write initial file header if first frame. // Write initial file header if first frame.
if (pkt->data.frame.pts == 0) { if (pkt->data.frame.pts == 0)
ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_); ivf_write_file_header(outfile_, &cfg_, VP9_FOURCC, out_frames_);
}
// Write frame header and data. // Write frame header and data.
ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz); ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz);
@ -175,9 +180,11 @@ class VP9NewEncodeDecodePerfTest
pkt->data.frame.sz); pkt->data.frame.sz);
} }
virtual bool DoDecode() const { return false; } virtual bool DoDecode() { return false; }
void set_speed(unsigned int speed) { speed_ = speed; } void set_speed(unsigned int speed) {
speed_ = speed;
}
private: private:
libvpx_test::TestMode encoding_mode_; libvpx_test::TestMode encoding_mode_;
@ -189,7 +196,10 @@ class VP9NewEncodeDecodePerfTest
struct EncodePerfTestVideo { struct EncodePerfTestVideo {
EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_, EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
uint32_t bitrate_, int frames_) uint32_t bitrate_, int frames_)
: name(name_), width(width_), height(height_), bitrate(bitrate_), : name(name_),
width(width_),
height(height_),
bitrate(bitrate_),
frames(frames_) {} frames(frames_) {}
const char *name; const char *name;
uint32_t width; uint32_t width;
@ -215,8 +225,10 @@ TEST_P(VP9NewEncodeDecodePerfTest, PerfTest) {
const char *video_name = kVP9EncodePerfTestVectors[i].name; const char *video_name = kVP9EncodePerfTestVectors[i].name;
libvpx_test::I420VideoSource video( libvpx_test::I420VideoSource video(
video_name, kVP9EncodePerfTestVectors[i].width, video_name,
kVP9EncodePerfTestVectors[i].height, timebase.den, timebase.num, 0, kVP9EncodePerfTestVectors[i].width,
kVP9EncodePerfTestVectors[i].height,
timebase.den, timebase.num, 0,
kVP9EncodePerfTestVectors[i].frames); kVP9EncodePerfTestVectors[i].frames);
set_speed(2); set_speed(2);
@ -256,6 +268,6 @@ TEST_P(VP9NewEncodeDecodePerfTest, PerfTest) {
printf("}\n"); printf("}\n");
} }
VP9_INSTANTIATE_TEST_CASE(VP9NewEncodeDecodePerfTest, VP9_INSTANTIATE_TEST_CASE(
::testing::Values(::libvpx_test::kTwoPassGood)); VP9NewEncodeDecodePerfTest, ::testing::Values(::libvpx_test::kTwoPassGood));
} // namespace } // namespace

View File

@ -1,124 +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 <string>
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/ivf_video_source.h"
#include "test/test_vectors.h"
#include "test/util.h"
namespace {
const unsigned int kNumFrames = 19;
class DecodeSvcTest : public ::libvpx_test::DecoderTest,
public ::libvpx_test::CodecTestWithParam<const char *> {
protected:
DecodeSvcTest() : DecoderTest(GET_PARAM(::libvpx_test::kCodecFactoryParam)) {}
virtual ~DecodeSvcTest() {}
virtual void PreDecodeFrameHook(
const libvpx_test::CompressedVideoSource &video,
libvpx_test::Decoder *decoder) {
if (video.frame_number() == 0)
decoder->Control(VP9_DECODE_SVC_SPATIAL_LAYER, spatial_layer_);
}
virtual void DecompressedFrameHook(const vpx_image_t &img,
const unsigned int frame_number) {
ASSERT_EQ(img.d_w, width_);
ASSERT_EQ(img.d_h, height_);
total_frames_ = frame_number;
}
int spatial_layer_;
unsigned int width_;
unsigned int height_;
unsigned int total_frames_;
};
// SVC test vector is 1280x720, with 3 spatial layers, and 20 frames.
// Decode the SVC test vector, which has 3 spatial layers, and decode up to
// spatial layer 0. Verify the resolution of each decoded frame and the total
// number of frames decoded. This results in 1/4x1/4 resolution (320x180).
TEST_P(DecodeSvcTest, DecodeSvcTestUpToSpatialLayer0) {
const std::string filename = GET_PARAM(1);
testing::internal::scoped_ptr<libvpx_test::CompressedVideoSource> video;
video.reset(new libvpx_test::IVFVideoSource(filename));
ASSERT_TRUE(video.get() != NULL);
video->Init();
total_frames_ = 0;
spatial_layer_ = 0;
width_ = 320;
height_ = 180;
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
ASSERT_EQ(total_frames_, kNumFrames);
}
// Decode the SVC test vector, which has 3 spatial layers, and decode up to
// spatial layer 1. Verify the resolution of each decoded frame and the total
// number of frames decoded. This results in 1/2x1/2 resolution (640x360).
TEST_P(DecodeSvcTest, DecodeSvcTestUpToSpatialLayer1) {
const std::string filename = GET_PARAM(1);
testing::internal::scoped_ptr<libvpx_test::CompressedVideoSource> video;
video.reset(new libvpx_test::IVFVideoSource(filename));
ASSERT_TRUE(video.get() != NULL);
video->Init();
total_frames_ = 0;
spatial_layer_ = 1;
width_ = 640;
height_ = 360;
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
ASSERT_EQ(total_frames_, kNumFrames);
}
// Decode the SVC test vector, which has 3 spatial layers, and decode up to
// spatial layer 2. Verify the resolution of each decoded frame and the total
// number of frames decoded. This results in the full resolution (1280x720).
TEST_P(DecodeSvcTest, DecodeSvcTestUpToSpatialLayer2) {
const std::string filename = GET_PARAM(1);
testing::internal::scoped_ptr<libvpx_test::CompressedVideoSource> video;
video.reset(new libvpx_test::IVFVideoSource(filename));
ASSERT_TRUE(video.get() != NULL);
video->Init();
total_frames_ = 0;
spatial_layer_ = 2;
width_ = 1280;
height_ = 720;
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
ASSERT_EQ(total_frames_, kNumFrames);
}
// Decode the SVC test vector, which has 3 spatial layers, and decode up to
// spatial layer 10. Verify the resolution of each decoded frame and the total
// number of frames decoded. This is beyond the number of spatial layers, so
// the decoding should result in the full resolution (1280x720).
TEST_P(DecodeSvcTest, DecodeSvcTestUpToSpatialLayer10) {
const std::string filename = GET_PARAM(1);
testing::internal::scoped_ptr<libvpx_test::CompressedVideoSource> video;
video.reset(new libvpx_test::IVFVideoSource(filename));
ASSERT_TRUE(video.get() != NULL);
video->Init();
total_frames_ = 0;
spatial_layer_ = 10;
width_ = 1280;
height_ = 720;
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
ASSERT_EQ(total_frames_, kNumFrames);
}
VP9_INSTANTIATE_TEST_CASE(
DecodeSvcTest, ::testing::ValuesIn(libvpx_test::kVP9TestVectorsSvc,
libvpx_test::kVP9TestVectorsSvc +
libvpx_test::kNumVP9TestVectorsSvc));
} // namespace

View File

@ -7,11 +7,9 @@
* 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"
@ -21,8 +19,9 @@ const char kVP8Name[] = "WebM Project VP8";
vpx_codec_err_t Decoder::PeekStream(const uint8_t *cxdata, size_t size, vpx_codec_err_t Decoder::PeekStream(const uint8_t *cxdata, size_t size,
vpx_codec_stream_info_t *stream_info) { vpx_codec_stream_info_t *stream_info) {
return vpx_codec_peek_stream_info( return vpx_codec_peek_stream_info(CodecInterface(),
CodecInterface(), cxdata, static_cast<unsigned int>(size), stream_info); 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) {
@ -34,8 +33,9 @@ vpx_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size,
vpx_codec_err_t res_dec; vpx_codec_err_t res_dec;
InitOnce(); InitOnce();
API_REGISTER_STATE_CHECK( API_REGISTER_STATE_CHECK(
res_dec = vpx_codec_decode( res_dec = vpx_codec_decode(&decoder_,
&decoder_, cxdata, static_cast<unsigned int>(size), user_priv, 0)); cxdata, static_cast<unsigned int>(size),
user_priv, 0));
return res_dec; return res_dec;
} }
@ -52,21 +52,20 @@ void DecoderTest::HandlePeekResult(Decoder *const decoder,
/* Vp8's implementation of PeekStream returns an error if the frame you /* 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 * pass it is not a keyframe, so we only expect VPX_CODEC_OK on the first
* frame, which must be a keyframe. */ * frame, which must be a keyframe. */
if (video->frame_number() == 0) { if (video->frame_number() == 0)
ASSERT_EQ(VPX_CODEC_OK, res_peek) ASSERT_EQ(VPX_CODEC_OK, res_peek) << "Peek return failed: "
<< "Peek return failed: " << vpx_codec_err_to_string(res_peek); << vpx_codec_err_to_string(res_peek);
}
} else { } else {
/* The Vp9 implementation of PeekStream returns an error only if the /* The Vp9 implementation of PeekStream returns an error only if the
* data passed to it isn't a valid Vp9 chunk. */ * data passed to it isn't a valid Vp9 chunk. */
ASSERT_EQ(VPX_CODEC_OK, res_peek) ASSERT_EQ(VPX_CODEC_OK, res_peek) << "Peek return failed: "
<< "Peek return failed: " << vpx_codec_err_to_string(res_peek); << vpx_codec_err_to_string(res_peek);
} }
} }
void DecoderTest::RunLoop(CompressedVideoSource *video, void DecoderTest::RunLoop(CompressedVideoSource *video,
const vpx_codec_dec_cfg_t &dec_cfg) { const vpx_codec_dec_cfg_t &dec_cfg) {
Decoder *const decoder = codec_->CreateDecoder(dec_cfg, flags_); Decoder* const decoder = codec_->CreateDecoder(dec_cfg, flags_, 0);
ASSERT_TRUE(decoder != NULL); ASSERT_TRUE(decoder != NULL);
bool end_of_file = false; bool end_of_file = false;
@ -79,14 +78,16 @@ void DecoderTest::RunLoop(CompressedVideoSource *video,
stream_info.sz = sizeof(stream_info); stream_info.sz = sizeof(stream_info);
if (video->cxdata() != NULL) { if (video->cxdata() != NULL) {
const vpx_codec_err_t res_peek = decoder->PeekStream( const vpx_codec_err_t res_peek = decoder->PeekStream(video->cxdata(),
video->cxdata(), video->frame_size(), &stream_info); video->frame_size(),
&stream_info);
HandlePeekResult(decoder, video, res_peek); HandlePeekResult(decoder, video, res_peek);
ASSERT_FALSE(::testing::Test::HasFailure()); ASSERT_FALSE(::testing::Test::HasFailure());
vpx_codec_err_t res_dec = vpx_codec_err_t res_dec = decoder->DecodeFrame(video->cxdata(),
decoder->DecodeFrame(video->cxdata(), video->frame_size()); video->frame_size());
if (!HandleDecodeResult(res_dec, *video, decoder)) break; if (!HandleDecodeResult(res_dec, *video, decoder))
break;
} else { } else {
// Signal end of the file to the decoder. // Signal end of the file to the decoder.
const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0); const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0);
@ -98,9 +99,8 @@ void DecoderTest::RunLoop(CompressedVideoSource *video,
const vpx_image_t *img = NULL; const vpx_image_t *img = NULL;
// Get decompressed data // Get decompressed data
while ((img = dec_iter.Next())) { while ((img = dec_iter.Next()))
DecompressedFrameHook(*img, video->frame_number()); DecompressedFrameHook(*img, video->frame_number());
}
} }
delete decoder; delete decoder;
} }
@ -114,6 +114,8 @@ void DecoderTest::set_cfg(const vpx_codec_dec_cfg_t &dec_cfg) {
memcpy(&cfg_, &dec_cfg, sizeof(cfg_)); memcpy(&cfg_, &dec_cfg, sizeof(cfg_));
} }
void DecoderTest::set_flags(const vpx_codec_flags_t flags) { flags_ = flags; } void DecoderTest::set_flags(const vpx_codec_flags_t flags) {
flags_ = flags;
}
} // namespace libvpx_test } // namespace libvpx_test

View File

@ -26,11 +26,13 @@ class DxDataIterator {
explicit DxDataIterator(vpx_codec_ctx_t *decoder) explicit DxDataIterator(vpx_codec_ctx_t *decoder)
: decoder_(decoder), iter_(NULL) {} : decoder_(decoder), iter_(NULL) {}
const vpx_image_t *Next() { return vpx_codec_get_frame(decoder_, &iter_); } const vpx_image_t *Next() {
return vpx_codec_get_frame(decoder_, &iter_);
}
private: private:
vpx_codec_ctx_t *decoder_; vpx_codec_ctx_t *decoder_;
vpx_codec_iter_t iter_; vpx_codec_iter_t iter_;
}; };
// Provides a simplified interface to manage one video decoding. // Provides a simplified interface to manage one video decoding.
@ -38,17 +40,20 @@ class DxDataIterator {
// as more tests are added. // as more tests are added.
class Decoder { class Decoder {
public: public:
explicit Decoder(vpx_codec_dec_cfg_t cfg) Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline)
: cfg_(cfg), flags_(0), init_done_(false) { : cfg_(cfg), flags_(0), deadline_(deadline), init_done_(false) {
memset(&decoder_, 0, sizeof(decoder_)); memset(&decoder_, 0, sizeof(decoder_));
} }
Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag) Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag,
: cfg_(cfg), flags_(flag), init_done_(false) { unsigned long deadline) // NOLINT
: cfg_(cfg), flags_(flag), deadline_(deadline), init_done_(false) {
memset(&decoder_, 0, sizeof(decoder_)); memset(&decoder_, 0, sizeof(decoder_));
} }
virtual ~Decoder() { vpx_codec_destroy(&decoder_); } virtual ~Decoder() {
vpx_codec_destroy(&decoder_);
}
vpx_codec_err_t PeekStream(const uint8_t *cxdata, size_t size, vpx_codec_err_t PeekStream(const uint8_t *cxdata, size_t size,
vpx_codec_stream_info_t *stream_info); vpx_codec_stream_info_t *stream_info);
@ -58,9 +63,17 @@ class Decoder {
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); void *user_priv);
DxDataIterator GetDxData() { return DxDataIterator(&decoder_); } DxDataIterator GetDxData() {
return DxDataIterator(&decoder_);
}
void Control(int ctrl_id, int arg) { Control(ctrl_id, arg, VPX_CODEC_OK); } void set_deadline(unsigned long deadline) {
deadline_ = deadline;
}
void Control(int ctrl_id, int arg) {
Control(ctrl_id, arg, VPX_CODEC_OK);
}
void Control(int ctrl_id, const void *arg) { void Control(int ctrl_id, const void *arg) {
InitOnce(); InitOnce();
@ -74,7 +87,7 @@ class Decoder {
ASSERT_EQ(expected_value, res) << DecodeError(); 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_);
} }
@ -84,34 +97,38 @@ class Decoder {
vpx_get_frame_buffer_cb_fn_t cb_get, vpx_get_frame_buffer_cb_fn_t cb_get,
vpx_release_frame_buffer_cb_fn_t cb_release, void *user_priv) { vpx_release_frame_buffer_cb_fn_t cb_release, void *user_priv) {
InitOnce(); InitOnce();
return vpx_codec_set_frame_buffer_functions(&decoder_, cb_get, cb_release, return vpx_codec_set_frame_buffer_functions(
user_priv); &decoder_, cb_get, cb_release, user_priv);
} }
const char *GetDecoderName() const { const char* GetDecoderName() const {
return vpx_codec_iface_name(CodecInterface()); return vpx_codec_iface_name(CodecInterface());
} }
bool IsVP8() const; bool IsVP8() const;
vpx_codec_ctx_t *GetDecoder() { return &decoder_; } 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;
void InitOnce() { void InitOnce() {
if (!init_done_) { if (!init_done_) {
const vpx_codec_err_t res = const vpx_codec_err_t res = vpx_codec_dec_init(&decoder_,
vpx_codec_dec_init(&decoder_, CodecInterface(), &cfg_, flags_); CodecInterface(),
&cfg_, flags_);
ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError(); ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError();
init_done_ = true; init_done_ = true;
} }
} }
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_; vpx_codec_flags_t flags_;
bool init_done_; unsigned int deadline_;
bool init_done_;
}; };
// Common test functionality for all Decoder tests. // Common test functionality for all Decoder tests.
@ -126,35 +143,37 @@ class DecoderTest {
virtual void set_flags(const vpx_codec_flags_t flags); 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. // Hook to be called to handle decode result. Return true to continue.
virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec, virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
const CompressedVideoSource & /*video*/, const CompressedVideoSource& /*video*/,
Decoder *decoder) { Decoder *decoder) {
EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError(); EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
return VPX_CODEC_OK == res_dec; 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 // Hook to be called on peek result
virtual void HandlePeekResult(Decoder *const decoder, virtual void HandlePeekResult(Decoder* const decoder,
CompressedVideoSource *video, CompressedVideoSource *video,
const vpx_codec_err_t res_peek); const vpx_codec_err_t res_peek);
protected: protected:
explicit DecoderTest(const CodecFactory *codec) explicit DecoderTest(const CodecFactory *codec)
: codec_(codec), cfg_(), flags_(0) {} : codec_(codec),
cfg_(),
flags_(0) {}
virtual ~DecoderTest() {} virtual ~DecoderTest() {}
const CodecFactory *codec_; const CodecFactory *codec_;
vpx_codec_dec_cfg_t cfg_; vpx_codec_dec_cfg_t cfg_;
vpx_codec_flags_t flags_; vpx_codec_flags_t flags_;
}; };
} // namespace libvpx_test } // namespace libvpx_test

View File

@ -1,195 +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_VP8_ENCODER
&vpx_codec_vp8_cx_algo,
#endif
#if CONFIG_VP9_ENCODER
&vpx_codec_vp9_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));
}
}
TEST(EncodeAPI, HighBitDepthCapability) {
// VP8 should not claim VP9 HBD as a capability.
#if CONFIG_VP8_ENCODER
const vpx_codec_caps_t vp8_caps = vpx_codec_get_caps(&vpx_codec_vp8_cx_algo);
EXPECT_EQ(vp8_caps & VPX_CODEC_CAP_HIGHBITDEPTH, 0);
#endif
#if CONFIG_VP9_ENCODER
const vpx_codec_caps_t vp9_caps = vpx_codec_get_caps(&vpx_codec_vp9_cx_algo);
#if CONFIG_VP9_HIGHBITDEPTH
EXPECT_EQ(vp9_caps & VPX_CODEC_CAP_HIGHBITDEPTH, VPX_CODEC_CAP_HIGHBITDEPTH);
#else
EXPECT_EQ(vp9_caps & VPX_CODEC_CAP_HIGHBITDEPTH, 0);
#endif
#endif
}
#if CONFIG_VP8_ENCODER
TEST(EncodeAPI, ImageSizeSetting) {
const int width = 711;
const int height = 360;
const int bps = 12;
vpx_image_t img;
vpx_codec_ctx_t enc;
vpx_codec_enc_cfg_t cfg;
uint8_t *img_buf = reinterpret_cast<uint8_t *>(
calloc(width * height * bps / 8, sizeof(*img_buf)));
vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &cfg, 0);
cfg.g_w = width;
cfg.g_h = height;
vpx_img_wrap(&img, VPX_IMG_FMT_I420, width, height, 1, img_buf);
vpx_codec_enc_init(&enc, vpx_codec_vp8_cx(), &cfg, 0);
EXPECT_EQ(VPX_CODEC_OK, vpx_codec_encode(&enc, &img, 0, 1, 0, 0));
free(img_buf);
vpx_codec_destroy(&enc);
}
#endif
// Set up 2 spatial streams with 2 temporal layers per stream, and generate
// invalid configuration by setting the temporal layer rate allocation
// (ts_target_bitrate[]) to 0 for both layers. This should fail independent of
// CONFIG_MULTI_RES_ENCODING.
TEST(EncodeAPI, MultiResEncode) {
static const vpx_codec_iface_t *kCodecs[] = {
#if CONFIG_VP8_ENCODER
&vpx_codec_vp8_cx_algo,
#endif
#if CONFIG_VP9_ENCODER
&vpx_codec_vp9_cx_algo,
#endif
};
const int width = 1280;
const int height = 720;
const int width_down = width / 2;
const int height_down = height / 2;
const int target_bitrate = 1000;
const int framerate = 30;
for (int c = 0; c < NELEMENTS(kCodecs); ++c) {
const vpx_codec_iface_t *const iface = kCodecs[c];
vpx_codec_ctx_t enc[2];
vpx_codec_enc_cfg_t cfg[2];
vpx_rational_t dsf[2] = { { 2, 1 }, { 2, 1 } };
memset(enc, 0, sizeof(enc));
for (int i = 0; i < 2; i++) {
vpx_codec_enc_config_default(iface, &cfg[i], 0);
}
/* Highest-resolution encoder settings */
cfg[0].g_w = width;
cfg[0].g_h = height;
cfg[0].rc_dropframe_thresh = 0;
cfg[0].rc_end_usage = VPX_CBR;
cfg[0].rc_resize_allowed = 0;
cfg[0].rc_min_quantizer = 2;
cfg[0].rc_max_quantizer = 56;
cfg[0].rc_undershoot_pct = 100;
cfg[0].rc_overshoot_pct = 15;
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;
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; /* Set target bitrate */
cfg[0].g_timebase.num = 1; /* Set fps */
cfg[0].g_timebase.den = framerate;
memcpy(&cfg[1], &cfg[0], sizeof(cfg[0]));
cfg[1].rc_target_bitrate = 500;
cfg[1].g_w = width_down;
cfg[1].g_h = height_down;
for (int i = 0; i < 2; i++) {
cfg[i].ts_number_layers = 2;
cfg[i].ts_periodicity = 2;
cfg[i].ts_rate_decimator[0] = 2;
cfg[i].ts_rate_decimator[1] = 1;
cfg[i].ts_layer_id[0] = 0;
cfg[i].ts_layer_id[1] = 1;
// Invalid parameters.
cfg[i].ts_target_bitrate[0] = 0;
cfg[i].ts_target_bitrate[1] = 0;
}
// VP9 should report incapable, VP8 invalid for all configurations.
const char kVP9Name[] = "WebM Project VP9";
const bool is_vp9 = strncmp(kVP9Name, vpx_codec_iface_name(iface),
sizeof(kVP9Name) - 1) == 0;
EXPECT_EQ(is_vp9 ? VPX_CODEC_INCAPABLE : VPX_CODEC_INVALID_PARAM,
vpx_codec_enc_init_multi(&enc[0], iface, &cfg[0], 2, 0, &dsf[0]));
for (int i = 0; i < 2; i++) {
vpx_codec_destroy(&enc[i]);
}
}
}
} // namespace

View File

@ -26,7 +26,10 @@ const double kUsecsInSec = 1000000.0;
struct EncodePerfTestVideo { struct EncodePerfTestVideo {
EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_, EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
uint32_t bitrate_, int frames_) uint32_t bitrate_, int frames_)
: name(name_), width(width_), height(height_), bitrate(bitrate_), : name(name_),
width(width_),
height(height_),
bitrate(bitrate_),
frames(frames_) {} frames(frames_) {}
const char *name; const char *name;
uint32_t width; uint32_t width;
@ -42,8 +45,8 @@ const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
EncodePerfTestVideo("macmarcostationary_640_480_30.yuv", 640, 480, 200, 718), EncodePerfTestVideo("macmarcostationary_640_480_30.yuv", 640, 480, 200, 718),
EncodePerfTestVideo("niklas_640_480_30.yuv", 640, 480, 200, 471), EncodePerfTestVideo("niklas_640_480_30.yuv", 640, 480, 200, 471),
EncodePerfTestVideo("tacomanarrows_640_480_30.yuv", 640, 480, 200, 300), EncodePerfTestVideo("tacomanarrows_640_480_30.yuv", 640, 480, 200, 300),
EncodePerfTestVideo("tacomasmallcameramovement_640_480_30.yuv", 640, 480, 200, EncodePerfTestVideo("tacomasmallcameramovement_640_480_30.yuv",
300), 640, 480, 200, 300),
EncodePerfTestVideo("thaloundeskmtg_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), EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
}; };
@ -58,8 +61,12 @@ class VP9EncodePerfTest
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> { public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected: protected:
VP9EncodePerfTest() VP9EncodePerfTest()
: EncoderTest(GET_PARAM(0)), min_psnr_(kMaxPsnr), nframes_(0), : EncoderTest(GET_PARAM(0)),
encoding_mode_(GET_PARAM(1)), speed_(0), threads_(1) {} min_psnr_(kMaxPsnr),
nframes_(0),
encoding_mode_(GET_PARAM(1)),
speed_(0),
threads_(1) {}
virtual ~VP9EncodePerfTest() {} virtual ~VP9EncodePerfTest() {}
@ -100,18 +107,24 @@ class VP9EncodePerfTest
virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) { virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
if (pkt->data.psnr.psnr[0] < min_psnr_) { if (pkt->data.psnr.psnr[0] < min_psnr_) {
min_psnr_ = pkt->data.psnr.psnr[0]; min_psnr_= pkt->data.psnr.psnr[0];
} }
} }
// for performance reasons don't decode // for performance reasons don't decode
virtual bool DoDecode() const { return false; } virtual bool DoDecode() { return 0; }
double min_psnr() const { return min_psnr_; } double min_psnr() const {
return min_psnr_;
}
void set_speed(unsigned int speed) { speed_ = speed; } void set_speed(unsigned int speed) {
speed_ = speed;
}
void set_threads(unsigned int threads) { threads_ = threads; } void set_threads(unsigned int threads) {
threads_ = threads;
}
private: private:
double min_psnr_; double min_psnr_;
@ -126,12 +139,11 @@ TEST_P(VP9EncodePerfTest, PerfTest) {
for (size_t j = 0; j < NELEMENTS(kEncodePerfTestSpeeds); ++j) { for (size_t j = 0; j < NELEMENTS(kEncodePerfTestSpeeds); ++j) {
for (size_t k = 0; k < NELEMENTS(kEncodePerfTestThreads); ++k) { for (size_t k = 0; k < NELEMENTS(kEncodePerfTestThreads); ++k) {
if (kVP9EncodePerfTestVectors[i].width < 512 && if (kVP9EncodePerfTestVectors[i].width < 512 &&
kEncodePerfTestThreads[k] > 1) { kEncodePerfTestThreads[k] > 1)
continue; continue;
} else if (kVP9EncodePerfTestVectors[i].width < 1024 && else if (kVP9EncodePerfTestVectors[i].width < 1024 &&
kEncodePerfTestThreads[k] > 2) { kEncodePerfTestThreads[k] > 2)
continue; continue;
}
set_threads(kEncodePerfTestThreads[k]); set_threads(kEncodePerfTestThreads[k]);
SetUp(); SetUp();
@ -145,8 +157,10 @@ TEST_P(VP9EncodePerfTest, PerfTest) {
const unsigned frames = kVP9EncodePerfTestVectors[i].frames; const unsigned frames = kVP9EncodePerfTestVectors[i].frames;
const char *video_name = kVP9EncodePerfTestVectors[i].name; const char *video_name = kVP9EncodePerfTestVectors[i].name;
libvpx_test::I420VideoSource video( libvpx_test::I420VideoSource video(
video_name, kVP9EncodePerfTestVectors[i].width, video_name,
kVP9EncodePerfTestVectors[i].height, timebase.den, timebase.num, 0, kVP9EncodePerfTestVectors[i].width,
kVP9EncodePerfTestVectors[i].height,
timebase.den, timebase.num, 0,
kVP9EncodePerfTestVectors[i].frames); kVP9EncodePerfTestVectors[i].frames);
set_speed(kEncodePerfTestSpeeds[j]); set_speed(kEncodePerfTestSpeeds[j]);
@ -183,6 +197,6 @@ TEST_P(VP9EncodePerfTest, PerfTest) {
} }
} }
VP9_INSTANTIATE_TEST_CASE(VP9EncodePerfTest, VP9_INSTANTIATE_TEST_CASE(
::testing::Values(::libvpx_test::kRealTime)); VP9EncodePerfTest, ::testing::Values(::libvpx_test::kRealTime));
} // namespace } // namespace

View File

@ -10,14 +10,13 @@
#include <string> #include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h" #include "./vpx_config.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) { void Encoder::InitEncoder(VideoSource *video) {
@ -30,7 +29,8 @@ void Encoder::InitEncoder(VideoSource *video) {
cfg_.g_timebase = video->timebase(); cfg_.g_timebase = video->timebase();
cfg_.rc_twopass_stats_in = stats_->buf(); cfg_.rc_twopass_stats_in = stats_->buf();
res = vpx_codec_enc_init(&encoder_, CodecInterface(), &cfg_, init_flags_); res = vpx_codec_enc_init(&encoder_, CodecInterface(), &cfg_,
init_flags_);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
@ -52,17 +52,17 @@ void Encoder::InitEncoder(VideoSource *video) {
} }
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);
} else { else
Flush(); Flush();
}
// Handle twopass stats // Handle twopass stats
CxDataIterator iter = GetCxData(); CxDataIterator iter = GetCxData();
while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) { while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
if (pkt->kind != VPX_CODEC_STATS_PKT) continue; if (pkt->kind != VPX_CODEC_STATS_PKT)
continue;
stats_->Append(*pkt); stats_->Append(*pkt);
} }
@ -82,15 +82,15 @@ void Encoder::EncodeFrameInternal(const VideoSource &video,
} }
// Encode the frame // Encode the frame
API_REGISTER_STATE_CHECK(res = vpx_codec_encode(&encoder_, img, video.pts(), API_REGISTER_STATE_CHECK(
video.duration(), frame_flags, res = vpx_codec_encode(&encoder_, img, video.pts(), video.duration(),
deadline_)); frame_flags, deadline_));
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
void Encoder::Flush() { void Encoder::Flush() {
const vpx_codec_err_t res = const vpx_codec_err_t res = vpx_codec_encode(&encoder_, NULL, 0, 0, 0,
vpx_codec_encode(&encoder_, NULL, 0, 0, 0, deadline_); deadline_);
if (!encoder_.priv) if (!encoder_.priv)
ASSERT_EQ(VPX_CODEC_ERROR, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_ERROR, res) << EncoderError();
else else
@ -105,57 +105,60 @@ void EncoderTest::InitializeConfig() {
void EncoderTest::SetMode(TestMode mode) { void EncoderTest::SetMode(TestMode mode) {
switch (mode) { switch (mode) {
case kRealTime: deadline_ = VPX_DL_REALTIME; break; case kRealTime:
deadline_ = VPX_DL_REALTIME;
break;
case kOnePassGood: case kOnePassGood:
case kTwoPassGood: deadline_ = VPX_DL_GOOD_QUALITY; break; case kTwoPassGood:
deadline_ = VPX_DL_GOOD_QUALITY;
break;
case kOnePassBest: case kOnePassBest:
case kTwoPassBest: deadline_ = VPX_DL_BEST_QUALITY; break; case kTwoPassBest:
deadline_ = VPX_DL_BEST_QUALITY;
break;
default: ASSERT_TRUE(false) << "Unexpected mode " << mode; default:
ASSERT_TRUE(false) << "Unexpected mode " << mode;
} }
if (mode == kTwoPassGood || mode == kTwoPassBest) { if (mode == kTwoPassGood || mode == kTwoPassBest)
passes_ = 2; passes_ = 2;
} else { else
passes_ = 1; passes_ = 1;
}
} }
// 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, const vpx_image_t *img2) { static bool compare_img(const vpx_image_t *img1,
bool match = (img1->fmt == img2->fmt) && (img1->cs == img2->cs) && const vpx_image_t *img2) {
(img1->d_w == img2->d_w) && (img1->d_h == img2->d_h); bool match = (img1->fmt == img2->fmt) &&
(img1->cs == img2->cs) &&
(img1->d_w == img2->d_w) &&
(img1->d_h == img2->d_h);
const unsigned int width_y = img1->d_w; const unsigned int width_y = img1->d_w;
const unsigned int height_y = img1->d_h; const unsigned int height_y = img1->d_h;
unsigned int i; unsigned int i;
for (i = 0; i < height_y; ++i) { for (i = 0; i < height_y; ++i)
match = (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y], match = (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y],
img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y], img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y],
width_y) == 0) && width_y) == 0) && match;
match; const unsigned int width_uv = (img1->d_w + 1) >> 1;
}
const unsigned int width_uv = (img1->d_w + 1) >> 1;
const unsigned int height_uv = (img1->d_h + 1) >> 1; const unsigned int height_uv = (img1->d_h + 1) >> 1;
for (i = 0; i < height_uv; ++i) { for (i = 0; i < height_uv; ++i)
match = (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U], match = (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U],
img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U], img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U],
width_uv) == 0) && width_uv) == 0) && match;
match; for (i = 0; i < height_uv; ++i)
}
for (i = 0; i < height_uv; ++i) {
match = (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V], match = (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V],
img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V], img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V],
width_uv) == 0) && width_uv) == 0) && match;
match;
}
return match; return match;
} }
void EncoderTest::MismatchHook(const vpx_image_t * /*img1*/, void EncoderTest::MismatchHook(const vpx_image_t* /*img1*/,
const vpx_image_t * /*img2*/) { const vpx_image_t* /*img2*/) {
ASSERT_TRUE(0) << "Encode/Decode mismatch found"; ASSERT_TRUE(0) << "Encode/Decode mismatch found";
} }
@ -168,41 +171,35 @@ void EncoderTest::RunLoop(VideoSource *video) {
for (unsigned int pass = 0; pass < passes_; pass++) { for (unsigned int pass = 0; pass < passes_; pass++) {
last_pts_ = 0; last_pts_ = 0;
if (passes_ == 1) { if (passes_ == 1)
cfg_.g_pass = VPX_RC_ONE_PASS; cfg_.g_pass = VPX_RC_ONE_PASS;
} else if (pass == 0) { else if (pass == 0)
cfg_.g_pass = VPX_RC_FIRST_PASS; cfg_.g_pass = VPX_RC_FIRST_PASS;
} else { else
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);
ASSERT_NO_FATAL_FAILURE(video->Begin()); video->Begin();
encoder->InitEncoder(video); encoder->InitEncoder(video);
ASSERT_FALSE(::testing::Test::HasFatalFailure());
unsigned long dec_init_flags = 0; // NOLINT unsigned long dec_init_flags = 0; // NOLINT
// Use fragment decoder if encoder outputs partitions. // Use fragment decoder if encoder outputs partitions.
// NOTE: fragment decoder and partition encoder are only supported by VP8. // NOTE: fragment decoder and partition encoder are only supported by VP8.
if (init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION) { if (init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION)
dec_init_flags |= VPX_CODEC_USE_INPUT_FRAGMENTS; dec_init_flags |= VPX_CODEC_USE_INPUT_FRAGMENTS;
} Decoder* const decoder = codec_->CreateDecoder(dec_cfg, dec_init_flags, 0);
testing::internal::scoped_ptr<Decoder> decoder(
codec_->CreateDecoder(dec_cfg, dec_init_flags));
bool again; bool again;
for (again = true; again; video->Next()) { for (again = true; 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_);
PostEncodeFrameHook();
CxDataIterator iter = encoder->GetCxData(); CxDataIterator iter = encoder->GetCxData();
bool has_cxdata = false; bool has_cxdata = false;
@ -213,11 +210,12 @@ 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);
if (!HandleDecodeResult(res_dec, *video, decoder.get())) break; if (!HandleDecodeResult(res_dec, *video, decoder))
break;
has_dxdata = true; has_dxdata = true;
} }
@ -226,18 +224,20 @@ void EncoderTest::RunLoop(VideoSource *video) {
FramePktHook(pkt); FramePktHook(pkt);
break; break;
case VPX_CODEC_PSNR_PKT: PSNRPktHook(pkt); break; case VPX_CODEC_PSNR_PKT:
PSNRPktHook(pkt);
break;
case VPX_CODEC_STATS_PKT: StatsPktHook(pkt); break; default:
break;
default: break;
} }
} }
// Flush the decoder when there are no more fragments. // Flush the decoder when there are no more fragments.
if ((init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION) && has_dxdata) { if ((init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION) && has_dxdata) {
const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0); const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0);
if (!HandleDecodeResult(res_dec, *video, decoder.get())) break; if (!HandleDecodeResult(res_dec, *video, decoder))
break;
} }
if (has_dxdata && has_cxdata) { if (has_dxdata && has_cxdata) {
@ -250,14 +250,21 @@ void EncoderTest::RunLoop(VideoSource *video) {
MismatchHook(img_enc, img_dec); MismatchHook(img_enc, img_dec);
} }
} }
if (img_dec) DecompressedFrameHook(*img_dec, video->pts()); if (img_dec)
DecompressedFrameHook(*img_dec, video->pts());
} }
if (!Continue()) break; if (!Continue())
break;
} }
EndPassHook(); EndPassHook();
if (!Continue()) break; if (decoder)
delete decoder;
delete encoder;
if (!Continue())
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"
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "vpx/vpx_encoder.h"
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER #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 {
@ -33,17 +32,19 @@ enum TestMode {
kTwoPassGood, kTwoPassGood,
kTwoPassBest kTwoPassBest
}; };
#define ALL_TEST_MODES \ #define ALL_TEST_MODES ::testing::Values(::libvpx_test::kRealTime, \
::testing::Values(::libvpx_test::kRealTime, ::libvpx_test::kOnePassGood, \ ::libvpx_test::kOnePassGood, \
::libvpx_test::kOnePassBest, ::libvpx_test::kTwoPassGood, \ ::libvpx_test::kOnePassBest, \
::libvpx_test::kTwoPassBest) ::libvpx_test::kTwoPassGood, \
::libvpx_test::kTwoPassBest)
#define ONE_PASS_TEST_MODES \ #define ONE_PASS_TEST_MODES ::testing::Values(::libvpx_test::kRealTime, \
::testing::Values(::libvpx_test::kRealTime, ::libvpx_test::kOnePassGood, \ ::libvpx_test::kOnePassGood, \
::libvpx_test::kOnePassBest) ::libvpx_test::kOnePassBest)
#define TWO_PASS_TEST_MODES ::testing::Values(::libvpx_test::kTwoPassGood, \
::libvpx_test::kTwoPassBest)
#define TWO_PASS_TEST_MODES \
::testing::Values(::libvpx_test::kTwoPassGood, ::libvpx_test::kTwoPassBest)
// Provides an object to handle the libvpx get_cx_data() iteration pattern // Provides an object to handle the libvpx get_cx_data() iteration pattern
class CxDataIterator { class CxDataIterator {
@ -56,8 +57,8 @@ class CxDataIterator {
} }
private: private:
vpx_codec_ctx_t *encoder_; vpx_codec_ctx_t *encoder_;
vpx_codec_iter_t iter_; vpx_codec_iter_t iter_;
}; };
// Implements an in-memory store for libvpx twopass statistics // Implements an in-memory store for libvpx twopass statistics
@ -73,12 +74,15 @@ class TwopassStatsStore {
return buf; return buf;
} }
void Reset() { buffer_.clear(); } void Reset() {
buffer_.clear();
}
protected: protected:
std::string buffer_; std::string buffer_;
}; };
// Provides a simplified interface to manage one video encoding pass, given // Provides a simplified interface to manage one video encoding pass, given
// a configuration and video source. // a configuration and video source.
// //
@ -92,9 +96,13 @@ class Encoder {
memset(&encoder_, 0, sizeof(encoder_)); memset(&encoder_, 0, sizeof(encoder_));
} }
virtual ~Encoder() { vpx_codec_destroy(&encoder_); } virtual ~Encoder() {
vpx_codec_destroy(&encoder_);
}
CxDataIterator GetCxData() { return CxDataIterator(&encoder_); } CxDataIterator GetCxData() {
return CxDataIterator(&encoder_);
}
void InitEncoder(VideoSource *video); void InitEncoder(VideoSource *video);
@ -106,14 +114,11 @@ class Encoder {
void EncodeFrame(VideoSource *video, const unsigned long frame_flags); void EncodeFrame(VideoSource *video, const unsigned long frame_flags);
// Convenience wrapper for EncodeFrame() // Convenience wrapper for EncodeFrame()
void EncodeFrame(VideoSource *video) { EncodeFrame(video, 0); } void EncodeFrame(VideoSource *video) {
EncodeFrame(video, 0);
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, int *arg) { void Control(int ctrl_id, int 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();
} }
@ -128,41 +133,25 @@ class Encoder {
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
void Control(int ctrl_id, struct vpx_svc_ref_frame_config *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_svc_parameters *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_svc_frame_drop *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER #if CONFIG_VP8_ENCODER || CONFIG_VP9_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();
} }
void Control(int ctrl_id, vpx_roi_map_t *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
#endif #endif
void Config(const vpx_codec_enc_cfg_t *cfg) { void Config(const vpx_codec_enc_cfg_t *cfg) {
const vpx_codec_err_t res = vpx_codec_enc_config_set(&encoder_, cfg); const vpx_codec_err_t res = vpx_codec_enc_config_set(&encoder_, cfg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
cfg_ = *cfg; cfg_ = *cfg;
} }
void set_deadline(unsigned long deadline) { deadline_ = deadline; } void set_deadline(unsigned long deadline) {
deadline_ = deadline;
}
protected: protected:
virtual vpx_codec_iface_t *CodecInterface() const = 0; virtual vpx_codec_iface_t* CodecInterface() const = 0;
const char *EncoderError() { const char *EncoderError() {
const char *detail = vpx_codec_error_detail(&encoder_); const char *detail = vpx_codec_error_detail(&encoder_);
@ -176,11 +165,11 @@ class Encoder {
// Flush the encoder on EOS // Flush the encoder on EOS
void Flush(); void Flush();
vpx_codec_ctx_t encoder_; vpx_codec_ctx_t encoder_;
vpx_codec_enc_cfg_t cfg_; vpx_codec_enc_cfg_t cfg_;
unsigned long deadline_; unsigned long deadline_;
unsigned long init_flags_; unsigned long init_flags_;
TwopassStatsStore *stats_; TwopassStatsStore *stats_;
}; };
// Common test functionality for all Encoder tests. // Common test functionality for all Encoder tests.
@ -222,40 +211,36 @@ class EncoderTest {
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*/) {}
virtual void PostEncodeFrameHook() {}
// 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 be called on every first pass stats packet.
virtual void StatsPktHook(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 {
return !(::testing::Test::HasFatalFailure() || abort_); return !(::testing::Test::HasFatalFailure() || abort_);
} }
const CodecFactory *codec_; const CodecFactory *codec_;
// Hook to determine whether to decode frame after encoding // Hook to determine whether to decode frame after encoding
virtual bool DoDecode() const { return 1; } virtual bool DoDecode() const { return 1; }
// Hook to handle encode/decode mismatch // Hook to handle encode/decode mismatch
virtual void MismatchHook(const vpx_image_t *img1, const vpx_image_t *img2); virtual void MismatchHook(const vpx_image_t *img1,
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. // Hook to be called to handle decode result. Return true to continue.
virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec, virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
const VideoSource & /*video*/, const VideoSource& /*video*/,
Decoder *decoder) { Decoder *decoder) {
EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError(); EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
return VPX_CODEC_OK == res_dec; return VPX_CODEC_OK == res_dec;
@ -267,15 +252,15 @@ class EncoderTest {
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_; vpx_codec_dec_cfg_t dec_cfg_;
unsigned int passes_; unsigned int passes_;
unsigned long deadline_; unsigned long deadline_;
TwopassStatsStore stats_; TwopassStatsStore stats_;
unsigned long init_flags_; unsigned long init_flags_;
unsigned long frame_flags_; unsigned long frame_flags_;
vpx_codec_pts_t last_pts_; vpx_codec_pts_t last_pts_;
}; };
} // namespace libvpx_test } // namespace libvpx_test

View File

@ -19,13 +19,15 @@ namespace {
const int kMaxErrorFrames = 12; const int kMaxErrorFrames = 12;
const int kMaxDroppableFrames = 12; const int kMaxDroppableFrames = 12;
class ErrorResilienceTestLarge class ErrorResilienceTestLarge : public ::libvpx_test::EncoderTest,
: public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, bool> {
protected: protected:
ErrorResilienceTestLarge() ErrorResilienceTestLarge()
: EncoderTest(GET_PARAM(0)), svc_support_(GET_PARAM(2)), psnr_(0.0), : EncoderTest(GET_PARAM(0)),
nframes_(0), mismatch_psnr_(0.0), mismatch_nframes_(0), psnr_(0.0),
nframes_(0),
mismatch_psnr_(0.0),
mismatch_nframes_(0),
encoding_mode_(GET_PARAM(1)) { encoding_mode_(GET_PARAM(1)) {
Reset(); Reset();
} }
@ -63,69 +65,81 @@ class ErrorResilienceTestLarge
// LAST is updated on base/layer 0, GOLDEN updated on layer 1. // LAST is updated on base/layer 0, GOLDEN updated on layer 1.
// Non-zero pattern_switch parameter means pattern will switch to // Non-zero pattern_switch parameter means pattern will switch to
// not using LAST for frame_num >= pattern_switch. // not using LAST for frame_num >= pattern_switch.
int SetFrameFlags(int frame_num, int num_temp_layers, int pattern_switch) { int SetFrameFlags(int frame_num,
int num_temp_layers,
int pattern_switch) {
int frame_flags = 0; int frame_flags = 0;
if (num_temp_layers == 2) { if (num_temp_layers == 2) {
if (frame_num % 2 == 0) { if (frame_num % 2 == 0) {
if (frame_num < pattern_switch || pattern_switch == 0) { if (frame_num < pattern_switch || pattern_switch == 0) {
// Layer 0: predict from LAST and ARF, update LAST. // Layer 0: predict from LAST and ARF, update LAST.
frame_flags = frame_flags = VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; 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 { } else {
// Layer 0: predict from GF and ARF, update GF. if (frame_num < pattern_switch || pattern_switch == 0) {
frame_flags = VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_UPD_LAST | // Layer 1: predict from L, GF, and ARF, update GF.
VP8_EFLAG_NO_UPD_ARF; 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;
}
} }
} 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; return frame_flags;
} }
virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video) { virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
frame_flags_ &= ::libvpx_test::Encoder *encoder) {
~(VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF); frame_flags_ &= ~(VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF);
// For temporal layer case. // For temporal layer case.
if (cfg_.ts_number_layers > 1) { if (cfg_.ts_number_layers > 1) {
frame_flags_ = frame_flags_ = SetFrameFlags(video->frame(),
SetFrameFlags(video->frame(), cfg_.ts_number_layers, pattern_switch_); cfg_.ts_number_layers,
pattern_switch_);
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: " << droppable_frames_[i] std::cout << "Encoding droppable frame: "
<< "\n"; << droppable_frames_[i] << "\n";
} }
} }
} else { } 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: " << droppable_frames_[i] std::cout << "Encoding droppable frame: "
<< "\n"; << droppable_frames_[i] << "\n";
frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ARF); VP8_EFLAG_NO_UPD_GF |
return; VP8_EFLAG_NO_UPD_ARF);
} return;
} }
} }
}
} }
} }
double GetAveragePsnr() const { double GetAveragePsnr() const {
if (nframes_) return psnr_ / nframes_; if (nframes_)
return psnr_ / nframes_;
return 0.0; return 0.0;
} }
double GetAverageMismatchPsnr() const { double GetAverageMismatchPsnr() const {
if (mismatch_nframes_) return mismatch_psnr_ / mismatch_nframes_; if (mismatch_nframes_)
return mismatch_psnr_ / mismatch_nframes_;
return 0.0; return 0.0;
} }
@ -143,7 +157,8 @@ class ErrorResilienceTestLarge
return 1; return 1;
} }
virtual void MismatchHook(const vpx_image_t *img1, const vpx_image_t *img2) { virtual void MismatchHook(const vpx_image_t *img1,
const vpx_image_t *img2) {
double mismatch_psnr = compute_psnr(img1, img2); double mismatch_psnr = compute_psnr(img1, img2);
mismatch_psnr_ += mismatch_psnr; mismatch_psnr_ += mismatch_psnr;
++mismatch_nframes_; ++mismatch_nframes_;
@ -151,34 +166,32 @@ class ErrorResilienceTestLarge
} }
void SetErrorFrames(int num, unsigned int *list) { void SetErrorFrames(int num, unsigned int *list) {
if (num > kMaxErrorFrames) { if (num > kMaxErrorFrames)
num = kMaxErrorFrames; num = kMaxErrorFrames;
} else if (num < 0) { else if (num < 0)
num = 0; num = 0;
}
error_nframes_ = num; error_nframes_ = num;
for (unsigned int i = 0; i < error_nframes_; ++i) { for (unsigned int i = 0; i < error_nframes_; ++i)
error_frames_[i] = list[i]; error_frames_[i] = list[i];
}
} }
void SetDroppableFrames(int num, unsigned int *list) { void SetDroppableFrames(int num, unsigned int *list) {
if (num > kMaxDroppableFrames) { if (num > kMaxDroppableFrames)
num = kMaxDroppableFrames; num = kMaxDroppableFrames;
} else if (num < 0) { else if (num < 0)
num = 0; num = 0;
}
droppable_nframes_ = num; droppable_nframes_ = num;
for (unsigned int i = 0; i < droppable_nframes_; ++i) { for (unsigned int i = 0; i < droppable_nframes_; ++i)
droppable_frames_[i] = list[i]; droppable_frames_[i] = list[i];
}
} }
unsigned int GetMismatchFrames() { return mismatch_nframes_; } unsigned int GetMismatchFrames() {
return mismatch_nframes_;
}
void SetPatternSwitch(int frame_switch) { pattern_switch_ = frame_switch; } void SetPatternSwitch(int frame_switch) {
pattern_switch_ = frame_switch;
bool svc_support_; }
private: private:
double psnr_; double psnr_;
@ -249,14 +262,15 @@ TEST_P(ErrorResilienceTestLarge, DropFramesWithoutRecovery) {
// In addition to isolated loss/drop, add a long consecutive series // In addition to isolated loss/drop, add a long consecutive series
// (of size 9) of dropped frames. // (of size 9) of dropped frames.
unsigned int num_droppable_frames = 11; unsigned int num_droppable_frames = 11;
unsigned int droppable_frame_list[] = { 5, 16, 22, 23, 24, 25, unsigned int droppable_frame_list[] = {5, 16, 22, 23, 24, 25, 26, 27, 28,
26, 27, 28, 29, 30 }; 29, 30};
SetDroppableFrames(num_droppable_frames, droppable_frame_list); SetDroppableFrames(num_droppable_frames, droppable_frame_list);
SetErrorFrames(num_droppable_frames, droppable_frame_list); SetErrorFrames(num_droppable_frames, droppable_frame_list);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// Test that no mismatches have been found // Test that no mismatches have been found
std::cout << " Mismatch frames: " << GetMismatchFrames() << "\n"; std::cout << " Mismatch frames: "
EXPECT_EQ(GetMismatchFrames(), (unsigned int)0); << GetMismatchFrames() << "\n";
EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
// Reset previously set of error/droppable frames. // Reset previously set of error/droppable frames.
Reset(); Reset();
@ -288,9 +302,6 @@ TEST_P(ErrorResilienceTestLarge, DropFramesWithoutRecovery) {
// two layer temporal pattern. The base layer does not predict from the top // two layer temporal pattern. The base layer does not predict from the top
// layer, so successful decoding is expected. // layer, so successful decoding is expected.
TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) { TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) {
// This test doesn't run if SVC is not supported.
if (!svc_support_) return;
const vpx_rational timebase = { 33333333, 1000000000 }; const vpx_rational timebase = { 33333333, 1000000000 };
cfg_.g_timebase = timebase; cfg_.g_timebase = timebase;
cfg_.rc_target_bitrate = 500; cfg_.rc_target_bitrate = 500;
@ -319,13 +330,14 @@ TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) {
// The odd frames are the enhancement layer for 2 layer pattern, so set // The odd frames are the enhancement layer for 2 layer pattern, so set
// those frames as droppable. Drop the last 7 frames. // those frames as droppable. Drop the last 7 frames.
unsigned int num_droppable_frames = 7; unsigned int num_droppable_frames = 7;
unsigned int droppable_frame_list[] = { 27, 29, 31, 33, 35, 37, 39 }; unsigned int droppable_frame_list[] = {27, 29, 31, 33, 35, 37, 39};
SetDroppableFrames(num_droppable_frames, droppable_frame_list); SetDroppableFrames(num_droppable_frames, droppable_frame_list);
SetErrorFrames(num_droppable_frames, droppable_frame_list); SetErrorFrames(num_droppable_frames, droppable_frame_list);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// Test that no mismatches have been found // Test that no mismatches have been found
std::cout << " Mismatch frames: " << GetMismatchFrames() << "\n"; std::cout << " Mismatch frames: "
EXPECT_EQ(GetMismatchFrames(), (unsigned int)0); << GetMismatchFrames() << "\n";
EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
// Reset previously set of error/droppable frames. // Reset previously set of error/droppable frames.
Reset(); Reset();
@ -335,9 +347,6 @@ TEST_P(ErrorResilienceTestLarge, 2LayersDropEnhancement) {
// for a two layer temporal pattern, where at some point in the // for a two layer temporal pattern, where at some point in the
// sequence, the LAST ref is not used anymore. // sequence, the LAST ref is not used anymore.
TEST_P(ErrorResilienceTestLarge, 2LayersNoRefLast) { TEST_P(ErrorResilienceTestLarge, 2LayersNoRefLast) {
// This test doesn't run if SVC is not supported.
if (!svc_support_) return;
const vpx_rational timebase = { 33333333, 1000000000 }; const vpx_rational timebase = { 33333333, 1000000000 };
cfg_.g_timebase = timebase; cfg_.g_timebase = timebase;
cfg_.rc_target_bitrate = 500; cfg_.rc_target_bitrate = 500;
@ -365,19 +374,20 @@ TEST_P(ErrorResilienceTestLarge, 2LayersNoRefLast) {
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// Test that no mismatches have been found // Test that no mismatches have been found
std::cout << " Mismatch frames: " << GetMismatchFrames() << "\n"; std::cout << " Mismatch frames: "
EXPECT_EQ(GetMismatchFrames(), (unsigned int)0); << GetMismatchFrames() << "\n";
EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
// Reset previously set of error/droppable frames. // Reset previously set of error/droppable frames.
Reset(); Reset();
} }
class ErrorResilienceTestLargeCodecControls class ErrorResilienceTestLargeCodecControls : public ::libvpx_test::EncoderTest,
: public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected: protected:
ErrorResilienceTestLargeCodecControls() ErrorResilienceTestLargeCodecControls()
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)) { : EncoderTest(GET_PARAM(0)),
encoding_mode_(GET_PARAM(1)) {
Reset(); Reset();
} }
@ -416,8 +426,8 @@ class ErrorResilienceTestLargeCodecControls
if (num_temp_layers == 2) { if (num_temp_layers == 2) {
if (frame_num % 2 == 0) { if (frame_num % 2 == 0) {
// Layer 0: predict from L and ARF, update L. // Layer 0: predict from L and ARF, update L.
frame_flags = frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; VP8_EFLAG_NO_UPD_ARF;
} else { } else {
// Layer 1: predict from L, G and ARF, and update G. // Layer 1: predict from L, G and ARF, and update G.
frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
@ -430,9 +440,9 @@ class ErrorResilienceTestLargeCodecControls
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF; VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
} else if ((frame_num - 2) % 4 == 0) { } else if ((frame_num - 2) % 4 == 0) {
// Layer 1: predict from L, G, update G. // Layer 1: predict from L, G, update G.
frame_flags = frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF; VP8_EFLAG_NO_REF_ARF;
} else if ((frame_num - 1) % 2 == 0) { } else if ((frame_num - 1) % 2 == 0) {
// Layer 2: predict from L, G, ARF; update ARG. // Layer 2: predict from L, G, ARF; update ARG.
frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
} }
@ -446,7 +456,7 @@ class ErrorResilienceTestLargeCodecControls
if (frame_num % 2 == 0) { if (frame_num % 2 == 0) {
layer_id = 0; layer_id = 0;
} else { } else {
layer_id = 1; layer_id = 1;
} }
} else if (num_temp_layers == 3) { } else if (num_temp_layers == 3) {
if (frame_num % 4 == 0) { if (frame_num % 4 == 0) {
@ -463,16 +473,16 @@ class ErrorResilienceTestLargeCodecControls
virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video, virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
libvpx_test::Encoder *encoder) { libvpx_test::Encoder *encoder) {
if (cfg_.ts_number_layers > 1) { if (cfg_.ts_number_layers > 1) {
int layer_id = SetLayerId(video->frame(), cfg_.ts_number_layers); int layer_id = SetLayerId(video->frame(), cfg_.ts_number_layers);
int frame_flags = SetFrameFlags(video->frame(), cfg_.ts_number_layers); int frame_flags = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
if (video->frame() > 0) { if (video->frame() > 0) {
encoder->Control(VP8E_SET_TEMPORAL_LAYER_ID, layer_id); encoder->Control(VP8E_SET_TEMPORAL_LAYER_ID, layer_id);
encoder->Control(VP8E_SET_FRAME_FLAGS, frame_flags); encoder->Control(VP8E_SET_FRAME_FLAGS, frame_flags);
} }
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;
return; return;
} }
} }
@ -498,28 +508,26 @@ class ErrorResilienceTestLargeCodecControls
virtual void EndPassHook(void) { virtual void EndPassHook(void) {
duration_ = (last_pts_ + 1) * timebase_; duration_ = (last_pts_ + 1) * timebase_;
if (cfg_.ts_number_layers > 1) { if (cfg_.ts_number_layers > 1) {
for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers); for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers);
++layer) { ++layer) {
if (bits_total_[layer]) { if (bits_total_[layer]) {
// Effective file datarate: // Effective file datarate:
effective_datarate_[layer] = effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_;
(bits_total_[layer] / 1000.0) / duration_;
} }
} }
} }
} }
double effective_datarate_[3]; double effective_datarate_[3];
private:
private: libvpx_test::TestMode encoding_mode_;
libvpx_test::TestMode encoding_mode_; vpx_codec_pts_t last_pts_;
vpx_codec_pts_t last_pts_; double timebase_;
double timebase_; int64_t bits_total_[3];
int64_t bits_total_[3]; double duration_;
double duration_; int tot_frame_number_;
int tot_frame_number_; };
};
// Check two codec controls used for: // Check two codec controls used for:
// (1) for setting temporal layer id, and (2) for settings encoder flags. // (1) for setting temporal layer id, and (2) for settings encoder flags.
@ -563,20 +571,16 @@ TEST_P(ErrorResilienceTestLargeCodecControls, CodecControl3TemporalLayers) {
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_.ts_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: " "for layer: " << j;
<< j;
ASSERT_LE(effective_datarate_[j], cfg_.ts_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: " "for layer: " << j;
<< j;
} }
} }
} }
VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES, VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES);
::testing::Values(true));
VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLargeCodecControls, VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTestLargeCodecControls,
ONE_PASS_TEST_MODES); ONE_PASS_TEST_MODES);
VP9_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES, VP9_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, ONE_PASS_TEST_MODES);
::testing::Values(true));
} // namespace } // 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 stress tools_common" exclude_list="examples 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

@ -24,6 +24,7 @@
namespace { namespace {
const int kVideoNameParam = 1; const int kVideoNameParam = 1;
const char kVP9TestFile[] = "vp90-2-02-size-lf-1920x1080.webm";
struct ExternalFrameBuffer { struct ExternalFrameBuffer {
uint8_t *data; uint8_t *data;
@ -35,18 +36,20 @@ struct ExternalFrameBuffer {
class ExternalFrameBufferList { class ExternalFrameBufferList {
public: public:
ExternalFrameBufferList() ExternalFrameBufferList()
: num_buffers_(0), num_used_buffers_(0), ext_fb_list_(NULL) {} : num_buffers_(0),
ext_fb_list_(NULL) {}
virtual ~ExternalFrameBufferList() { virtual ~ExternalFrameBufferList() {
for (int i = 0; i < num_buffers_; ++i) { for (int i = 0; i < num_buffers_; ++i) {
delete[] ext_fb_list_[i].data; delete [] ext_fb_list_[i].data;
} }
delete[] ext_fb_list_; delete [] ext_fb_list_;
} }
// Creates the list to hold the external buffers. Returns true on success. // Creates the list to hold the external buffers. Returns true on success.
bool CreateBufferList(int num_buffers) { bool CreateBufferList(int num_buffers) {
if (num_buffers < 0) return false; if (num_buffers < 0)
return false;
num_buffers_ = num_buffers; num_buffers_ = num_buffers;
ext_fb_list_ = new ExternalFrameBuffer[num_buffers_]; ext_fb_list_ = new ExternalFrameBuffer[num_buffers_];
@ -62,18 +65,17 @@ class ExternalFrameBufferList {
int GetFreeFrameBuffer(size_t min_size, vpx_codec_frame_buffer_t *fb) { int GetFreeFrameBuffer(size_t min_size, vpx_codec_frame_buffer_t *fb) {
EXPECT_TRUE(fb != NULL); EXPECT_TRUE(fb != NULL);
const int idx = FindFreeBufferIndex(); const int idx = FindFreeBufferIndex();
if (idx == num_buffers_) return -1; if (idx == num_buffers_)
return -1;
if (ext_fb_list_[idx].size < min_size) { if (ext_fb_list_[idx].size < min_size) {
delete[] ext_fb_list_[idx].data; delete [] ext_fb_list_[idx].data;
ext_fb_list_[idx].data = new uint8_t[min_size]; ext_fb_list_[idx].data = new uint8_t[min_size];
memset(ext_fb_list_[idx].data, 0, min_size); memset(ext_fb_list_[idx].data, 0, min_size);
ext_fb_list_[idx].size = min_size; ext_fb_list_[idx].size = min_size;
} }
SetFrameBuffer(idx, fb); SetFrameBuffer(idx, fb);
num_used_buffers_++;
return 0; return 0;
} }
@ -82,10 +84,11 @@ class ExternalFrameBufferList {
int GetZeroFrameBuffer(size_t min_size, vpx_codec_frame_buffer_t *fb) { int GetZeroFrameBuffer(size_t min_size, vpx_codec_frame_buffer_t *fb) {
EXPECT_TRUE(fb != NULL); EXPECT_TRUE(fb != NULL);
const int idx = FindFreeBufferIndex(); const int idx = FindFreeBufferIndex();
if (idx == num_buffers_) return -1; if (idx == num_buffers_)
return -1;
if (ext_fb_list_[idx].size < min_size) { if (ext_fb_list_[idx].size < min_size) {
delete[] ext_fb_list_[idx].data; delete [] ext_fb_list_[idx].data;
ext_fb_list_[idx].data = NULL; ext_fb_list_[idx].data = NULL;
ext_fb_list_[idx].size = min_size; ext_fb_list_[idx].size = min_size;
} }
@ -102,14 +105,13 @@ class ExternalFrameBufferList {
return -1; return -1;
} }
ExternalFrameBuffer *const ext_fb = ExternalFrameBuffer *const ext_fb =
reinterpret_cast<ExternalFrameBuffer *>(fb->priv); reinterpret_cast<ExternalFrameBuffer*>(fb->priv);
if (ext_fb == NULL) { if (ext_fb == NULL) {
EXPECT_TRUE(ext_fb != NULL); EXPECT_TRUE(ext_fb != NULL);
return -1; return -1;
} }
EXPECT_EQ(1, ext_fb->in_use); EXPECT_EQ(1, ext_fb->in_use);
ext_fb->in_use = 0; ext_fb->in_use = 0;
num_used_buffers_--;
return 0; return 0;
} }
@ -118,15 +120,13 @@ class ExternalFrameBufferList {
void CheckXImageFrameBuffer(const vpx_image_t *img) { void CheckXImageFrameBuffer(const vpx_image_t *img) {
if (img->fb_priv != NULL) { if (img->fb_priv != NULL) {
const struct ExternalFrameBuffer *const ext_fb = const struct ExternalFrameBuffer *const ext_fb =
reinterpret_cast<ExternalFrameBuffer *>(img->fb_priv); reinterpret_cast<ExternalFrameBuffer*>(img->fb_priv);
ASSERT_TRUE(img->planes[0] >= ext_fb->data && ASSERT_TRUE(img->planes[0] >= ext_fb->data &&
img->planes[0] < (ext_fb->data + ext_fb->size)); img->planes[0] < (ext_fb->data + ext_fb->size));
} }
} }
int num_used_buffers() const { return num_used_buffers_; }
private: private:
// Returns the index of the first free frame buffer. Returns |num_buffers_| // Returns the index of the first free frame buffer. Returns |num_buffers_|
// if there are no free frame buffers. // if there are no free frame buffers.
@ -134,7 +134,8 @@ class ExternalFrameBufferList {
int i; int i;
// Find a free frame buffer. // Find a free frame buffer.
for (i = 0; i < num_buffers_; ++i) { for (i = 0; i < num_buffers_; ++i) {
if (!ext_fb_list_[i].in_use) break; if (!ext_fb_list_[i].in_use)
break;
} }
return i; return i;
} }
@ -151,26 +152,24 @@ class ExternalFrameBufferList {
} }
int num_buffers_; int num_buffers_;
int num_used_buffers_;
ExternalFrameBuffer *ext_fb_list_; ExternalFrameBuffer *ext_fb_list_;
}; };
#if CONFIG_WEBM_IO
// Callback used by libvpx to request the application to return a frame // Callback used by libvpx to request the application to return a frame
// buffer of at least |min_size| in bytes. // buffer of at least |min_size| in bytes.
int get_vp9_frame_buffer(void *user_priv, size_t min_size, int get_vp9_frame_buffer(void *user_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb) { vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list = ExternalFrameBufferList *const fb_list =
reinterpret_cast<ExternalFrameBufferList *>(user_priv); reinterpret_cast<ExternalFrameBufferList*>(user_priv);
return fb_list->GetFreeFrameBuffer(min_size, fb); return fb_list->GetFreeFrameBuffer(min_size, fb);
} }
// Callback used by libvpx to tell the application that |fb| is not needed // Callback used by libvpx to tell the application that |fb| is not needed
// anymore. // anymore.
int release_vp9_frame_buffer(void *user_priv, vpx_codec_frame_buffer_t *fb) { int release_vp9_frame_buffer(void *user_priv,
vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list = ExternalFrameBufferList *const fb_list =
reinterpret_cast<ExternalFrameBufferList *>(user_priv); reinterpret_cast<ExternalFrameBufferList*>(user_priv);
return fb_list->ReturnFrameBuffer(fb); return fb_list->ReturnFrameBuffer(fb);
} }
@ -178,7 +177,7 @@ int release_vp9_frame_buffer(void *user_priv, vpx_codec_frame_buffer_t *fb) {
int get_vp9_zero_frame_buffer(void *user_priv, size_t min_size, int get_vp9_zero_frame_buffer(void *user_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb) { vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list = ExternalFrameBufferList *const fb_list =
reinterpret_cast<ExternalFrameBufferList *>(user_priv); reinterpret_cast<ExternalFrameBufferList*>(user_priv);
return fb_list->GetZeroFrameBuffer(min_size, fb); return fb_list->GetZeroFrameBuffer(min_size, fb);
} }
@ -186,7 +185,7 @@ int get_vp9_zero_frame_buffer(void *user_priv, size_t min_size,
int get_vp9_one_less_byte_frame_buffer(void *user_priv, size_t min_size, int get_vp9_one_less_byte_frame_buffer(void *user_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb) { vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferList *const fb_list = ExternalFrameBufferList *const fb_list =
reinterpret_cast<ExternalFrameBufferList *>(user_priv); reinterpret_cast<ExternalFrameBufferList*>(user_priv);
return fb_list->GetFreeFrameBuffer(min_size - 1, fb); return fb_list->GetFreeFrameBuffer(min_size - 1, fb);
} }
@ -198,19 +197,19 @@ int do_not_release_vp9_frame_buffer(void *user_priv,
return 0; return 0;
} }
#endif // CONFIG_WEBM_IO
// Class for testing passing in external frame buffers to libvpx. // Class for testing passing in external frame buffers to libvpx.
class ExternalFrameBufferMD5Test class ExternalFrameBufferMD5Test
: public ::libvpx_test::DecoderTest, : public ::libvpx_test::DecoderTest,
public ::libvpx_test::CodecTestWithParam<const char *> { public ::libvpx_test::CodecTestWithParam<const char*> {
protected: protected:
ExternalFrameBufferMD5Test() ExternalFrameBufferMD5Test()
: DecoderTest(GET_PARAM(::libvpx_test::kCodecFactoryParam)), : DecoderTest(GET_PARAM(::libvpx_test::kCodecFactoryParam)),
md5_file_(NULL), num_buffers_(0) {} md5_file_(NULL),
num_buffers_(0) {}
virtual ~ExternalFrameBufferMD5Test() { virtual ~ExternalFrameBufferMD5Test() {
if (md5_file_ != NULL) fclose(md5_file_); if (md5_file_ != NULL)
fclose(md5_file_);
} }
virtual void PreDecodeFrameHook( virtual void PreDecodeFrameHook(
@ -220,15 +219,15 @@ class ExternalFrameBufferMD5Test
// Have libvpx use frame buffers we create. // Have libvpx use frame buffers we create.
ASSERT_TRUE(fb_list_.CreateBufferList(num_buffers_)); ASSERT_TRUE(fb_list_.CreateBufferList(num_buffers_));
ASSERT_EQ(VPX_CODEC_OK, ASSERT_EQ(VPX_CODEC_OK,
decoder->SetFrameBufferFunctions(GetVP9FrameBuffer, decoder->SetFrameBufferFunctions(
ReleaseVP9FrameBuffer, this)); GetVP9FrameBuffer, ReleaseVP9FrameBuffer, this));
} }
} }
void OpenMD5File(const std::string &md5_file_name_) { void OpenMD5File(const std::string &md5_file_name_) {
md5_file_ = libvpx_test::OpenTestDataFile(md5_file_name_); md5_file_ = libvpx_test::OpenTestDataFile(md5_file_name_);
ASSERT_TRUE(md5_file_ != NULL) ASSERT_TRUE(md5_file_ != NULL) << "Md5 file open failed. Filename: "
<< "Md5 file open failed. Filename: " << md5_file_name_; << md5_file_name_;
} }
virtual void DecompressedFrameHook(const vpx_image_t &img, virtual void DecompressedFrameHook(const vpx_image_t &img,
@ -256,7 +255,7 @@ class ExternalFrameBufferMD5Test
static int GetVP9FrameBuffer(void *user_priv, size_t min_size, static int GetVP9FrameBuffer(void *user_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb) { vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferMD5Test *const md5Test = ExternalFrameBufferMD5Test *const md5Test =
reinterpret_cast<ExternalFrameBufferMD5Test *>(user_priv); reinterpret_cast<ExternalFrameBufferMD5Test*>(user_priv);
return md5Test->fb_list_.GetFreeFrameBuffer(min_size, fb); return md5Test->fb_list_.GetFreeFrameBuffer(min_size, fb);
} }
@ -265,7 +264,7 @@ class ExternalFrameBufferMD5Test
static int ReleaseVP9FrameBuffer(void *user_priv, static int ReleaseVP9FrameBuffer(void *user_priv,
vpx_codec_frame_buffer_t *fb) { vpx_codec_frame_buffer_t *fb) {
ExternalFrameBufferMD5Test *const md5Test = ExternalFrameBufferMD5Test *const md5Test =
reinterpret_cast<ExternalFrameBufferMD5Test *>(user_priv); reinterpret_cast<ExternalFrameBufferMD5Test*>(user_priv);
return md5Test->fb_list_.ReturnFrameBuffer(fb); return md5Test->fb_list_.ReturnFrameBuffer(fb);
} }
@ -279,13 +278,13 @@ class ExternalFrameBufferMD5Test
}; };
#if CONFIG_WEBM_IO #if CONFIG_WEBM_IO
const char kVP9TestFile[] = "vp90-2-02-size-lf-1920x1080.webm";
const char kVP9NonRefTestFile[] = "vp90-2-22-svc_1280x720_1.webm";
// Class for testing passing in external frame buffers to libvpx. // Class for testing passing in external frame buffers to libvpx.
class ExternalFrameBufferTest : public ::testing::Test { class ExternalFrameBufferTest : public ::testing::Test {
protected: protected:
ExternalFrameBufferTest() : video_(NULL), decoder_(NULL), num_buffers_(0) {} ExternalFrameBufferTest()
: video_(NULL),
decoder_(NULL),
num_buffers_(0) {}
virtual void SetUp() { virtual void SetUp() {
video_ = new libvpx_test::WebMVideoSource(kVP9TestFile); video_ = new libvpx_test::WebMVideoSource(kVP9TestFile);
@ -300,14 +299,13 @@ class ExternalFrameBufferTest : public ::testing::Test {
virtual void TearDown() { virtual void TearDown() {
delete decoder_; delete decoder_;
decoder_ = NULL;
delete video_; delete video_;
video_ = NULL;
} }
// Passes the external frame buffer information to libvpx. // Passes the external frame buffer information to libvpx.
vpx_codec_err_t SetFrameBufferFunctions( vpx_codec_err_t SetFrameBufferFunctions(
int num_buffers, vpx_get_frame_buffer_cb_fn_t cb_get, int num_buffers,
vpx_get_frame_buffer_cb_fn_t cb_get,
vpx_release_frame_buffer_cb_fn_t cb_release) { vpx_release_frame_buffer_cb_fn_t cb_release) {
if (num_buffers > 0) { if (num_buffers > 0) {
num_buffers_ = num_buffers; num_buffers_ = num_buffers;
@ -321,7 +319,8 @@ class ExternalFrameBufferTest : public ::testing::Test {
const vpx_codec_err_t res = const vpx_codec_err_t res =
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size()); decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
CheckDecodedFrames(); CheckDecodedFrames();
if (res == VPX_CODEC_OK) video_->Next(); if (res == VPX_CODEC_OK)
video_->Next();
return res; return res;
} }
@ -329,13 +328,14 @@ class ExternalFrameBufferTest : public ::testing::Test {
for (; video_->cxdata() != NULL; video_->Next()) { for (; video_->cxdata() != NULL; video_->Next()) {
const vpx_codec_err_t res = const vpx_codec_err_t res =
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size()); decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
if (res != VPX_CODEC_OK) return res; if (res != VPX_CODEC_OK)
return res;
CheckDecodedFrames(); CheckDecodedFrames();
} }
return VPX_CODEC_OK; return VPX_CODEC_OK;
} }
protected: private:
void CheckDecodedFrames() { void CheckDecodedFrames() {
libvpx_test::DxDataIterator dec_iter = decoder_->GetDxData(); libvpx_test::DxDataIterator dec_iter = decoder_->GetDxData();
const vpx_image_t *img = NULL; const vpx_image_t *img = NULL;
@ -351,25 +351,6 @@ class ExternalFrameBufferTest : public ::testing::Test {
int num_buffers_; int num_buffers_;
ExternalFrameBufferList fb_list_; ExternalFrameBufferList fb_list_;
}; };
class ExternalFrameBufferNonRefTest : public ExternalFrameBufferTest {
protected:
virtual void SetUp() {
video_ = new libvpx_test::WebMVideoSource(kVP9NonRefTestFile);
ASSERT_TRUE(video_ != NULL);
video_->Init();
video_->Begin();
vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
decoder_ = new libvpx_test::VP9Decoder(cfg, 0);
ASSERT_TRUE(decoder_ != NULL);
}
virtual void CheckFrameBufferRelease() {
TearDown();
ASSERT_EQ(0, fb_list_.num_used_buffers());
}
};
#endif // CONFIG_WEBM_IO #endif // CONFIG_WEBM_IO
// This test runs through the set of test vectors, and decodes them. // This test runs through the set of test vectors, and decodes them.
@ -379,6 +360,7 @@ class ExternalFrameBufferNonRefTest : public ExternalFrameBufferTest {
// Otherwise, the test failed. // Otherwise, the test failed.
TEST_P(ExternalFrameBufferMD5Test, ExtFBMD5Match) { TEST_P(ExternalFrameBufferMD5Test, ExtFBMD5Match) {
const std::string filename = GET_PARAM(kVideoNameParam); const std::string filename = GET_PARAM(kVideoNameParam);
libvpx_test::CompressedVideoSource *video = NULL;
// Number of buffers equals #VP9_MAXIMUM_REF_BUFFERS + // Number of buffers equals #VP9_MAXIMUM_REF_BUFFERS +
// #VPX_MAXIMUM_WORK_BUFFERS + four jitter buffers. // #VPX_MAXIMUM_WORK_BUFFERS + four jitter buffers.
@ -393,19 +375,18 @@ TEST_P(ExternalFrameBufferMD5Test, ExtFBMD5Match) {
#endif #endif
// Open compressed video file. // Open compressed video file.
testing::internal::scoped_ptr<libvpx_test::CompressedVideoSource> video;
if (filename.substr(filename.length() - 3, 3) == "ivf") { if (filename.substr(filename.length() - 3, 3) == "ivf") {
video.reset(new libvpx_test::IVFVideoSource(filename)); video = new libvpx_test::IVFVideoSource(filename);
} else { } else {
#if CONFIG_WEBM_IO #if CONFIG_WEBM_IO
video.reset(new libvpx_test::WebMVideoSource(filename)); video = new libvpx_test::WebMVideoSource(filename);
#else #else
fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n", fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
filename.c_str()); filename.c_str());
return; return;
#endif #endif
} }
ASSERT_TRUE(video.get() != NULL); ASSERT_TRUE(video != NULL);
video->Init(); video->Init();
// Construct md5 file name. // Construct md5 file name.
@ -413,7 +394,8 @@ TEST_P(ExternalFrameBufferMD5Test, ExtFBMD5Match) {
OpenMD5File(md5_filename); OpenMD5File(md5_filename);
// Decode frame, and check the md5 matching. // Decode frame, and check the md5 matching.
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get())); ASSERT_NO_FATAL_FAILURE(RunLoop(video));
delete video;
} }
#if CONFIG_WEBM_IO #if CONFIG_WEBM_IO
@ -422,8 +404,8 @@ TEST_F(ExternalFrameBufferTest, MinFrameBuffers) {
// #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS. // #VP9_MAXIMUM_REF_BUFFERS + #VPX_MAXIMUM_WORK_BUFFERS.
const int num_buffers = 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, ASSERT_EQ(VPX_CODEC_OK,
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer, SetFrameBufferFunctions(
release_vp9_frame_buffer)); num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames()); ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames());
} }
@ -434,8 +416,8 @@ TEST_F(ExternalFrameBufferTest, EightJitterBuffers) {
const int num_buffers = const int num_buffers =
VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS + jitter_buffers; VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS + jitter_buffers;
ASSERT_EQ(VPX_CODEC_OK, ASSERT_EQ(VPX_CODEC_OK,
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer, SetFrameBufferFunctions(
release_vp9_frame_buffer)); num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames()); ASSERT_EQ(VPX_CODEC_OK, DecodeRemainingFrames());
} }
@ -445,11 +427,9 @@ TEST_F(ExternalFrameBufferTest, NotEnoughBuffers) {
// only use 5 frame buffers at one time. // only use 5 frame buffers at one time.
const int num_buffers = 2; const int num_buffers = 2;
ASSERT_EQ(VPX_CODEC_OK, ASSERT_EQ(VPX_CODEC_OK,
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer, SetFrameBufferFunctions(
release_vp9_frame_buffer)); num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_OK, DecodeOneFrame()); ASSERT_EQ(VPX_CODEC_OK, DecodeOneFrame());
// Only run this on long clips. Decoding a very short clip will return
// VPX_CODEC_OK even with only 2 buffers.
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeRemainingFrames()); ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeRemainingFrames());
} }
@ -472,17 +452,18 @@ TEST_F(ExternalFrameBufferTest, NullRealloc) {
TEST_F(ExternalFrameBufferTest, ReallocOneLessByte) { TEST_F(ExternalFrameBufferTest, ReallocOneLessByte) {
const int num_buffers = 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( ASSERT_EQ(VPX_CODEC_OK,
num_buffers, get_vp9_one_less_byte_frame_buffer, SetFrameBufferFunctions(
release_vp9_frame_buffer)); num_buffers, get_vp9_one_less_byte_frame_buffer,
release_vp9_frame_buffer));
ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeOneFrame()); ASSERT_EQ(VPX_CODEC_MEM_ERROR, DecodeOneFrame());
} }
TEST_F(ExternalFrameBufferTest, NullGetFunction) { TEST_F(ExternalFrameBufferTest, NullGetFunction) {
const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS; const int num_buffers = VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
ASSERT_EQ( ASSERT_EQ(VPX_CODEC_INVALID_PARAM,
VPX_CODEC_INVALID_PARAM, SetFrameBufferFunctions(num_buffers, NULL,
SetFrameBufferFunctions(num_buffers, NULL, release_vp9_frame_buffer)); release_vp9_frame_buffer));
} }
TEST_F(ExternalFrameBufferTest, NullReleaseFunction) { TEST_F(ExternalFrameBufferTest, NullReleaseFunction) {
@ -495,23 +476,13 @@ TEST_F(ExternalFrameBufferTest, SetAfterDecode) {
const int num_buffers = 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, DecodeOneFrame()); ASSERT_EQ(VPX_CODEC_OK, DecodeOneFrame());
ASSERT_EQ(VPX_CODEC_ERROR, ASSERT_EQ(VPX_CODEC_ERROR,
SetFrameBufferFunctions(num_buffers, get_vp9_frame_buffer, SetFrameBufferFunctions(
release_vp9_frame_buffer)); num_buffers, get_vp9_frame_buffer, release_vp9_frame_buffer));
}
TEST_F(ExternalFrameBufferNonRefTest, ReleaseNonRefFrameBuffer) {
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());
CheckFrameBufferRelease();
} }
#endif // CONFIG_WEBM_IO #endif // CONFIG_WEBM_IO
VP9_INSTANTIATE_TEST_CASE( VP9_INSTANTIATE_TEST_CASE(ExternalFrameBufferMD5Test,
ExternalFrameBufferMD5Test, ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
::testing::ValuesIn(libvpx_test::kVP9TestVectors, libvpx_test::kVP9TestVectors +
libvpx_test::kVP9TestVectors + libvpx_test::kNumVP9TestVectors));
libvpx_test::kNumVP9TestVectors));
} // namespace } // namespace

539
test/fdct4x4_test.cc Normal file
View File

@ -0,0 +1,539 @@
/*
* 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 <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 "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_codec.h"
#include "vpx/vpx_integer.h"
using libvpx_test::ACMRandom;
namespace {
const int kNumCoeffs = 16;
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);
typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride,
int tx_type);
typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct4x4Param;
typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht4x4Param;
void fdct4x4_ref(const int16_t *in, tran_low_t *out, int stride,
int tx_type) {
vp9_fdct4x4_c(in, out, stride);
}
void fht4x4_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) {
vp9_fht4x4_c(in, out, stride, tx_type);
}
void fwht4x4_ref(const int16_t *in, tran_low_t *out, int stride,
int tx_type) {
vp9_fwht4x4_c(in, out, stride);
}
#if CONFIG_VP9_HIGHBITDEPTH
void idct4x4_10(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct4x4_16_add_c(in, out, stride, 10);
}
void idct4x4_12(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct4x4_16_add_c(in, out, stride, 12);
}
void iht4x4_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp9_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) {
vp9_highbd_iht4x4_16_add_c(in, out, stride, tx_type, 12);
}
void iwht4x4_10(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_iwht4x4_16_add_c(in, out, stride, 10);
}
void iwht4x4_12(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_iwht4x4_16_add_c(in, out, stride, 12);
}
#if HAVE_SSE2
void idct4x4_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct4x4_16_add_sse2(in, out, stride, 10);
}
void idct4x4_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct4x4_16_add_sse2(in, out, stride, 12);
}
#endif // HAVE_SSE2
#endif // CONFIG_VP9_HIGHBITDEPTH
class Trans4x4TestBase {
public:
virtual ~Trans4x4TestBase() {}
protected:
virtual void RunFwdTxfm(const int16_t *in, tran_low_t *out, int stride) = 0;
virtual void RunInvTxfm(const tran_low_t *out, uint8_t *dst, int stride) = 0;
void RunAccuracyCheck(int limit) {
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, tran_low_t, test_temp_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
#if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, kNumCoeffs);
#endif
// 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();
dst[j] = rnd.Rand8();
test_input_block[j] = src[j] - dst[j];
#if CONFIG_VP9_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,
test_temp_block, pitch_));
if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH
} else {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block,
CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif
}
for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VP9_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];
#endif
const uint32_t error = diff * diff;
if (max_error < error)
max_error = error;
total_error += error;
}
}
EXPECT_GE(static_cast<uint32_t>(limit), max_error)
<< "Error: 4x4 FHT/IHT has an individual round trip error > "
<< limit;
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, tran_low_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, output_block, kNumCoeffs);
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_].
for (int j = 0; j < kNumCoeffs; ++j)
input_block[j] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_);
fwd_txfm_ref(input_block, output_ref_block, pitch_, tx_type_);
ASM_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, tran_low_t, output_ref_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, output_block, kNumCoeffs);
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_].
for (int j = 0; j < kNumCoeffs; ++j) {
input_block[j] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_);
input_extreme_block[j] = rnd.Rand8() % 2 ? mask_ : -mask_;
}
if (i == 0) {
for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = mask_;
} else if (i == 1) {
for (int j = 0; j < kNumCoeffs; ++j)
input_extreme_block[j] = -mask_;
}
fwd_txfm_ref(input_extreme_block, output_ref_block, pitch_, tx_type_);
ASM_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 << (bit_depth_ - 8), abs(output_block[j]))
<< "Error: 4x4 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, tran_low_t, coeff, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
#if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, kNumCoeffs);
#endif
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_].
for (int j = 0; j < kNumCoeffs; ++j) {
if (bit_depth_ == VPX_BITS_8) {
src[j] = rnd.Rand8();
dst[j] = rnd.Rand8();
in[j] = src[j] - dst[j];
#if CONFIG_VP9_HIGHBITDEPTH
} else {
src16[j] = rnd.Rand16() & mask_;
dst16[j] = rnd.Rand16() & mask_;
in[j] = src16[j] - dst16[j];
#endif
}
}
fwd_txfm_ref(in, coeff, pitch_, tx_type_);
if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH
} else {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
pitch_));
#endif
}
for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VP9_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];
#endif
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_;
FhtFunc fwd_txfm_ref;
vpx_bit_depth_t bit_depth_;
int mask_;
};
class Trans4x4DCT
: public Trans4x4TestBase,
public ::testing::TestWithParam<Dct4x4Param> {
public:
virtual ~Trans4x4DCT() {}
virtual void SetUp() {
fwd_txfm_ = GET_PARAM(0);
inv_txfm_ = GET_PARAM(1);
tx_type_ = GET_PARAM(2);
pitch_ = 4;
fwd_txfm_ref = fdct4x4_ref;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
void RunFwdTxfm(const int16_t *in, tran_low_t *out, int stride) {
fwd_txfm_(in, out, stride);
}
void RunInvTxfm(const tran_low_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride);
}
FdctFunc fwd_txfm_;
IdctFunc inv_txfm_;
};
TEST_P(Trans4x4DCT, AccuracyCheck) {
RunAccuracyCheck(1);
}
TEST_P(Trans4x4DCT, CoeffCheck) {
RunCoeffCheck();
}
TEST_P(Trans4x4DCT, MemCheck) {
RunMemCheck();
}
TEST_P(Trans4x4DCT, InvAccuracyCheck) {
RunInvAccuracyCheck(1);
}
class Trans4x4HT
: public Trans4x4TestBase,
public ::testing::TestWithParam<Ht4x4Param> {
public:
virtual ~Trans4x4HT() {}
virtual void SetUp() {
fwd_txfm_ = GET_PARAM(0);
inv_txfm_ = GET_PARAM(1);
tx_type_ = GET_PARAM(2);
pitch_ = 4;
fwd_txfm_ref = fht4x4_ref;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
void RunFwdTxfm(const int16_t *in, tran_low_t *out, int stride) {
fwd_txfm_(in, out, stride, tx_type_);
}
void RunInvTxfm(const tran_low_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride, tx_type_);
}
FhtFunc fwd_txfm_;
IhtFunc inv_txfm_;
};
TEST_P(Trans4x4HT, AccuracyCheck) {
RunAccuracyCheck(1);
}
TEST_P(Trans4x4HT, CoeffCheck) {
RunCoeffCheck();
}
TEST_P(Trans4x4HT, MemCheck) {
RunMemCheck();
}
TEST_P(Trans4x4HT, InvAccuracyCheck) {
RunInvAccuracyCheck(1);
}
class Trans4x4WHT
: public Trans4x4TestBase,
public ::testing::TestWithParam<Dct4x4Param> {
public:
virtual ~Trans4x4WHT() {}
virtual void SetUp() {
fwd_txfm_ = GET_PARAM(0);
inv_txfm_ = GET_PARAM(1);
tx_type_ = GET_PARAM(2);
pitch_ = 4;
fwd_txfm_ref = fwht4x4_ref;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
void RunFwdTxfm(const int16_t *in, tran_low_t *out, int stride) {
fwd_txfm_(in, out, stride);
}
void RunInvTxfm(const tran_low_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride);
}
FdctFunc fwd_txfm_;
IdctFunc inv_txfm_;
};
TEST_P(Trans4x4WHT, AccuracyCheck) {
RunAccuracyCheck(0);
}
TEST_P(Trans4x4WHT, CoeffCheck) {
RunCoeffCheck();
}
TEST_P(Trans4x4WHT, MemCheck) {
RunMemCheck();
}
TEST_P(Trans4x4WHT, InvAccuracyCheck) {
RunInvAccuracyCheck(0);
}
using std::tr1::make_tuple;
#if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
C, Trans4x4DCT,
::testing::Values(
make_tuple(&vp9_highbd_fdct4x4_c, &idct4x4_10, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct4x4_c, &idct4x4_12, 0, VPX_BITS_12),
make_tuple(&vp9_fdct4x4_c, &vp9_idct4x4_16_add_c, 0, VPX_BITS_8)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans4x4DCT,
::testing::Values(
make_tuple(&vp9_fdct4x4_c, &vp9_idct4x4_16_add_c, 0, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
C, Trans4x4HT,
::testing::Values(
make_tuple(&vp9_highbd_fht4x4_c, &iht4x4_10, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_c, &iht4x4_10, 1, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_c, &iht4x4_10, 2, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_c, &iht4x4_10, 3, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_c, &iht4x4_12, 0, VPX_BITS_12),
make_tuple(&vp9_highbd_fht4x4_c, &iht4x4_12, 1, VPX_BITS_12),
make_tuple(&vp9_highbd_fht4x4_c, &iht4x4_12, 2, VPX_BITS_12),
make_tuple(&vp9_highbd_fht4x4_c, &iht4x4_12, 3, VPX_BITS_12),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 0, VPX_BITS_8),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 1, VPX_BITS_8),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 2, VPX_BITS_8),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 3, VPX_BITS_8)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans4x4HT,
::testing::Values(
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 0, VPX_BITS_8),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 1, VPX_BITS_8),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 2, VPX_BITS_8),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_c, 3, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
C, Trans4x4WHT,
::testing::Values(
make_tuple(&vp9_highbd_fwht4x4_c, &iwht4x4_10, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fwht4x4_c, &iwht4x4_12, 0, VPX_BITS_12),
make_tuple(&vp9_fwht4x4_c, &vp9_iwht4x4_16_add_c, 0, VPX_BITS_8)));
#else
INSTANTIATE_TEST_CASE_P(
C, Trans4x4WHT,
::testing::Values(
make_tuple(&vp9_fwht4x4_c, &vp9_iwht4x4_16_add_c, 0, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
NEON, Trans4x4DCT,
::testing::Values(
make_tuple(&vp9_fdct4x4_c,
&vp9_idct4x4_16_add_neon, 0, VPX_BITS_8)));
#endif // HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
NEON, Trans4x4HT,
::testing::Values(
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_neon, 0, VPX_BITS_8),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_neon, 1, VPX_BITS_8),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_neon, 2, VPX_BITS_8),
make_tuple(&vp9_fht4x4_c, &vp9_iht4x4_16_add_neon, 3, VPX_BITS_8)));
#endif // HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if CONFIG_USE_X86INC && HAVE_MMX && !CONFIG_VP9_HIGHBITDEPTH && \
!CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
MMX, Trans4x4WHT,
::testing::Values(
make_tuple(&vp9_fwht4x4_mmx, &vp9_iwht4x4_16_add_c, 0, VPX_BITS_8)));
#endif
#if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4DCT,
::testing::Values(
make_tuple(&vp9_fdct4x4_sse2,
&vp9_idct4x4_16_add_sse2, 0, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4HT,
::testing::Values(
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 0, VPX_BITS_8),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 1, VPX_BITS_8),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 2, VPX_BITS_8),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 3, VPX_BITS_8)));
#endif // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4DCT,
::testing::Values(
make_tuple(&vp9_highbd_fdct4x4_c, &idct4x4_10_sse2, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct4x4_sse2, &idct4x4_10_sse2, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct4x4_c, &idct4x4_12_sse2, 0, VPX_BITS_12),
make_tuple(&vp9_highbd_fdct4x4_sse2, &idct4x4_12_sse2, 0, VPX_BITS_12),
make_tuple(&vp9_fdct4x4_sse2, &vp9_idct4x4_16_add_c, 0,
VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4HT,
::testing::Values(
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_10, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_10, 1, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_10, 2, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_10, 3, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_12, 0, VPX_BITS_12),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_12, 1, VPX_BITS_12),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_12, 2, VPX_BITS_12),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_12, 3, VPX_BITS_12),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_c, 0, VPX_BITS_8),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_c, 1, VPX_BITS_8),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_c, 2, VPX_BITS_8),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_c, 3, VPX_BITS_8)));
#endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace

View File

@ -13,26 +13,56 @@
#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 "./vp9_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 "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h" #include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_scan.h"
#include "vpx/vpx_codec.h" #include "vpx/vpx_codec.h"
#include "vpx/vpx_integer.h" #include "vpx/vpx_integer.h"
#include "vpx_ports/mem.h"
const int kNumCoeffs = 64;
const double kPi = 3.141592653589793238462643383279502884;
void reference_8x8_dct_1d(const double in[8], double out[8], int stride) {
const double kInvSqrt2 = 0.707106781186547524400844362104;
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],
double output[kNumCoeffs]) {
// 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, 1);
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, 1);
// Scale by some magic number
for (int j = 0; j < 8; ++j)
output[j + i * 8] = temp_out[j] * 2;
}
}
using libvpx_test::ACMRandom; using libvpx_test::ACMRandom;
namespace { namespace {
const int kNumCoeffs = 64;
const double kPi = 3.141592653589793238462643383279502884;
const int kSignBiasMaxDiff255 = 1500; const int kSignBiasMaxDiff255 = 1500;
const int kSignBiasMaxDiff15 = 10000; const int kSignBiasMaxDiff15 = 10000;
@ -43,43 +73,12 @@ typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride,
typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride,
int tx_type); int tx_type);
typedef ::testing::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct8x8Param; typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct8x8Param;
typedef ::testing::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht8x8Param; typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht8x8Param;
typedef ::testing::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t> Idct8x8Param; 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, tran_low_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],
double output[kNumCoeffs]) {
// 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) { void fht8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) {
@ -88,45 +87,44 @@ void fht8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) {
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
void idct8x8_10(const tran_low_t *in, uint8_t *out, int stride) { void idct8x8_10(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, 10); vp9_highbd_idct8x8_64_add_c(in, out, stride, 10);
} }
void idct8x8_12(const tran_low_t *in, uint8_t *out, int stride) { void idct8x8_12(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, 12); vp9_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) { void iht8x8_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp9_highbd_iht8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, tx_type, 10); vp9_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) { void iht8x8_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp9_highbd_iht8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, tx_type, 12); vp9_highbd_iht8x8_64_add_c(in, out, stride, tx_type, 12);
}
void idct8x8_10_add_10_c(const tran_low_t *in, uint8_t *out, int stride) {
vp9_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) {
vp9_highbd_idct8x8_10_add_c(in, out, stride, 12);
} }
#if HAVE_SSE2 #if HAVE_SSE2
void idct8x8_10_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
void idct8x8_12_add_10_c(const tran_low_t *in, uint8_t *out, int stride) { vp9_highbd_idct8x8_10_add_sse2(in, out, stride, 10);
vpx_highbd_idct8x8_12_add_c(in, CAST_TO_SHORTPTR(out), stride, 10);
} }
void idct8x8_12_add_12_c(const tran_low_t *in, uint8_t *out, int stride) { void idct8x8_10_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_12_add_c(in, CAST_TO_SHORTPTR(out), stride, 12); vp9_highbd_idct8x8_10_add_sse2(in, out, stride, 12);
}
void idct8x8_12_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_12_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 10);
}
void idct8x8_12_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_12_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 12);
} }
void idct8x8_64_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) { void idct8x8_64_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_64_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 10); vp9_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) { void idct8x8_64_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vpx_highbd_idct8x8_64_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 12); vp9_highbd_idct8x8_64_add_sse2(in, out, stride, 12);
} }
#endif // HAVE_SSE2 #endif // HAVE_SSE2
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
@ -141,8 +139,8 @@ class FwdTrans8x8TestBase {
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, tran_low_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;
@ -150,19 +148,17 @@ 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.Rand16() >> (16 - bit_depth_)) & mask_) -
((rnd.Rand16() >> (16 - bit_depth_)) & mask_); ((rnd.Rand16() >> (16 - bit_depth_)) & mask_);
}
ASM_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) {
if (test_output_block[j] < 0) { if (test_output_block[j] < 0)
++count_sign_block[j][0]; ++count_sign_block[j][0];
} else if (test_output_block[j] > 0) { else if (test_output_block[j] > 0)
++count_sign_block[j][1]; ++count_sign_block[j][1];
}
} }
} }
@ -174,26 +170,25 @@ class FwdTrans8x8TestBase {
<< 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
<< " count0: " << count_sign_block[j][0] << " count0: " << count_sign_block[j][0]
<< " count1: " << count_sign_block[j][1] << " diff: " << diff; << " count1: " << count_sign_block[j][1]
<< " diff: " << diff;
} }
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 [-mask_ / 16, mask_ / 16].
for (int j = 0; j < 64; ++j) { for (int j = 0; j < 64; ++j)
test_input_block[j] = test_input_block[j] = ((rnd.Rand16() & mask_) >> 4) -
((rnd.Rand16() & mask_) >> 4) - ((rnd.Rand16() & mask_) >> 4); ((rnd.Rand16() & mask_) >> 4);
}
ASM_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) {
if (test_output_block[j] < 0) { if (test_output_block[j] < 0)
++count_sign_block[j][0]; ++count_sign_block[j][0];
} else if (test_output_block[j] > 0) { else if (test_output_block[j] > 0)
++count_sign_block[j][1]; ++count_sign_block[j][1];
}
} }
} }
@ -205,7 +200,8 @@ class FwdTrans8x8TestBase {
<< 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]
<< " count1: " << count_sign_block[j][1] << " diff: " << diff; << " count1: " << count_sign_block[j][1]
<< " diff: " << diff;
} }
} }
@ -214,13 +210,13 @@ 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, tran_low_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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[64]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, 64);
DECLARE_ALIGNED(16, uint16_t, src16[64]); DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, 64);
#endif #endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
@ -242,22 +238,23 @@ class FwdTrans8x8TestBase {
ASM_REGISTER_STATE_CHECK( ASM_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) {
test_temp_block[j] += 2; test_temp_block[j] += 2;
test_temp_block[j] /= 4; test_temp_block[j] /= 4;
test_temp_block[j] *= 4; test_temp_block[j] *= 4;
} else { } else {
test_temp_block[j] -= 2; test_temp_block[j] -= 2;
test_temp_block[j] /= 4; test_temp_block[j] /= 4;
test_temp_block[j] *= 4; test_temp_block[j] *= 4;
} }
} }
if (bit_depth_ == VPX_BITS_8) { if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_)); ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
ASM_REGISTER_STATE_CHECK( ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, CAST_TO_BYTEPTR(dst16), pitch_)); RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif #endif
} }
@ -269,18 +266,19 @@ class FwdTrans8x8TestBase {
const int diff = dst[j] - src[j]; const int diff = dst[j] - src[j];
#endif #endif
const int error = diff * diff; const int error = diff * diff;
if (max_error < error) max_error = error; if (max_error < error)
max_error = error;
total_error += error; total_error += error;
} }
} }
EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error) EXPECT_GE(1 << 2 * (bit_depth_ - 8), 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 << 2 * (bit_depth_ - 8))/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";
} }
void RunExtremalCheck() { void RunExtremalCheck() {
@ -289,14 +287,14 @@ 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, tran_low_t, test_temp_block, 64);
DECLARE_ALIGNED(16, tran_low_t, ref_temp_block[64]); DECLARE_ALIGNED_ARRAY(16, tran_low_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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[64]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, 64);
DECLARE_ALIGNED(16, uint16_t, src16[64]); DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, 64);
#endif #endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
@ -336,11 +334,12 @@ class FwdTrans8x8TestBase {
ASM_REGISTER_STATE_CHECK( ASM_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) { if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_)); ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
ASM_REGISTER_STATE_CHECK( ASM_REGISTER_STATE_CHECK(
RunInvTxfm(test_temp_block, CAST_TO_BYTEPTR(dst16), pitch_)); RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
#endif #endif
} }
@ -352,7 +351,8 @@ class FwdTrans8x8TestBase {
const int diff = dst[j] - src[j]; const int diff = dst[j] - src[j];
#endif #endif
const int error = diff * diff; const int error = diff * diff;
if (max_error < error) max_error = error; if (max_error < error)
max_error = error;
total_error += error; total_error += error;
const int coeff_diff = test_temp_block[j] - ref_temp_block[j]; const int coeff_diff = test_temp_block[j] - ref_temp_block[j];
@ -363,7 +363,7 @@ class FwdTrans8x8TestBase {
<< "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 << 2 * (bit_depth_ - 8))/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";
@ -376,13 +376,13 @@ class FwdTrans8x8TestBase {
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, tran_low_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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, kNumCoeffs);
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
#endif #endif
for (int i = 0; i < count_test_block; ++i) { for (int i = 0; i < count_test_block; ++i) {
@ -404,29 +404,29 @@ class FwdTrans8x8TestBase {
} }
reference_8x8_dct_2d(in, out_r); reference_8x8_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] = static_cast<tran_low_t>(round(out_r[j]));
}
if (bit_depth_ == VPX_BITS_8) { if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_)); ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
ASM_REGISTER_STATE_CHECK( ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
RunInvTxfm(coeff, CAST_TO_BYTEPTR(dst16), pitch_)); pitch_));
#endif #endif
} }
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
const int diff = const uint32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
#else #else
const int diff = dst[j] - src[j]; const uint32_t diff = dst[j] - src[j];
#endif #endif
const uint32_t error = diff * diff; const uint32_t error = diff * diff;
EXPECT_GE(1u << 2 * (bit_depth_ - 8), error) EXPECT_GE(1u << 2 * (bit_depth_ - 8), error)
<< "Error: 8x8 IDCT has error " << error << " at index " << j; << "Error: 8x8 IDCT has error " << error
<< " at index " << j;
} }
} }
} }
@ -434,43 +434,42 @@ class FwdTrans8x8TestBase {
void RunFwdAccuracyCheck() { void RunFwdAccuracyCheck() {
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_r[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff_r, kNumCoeffs);
DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff, kNumCoeffs);
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 [-mask_, mask_]. // Initialize a test block with input range [-mask_, mask_].
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j)
in[j] = rnd.Rand8() % 2 == 0 ? mask_ : -mask_; in[j] = rnd.Rand8() % 2 == 0 ? mask_ : -mask_;
}
RunFwdTxfm(in, coeff, pitch_); RunFwdTxfm(in, coeff, pitch_);
reference_8x8_dct_2d(in, out_r); reference_8x8_dct_2d(in, out_r);
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j)
coeff_r[j] = static_cast<tran_low_t>(round(out_r[j])); coeff_r[j] = static_cast<tran_low_t>(round(out_r[j]));
}
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
const int32_t diff = coeff[j] - coeff_r[j]; const uint32_t diff = coeff[j] - coeff_r[j];
const uint32_t error = diff * diff; const uint32_t error = diff * diff;
EXPECT_GE(9u << 2 * (bit_depth_ - 8), error) EXPECT_GE(9u << 2 * (bit_depth_ - 8), error)
<< "Error: 8x8 DCT has error " << error << " at index " << j; << "Error: 8x8 DCT has error " << error
<< " at index " << j;
} }
} }
} }
void CompareInvReference(IdctFunc ref_txfm, int thresh) { void CompareInvReference(IdctFunc ref_txfm, int thresh) {
ACMRandom rnd(ACMRandom::DeterministicSeed()); ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 10000; const int count_test_block = 10000;
const int eob = 12; const int eob = 12;
DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff, 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_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED(16, uint16_t, ref16[kNumCoeffs]); DECLARE_ALIGNED_ARRAY(16, uint16_t, ref16, kNumCoeffs);
#endif #endif
const int16_t *scan = vp9_default_scan_orders[TX_8X8].scan; const int16_t *scan = vp9_default_scan_orders[TX_8X8].scan;
@ -478,7 +477,7 @@ class FwdTrans8x8TestBase {
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
if (j < eob) { if (j < eob) {
// Random values less than the threshold, either positive or negative // Random values less than the threshold, either positive or negative
coeff[scan[j]] = rnd(thresh) * (1 - 2 * (i % 2)); coeff[scan[j]] = rnd(thresh) * (1-2*(i%2));
} else { } else {
coeff[scan[j]] = 0; coeff[scan[j]] = 0;
} }
@ -497,22 +496,23 @@ class FwdTrans8x8TestBase {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_)); ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
} else { } else {
ref_txfm(coeff, CAST_TO_BYTEPTR(ref16), pitch_); ref_txfm(coeff, CONVERT_TO_BYTEPTR(ref16), pitch_);
ASM_REGISTER_STATE_CHECK( ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
RunInvTxfm(coeff, CAST_TO_BYTEPTR(dst16), pitch_)); pitch_));
#endif #endif
} }
for (int j = 0; j < kNumCoeffs; ++j) { for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
const int diff = const uint32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - ref[j] : dst16[j] - ref16[j]; bit_depth_ == VPX_BITS_8 ? dst[j] - ref[j] : dst16[j] - ref16[j];
#else #else
const int diff = dst[j] - ref[j]; const uint32_t diff = dst[j] - ref[j];
#endif #endif
const uint32_t error = diff * diff; const uint32_t error = diff * diff;
EXPECT_EQ(0u, error) EXPECT_EQ(0u, error)
<< "Error: 8x8 IDCT has error " << error << " at index " << j; << "Error: 8x8 IDCT has error " << error
<< " at index " << j;
} }
} }
} }
@ -523,16 +523,17 @@ class FwdTrans8x8TestBase {
int mask_; int mask_;
}; };
class FwdTrans8x8DCT : public FwdTrans8x8TestBase, class FwdTrans8x8DCT
public ::testing::TestWithParam<Dct8x8Param> { : public FwdTrans8x8TestBase,
public ::testing::TestWithParam<Dct8x8Param> {
public: public:
virtual ~FwdTrans8x8DCT() {} virtual ~FwdTrans8x8DCT() {}
virtual void SetUp() { virtual void SetUp() {
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);
pitch_ = 8; pitch_ = 8;
fwd_txfm_ref = fdct8x8_ref; fwd_txfm_ref = fdct8x8_ref;
bit_depth_ = GET_PARAM(3); bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1; mask_ = (1 << bit_depth_) - 1;
@ -552,26 +553,37 @@ class FwdTrans8x8DCT : public FwdTrans8x8TestBase,
IdctFunc inv_txfm_; IdctFunc inv_txfm_;
}; };
TEST_P(FwdTrans8x8DCT, SignBiasCheck) { RunSignBiasCheck(); } TEST_P(FwdTrans8x8DCT, SignBiasCheck) {
RunSignBiasCheck();
}
TEST_P(FwdTrans8x8DCT, RoundTripErrorCheck) { RunRoundTripErrorCheck(); } TEST_P(FwdTrans8x8DCT, RoundTripErrorCheck) {
RunRoundTripErrorCheck();
}
TEST_P(FwdTrans8x8DCT, ExtremalCheck) { RunExtremalCheck(); } TEST_P(FwdTrans8x8DCT, ExtremalCheck) {
RunExtremalCheck();
}
TEST_P(FwdTrans8x8DCT, FwdAccuracyCheck) { RunFwdAccuracyCheck(); } TEST_P(FwdTrans8x8DCT, FwdAccuracyCheck) {
RunFwdAccuracyCheck();
}
TEST_P(FwdTrans8x8DCT, InvAccuracyCheck) { RunInvAccuracyCheck(); } TEST_P(FwdTrans8x8DCT, InvAccuracyCheck) {
RunInvAccuracyCheck();
}
class FwdTrans8x8HT : public FwdTrans8x8TestBase, class FwdTrans8x8HT
public ::testing::TestWithParam<Ht8x8Param> { : public FwdTrans8x8TestBase,
public ::testing::TestWithParam<Ht8x8Param> {
public: public:
virtual ~FwdTrans8x8HT() {} virtual ~FwdTrans8x8HT() {}
virtual void SetUp() { virtual void SetUp() {
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);
pitch_ = 8; pitch_ = 8;
fwd_txfm_ref = fht8x8_ref; fwd_txfm_ref = fht8x8_ref;
bit_depth_ = GET_PARAM(3); bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1; mask_ = (1 << bit_depth_) - 1;
@ -591,14 +603,21 @@ class FwdTrans8x8HT : public FwdTrans8x8TestBase,
IhtFunc inv_txfm_; IhtFunc inv_txfm_;
}; };
TEST_P(FwdTrans8x8HT, SignBiasCheck) { RunSignBiasCheck(); } TEST_P(FwdTrans8x8HT, SignBiasCheck) {
RunSignBiasCheck();
}
TEST_P(FwdTrans8x8HT, RoundTripErrorCheck) { RunRoundTripErrorCheck(); } TEST_P(FwdTrans8x8HT, RoundTripErrorCheck) {
RunRoundTripErrorCheck();
}
TEST_P(FwdTrans8x8HT, ExtremalCheck) { RunExtremalCheck(); } TEST_P(FwdTrans8x8HT, ExtremalCheck) {
RunExtremalCheck();
}
class InvTrans8x8DCT : public FwdTrans8x8TestBase, class InvTrans8x8DCT
public ::testing::TestWithParam<Idct8x8Param> { : public FwdTrans8x8TestBase,
public ::testing::TestWithParam<Idct8x8Param> {
public: public:
virtual ~InvTrans8x8DCT() {} virtual ~InvTrans8x8DCT() {}
@ -617,7 +636,7 @@ class InvTrans8x8DCT : public FwdTrans8x8TestBase,
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride); inv_txfm_(out, dst, stride);
} }
void RunFwdTxfm(int16_t * /*out*/, tran_low_t * /*dst*/, int /*stride*/) {} void RunFwdTxfm(int16_t *out, tran_low_t *dst, int stride) {}
IdctFunc ref_txfm_; IdctFunc ref_txfm_;
IdctFunc inv_txfm_; IdctFunc inv_txfm_;
@ -628,20 +647,20 @@ TEST_P(InvTrans8x8DCT, CompareReference) {
CompareInvReference(ref_txfm_, thresh_); CompareInvReference(ref_txfm_, thresh_);
} }
using ::testing::make_tuple; using std::tr1::make_tuple;
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_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, VPX_BITS_8),
make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_10, 0, VPX_BITS_10), make_tuple(&vp9_highbd_fdct8x8_c, &idct8x8_10, 0, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_12, 0, VPX_BITS_12))); make_tuple(&vp9_highbd_fdct8x8_c, &idct8x8_12, 0, VPX_BITS_12)));
#else #else
INSTANTIATE_TEST_CASE_P(C, FwdTrans8x8DCT, INSTANTIATE_TEST_CASE_P(
::testing::Values(make_tuple(&vpx_fdct8x8_c, C, FwdTrans8x8DCT,
&vpx_idct8x8_64_add_c, 0, ::testing::Values(
VPX_BITS_8))); make_tuple(&vp9_fdct8x8_c, &vp9_idct8x8_64_add_c, 0, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
@ -661,6 +680,8 @@ INSTANTIATE_TEST_CASE_P(
make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8),
make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8))); make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8)));
#else #else
// TODO(jingning): re-enable after this handles the expanded range [0, 65535]
// returned from Rand16().
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
C, FwdTrans8x8HT, C, FwdTrans8x8HT,
::testing::Values( ::testing::Values(
@ -670,13 +691,17 @@ INSTANTIATE_TEST_CASE_P(
make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8))); make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8)));
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
#if HAVE_NEON && !CONFIG_EMULATE_HARDWARE #if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(NEON, FwdTrans8x8DCT, // TODO(jingning): re-enable after this handles the expanded range [0, 65535]
::testing::Values(make_tuple(&vpx_fdct8x8_neon, // returned from Rand16().
&vpx_idct8x8_64_add_neon, INSTANTIATE_TEST_CASE_P(
0, VPX_BITS_8))); NEON, FwdTrans8x8DCT,
::testing::Values(
make_tuple(&vp9_fdct8x8_neon, &vp9_idct8x8_64_add_neon, 0,
VPX_BITS_8)));
#endif // HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if !CONFIG_VP9_HIGHBITDEPTH #if HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
NEON, FwdTrans8x8HT, NEON, FwdTrans8x8HT,
::testing::Values( ::testing::Values(
@ -684,14 +709,16 @@ INSTANTIATE_TEST_CASE_P(
make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 1, VPX_BITS_8), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 1, VPX_BITS_8),
make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 2, VPX_BITS_8), make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 2, VPX_BITS_8),
make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 3, VPX_BITS_8))); make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 3, VPX_BITS_8)));
#endif // !CONFIG_VP9_HIGHBITDEPTH #endif // HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#endif // HAVE_NEON && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(SSE2, FwdTrans8x8DCT, // TODO(jingning): re-enable after these handle the expanded range [0, 65535]
::testing::Values(make_tuple(&vpx_fdct8x8_sse2, // returned from Rand16().
&vpx_idct8x8_64_add_sse2, INSTANTIATE_TEST_CASE_P(
0, VPX_BITS_8))); SSE2, FwdTrans8x8DCT,
::testing::Values(
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(
@ -704,17 +731,19 @@ INSTANTIATE_TEST_CASE_P(
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, FwdTrans8x8DCT, SSE2, FwdTrans8x8DCT,
::testing::Values(make_tuple(&vpx_fdct8x8_sse2, &vpx_idct8x8_64_add_c, 0, ::testing::Values(
VPX_BITS_8), make_tuple(&vp9_fdct8x8_sse2, &vp9_idct8x8_64_add_c, 0, VPX_BITS_8),
make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_64_add_10_sse2, make_tuple(&vp9_highbd_fdct8x8_c,
12, VPX_BITS_10), &idct8x8_64_add_10_sse2, 12, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct8x8_sse2, make_tuple(&vp9_highbd_fdct8x8_sse2,
&idct8x8_64_add_10_sse2, 12, VPX_BITS_10), &idct8x8_64_add_10_sse2, 12, VPX_BITS_10),
make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_64_add_12_sse2, make_tuple(&vp9_highbd_fdct8x8_c,
12, VPX_BITS_12), &idct8x8_64_add_12_sse2, 12, VPX_BITS_12),
make_tuple(&vpx_highbd_fdct8x8_sse2, make_tuple(&vp9_highbd_fdct8x8_sse2,
&idct8x8_64_add_12_sse2, 12, VPX_BITS_12))); &idct8x8_64_add_12_sse2, 12, VPX_BITS_12)));
// TODO(jingning): re-enable after these handle the expanded range [0, 65535]
// returned from Rand16().
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, FwdTrans8x8HT, SSE2, FwdTrans8x8HT,
::testing::Values( ::testing::Values(
@ -728,40 +757,24 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
SSE2, InvTrans8x8DCT, SSE2, InvTrans8x8DCT,
::testing::Values( ::testing::Values(
make_tuple(&idct8x8_12_add_10_c, &idct8x8_12_add_10_sse2, 6225, make_tuple(&idct8x8_10_add_10_c,
VPX_BITS_10), &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,
make_tuple(&idct8x8_12_add_12_c, &idct8x8_12_add_12_sse2, 6225, &idct8x8_64_add_10_sse2, 6225, VPX_BITS_10),
VPX_BITS_12), make_tuple(&idct8x8_10_add_12_c,
make_tuple(&idct8x8_12, &idct8x8_64_add_12_sse2, 6225, VPX_BITS_12))); &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_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE #endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_SSSE3 && ARCH_X86_64 && !CONFIG_VP9_HIGHBITDEPTH && \ #if HAVE_SSSE3 && ARCH_X86_64 && !CONFIG_VP9_HIGHBITDEPTH && \
!CONFIG_EMULATE_HARDWARE !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(SSSE3, FwdTrans8x8DCT, // TODO(jingning): re-enable after this handles the expanded range [0, 65535]
::testing::Values(make_tuple(&vpx_fdct8x8_ssse3, // returned from Rand16().
&vpx_idct8x8_64_add_sse2,
0, VPX_BITS_8)));
#endif
#if HAVE_MSA && !CONFIG_VP9_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( INSTANTIATE_TEST_CASE_P(
MSA, FwdTrans8x8HT, SSSE3, FwdTrans8x8DCT,
::testing::Values( ::testing::Values(
make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 0, VPX_BITS_8), make_tuple(&vp9_fdct8x8_ssse3, &vp9_idct8x8_64_add_ssse3, 0,
make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 1, VPX_BITS_8), VPX_BITS_8)));
make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 2, VPX_BITS_8), #endif
make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 3, VPX_BITS_8)));
#endif // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
#if HAVE_VSX && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(VSX, FwdTrans8x8DCT,
::testing::Values(make_tuple(&vpx_fdct8x8_c,
&vpx_idct8x8_64_add_vsx, 0,
VPX_BITS_8)));
#endif // HAVE_VSX && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
} // namespace } // namespace

View File

@ -13,11 +13,12 @@
namespace { namespace {
class VP9FrameSizeTestsLarge : public ::libvpx_test::EncoderTest, class VP9FrameSizeTestsLarge
public ::testing::Test { : public ::libvpx_test::EncoderTest,
public ::testing::Test {
protected: protected:
VP9FrameSizeTestsLarge() VP9FrameSizeTestsLarge() : EncoderTest(&::libvpx_test::kVP9),
: EncoderTest(&::libvpx_test::kVP9), expected_res_(VPX_CODEC_OK) {} expected_res_(VPX_CODEC_OK) {}
virtual ~VP9FrameSizeTestsLarge() {} virtual ~VP9FrameSizeTestsLarge() {}
virtual void SetUp() { virtual void SetUp() {
@ -26,7 +27,7 @@ class VP9FrameSizeTestsLarge : public ::libvpx_test::EncoderTest,
} }
virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec, virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
const libvpx_test::VideoSource & /*video*/, const libvpx_test::VideoSource& /*video*/,
libvpx_test::Decoder *decoder) { libvpx_test::Decoder *decoder) {
EXPECT_EQ(expected_res_, res_dec) << decoder->DecodeError(); EXPECT_EQ(expected_res_, res_dec) << decoder->DecodeError();
return !::testing::Test::HasFailure(); return !::testing::Test::HasFailure();
@ -66,14 +67,14 @@ TEST_F(VP9FrameSizeTestsLarge, ValidSizes) {
expected_res_ = VPX_CODEC_OK; expected_res_ = VPX_CODEC_OK;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
#else #else
// This test produces a pretty large single frame allocation, (roughly // This test produces a pretty large single frame allocation, (roughly
// 25 megabits). The encoder allocates a good number of these frames // 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 // 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 // reference buffer (8) - we can end up with up to 30 buffers of roughly this
// size or almost 1 gig of memory. // size or almost 1 gig of memory.
// In total the allocations will exceed 2GiB which may cause a failure with // In total the allocations will exceed 2GiB which may cause a failure with
// mingw + wine, use a smaller size in that case. // mingw + wine, use a smaller size in that case.
#if defined(_WIN32) && !defined(_WIN64) || defined(__OS2__) #if defined(_WIN32) && !defined(_WIN64)
video.SetSize(4096, 3072); video.SetSize(4096, 3072);
#else #else
video.SetSize(4096, 4096); video.SetSize(4096, 4096);

View File

@ -1,293 +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 "vpx_ports/vpx_timer.h"
#include "test/acm_random.h"
#include "test/register_state_check.h"
namespace {
using ::libvpx_test::ACMRandom;
typedef void (*HadamardFunc)(const int16_t *a, ptrdiff_t a_stride,
tran_low_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, tran_low_t *b) {
int16_t buf[64];
int16_t buf2[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, buf2 + i * 8);
for (int i = 0; i < 64; ++i) b[i] = (tran_low_t)buf2[i];
}
void reference_hadamard16x16(const int16_t *a, int a_stride, tran_low_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 tran_low_t a0 = b[0];
const tran_low_t a1 = b[64];
const tran_low_t a2 = b[128];
const tran_low_t a3 = b[192];
/* Prevent the result from escaping int16_t. */
const tran_low_t b0 = (a0 + a1) >> 1;
const tran_low_t b1 = (a0 - a1) >> 1;
const tran_low_t b2 = (a2 + a3) >> 1;
const tran_low_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_;
};
void HadamardSpeedTest(const char *name, HadamardFunc const func,
const int16_t *input, int stride, tran_low_t *output,
int times) {
int i;
vpx_usec_timer timer;
vpx_usec_timer_start(&timer);
for (i = 0; i < times; ++i) {
func(input, stride, output);
}
vpx_usec_timer_mark(&timer);
const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
printf("%s[%12d runs]: %d us\n", name, times, elapsed_time);
}
class Hadamard8x8Test : public HadamardTestBase {};
void HadamardSpeedTest8x8(HadamardFunc const func, int times) {
DECLARE_ALIGNED(16, int16_t, input[64]);
DECLARE_ALIGNED(16, tran_low_t, output[64]);
memset(input, 1, sizeof(input));
HadamardSpeedTest("Hadamard8x8", func, input, 8, output, times);
}
TEST_P(Hadamard8x8Test, CompareReferenceRandom) {
DECLARE_ALIGNED(16, int16_t, a[64]);
DECLARE_ALIGNED(16, tran_low_t, b[64]);
tran_low_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, tran_low_t, b[64]);
tran_low_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)));
}
}
TEST_P(Hadamard8x8Test, DISABLED_Speed) {
HadamardSpeedTest8x8(h_func_, 10);
HadamardSpeedTest8x8(h_func_, 10000);
HadamardSpeedTest8x8(h_func_, 10000000);
}
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
// TODO(jingning): Remove highbitdepth flag when the SIMD functions are
// in place and turn on the unit test.
#if !CONFIG_VP9_HIGHBITDEPTH
#if HAVE_MSA
INSTANTIATE_TEST_CASE_P(MSA, Hadamard8x8Test,
::testing::Values(&vpx_hadamard_8x8_msa));
#endif // HAVE_MSA
#endif // !CONFIG_VP9_HIGHBITDEPTH
#if HAVE_VSX
INSTANTIATE_TEST_CASE_P(VSX, Hadamard8x8Test,
::testing::Values(&vpx_hadamard_8x8_vsx));
#endif // HAVE_VSX
class Hadamard16x16Test : public HadamardTestBase {};
void HadamardSpeedTest16x16(HadamardFunc const func, int times) {
DECLARE_ALIGNED(16, int16_t, input[256]);
DECLARE_ALIGNED(16, tran_low_t, output[256]);
memset(input, 1, sizeof(input));
HadamardSpeedTest("Hadamard16x16", func, input, 16, output, times);
}
TEST_P(Hadamard16x16Test, CompareReferenceRandom) {
DECLARE_ALIGNED(16, int16_t, a[16 * 16]);
DECLARE_ALIGNED(16, tran_low_t, b[16 * 16]);
tran_low_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, tran_low_t, b[16 * 16]);
tran_low_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)));
}
}
TEST_P(Hadamard16x16Test, DISABLED_Speed) {
HadamardSpeedTest16x16(h_func_, 10);
HadamardSpeedTest16x16(h_func_, 10000);
HadamardSpeedTest16x16(h_func_, 10000000);
}
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_AVX2
INSTANTIATE_TEST_CASE_P(AVX2, Hadamard16x16Test,
::testing::Values(&vpx_hadamard_16x16_avx2));
#endif // HAVE_AVX2
#if HAVE_VSX
INSTANTIATE_TEST_CASE_P(VSX, Hadamard16x16Test,
::testing::Values(&vpx_hadamard_16x16_vsx));
#endif // HAVE_VSX
#if HAVE_NEON
INSTANTIATE_TEST_CASE_P(NEON, Hadamard16x16Test,
::testing::Values(&vpx_hadamard_16x16_neon));
#endif // HAVE_NEON
#if !CONFIG_VP9_HIGHBITDEPTH
#if HAVE_MSA
INSTANTIATE_TEST_CASE_P(MSA, Hadamard16x16Test,
::testing::Values(&vpx_hadamard_16x16_msa));
#endif // HAVE_MSA
#endif // !CONFIG_VP9_HIGHBITDEPTH
} // namespace

View File

@ -21,11 +21,14 @@ namespace libvpx_test {
// so that we can do actual file encodes. // so that we can do actual file encodes.
class I420VideoSource : public YUVVideoSource { class I420VideoSource : public YUVVideoSource {
public: public:
I420VideoSource(const std::string &file_name, unsigned int width, I420VideoSource(const std::string &file_name,
unsigned int height, int rate_numerator, int rate_denominator, unsigned int width, unsigned int height,
int rate_numerator, int rate_denominator,
unsigned int start, int limit) unsigned int start, int limit)
: YUVVideoSource(file_name, VPX_IMG_FMT_I420, width, height, : YUVVideoSource(file_name, VPX_IMG_FMT_I420,
rate_numerator, rate_denominator, start, limit) {} width, height,
rate_numerator, rate_denominator,
start, limit) {}
}; };
} // namespace libvpx_test } // namespace libvpx_test

View File

@ -14,24 +14,33 @@
#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;
for (int k = 0; k < 8; k++) { for (int k = 0; k < 8; k++) {
output[k] = 0.0; output[k] = 0.0;
for (int n = 0; n < 8; n++) { for (int n = 0; n < 8; n++)
output[k] += input[n] * cos(kPi * (2 * n + 1) * k / 16.0); output[k] += input[n]*cos(kPi*(2*n+1)*k/16.0);
} if (k == 0)
if (k == 0) output[k] = output[k] * kInvSqrt2; output[k] = output[k]*kInvSqrt2;
} }
} }
@ -39,19 +48,61 @@ void reference_dct_2d(int16_t input[64], double output[64]) {
// First transform columns // First transform columns
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
double temp_in[8], temp_out[8]; double temp_in[8], temp_out[8];
for (int j = 0; j < 8; ++j) temp_in[j] = input[j * 8 + i]; for (int j = 0; j < 8; ++j)
temp_in[j] = input[j*8 + i];
reference_dct_1d(temp_in, temp_out); reference_dct_1d(temp_in, temp_out);
for (int j = 0; j < 8; ++j) output[j * 8 + i] = temp_out[j]; for (int j = 0; j < 8; ++j)
output[j*8 + i] = temp_out[j];
} }
// Then transform rows // Then transform rows
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
double temp_in[8], temp_out[8]; double temp_in[8], temp_out[8];
for (int j = 0; j < 8; ++j) temp_in[j] = output[j + i * 8]; for (int j = 0; j < 8; ++j)
temp_in[j] = output[j + i*8];
reference_dct_1d(temp_in, temp_out); reference_dct_1d(temp_in, temp_out);
for (int j = 0; j < 8; ++j) output[j + i * 8] = temp_out[j]; for (int j = 0; j < 8; ++j)
output[j + i*8] = temp_out[j];
} }
// Scale by some magic number // Scale by some magic number
for (int i = 0; i < 64; ++i) output[i] *= 2; for (int i = 0; i < 64; ++i)
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) {
@ -68,18 +119,19 @@ TEST(VP9Idct8x8Test, AccuracyCheck) {
dst[j] = rnd.Rand8(); dst[j] = rnd.Rand8();
} }
// 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) input[j] = src[j] - dst[j]; for (int j = 0; j < 64; ++j)
input[j] = src[j] - dst[j];
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]);
} vp9_idct8x8_64_add_c(coeff, dst, 8);
vpx_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;
EXPECT_GE(1, error) << "Error: 8x8 FDCT/IDCT has error " << error EXPECT_GE(1, error)
<< " at index " << j; << "Error: 8x8 FDCT/IDCT has error " << error
<< " at index " << j;
} }
} }
} }

View File

@ -10,168 +10,107 @@
#include "./vpx_config.h" #include "./vpx_config.h"
#include "./vp8_rtcd.h" #include "./vp8_rtcd.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/buffer.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 (*IdctFunc)(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 {
using libvpx_test::Buffer;
class IDCTTest : public ::testing::TestWithParam<IdctFunc> { class IDCTTest : public ::testing::TestWithParam<IdctFunc> {
protected: protected:
virtual void SetUp() { virtual void SetUp() {
int i;
UUT = GetParam(); UUT = GetParam();
memset(input, 0, sizeof(input));
input = new Buffer<int16_t>(4, 4, 0); /* Set up guard blocks */
ASSERT_TRUE(input != NULL); for (i = 0; i < 256; i++) output[i] = ((i & 0xF) < 4 && (i < 64)) ? 0 : -1;
ASSERT_TRUE(input->Init());
predict = new Buffer<uint8_t>(4, 4, 3);
ASSERT_TRUE(predict != NULL);
ASSERT_TRUE(predict->Init());
output = new Buffer<uint8_t>(4, 4, 3);
ASSERT_TRUE(output != NULL);
ASSERT_TRUE(output->Init());
} }
virtual void TearDown() { virtual void TearDown() { libvpx_test::ClearSystemState(); }
delete input;
delete predict;
delete output;
libvpx_test::ClearSystemState();
}
IdctFunc UUT; IdctFunc UUT;
Buffer<int16_t> *input; int16_t input[16];
Buffer<uint8_t> *predict; unsigned char output[256];
Buffer<uint8_t> *output; unsigned char predict[256];
}; };
TEST_P(IDCTTest, TestGuardBlocks) {
int i;
for (i = 0; i < 256; i++)
if ((i & 0xF) < 4 && i < 64)
EXPECT_EQ(0, output[i]) << i;
else
EXPECT_EQ(255, output[i]);
}
TEST_P(IDCTTest, TestAllZeros) { TEST_P(IDCTTest, TestAllZeros) {
// When the input is '0' the output will be '0'. int i;
input->Set(0);
predict->Set(0);
output->Set(0);
ASM_REGISTER_STATE_CHECK(UUT(input->TopLeftPixel(), predict->TopLeftPixel(), ASM_REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16));
predict->stride(), output->TopLeftPixel(),
output->stride()));
ASSERT_TRUE(input->CheckValues(0)); for (i = 0; i < 256; i++)
ASSERT_TRUE(input->CheckPadding()); if ((i & 0xF) < 4 && i < 64)
ASSERT_TRUE(output->CheckValues(0)); EXPECT_EQ(0, output[i]) << "i==" << i;
ASSERT_TRUE(output->CheckPadding()); else
EXPECT_EQ(255, output[i]) << "i==" << i;
} }
TEST_P(IDCTTest, TestAllOnes) { TEST_P(IDCTTest, TestAllOnes) {
input->Set(0); int i;
// When the first element is '4' it will fill the output buffer with '1'.
input->TopLeftPixel()[0] = 4;
predict->Set(0);
output->Set(0);
ASM_REGISTER_STATE_CHECK(UUT(input->TopLeftPixel(), predict->TopLeftPixel(), input[0] = 4;
predict->stride(), output->TopLeftPixel(), ASM_REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16));
output->stride()));
ASSERT_TRUE(output->CheckValues(1)); for (i = 0; i < 256; i++)
ASSERT_TRUE(output->CheckPadding()); if ((i & 0xF) < 4 && i < 64)
EXPECT_EQ(1, output[i]) << "i==" << i;
else
EXPECT_EQ(255, output[i]) << "i==" << i;
} }
TEST_P(IDCTTest, TestAddOne) { TEST_P(IDCTTest, TestAddOne) {
// Set the transform output to '1' and make sure it gets added to the int i;
// prediction buffer.
input->Set(0);
input->TopLeftPixel()[0] = 4;
output->Set(0);
uint8_t *pred = predict->TopLeftPixel(); for (i = 0; i < 256; i++) predict[i] = i;
for (int y = 0; y < 4; ++y) { input[0] = 4;
for (int x = 0; x < 4; ++x) { ASM_REGISTER_STATE_CHECK(UUT(input, predict, 16, output, 16));
pred[y * predict->stride() + x] = y * 4 + x;
}
}
ASM_REGISTER_STATE_CHECK(UUT(input->TopLeftPixel(), predict->TopLeftPixel(), for (i = 0; i < 256; i++)
predict->stride(), output->TopLeftPixel(), if ((i & 0xF) < 4 && i < 64)
output->stride())); EXPECT_EQ(i + 1, output[i]) << "i==" << i;
else
uint8_t const *out = output->TopLeftPixel(); EXPECT_EQ(255, output[i]) << "i==" << i;
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
EXPECT_EQ(1 + y * 4 + x, out[y * output->stride() + x]);
}
}
if (HasFailure()) {
output->DumpBuffer();
}
ASSERT_TRUE(output->CheckPadding());
} }
TEST_P(IDCTTest, TestWithData) { TEST_P(IDCTTest, TestWithData) {
// Test a single known input. int i;
predict->Set(0);
int16_t *in = input->TopLeftPixel(); for (i = 0; i < 16; i++) input[i] = i;
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
in[y * input->stride() + x] = y * 4 + x;
}
}
ASM_REGISTER_STATE_CHECK(UUT(input->TopLeftPixel(), predict->TopLeftPixel(), ASM_REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16));
predict->stride(), output->TopLeftPixel(),
output->stride()));
uint8_t *out = output->TopLeftPixel(); for (i = 0; i < 256; i++)
for (int y = 0; y < 4; ++y) { if ((i & 0xF) > 3 || i > 63)
for (int x = 0; x < 4; ++x) { EXPECT_EQ(255, output[i]) << "i==" << i;
switch (y * 4 + x) { else if (i == 0)
case 0: EXPECT_EQ(11, out[y * output->stride() + x]); break; EXPECT_EQ(11, output[i]) << "i==" << i;
case 2: else if (i == 34)
case 5: EXPECT_EQ(1, output[i]) << "i==" << i;
case 8: EXPECT_EQ(3, out[y * output->stride() + x]); break; else if (i == 2 || i == 17 || i == 32)
case 10: EXPECT_EQ(1, out[y * output->stride() + x]); break; EXPECT_EQ(3, output[i]) << "i==" << i;
default: EXPECT_EQ(0, out[y * output->stride() + x]); else
} EXPECT_EQ(0, output[i]) << "i==" << i;
}
}
if (HasFailure()) {
output->DumpBuffer();
}
ASSERT_TRUE(output->CheckPadding());
} }
INSTANTIATE_TEST_CASE_P(C, IDCTTest, ::testing::Values(vp8_short_idct4x4llm_c)); INSTANTIATE_TEST_CASE_P(C, IDCTTest, ::testing::Values(vp8_short_idct4x4llm_c));
#if HAVE_NEON
INSTANTIATE_TEST_CASE_P(NEON, IDCTTest,
::testing::Values(vp8_short_idct4x4llm_neon));
#endif // HAVE_NEON
#if HAVE_MMX #if HAVE_MMX
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 // HAVE_MMX #endif
}
#if HAVE_MSA
INSTANTIATE_TEST_CASE_P(MSA, IDCTTest,
::testing::Values(vp8_short_idct4x4llm_msa));
#endif // HAVE_MSA
#if HAVE_MMI
INSTANTIATE_TEST_CASE_P(MMI, IDCTTest,
::testing::Values(vp8_short_idct4x4llm_mmi));
#endif // HAVE_MMI
} // namespace

396
test/intrapred_test.cc Normal file
View File

@ -0,0 +1,396 @@
/*
* 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 <string.h>
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "./vp8_rtcd.h"
#include "vp8/common/blockd.h"
#include "vpx_mem/vpx_mem.h"
namespace {
using libvpx_test::ACMRandom;
class IntraPredBase {
public:
virtual ~IntraPredBase() { libvpx_test::ClearSystemState(); }
protected:
void SetupMacroblock(MACROBLOCKD *mbptr,
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;
}
void FillRandom() {
// Fill edges with random data
ACMRandom rnd(ACMRandom::DeterministicSeed());
for (int p = 0; p < num_planes_; p++) {
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();
}
}
virtual void Predict(MB_PREDICTION_MODE mode) = 0;
void SetLeftUnavailable() {
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_;
};
typedef void (*IntraPredYFunc)(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<IntraPredYFunc> {
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 = 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() {
pred_fn_ = GetParam();
SetupMacroblock(mb_, mi_, data_array_, kBlockSize, kStride, 1);
}
virtual void Predict(MB_PREDICTION_MODE mode) {
mbptr_->mode_info_context->mbmi.mode = mode;
ASM_REGISTER_STATE_CHECK(pred_fn_(mbptr_,
data_ptr_[0] - kStride,
data_ptr_[0] - 1, kStride,
data_ptr_[0], kStride));
}
IntraPredYFunc pred_fn_;
static uint8_t* data_array_;
static MACROBLOCKD * mb_;
static MODE_INFO *mi_;
};
MACROBLOCKD* IntraPredYTest::mb_ = NULL;
MODE_INFO* IntraPredYTest::mi_ = NULL;
uint8_t* IntraPredYTest::data_array_ = NULL;
TEST_P(IntraPredYTest, IntraPredTests) {
RunTest();
}
INSTANTIATE_TEST_CASE_P(C, IntraPredYTest,
::testing::Values(
vp8_build_intra_predictors_mby_s_c));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(SSE2, IntraPredYTest,
::testing::Values(
vp8_build_intra_predictors_mby_s_sse2));
#endif
#if HAVE_SSSE3
INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredYTest,
::testing::Values(
vp8_build_intra_predictors_mby_s_ssse3));
#endif
#if HAVE_NEON
INSTANTIATE_TEST_CASE_P(NEON, IntraPredYTest,
::testing::Values(
vp8_build_intra_predictors_mby_s_neon));
#endif
typedef void (*IntraPredUvFunc)(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<IntraPredUvFunc> {
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);
}
IntraPredUvFunc 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(
vp8_build_intra_predictors_mbuv_s_c));
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(SSE2, IntraPredUVTest,
::testing::Values(
vp8_build_intra_predictors_mbuv_s_sse2));
#endif
#if HAVE_SSSE3
INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredUVTest,
::testing::Values(
vp8_build_intra_predictors_mbuv_s_ssse3));
#endif
#if HAVE_NEON
INSTANTIATE_TEST_CASE_P(NEON, IntraPredUVTest,
::testing::Values(
vp8_build_intra_predictors_mbuv_s_neon));
#endif
} // namespace

View File

@ -34,19 +34,21 @@ std::ostream &operator<<(std::ostream &os, const DecodeParam &dp) {
return os << "threads: " << dp.threads << " file: " << dp.filename; return os << "threads: " << dp.threads << " file: " << dp.filename;
} }
class InvalidFileTest : public ::libvpx_test::DecoderTest, class InvalidFileTest
public ::libvpx_test::CodecTestWithParam<DecodeParam> { : public ::libvpx_test::DecoderTest,
public ::libvpx_test::CodecTestWithParam<DecodeParam> {
protected: protected:
InvalidFileTest() : DecoderTest(GET_PARAM(0)), res_file_(NULL) {} InvalidFileTest() : DecoderTest(GET_PARAM(0)), res_file_(NULL) {}
virtual ~InvalidFileTest() { virtual ~InvalidFileTest() {
if (res_file_ != NULL) fclose(res_file_); if (res_file_ != NULL)
fclose(res_file_);
} }
void OpenResFile(const std::string &res_file_name_) { void OpenResFile(const std::string &res_file_name_) {
res_file_ = libvpx_test::OpenTestDataFile(res_file_name_); res_file_ = libvpx_test::OpenTestDataFile(res_file_name_);
ASSERT_TRUE(res_file_ != NULL) ASSERT_TRUE(res_file_ != NULL) << "Result file open failed. Filename: "
<< "Result file open failed. Filename: " << res_file_name_; << res_file_name_;
} }
virtual bool HandleDecodeResult( virtual bool HandleDecodeResult(
@ -61,47 +63,32 @@ class InvalidFileTest : public ::libvpx_test::DecoderTest,
EXPECT_NE(res, EOF) << "Read result data failed"; EXPECT_NE(res, EOF) << "Read result data failed";
// Check results match. // Check results match.
const DecodeParam input = GET_PARAM(1); EXPECT_EQ(expected_res_dec, res_dec)
if (input.threads > 1) { << "Results don't match: frame number = " << video.frame_number()
// The serial decode check is too strict for tile-threaded decoding as << ". (" << decoder->DecodeError() << ")";
// there is no guarantee on the decode order nor which specific error
// will take precedence. Currently a tile-level error is not forwarded so
// the frame will simply be marked corrupt.
EXPECT_TRUE(res_dec == expected_res_dec ||
res_dec == VPX_CODEC_CORRUPT_FRAME)
<< "Results don't match: frame number = " << video.frame_number()
<< ". (" << decoder->DecodeError()
<< "). Expected: " << expected_res_dec << " or "
<< VPX_CODEC_CORRUPT_FRAME;
} else {
EXPECT_EQ(expected_res_dec, res_dec)
<< "Results don't match: frame number = " << video.frame_number()
<< ". (" << decoder->DecodeError() << ")";
}
return !HasFailure(); return !HasFailure();
} }
void RunTest() { void RunTest() {
const DecodeParam input = GET_PARAM(1); const DecodeParam input = GET_PARAM(1);
libvpx_test::CompressedVideoSource *video = NULL;
vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t(); vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t();
cfg.threads = input.threads; cfg.threads = input.threads;
const std::string filename = input.filename; const std::string filename = input.filename;
// Open compressed video file. // Open compressed video file.
testing::internal::scoped_ptr<libvpx_test::CompressedVideoSource> video;
if (filename.substr(filename.length() - 3, 3) == "ivf") { if (filename.substr(filename.length() - 3, 3) == "ivf") {
video.reset(new libvpx_test::IVFVideoSource(filename)); video = new libvpx_test::IVFVideoSource(filename);
} else if (filename.substr(filename.length() - 4, 4) == "webm") { } else if (filename.substr(filename.length() - 4, 4) == "webm") {
#if CONFIG_WEBM_IO #if CONFIG_WEBM_IO
video.reset(new libvpx_test::WebMVideoSource(filename)); video = new libvpx_test::WebMVideoSource(filename);
#else #else
fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n", fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
filename.c_str()); filename.c_str());
return; return;
#endif #endif
} }
ASSERT_TRUE(video.get() != NULL);
video->Init(); video->Init();
// Construct result file name. The file holds a list of expected integer // Construct result file name. The file holds a list of expected integer
@ -111,58 +98,35 @@ class InvalidFileTest : public ::libvpx_test::DecoderTest,
OpenResFile(res_filename); OpenResFile(res_filename);
// Decode frame, and check the md5 matching. // Decode frame, and check the md5 matching.
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get(), cfg)); ASSERT_NO_FATAL_FAILURE(RunLoop(video, cfg));
delete video;
} }
private: private:
FILE *res_file_; FILE *res_file_;
}; };
TEST_P(InvalidFileTest, ReturnCode) { RunTest(); } TEST_P(InvalidFileTest, ReturnCode) {
RunTest();
}
#if CONFIG_VP8_DECODER
const DecodeParam kVP8InvalidFileTests[] = {
{ 1, "invalid-bug-1443.ivf" },
{ 1, "invalid-token-partition.ivf" },
};
VP8_INSTANTIATE_TEST_CASE(InvalidFileTest,
::testing::ValuesIn(kVP8InvalidFileTests));
#endif // CONFIG_VP8_DECODER
#if CONFIG_VP9_DECODER
const DecodeParam kVP9InvalidFileTests[] = { const DecodeParam kVP9InvalidFileTests[] = {
{ 1, "invalid-vp90-02-v2.webm" }, {1, "invalid-vp90-02-v2.webm"},
#if CONFIG_VP9_HIGHBITDEPTH {1, "invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.v2.ivf"},
{ 1, "invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.v2.ivf" }, {1, "invalid-vp90-03-v3.webm"},
{ 1, {1, "invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-.ivf"},
"invalid-vp90-2-21-resize_inter_320x180_5_3-4.webm.ivf.s45551_r01-05_b6-." {1, "invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-z.ivf"},
"ivf" }, {1, "invalid-vp90-2-12-droppable_1.ivf.s3676_r01-05_b6-.ivf"},
#endif {1, "invalid-vp90-2-05-resize.ivf.s59293_r01-05_b6-.ivf"},
{ 1, "invalid-vp90-03-v3.webm" }, {1, "invalid-vp90-2-09-subpixel-00.ivf.s20492_r01-05_b6-.v2.ivf"},
{ 1, "invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-.ivf" }, {1, "invalid-vp91-2-mixedrefcsp-444to420.ivf"},
{ 1, "invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-z.ivf" }, {1, "invalid-vp90-2-12-droppable_1.ivf.s73804_r01-05_b6-.ivf"},
// This file will cause a large allocation which is expected to fail in 32-bit {1, "invalid-vp90-2-03-size-224x196.webm.ivf.s44156_r01-05_b6-.ivf"},
// environments. Test x86 for coverage purposes as the allocation failure will {1, "invalid-vp90-2-03-size-202x210.webm.ivf.s113306_r01-05_b6-.ivf"},
// be in platform agnostic code.
#if ARCH_X86
{ 1, "invalid-vp90-2-00-quantizer-63.ivf.kf_65527x61446.ivf" },
#endif
{ 1, "invalid-vp90-2-12-droppable_1.ivf.s3676_r01-05_b6-.ivf" },
{ 1, "invalid-vp90-2-05-resize.ivf.s59293_r01-05_b6-.ivf" },
{ 1, "invalid-vp90-2-09-subpixel-00.ivf.s20492_r01-05_b6-.v2.ivf" },
{ 1, "invalid-vp91-2-mixedrefcsp-444to420.ivf" },
{ 1, "invalid-vp90-2-12-droppable_1.ivf.s73804_r01-05_b6-.ivf" },
{ 1, "invalid-vp90-2-03-size-224x196.webm.ivf.s44156_r01-05_b6-.ivf" },
{ 1, "invalid-vp90-2-03-size-202x210.webm.ivf.s113306_r01-05_b6-.ivf" },
{ 1,
"invalid-vp90-2-10-show-existing-frame.webm.ivf.s180315_r01-05_b6-.ivf" },
{ 1, "invalid-crbug-667044.webm" },
}; };
VP9_INSTANTIATE_TEST_CASE(InvalidFileTest, VP9_INSTANTIATE_TEST_CASE(InvalidFileTest,
::testing::ValuesIn(kVP9InvalidFileTests)); ::testing::ValuesIn(kVP9InvalidFileTests));
#endif // CONFIG_VP9_DECODER
// This class will include test vectors that are expected to fail // This class will include test vectors that are expected to fail
// peek. However they are still expected to have no fatal failures. // peek. However they are still expected to have no fatal failures.
@ -170,46 +134,34 @@ class InvalidFileInvalidPeekTest : public InvalidFileTest {
protected: protected:
InvalidFileInvalidPeekTest() : InvalidFileTest() {} InvalidFileInvalidPeekTest() : InvalidFileTest() {}
virtual void HandlePeekResult(libvpx_test::Decoder *const /*decoder*/, virtual void HandlePeekResult(libvpx_test::Decoder *const /*decoder*/,
libvpx_test::CompressedVideoSource * /*video*/, libvpx_test::CompressedVideoSource* /*video*/,
const vpx_codec_err_t /*res_peek*/) {} const vpx_codec_err_t /*res_peek*/) {}
}; };
TEST_P(InvalidFileInvalidPeekTest, ReturnCode) { RunTest(); } TEST_P(InvalidFileInvalidPeekTest, ReturnCode) {
RunTest();
}
#if CONFIG_VP8_DECODER
const DecodeParam kVP8InvalidPeekTests[] = {
{ 1, "invalid-vp80-00-comprehensive-018.ivf.2kf_0x6.ivf" },
};
VP8_INSTANTIATE_TEST_CASE(InvalidFileInvalidPeekTest,
::testing::ValuesIn(kVP8InvalidPeekTests));
#endif // CONFIG_VP8_DECODER
#if CONFIG_VP9_DECODER
const DecodeParam kVP9InvalidFileInvalidPeekTests[] = { const DecodeParam kVP9InvalidFileInvalidPeekTests[] = {
{ 1, "invalid-vp90-01-v3.webm" }, {1, "invalid-vp90-01-v2.webm"},
}; };
VP9_INSTANTIATE_TEST_CASE(InvalidFileInvalidPeekTest, VP9_INSTANTIATE_TEST_CASE(InvalidFileInvalidPeekTest,
::testing::ValuesIn(kVP9InvalidFileInvalidPeekTests)); ::testing::ValuesIn(kVP9InvalidFileInvalidPeekTests));
const DecodeParam kMultiThreadedVP9InvalidFileTests[] = { const DecodeParam kMultiThreadedVP9InvalidFileTests[] = {
{ 4, "invalid-vp90-2-08-tile_1x4_frame_parallel_all_key.webm" }, {4, "invalid-vp90-2-08-tile_1x4_frame_parallel_all_key.webm"},
{ 4, {4, "invalid-"
"invalid-" "vp90-2-08-tile_1x2_frame_parallel.webm.ivf.s47039_r01-05_b6-.ivf"},
"vp90-2-08-tile_1x2_frame_parallel.webm.ivf.s47039_r01-05_b6-.ivf" }, {4, "invalid-vp90-2-08-tile_1x8_frame_parallel.webm.ivf.s288_r01-05_b6-.ivf"},
{ 4, {2, "invalid-vp90-2-09-aq2.webm.ivf.s3984_r01-05_b6-.v2.ivf"},
"invalid-vp90-2-08-tile_1x8_frame_parallel.webm.ivf.s288_r01-05_b6-.ivf" }, {4, "invalid-vp90-2-09-subpixel-00.ivf.s19552_r01-05_b6-.v2.ivf"},
{ 2, "invalid-vp90-2-09-aq2.webm.ivf.s3984_r01-05_b6-.v2.ivf" },
{ 4, "invalid-vp90-2-09-subpixel-00.ivf.s19552_r01-05_b6-.v2.ivf" },
{ 2, "invalid-crbug-629481.webm" },
}; };
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
VP9MultiThreaded, InvalidFileTest, VP9MultiThreaded, InvalidFileTest,
::testing::Combine( ::testing::Combine(
::testing::Values( ::testing::Values(
static_cast<const libvpx_test::CodecFactory *>(&libvpx_test::kVP9)), static_cast<const libvpx_test::CodecFactory*>(&libvpx_test::kVP9)),
::testing::ValuesIn(kMultiThreadedVP9InvalidFileTests))); ::testing::ValuesIn(kMultiThreadedVP9InvalidFileTests)));
#endif // CONFIG_VP9_DECODER
} // namespace } // namespace

View File

@ -29,13 +29,19 @@ static unsigned int MemGetLe32(const uint8_t *mem) {
class IVFVideoSource : public CompressedVideoSource { class IVFVideoSource : public CompressedVideoSource {
public: public:
explicit IVFVideoSource(const std::string &file_name) explicit IVFVideoSource(const std::string &file_name)
: file_name_(file_name), input_file_(NULL), compressed_frame_buf_(NULL), : file_name_(file_name),
frame_sz_(0), frame_(0), end_of_file_(false) {} input_file_(NULL),
compressed_frame_buf_(NULL),
frame_sz_(0),
frame_(0),
end_of_file_(false) {
}
virtual ~IVFVideoSource() { virtual ~IVFVideoSource() {
delete[] compressed_frame_buf_; delete[] compressed_frame_buf_;
if (input_file_) fclose(input_file_); if (input_file_)
fclose(input_file_);
} }
virtual void Init() { virtual void Init() {
@ -47,17 +53,16 @@ class IVFVideoSource : public CompressedVideoSource {
virtual void Begin() { virtual void Begin() {
input_file_ = OpenTestDataFile(file_name_); input_file_ = OpenTestDataFile(file_name_);
ASSERT_TRUE(input_file_ != NULL) ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: "
<< "Input file open failed. Filename: " << file_name_; << file_name_;
// Read file header // Read file header
uint8_t file_hdr[kIvfFileHdrSize]; uint8_t file_hdr[kIvfFileHdrSize];
ASSERT_EQ(kIvfFileHdrSize, fread(file_hdr, 1, kIvfFileHdrSize, input_file_)) ASSERT_EQ(kIvfFileHdrSize, fread(file_hdr, 1, kIvfFileHdrSize, input_file_))
<< "File header read failed."; << "File header read failed.";
// Check file header // Check file header
ASSERT_TRUE(file_hdr[0] == 'D' && file_hdr[1] == 'K' && ASSERT_TRUE(file_hdr[0] == 'D' && file_hdr[1] == 'K' && file_hdr[2] == 'I'
file_hdr[2] == 'I' && file_hdr[3] == 'F') && file_hdr[3] == 'F') << "Input is not an IVF file.";
<< "Input is not an IVF file.";
FillFrame(); FillFrame();
} }
@ -71,8 +76,8 @@ class IVFVideoSource : public CompressedVideoSource {
ASSERT_TRUE(input_file_ != NULL); ASSERT_TRUE(input_file_ != NULL);
uint8_t frame_hdr[kIvfFrameHdrSize]; uint8_t frame_hdr[kIvfFrameHdrSize];
// Check frame header and read a frame from input_file. // Check frame header and read a frame from input_file.
if (fread(frame_hdr, 1, kIvfFrameHdrSize, input_file_) != if (fread(frame_hdr, 1, kIvfFrameHdrSize, input_file_)
kIvfFrameHdrSize) { != kIvfFrameHdrSize) {
end_of_file_ = true; end_of_file_ = true;
} else { } else {
end_of_file_ = false; end_of_file_ = false;

View File

@ -17,9 +17,8 @@
namespace { namespace {
class KeyframeTest class KeyframeTest : public ::libvpx_test::EncoderTest,
: public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected: protected:
KeyframeTest() : EncoderTest(GET_PARAM(0)) {} KeyframeTest() : EncoderTest(GET_PARAM(0)) {}
virtual ~KeyframeTest() {} virtual ~KeyframeTest() {}
@ -35,12 +34,10 @@ class KeyframeTest
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) { ::libvpx_test::Encoder *encoder) {
if (kf_do_force_kf_) { if (kf_do_force_kf_)
frame_flags_ = (video->frame() % 3) ? 0 : VPX_EFLAG_FORCE_KF; frame_flags_ = (video->frame() % 3) ? 0 : VPX_EFLAG_FORCE_KF;
} if (set_cpu_used_ && video->frame() == 1)
if (set_cpu_used_ && video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
}
} }
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
@ -68,9 +65,8 @@ TEST_P(KeyframeTest, TestRandomVideoSource) {
// In realtime mode - auto placed keyframes are exceedingly rare, don't // In realtime mode - auto placed keyframes are exceedingly rare, don't
// bother with this check if(GetParam() > 0) // bother with this check if(GetParam() > 0)
if (GET_PARAM(1) > 0) { if (GET_PARAM(1) > 0)
EXPECT_GT(kf_count_, 1); EXPECT_GT(kf_count_, 1);
}
} }
TEST_P(KeyframeTest, TestDisableKeyframes) { TEST_P(KeyframeTest, TestDisableKeyframes) {
@ -118,7 +114,8 @@ TEST_P(KeyframeTest, TestAutoKeyframe) {
// may not produce a keyframe like we expect. This is necessary when running // may not produce a keyframe like we expect. This is necessary when running
// on very slow environments (like Valgrind). The step -11 was determined // on very slow environments (like Valgrind). The step -11 was determined
// experimentally as the fastest mode that still throws the keyframe. // experimentally as the fastest mode that still throws the keyframe.
if (deadline_ == VPX_DL_REALTIME) set_cpu_used_ = -11; if (deadline_ == VPX_DL_REALTIME)
set_cpu_used_ = -11;
// This clip has a cut scene every 30 frames -> Frame 0, 30, 60, 90, 120. // 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 // I check only the first 40 frames to make sure there's a keyframe at frame
@ -130,16 +127,15 @@ TEST_P(KeyframeTest, TestAutoKeyframe) {
// In realtime mode - auto placed keyframes are exceedingly rare, don't // In realtime mode - auto placed keyframes are exceedingly rare, don't
// bother with this check // bother with this check
if (GET_PARAM(1) > 0) { if (GET_PARAM(1) > 0)
EXPECT_EQ(2u, kf_pts_list_.size()) << " Not the right number of keyframes "; EXPECT_EQ(2u, kf_pts_list_.size()) << " Not the right number of keyframes ";
}
// Verify that keyframes match the file keyframes in the file. // Verify that keyframes match the file keyframes in the file.
for (std::vector<vpx_codec_pts_t>::const_iterator iter = kf_pts_list_.begin(); for (std::vector<vpx_codec_pts_t>::const_iterator iter = kf_pts_list_.begin();
iter != kf_pts_list_.end(); ++iter) { iter != kf_pts_list_.end(); ++iter) {
if (deadline_ == VPX_DL_REALTIME && *iter > 0) if (deadline_ == VPX_DL_REALTIME && *iter > 0)
EXPECT_EQ(0, (*iter - 1) % 30) EXPECT_EQ(0, (*iter - 1) % 30) << "Unexpected keyframe at frame "
<< "Unexpected keyframe at frame " << *iter; << *iter;
else else
EXPECT_EQ(0, *iter % 30) << "Unexpected keyframe at frame " << *iter; EXPECT_EQ(0, *iter % 30) << "Unexpected keyframe at frame " << *iter;
} }

View File

@ -1,147 +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_P(LevelTest, TestTargetLevel11Large) {
ASSERT_NE(encoding_mode_, ::libvpx_test::kRealTime);
::libvpx_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
60);
target_level_ = 11;
cfg_.rc_target_bitrate = 150;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(target_level_, level_);
}
TEST_P(LevelTest, TestTargetLevel20Large) {
ASSERT_NE(encoding_mode_, ::libvpx_test::kRealTime);
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 60);
target_level_ = 20;
cfg_.rc_target_bitrate = 1200;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(target_level_, level_);
}
TEST_P(LevelTest, TestTargetLevel31Large) {
ASSERT_NE(encoding_mode_, ::libvpx_test::kRealTime);
::libvpx_test::I420VideoSource video("niklas_1280_720_30.y4m", 1280, 720, 30,
1, 0, 60);
target_level_ = 31;
cfg_.rc_target_bitrate = 8000;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(target_level_, 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_GE(11, level_);
cfg_.rc_target_bitrate = 1600;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(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));
cfg.rc_target_bitrate = 100;
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 == 1 || 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

679
test/lpf_8_test.cc Normal file
View File

@ -0,0 +1,679 @@
/*
* 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 "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 "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_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_VP9_HIGHBITDEPTH
typedef void (*loop_op_t)(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count, 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,
int count);
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_VP9_HIGHBITDEPTH
typedef std::tr1::tuple<loop_op_t, loop_op_t, int, int> loop8_param_t;
typedef std::tr1::tuple<dual_loop_op_t, dual_loop_op_t, int> dualloop8_param_t;
#if HAVE_SSE2
#if CONFIG_VP9_HIGHBITDEPTH
void wrapper_vertical_16_sse2(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count, int bd) {
vp9_highbd_lpf_vertical_16_sse2(s, p, blimit, limit, thresh, bd);
}
void wrapper_vertical_16_c(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count, int bd) {
vp9_highbd_lpf_vertical_16_c(s, p, blimit, limit, thresh, bd);
}
void wrapper_vertical_16_dual_sse2(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count, int bd) {
vp9_highbd_lpf_vertical_16_dual_sse2(s, p, blimit, limit, thresh, bd);
}
void wrapper_vertical_16_dual_c(uint16_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count, int bd) {
vp9_highbd_lpf_vertical_16_dual_c(s, p, blimit, limit, thresh, bd);
}
#else
void wrapper_vertical_16_sse2(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count) {
vp9_lpf_vertical_16_sse2(s, p, blimit, limit, thresh);
}
void wrapper_vertical_16_c(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count) {
vp9_lpf_vertical_16_c(s, p, blimit, limit, thresh);
}
void wrapper_vertical_16_dual_sse2(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count) {
vp9_lpf_vertical_16_dual_sse2(s, p, blimit, limit, thresh);
}
void wrapper_vertical_16_dual_c(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count) {
vp9_lpf_vertical_16_dual_c(s, p, blimit, limit, thresh);
}
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // HAVE_SSE2
#if HAVE_NEON_ASM
#if CONFIG_VP9_HIGHBITDEPTH
// No neon high bitdepth functions.
#else
void wrapper_vertical_16_neon(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count) {
vp9_lpf_vertical_16_neon(s, p, blimit, limit, thresh);
}
void wrapper_vertical_16_c(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count) {
vp9_lpf_vertical_16_c(s, p, blimit, limit, thresh);
}
void wrapper_vertical_16_dual_neon(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count) {
vp9_lpf_vertical_16_dual_neon(s, p, blimit, limit, thresh);
}
void wrapper_vertical_16_dual_c(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh,
int count) {
vp9_lpf_vertical_16_dual_c(s, p, blimit, limit, thresh);
}
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // HAVE_NEON_ASM
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);
count_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
int bit_depth_;
int count_;
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_VP9_HIGHBITDEPTH
int32_t bd = bit_depth_;
DECLARE_ALIGNED_ARRAY(16, uint16_t, s, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_s, kNumCoeffs);
#else
DECLARE_ALIGNED_ARRAY(8, uint8_t, s, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(8, uint8_t, ref_s, kNumCoeffs);
#endif // CONFIG_VP9_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_VP9_HIGHBITDEPTH
ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit, limit, thresh, count_, bd);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh, count_, bd));
#else
ref_loopfilter_op_(ref_s+8+p*8, p, blimit, limit, thresh, count_);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh, count_));
#endif // CONFIG_VP9_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_VP9_HIGHBITDEPTH
const int32_t bd = bit_depth_;
DECLARE_ALIGNED_ARRAY(16, uint16_t, s, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_s, kNumCoeffs);
#else
DECLARE_ALIGNED_ARRAY(8, uint8_t, s, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(8, uint8_t, ref_s, kNumCoeffs);
#endif // CONFIG_VP9_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_VP9_HIGHBITDEPTH
ref_loopfilter_op_(ref_s + 8 + p * 8, p, blimit, limit, thresh, count_, bd);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh, count_, bd));
#else
ref_loopfilter_op_(ref_s+8+p*8, p, blimit, limit, thresh, count_);
ASM_REGISTER_STATE_CHECK(
loopfilter_op_(s + 8 + p * 8, p, blimit, limit, thresh, count_));
#endif // CONFIG_VP9_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_VP9_HIGHBITDEPTH
const int32_t bd = bit_depth_;
DECLARE_ALIGNED_ARRAY(16, uint16_t, s, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_s, kNumCoeffs);
#else
DECLARE_ALIGNED_ARRAY(8, uint8_t, s, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(8, uint8_t, ref_s, kNumCoeffs);
#endif // CONFIG_VP9_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_VP9_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_VP9_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_VP9_HIGHBITDEPTH
DECLARE_ALIGNED_ARRAY(16, uint16_t, s, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_s, kNumCoeffs);
#else
DECLARE_ALIGNED_ARRAY(8, uint8_t, s, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(8, uint8_t, ref_s, kNumCoeffs);
#endif // CONFIG_VP9_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_VP9_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_VP9_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_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
SSE2, Loop8Test6Param,
::testing::Values(
make_tuple(&vp9_highbd_lpf_horizontal_4_sse2,
&vp9_highbd_lpf_horizontal_4_c, 8, 1),
make_tuple(&vp9_highbd_lpf_vertical_4_sse2,
&vp9_highbd_lpf_vertical_4_c, 8, 1),
make_tuple(&vp9_highbd_lpf_horizontal_8_sse2,
&vp9_highbd_lpf_horizontal_8_c, 8, 1),
make_tuple(&vp9_highbd_lpf_horizontal_16_sse2,
&vp9_highbd_lpf_horizontal_16_c, 8, 1),
make_tuple(&vp9_highbd_lpf_horizontal_16_sse2,
&vp9_highbd_lpf_horizontal_16_c, 8, 2),
make_tuple(&vp9_highbd_lpf_vertical_8_sse2,
&vp9_highbd_lpf_vertical_8_c, 8, 1),
make_tuple(&wrapper_vertical_16_sse2,
&wrapper_vertical_16_c, 8, 1),
make_tuple(&vp9_highbd_lpf_horizontal_4_sse2,
&vp9_highbd_lpf_horizontal_4_c, 10, 1),
make_tuple(&vp9_highbd_lpf_vertical_4_sse2,
&vp9_highbd_lpf_vertical_4_c, 10, 1),
make_tuple(&vp9_highbd_lpf_horizontal_8_sse2,
&vp9_highbd_lpf_horizontal_8_c, 10, 1),
make_tuple(&vp9_highbd_lpf_horizontal_16_sse2,
&vp9_highbd_lpf_horizontal_16_c, 10, 1),
make_tuple(&vp9_highbd_lpf_horizontal_16_sse2,
&vp9_highbd_lpf_horizontal_16_c, 10, 2),
make_tuple(&vp9_highbd_lpf_vertical_8_sse2,
&vp9_highbd_lpf_vertical_8_c, 10, 1),
make_tuple(&wrapper_vertical_16_sse2,
&wrapper_vertical_16_c, 10, 1),
make_tuple(&vp9_highbd_lpf_horizontal_4_sse2,
&vp9_highbd_lpf_horizontal_4_c, 12, 1),
make_tuple(&vp9_highbd_lpf_vertical_4_sse2,
&vp9_highbd_lpf_vertical_4_c, 12, 1),
make_tuple(&vp9_highbd_lpf_horizontal_8_sse2,
&vp9_highbd_lpf_horizontal_8_c, 12, 1),
make_tuple(&vp9_highbd_lpf_horizontal_16_sse2,
&vp9_highbd_lpf_horizontal_16_c, 12, 1),
make_tuple(&vp9_highbd_lpf_horizontal_16_sse2,
&vp9_highbd_lpf_horizontal_16_c, 12, 2),
make_tuple(&vp9_highbd_lpf_vertical_8_sse2,
&vp9_highbd_lpf_vertical_8_c, 12, 1),
make_tuple(&wrapper_vertical_16_sse2,
&wrapper_vertical_16_c, 12, 1),
make_tuple(&wrapper_vertical_16_dual_sse2,
&wrapper_vertical_16_dual_c, 8, 1),
make_tuple(&wrapper_vertical_16_dual_sse2,
&wrapper_vertical_16_dual_c, 10, 1),
make_tuple(&wrapper_vertical_16_dual_sse2,
&wrapper_vertical_16_dual_c, 12, 1)));
#else
INSTANTIATE_TEST_CASE_P(
SSE2, Loop8Test6Param,
::testing::Values(
make_tuple(&vp9_lpf_horizontal_8_sse2, &vp9_lpf_horizontal_8_c, 8, 1),
make_tuple(&vp9_lpf_horizontal_16_sse2, &vp9_lpf_horizontal_16_c, 8, 1),
make_tuple(&vp9_lpf_horizontal_16_sse2, &vp9_lpf_horizontal_16_c, 8, 2),
make_tuple(&vp9_lpf_vertical_8_sse2, &vp9_lpf_vertical_8_c, 8, 1),
make_tuple(&wrapper_vertical_16_sse2, &wrapper_vertical_16_c, 8, 1)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif
#if HAVE_AVX2 && (!CONFIG_VP9_HIGHBITDEPTH)
INSTANTIATE_TEST_CASE_P(
AVX2, Loop8Test6Param,
::testing::Values(
make_tuple(&vp9_lpf_horizontal_16_avx2, &vp9_lpf_horizontal_16_c, 8, 1),
make_tuple(&vp9_lpf_horizontal_16_avx2, &vp9_lpf_horizontal_16_c, 8,
2)));
#endif
#if HAVE_SSE2
#if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
SSE2, Loop8Test9Param,
::testing::Values(
make_tuple(&vp9_highbd_lpf_horizontal_4_dual_sse2,
&vp9_highbd_lpf_horizontal_4_dual_c, 8),
make_tuple(&vp9_highbd_lpf_horizontal_8_dual_sse2,
&vp9_highbd_lpf_horizontal_8_dual_c, 8),
make_tuple(&vp9_highbd_lpf_vertical_4_dual_sse2,
&vp9_highbd_lpf_vertical_4_dual_c, 8),
make_tuple(&vp9_highbd_lpf_vertical_8_dual_sse2,
&vp9_highbd_lpf_vertical_8_dual_c, 8),
make_tuple(&vp9_highbd_lpf_horizontal_4_dual_sse2,
&vp9_highbd_lpf_horizontal_4_dual_c, 10),
make_tuple(&vp9_highbd_lpf_horizontal_8_dual_sse2,
&vp9_highbd_lpf_horizontal_8_dual_c, 10),
make_tuple(&vp9_highbd_lpf_vertical_4_dual_sse2,
&vp9_highbd_lpf_vertical_4_dual_c, 10),
make_tuple(&vp9_highbd_lpf_vertical_8_dual_sse2,
&vp9_highbd_lpf_vertical_8_dual_c, 10),
make_tuple(&vp9_highbd_lpf_horizontal_4_dual_sse2,
&vp9_highbd_lpf_horizontal_4_dual_c, 12),
make_tuple(&vp9_highbd_lpf_horizontal_8_dual_sse2,
&vp9_highbd_lpf_horizontal_8_dual_c, 12),
make_tuple(&vp9_highbd_lpf_vertical_4_dual_sse2,
&vp9_highbd_lpf_vertical_4_dual_c, 12),
make_tuple(&vp9_highbd_lpf_vertical_8_dual_sse2,
&vp9_highbd_lpf_vertical_8_dual_c, 12)));
#else
INSTANTIATE_TEST_CASE_P(
SSE2, Loop8Test9Param,
::testing::Values(
make_tuple(&vp9_lpf_horizontal_4_dual_sse2,
&vp9_lpf_horizontal_4_dual_c, 8),
make_tuple(&vp9_lpf_horizontal_8_dual_sse2,
&vp9_lpf_horizontal_8_dual_c, 8),
make_tuple(&vp9_lpf_vertical_4_dual_sse2,
&vp9_lpf_vertical_4_dual_c, 8),
make_tuple(&vp9_lpf_vertical_8_dual_sse2,
&vp9_lpf_vertical_8_dual_c, 8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif
#if HAVE_NEON
#if CONFIG_VP9_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(&vp9_lpf_horizontal_16_neon,
&vp9_lpf_horizontal_16_c, 8, 1),
make_tuple(&vp9_lpf_horizontal_16_neon,
&vp9_lpf_horizontal_16_c, 8, 2),
make_tuple(&wrapper_vertical_16_neon,
&wrapper_vertical_16_c, 8, 1),
make_tuple(&wrapper_vertical_16_dual_neon,
&wrapper_vertical_16_dual_c, 8, 1),
make_tuple(&vp9_lpf_horizontal_8_neon,
&vp9_lpf_horizontal_8_c, 8, 1),
make_tuple(&vp9_lpf_vertical_8_neon,
&vp9_lpf_vertical_8_c, 8, 1),
#endif // HAVE_NEON_ASM
make_tuple(&vp9_lpf_horizontal_4_neon,
&vp9_lpf_horizontal_4_c, 8, 1),
make_tuple(&vp9_lpf_vertical_4_neon,
&vp9_lpf_vertical_4_c, 8, 1)));
INSTANTIATE_TEST_CASE_P(
NEON, Loop8Test9Param,
::testing::Values(
#if HAVE_NEON_ASM
make_tuple(&vp9_lpf_horizontal_8_dual_neon,
&vp9_lpf_horizontal_8_dual_c, 8),
make_tuple(&vp9_lpf_vertical_8_dual_neon,
&vp9_lpf_vertical_8_dual_c, 8),
#endif // HAVE_NEON_ASM
make_tuple(&vp9_lpf_horizontal_4_dual_neon,
&vp9_lpf_horizontal_4_dual_c, 8),
make_tuple(&vp9_lpf_vertical_4_dual_neon,
&vp9_lpf_vertical_4_dual_c, 8)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // HAVE_NEON
} // namespace

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