Compare commits
No commits in common. "main" and "sandbox/luoyi@google.com/convolve" have entirely different histories.
main
...
sandbox/lu
109
.clang-format
109
.clang-format
@ -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
|
||||
...
|
||||
|
18
.gitattributes
vendored
18
.gitattributes
vendored
@ -1,18 +0,0 @@
|
||||
*.[chs] filter=fixtabswsp
|
||||
*.[ch]pp filter=fixtabswsp
|
||||
*.[ch]xx filter=fixtabswsp
|
||||
*.asm filter=fixtabswsp
|
||||
*.php filter=fixtabswsp
|
||||
*.pl filter=fixtabswsp
|
||||
*.sh filter=fixtabswsp
|
||||
*.txt filter=fixwsp
|
||||
[Mm]akefile filter=fixwsp
|
||||
*.mk filter=fixwsp
|
||||
*.rc -crlf
|
||||
*.ds[pw] -crlf
|
||||
*.bat -crlf
|
||||
*.mmp -crlf
|
||||
*.dpj -crlf
|
||||
*.pjt -crlf
|
||||
*.vcp -crlf
|
||||
*.inf -crlf
|
68
.gitignore
vendored
68
.gitignore
vendored
@ -1,68 +0,0 @@
|
||||
*.S
|
||||
*.a
|
||||
*.asm.s
|
||||
*.d
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.o
|
||||
*~
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
||||
/*-*.mk
|
||||
/*.asm
|
||||
/*.doxy
|
||||
/*.ivf
|
||||
/*.ivf.md5
|
||||
/.bins
|
||||
/.deps
|
||||
/.docs
|
||||
/.install-*
|
||||
/.libs
|
||||
/Makefile
|
||||
/config.log
|
||||
/config.mk
|
||||
/docs/
|
||||
/doxyfile
|
||||
/examples/*.dox
|
||||
/examples/decode_to_md5
|
||||
/examples/decode_with_drops
|
||||
/examples/decode_with_partial_drops
|
||||
/examples/example_xma
|
||||
/examples/postproc
|
||||
/examples/resize_util
|
||||
/examples/set_maps
|
||||
/examples/simple_decoder
|
||||
/examples/simple_encoder
|
||||
/examples/twopass_encoder
|
||||
/examples/vp8_multi_resolution_encoder
|
||||
/examples/vp8cx_set_ref
|
||||
/examples/vp9cx_set_ref
|
||||
/examples/vp9_lossless_encoder
|
||||
/examples/vp9_spatial_svc_encoder
|
||||
/examples/vpx_temporal_svc_encoder
|
||||
/ivfdec
|
||||
/ivfdec.dox
|
||||
/ivfenc
|
||||
/ivfenc.dox
|
||||
/libvpx.so*
|
||||
/libvpx.ver
|
||||
/samples.dox
|
||||
/test_intra_pred_speed
|
||||
/test_libvpx
|
||||
/tools.dox
|
||||
/tools/*.dox
|
||||
/tools/tiny_ssim
|
||||
/vp8_api1_migration.dox
|
||||
/vp[89x]_rtcd.h
|
||||
/vpx.pc
|
||||
/vpx_config.c
|
||||
/vpx_config.h
|
||||
/vpx_dsp_rtcd.h
|
||||
/vpx_scale_rtcd.h
|
||||
/vpx_version.h
|
||||
/vpxdec
|
||||
/vpxdec.dox
|
||||
/vpxenc
|
||||
/vpxenc.dox
|
||||
TAGS
|
42
.mailmap
42
.mailmap
@ -1,42 +0,0 @@
|
||||
Adrian Grange <agrange@google.com>
|
||||
Aℓex Converse <aconverse@google.com>
|
||||
Aℓex Converse <aconverse@google.com> <alex.converse@gmail.com>
|
||||
Alexis Ballier <aballier@gentoo.org> <alexis.ballier@gmail.com>
|
||||
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>
|
||||
Erik Niemeyer <erik.a.niemeyer@intel.com> <erik.a.niemeyer@gmail.com>
|
||||
Guillaume Martres <gmartres@google.com> <smarter3@gmail.com>
|
||||
Hangyu Kuang <hkuang@google.com>
|
||||
Hui Su <huisu@google.com>
|
||||
Jacky Chen <jackychen@google.com>
|
||||
Jim Bankoski <jimbankoski@google.com>
|
||||
Johann Koenig <johannkoenig@google.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>
|
||||
Joshua Litt <joshualitt@google.com> <joshualitt@chromium.org>
|
||||
Marco Paniconi <marpan@google.com>
|
||||
Marco Paniconi <marpan@google.com> <marpan@chromium.org>
|
||||
Pascal Massimino <pascal.massimino@gmail.com>
|
||||
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@mozilla.com>
|
||||
Ronald S. Bultje <rsbultje@gmail.com> <rbultje@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> <levytamar82@gmail.com>
|
||||
Tero Rintaluoma <teror@google.com> <tero.rintaluoma@on2.com>
|
||||
Timothy B. Terriberry <tterribe@xiph.org> <tterriberry@mozilla.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 Xu>
|
170
AUTHORS
170
AUTHORS
@ -1,170 +0,0 @@
|
||||
# This file is automatically generated from the git commit history
|
||||
# by tools/gen_authors.sh.
|
||||
|
||||
Aaron Watry <awatry@gmail.com>
|
||||
Abo Talib Mahfoodh <ab.mahfoodh@gmail.com>
|
||||
Adrian Grange <agrange@google.com>
|
||||
Aℓex Converse <aconverse@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>
|
||||
Alexandra Hájková <alexandra.khirnova@gmail.com>
|
||||
Alexis Ballier <aballier@gentoo.org>
|
||||
Alok Ahuja <waveletcoeff@gmail.com>
|
||||
Alpha Lam <hclam@google.com>
|
||||
A.Mahfoodh <ab.mahfoodh@gmail.com>
|
||||
Ami Fischman <fischman@chromium.org>
|
||||
Andoni Morales Alastruey <ylatuya@gmail.com>
|
||||
Andres Mejia <mcitadel@gmail.com>
|
||||
Andrew Lewis <andrewlewis@google.com>
|
||||
Andrew Russell <anrussell@google.com>
|
||||
Angie Chiang <angiebird@google.com>
|
||||
Aron Rosenberg <arosenberg@logitech.com>
|
||||
Attila Nagy <attilanagy@google.com>
|
||||
Brion Vibber <bvibber@wikimedia.org>
|
||||
changjun.yang <changjun.yang@intel.com>
|
||||
Charles 'Buck' Krasic <ckrasic@google.com>
|
||||
Cheng Chen <chengchen@google.com>
|
||||
chm <chm@rock-chips.com>
|
||||
Chris Cunningham <chcunningham@chromium.org>
|
||||
Christian Duvivier <cduvivier@google.com>
|
||||
Daniele Castagna <dcastagna@chromium.org>
|
||||
Daniel Kang <ddkang@google.com>
|
||||
Deb Mukherjee <debargha@google.com>
|
||||
Deepa K G <deepa.kg@ittiam.com>
|
||||
Dim Temp <dimtemp0@gmail.com>
|
||||
Dmitry Kovalev <dkovalev@google.com>
|
||||
Dragan Mrdjan <dmrdjan@mips.com>
|
||||
Ed Baker <edward.baker@intel.com>
|
||||
Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||
Erik Niemeyer <erik.a.niemeyer@intel.com>
|
||||
Fabio Pedretti <fabio.ped@libero.it>
|
||||
Frank Galligan <fgalligan@google.com>
|
||||
Fredrik Söderquist <fs@opera.com>
|
||||
Fritz Koenig <frkoenig@google.com>
|
||||
Gabriel Marin <gmx@chromium.org>
|
||||
Gaute Strokkenes <gaute.strokkenes@broadcom.com>
|
||||
Geza Lore <gezalore@gmail.com>
|
||||
Ghislain MARY <ghislainmary2@gmail.com>
|
||||
Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
Gordana Cmiljanovic <gordana.cmiljanovic@imgtec.com>
|
||||
Gregor Jasny <gjasny@gmail.com>
|
||||
Guillaume Martres <gmartres@google.com>
|
||||
Guillermo Ballester Valor <gbvalor@gmail.com>
|
||||
Hangyu Kuang <hkuang@google.com>
|
||||
Hanno Böck <hanno@hboeck.de>
|
||||
Han Shen <shenhan@google.com>
|
||||
Henrik Lundin <hlundin@google.com>
|
||||
Hui Su <huisu@google.com>
|
||||
Ivan Krasin <krasin@chromium.org>
|
||||
Ivan Maltz <ivanmaltz@google.com>
|
||||
Jacek Caban <cjacek@gmail.com>
|
||||
Jacky Chen <jackychen@google.com>
|
||||
James Berry <jamesberry@google.com>
|
||||
James Yu <james.yu@linaro.org>
|
||||
James Zern <jzern@google.com>
|
||||
Jan Gerber <j@mailb.org>
|
||||
Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
Janne Salonen <jsalonen@google.com>
|
||||
Jean-Yves Avenard <jyavenard@mozilla.com>
|
||||
Jeff Faust <jfaust@google.com>
|
||||
Jeff Muizelaar <jmuizelaar@mozilla.com>
|
||||
Jeff Petkau <jpet@chromium.org>
|
||||
Jerome Jiang <jianj@google.com>
|
||||
Jia Jia <jia.jia@linaro.org>
|
||||
Jian Zhou <zhoujian@google.com>
|
||||
Jim Bankoski <jimbankoski@google.com>
|
||||
Jingning Han <jingning@google.com>
|
||||
Joey Parrish <joeyparrish@google.com>
|
||||
Johann Koenig <johannkoenig@google.com>
|
||||
John Koleszar <jkoleszar@google.com>
|
||||
Johnny Klonaris <google@jawknee.com>
|
||||
John Stark <jhnstrk@gmail.com>
|
||||
Joshua Bleecher Snyder <josh@treelinelabs.com>
|
||||
Joshua Litt <joshualitt@google.com>
|
||||
Julia Robson <juliamrobson@gmail.com>
|
||||
Justin Clift <justin@salasaga.org>
|
||||
Justin Lebar <justin.lebar@gmail.com>
|
||||
Kaustubh Raste <kaustubh.raste@imgtec.com>
|
||||
KO Myung-Hun <komh@chollian.net>
|
||||
Kyle Siefring <kylesiefring@gmail.com>
|
||||
Lawrence Velázquez <larryv@macports.org>
|
||||
Linfeng Zhang <linfengz@google.com>
|
||||
Lou Quillio <louquillio@google.com>
|
||||
Luca Barbato <lu_zero@gentoo.org>
|
||||
Makoto Kato <makoto.kt@gmail.com>
|
||||
Mans Rullgard <mans@mansr.com>
|
||||
Marco Paniconi <marpan@google.com>
|
||||
Mark Mentovai <mark@chromium.org>
|
||||
Martin Ettl <ettl.martin78@googlemail.com>
|
||||
Martin Storsjo <martin@martin.st>
|
||||
Matthew Heaney <matthewjheaney@chromium.org>
|
||||
Michael Kohler <michaelkohler@live.com>
|
||||
Mike Frysinger <vapier@chromium.org>
|
||||
Mike Hommey <mhommey@mozilla.com>
|
||||
Mikhal Shemer <mikhal@google.com>
|
||||
Min Chen <chenm003@gmail.com>
|
||||
Minghai Shang <minghai@google.com>
|
||||
Min Ye <yeemmi@google.com>
|
||||
Moriyoshi Koizumi <mozo@mozo.jp>
|
||||
Morton Jonuschat <yabawock@gmail.com>
|
||||
Nathan E. Egge <negge@mozilla.com>
|
||||
Nico Weber <thakis@chromium.org>
|
||||
Parag Salasakar <img.mips1@gmail.com>
|
||||
Pascal Massimino <pascal.massimino@gmail.com>
|
||||
Patrik Westin <patrik.westin@gmail.com>
|
||||
Paul Wilkins <paulwilkins@google.com>
|
||||
Pavol Rusnak <stick@gk2.sk>
|
||||
Paweł Hajdan <phajdan@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>
|
||||
Philip Jägenstedt <philipj@opera.com>
|
||||
Priit Laes <plaes@plaes.org>
|
||||
Rafael Ávila de Espíndola <rafael.espindola@gmail.com>
|
||||
Rafaël Carré <funman@videolan.org>
|
||||
Rafael de Lucena Valle <rafaeldelucena@gmail.com>
|
||||
Rahul Chaudhry <rahulchaudhry@google.com>
|
||||
Ralph Giles <giles@xiph.org>
|
||||
Ranjit Kumar Tulabandu <ranjit.tulabandu@ittiam.com>
|
||||
Rob Bradford <rob@linux.intel.com>
|
||||
Ronald S. Bultje <rsbultje@gmail.com>
|
||||
Rui Ueyama <ruiu@google.com>
|
||||
Sami Pietilä <samipietila@google.com>
|
||||
Sarah Parker <sarahparker@google.com>
|
||||
Sasi Inguva <isasi@google.com>
|
||||
Scott Graham <scottmg@chromium.org>
|
||||
Scott LaVarnway <slavarnway@google.com>
|
||||
Sean McGovern <gseanmcg@gmail.com>
|
||||
Sergey Kolomenkin <kolomenkin@gmail.com>
|
||||
Sergey Ulanov <sergeyu@chromium.org>
|
||||
Shimon Doodkin <helpmepro1@gmail.com>
|
||||
Shiyou Yin <yinshiyou-hf@loongson.cn>
|
||||
Shunyao Li <shunyaoli@google.com>
|
||||
Stefan Holmer <holmer@google.com>
|
||||
Suman Sunkara <sunkaras@google.com>
|
||||
Sylvestre Ledru <sylvestre@mozilla.com>
|
||||
Taekhyun Kim <takim@nvidia.com>
|
||||
Takanori MATSUURA <t.matsuu@gmail.com>
|
||||
Tamar Levy <tamar.levy@intel.com>
|
||||
Tao Bai <michaelbai@chromium.org>
|
||||
Tero Rintaluoma <teror@google.com>
|
||||
Thijs Vermeir <thijsvermeir@gmail.com>
|
||||
Tim Kopp <tkopp@google.com>
|
||||
Timothy B. Terriberry <tterribe@xiph.org>
|
||||
Tom Finegan <tomfinegan@google.com>
|
||||
Tristan Matthews <le.businessman@gmail.com>
|
||||
Urvang Joshi <urvang@google.com>
|
||||
Vignesh Venkatasubramanian <vigneshv@google.com>
|
||||
Vlad Tsyrklevich <vtsyrklevich@chromium.org>
|
||||
Yaowu Xu <yaowu@google.com>
|
||||
Yi Luo <luoyi@google.com>
|
||||
Yongzhe Wang <yongzhe@google.com>
|
||||
Yunqing Wang <yunqingwang@google.com>
|
||||
Yury Gitman <yuryg@google.com>
|
||||
Zoe Liu <zoeliu@google.com>
|
||||
Google Inc.
|
||||
The Mozilla Foundation
|
||||
The Xiph.Org Foundation
|
695
CHANGELOG
695
CHANGELOG
@ -1,695 +0,0 @@
|
||||
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"
|
||||
This release includes significant improvements to the VP9 codec.
|
||||
|
||||
- Upgrading:
|
||||
This release is ABI incompatible with 1.3.0. It drops the compatibility
|
||||
layer, requiring VPX_IMG_FMT_* instead of IMG_FMT_*, and adds several codec
|
||||
controls for VP9.
|
||||
|
||||
- Enhancements:
|
||||
Faster VP9 encoding and decoding
|
||||
Multithreaded VP9 decoding (tile and frame-based)
|
||||
Multithreaded VP9 encoding - on by default
|
||||
YUV 4:2:2 and 4:4:4 support in VP9
|
||||
10 and 12bit support in VP9
|
||||
64bit ARM support by replacing ARM assembly with intrinsics
|
||||
|
||||
- Bug Fixes:
|
||||
Fixes a VP9 bitstream issue in Profile 1. This only affected non-YUV 4:2:0
|
||||
files.
|
||||
|
||||
- Known Issues:
|
||||
Frame Parallel decoding fails for segmented and non-420 files.
|
||||
|
||||
2013-11-15 v1.3.0 "Forest"
|
||||
This release introduces the VP9 codec in a backward-compatible way.
|
||||
All existing users of VP8 can continue to use the library without
|
||||
modification. However, some VP8 options do not map to VP9 in the same manner.
|
||||
|
||||
The VP9 encoder in this release is not feature complete. Users interested in
|
||||
the encoder are advised to use the git master branch and discuss issues on
|
||||
libvpx mailing lists.
|
||||
|
||||
- Upgrading:
|
||||
This release is ABI and API compatible with Duclair (v1.0.0). Users
|
||||
of older releases should refer to the Upgrading notes in this document
|
||||
for that release.
|
||||
|
||||
- Enhancements:
|
||||
Get rid of bashisms in the main build scripts
|
||||
Added usage info on command line options
|
||||
Add lossless compression mode
|
||||
Dll build of libvpx
|
||||
Add additional Mac OS X targets: 10.7, 10.8 and 10.9 (darwin11-13)
|
||||
Add option to disable documentation
|
||||
configure: add --enable-external-build support
|
||||
make: support V=1 as short form of verbose=yes
|
||||
configure: support mingw-w64
|
||||
configure: support hardfloat armv7 CHOSTS
|
||||
configure: add support for android x86
|
||||
Add estimated completion time to vpxenc
|
||||
Don't exit on decode errors in vpxenc
|
||||
vpxenc: support scaling prior to encoding
|
||||
vpxdec: support scaling output
|
||||
vpxenc: improve progress indicators with --skip
|
||||
msvs: Don't link to winmm.lib
|
||||
Add a new script for producing vcxproj files
|
||||
Produce Visual Studio 10 and 11 project files
|
||||
Produce Windows Phone project files
|
||||
msvs-build: use msbuild for vs >= 2005
|
||||
configure: default configure log to config.log
|
||||
Add encoding option --static-thresh
|
||||
|
||||
- Speed:
|
||||
Miscellaneous speed optimizations for VP8 and VP9.
|
||||
|
||||
- Quality:
|
||||
In general, quality is consistent with the Eider release.
|
||||
|
||||
- Bug Fixes:
|
||||
This release represents approximately a year of engineering effort,
|
||||
and contains multiple bug fixes. Please refer to git history for details.
|
||||
|
||||
|
||||
2012-12-21 v1.2.0
|
||||
This release acts as a checkpoint for a large amount of internal refactoring
|
||||
and testing. It also contains a number of small bugfixes, so all users are
|
||||
encouraged to upgrade.
|
||||
|
||||
- Upgrading:
|
||||
This release is ABI and API compatible with Duclair (v1.0.0). Users
|
||||
of older releases should refer to the Upgrading notes in this
|
||||
document for that release.
|
||||
|
||||
- Enhancements:
|
||||
VP8 optimizations for MIPS dspr2
|
||||
vpxenc: add -quiet option
|
||||
|
||||
- Speed:
|
||||
Encoder and decoder speed is consistent with the Eider release.
|
||||
|
||||
- Quality:
|
||||
In general, quality is consistent with the Eider release.
|
||||
|
||||
Minor tweaks to ARNR filtering
|
||||
Minor improvements to real time encoding with multiple temporal layers
|
||||
|
||||
- Bug Fixes:
|
||||
Fixes multithreaded encoder race condition in loopfilter
|
||||
Fixes multi-resolution threaded encoding
|
||||
Fix potential encoder dead-lock after picture resize
|
||||
|
||||
|
||||
2012-05-09 v1.1.0 "Eider"
|
||||
This introduces a number of enhancements, mostly focused on real-time
|
||||
encoding. In addition, it fixes a decoder bug (first introduced in
|
||||
Duclair) so all users of that release are encouraged to upgrade.
|
||||
|
||||
- Upgrading:
|
||||
This release is ABI and API compatible with Duclair (v1.0.0). Users
|
||||
of older releases should refer to the Upgrading notes in this
|
||||
document for that release.
|
||||
|
||||
This release introduces a new temporal denoiser, controlled by the
|
||||
VP8E_SET_NOISE_SENSITIVITY control. The temporal denoiser does not
|
||||
currently take a strength parameter, so the control is effectively
|
||||
a boolean - zero (off) or non-zero (on). For compatibility with
|
||||
existing applications, the values accepted are the same as those
|
||||
for the spatial denoiser (0-6). The temporal denoiser is enabled
|
||||
by default, and the older spatial denoiser may be restored by
|
||||
configuring with --disable-temporal-denoising. The temporal denoiser
|
||||
is more computationally intensive than the spatial one.
|
||||
|
||||
This release removes support for a legacy, decode only API that was
|
||||
supported, but deprecated, at the initial release of libvpx
|
||||
(v0.9.0). This is not expected to have any impact. If you are
|
||||
impacted, you can apply a reversion to commit 2bf8fb58 locally.
|
||||
Please update to the latest libvpx API if you are affected.
|
||||
|
||||
- Enhancements:
|
||||
Adds a motion compensated temporal denoiser to the encoder, which
|
||||
gives higher quality than the older spatial denoiser. (See above
|
||||
for notes on upgrading).
|
||||
|
||||
In addition, support for new compilers and platforms were added,
|
||||
including:
|
||||
improved support for XCode
|
||||
Android x86 NDK build
|
||||
OS/2 support
|
||||
SunCC support
|
||||
|
||||
Changing resolution with vpx_codec_enc_config_set() is now
|
||||
supported. Previously, reinitializing the codec was required to
|
||||
change the input resolution.
|
||||
|
||||
The vpxenc application has initial support for producing multiple
|
||||
encodes from the same input in one call. Resizing is not yet
|
||||
supported, but varying other codec parameters is. Use -- to
|
||||
delineate output streams. Options persist from one stream to the
|
||||
next.
|
||||
|
||||
Also, the vpxenc application will now use a keyframe interval of
|
||||
5 seconds by default. Use the --kf-max-dist option to override.
|
||||
|
||||
- Speed:
|
||||
Decoder performance improved 2.5% versus Duclair. Encoder speed is
|
||||
consistent with Duclair for most material. Two pass encoding of
|
||||
slideshow-like material will see significant improvements.
|
||||
|
||||
Large realtime encoding speed gains at a small quality expense are
|
||||
possible by configuring the on-the-fly bitpacking experiment with
|
||||
--enable-onthefly-bitpacking. Realtime encoder can be up to 13%
|
||||
faster (ARM) depending on the number of threads and bitrate
|
||||
settings. This technique sees constant gain over the 5-16 speed
|
||||
range. For VC style input the loss seen is up to 0.2dB. See commit
|
||||
52cf4dca for further details.
|
||||
|
||||
- Quality:
|
||||
On the whole, quality is consistent with the Duclair release. Some
|
||||
tweaks:
|
||||
|
||||
Reduced blockiness in easy sections by applying a penalty to
|
||||
intra modes.
|
||||
|
||||
Improved quality of static sections (like slideshows) with
|
||||
two pass encoding.
|
||||
|
||||
Improved keyframe sizing with multiple temporal layers
|
||||
|
||||
- Bug Fixes:
|
||||
Corrected alt-ref contribution to frame rate for visible updates
|
||||
to the alt-ref buffer. This affected applications making manual
|
||||
usage of the frame reference flags, or temporal layers.
|
||||
|
||||
Additional constraints were added to disable multi-frame quality
|
||||
enhancement (MFQE) in sections of the frame where there is motion.
|
||||
(#392)
|
||||
|
||||
Fixed corruption issues when vpx_codec_enc_config_set() was called
|
||||
with spatial resampling enabled.
|
||||
|
||||
Fixed a decoder error introduced in Duclair where the segmentation
|
||||
map was not being reinitialized on keyframes (#378)
|
||||
|
||||
|
||||
2012-01-27 v1.0.0 "Duclair"
|
||||
Our fourth named release, focused on performance and features related to
|
||||
real-time encoding. It also fixes a decoder crash bug introduced in
|
||||
v0.9.7, so all users of that release are encouraged to upgrade.
|
||||
|
||||
- Upgrading:
|
||||
This release is ABI incompatible with prior releases of libvpx, so the
|
||||
"major" version number has been bumped to 1. You must recompile your
|
||||
applications against the latest version of the libvpx headers. The
|
||||
API remains compatible, and this should not require code changes in most
|
||||
applications.
|
||||
|
||||
- Enhancements:
|
||||
This release introduces several substantial new features to the encoder,
|
||||
of particular interest to real time streaming applications.
|
||||
|
||||
Temporal scalability allows the encoder to produce a stream that can
|
||||
be decimated to different frame rates, with independent rate targetting
|
||||
for each substream.
|
||||
|
||||
Multiframe quality enhancement postprocessing can make visual quality
|
||||
more consistent in the presence of frames that are substantially
|
||||
different quality than the surrounding frames, as in the temporal
|
||||
scalability case and in some forced keyframe scenarios.
|
||||
|
||||
Multiple-resolution encoding support allows the encoding of the
|
||||
same content at different resolutions faster than encoding them
|
||||
separately.
|
||||
|
||||
- Speed:
|
||||
Optimization targets for this release included the decoder and the real-
|
||||
time modes of the encoder. Decoder speed on x86 has improved 10.5% with
|
||||
this release. Encoder improvements followed a curve where speeds 1-3
|
||||
improved 4.0%-1.5%, speeds 4-8 improved <1%, and speeds 9-16 improved
|
||||
1.5% to 10.5%, respectively. "Best" mode speed is consistent with the
|
||||
Cayuga release.
|
||||
|
||||
- Quality:
|
||||
Encoder quality in the single stream case is consistent with the Cayuga
|
||||
release.
|
||||
|
||||
- Bug Fixes:
|
||||
This release fixes an OOB read decoder crash bug present in v0.9.7
|
||||
related to the clamping of motion vectors in SPLITMV blocks. This
|
||||
behavior could be triggered by corrupt input or by starting
|
||||
decoding from a P-frame.
|
||||
|
||||
|
||||
2011-08-15 v0.9.7-p1 "Cayuga" patch 1
|
||||
This is an incremental bugfix release against Cayuga. All users of that
|
||||
release are strongly encouraged to upgrade.
|
||||
|
||||
- Fix potential OOB reads (cdae03a)
|
||||
|
||||
An unbounded out of bounds read was discovered when the
|
||||
decoder was requested to perform error concealment (new in
|
||||
Cayuga) given a frame with corrupt partition sizes.
|
||||
|
||||
A bounded out of bounds read was discovered affecting all
|
||||
versions of libvpx. Given an multipartition input frame that
|
||||
is truncated between the mode/mv partition and the first
|
||||
residiual paritition (in the block of partition offsets), up
|
||||
to 3 extra bytes could have been read from the source buffer.
|
||||
The code will not take any action regardless of the contents
|
||||
of these undefined bytes, as the truncated buffer is detected
|
||||
immediately following the read based on the calculated
|
||||
starting position of the coefficient partition.
|
||||
|
||||
- Fix potential error concealment crash when the very first frame
|
||||
is missing or corrupt (a609be5)
|
||||
|
||||
- Fix significant artifacts in error concealment (a4c2211, 99d870a)
|
||||
|
||||
- Revert 1-pass CBR rate control changes (e961317)
|
||||
Further testing showed this change produced undesirable visual
|
||||
artifacts, rolling back for now.
|
||||
|
||||
|
||||
2011-08-02 v0.9.7 "Cayuga"
|
||||
Our third named release, focused on a faster, higher quality, encoder.
|
||||
|
||||
- Upgrading:
|
||||
This release is backwards compatible with Aylesbury (v0.9.5) and
|
||||
Bali (v0.9.6). Users of older releases should refer to the Upgrading
|
||||
notes in this document for that release.
|
||||
|
||||
- Enhancements:
|
||||
Stereo 3D format support for vpxenc
|
||||
Runtime detection of available processor cores.
|
||||
Allow specifying --end-usage by enum name
|
||||
vpxdec: test for frame corruption
|
||||
vpxenc: add quantizer histogram display
|
||||
vpxenc: add rate histogram display
|
||||
Set VPX_FRAME_IS_DROPPABLE
|
||||
update configure for ios sdk 4.3
|
||||
Avoid text relocations in ARM vp8 decoder
|
||||
Generate a vpx.pc file for pkg-config.
|
||||
New ways of passing encoded data between encoder and decoder.
|
||||
|
||||
- Speed:
|
||||
This release includes across-the-board speed improvements to the
|
||||
encoder. On x86, these measure at approximately 11.5% in Best mode,
|
||||
21.5% in Good mode (speed 0), and 22.5% in Realtime mode (speed 6).
|
||||
On ARM Cortex A9 with Neon extensions, real-time encoding of video
|
||||
telephony content is 35% faster than Bali on single core and 48%
|
||||
faster on multi-core. On the NVidia Tegra2 platform, real time
|
||||
encoding is 40% faster than Bali.
|
||||
|
||||
Decoder speed was not a priority for this release, but improved
|
||||
approximately 8.4% on x86.
|
||||
|
||||
Reduce motion vector search on alt-ref frame.
|
||||
Encoder loopfilter running in its own thread
|
||||
Reworked loopfilter to precalculate more parameters
|
||||
SSE2/SSSE3 optimizations for build_predictors_mbuv{,_s}().
|
||||
Make hor UV predict ~2x faster (73 vs 132 cycles) using SSSE3.
|
||||
Removed redundant checks
|
||||
Reduced structure sizes
|
||||
utilize preload in ARMv6 MC/LPF/Copy routines
|
||||
ARM optimized quantization, dfct, variance, subtract
|
||||
Increase chrow row alignment to 16 bytes.
|
||||
disable trellis optimization for first pass
|
||||
Write SSSE3 sub-pixel filter function
|
||||
Improve SSE2 half-pixel filter funtions
|
||||
Add vp8_sub_pixel_variance16x8_ssse3 function
|
||||
Reduce unnecessary distortion computation
|
||||
Use diamond search to replace full search
|
||||
Preload reference area in sub-pixel motion search (real-time mode)
|
||||
|
||||
- Quality:
|
||||
This release focused primarily on one-pass use cases, including
|
||||
video conferencing. Low latency data rate control was significantly
|
||||
improved, improving streamability over bandwidth constrained links.
|
||||
Added support for error concealment, allowing frames to maintain
|
||||
visual quality in the presence of substantial packet loss.
|
||||
|
||||
Add rc_max_intra_bitrate_pct control
|
||||
Limit size of initial keyframe in one-pass.
|
||||
Improve framerate adaptation
|
||||
Improved 1-pass CBR rate control
|
||||
Improved KF insertion after fades to still.
|
||||
Improved key frame detection.
|
||||
Improved activity masking (lower PSNR impact for same SSIM boost)
|
||||
Improved interaction between GF and ARFs
|
||||
Adding error-concealment to the decoder.
|
||||
Adding support for independent partitions
|
||||
Adjusted rate-distortion constants
|
||||
|
||||
|
||||
- Bug Fixes:
|
||||
Removed firstpass motion map
|
||||
Fix parallel make install
|
||||
Fix multithreaded encoding for 1 MB wide frame
|
||||
Fixed iwalsh_neon build problems with RVDS4.1
|
||||
Fix semaphore emulation, spin-wait intrinsics on Windows
|
||||
Fix build with xcode4 and simplify GLOBAL.
|
||||
Mark ARM asm objects as allowing a non-executable stack.
|
||||
Fix vpxenc encoding incorrect webm file header on big endian
|
||||
|
||||
|
||||
2011-03-07 v0.9.6 "Bali"
|
||||
Our second named release, focused on a faster, higher quality, encoder.
|
||||
|
||||
- Upgrading:
|
||||
This release is backwards compatible with Aylesbury (v0.9.5). Users
|
||||
of older releases should refer to the Upgrading notes in this
|
||||
document for that release.
|
||||
|
||||
- Enhancements:
|
||||
vpxenc --psnr shows a summary when encode completes
|
||||
--tune=ssim option to enable activity masking
|
||||
improved postproc visualizations for development
|
||||
updated support for Apple iOS to SDK 4.2
|
||||
query decoder to determine which reference frames were updated
|
||||
implemented error tracking in the decoder
|
||||
fix pipe support on windows
|
||||
|
||||
- Speed:
|
||||
Primary focus was on good quality mode, speed 0. Average improvement
|
||||
on x86 about 40%, up to 100% on user-generated content at that speed.
|
||||
Best quality mode speed improved 35%, and realtime speed 10-20%. This
|
||||
release also saw significant improvement in realtime encoding speed
|
||||
on ARM platforms.
|
||||
|
||||
Improved encoder threading
|
||||
Dont pick encoder filter level when loopfilter is disabled.
|
||||
Avoid double copying of key frames into alt and golden buffer
|
||||
FDCT optimizations.
|
||||
x86 sse2 temporal filter
|
||||
SSSE3 version of fast quantizer
|
||||
vp8_rd_pick_best_mbsegmentation code restructure
|
||||
Adjusted breakout RD for SPLITMV
|
||||
Changed segmentation check order
|
||||
Improved rd_pick_intra4x4block
|
||||
Adds armv6 optimized variance calculation
|
||||
ARMv6 optimized sad16x16
|
||||
ARMv6 optimized half pixel variance calculations
|
||||
Full search SAD function optimization in SSE4.1
|
||||
Improve MV prediction accuracy to achieve performance gain
|
||||
Improve MV prediction in vp8_pick_inter_mode() for speed>3
|
||||
|
||||
- Quality:
|
||||
Best quality mode improved PSNR 6.3%, and SSIM 6.1%. This release
|
||||
also includes support for "activity masking," which greatly improves
|
||||
SSIM at the expense of PSNR. For now, this feature is available with
|
||||
the --tune=ssim option. Further experimentation in this area
|
||||
is ongoing. This release also introduces a new rate control mode
|
||||
called "CQ," which changes the allocation of bits within a clip to
|
||||
the sections where they will have the most visual impact.
|
||||
|
||||
Tuning for the more exact quantizer.
|
||||
Relax rate control for last few frames
|
||||
CQ Mode
|
||||
Limit key frame quantizer for forced key frames.
|
||||
KF/GF Pulsing
|
||||
Add simple version of activity masking.
|
||||
make rdmult adaptive for intra in quantizer RDO
|
||||
cap the best quantizer for 2nd order DC
|
||||
change the threshold of DC check for encode breakout
|
||||
|
||||
- Bug Fixes:
|
||||
Fix crash on Sparc Solaris.
|
||||
Fix counter of fixed keyframe distance
|
||||
ARNR filter pointer update bug fix
|
||||
Fixed use of motion percentage in KF/GF group calc
|
||||
Changed condition for using RD in Intra Mode
|
||||
Fix encoder real-time only configuration.
|
||||
Fix ARM encoder crash with multiple token partitions
|
||||
Fixed bug first cluster timecode of webm file is wrong.
|
||||
Fixed various encoder bugs with odd-sized images
|
||||
vp8e_get_preview fixed when spatial resampling enabled
|
||||
quantizer: fix assertion in fast quantizer path
|
||||
Allocate source buffers to be multiples of 16
|
||||
Fix for manual Golden frame frequency
|
||||
Fix drastic undershoot in long form content
|
||||
|
||||
|
||||
2010-10-28 v0.9.5 "Aylesbury"
|
||||
Our first named release, focused on a faster decoder, and a better encoder.
|
||||
|
||||
- Upgrading:
|
||||
This release incorporates backwards-incompatible changes to the
|
||||
ivfenc and ivfdec tools. These tools are now called vpxenc and vpxdec.
|
||||
|
||||
vpxdec
|
||||
* the -q (quiet) option has been removed, and replaced with
|
||||
-v (verbose). the output is quiet by default. Use -v to see
|
||||
the version number of the binary.
|
||||
|
||||
* The default behavior is now to write output to a single file
|
||||
instead of individual frames. The -y option has been removed.
|
||||
Y4M output is the default.
|
||||
|
||||
* For raw I420/YV12 output instead of Y4M, the --i420 or --yv12
|
||||
options must be specified.
|
||||
|
||||
$ ivfdec -o OUTPUT INPUT
|
||||
$ vpxdec --i420 -o OUTPUT INPUT
|
||||
|
||||
* If an output file is not specified, the default is to write
|
||||
Y4M to stdout. This makes piping more natural.
|
||||
|
||||
$ ivfdec -y -o - INPUT | ...
|
||||
$ vpxdec INPUT | ...
|
||||
|
||||
* The output file has additional flexibility for formatting the
|
||||
filename. It supports escape characters for constructing a
|
||||
filename from the width, height, and sequence number. This
|
||||
replaces the -p option. To get the equivalent:
|
||||
|
||||
$ ivfdec -p frame INPUT
|
||||
$ vpxdec --i420 -o frame-%wx%h-%4.i420 INPUT
|
||||
|
||||
vpxenc
|
||||
* The output file must be specified with -o, rather than as the
|
||||
last argument.
|
||||
|
||||
$ ivfenc <options> INPUT OUTPUT
|
||||
$ vpxenc <options> -o OUTPUT INPUT
|
||||
|
||||
* The output defaults to webm. To get IVF output, use the --ivf
|
||||
option.
|
||||
|
||||
$ ivfenc <options> INPUT OUTPUT.ivf
|
||||
$ vpxenc <options> -o OUTPUT.ivf --ivf INPUT
|
||||
|
||||
|
||||
- Enhancements:
|
||||
ivfenc and ivfdec have been renamed to vpxenc, vpxdec.
|
||||
vpxdec supports .webm input
|
||||
vpxdec writes .y4m by default
|
||||
vpxenc writes .webm output by default
|
||||
vpxenc --psnr now shows the average/overall PSNR at the end
|
||||
ARM platforms now support runtime cpu detection
|
||||
vpxdec visualizations added for motion vectors, block modes, references
|
||||
vpxdec now silent by default
|
||||
vpxdec --progress shows frame-by-frame timing information
|
||||
vpxenc supports the distinction between --fps and --timebase
|
||||
NASM is now a supported assembler
|
||||
configure: enable PIC for shared libs by default
|
||||
configure: add --enable-small
|
||||
configure: support for ppc32-linux-gcc
|
||||
configure: support for sparc-solaris-gcc
|
||||
|
||||
- Bugs:
|
||||
Improve handling of invalid frames
|
||||
Fix valgrind errors in the NEON loop filters.
|
||||
Fix loopfilter delta zero transitions
|
||||
Fix valgrind errors in vp8_sixtap_predict8x4_armv6().
|
||||
Build fixes for darwin-icc
|
||||
|
||||
- Speed:
|
||||
20-40% (average 28%) improvement in libvpx decoder speed,
|
||||
including:
|
||||
Rewrite vp8_short_walsh4x4_sse2()
|
||||
Optimizations on the loopfilters.
|
||||
Miscellaneous improvements for Atom
|
||||
Add 4-tap version of 2nd-pass ARMv6 MC filter.
|
||||
Improved multithread utilization
|
||||
Better instruction choices on x86
|
||||
reorder data to use wider instructions
|
||||
Update NEON wide idcts
|
||||
Make block access to frame buffer sequential
|
||||
Improved subset block search
|
||||
Bilinear subpixel optimizations for ssse3.
|
||||
Decrease memory footprint
|
||||
|
||||
Encoder speed improvements (percentage gain not measured):
|
||||
Skip unnecessary search of identical frames
|
||||
Add SSE2 subtract functions
|
||||
Improve bounds checking in vp8_diamond_search_sadx4()
|
||||
Added vp8_fast_quantize_b_sse2
|
||||
|
||||
- Quality:
|
||||
Over 7% overall PSNR improvement (6.3% SSIM) in "best" quality
|
||||
encoding mode, and up to 60% improvement on very noisy, still
|
||||
or slow moving source video
|
||||
|
||||
Motion compensated temporal filter for Alt-Ref Noise Reduction
|
||||
Improved use of trellis quantization on 2nd order Y blocks
|
||||
Tune effect of motion on KF/GF boost in two pass
|
||||
Allow coefficient optimization for good quality speed 0.
|
||||
Improved control of active min quantizer for two pass.
|
||||
Enable ARFs for non-lagged compress
|
||||
|
||||
2010-09-02 v0.9.2
|
||||
- Enhancements:
|
||||
Disable frame dropping by default
|
||||
Improved multithreaded performance
|
||||
Improved Force Key Frame Behaviour
|
||||
Increased rate control buffer level precision
|
||||
Fix bug in 1st pass motion compensation
|
||||
ivfenc: correct fixed kf interval, --disable-kf
|
||||
- Speed:
|
||||
Changed above and left context data layout
|
||||
Rework idct calling structure.
|
||||
Removed unnecessary MB_MODE_INFO copies
|
||||
x86: SSSE3 sixtap prediction
|
||||
Reworked IDCT to include reconstruction (add) step
|
||||
Swap alt/gold/new/last frame buffer ptrs instead of copying.
|
||||
Improve SSE2 loopfilter functions
|
||||
Change bitreader to use a larger window.
|
||||
Avoid loopfilter reinitialization when possible
|
||||
- Quality:
|
||||
Normalize quantizer's zero bin and rounding factors
|
||||
Add trellis quantization.
|
||||
Make the quantizer exact.
|
||||
Updates to ARNR filtering algorithm
|
||||
Fix breakout thresh computation for golden & AltRef frames
|
||||
Redo the forward 4x4 dct
|
||||
Improve the accuracy of forward walsh-hadamard transform
|
||||
Further adjustment of RD behaviour with Q and Zbin.
|
||||
- Build System:
|
||||
Allow linking of libs built with MinGW to MSVC
|
||||
Fix target auto-detection on mingw32
|
||||
Allow --cpu= to work for x86.
|
||||
configure: pass original arguments through to make dist
|
||||
Fix builds without runtime CPU detection
|
||||
msvs: fix install of codec sources
|
||||
msvs: Change devenv.com command line for better msys support
|
||||
msvs: Add vs9 targets.
|
||||
Add x86_64-linux-icc target
|
||||
- Bugs:
|
||||
Potential crashes on older MinGW builds
|
||||
Fix two-pass framrate for Y4M input.
|
||||
Fixed simple loop filter, other crashes on ARM v6
|
||||
arm: fix missing dependency with --enable-shared
|
||||
configure: support directories containing .o
|
||||
Replace pinsrw (SSE) with MMX instructions
|
||||
apple: include proper mach primatives
|
||||
Fixed rate control bug with long key frame interval.
|
||||
Fix DSO link errors on x86-64 when not using a version script
|
||||
Fixed buffer selection for UV in AltRef filtering
|
||||
|
||||
|
||||
2010-06-17 v0.9.1
|
||||
- Enhancements:
|
||||
* ivfenc/ivfdec now support YUV4MPEG2 input and pipe I/O
|
||||
* Speed optimizations
|
||||
- Bugfixes:
|
||||
* Rate control
|
||||
* Prevent out-of-bounds accesses on invalid data
|
||||
- Build system updates:
|
||||
* Detect toolchain to be used automatically for native builds
|
||||
* Support building shared libraries
|
||||
* Better autotools emulation (--prefix, --libdir, DESTDIR)
|
||||
- Updated LICENSE
|
||||
* http://webmproject.blogspot.com/2010/06/changes-to-webm-open-source-license.html
|
||||
|
||||
|
||||
2010-05-18 v0.9.0
|
||||
- Initial open source release. Welcome to WebM and VP8!
|
||||
|
31
LICENSE
31
LICENSE
@ -1,31 +0,0 @@
|
||||
Copyright (c) 2010, The WebM Project authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
* Neither the name of Google, nor the WebM Project, nor the names
|
||||
of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
23
PATENTS
23
PATENTS
@ -1,23 +0,0 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
------------------------------------
|
||||
|
||||
"These implementations" means the copyrightable works that implement the WebM
|
||||
codecs distributed by Google as part of the WebM Project.
|
||||
|
||||
Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge,
|
||||
royalty-free, irrevocable (except as stated in this section) patent license to
|
||||
make, have made, use, offer to sell, sell, import, transfer, and otherwise
|
||||
run, modify and propagate the contents of these implementations of WebM, where
|
||||
such license applies only to those patent claims, both currently owned by
|
||||
Google and acquired in the future, licensable by Google that are necessarily
|
||||
infringed by these implementations of WebM. This grant does not include claims
|
||||
that would be infringed only as a consequence of further modification of these
|
||||
implementations. If you or your agent or exclusive licensee institute or order
|
||||
or agree to the institution of patent litigation or any other patent
|
||||
enforcement activity against any entity (including a cross-claim or
|
||||
counterclaim in a lawsuit) alleging that any of these implementations of WebM
|
||||
or any code incorporated within any of these implementations of WebM
|
||||
constitute direct or contributory patent infringement, or inducement of
|
||||
patent infringement, then any patent rights granted to you under this License
|
||||
for these implementations of WebM shall terminate as of the date such
|
||||
litigation is filed.
|
170
README
170
README
@ -1,170 +0,0 @@
|
||||
README - 24 January 2018
|
||||
|
||||
Welcome to the WebM VP8/VP9 Codec SDK!
|
||||
|
||||
COMPILING THE APPLICATIONS/LIBRARIES:
|
||||
The build system used is similar to autotools. Building generally consists of
|
||||
"configuring" with your desired build options, then using GNU make to build
|
||||
the application.
|
||||
|
||||
1. Prerequisites
|
||||
|
||||
* All x86 targets require the Yasm[1] assembler be installed[2].
|
||||
* All Windows builds require that Cygwin[3] be installed.
|
||||
* Building the documentation requires Doxygen[4]. If you do not
|
||||
have this package, the install-docs option will be disabled.
|
||||
* Downloading the data for the unit tests requires curl[5] and sha1sum.
|
||||
sha1sum is provided via the GNU coreutils, installed by default on
|
||||
many *nix platforms, as well as MinGW and Cygwin. If coreutils is not
|
||||
available, a compatible version of sha1sum can be built from
|
||||
source[6]. These requirements are optional if not running the unit
|
||||
tests.
|
||||
|
||||
[1]: http://www.tortall.net/projects/yasm
|
||||
[2]: For Visual Studio the base yasm binary (not vsyasm) should be in the
|
||||
PATH for Visual Studio. For VS2017 it is sufficient to rename
|
||||
yasm-<version>-<arch>.exe to yasm.exe and place it in:
|
||||
Program Files (x86)/Microsoft Visual Studio/2017/<level>/Common7/Tools/
|
||||
[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
|
||||
Out of tree builds are a supported method of building the application. For
|
||||
an out of tree build, the source tree is kept separate from the object
|
||||
files produced during compilation. For instance:
|
||||
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ ../libvpx/configure <options>
|
||||
$ make
|
||||
|
||||
3. Configuration options
|
||||
The 'configure' script supports a number of options. The --help option can be
|
||||
used to get a list of supported options:
|
||||
$ ../libvpx/configure --help
|
||||
|
||||
4. Compiler analyzers
|
||||
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
|
||||
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
|
||||
available targets is:
|
||||
|
||||
arm64-android-gcc
|
||||
arm64-darwin-gcc
|
||||
arm64-linux-gcc
|
||||
armv7-android-gcc
|
||||
armv7-darwin-gcc
|
||||
armv7-linux-rvct
|
||||
armv7-linux-gcc
|
||||
armv7-none-rvct
|
||||
armv7-win32-vs11
|
||||
armv7-win32-vs12
|
||||
armv7-win32-vs14
|
||||
armv7-win32-vs15
|
||||
armv7s-darwin-gcc
|
||||
armv8-linux-gcc
|
||||
mips32-linux-gcc
|
||||
mips64-linux-gcc
|
||||
ppc64-linux-gcc
|
||||
ppc64le-linux-gcc
|
||||
sparc-solaris-gcc
|
||||
x86-android-gcc
|
||||
x86-darwin8-gcc
|
||||
x86-darwin8-icc
|
||||
x86-darwin9-gcc
|
||||
x86-darwin9-icc
|
||||
x86-darwin10-gcc
|
||||
x86-darwin11-gcc
|
||||
x86-darwin12-gcc
|
||||
x86-darwin13-gcc
|
||||
x86-darwin14-gcc
|
||||
x86-darwin15-gcc
|
||||
x86-darwin16-gcc
|
||||
x86-iphonesimulator-gcc
|
||||
x86-linux-gcc
|
||||
x86-linux-icc
|
||||
x86-os2-gcc
|
||||
x86-solaris-gcc
|
||||
x86-win32-gcc
|
||||
x86-win32-vs10
|
||||
x86-win32-vs11
|
||||
x86-win32-vs12
|
||||
x86-win32-vs14
|
||||
x86-win32-vs15
|
||||
x86_64-android-gcc
|
||||
x86_64-darwin9-gcc
|
||||
x86_64-darwin10-gcc
|
||||
x86_64-darwin11-gcc
|
||||
x86_64-darwin12-gcc
|
||||
x86_64-darwin13-gcc
|
||||
x86_64-darwin14-gcc
|
||||
x86_64-darwin15-gcc
|
||||
x86_64-darwin16-gcc
|
||||
x86_64-iphonesimulator-gcc
|
||||
x86_64-linux-gcc
|
||||
x86_64-linux-icc
|
||||
x86_64-solaris-gcc
|
||||
x86_64-win64-gcc
|
||||
x86_64-win64-vs10
|
||||
x86_64-win64-vs11
|
||||
x86_64-win64-vs12
|
||||
x86_64-win64-vs14
|
||||
x86_64-win64-vs15
|
||||
generic-gnu
|
||||
|
||||
The generic-gnu target, in conjunction with the CROSS environment variable,
|
||||
can be used to cross compile architectures that aren't explicitly listed, if
|
||||
the toolchain is a cross GNU (gcc/binutils) toolchain. Other POSIX toolchains
|
||||
will likely work as well. For instance, to build using the mipsel-linux-uclibc
|
||||
toolchain, the following command could be used (note, POSIX SH syntax, adapt
|
||||
to your shell as necessary):
|
||||
|
||||
$ CROSS=mipsel-linux-uclibc- ../libvpx/configure
|
||||
|
||||
In addition, the executables to be invoked can be overridden by specifying the
|
||||
environment variables: CC, AR, LD, AS, STRIP, NM. Additional flags can be
|
||||
passed to these executables with CFLAGS, LDFLAGS, and ASFLAGS.
|
||||
|
||||
6. Configuration errors
|
||||
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
|
||||
wrong. If not, contact us for support.
|
||||
|
||||
VP8/VP9 TEST VECTORS:
|
||||
The test vectors can be downloaded and verified using the build system after
|
||||
running configure. To specify an alternate directory the
|
||||
LIBVPX_TEST_DATA_PATH environment variable can be used.
|
||||
|
||||
$ ./configure --enable-unit-tests
|
||||
$ 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
|
||||
This library is an open source project supported by its community. Please
|
||||
email webm-discuss@webmproject.org for help.
|
||||
|
215
args.c
215
args.c
@ -1,215 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "args.h"
|
||||
|
||||
#include "vpx/vpx_integer.h"
|
||||
#include "vpx_ports/msvc.h"
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__
|
||||
extern void die(const char *fmt, ...) __attribute__((noreturn));
|
||||
#else
|
||||
extern void die(const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
struct arg arg_init(char **argv) {
|
||||
struct arg a;
|
||||
|
||||
a.argv = argv;
|
||||
a.argv_step = 1;
|
||||
a.name = NULL;
|
||||
a.val = NULL;
|
||||
a.def = NULL;
|
||||
return a;
|
||||
}
|
||||
|
||||
int arg_match(struct arg *arg_, const struct arg_def *def, char **argv) {
|
||||
struct arg arg;
|
||||
|
||||
if (!argv[0] || argv[0][0] != '-') return 0;
|
||||
|
||||
arg = arg_init(argv);
|
||||
|
||||
if (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.val = def->has_val ? arg.argv[1] : NULL;
|
||||
arg.argv_step = def->has_val ? 2 : 1;
|
||||
} else if (def->long_name) {
|
||||
const size_t name_len = strlen(def->long_name);
|
||||
|
||||
if (strlen(arg.argv[0]) >= name_len + 2 && arg.argv[0][1] == '-' &&
|
||||
!strncmp(arg.argv[0] + 2, def->long_name, name_len) &&
|
||||
(arg.argv[0][name_len + 2] == '=' ||
|
||||
arg.argv[0][name_len + 2] == '\0')) {
|
||||
arg.name = arg.argv[0] + 2;
|
||||
arg.val = arg.name[name_len] == '=' ? arg.name + name_len + 1 : NULL;
|
||||
arg.argv_step = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.name && !arg.val && def->has_val)
|
||||
die("Error: option %s requires argument.\n", arg.name);
|
||||
|
||||
if (arg.name && arg.val && !def->has_val)
|
||||
die("Error: option %s requires no argument.\n", arg.name);
|
||||
|
||||
if (arg.name && (arg.val || !def->has_val)) {
|
||||
arg.def = def;
|
||||
*arg_ = arg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *arg_next(struct arg *arg) {
|
||||
if (arg->argv[0]) arg->argv += arg->argv_step;
|
||||
|
||||
return *arg->argv;
|
||||
}
|
||||
|
||||
char **argv_dup(int argc, const char **argv) {
|
||||
char **new_argv = malloc((argc + 1) * sizeof(*argv));
|
||||
|
||||
memcpy(new_argv, argv, argc * sizeof(*argv));
|
||||
new_argv[argc] = NULL;
|
||||
return new_argv;
|
||||
}
|
||||
|
||||
void arg_show_usage(FILE *fp, const struct arg_def *const *defs) {
|
||||
char option_text[40] = { 0 };
|
||||
|
||||
for (; *defs; defs++) {
|
||||
const struct arg_def *def = *defs;
|
||||
char *short_val = def->has_val ? " <arg>" : "";
|
||||
char *long_val = def->has_val ? "=<arg>" : "";
|
||||
|
||||
if (def->short_name && def->long_name) {
|
||||
char *comma = def->has_val ? "," : ", ";
|
||||
|
||||
snprintf(option_text, 37, "-%s%s%s --%s%6s", def->short_name, short_val,
|
||||
comma, def->long_name, long_val);
|
||||
} else if (def->short_name)
|
||||
snprintf(option_text, 37, "-%s%s", def->short_name, short_val);
|
||||
else if (def->long_name)
|
||||
snprintf(option_text, 37, " --%s%s", def->long_name, long_val);
|
||||
|
||||
fprintf(fp, " %-37s\t%s\n", option_text, def->desc);
|
||||
|
||||
if (def->enums) {
|
||||
const struct arg_enum_list *listptr;
|
||||
|
||||
fprintf(fp, " %-37s\t ", "");
|
||||
|
||||
for (listptr = def->enums; listptr->name; listptr++)
|
||||
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);
|
||||
|
||||
if (arg->val[0] != '\0' && endptr[0] == '\0') {
|
||||
if (rawval <= UINT_MAX) return rawval;
|
||||
|
||||
die("Option %s: Value %ld out of range for unsigned int\n", arg->name,
|
||||
rawval);
|
||||
}
|
||||
|
||||
die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arg_parse_int(const struct arg *arg) {
|
||||
int32_t rawval;
|
||||
char *endptr;
|
||||
|
||||
rawval = (int32_t)strtol(arg->val, &endptr, 10);
|
||||
|
||||
if (arg->val[0] != '\0' && endptr[0] == '\0') {
|
||||
if (rawval >= INT_MIN && rawval <= INT_MAX) return (int)rawval;
|
||||
|
||||
die("Option %s: Value %ld out of range for signed int\n", arg->name,
|
||||
rawval);
|
||||
}
|
||||
|
||||
die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct vpx_rational {
|
||||
int num; /**< fraction numerator */
|
||||
int den; /**< fraction denominator */
|
||||
};
|
||||
struct vpx_rational arg_parse_rational(const struct arg *arg) {
|
||||
long int rawval;
|
||||
char *endptr;
|
||||
struct vpx_rational rat;
|
||||
|
||||
/* parse numerator */
|
||||
rawval = strtol(arg->val, &endptr, 10);
|
||||
|
||||
if (arg->val[0] != '\0' && endptr[0] == '/') {
|
||||
if (rawval >= INT_MIN && rawval <= INT_MAX)
|
||||
rat.num = (int)rawval;
|
||||
else
|
||||
die("Option %s: Value %ld out of range for signed int\n", arg->name,
|
||||
rawval);
|
||||
} else
|
||||
die("Option %s: Expected / at '%c'\n", arg->name, *endptr);
|
||||
|
||||
/* parse denominator */
|
||||
rawval = strtol(endptr + 1, &endptr, 10);
|
||||
|
||||
if (arg->val[0] != '\0' && endptr[0] == '\0') {
|
||||
if (rawval >= INT_MIN && rawval <= INT_MAX)
|
||||
rat.den = (int)rawval;
|
||||
else
|
||||
die("Option %s: Value %ld out of range for signed int\n", arg->name,
|
||||
rawval);
|
||||
} else
|
||||
die("Option %s: Invalid character '%c'\n", arg->name, *endptr);
|
||||
|
||||
return rat;
|
||||
}
|
||||
|
||||
int arg_parse_enum(const struct arg *arg) {
|
||||
const struct arg_enum_list *listptr;
|
||||
long int rawval;
|
||||
char *endptr;
|
||||
|
||||
/* First see if the value can be parsed as a raw value */
|
||||
rawval = strtol(arg->val, &endptr, 10);
|
||||
if (arg->val[0] != '\0' && endptr[0] == '\0') {
|
||||
/* Got a raw value, make sure it's valid */
|
||||
for (listptr = arg->def->enums; listptr->name; listptr++)
|
||||
if (listptr->val == rawval) return (int)rawval;
|
||||
}
|
||||
|
||||
/* Next see if it can be parsed as a string */
|
||||
for (listptr = arg->def->enums; listptr->name; listptr++)
|
||||
if (!strcmp(arg->val, listptr->name)) return listptr->val;
|
||||
|
||||
die("Option %s: Invalid value '%s'\n", arg->name, arg->val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arg_parse_enum_or_int(const struct arg *arg) {
|
||||
if (arg->def->enums) return arg_parse_enum(arg);
|
||||
return arg_parse_int(arg);
|
||||
}
|
63
args.h
63
args.h
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef ARGS_H_
|
||||
#define ARGS_H_
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct arg {
|
||||
char **argv;
|
||||
const char *name;
|
||||
const char *val;
|
||||
unsigned int argv_step;
|
||||
const struct arg_def *def;
|
||||
};
|
||||
|
||||
struct arg_enum_list {
|
||||
const char *name;
|
||||
int val;
|
||||
};
|
||||
#define ARG_ENUM_LIST_END \
|
||||
{ 0 }
|
||||
|
||||
typedef struct arg_def {
|
||||
const char *short_name;
|
||||
const char *long_name;
|
||||
int has_val;
|
||||
const char *desc;
|
||||
const struct arg_enum_list *enums;
|
||||
} arg_def_t;
|
||||
#define ARG_DEF(s, l, v, d) \
|
||||
{ s, l, v, d, NULL }
|
||||
#define ARG_DEF_ENUM(s, l, v, d, e) \
|
||||
{ s, l, v, d, e }
|
||||
#define ARG_DEF_LIST_END \
|
||||
{ 0 }
|
||||
|
||||
struct arg arg_init(char **argv);
|
||||
int arg_match(struct arg *arg_, const struct arg_def *def, char **argv);
|
||||
const char *arg_next(struct arg *arg);
|
||||
void arg_show_usage(FILE *fp, const struct arg_def *const *defs);
|
||||
char **argv_dup(int argc, const char **argv);
|
||||
|
||||
unsigned int arg_parse_uint(const struct arg *arg);
|
||||
int arg_parse_int(const struct arg *arg);
|
||||
struct vpx_rational arg_parse_rational(const struct arg *arg);
|
||||
int arg_parse_enum(const struct arg *arg);
|
||||
int arg_parse_enum_or_int(const struct arg *arg);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // ARGS_H_
|
@ -1,228 +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.
|
||||
##
|
||||
|
||||
#
|
||||
# This file is to be used for compiling libvpx for Android using the NDK.
|
||||
# In an Android project place a libvpx checkout in the jni directory.
|
||||
# Run the configure script from the jni directory. Base libvpx
|
||||
# encoder/decoder configuration will look similar to:
|
||||
# ./libvpx/configure --target=armv7-android-gcc --disable-examples \
|
||||
# --sdk-path=/opt/android-ndk-r6b/
|
||||
#
|
||||
# When targeting Android, realtime-only is enabled by default. This can
|
||||
# be overridden by adding the command line flag:
|
||||
# --disable-realtime-only
|
||||
#
|
||||
# This will create .mk files that contain variables that contain the
|
||||
# source files to compile.
|
||||
#
|
||||
# Place an Android.mk file in the jni directory that references the
|
||||
# Android.mk file in the libvpx directory:
|
||||
# LOCAL_PATH := $(call my-dir)
|
||||
# include $(CLEAR_VARS)
|
||||
# include jni/libvpx/build/make/Android.mk
|
||||
#
|
||||
# By default libvpx will detect at runtime the existance of NEON extension.
|
||||
# For this we import the 'cpufeatures' module from the NDK sources.
|
||||
# libvpx can also be configured without this runtime detection method.
|
||||
# Configuring with --disable-runtime-cpu-detect will assume presence of NEON.
|
||||
# Configuring with --disable-runtime-cpu-detect --disable-neon \
|
||||
# --disable-neon-asm
|
||||
# will remove any NEON dependency.
|
||||
|
||||
#
|
||||
# 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)/
|
||||
LIBVPX_PATH := $(LOCAL_PATH)/libvpx
|
||||
ASM_CNV_PATH_LOCAL := $(TARGET_ARCH_ABI)/ads2gas
|
||||
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
|
||||
# build. Also set any architecture-specific flags.
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
include $(CONFIG_DIR)libs-armv7-android-gcc.mk
|
||||
LOCAL_ARM_MODE := arm
|
||||
else ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
||||
include $(CONFIG_DIR)libs-arm64-android-gcc.mk
|
||||
LOCAL_ARM_MODE := arm
|
||||
else ifeq ($(TARGET_ARCH_ABI),x86)
|
||||
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)
|
||||
include $(CONFIG_DIR)libs-mips-android-gcc.mk
|
||||
else
|
||||
$(error Not a supported TARGET_ARCH_ABI: $(TARGET_ARCH_ABI))
|
||||
endif
|
||||
|
||||
# Rule that is normally in Makefile created by libvpx
|
||||
# configure. Used to filter out source files based on configuration.
|
||||
enabled=$(filter-out $($(1)-no),$($(1)-yes))
|
||||
|
||||
# Override the relative path that is defined by the libvpx
|
||||
# configure process
|
||||
SRC_PATH_BARE := $(LIBVPX_PATH)
|
||||
|
||||
# Include the list of files to be built
|
||||
include $(LIBVPX_PATH)/libs.mk
|
||||
|
||||
# Optimise the code. May want to revisit this setting in the future.
|
||||
LOCAL_CFLAGS := -O3
|
||||
|
||||
# For x86, include the source code in the search path so it will find files
|
||||
# like x86inc.asm and x86_abi_support.asm
|
||||
LOCAL_ASMFLAGS := -I$(LIBVPX_PATH)
|
||||
|
||||
.PRECIOUS: %.asm.S
|
||||
$(ASM_CNV_PATH)/libvpx/%.asm.S: $(LIBVPX_PATH)/%.asm
|
||||
$(qexec)mkdir -p $(dir $@)
|
||||
$(qexec)$(CONFIG_DIR)$(ASM_CONVERSION) <$< > $@
|
||||
|
||||
# For building *_rtcd.h, which have rules in libs.mk
|
||||
TGT_ISA:=$(word 1, $(subst -, ,$(TOOLCHAIN)))
|
||||
target := libs
|
||||
|
||||
LOCAL_SRC_FILES += vpx_config.c
|
||||
|
||||
# Remove duplicate entries
|
||||
CODEC_SRCS_UNIQUE = $(sort $(CODEC_SRCS))
|
||||
|
||||
# Pull out C files. vpx_config.c is in the immediate directory and
|
||||
# so it does not need libvpx/ prefixed like the rest of the source files.
|
||||
# The neon files with intrinsics need to have .neon appended so the proper
|
||||
# flags are applied.
|
||||
CODEC_SRCS_C = $(filter %.c, $(CODEC_SRCS_UNIQUE))
|
||||
LOCAL_NEON_SRCS_C = $(filter %_neon.c, $(CODEC_SRCS_C))
|
||||
LOCAL_CODEC_SRCS_C = $(filter-out vpx_config.c %_neon.c, $(CODEC_SRCS_C))
|
||||
|
||||
LOCAL_SRC_FILES += $(foreach file, $(LOCAL_CODEC_SRCS_C), libvpx/$(file))
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
LOCAL_SRC_FILES += $(foreach file, $(LOCAL_NEON_SRCS_C), libvpx/$(file).neon)
|
||||
else # If there are neon sources then we are building for arm64 and do not need to specify .neon
|
||||
LOCAL_SRC_FILES += $(foreach file, $(LOCAL_NEON_SRCS_C), libvpx/$(file))
|
||||
endif
|
||||
|
||||
# Pull out assembly files, splitting NEON from the rest. This is
|
||||
# done to specify that the NEON assembly files use NEON assembler flags.
|
||||
# x86 assembly matches %.asm, arm matches %.asm.S
|
||||
|
||||
# x86:
|
||||
|
||||
CODEC_SRCS_ASM_X86 = $(filter %.asm, $(CODEC_SRCS_UNIQUE))
|
||||
LOCAL_SRC_FILES += $(foreach file, $(CODEC_SRCS_ASM_X86), libvpx/$(file))
|
||||
|
||||
# arm:
|
||||
CODEC_SRCS_ASM_ARM_ALL = $(filter %.asm.S, $(CODEC_SRCS_UNIQUE))
|
||||
CODEC_SRCS_ASM_ARM = $(foreach v, \
|
||||
$(CODEC_SRCS_ASM_ARM_ALL), \
|
||||
$(if $(findstring neon,$(v)),,$(v)))
|
||||
CODEC_SRCS_ASM_ADS2GAS = $(patsubst %.S, \
|
||||
$(ASM_CNV_PATH_LOCAL)/libvpx/%.S, \
|
||||
$(CODEC_SRCS_ASM_ARM))
|
||||
LOCAL_SRC_FILES += $(CODEC_SRCS_ASM_ADS2GAS)
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
ASM_INCLUDES := vpx_dsp/arm/idct_neon.asm.S
|
||||
CODEC_SRCS_ASM_NEON = $(foreach v, \
|
||||
$(CODEC_SRCS_ASM_ARM_ALL),\
|
||||
$(if $(findstring neon,$(v)),$(v),))
|
||||
CODEC_SRCS_ASM_NEON := $(filter-out $(addprefix %, $(ASM_INCLUDES)), \
|
||||
$(CODEC_SRCS_ASM_NEON))
|
||||
CODEC_SRCS_ASM_NEON_ADS2GAS = $(patsubst %.S, \
|
||||
$(ASM_CNV_PATH_LOCAL)/libvpx/%.S, \
|
||||
$(CODEC_SRCS_ASM_NEON))
|
||||
LOCAL_SRC_FILES += $(patsubst %.S, \
|
||||
%.S.neon, \
|
||||
$(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
|
||||
|
||||
LOCAL_CFLAGS += \
|
||||
-DHAVE_CONFIG_H=vpx_config.h \
|
||||
-I$(LIBVPX_PATH) \
|
||||
-I$(ASM_CNV_PATH) \
|
||||
-I$(ASM_CNV_PATH)/libvpx
|
||||
|
||||
LOCAL_MODULE := libvpx
|
||||
|
||||
ifeq ($(CONFIG_RUNTIME_CPU_DETECT),yes)
|
||||
LOCAL_STATIC_LIBRARIES := cpufeatures
|
||||
endif
|
||||
|
||||
# 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)
|
||||
$$(rtcd_dep_template_SRCS): vp8_rtcd.h
|
||||
endif
|
||||
ifeq ($(CONFIG_VP9), yes)
|
||||
$$(rtcd_dep_template_SRCS): vp9_rtcd.h
|
||||
endif
|
||||
$$(rtcd_dep_template_SRCS): vpx_scale_rtcd.h
|
||||
$$(rtcd_dep_template_SRCS): vpx_dsp_rtcd.h
|
||||
|
||||
rtcd_dep_template_CONFIG_ASM_ABIS := x86 x86_64 armeabi-v7a
|
||||
ifneq ($$(findstring $(TARGET_ARCH_ABI),$$(rtcd_dep_template_CONFIG_ASM_ABIS)),)
|
||||
$$(rtcd_dep_template_SRCS): vpx_config.asm
|
||||
endif
|
||||
endef
|
||||
|
||||
$(eval $(call rtcd_dep_template))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Clean: ads2gas files [$(TARGET_ARCH_ABI)]"
|
||||
$(qexec)$(RM) $(CODEC_SRCS_ASM_ADS2GAS) $(CODEC_SRCS_ASM_NEON_ADS2GAS)
|
||||
$(qexec)$(RM) -r $(ASM_CNV_PATH)
|
||||
$(qexec)$(RM) $(CLEAN-OBJS)
|
||||
|
||||
ifeq ($(ENABLE_SHARED),1)
|
||||
LOCAL_CFLAGS += -fPIC
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
else
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RUNTIME_CPU_DETECT),yes)
|
||||
$(call import-module,android/cpufeatures)
|
||||
endif
|
@ -1,459 +0,0 @@
|
||||
##
|
||||
## Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
##
|
||||
## Use of this source code is governed by a BSD-style license
|
||||
## that can be found in the LICENSE file in the root of the source
|
||||
## tree. An additional intellectual property rights grant can be found
|
||||
## in the file PATENTS. All contributing project authors may
|
||||
## be found in the AUTHORS file in the root of the source tree.
|
||||
##
|
||||
|
||||
|
||||
include config.mk
|
||||
quiet?=true
|
||||
ifeq ($(target),)
|
||||
# If a target wasn't specified, invoke for all enabled targets.
|
||||
.DEFAULT:
|
||||
@for t in $(ALL_TARGETS); do \
|
||||
$(MAKE) --no-print-directory target=$$t $(MAKECMDGOALS) || exit $$?;\
|
||||
done
|
||||
all: .DEFAULT
|
||||
clean:: .DEFAULT
|
||||
exampletest: .DEFAULT
|
||||
install:: .DEFAULT
|
||||
test:: .DEFAULT
|
||||
test-no-data-check:: .DEFAULT
|
||||
testdata:: .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
|
||||
# installed on cygwin, so we need to autodetect here.
|
||||
md5sum := $(firstword $(wildcard \
|
||||
$(foreach e,md5sum openssl,\
|
||||
$(foreach p,$(subst :, ,$(PATH)),$(p)/$(e)*))\
|
||||
))
|
||||
md5sum := $(if $(filter %openssl,$(md5sum)),$(md5sum) dgst -md5,$(md5sum))
|
||||
|
||||
TGT_CC:=$(word 3, $(subst -, ,$(TOOLCHAIN)))
|
||||
dist:
|
||||
@for t in $(ALL_TARGETS); do \
|
||||
$(MAKE) --no-print-directory target=$$t $(MAKECMDGOALS) || exit $$?;\
|
||||
done
|
||||
# Run configure for the user with the current toolchain.
|
||||
@if [ -d "$(DIST_DIR)/src" ]; then \
|
||||
mkdir -p "$(DIST_DIR)/build"; \
|
||||
cd "$(DIST_DIR)/build"; \
|
||||
echo "Rerunning configure $(CONFIGURE_ARGS)"; \
|
||||
../src/configure $(CONFIGURE_ARGS); \
|
||||
$(if $(filter vs%,$(TGT_CC)),make NO_LAUNCH_DEVENV=1;) \
|
||||
fi
|
||||
@if [ -d "$(DIST_DIR)" ]; then \
|
||||
echo " [MD5SUM] $(DIST_DIR)"; \
|
||||
cd $(DIST_DIR) && \
|
||||
$(md5sum) `find . -name md5sums.txt -prune -o -type f -print` \
|
||||
| sed -e 's/MD5(\(.*\))= \([0-9a-f]\{32\}\)/\2 \1/' \
|
||||
> md5sums.txt;\
|
||||
fi
|
||||
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),)
|
||||
include $(target)-$(TOOLCHAIN).mk
|
||||
endif
|
||||
BUILD_ROOT?=.
|
||||
VPATH=$(SRC_PATH_BARE)
|
||||
CFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT) -I$(SRC_PATH)
|
||||
CXXFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT) -I$(SRC_PATH)
|
||||
ASFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT)/ -I$(SRC_PATH)/
|
||||
DIST_DIR?=dist
|
||||
HOSTCC?=gcc
|
||||
TGT_ISA:=$(word 1, $(subst -, ,$(TOOLCHAIN)))
|
||||
TGT_OS:=$(word 2, $(subst -, ,$(TOOLCHAIN)))
|
||||
TGT_CC:=$(word 3, $(subst -, ,$(TOOLCHAIN)))
|
||||
quiet:=$(if $(or $(verbose), $(V)),, yes)
|
||||
qexec=$(if $(quiet),@)
|
||||
|
||||
# Cancel built-in implicit rules
|
||||
%: %.o
|
||||
%.asm:
|
||||
%.a:
|
||||
%: %.cc
|
||||
|
||||
#
|
||||
# Common rules"
|
||||
#
|
||||
.PHONY: all
|
||||
all:
|
||||
|
||||
.PHONY: clean
|
||||
clean::
|
||||
rm -f $(OBJS-yes) $(OBJS-yes:.o=.d) $(OBJS-yes:.asm.S.o=.asm.S)
|
||||
rm -f $(CLEAN-OBJS)
|
||||
|
||||
.PHONY: clean
|
||||
distclean: clean
|
||||
if [ -z "$(target)" ]; then \
|
||||
rm -f Makefile; \
|
||||
rm -f config.log config.mk; \
|
||||
rm -f vpx_config.[hc] vpx_config.asm; \
|
||||
else \
|
||||
rm -f $(target)-$(TOOLCHAIN).mk; \
|
||||
fi
|
||||
|
||||
.PHONY: dist
|
||||
dist:
|
||||
.PHONY: exampletest
|
||||
exampletest:
|
||||
.PHONY: install
|
||||
install::
|
||||
.PHONY: test
|
||||
test::
|
||||
.PHONY: testdata
|
||||
testdata::
|
||||
.PHONY: utiltest
|
||||
utiltest:
|
||||
.PHONY: test-no-data-check exampletest-no-data-check utiltest-no-data-check
|
||||
test-no-data-check::
|
||||
exampletest-no-data-check utiltest-no-data-check:
|
||||
|
||||
# Force to realign stack always on OS/2
|
||||
ifeq ($(TOOLCHAIN), x86-os2-gcc)
|
||||
CFLAGS += -mstackrealign
|
||||
endif
|
||||
|
||||
# x86[_64]
|
||||
$(BUILD_PFX)%_mmx.c.d: CFLAGS += -mmmx
|
||||
$(BUILD_PFX)%_mmx.c.o: CFLAGS += -mmmx
|
||||
$(BUILD_PFX)%_sse2.c.d: CFLAGS += -msse2
|
||||
$(BUILD_PFX)%_sse2.c.o: CFLAGS += -msse2
|
||||
$(BUILD_PFX)%_sse3.c.d: CFLAGS += -msse3
|
||||
$(BUILD_PFX)%_sse3.c.o: CFLAGS += -msse3
|
||||
$(BUILD_PFX)%_ssse3.c.d: CFLAGS += -mssse3
|
||||
$(BUILD_PFX)%_ssse3.c.o: CFLAGS += -mssse3
|
||||
$(BUILD_PFX)%_sse4.c.d: CFLAGS += -msse4.1
|
||||
$(BUILD_PFX)%_sse4.c.o: CFLAGS += -msse4.1
|
||||
$(BUILD_PFX)%_avx.c.d: CFLAGS += -mavx
|
||||
$(BUILD_PFX)%_avx.c.o: CFLAGS += -mavx
|
||||
$(BUILD_PFX)%_avx2.c.d: CFLAGS += -mavx2
|
||||
$(BUILD_PFX)%_avx2.c.o: CFLAGS += -mavx2
|
||||
$(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
|
||||
$(if $(quiet),@echo " [DEP] $@")
|
||||
$(qexec)mkdir -p $(dir $@)
|
||||
$(qexec)$(CC) $(INTERNAL_CFLAGS) $(CFLAGS) -M $< | $(fmt_deps) > $@
|
||||
|
||||
$(BUILD_PFX)%.c.o: %.c
|
||||
$(if $(quiet),@echo " [CC] $@")
|
||||
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
|
||||
$(qexec)$(CC) $(INTERNAL_CFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(BUILD_PFX)%.cc.d: %.cc
|
||||
$(if $(quiet),@echo " [DEP] $@")
|
||||
$(qexec)mkdir -p $(dir $@)
|
||||
$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -M $< | $(fmt_deps) > $@
|
||||
|
||||
$(BUILD_PFX)%.cc.o: %.cc
|
||||
$(if $(quiet),@echo " [CXX] $@")
|
||||
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
|
||||
$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
$(BUILD_PFX)%.cpp.d: %.cpp
|
||||
$(if $(quiet),@echo " [DEP] $@")
|
||||
$(qexec)mkdir -p $(dir $@)
|
||||
$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -M $< | $(fmt_deps) > $@
|
||||
|
||||
$(BUILD_PFX)%.cpp.o: %.cpp
|
||||
$(if $(quiet),@echo " [CXX] $@")
|
||||
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
|
||||
$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
$(BUILD_PFX)%.asm.d: %.asm
|
||||
$(if $(quiet),@echo " [DEP] $@")
|
||||
$(qexec)mkdir -p $(dir $@)
|
||||
$(qexec)$(SRC_PATH_BARE)/build/make/gen_asm_deps.sh \
|
||||
--build-pfx=$(BUILD_PFX) --depfile=$@ $(ASFLAGS) $< > $@
|
||||
|
||||
$(BUILD_PFX)%.asm.o: %.asm
|
||||
$(if $(quiet),@echo " [AS] $@")
|
||||
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
|
||||
$(qexec)$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_PFX)%.S.d: %.S
|
||||
$(if $(quiet),@echo " [DEP] $@")
|
||||
$(qexec)mkdir -p $(dir $@)
|
||||
$(qexec)$(SRC_PATH_BARE)/build/make/gen_asm_deps.sh \
|
||||
--build-pfx=$(BUILD_PFX) --depfile=$@ $(ASFLAGS) $< > $@
|
||||
|
||||
$(BUILD_PFX)%.S.o: %.S
|
||||
$(if $(quiet),@echo " [AS] $@")
|
||||
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
|
||||
$(qexec)$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
||||
.PRECIOUS: %.c.S
|
||||
%.c.S: CFLAGS += -DINLINE_ASM
|
||||
$(BUILD_PFX)%.c.S: %.c
|
||||
$(if $(quiet),@echo " [GEN] $@")
|
||||
$(qexec)$(if $(CONFIG_DEPENDENCY_TRACKING),,mkdir -p $(dir $@))
|
||||
$(qexec)$(CC) -S $(CFLAGS) -o $@ $<
|
||||
|
||||
.PRECIOUS: %.asm.S
|
||||
$(BUILD_PFX)%.asm.S: %.asm
|
||||
$(if $(quiet),@echo " [ASM CONVERSION] $@")
|
||||
$(qexec)mkdir -p $(dir $@)
|
||||
$(qexec)$(ASM_CONVERSION) <$< >$@
|
||||
|
||||
# If we're in debug mode, pretend we don't have GNU strip, to fall back to
|
||||
# the copy implementation
|
||||
HAVE_GNU_STRIP := $(if $(CONFIG_DEBUG),,$(HAVE_GNU_STRIP))
|
||||
ifeq ($(HAVE_GNU_STRIP),yes)
|
||||
# Older binutils strip global symbols not needed for relocation processing
|
||||
# when given --strip-unneeded. Using nm and awk to identify globals and
|
||||
# keep them caused command line length issues under mingw and segfaults in
|
||||
# test_libvpx were observed under OS/2: simply use --strip-debug.
|
||||
%.a: %_g.a
|
||||
$(if $(quiet),@echo " [STRIP] $@ < $<")
|
||||
$(qexec)$(STRIP) --strip-debug \
|
||||
-o $@ $<
|
||||
else
|
||||
%.a: %_g.a
|
||||
$(if $(quiet),@echo " [CP] $@ < $<")
|
||||
$(qexec)cp $< $@
|
||||
endif
|
||||
|
||||
#
|
||||
# Utility functions
|
||||
#
|
||||
pairmap=$(if $(strip $(2)),\
|
||||
$(call $(1),$(word 1,$(2)),$(word 2,$(2)))\
|
||||
$(call pairmap,$(1),$(wordlist 3,$(words $(2)),$(2)))\
|
||||
)
|
||||
|
||||
enabled=$(filter-out $($(1)-no),$($(1)-yes))
|
||||
cond_enabled=$(if $(filter yes,$($(1))), $(call enabled,$(2)))
|
||||
|
||||
find_file1=$(word 1,$(wildcard $(subst //,/,$(addsuffix /$(1),$(2)))))
|
||||
find_file=$(foreach f,$(1),$(call find_file1,$(strip $(f)),$(strip $(2))) )
|
||||
obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o .cpp=.cpp.o
|
||||
objs=$(addprefix $(BUILD_PFX),$(foreach p,$(obj_pats),$(filter %.o,$(1:$(p))) ))
|
||||
|
||||
install_map_templates=$(eval $(call install_map_template,$(1),$(2)))
|
||||
|
||||
not=$(subst yes,no,$(1))
|
||||
|
||||
ifeq ($(CONFIG_MSVS),yes)
|
||||
lib_file_name=$(1).lib
|
||||
else
|
||||
lib_file_name=lib$(1).a
|
||||
endif
|
||||
#
|
||||
# Rule Templates
|
||||
#
|
||||
define linker_template
|
||||
$(1): $(filter-out -%,$(2))
|
||||
$(1):
|
||||
$(if $(quiet),@echo " [LD] $$@")
|
||||
$(qexec)$$(LD) $$(strip $$(INTERNAL_LDFLAGS) $$(LDFLAGS) -o $$@ $(2) $(3) $$(extralibs))
|
||||
endef
|
||||
define linkerxx_template
|
||||
$(1): $(filter-out -%,$(2))
|
||||
$(1):
|
||||
$(if $(quiet),@echo " [LD] $$@")
|
||||
$(qexec)$$(CXX) $$(strip $$(INTERNAL_LDFLAGS) $$(LDFLAGS) -o $$@ $(2) $(3) $$(extralibs))
|
||||
endef
|
||||
# make-3.80 has a bug with expanding large input strings to the eval function,
|
||||
# which was triggered in some cases by the following component of
|
||||
# linker_template:
|
||||
# $(1): $$(call find_file, $(patsubst -l%,lib%.a,$(filter -l%,$(2))),\
|
||||
# $$(patsubst -L%,%,$$(filter -L%,$$(LDFLAGS) $(2))))
|
||||
# This may be useful to revisit in the future (it tries to locate libraries
|
||||
# in a search path and add them as prerequisites
|
||||
|
||||
define install_map_template
|
||||
$(DIST_DIR)/$(1): $(2)
|
||||
$(if $(quiet),@echo " [INSTALL] $$@")
|
||||
$(qexec)mkdir -p $$(dir $$@)
|
||||
$(qexec)cp -p $$< $$@
|
||||
endef
|
||||
|
||||
define archive_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
|
||||
# for creating them.
|
||||
$(1):
|
||||
$(if $(quiet),@echo " [AR] $$@")
|
||||
$(qexec)$$(AR) $$(ARFLAGS) $$@ $$^
|
||||
endef
|
||||
|
||||
define so_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
|
||||
# for creating them.
|
||||
#
|
||||
# This needs further abstraction for dealing with non-GNU linkers.
|
||||
$(1):
|
||||
$(if $(quiet),@echo " [LD] $$@")
|
||||
$(qexec)$$(LD) -shared $$(LDFLAGS) \
|
||||
-Wl,--no-undefined -Wl,-soname,$$(SONAME) \
|
||||
-Wl,--version-script,$$(EXPORTS_FILE) -o $$@ \
|
||||
$$(filter %.o,$$^) $$(extralibs)
|
||||
endef
|
||||
|
||||
define dl_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
|
||||
# for creating them.
|
||||
$(1):
|
||||
$(if $(quiet),@echo " [LD] $$@")
|
||||
$(qexec)$$(LD) -dynamiclib $$(LDFLAGS) \
|
||||
-exported_symbols_list $$(EXPORTS_FILE) \
|
||||
-Wl,-headerpad_max_install_names,-compatibility_version,1.0,-current_version,$$(VERSION_MAJOR) \
|
||||
-o $$@ \
|
||||
$$(filter %.o,$$^) $$(extralibs)
|
||||
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
|
||||
# for creating them.
|
||||
$(1):
|
||||
$(if $(quiet),@echo " [LD] $$@")
|
||||
$(qexec)$$(LD) -Zdll $$(LDFLAGS) \
|
||||
-o $$@ \
|
||||
$$(filter %.o,$$^) $$(extralibs) $$(EXPORTS_FILE)
|
||||
endef
|
||||
|
||||
|
||||
#
|
||||
# Get current configuration
|
||||
#
|
||||
ifneq ($(target),)
|
||||
include $(SRC_PATH_BARE)/$(target:-$(TOOLCHAIN)=).mk
|
||||
endif
|
||||
|
||||
skip_deps := $(filter %clean,$(MAKECMDGOALS))
|
||||
skip_deps += $(findstring testdata,$(MAKECMDGOALS))
|
||||
ifeq ($(strip $(skip_deps)),)
|
||||
ifeq ($(CONFIG_DEPENDENCY_TRACKING),yes)
|
||||
# Older versions of make don't like -include directives with no arguments
|
||||
ifneq ($(filter %.d,$(OBJS-yes:.o=.d)),)
|
||||
-include $(filter %.d,$(OBJS-yes:.o=.d))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Configuration dependent rules
|
||||
#
|
||||
$(call pairmap,install_map_templates,$(INSTALL_MAPS))
|
||||
|
||||
DOCS=$(call cond_enabled,CONFIG_INSTALL_DOCS,DOCS)
|
||||
.docs: $(DOCS)
|
||||
@touch $@
|
||||
|
||||
INSTALL-DOCS=$(call cond_enabled,CONFIG_INSTALL_DOCS,INSTALL-DOCS)
|
||||
ifeq ($(MAKECMDGOALS),dist)
|
||||
INSTALL-DOCS+=$(call cond_enabled,CONFIG_INSTALL_DOCS,DIST-DOCS)
|
||||
endif
|
||||
.install-docs: .docs $(addprefix $(DIST_DIR)/,$(INSTALL-DOCS))
|
||||
@touch $@
|
||||
|
||||
clean::
|
||||
rm -f .docs .install-docs $(DOCS)
|
||||
|
||||
BINS=$(call enabled,BINS)
|
||||
.bins: $(BINS)
|
||||
@touch $@
|
||||
|
||||
INSTALL-BINS=$(call cond_enabled,CONFIG_INSTALL_BINS,INSTALL-BINS)
|
||||
ifeq ($(MAKECMDGOALS),dist)
|
||||
INSTALL-BINS+=$(call cond_enabled,CONFIG_INSTALL_BINS,DIST-BINS)
|
||||
endif
|
||||
.install-bins: .bins $(addprefix $(DIST_DIR)/,$(INSTALL-BINS))
|
||||
@touch $@
|
||||
|
||||
clean::
|
||||
rm -f .bins .install-bins $(BINS)
|
||||
|
||||
LIBS=$(call enabled,LIBS)
|
||||
.libs: $(LIBS)
|
||||
@touch $@
|
||||
$(foreach lib,$(filter %_g.a,$(LIBS)),$(eval $(call archive_template,$(lib))))
|
||||
$(foreach lib,$(filter %so.$(SO_VERSION_MAJOR).$(SO_VERSION_MINOR).$(SO_VERSION_PATCH),$(LIBS)),$(eval $(call so_template,$(lib))))
|
||||
$(foreach lib,$(filter %$(SO_VERSION_MAJOR).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)
|
||||
ifeq ($(MAKECMDGOALS),dist)
|
||||
INSTALL-LIBS+=$(call cond_enabled,CONFIG_INSTALL_LIBS,DIST-LIBS)
|
||||
endif
|
||||
.install-libs: .libs $(addprefix $(DIST_DIR)/,$(INSTALL-LIBS))
|
||||
@touch $@
|
||||
|
||||
clean::
|
||||
rm -f .libs .install-libs $(LIBS)
|
||||
|
||||
ifeq ($(CONFIG_EXTERNAL_BUILD),yes)
|
||||
PROJECTS=$(call enabled,PROJECTS)
|
||||
.projects: $(PROJECTS)
|
||||
@touch $@
|
||||
|
||||
INSTALL-PROJECTS=$(call cond_enabled,CONFIG_INSTALL_PROJECTS,INSTALL-PROJECTS)
|
||||
ifeq ($(MAKECMDGOALS),dist)
|
||||
INSTALL-PROJECTS+=$(call cond_enabled,CONFIG_INSTALL_PROJECTS,DIST-PROJECTS)
|
||||
endif
|
||||
.install-projects: .projects $(addprefix $(DIST_DIR)/,$(INSTALL-PROJECTS))
|
||||
@touch $@
|
||||
|
||||
clean::
|
||||
rm -f .projects .install-projects $(PROJECTS)
|
||||
endif
|
||||
|
||||
# If there are any source files to be distributed, then include the build
|
||||
# system too.
|
||||
ifneq ($(call enabled,DIST-SRCS),)
|
||||
DIST-SRCS-yes += configure
|
||||
DIST-SRCS-yes += build/make/configure.sh
|
||||
DIST-SRCS-yes += build/make/gen_asm_deps.sh
|
||||
DIST-SRCS-yes += build/make/Makefile
|
||||
DIST-SRCS-$(CONFIG_MSVS) += build/make/gen_msvs_def.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/msvs_common.sh
|
||||
DIST-SRCS-$(CONFIG_RVCT) += build/make/armlink_adapter.sh
|
||||
DIST-SRCS-$(ARCH_ARM) += build/make/ads2gas.pl
|
||||
DIST-SRCS-$(ARCH_ARM) += build/make/ads2gas_apple.pl
|
||||
DIST-SRCS-$(ARCH_ARM) += build/make/ads2armasm_ms.pl
|
||||
DIST-SRCS-$(ARCH_ARM) += build/make/thumb.pm
|
||||
DIST-SRCS-yes += $(target:-$(TOOLCHAIN)=).mk
|
||||
endif
|
||||
INSTALL-SRCS := $(call cond_enabled,CONFIG_INSTALL_SRCS,INSTALL-SRCS)
|
||||
ifeq ($(MAKECMDGOALS),dist)
|
||||
INSTALL-SRCS += $(call cond_enabled,CONFIG_INSTALL_SRCS,DIST-SRCS)
|
||||
endif
|
||||
.install-srcs: $(addprefix $(DIST_DIR)/src/,$(INSTALL-SRCS))
|
||||
@touch $@
|
||||
|
||||
clean::
|
||||
rm -f .install-srcs
|
||||
|
||||
ifeq ($(CONFIG_EXTERNAL_BUILD),yes)
|
||||
BUILD_TARGETS += .projects
|
||||
INSTALL_TARGETS += .install-projects
|
||||
endif
|
||||
BUILD_TARGETS += .docs .libs .bins
|
||||
INSTALL_TARGETS += .install-docs .install-srcs .install-libs .install-bins
|
||||
all: $(BUILD_TARGETS)
|
||||
install:: $(INSTALL_TARGETS)
|
||||
dist: $(INSTALL_TARGETS)
|
||||
test::
|
||||
|
||||
.SUFFIXES: # Delete default suffix rules
|
@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
##
|
||||
## Copyright (c) 2013 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.
|
||||
##
|
||||
|
||||
use FindBin;
|
||||
use lib $FindBin::Bin;
|
||||
use thumb;
|
||||
|
||||
print "; This file was created from a .asm file\n";
|
||||
print "; using the ads2armasm_ms.pl script.\n";
|
||||
|
||||
while (<STDIN>)
|
||||
{
|
||||
undef $comment;
|
||||
undef $line;
|
||||
|
||||
s/REQUIRE8//;
|
||||
s/PRESERVE8//;
|
||||
s/^\s*ARM\s*$//;
|
||||
s/AREA\s+\|\|(.*)\|\|/AREA |$1|/;
|
||||
s/qsubaddx/qsax/i;
|
||||
s/qaddsubx/qasx/i;
|
||||
|
||||
thumb::FixThumbInstructions($_, 1);
|
||||
|
||||
s/ldrneb/ldrbne/i;
|
||||
s/ldrneh/ldrhne/i;
|
||||
s/^(\s*)ENDP.*/$&\n$1ALIGN 4/;
|
||||
|
||||
print;
|
||||
}
|
||||
|
@ -1,239 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
|
||||
# ads2gas.pl
|
||||
# Author: Eric Fung (efung (at) acm.org)
|
||||
#
|
||||
# Convert ARM Developer Suite 1.0.1 syntax assembly source to GNU as format
|
||||
#
|
||||
# Usage: cat inputfile | perl ads2gas.pl > outputfile
|
||||
#
|
||||
|
||||
use FindBin;
|
||||
use lib $FindBin::Bin;
|
||||
use thumb;
|
||||
|
||||
my $thumb = 0;
|
||||
my $elf = 1;
|
||||
|
||||
foreach my $arg (@ARGV) {
|
||||
$thumb = 1 if ($arg eq "-thumb");
|
||||
$elf = 0 if ($arg eq "-noelf");
|
||||
}
|
||||
|
||||
print "@ This file was created from a .asm file\n";
|
||||
print "@ using the ads2gas.pl script.\n";
|
||||
print "\t.equ DO1STROUNDING, 0\n";
|
||||
if ($thumb) {
|
||||
print "\t.syntax unified\n";
|
||||
print "\t.thumb\n";
|
||||
}
|
||||
|
||||
# Stack of procedure names.
|
||||
@proc_stack = ();
|
||||
|
||||
while (<STDIN>)
|
||||
{
|
||||
undef $comment;
|
||||
undef $line;
|
||||
$comment_char = ";";
|
||||
$comment_sub = "@";
|
||||
|
||||
# Handle comments.
|
||||
if (/$comment_char/)
|
||||
{
|
||||
$comment = "";
|
||||
($line, $comment) = /(.*?)$comment_char(.*)/;
|
||||
$_ = $line;
|
||||
}
|
||||
|
||||
# Load and store alignment
|
||||
s/@/,:/g;
|
||||
|
||||
# Hexadecimal constants prefaced by 0x
|
||||
s/#&/#0x/g;
|
||||
|
||||
# Convert :OR: to |
|
||||
s/:OR:/ | /g;
|
||||
|
||||
# Convert :AND: to &
|
||||
s/:AND:/ & /g;
|
||||
|
||||
# Convert :NOT: to ~
|
||||
s/:NOT:/ ~ /g;
|
||||
|
||||
# Convert :SHL: to <<
|
||||
s/:SHL:/ << /g;
|
||||
|
||||
# Convert :SHR: to >>
|
||||
s/:SHR:/ >> /g;
|
||||
|
||||
# Convert ELSE to .else
|
||||
s/\bELSE\b/.else/g;
|
||||
|
||||
# Convert ENDIF to .endif
|
||||
s/\bENDIF\b/.endif/g;
|
||||
|
||||
# Convert ELSEIF to .elseif
|
||||
s/\bELSEIF\b/.elseif/g;
|
||||
|
||||
# Convert LTORG to .ltorg
|
||||
s/\bLTORG\b/.ltorg/g;
|
||||
|
||||
# Convert endfunc to nothing.
|
||||
s/\bendfunc\b//ig;
|
||||
|
||||
# Convert FUNCTION to nothing.
|
||||
s/\bFUNCTION\b//g;
|
||||
s/\bfunction\b//g;
|
||||
|
||||
s/\bENTRY\b//g;
|
||||
s/\bMSARMASM\b/0/g;
|
||||
s/^\s+end\s+$//g;
|
||||
|
||||
# Convert IF :DEF:to .if
|
||||
# gcc doesn't have the ability to do a conditional
|
||||
# if defined variable that is set by IF :DEF: on
|
||||
# armasm, so convert it to a normal .if and then
|
||||
# make sure to define a value elesewhere
|
||||
if (s/\bIF :DEF:\b/.if /g)
|
||||
{
|
||||
s/=/==/g;
|
||||
}
|
||||
|
||||
# Convert IF to .if
|
||||
if (s/\bIF\b/.if/g)
|
||||
{
|
||||
s/=+/==/g;
|
||||
}
|
||||
|
||||
# Convert INCLUDE to .INCLUDE "file"
|
||||
s/INCLUDE(\s*)(.*)$/.include $1\"$2\"/;
|
||||
|
||||
# Code directive (ARM vs Thumb)
|
||||
s/CODE([0-9][0-9])/.code $1/;
|
||||
|
||||
# No AREA required
|
||||
# But ALIGNs in AREA must be obeyed
|
||||
s/^\s*AREA.*ALIGN=([0-9])$/.text\n.p2align $1/;
|
||||
# If no ALIGN, strip the AREA and align to 4 bytes
|
||||
s/^\s*AREA.*$/.text\n.p2align 2/;
|
||||
|
||||
# DCD to .word
|
||||
# This one is for incoming symbols
|
||||
s/DCD\s+\|(\w*)\|/.long $1/;
|
||||
|
||||
# DCW to .short
|
||||
s/DCW\s+\|(\w*)\|/.short $1/;
|
||||
s/DCW(.*)/.short $1/;
|
||||
|
||||
# Constants defined in scope
|
||||
s/DCD(.*)/.long $1/;
|
||||
s/DCB(.*)/.byte $1/;
|
||||
|
||||
# Make function visible to linker, and make additional symbol with
|
||||
# prepended underscore
|
||||
if ($elf) {
|
||||
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/EXPORT\s+([\$\w]*)/.global $1/;
|
||||
s/export\s+([\$\w]*)/.global $1/;
|
||||
|
||||
# No vertical bars required; make additional symbol with prepended
|
||||
# underscore
|
||||
s/^\|(\$?\w+)\|/_$1\n\t$1:/g;
|
||||
|
||||
# Labels need trailing colon
|
||||
# s/^(\w+)/$1:/ if !/EQU/;
|
||||
# put the colon at the end of the line in the macro
|
||||
s/^([a-zA-Z_0-9\$]+)/$1:/ if !/EQU/;
|
||||
|
||||
# ALIGN directive
|
||||
s/\bALIGN\b/.balign/g;
|
||||
|
||||
if ($thumb) {
|
||||
# ARM code - we force everything to thumb with the declaration in the header
|
||||
s/\sARM//g;
|
||||
} else {
|
||||
# ARM code
|
||||
s/\sARM/.arm/g;
|
||||
}
|
||||
|
||||
# push/pop
|
||||
s/(push\s+)(r\d+)/stmdb sp\!, \{$2\}/g;
|
||||
s/(pop\s+)(r\d+)/ldmia sp\!, \{$2\}/g;
|
||||
|
||||
# NEON code
|
||||
s/(vld1.\d+\s+)(q\d+)/$1\{$2\}/g;
|
||||
s/(vtbl.\d+\s+[^,]+),([^,]+)/$1,\{$2\}/g;
|
||||
|
||||
if ($thumb) {
|
||||
thumb::FixThumbInstructions($_, 0);
|
||||
}
|
||||
|
||||
# eabi_attributes numerical equivalents can be found in the
|
||||
# "ARM IHI 0045C" document.
|
||||
|
||||
if ($elf) {
|
||||
# REQUIRE8 Stack is required to be 8-byte aligned
|
||||
s/\sREQUIRE8/.eabi_attribute 24, 1 \@Tag_ABI_align_needed/g;
|
||||
|
||||
# PRESERVE8 Stack 8-byte align is preserved
|
||||
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.
|
||||
# This makes them show up properly in debugging tools like gdb and valgrind.
|
||||
if (/\bPROC\b/)
|
||||
{
|
||||
my $proc;
|
||||
/^_([\.0-9A-Z_a-z]\w+)\b/;
|
||||
$proc = $1;
|
||||
push(@proc_stack, $proc) if ($proc);
|
||||
s/\bPROC\b/@ $&/;
|
||||
}
|
||||
if (/\bENDP\b/)
|
||||
{
|
||||
my $proc;
|
||||
s/\bENDP\b/@ $&/;
|
||||
$proc = pop(@proc_stack);
|
||||
$_ = "\t.size $proc, .-$proc".$_ if ($proc and $elf);
|
||||
}
|
||||
|
||||
# EQU directive
|
||||
s/(\S+\s+)EQU(\s+\S+)/.equ $1, $2/;
|
||||
|
||||
# Begin macro definition
|
||||
if (/\bMACRO\b/) {
|
||||
$_ = <STDIN>;
|
||||
s/^/.macro/;
|
||||
s/\$//g; # remove formal param reference
|
||||
s/;/@/g; # change comment characters
|
||||
}
|
||||
|
||||
# For macros, use \ to reference formal params
|
||||
s/\$/\\/g; # End macro definition
|
||||
s/\bMEND\b/.endm/; # No need to tell it where to stop assembling
|
||||
next if /^\s*END\s*$/;
|
||||
print;
|
||||
print "$comment_sub$comment\n" if defined $comment;
|
||||
}
|
||||
|
||||
# Mark that this object doesn't need an executable stack.
|
||||
printf ("\t.section\t.note.GNU-stack,\"\",\%\%progbits\n") if $elf;
|
@ -1,204 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
|
||||
# ads2gas_apple.pl
|
||||
# Author: Eric Fung (efung (at) acm.org)
|
||||
#
|
||||
# Convert ARM Developer Suite 1.0.1 syntax assembly source to GNU as format
|
||||
#
|
||||
# Usage: cat inputfile | perl ads2gas_apple.pl > outputfile
|
||||
#
|
||||
|
||||
print "@ This file was created from a .asm file\n";
|
||||
print "@ using the ads2gas_apple.pl script.\n\n";
|
||||
print "\t.set WIDE_REFERENCE, 0\n";
|
||||
print "\t.set ARCHITECTURE, 5\n";
|
||||
print "\t.set DO1STROUNDING, 0\n";
|
||||
|
||||
my %register_aliases;
|
||||
my %macro_aliases;
|
||||
|
||||
my @mapping_list = ("\$0", "\$1", "\$2", "\$3", "\$4", "\$5", "\$6", "\$7", "\$8", "\$9");
|
||||
|
||||
my @incoming_array;
|
||||
|
||||
my @imported_functions;
|
||||
|
||||
# Perl trim function to remove whitespace from the start and end of the string
|
||||
sub trim($)
|
||||
{
|
||||
my $string = shift;
|
||||
$string =~ s/^\s+//;
|
||||
$string =~ s/\s+$//;
|
||||
return $string;
|
||||
}
|
||||
|
||||
while (<STDIN>)
|
||||
{
|
||||
# Load and store alignment
|
||||
s/@/,:/g;
|
||||
|
||||
# Comment character
|
||||
s/;/ @/g;
|
||||
|
||||
# Hexadecimal constants prefaced by 0x
|
||||
s/#&/#0x/g;
|
||||
|
||||
# Convert :OR: to |
|
||||
s/:OR:/ | /g;
|
||||
|
||||
# Convert :AND: to &
|
||||
s/:AND:/ & /g;
|
||||
|
||||
# Convert :NOT: to ~
|
||||
s/:NOT:/ ~ /g;
|
||||
|
||||
# Convert :SHL: to <<
|
||||
s/:SHL:/ << /g;
|
||||
|
||||
# Convert :SHR: to >>
|
||||
s/:SHR:/ >> /g;
|
||||
|
||||
# Convert ELSE to .else
|
||||
s/\bELSE\b/.else/g;
|
||||
|
||||
# Convert ENDIF to .endif
|
||||
s/\bENDIF\b/.endif/g;
|
||||
|
||||
# Convert ELSEIF to .elseif
|
||||
s/\bELSEIF\b/.elseif/g;
|
||||
|
||||
# Convert LTORG to .ltorg
|
||||
s/\bLTORG\b/.ltorg/g;
|
||||
|
||||
# Convert IF :DEF:to .if
|
||||
# gcc doesn't have the ability to do a conditional
|
||||
# if defined variable that is set by IF :DEF: on
|
||||
# armasm, so convert it to a normal .if and then
|
||||
# make sure to define a value elesewhere
|
||||
if (s/\bIF :DEF:\b/.if /g)
|
||||
{
|
||||
s/=/==/g;
|
||||
}
|
||||
|
||||
# Convert IF to .if
|
||||
if (s/\bIF\b/.if/g)
|
||||
{
|
||||
s/=/==/g;
|
||||
}
|
||||
|
||||
# Convert INCLUDE to .INCLUDE "file"
|
||||
s/INCLUDE(\s*)(.*)$/.include $1\"$2\"/;
|
||||
|
||||
# Code directive (ARM vs Thumb)
|
||||
s/CODE([0-9][0-9])/.code $1/;
|
||||
|
||||
# No AREA required
|
||||
# But ALIGNs in AREA must be obeyed
|
||||
s/^\s*AREA.*ALIGN=([0-9])$/.text\n.p2align $1/;
|
||||
# If no ALIGN, strip the AREA and align to 4 bytes
|
||||
s/^\s*AREA.*$/.text\n.p2align 2/;
|
||||
|
||||
# DCD to .word
|
||||
# This one is for incoming symbols
|
||||
s/DCD\s+\|(\w*)\|/.long $1/;
|
||||
|
||||
# DCW to .short
|
||||
s/DCW\s+\|(\w*)\|/.short $1/;
|
||||
s/DCW(.*)/.short $1/;
|
||||
|
||||
# Constants defined in scope
|
||||
s/DCD(.*)/.long $1/;
|
||||
s/DCB(.*)/.byte $1/;
|
||||
|
||||
# Make function visible to linker, and make additional symbol with
|
||||
# prepended underscore
|
||||
s/EXPORT\s+\|([\$\w]*)\|/.globl _$1\n\t.globl $1/;
|
||||
|
||||
# Prepend imported functions with _
|
||||
if (s/IMPORT\s+\|([\$\w]*)\|/.globl $1/)
|
||||
{
|
||||
$function = trim($1);
|
||||
push(@imported_functions, $function);
|
||||
}
|
||||
|
||||
foreach $function (@imported_functions)
|
||||
{
|
||||
s/$function/_$function/;
|
||||
}
|
||||
|
||||
# No vertical bars required; make additional symbol with prepended
|
||||
# underscore
|
||||
s/^\|(\$?\w+)\|/_$1\n\t$1:/g;
|
||||
|
||||
# Labels need trailing colon
|
||||
# s/^(\w+)/$1:/ if !/EQU/;
|
||||
# put the colon at the end of the line in the macro
|
||||
s/^([a-zA-Z_0-9\$]+)/$1:/ if !/EQU/;
|
||||
|
||||
# ALIGN directive
|
||||
s/\bALIGN\b/.balign/g;
|
||||
|
||||
# Strip ARM
|
||||
s/\sARM/@ ARM/g;
|
||||
|
||||
# Strip REQUIRE8
|
||||
#s/\sREQUIRE8/@ REQUIRE8/g;
|
||||
s/\sREQUIRE8/@ /g;
|
||||
|
||||
# Strip PRESERVE8
|
||||
s/\sPRESERVE8/@ PRESERVE8/g;
|
||||
|
||||
# Strip PROC and ENDPROC
|
||||
s/\bPROC\b/@/g;
|
||||
s/\bENDP\b/@/g;
|
||||
|
||||
# EQU directive
|
||||
s/(.*)EQU(.*)/.set $1, $2/;
|
||||
|
||||
# Begin macro definition
|
||||
if (/\bMACRO\b/)
|
||||
{
|
||||
# Process next line down, which will be the macro definition
|
||||
$_ = <STDIN>;
|
||||
|
||||
$trimmed = trim($_);
|
||||
|
||||
# remove commas that are separating list
|
||||
$trimmed =~ s/,//g;
|
||||
|
||||
# string to array
|
||||
@incoming_array = split(/\s+/, $trimmed);
|
||||
|
||||
print ".macro @incoming_array[0]\n";
|
||||
|
||||
# remove the first element, as that is the name of the macro
|
||||
shift (@incoming_array);
|
||||
|
||||
@macro_aliases{@incoming_array} = @mapping_list;
|
||||
|
||||
next;
|
||||
}
|
||||
|
||||
while (($key, $value) = each(%macro_aliases))
|
||||
{
|
||||
$key =~ s/\$/\\\$/;
|
||||
s/$key\b/$value/g;
|
||||
}
|
||||
|
||||
# For macros, use \ to reference formal params
|
||||
# s/\$/\\/g; # End macro definition
|
||||
s/\bMEND\b/.endm/; # No need to tell it where to stop assembling
|
||||
next if /^\s*END\s*$/;
|
||||
|
||||
print;
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
#!/bin/sh
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
|
||||
verbose=0
|
||||
set -- $*
|
||||
for i; do
|
||||
if [ "$i" = "-o" ]; then
|
||||
on_of=1
|
||||
elif [ "$i" = "-v" ]; then
|
||||
verbose=1
|
||||
elif [ "$i" = "-g" ]; then
|
||||
args="${args} --debug"
|
||||
elif [ "$on_of" = "1" ]; then
|
||||
outfile=$i
|
||||
on_of=0
|
||||
elif [ -f "$i" ]; then
|
||||
infiles="$infiles $i"
|
||||
elif [ "${i#-l}" != "$i" ]; then
|
||||
libs="$libs ${i#-l}"
|
||||
elif [ "${i#-L}" != "$i" ]; then
|
||||
libpaths="${libpaths} ${i#-L}"
|
||||
else
|
||||
args="${args} ${i}"
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
# Absolutize library file names
|
||||
for f in $libs; do
|
||||
found=0
|
||||
for d in $libpaths; do
|
||||
[ -f "$d/$f" ] && infiles="$infiles $d/$f" && found=1 && break
|
||||
[ -f "$d/lib${f}.so" ] && infiles="$infiles $d/lib${f}.so" && found=1 && break
|
||||
[ -f "$d/lib${f}.a" ] && infiles="$infiles $d/lib${f}.a" && found=1 && break
|
||||
done
|
||||
[ $found -eq 0 ] && infiles="$infiles $f"
|
||||
done
|
||||
for d in $libpaths; do
|
||||
[ -n "$libsearchpath" ] && libsearchpath="${libsearchpath},"
|
||||
libsearchpath="${libsearchpath}$d"
|
||||
done
|
||||
|
||||
cmd="armlink $args --userlibpath=$libsearchpath --output=$outfile $infiles"
|
||||
[ $verbose -eq 1 ] && echo $cmd
|
||||
$cmd
|
File diff suppressed because it is too large
Load Diff
@ -1,64 +0,0 @@
|
||||
#!/bin/sh
|
||||
##
|
||||
## 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
|
||||
show_help() {
|
||||
echo "usage: $self [options] <srcfile>"
|
||||
echo
|
||||
echo "Generate Makefile dependency information from assembly code source"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
die_unknown(){
|
||||
echo "Unknown option \"$1\"."
|
||||
echo "See $0 --help for available options."
|
||||
exit 1
|
||||
}
|
||||
for opt do
|
||||
optval="${opt#*=}"
|
||||
case "$opt" in
|
||||
--build-pfx=*) pfx="${optval}"
|
||||
;;
|
||||
--depfile=*) out="${optval}"
|
||||
;;
|
||||
-I*) raw_inc_paths="${raw_inc_paths} ${opt}"
|
||||
inc_path="${inc_path} ${opt#-I}"
|
||||
;;
|
||||
-h|--help) show_help
|
||||
;;
|
||||
*) [ -f "$opt" ] && srcfile="$opt"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ -n "$srcfile" ] || show_help
|
||||
sfx=${sfx:-asm}
|
||||
includes=$(LC_ALL=C egrep -i "include +\"?[a-z0-9_/]+\.${sfx}" $srcfile |
|
||||
perl -p -e "s;.*?([a-z0-9_/]+.${sfx}).*;\1;")
|
||||
#" restore editor state
|
||||
for inc in ${includes}; do
|
||||
found_inc_path=
|
||||
for idir in ${inc_path}; do
|
||||
[ -f "${idir}/${inc}" ] && found_inc_path="${idir}" && break
|
||||
done
|
||||
if [ -f `dirname $srcfile`/$inc ]; then
|
||||
# Handle include files in the same directory as the source
|
||||
$self --build-pfx=$pfx --depfile=$out ${raw_inc_paths} `dirname $srcfile`/$inc
|
||||
elif [ -n "${found_inc_path}" ]; then
|
||||
# Handle include files on the include path
|
||||
$self --build-pfx=$pfx --depfile=$out ${raw_inc_paths} "${found_inc_path}/$inc"
|
||||
else
|
||||
# Handle generated includes in the build root (which may not exist yet)
|
||||
echo ${out} ${out%d}o: "${pfx}${inc}"
|
||||
fi
|
||||
done
|
||||
echo ${out} ${out%d}o: $srcfile
|
@ -1,83 +0,0 @@
|
||||
#!/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##*/}
|
||||
EOL=$'\n'
|
||||
|
||||
show_help() {
|
||||
cat <<EOF
|
||||
Usage: ${self_basename} [options] file1 [file2 ...]
|
||||
|
||||
This script generates a MSVC module definition file containing a list of symbols
|
||||
to export from a DLL. Source files are technically bash scripts (and thus may
|
||||
use #comment syntax) but in general, take the form of a list of symbols:
|
||||
|
||||
<kind> symbol1 [symbol2, symbol3, ...]
|
||||
|
||||
where <kind> is either 'text' or 'data'
|
||||
|
||||
|
||||
Options:
|
||||
--help Print this message
|
||||
--out=filename Write output to a file [stdout]
|
||||
--name=project_name Name of the library (required)
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "${self_basename}: $@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
die_unknown(){
|
||||
echo "Unknown option \"$1\"."
|
||||
echo "See ${self_basename} --help for available options."
|
||||
exit 1
|
||||
}
|
||||
|
||||
text() {
|
||||
for sym in "$@"; do
|
||||
echo " $sym" >> ${outfile}
|
||||
done
|
||||
}
|
||||
|
||||
data() {
|
||||
for sym in "$@"; do
|
||||
printf " %-40s DATA\n" "$sym" >> ${outfile}
|
||||
done
|
||||
}
|
||||
|
||||
# Process command line
|
||||
for opt in "$@"; do
|
||||
optval="${opt#*=}"
|
||||
case "$opt" in
|
||||
--help|-h) show_help
|
||||
;;
|
||||
--out=*) outfile="$optval"
|
||||
;;
|
||||
--name=*) name="${optval}"
|
||||
;;
|
||||
-*) die_unknown $opt
|
||||
;;
|
||||
*) file_list[${#file_list[@]}]="$opt"
|
||||
esac
|
||||
done
|
||||
outfile=${outfile:-/dev/stdout}
|
||||
[ -n "$name" ] || die "Library name (--name) must be specified!"
|
||||
|
||||
echo "LIBRARY ${name}" > ${outfile}
|
||||
echo "EXPORTS" >> ${outfile}
|
||||
for f in "${file_list[@]}"; do
|
||||
. $f
|
||||
done
|
@ -1,263 +0,0 @@
|
||||
#!/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##*/}
|
||||
EOL=$'\n'
|
||||
EOLDOS=$'\r'
|
||||
|
||||
show_help() {
|
||||
cat <<EOF
|
||||
Usage: ${self_basename} [options] file1 [file2 ...]
|
||||
|
||||
This script generates a Visual Studio solution file from a list of project
|
||||
files.
|
||||
|
||||
Options:
|
||||
--help Print this message
|
||||
--out=outfile Redirect output to a file
|
||||
--ver=version Version (7,8,9,10,11,12,14,15) of visual studio to generate for
|
||||
--target=isa-os-cc Target specifier
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "${self_basename}: $@" >&2
|
||||
[ -f "${outfile}" ] && rm -f ${outfile}{,.mk}
|
||||
exit 1
|
||||
}
|
||||
|
||||
die_unknown(){
|
||||
echo "Unknown option \"$1\"." >&2
|
||||
echo "See ${self_basename} --help for available options." >&2
|
||||
[ -f "${outfile}" ] && rm -f ${outfile}{,.mk}
|
||||
exit 1
|
||||
}
|
||||
|
||||
indent1=$'\t'
|
||||
indent=""
|
||||
indent_push() {
|
||||
indent="${indent}${indent1}"
|
||||
}
|
||||
indent_pop() {
|
||||
indent="${indent%${indent1}}"
|
||||
}
|
||||
|
||||
parse_project() {
|
||||
local file=$1
|
||||
local name=`grep RootNamespace "$file" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'`
|
||||
local guid=`grep ProjectGuid "$file" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'`
|
||||
|
||||
# save the project GUID to a varaible, normalizing to the basename of the
|
||||
# vcxproj file without the extension
|
||||
local var
|
||||
var=${file##*/}
|
||||
var=${var%%.${sfx}}
|
||||
eval "${var}_file=\"$1\""
|
||||
eval "${var}_name=$name"
|
||||
eval "${var}_guid=$guid"
|
||||
|
||||
cur_config_list=`grep -B1 'Label="Configuration"' $file |
|
||||
grep Condition | cut -d\' -f4`
|
||||
new_config_list=$(for i in $config_list $cur_config_list; do
|
||||
echo $i
|
||||
done | sort | uniq)
|
||||
if [ "$config_list" != "" ] && [ "$config_list" != "$new_config_list" ]; then
|
||||
mixed_platforms=1
|
||||
fi
|
||||
config_list="$new_config_list"
|
||||
eval "${var}_config_list=\"$cur_config_list\""
|
||||
proj_list="${proj_list} ${var}"
|
||||
}
|
||||
|
||||
process_project() {
|
||||
eval "local file=\${$1_file}"
|
||||
eval "local name=\${$1_name}"
|
||||
eval "local guid=\${$1_guid}"
|
||||
|
||||
# save the project GUID to a varaible, normalizing to the basename of the
|
||||
# vcproj file without the extension
|
||||
local var
|
||||
var=${file##*/}
|
||||
var=${var%%.${sfx}}
|
||||
eval "${var}_guid=$guid"
|
||||
|
||||
echo "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"$name\", \"$file\", \"$guid\""
|
||||
echo "EndProject"
|
||||
}
|
||||
|
||||
process_global() {
|
||||
echo "Global"
|
||||
indent_push
|
||||
|
||||
#
|
||||
# Solution Configuration Platforms
|
||||
#
|
||||
echo "${indent}GlobalSection(SolutionConfigurationPlatforms) = preSolution"
|
||||
indent_push
|
||||
IFS_bak=${IFS}
|
||||
IFS=$'\r'$'\n'
|
||||
if [ "$mixed_platforms" != "" ]; then
|
||||
config_list="
|
||||
Release|Mixed Platforms
|
||||
Debug|Mixed Platforms"
|
||||
fi
|
||||
for config in ${config_list}; do
|
||||
echo "${indent}$config = $config"
|
||||
done
|
||||
IFS=${IFS_bak}
|
||||
indent_pop
|
||||
echo "${indent}EndGlobalSection"
|
||||
|
||||
#
|
||||
# Project Configuration Platforms
|
||||
#
|
||||
echo "${indent}GlobalSection(ProjectConfigurationPlatforms) = postSolution"
|
||||
indent_push
|
||||
for proj in ${proj_list}; do
|
||||
eval "local proj_guid=\${${proj}_guid}"
|
||||
eval "local proj_config_list=\${${proj}_config_list}"
|
||||
IFS=$'\r'$'\n'
|
||||
for config in ${proj_config_list}; do
|
||||
if [ "$mixed_platforms" != "" ]; then
|
||||
local c=${config%%|*}
|
||||
echo "${indent}${proj_guid}.${c}|Mixed Platforms.ActiveCfg = ${config}"
|
||||
echo "${indent}${proj_guid}.${c}|Mixed Platforms.Build.0 = ${config}"
|
||||
else
|
||||
echo "${indent}${proj_guid}.${config}.ActiveCfg = ${config}"
|
||||
echo "${indent}${proj_guid}.${config}.Build.0 = ${config}"
|
||||
fi
|
||||
|
||||
done
|
||||
IFS=${IFS_bak}
|
||||
done
|
||||
indent_pop
|
||||
echo "${indent}EndGlobalSection"
|
||||
|
||||
#
|
||||
# Solution Properties
|
||||
#
|
||||
echo "${indent}GlobalSection(SolutionProperties) = preSolution"
|
||||
indent_push
|
||||
echo "${indent}HideSolutionNode = FALSE"
|
||||
indent_pop
|
||||
echo "${indent}EndGlobalSection"
|
||||
|
||||
indent_pop
|
||||
echo "EndGlobal"
|
||||
}
|
||||
|
||||
process_makefile() {
|
||||
IFS_bak=${IFS}
|
||||
IFS=$'\r'$'\n'
|
||||
local TAB=$'\t'
|
||||
cat <<EOF
|
||||
MSBUILD_TOOL := msbuild.exe
|
||||
found_devenv := \$(shell which \$(MSBUILD_TOOL) >/dev/null 2>&1 && echo yes)
|
||||
.nodevenv.once:
|
||||
${TAB}@echo " * \$(MSBUILD_TOOL) not found in path."
|
||||
${TAB}@echo " * "
|
||||
${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 " * add the Common7/IDE directory of your Visual Studio"
|
||||
${TAB}@echo " * installation to your path, eg:"
|
||||
${TAB}@echo " * C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE"
|
||||
${TAB}@echo " * "
|
||||
${TAB}@touch \$@
|
||||
CLEAN-OBJS += \$(if \$(found_devenv),,.nodevenv.once)
|
||||
|
||||
EOF
|
||||
|
||||
for sln_config in ${config_list}; do
|
||||
local config=${sln_config%%|*}
|
||||
local platform=${sln_config##*|}
|
||||
local nows_sln_config=`echo $sln_config | sed -e 's/[^a-zA-Z0-9]/_/g'`
|
||||
cat <<EOF
|
||||
BUILD_TARGETS += \$(if \$(NO_LAUNCH_DEVENV),,$nows_sln_config)
|
||||
clean::
|
||||
${TAB}rm -rf "$platform"/"$config"
|
||||
.PHONY: $nows_sln_config
|
||||
ifneq (\$(found_devenv),)
|
||||
$nows_sln_config: $outfile
|
||||
${TAB}\$(MSBUILD_TOOL) $outfile -m -t:Build \\
|
||||
${TAB}${TAB}-p:Configuration="$config" -p:Platform="$platform"
|
||||
else
|
||||
$nows_sln_config: $outfile .nodevenv.once
|
||||
${TAB}@echo " * Skipping build of $sln_config (\$(MSBUILD_TOOL) not in path)."
|
||||
${TAB}@echo " * "
|
||||
endif
|
||||
|
||||
EOF
|
||||
done
|
||||
IFS=${IFS_bak}
|
||||
}
|
||||
|
||||
# Process command line
|
||||
outfile=/dev/stdout
|
||||
for opt in "$@"; do
|
||||
optval="${opt#*=}"
|
||||
case "$opt" in
|
||||
--help|-h) show_help
|
||||
;;
|
||||
--out=*) outfile="${optval}"; mkoutfile="${optval}".mk
|
||||
;;
|
||||
--dep=*) eval "${optval%%:*}_deps=\"\${${optval%%:*}_deps} ${optval##*:}\""
|
||||
;;
|
||||
--ver=*) vs_ver="$optval"
|
||||
case $optval in
|
||||
10|11|12|14|15)
|
||||
;;
|
||||
*) die Unrecognized Visual Studio Version in $opt
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
--target=*) target="${optval}"
|
||||
;;
|
||||
-*) die_unknown $opt
|
||||
;;
|
||||
*) file_list[${#file_list[@]}]="$opt"
|
||||
esac
|
||||
done
|
||||
outfile=${outfile:-/dev/stdout}
|
||||
mkoutfile=${mkoutfile:-/dev/stdout}
|
||||
case "${vs_ver:-10}" in
|
||||
10) sln_vers="11.00"
|
||||
sln_vers_str="Visual Studio 2010"
|
||||
;;
|
||||
11) sln_vers="12.00"
|
||||
sln_vers_str="Visual Studio 2012"
|
||||
;;
|
||||
12) sln_vers="12.00"
|
||||
sln_vers_str="Visual Studio 2013"
|
||||
;;
|
||||
14) sln_vers="12.00"
|
||||
sln_vers_str="Visual Studio 2015"
|
||||
;;
|
||||
15) sln_vers="12.00"
|
||||
sln_vers_str="Visual Studio 2017"
|
||||
;;
|
||||
esac
|
||||
sfx=vcxproj
|
||||
|
||||
for f in "${file_list[@]}"; do
|
||||
parse_project $f
|
||||
done
|
||||
cat >${outfile} <<EOF
|
||||
Microsoft Visual Studio Solution File, Format Version $sln_vers${EOLDOS}
|
||||
# $sln_vers_str${EOLDOS}
|
||||
EOF
|
||||
for proj in ${proj_list}; do
|
||||
process_project $proj >>${outfile}
|
||||
done
|
||||
process_global >>${outfile}
|
||||
process_makefile >${mkoutfile}
|
@ -1,493 +0,0 @@
|
||||
#!/bin/bash
|
||||
##
|
||||
## Copyright (c) 2013 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)
|
||||
--enable-werror Treat warnings as errors (/WX)
|
||||
--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 (10,11,12,14,15) 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
|
||||
}
|
||||
|
||||
tag_content() {
|
||||
local tag=$1
|
||||
local content=$2
|
||||
shift
|
||||
shift
|
||||
if [ $# -ne 0 ]; then
|
||||
echo "${indent}<${tag}"
|
||||
indent_push
|
||||
tag_attributes "$@"
|
||||
echo "${indent}>${content}</${tag}>"
|
||||
indent_pop
|
||||
else
|
||||
echo "${indent}<${tag}>${content}</${tag}>"
|
||||
fi
|
||||
}
|
||||
|
||||
generate_filter() {
|
||||
local name=$1
|
||||
local pats=$2
|
||||
local file_list_sz
|
||||
local i
|
||||
local f
|
||||
local saveIFS="$IFS"
|
||||
local pack
|
||||
echo "generating filter '$name' from ${#file_list[@]} files" >&2
|
||||
IFS=*
|
||||
|
||||
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')
|
||||
|
||||
if ([ "$pat" == "asm" ] || [ "$pat" == "s" ] || [ "$pat" == "S" ]) && $asm_use_custom_step; then
|
||||
# Avoid object file name collisions, i.e. vpx_config.c and
|
||||
# vpx_config.asm produce the same object file without
|
||||
# this additional suffix.
|
||||
objf=${objf%.obj}_asm.obj
|
||||
open_tag CustomBuild \
|
||||
Include="$f"
|
||||
for plat in "${platforms[@]}"; do
|
||||
for cfg in Debug Release; do
|
||||
tag_content Message "Assembling %(Filename)%(Extension)" \
|
||||
Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'"
|
||||
tag_content Command "$(eval echo \$asm_${cfg}_cmdline) -o \$(IntDir)$objf" \
|
||||
Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'"
|
||||
tag_content Outputs "\$(IntDir)$objf" \
|
||||
Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'"
|
||||
done
|
||||
done
|
||||
close_tag CustomBuild
|
||||
elif [ "$pat" == "c" ] || \
|
||||
[ "$pat" == "cc" ] || [ "$pat" == "cpp" ]; then
|
||||
open_tag ClCompile \
|
||||
Include="$f"
|
||||
# Separate file names with Condition?
|
||||
tag_content ObjectFileName "\$(IntDir)$objf"
|
||||
# Check for AVX and turn it on to avoid warnings.
|
||||
if [[ $f =~ avx.?\.c$ ]]; then
|
||||
tag_content AdditionalOptions "/arch:AVX"
|
||||
fi
|
||||
close_tag ClCompile
|
||||
elif [ "$pat" == "h" ] ; then
|
||||
tag ClInclude \
|
||||
Include="$f"
|
||||
elif [ "$pat" == "vcxproj" ] ; then
|
||||
open_tag ProjectReference \
|
||||
Include="$f"
|
||||
depguid=`grep ProjectGuid "$f" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'`
|
||||
tag_content Project "$depguid"
|
||||
tag_content ReferenceOutputAssembly false
|
||||
close_tag ProjectReference
|
||||
else
|
||||
tag None \
|
||||
Include="$f"
|
||||
fi
|
||||
|
||||
break
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
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=*) module_def="${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
|
||||
;;
|
||||
--enable-werror) werror=true
|
||||
;;
|
||||
--ver=*)
|
||||
vs_ver="$optval"
|
||||
case "$optval" in
|
||||
10|11|12|14|15)
|
||||
;;
|
||||
*) die Unrecognized Visual Studio Version in $opt
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I*)
|
||||
opt=${opt##-I}
|
||||
opt=$(fix_path "$opt")
|
||||
opt="${opt%/}"
|
||||
incs="${incs}${incs:+;}"${opt}""
|
||||
yasmincs="${yasmincs} -I"${opt}""
|
||||
;;
|
||||
-D*) defines="${defines}${defines:+;}${opt##-D}"
|
||||
;;
|
||||
-L*) # fudge . to $(OutDir)
|
||||
if [ "${opt##-L}" == "." ]; then
|
||||
libdirs="${libdirs}${libdirs:+;}"\$(OutDir)""
|
||||
else
|
||||
# Also try directories for this platform/configuration
|
||||
opt=${opt##-L}
|
||||
opt=$(fix_path "$opt")
|
||||
libdirs="${libdirs}${libdirs:+;}"${opt}""
|
||||
libdirs="${libdirs}${libdirs:+;}"${opt}/\$(PlatformName)/\$(Configuration)""
|
||||
libdirs="${libdirs}${libdirs:+;}"${opt}/\$(PlatformName)""
|
||||
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|*.[Ss]) uses_asm=true
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Make one call to fix_path for file_list to improve performance.
|
||||
fix_file_list file_list
|
||||
|
||||
outfile=${outfile:-/dev/stdout}
|
||||
guid=${guid:-`generate_uuid`}
|
||||
asm_use_custom_step=false
|
||||
uses_asm=${uses_asm:-false}
|
||||
case "${vs_ver:-11}" in
|
||||
10|11|12|14|15)
|
||||
asm_use_custom_step=$uses_asm
|
||||
;;
|
||||
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=MultiThreaded
|
||||
debug_runtime=MultiThreadedDebug
|
||||
lib_sfx=mt
|
||||
else
|
||||
release_runtime=MultiThreadedDLL
|
||||
debug_runtime=MultiThreadedDebugDLL
|
||||
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
|
||||
debug_libs=${debug_libs// /;}
|
||||
libs=${libs// /;}
|
||||
|
||||
|
||||
# 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} "%(FullPath)""
|
||||
asm_Release_cmdline="yasm -Xvc -f win64 ${yasmincs} "%(FullPath)""
|
||||
;;
|
||||
x86*)
|
||||
platforms[0]="Win32"
|
||||
asm_Debug_cmdline="yasm -Xvc -g cv8 -f win32 ${yasmincs} "%(FullPath)""
|
||||
asm_Release_cmdline="yasm -Xvc -f win32 ${yasmincs} "%(FullPath)""
|
||||
;;
|
||||
arm*)
|
||||
platforms[0]="ARM"
|
||||
asm_Debug_cmdline="armasm -nologo -oldit "%(FullPath)""
|
||||
asm_Release_cmdline="armasm -nologo -oldit "%(FullPath)""
|
||||
;;
|
||||
*) die "Unsupported target $target!"
|
||||
;;
|
||||
esac
|
||||
|
||||
generate_vcxproj() {
|
||||
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
open_tag Project \
|
||||
DefaultTargets="Build" \
|
||||
ToolsVersion="4.0" \
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003" \
|
||||
|
||||
open_tag ItemGroup \
|
||||
Label="ProjectConfigurations"
|
||||
for plat in "${platforms[@]}"; do
|
||||
for config in Debug Release; do
|
||||
open_tag ProjectConfiguration \
|
||||
Include="$config|$plat"
|
||||
tag_content Configuration $config
|
||||
tag_content Platform $plat
|
||||
close_tag ProjectConfiguration
|
||||
done
|
||||
done
|
||||
close_tag ItemGroup
|
||||
|
||||
open_tag PropertyGroup \
|
||||
Label="Globals"
|
||||
tag_content ProjectGuid "{${guid}}"
|
||||
tag_content RootNamespace ${name}
|
||||
tag_content Keyword ManagedCProj
|
||||
if [ $vs_ver -ge 12 ] && [ "${platforms[0]}" = "ARM" ]; then
|
||||
tag_content AppContainerApplication true
|
||||
# The application type can be one of "Windows Store",
|
||||
# "Windows Phone" or "Windows Phone Silverlight". The
|
||||
# actual value doesn't matter from the libvpx point of view,
|
||||
# since a static library built for one works on the others.
|
||||
# The PlatformToolset field needs to be set in sync with this;
|
||||
# for Windows Store and Windows Phone Silverlight it should be
|
||||
# v120 while it should be v120_wp81 if the type is Windows Phone.
|
||||
tag_content ApplicationType "Windows Store"
|
||||
tag_content ApplicationTypeRevision 8.1
|
||||
fi
|
||||
close_tag PropertyGroup
|
||||
|
||||
tag Import \
|
||||
Project="\$(VCTargetsPath)\\Microsoft.Cpp.Default.props"
|
||||
|
||||
for plat in "${platforms[@]}"; do
|
||||
for config in Release Debug; do
|
||||
open_tag PropertyGroup \
|
||||
Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" \
|
||||
Label="Configuration"
|
||||
if [ "$proj_kind" = "exe" ]; then
|
||||
tag_content ConfigurationType Application
|
||||
elif [ "$proj_kind" = "dll" ]; then
|
||||
tag_content ConfigurationType DynamicLibrary
|
||||
else
|
||||
tag_content ConfigurationType StaticLibrary
|
||||
fi
|
||||
if [ "$vs_ver" = "11" ]; then
|
||||
if [ "$plat" = "ARM" ]; then
|
||||
# Setting the wp80 toolchain automatically sets the
|
||||
# WINAPI_FAMILY define, which is required for building
|
||||
# code for arm with the windows headers. Alternatively,
|
||||
# one could add AppContainerApplication=true in the Globals
|
||||
# section and add PrecompiledHeader=NotUsing and
|
||||
# CompileAsWinRT=false in ClCompile and SubSystem=Console
|
||||
# in Link.
|
||||
tag_content PlatformToolset v110_wp80
|
||||
else
|
||||
tag_content PlatformToolset v110
|
||||
fi
|
||||
fi
|
||||
if [ "$vs_ver" = "12" ]; then
|
||||
# Setting a PlatformToolset indicating windows phone isn't
|
||||
# enough to build code for arm with MSVC 2013, one strictly
|
||||
# has to enable AppContainerApplication as well.
|
||||
tag_content PlatformToolset v120
|
||||
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
|
||||
if [ "$config" = "Release" ]; then
|
||||
tag_content WholeProgramOptimization true
|
||||
fi
|
||||
close_tag PropertyGroup
|
||||
done
|
||||
done
|
||||
|
||||
tag Import \
|
||||
Project="\$(VCTargetsPath)\\Microsoft.Cpp.props"
|
||||
|
||||
open_tag ImportGroup \
|
||||
Label="PropertySheets"
|
||||
tag Import \
|
||||
Project="\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props" \
|
||||
Condition="exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')" \
|
||||
Label="LocalAppDataPlatform"
|
||||
close_tag ImportGroup
|
||||
|
||||
tag PropertyGroup \
|
||||
Label="UserMacros"
|
||||
|
||||
for plat in "${platforms[@]}"; do
|
||||
plat_no_ws=`echo $plat | sed 's/[^A-Za-z0-9_]/_/g'`
|
||||
for config in Debug Release; do
|
||||
open_tag PropertyGroup \
|
||||
Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'"
|
||||
tag_content OutDir "\$(SolutionDir)$plat_no_ws\\\$(Configuration)\\"
|
||||
tag_content IntDir "$plat_no_ws\\\$(Configuration)\\${name}\\"
|
||||
if [ "$proj_kind" == "lib" ]; then
|
||||
if [ "$config" == "Debug" ]; then
|
||||
config_suffix=d
|
||||
else
|
||||
config_suffix=""
|
||||
fi
|
||||
tag_content TargetName "${name}${lib_sfx}${config_suffix}"
|
||||
fi
|
||||
close_tag PropertyGroup
|
||||
done
|
||||
done
|
||||
|
||||
for plat in "${platforms[@]}"; do
|
||||
for config in Debug Release; do
|
||||
open_tag ItemDefinitionGroup \
|
||||
Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'"
|
||||
if [ "$name" == "vpx" ]; then
|
||||
hostplat=$plat
|
||||
if [ "$hostplat" == "ARM" ]; then
|
||||
hostplat=Win32
|
||||
fi
|
||||
fi
|
||||
open_tag ClCompile
|
||||
if [ "$config" = "Debug" ]; then
|
||||
opt=Disabled
|
||||
runtime=$debug_runtime
|
||||
curlibs=$debug_libs
|
||||
debug=_DEBUG
|
||||
else
|
||||
opt=MaxSpeed
|
||||
runtime=$release_runtime
|
||||
curlibs=$libs
|
||||
tag_content FavorSizeOrSpeed Speed
|
||||
debug=NDEBUG
|
||||
fi
|
||||
extradefines=";$defines"
|
||||
tag_content Optimization $opt
|
||||
tag_content AdditionalIncludeDirectories "$incs;%(AdditionalIncludeDirectories)"
|
||||
tag_content PreprocessorDefinitions "WIN32;$debug;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE$extradefines;%(PreprocessorDefinitions)"
|
||||
tag_content RuntimeLibrary $runtime
|
||||
tag_content WarningLevel Level3
|
||||
if ${werror:-false}; then
|
||||
tag_content TreatWarningAsError true
|
||||
fi
|
||||
if [ $vs_ver -ge 11 ]; then
|
||||
# We need to override the defaults for these settings
|
||||
# if AppContainerApplication is set.
|
||||
tag_content CompileAsWinRT false
|
||||
tag_content PrecompiledHeader NotUsing
|
||||
tag_content SDLCheck false
|
||||
fi
|
||||
close_tag ClCompile
|
||||
case "$proj_kind" in
|
||||
exe)
|
||||
open_tag Link
|
||||
tag_content GenerateDebugInformation true
|
||||
# Console is the default normally, but if
|
||||
# AppContainerApplication is set, we need to override it.
|
||||
tag_content SubSystem Console
|
||||
close_tag Link
|
||||
;;
|
||||
dll)
|
||||
open_tag Link
|
||||
tag_content GenerateDebugInformation true
|
||||
tag_content ModuleDefinitionFile $module_def
|
||||
close_tag Link
|
||||
;;
|
||||
lib)
|
||||
;;
|
||||
esac
|
||||
close_tag ItemDefinitionGroup
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
open_tag ItemGroup
|
||||
generate_filter "Source Files" "c;cc;cpp;def;odl;idl;hpj;bat;asm;asmx;s;S"
|
||||
close_tag ItemGroup
|
||||
open_tag ItemGroup
|
||||
generate_filter "Header Files" "h;hm;inl;inc;xsd"
|
||||
close_tag ItemGroup
|
||||
open_tag ItemGroup
|
||||
generate_filter "Build Files" "mk"
|
||||
close_tag ItemGroup
|
||||
open_tag ItemGroup
|
||||
generate_filter "References" "vcxproj"
|
||||
close_tag ItemGroup
|
||||
|
||||
tag Import \
|
||||
Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets"
|
||||
|
||||
open_tag ImportGroup \
|
||||
Label="ExtensionTargets"
|
||||
close_tag ImportGroup
|
||||
|
||||
close_tag Project
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# This regexp doesn't catch most of the strings in the vcxproj format,
|
||||
# since they're like <tag>path</tag> instead of <tag attr="path" />
|
||||
# as previously. It still seems to work ok despite this.
|
||||
generate_vcxproj |
|
||||
sed -e '/"/s;\([^ "]\)/;\1\\;g' |
|
||||
sed -e '/xmlns/s;\\;/;g' > ${outfile}
|
||||
|
||||
exit
|
@ -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>
|
@ -1,383 +0,0 @@
|
||||
#!/bin/sh
|
||||
##
|
||||
## Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||
##
|
||||
## Use of this source code is governed by a BSD-style license
|
||||
## that can be found in the LICENSE file in the root of the source
|
||||
## tree. An additional intellectual property rights grant can be found
|
||||
## in the file PATENTS. All contributing project authors may
|
||||
## be found in the AUTHORS file in the root of the source tree.
|
||||
##
|
||||
##
|
||||
## This script generates 'VPX.framework'. An iOS app can encode and decode VPx
|
||||
## video by including 'VPX.framework'.
|
||||
##
|
||||
## Run iosbuild.sh to create 'VPX.framework' in the current directory.
|
||||
##
|
||||
set -e
|
||||
devnull='> /dev/null 2>&1'
|
||||
|
||||
BUILD_ROOT="_iosbuild"
|
||||
CONFIGURE_ARGS="--disable-docs
|
||||
--disable-examples
|
||||
--disable-libyuv
|
||||
--disable-unit-tests"
|
||||
DIST_DIR="_dist"
|
||||
FRAMEWORK_DIR="VPX.framework"
|
||||
FRAMEWORK_LIB="VPX.framework/VPX"
|
||||
HEADER_DIR="${FRAMEWORK_DIR}/Headers/vpx"
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
LIBVPX_SOURCE_DIR=$(cd ${SCRIPT_DIR}/../..; pwd)
|
||||
LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo)
|
||||
ORIG_PWD="$(pwd)"
|
||||
ARM_TARGETS="arm64-darwin-gcc
|
||||
armv7-darwin-gcc
|
||||
armv7s-darwin-gcc"
|
||||
SIM_TARGETS="x86-iphonesimulator-gcc
|
||||
x86_64-iphonesimulator-gcc"
|
||||
OSX_TARGETS="x86-darwin16-gcc
|
||||
x86_64-darwin16-gcc"
|
||||
TARGETS="${ARM_TARGETS} ${SIM_TARGETS}"
|
||||
|
||||
# Configures for the target specified by $1, and invokes make with the dist
|
||||
# target using $DIST_DIR as the distribution output directory.
|
||||
build_target() {
|
||||
local target="$1"
|
||||
local old_pwd="$(pwd)"
|
||||
local target_specific_flags=""
|
||||
|
||||
vlog "***Building target: ${target}***"
|
||||
|
||||
case "${target}" in
|
||||
x86-*)
|
||||
target_specific_flags="--enable-pic"
|
||||
vlog "Enabled PIC for ${target}"
|
||||
;;
|
||||
esac
|
||||
|
||||
mkdir "${target}"
|
||||
cd "${target}"
|
||||
eval "${LIBVPX_SOURCE_DIR}/configure" --target="${target}" \
|
||||
${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS} ${target_specific_flags} \
|
||||
${devnull}
|
||||
export DIST_DIR
|
||||
eval make dist ${devnull}
|
||||
cd "${old_pwd}"
|
||||
|
||||
vlog "***Done building target: ${target}***"
|
||||
}
|
||||
|
||||
# Returns the preprocessor symbol for the target specified by $1.
|
||||
target_to_preproc_symbol() {
|
||||
target="$1"
|
||||
case "${target}" in
|
||||
arm64-*)
|
||||
echo "__aarch64__"
|
||||
;;
|
||||
armv7-*)
|
||||
echo "__ARM_ARCH_7A__"
|
||||
;;
|
||||
armv7s-*)
|
||||
echo "__ARM_ARCH_7S__"
|
||||
;;
|
||||
x86-*)
|
||||
echo "__i386__"
|
||||
;;
|
||||
x86_64-*)
|
||||
echo "__x86_64__"
|
||||
;;
|
||||
*)
|
||||
echo "#error ${target} unknown/unsupported"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Create a vpx_config.h shim that, based on preprocessor settings for the
|
||||
# current target CPU, includes the real vpx_config.h for the current target.
|
||||
# $1 is the list of targets.
|
||||
create_vpx_framework_config_shim() {
|
||||
local targets="$1"
|
||||
local config_file="${HEADER_DIR}/vpx_config.h"
|
||||
local preproc_symbol=""
|
||||
local target=""
|
||||
local include_guard="VPX_FRAMEWORK_HEADERS_VPX_VPX_CONFIG_H_"
|
||||
|
||||
local file_header="/*
|
||||
* Copyright (c) $(date +%Y) The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/* GENERATED FILE: DO NOT EDIT! */
|
||||
|
||||
#ifndef ${include_guard}
|
||||
#define ${include_guard}
|
||||
|
||||
#if defined"
|
||||
|
||||
printf "%s" "${file_header}" > "${config_file}"
|
||||
for target in ${targets}; do
|
||||
preproc_symbol=$(target_to_preproc_symbol "${target}")
|
||||
printf " ${preproc_symbol}\n" >> "${config_file}"
|
||||
printf "#define VPX_FRAMEWORK_TARGET \"${target}\"\n" >> "${config_file}"
|
||||
printf "#include \"VPX/vpx/${target}/vpx_config.h\"\n" >> "${config_file}"
|
||||
printf "#elif defined" >> "${config_file}"
|
||||
mkdir "${HEADER_DIR}/${target}"
|
||||
cp -p "${BUILD_ROOT}/${target}/vpx_config.h" "${HEADER_DIR}/${target}"
|
||||
done
|
||||
|
||||
# Consume the last line of output from the loop: We don't want it.
|
||||
sed -i '' -e '$d' "${config_file}"
|
||||
|
||||
printf "#endif\n\n" >> "${config_file}"
|
||||
printf "#endif // ${include_guard}" >> "${config_file}"
|
||||
}
|
||||
|
||||
# Verifies that $FRAMEWORK_LIB fat library contains requested builds.
|
||||
verify_framework_targets() {
|
||||
local requested_cpus=""
|
||||
local cpu=""
|
||||
|
||||
# Extract CPU from full target name.
|
||||
for target; do
|
||||
cpu="${target%%-*}"
|
||||
if [ "${cpu}" = "x86" ]; then
|
||||
# lipo -info outputs i386 for libvpx x86 targets.
|
||||
cpu="i386"
|
||||
fi
|
||||
requested_cpus="${requested_cpus}${cpu} "
|
||||
done
|
||||
|
||||
# Get target CPUs present in framework library.
|
||||
local targets_built=$(${LIPO} -info ${FRAMEWORK_LIB})
|
||||
|
||||
# $LIPO -info outputs a string like the following:
|
||||
# Architectures in the fat file: $FRAMEWORK_LIB <architectures>
|
||||
# Capture only the architecture strings.
|
||||
targets_built=${targets_built##*: }
|
||||
|
||||
# Sort CPU strings to make the next step a simple string compare.
|
||||
local actual=$(echo ${targets_built} | tr " " "\n" | sort | tr "\n" " ")
|
||||
local requested=$(echo ${requested_cpus} | tr " " "\n" | sort | tr "\n" " ")
|
||||
|
||||
vlog "Requested ${FRAMEWORK_LIB} CPUs: ${requested}"
|
||||
vlog "Actual ${FRAMEWORK_LIB} CPUs: ${actual}"
|
||||
|
||||
if [ "${requested}" != "${actual}" ]; then
|
||||
elog "Actual ${FRAMEWORK_LIB} targets do not match requested target list."
|
||||
elog " Requested target CPUs: ${requested}"
|
||||
elog " Actual target CPUs: ${actual}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Configures and builds each target specified by $1, and then builds
|
||||
# VPX.framework.
|
||||
build_framework() {
|
||||
local lib_list=""
|
||||
local targets="$1"
|
||||
local target=""
|
||||
local target_dist_dir=""
|
||||
|
||||
# Clean up from previous build(s).
|
||||
rm -rf "${BUILD_ROOT}" "${FRAMEWORK_DIR}"
|
||||
|
||||
# Create output dirs.
|
||||
mkdir -p "${BUILD_ROOT}"
|
||||
mkdir -p "${HEADER_DIR}"
|
||||
|
||||
cd "${BUILD_ROOT}"
|
||||
|
||||
for target in ${targets}; do
|
||||
build_target "${target}"
|
||||
target_dist_dir="${BUILD_ROOT}/${target}/${DIST_DIR}"
|
||||
if [ "${ENABLE_SHARED}" = "yes" ]; then
|
||||
local suffix="dylib"
|
||||
else
|
||||
local suffix="a"
|
||||
fi
|
||||
lib_list="${lib_list} ${target_dist_dir}/lib/libvpx.${suffix}"
|
||||
done
|
||||
|
||||
cd "${ORIG_PWD}"
|
||||
|
||||
# The basic libvpx API includes are all the same; just grab the most recent
|
||||
# set.
|
||||
cp -p "${target_dist_dir}"/include/vpx/* "${HEADER_DIR}"
|
||||
|
||||
# Build the fat library.
|
||||
${LIPO} -create ${lib_list} -output ${FRAMEWORK_DIR}/VPX
|
||||
|
||||
# Create the vpx_config.h shim that allows usage of vpx_config.h from
|
||||
# within VPX.framework.
|
||||
create_vpx_framework_config_shim "${targets}"
|
||||
|
||||
# Copy in vpx_version.h.
|
||||
cp -p "${BUILD_ROOT}/${target}/vpx_version.h" "${HEADER_DIR}"
|
||||
|
||||
if [ "${ENABLE_SHARED}" = "yes" ]; then
|
||||
# Adjust the dylib's name so dynamic linking in apps works as expected.
|
||||
install_name_tool -id '@rpath/VPX.framework/VPX' ${FRAMEWORK_DIR}/VPX
|
||||
|
||||
# Copy in Info.plist.
|
||||
cat "${SCRIPT_DIR}/ios-Info.plist" \
|
||||
| sed "s/\${FULLVERSION}/${FULLVERSION}/g" \
|
||||
| sed "s/\${VERSION}/${VERSION}/g" \
|
||||
| sed "s/\${IOS_VERSION_MIN}/${IOS_VERSION_MIN}/g" \
|
||||
> "${FRAMEWORK_DIR}/Info.plist"
|
||||
fi
|
||||
|
||||
# Confirm VPX.framework/VPX contains the targets requested.
|
||||
verify_framework_targets ${targets}
|
||||
|
||||
vlog "Created fat library ${FRAMEWORK_LIB} containing:"
|
||||
for lib in ${lib_list}; do
|
||||
vlog " $(echo ${lib} | awk -F / '{print $2, $NF}')"
|
||||
done
|
||||
}
|
||||
|
||||
# Trap function. Cleans up the subtree used to build all targets contained in
|
||||
# $TARGETS.
|
||||
cleanup() {
|
||||
local readonly res=$?
|
||||
cd "${ORIG_PWD}"
|
||||
|
||||
if [ $res -ne 0 ]; then
|
||||
elog "build exited with error ($res)"
|
||||
fi
|
||||
|
||||
if [ "${PRESERVE_BUILD_OUTPUT}" != "yes" ]; then
|
||||
rm -rf "${BUILD_ROOT}"
|
||||
fi
|
||||
}
|
||||
|
||||
print_list() {
|
||||
local indent="$1"
|
||||
shift
|
||||
local list="$@"
|
||||
for entry in ${list}; do
|
||||
echo "${indent}${entry}"
|
||||
done
|
||||
}
|
||||
|
||||
iosbuild_usage() {
|
||||
cat << EOF
|
||||
Usage: ${0##*/} [arguments]
|
||||
--help: Display this message and exit.
|
||||
--enable-shared: Build a dynamic framework for use on iOS 8 or later.
|
||||
--extra-configure-args <args>: Extra args to pass when configuring libvpx.
|
||||
--macosx: Uses darwin16 targets instead of iphonesimulator targets for x86
|
||||
and x86_64. Allows linking to framework when builds target MacOSX
|
||||
instead of iOS.
|
||||
--preserve-build-output: Do not delete the build directory.
|
||||
--show-build-output: Show output from each library build.
|
||||
--targets <targets>: Override default target list. Defaults:
|
||||
$(print_list " " ${TARGETS})
|
||||
--test-link: Confirms all targets can be linked. Functionally identical to
|
||||
passing --enable-examples via --extra-configure-args.
|
||||
--verbose: Output information about the environment and each stage of the
|
||||
build.
|
||||
EOF
|
||||
}
|
||||
|
||||
elog() {
|
||||
echo "${0##*/} failed because: $@" 1>&2
|
||||
}
|
||||
|
||||
vlog() {
|
||||
if [ "${VERBOSE}" = "yes" ]; then
|
||||
echo "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
# Parse the command line.
|
||||
while [ -n "$1" ]; do
|
||||
case "$1" in
|
||||
--extra-configure-args)
|
||||
EXTRA_CONFIGURE_ARGS="$2"
|
||||
shift
|
||||
;;
|
||||
--help)
|
||||
iosbuild_usage
|
||||
exit
|
||||
;;
|
||||
--enable-shared)
|
||||
ENABLE_SHARED=yes
|
||||
;;
|
||||
--preserve-build-output)
|
||||
PRESERVE_BUILD_OUTPUT=yes
|
||||
;;
|
||||
--show-build-output)
|
||||
devnull=
|
||||
;;
|
||||
--test-link)
|
||||
EXTRA_CONFIGURE_ARGS="${EXTRA_CONFIGURE_ARGS} --enable-examples"
|
||||
;;
|
||||
--targets)
|
||||
TARGETS="$2"
|
||||
shift
|
||||
;;
|
||||
--macosx)
|
||||
TARGETS="${ARM_TARGETS} ${OSX_TARGETS}"
|
||||
;;
|
||||
--verbose)
|
||||
VERBOSE=yes
|
||||
;;
|
||||
*)
|
||||
iosbuild_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "${ENABLE_SHARED}" = "yes" ]; then
|
||||
CONFIGURE_ARGS="--enable-shared ${CONFIGURE_ARGS}"
|
||||
fi
|
||||
|
||||
FULLVERSION=$("${SCRIPT_DIR}"/version.sh --bare "${LIBVPX_SOURCE_DIR}")
|
||||
VERSION=$(echo "${FULLVERSION}" | sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+).*$/\1/')
|
||||
|
||||
if [ "$ENABLE_SHARED" = "yes" ]; then
|
||||
IOS_VERSION_OPTIONS="--enable-shared"
|
||||
IOS_VERSION_MIN="8.0"
|
||||
else
|
||||
IOS_VERSION_OPTIONS=""
|
||||
IOS_VERSION_MIN="6.0"
|
||||
fi
|
||||
|
||||
if [ "${VERBOSE}" = "yes" ]; then
|
||||
cat << EOF
|
||||
BUILD_ROOT=${BUILD_ROOT}
|
||||
DIST_DIR=${DIST_DIR}
|
||||
CONFIGURE_ARGS=${CONFIGURE_ARGS}
|
||||
EXTRA_CONFIGURE_ARGS=${EXTRA_CONFIGURE_ARGS}
|
||||
FRAMEWORK_DIR=${FRAMEWORK_DIR}
|
||||
FRAMEWORK_LIB=${FRAMEWORK_LIB}
|
||||
HEADER_DIR=${HEADER_DIR}
|
||||
LIBVPX_SOURCE_DIR=${LIBVPX_SOURCE_DIR}
|
||||
LIPO=${LIPO}
|
||||
MAKEFLAGS=${MAKEFLAGS}
|
||||
ORIG_PWD=${ORIG_PWD}
|
||||
PRESERVE_BUILD_OUTPUT=${PRESERVE_BUILD_OUTPUT}
|
||||
TARGETS="$(print_list "" ${TARGETS})"
|
||||
ENABLE_SHARED=${ENABLE_SHARED}
|
||||
OSX_TARGETS="${OSX_TARGETS}"
|
||||
SIM_TARGETS="${SIM_TARGETS}"
|
||||
SCRIPT_DIR="${SCRIPT_DIR}"
|
||||
FULLVERSION="${FULLVERSION}"
|
||||
VERSION="${VERSION}"
|
||||
IOS_VERSION_MIN="${IOS_VERSION_MIN}"
|
||||
EOF
|
||||
fi
|
||||
|
||||
build_framework "${TARGETS}"
|
||||
echo "Successfully built '${FRAMEWORK_DIR}' for:"
|
||||
print_list "" ${TARGETS}
|
@ -1,123 +0,0 @@
|
||||
#!/bin/bash
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
if [ "$(uname -o 2>/dev/null)" = "Cygwin" ] \
|
||||
&& cygpath --help >/dev/null 2>&1; then
|
||||
FIXPATH='cygpath -m'
|
||||
else
|
||||
FIXPATH='echo_path'
|
||||
fi
|
||||
|
||||
die() {
|
||||
echo "${self_basename}: $@" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
die_unknown(){
|
||||
echo "Unknown option \"$1\"." >&2
|
||||
echo "See ${self_basename} --help for available options." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo_path() {
|
||||
for path; do
|
||||
echo "$path"
|
||||
done
|
||||
}
|
||||
|
||||
# Output one, possibly changed based on the system, path per line.
|
||||
fix_path() {
|
||||
$FIXPATH "$@"
|
||||
}
|
||||
|
||||
# Corrects the paths in file_list in one pass for efficiency.
|
||||
# $1 is the name of the array to be modified.
|
||||
fix_file_list() {
|
||||
if [ "${FIXPATH}" = "echo_path" ] ; then
|
||||
# When used with echo_path, fix_file_list is a no-op. Avoid warning about
|
||||
# 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'
|
||||
array_ref=($files)
|
||||
}
|
||||
|
||||
generate_uuid() {
|
||||
local hex="0123456789ABCDEF"
|
||||
local i
|
||||
local uuid=""
|
||||
local j
|
||||
#93995380-89BD-4b04-88EB-625FBE52EBFB
|
||||
for ((i=0; i<32; i++)); do
|
||||
(( j = $RANDOM % 16 ))
|
||||
uuid="${uuid}${hex:$j:1}"
|
||||
done
|
||||
echo "${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}"
|
||||
}
|
||||
|
||||
indent1=" "
|
||||
indent=""
|
||||
indent_push() {
|
||||
indent="${indent}${indent1}"
|
||||
}
|
||||
indent_pop() {
|
||||
indent="${indent%${indent1}}"
|
||||
}
|
||||
|
||||
tag_attributes() {
|
||||
for opt in "$@"; do
|
||||
optval="${opt#*=}"
|
||||
[ -n "${optval}" ] ||
|
||||
die "Missing attribute value in '$opt' while generating $tag tag"
|
||||
echo "${indent}${opt%%=*}=\"${optval}\""
|
||||
done
|
||||
}
|
||||
|
||||
open_tag() {
|
||||
local tag=$1
|
||||
shift
|
||||
if [ $# -ne 0 ]; then
|
||||
echo "${indent}<${tag}"
|
||||
indent_push
|
||||
tag_attributes "$@"
|
||||
echo "${indent}>"
|
||||
else
|
||||
echo "${indent}<${tag}>"
|
||||
indent_push
|
||||
fi
|
||||
}
|
||||
|
||||
close_tag() {
|
||||
local tag=$1
|
||||
indent_pop
|
||||
echo "${indent}</${tag}>"
|
||||
}
|
||||
|
||||
tag() {
|
||||
local tag=$1
|
||||
shift
|
||||
if [ $# -ne 0 ]; then
|
||||
echo "${indent}<${tag}"
|
||||
indent_push
|
||||
tag_attributes "$@"
|
||||
indent_pop
|
||||
echo "${indent}/>"
|
||||
else
|
||||
echo "${indent}<${tag}/>"
|
||||
fi
|
||||
}
|
||||
|
@ -1,468 +0,0 @@
|
||||
#!/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';
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
Getopt::Long::Configure("auto_help") if $Getopt::Long::VERSION > 2.32;
|
||||
|
||||
my %ALL_FUNCS = ();
|
||||
my @ALL_ARCHS;
|
||||
my @ALL_FORWARD_DECLS;
|
||||
my @REQUIRES;
|
||||
|
||||
my %opts = ();
|
||||
my %disabled = ();
|
||||
my %required = ();
|
||||
|
||||
my @argv;
|
||||
foreach (@ARGV) {
|
||||
$disabled{$1} = 1, next if /--disable-(.*)/;
|
||||
$required{$1} = 1, next if /--require-(.*)/;
|
||||
push @argv, $_;
|
||||
}
|
||||
|
||||
# NB: use GetOptions() instead of GetOptionsFromArray() for compatibility.
|
||||
@ARGV = @argv;
|
||||
GetOptions(
|
||||
\%opts,
|
||||
'arch=s',
|
||||
'sym=s',
|
||||
'config=s',
|
||||
);
|
||||
|
||||
foreach my $opt (qw/arch config/) {
|
||||
if (!defined($opts{$opt})) {
|
||||
warn "--$opt is required!\n";
|
||||
Getopt::Long::HelpMessage('-exit' => 1);
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $defs_file (@ARGV) {
|
||||
if (!-f $defs_file) {
|
||||
warn "$defs_file: $!\n";
|
||||
Getopt::Long::HelpMessage('-exit' => 1);
|
||||
}
|
||||
}
|
||||
|
||||
open CONFIG_FILE, $opts{config} or
|
||||
die "Error opening config file '$opts{config}': $!\n";
|
||||
|
||||
my %config = ();
|
||||
while (<CONFIG_FILE>) {
|
||||
next if !/^(?:CONFIG_|HAVE_)/;
|
||||
chomp;
|
||||
my @pair = split /=/;
|
||||
$config{$pair[0]} = $pair[1];
|
||||
}
|
||||
close CONFIG_FILE;
|
||||
|
||||
#
|
||||
# Routines for the RTCD DSL to call
|
||||
#
|
||||
sub vpx_config($) {
|
||||
return (defined $config{$_[0]}) ? $config{$_[0]} : "";
|
||||
}
|
||||
|
||||
sub specialize {
|
||||
my $fn=$_[0];
|
||||
shift;
|
||||
foreach my $opt (@_) {
|
||||
eval "\$${fn}_${opt}=${fn}_${opt}";
|
||||
}
|
||||
}
|
||||
|
||||
sub add_proto {
|
||||
my $fn = splice(@_, -2, 1);
|
||||
$ALL_FUNCS{$fn} = \@_;
|
||||
specialize $fn, "c";
|
||||
}
|
||||
|
||||
sub require {
|
||||
foreach my $fn (keys %ALL_FUNCS) {
|
||||
foreach my $opt (@_) {
|
||||
my $ofn = eval "\$${fn}_${opt}";
|
||||
next if !$ofn;
|
||||
|
||||
# if we already have a default, then we can disable it, as we know
|
||||
# we can do better.
|
||||
my $best = eval "\$${fn}_default";
|
||||
if ($best) {
|
||||
my $best_ofn = eval "\$${best}";
|
||||
if ($best_ofn && "$best_ofn" ne "$ofn") {
|
||||
eval "\$${best}_link = 'false'";
|
||||
}
|
||||
}
|
||||
eval "\$${fn}_default=${fn}_${opt}";
|
||||
eval "\$${fn}_${opt}_link='true'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub forward_decls {
|
||||
push @ALL_FORWARD_DECLS, @_;
|
||||
}
|
||||
|
||||
#
|
||||
# Include the user's directives
|
||||
#
|
||||
foreach my $f (@ARGV) {
|
||||
open FILE, "<", $f or die "cannot open $f: $!\n";
|
||||
my $contents = join('', <FILE>);
|
||||
close FILE;
|
||||
eval $contents or warn "eval failed: $@\n";
|
||||
}
|
||||
|
||||
#
|
||||
# Process the directives according to the command line
|
||||
#
|
||||
sub process_forward_decls() {
|
||||
foreach (@ALL_FORWARD_DECLS) {
|
||||
$_->();
|
||||
}
|
||||
}
|
||||
|
||||
sub determine_indirection {
|
||||
vpx_config("CONFIG_RUNTIME_CPU_DETECT") eq "yes" or &require(@ALL_ARCHS);
|
||||
foreach my $fn (keys %ALL_FUNCS) {
|
||||
my $n = "";
|
||||
my @val = @{$ALL_FUNCS{$fn}};
|
||||
my $args = pop @val;
|
||||
my $rtyp = "@val";
|
||||
my $dfn = eval "\$${fn}_default";
|
||||
$dfn = eval "\$${dfn}";
|
||||
foreach my $opt (@_) {
|
||||
my $ofn = eval "\$${fn}_${opt}";
|
||||
next if !$ofn;
|
||||
my $link = eval "\$${fn}_${opt}_link";
|
||||
next if $link && $link eq "false";
|
||||
$n .= "x";
|
||||
}
|
||||
if ($n eq "x") {
|
||||
eval "\$${fn}_indirect = 'false'";
|
||||
} else {
|
||||
eval "\$${fn}_indirect = 'true'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub declare_function_pointers {
|
||||
foreach my $fn (sort keys %ALL_FUNCS) {
|
||||
my @val = @{$ALL_FUNCS{$fn}};
|
||||
my $args = pop @val;
|
||||
my $rtyp = "@val";
|
||||
my $dfn = eval "\$${fn}_default";
|
||||
$dfn = eval "\$${dfn}";
|
||||
foreach my $opt (@_) {
|
||||
my $ofn = eval "\$${fn}_${opt}";
|
||||
next if !$ofn;
|
||||
print "$rtyp ${ofn}($args);\n";
|
||||
}
|
||||
if (eval "\$${fn}_indirect" eq "false") {
|
||||
print "#define ${fn} ${dfn}\n";
|
||||
} else {
|
||||
print "RTCD_EXTERN $rtyp (*${fn})($args);\n";
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub set_function_pointers {
|
||||
foreach my $fn (sort keys %ALL_FUNCS) {
|
||||
my @val = @{$ALL_FUNCS{$fn}};
|
||||
my $args = pop @val;
|
||||
my $rtyp = "@val";
|
||||
my $dfn = eval "\$${fn}_default";
|
||||
$dfn = eval "\$${dfn}";
|
||||
if (eval "\$${fn}_indirect" eq "true") {
|
||||
print " $fn = $dfn;\n";
|
||||
foreach my $opt (@_) {
|
||||
my $ofn = eval "\$${fn}_${opt}";
|
||||
next if !$ofn;
|
||||
next if "$ofn" eq "$dfn";
|
||||
my $link = eval "\$${fn}_${opt}_link";
|
||||
next if $link && $link eq "false";
|
||||
my $cond = eval "\$have_${opt}";
|
||||
print " if (${cond}) $fn = $ofn;\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub filter {
|
||||
my @filtered;
|
||||
foreach (@_) { push @filtered, $_ unless $disabled{$_}; }
|
||||
return @filtered;
|
||||
}
|
||||
|
||||
#
|
||||
# Helper functions for generating the arch specific RTCD files
|
||||
#
|
||||
sub common_top() {
|
||||
my $include_guard = uc($opts{sym})."_H_";
|
||||
print <<EOF;
|
||||
// This file is generated. Do not edit.
|
||||
#ifndef ${include_guard}
|
||||
#define ${include_guard}
|
||||
|
||||
#ifdef RTCD_C
|
||||
#define RTCD_EXTERN
|
||||
#else
|
||||
#define RTCD_EXTERN extern
|
||||
#endif
|
||||
|
||||
EOF
|
||||
|
||||
process_forward_decls();
|
||||
print <<EOF;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
EOF
|
||||
declare_function_pointers("c", @ALL_ARCHS);
|
||||
|
||||
print <<EOF;
|
||||
void $opts{sym}(void);
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
sub common_bottom() {
|
||||
print <<EOF;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
EOF
|
||||
}
|
||||
|
||||
sub x86() {
|
||||
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;
|
||||
#ifdef RTCD_C
|
||||
#include "vpx_ports/x86.h"
|
||||
static void setup_rtcd_internal(void)
|
||||
{
|
||||
int flags = x86_simd_caps();
|
||||
|
||||
(void)flags;
|
||||
|
||||
EOF
|
||||
|
||||
set_function_pointers("c", @ALL_ARCHS);
|
||||
|
||||
print <<EOF;
|
||||
}
|
||||
#endif
|
||||
EOF
|
||||
common_bottom;
|
||||
}
|
||||
|
||||
sub arm() {
|
||||
determine_indirection("c", @ALL_ARCHS);
|
||||
|
||||
# Assign the helper variable for each enabled extension
|
||||
foreach my $opt (@ALL_ARCHS) {
|
||||
my $opt_uc = uc $opt;
|
||||
# Enable neon assembly based on HAVE_NEON logic instead of adding new
|
||||
# HAVE_NEON_ASM logic
|
||||
if ($opt eq 'neon_asm') { $opt_uc = 'NEON' }
|
||||
eval "\$have_${opt}=\"flags & HAS_${opt_uc}\"";
|
||||
}
|
||||
|
||||
common_top;
|
||||
print <<EOF;
|
||||
#include "vpx_config.h"
|
||||
|
||||
#ifdef RTCD_C
|
||||
#include "vpx_ports/arm.h"
|
||||
static void setup_rtcd_internal(void)
|
||||
{
|
||||
int flags = arm_cpu_caps();
|
||||
|
||||
(void)flags;
|
||||
|
||||
EOF
|
||||
|
||||
set_function_pointers("c", @ALL_ARCHS);
|
||||
|
||||
print <<EOF;
|
||||
}
|
||||
#endif
|
||||
EOF
|
||||
common_bottom;
|
||||
}
|
||||
|
||||
sub mips() {
|
||||
determine_indirection("c", @ALL_ARCHS);
|
||||
common_top;
|
||||
|
||||
print <<EOF;
|
||||
#include "vpx_config.h"
|
||||
|
||||
#ifdef RTCD_C
|
||||
static void setup_rtcd_internal(void)
|
||||
{
|
||||
EOF
|
||||
|
||||
set_function_pointers("c", @ALL_ARCHS);
|
||||
|
||||
print <<EOF;
|
||||
#if HAVE_DSPR2
|
||||
void vpx_dsputil_static_init();
|
||||
#if CONFIG_VP8
|
||||
void dsputil_static_init();
|
||||
#endif
|
||||
|
||||
vpx_dsputil_static_init();
|
||||
#if CONFIG_VP8
|
||||
dsputil_static_init();
|
||||
#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
|
||||
EOF
|
||||
common_bottom;
|
||||
}
|
||||
|
||||
sub unoptimized() {
|
||||
determine_indirection "c";
|
||||
common_top;
|
||||
print <<EOF;
|
||||
#include "vpx_config.h"
|
||||
|
||||
#ifdef RTCD_C
|
||||
static void setup_rtcd_internal(void)
|
||||
{
|
||||
EOF
|
||||
|
||||
set_function_pointers "c";
|
||||
|
||||
print <<EOF;
|
||||
}
|
||||
#endif
|
||||
EOF
|
||||
common_bottom;
|
||||
}
|
||||
|
||||
#
|
||||
# Main Driver
|
||||
#
|
||||
|
||||
&require("c");
|
||||
if ($opts{arch} eq 'x86') {
|
||||
@ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2 avx512/);
|
||||
x86;
|
||||
} elsif ($opts{arch} eq 'x86_64') {
|
||||
@ALL_ARCHS = filter(qw/mmx sse sse2 sse3 ssse3 sse4_1 avx avx2 avx512/);
|
||||
@REQUIRES = filter(keys %required ? keys %required : qw/mmx sse sse2/);
|
||||
&require(@REQUIRES);
|
||||
x86;
|
||||
} elsif ($opts{arch} eq 'mips32' || $opts{arch} eq 'mips64') {
|
||||
@ALL_ARCHS = filter("$opts{arch}");
|
||||
open CONFIG_FILE, $opts{config} or
|
||||
die "Error opening config file '$opts{config}': $!\n";
|
||||
while (<CONFIG_FILE>) {
|
||||
if (/HAVE_DSPR2=yes/) {
|
||||
@ALL_ARCHS = filter("$opts{arch}", qw/dspr2/);
|
||||
last;
|
||||
}
|
||||
if (/HAVE_MSA=yes/) {
|
||||
@ALL_ARCHS = filter("$opts{arch}", qw/msa/);
|
||||
last;
|
||||
}
|
||||
if (/HAVE_MMI=yes/) {
|
||||
@ALL_ARCHS = filter("$opts{arch}", qw/mmi/);
|
||||
last;
|
||||
}
|
||||
}
|
||||
close CONFIG_FILE;
|
||||
mips;
|
||||
} elsif ($opts{arch} =~ /armv7\w?/) {
|
||||
@ALL_ARCHS = filter(qw/neon_asm neon/);
|
||||
arm;
|
||||
} elsif ($opts{arch} eq 'armv8' || $opts{arch} eq 'arm64' ) {
|
||||
@ALL_ARCHS = filter(qw/neon/);
|
||||
arm;
|
||||
} elsif ($opts{arch} =~ /^ppc/ ) {
|
||||
@ALL_ARCHS = filter(qw/vsx/);
|
||||
ppc;
|
||||
} else {
|
||||
unoptimized;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
rtcd -
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
Usage: rtcd.pl [options] FILE
|
||||
|
||||
See 'perldoc rtcd.pl' for more details.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Reads the Run Time CPU Detections definitions from FILE and generates a
|
||||
C header file on stdout.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
Options:
|
||||
--arch=ARCH Architecture to generate defs for (required)
|
||||
--disable-EXT Disable support for EXT extensions
|
||||
--require-EXT Require support for EXT extensions
|
||||
--sym=SYMBOL Unique symbol to use for RTCD initialization function
|
||||
--config=FILE File with CONFIG_FOO=yes lines to parse
|
@ -1,63 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
##
|
||||
## Copyright (c) 2013 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.
|
||||
##
|
||||
|
||||
package thumb;
|
||||
|
||||
sub FixThumbInstructions($$)
|
||||
{
|
||||
my $short_branches = $_[1];
|
||||
my $branch_shift_offset = $short_branches ? 1 : 0;
|
||||
|
||||
# Write additions with shifts, such as "add r10, r11, lsl #8",
|
||||
# in three operand form, "add r10, r10, r11, lsl #8".
|
||||
s/(add\s+)(r\d+),\s*(r\d+),\s*(lsl #\d+)/$1$2, $2, $3, $4/g;
|
||||
|
||||
# Convert additions with a non-constant shift into a sequence
|
||||
# with left shift, addition and a right shift (to restore the
|
||||
# register to the original value). Currently the right shift
|
||||
# isn't necessary in the code base since the values in these
|
||||
# registers aren't used, but doing the shift for consistency.
|
||||
# This converts instructions such as "add r12, r12, r5, lsl r4"
|
||||
# into the sequence "lsl r5, r4", "add r12, r12, r5", "lsr r5, r4".
|
||||
s/^(\s*)(add)(\s+)(r\d+),\s*(r\d+),\s*(r\d+),\s*lsl (r\d+)/$1lsl$3$6, $7\n$1$2$3$4, $5, $6\n$1lsr$3$6, $7/g;
|
||||
|
||||
# Convert loads with right shifts in the indexing into a
|
||||
# sequence of an add, load and sub. This converts
|
||||
# "ldrb r4, [r9, lr, asr #1]" into "add r9, r9, lr, asr #1",
|
||||
# "ldrb r9, [r9]", "sub r9, r9, lr, asr #1".
|
||||
s/^(\s*)(ldrb)(\s+)(r\d+),\s*\[(\w+),\s*(\w+),\s*(asr #\d+)\]/$1add $3$5, $5, $6, $7\n$1$2$3$4, [$5]\n$1sub $3$5, $5, $6, $7/g;
|
||||
|
||||
# Convert register indexing with writeback into a separate add
|
||||
# instruction. This converts "ldrb r12, [r1, r2]!" into
|
||||
# "ldrb r12, [r1, r2]", "add r1, r1, r2".
|
||||
s/^(\s*)(ldrb)(\s+)(r\d+),\s*\[(\w+),\s*(\w+)\]!/$1$2$3$4, [$5, $6]\n$1add $3$5, $6/g;
|
||||
|
||||
# Convert negative register indexing into separate sub/add instructions.
|
||||
# This converts "ldrne r4, [src, -pstep, lsl #1]" into
|
||||
# "subne src, src, pstep, lsl #1", "ldrne r4, [src]",
|
||||
# "addne src, src, pstep, lsl #1". In a couple of cases where
|
||||
# this is used, it's used for two subsequent load instructions,
|
||||
# where a hand-written version of it could merge two subsequent
|
||||
# add and sub instructions.
|
||||
s/^(\s*)((ldr|str|pld)(ne)?)(\s+)(r\d+,\s*)?\[(\w+), -([^\]]+)\]/$1sub$4$5$7, $7, $8\n$1$2$5$6\[$7\]\n$1add$4$5$7, $7, $8/g;
|
||||
|
||||
# Convert register post indexing to a separate add instruction.
|
||||
# This converts "ldrneb r9, [r0], r2" into "ldrneb r9, [r0]",
|
||||
# "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;
|
||||
|
||||
# Convert "mov pc, lr" into "bx lr", since the former only works
|
||||
# for switching from arm to thumb (and only in armv7), but not
|
||||
# from thumb to arm.
|
||||
s/mov(\s*)pc\s*,\s*lr/bx$1lr/g;
|
||||
}
|
||||
|
||||
1;
|
@ -1,78 +0,0 @@
|
||||
#!/bin/sh
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
|
||||
|
||||
for opt in "$@"; do
|
||||
optval="${opt#*=}"
|
||||
case "$opt" in
|
||||
--bare) bare=true ;;
|
||||
*) break ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
source_path=${1:-.}
|
||||
out_file=${2}
|
||||
id=${3:-VERSION_STRING}
|
||||
|
||||
git_version_id=""
|
||||
if [ -e "${source_path}/.git" ]; then
|
||||
# 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"
|
||||
git_version_id=`git describe --match=v[0-9]* 2>/dev/null`
|
||||
fi
|
||||
|
||||
changelog_version=""
|
||||
for p in "${source_path}" "${source_path}/.."; do
|
||||
if [ -z "$git_version_id" -a -f "${p}/CHANGELOG" ]; then
|
||||
changelog_version=`head -n1 "${p}/CHANGELOG" | awk '{print $2}'`
|
||||
changelog_version="${changelog_version}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
version_str="${changelog_version}${git_version_id}"
|
||||
bare_version=${version_str#v}
|
||||
major_version=${bare_version%%.*}
|
||||
bare_version=${bare_version#*.}
|
||||
minor_version=${bare_version%%.*}
|
||||
bare_version=${bare_version#*.}
|
||||
patch_version=${bare_version%%-*}
|
||||
bare_version=${bare_version#${patch_version}}
|
||||
extra_version=${bare_version##-}
|
||||
|
||||
#since they'll be used as integers below make sure they are or force to 0
|
||||
for v in major_version minor_version patch_version; do
|
||||
if eval echo \$$v |grep -E -q '[^[:digit:]]'; then
|
||||
eval $v=0
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${bare} ]; then
|
||||
echo "${changelog_version}${git_version_id}" > $$.tmp
|
||||
else
|
||||
cat<<EOF>$$.tmp
|
||||
// This file is generated. Do not edit.
|
||||
#define VERSION_MAJOR $major_version
|
||||
#define VERSION_MINOR $minor_version
|
||||
#define VERSION_PATCH $patch_version
|
||||
#define VERSION_EXTRA "$extra_version"
|
||||
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||
#define ${id}_NOSP "${version_str}"
|
||||
#define ${id} " ${version_str}"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$out_file" ]; then
|
||||
diff $$.tmp ${out_file} >/dev/null 2>&1 || cat $$.tmp > ${out_file}
|
||||
else
|
||||
cat $$.tmp
|
||||
fi
|
||||
rm $$.tmp
|
@ -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
|
755
configure
vendored
755
configure
vendored
@ -1,755 +0,0 @@
|
||||
#!/bin/sh
|
||||
##
|
||||
## configure
|
||||
##
|
||||
## This script is the front-end to the build system. It provides a similar
|
||||
## interface to standard configure scripts with some extra bits for dealing
|
||||
## with toolchains that differ from the standard POSIX interface and
|
||||
## for extracting subsets of the source tree. In theory, reusable parts
|
||||
## of this script were intended to live in build/make/configure.sh,
|
||||
## but in practice, the line is pretty blurry.
|
||||
##
|
||||
## This build system is based in part on the FFmpeg configure script.
|
||||
##
|
||||
|
||||
#source_path="`dirname \"$0\"`"
|
||||
source_path=${0%/*}
|
||||
. "${source_path}/build/make/configure.sh"
|
||||
|
||||
show_help(){
|
||||
show_help_pre
|
||||
cat << EOF
|
||||
Advanced options:
|
||||
${toggle_libs} libraries
|
||||
${toggle_examples} examples
|
||||
${toggle_tools} tools
|
||||
${toggle_docs} documentation
|
||||
${toggle_unit_tests} unit tests
|
||||
${toggle_decode_perf_tests} build decoder perf tests with unit tests
|
||||
${toggle_encode_perf_tests} build encoder perf tests with unit tests
|
||||
--cpu=CPU tune for the specified CPU (ARM: cortex-a8, X86: sse3)
|
||||
--libc=PATH path to alternate libc
|
||||
--size-limit=WxH max size to allow in the decoder
|
||||
--as={yasm|nasm|auto} use specified assembler [auto, yasm preferred]
|
||||
--sdk-path=PATH path to root of sdk (android builds only)
|
||||
${toggle_codec_srcs} in/exclude codec library source code
|
||||
${toggle_debug_libs} in/exclude debug version of libraries
|
||||
${toggle_static_msvcrt} use static MSVCRT (VS builds only)
|
||||
${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_vp9} VP9 codec support
|
||||
${toggle_internal_stats} output of encoder internal stats for debug, if supported (encoders)
|
||||
${toggle_postproc} postprocessing
|
||||
${toggle_vp9_postproc} vp9 specific postprocessing
|
||||
${toggle_multithread} multithreaded encoding and decoding
|
||||
${toggle_spatial_resampling} spatial sampling (scaling) support
|
||||
${toggle_realtime_only} enable this option while building for real-time encoding
|
||||
${toggle_onthefly_bitpacking} enable on-the-fly bitpacking in real-time encoding
|
||||
${toggle_error_concealment} enable this option to get a decoder which is able to conceal losses
|
||||
${toggle_coefficient_range_checking}
|
||||
enable decoder to check if intermediate
|
||||
transform coefficients are in valid range
|
||||
${toggle_runtime_cpu_detect} runtime cpu detection
|
||||
${toggle_shared} shared library support
|
||||
${toggle_static} static library support
|
||||
${toggle_small} favor smaller size over speed
|
||||
${toggle_postproc_visualizer} macro block / block level visualizers
|
||||
${toggle_multi_res_encoding} enable multiple-resolution encoding
|
||||
${toggle_temporal_denoising} enable temporal denoising and disable the spatial denoiser
|
||||
${toggle_vp9_temporal_denoising}
|
||||
enable vp9 temporal denoising
|
||||
${toggle_webm_io} enable input from and output to WebM container
|
||||
${toggle_libyuv} enable libyuv
|
||||
|
||||
Codecs:
|
||||
Codecs can be selectively enabled or disabled individually, or by family:
|
||||
--disable-<codec>
|
||||
is equivalent to:
|
||||
--disable-<codec>-encoder
|
||||
--disable-<codec>-decoder
|
||||
|
||||
Codecs available in this distribution:
|
||||
EOF
|
||||
#restore editor state '
|
||||
|
||||
family="";
|
||||
last_family="";
|
||||
c="";
|
||||
str="";
|
||||
for c in ${CODECS}; do
|
||||
family=${c%_*}
|
||||
if [ "${family}" != "${last_family}" ]; then
|
||||
[ -z "${str}" ] || echo "${str}"
|
||||
str="$(printf ' %10s:' ${family})"
|
||||
fi
|
||||
str="${str} $(printf '%10s' ${c#*_})"
|
||||
last_family=${family}
|
||||
done
|
||||
echo "${str}"
|
||||
show_help_post
|
||||
}
|
||||
|
||||
##
|
||||
## BEGIN APPLICATION SPECIFIC CONFIGURATION
|
||||
##
|
||||
|
||||
# all_platforms is a list of all supported target platforms. Maintain
|
||||
# alphabetically by architecture, generic-gnu last.
|
||||
all_platforms="${all_platforms} arm64-android-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-darwin-gcc" #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-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-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} armv8-linux-gcc"
|
||||
all_platforms="${all_platforms} mips32-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} x86-android-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin8-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin8-icc"
|
||||
all_platforms="${all_platforms} x86-darwin9-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin9-icc"
|
||||
all_platforms="${all_platforms} x86-darwin10-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin11-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin12-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin13-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin14-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin15-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin16-gcc"
|
||||
all_platforms="${all_platforms} x86-darwin17-gcc"
|
||||
all_platforms="${all_platforms} x86-iphonesimulator-gcc"
|
||||
all_platforms="${all_platforms} x86-linux-gcc"
|
||||
all_platforms="${all_platforms} x86-linux-icc"
|
||||
all_platforms="${all_platforms} x86-os2-gcc"
|
||||
all_platforms="${all_platforms} x86-solaris-gcc"
|
||||
all_platforms="${all_platforms} x86-win32-gcc"
|
||||
all_platforms="${all_platforms} x86-win32-vs10"
|
||||
all_platforms="${all_platforms} x86-win32-vs11"
|
||||
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-darwin10-gcc"
|
||||
all_platforms="${all_platforms} x86_64-darwin11-gcc"
|
||||
all_platforms="${all_platforms} x86_64-darwin12-gcc"
|
||||
all_platforms="${all_platforms} x86_64-darwin13-gcc"
|
||||
all_platforms="${all_platforms} x86_64-darwin14-gcc"
|
||||
all_platforms="${all_platforms} x86_64-darwin15-gcc"
|
||||
all_platforms="${all_platforms} x86_64-darwin16-gcc"
|
||||
all_platforms="${all_platforms} x86_64-darwin17-gcc"
|
||||
all_platforms="${all_platforms} x86_64-iphonesimulator-gcc"
|
||||
all_platforms="${all_platforms} x86_64-linux-gcc"
|
||||
all_platforms="${all_platforms} x86_64-linux-icc"
|
||||
all_platforms="${all_platforms} x86_64-solaris-gcc"
|
||||
all_platforms="${all_platforms} x86_64-win64-gcc"
|
||||
all_platforms="${all_platforms} x86_64-win64-vs10"
|
||||
all_platforms="${all_platforms} x86_64-win64-vs11"
|
||||
all_platforms="${all_platforms} x86_64-win64-vs12"
|
||||
all_platforms="${all_platforms} x86_64-win64-vs14"
|
||||
all_platforms="${all_platforms} x86_64-win64-vs15"
|
||||
all_platforms="${all_platforms} generic-gnu"
|
||||
|
||||
# all_targets is a list of all targets that can be configured
|
||||
# note that these should be in dependency order for now.
|
||||
all_targets="libs examples tools docs"
|
||||
|
||||
# all targets available are enabled, by default.
|
||||
for t in ${all_targets}; do
|
||||
[ -f "${source_path}/${t}.mk" ] && enable_feature ${t}
|
||||
done
|
||||
|
||||
if ! diff --version >/dev/null; then
|
||||
die "diff missing: Try installing diffutils via your package manager."
|
||||
fi
|
||||
|
||||
if ! perl --version >/dev/null; then
|
||||
die "Perl is required to build"
|
||||
fi
|
||||
|
||||
if [ "`cd \"${source_path}\" && pwd`" != "`pwd`" ]; then
|
||||
# test to see if source_path already configured
|
||||
if [ -f "${source_path}/vpx_config.h" ]; then
|
||||
die "source directory already configured; run 'make distclean' there first"
|
||||
fi
|
||||
fi
|
||||
|
||||
# check installed doxygen version
|
||||
doxy_version=$(doxygen --version 2>/dev/null)
|
||||
doxy_major=${doxy_version%%.*}
|
||||
if [ ${doxy_major:-0} -ge 1 ]; then
|
||||
doxy_version=${doxy_version#*.}
|
||||
doxy_minor=${doxy_version%%.*}
|
||||
doxy_patch=${doxy_version##*.}
|
||||
|
||||
[ $doxy_major -gt 1 ] && enable_feature doxygen
|
||||
[ $doxy_minor -gt 5 ] && enable_feature doxygen
|
||||
[ $doxy_minor -eq 5 ] && [ $doxy_patch -ge 3 ] && enable_feature doxygen
|
||||
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
|
||||
# to be enabled when doing dist builds, since that's no longer a common
|
||||
# case.
|
||||
enabled doxygen && enable_feature install_docs
|
||||
enable_feature install_bins
|
||||
enable_feature install_libs
|
||||
|
||||
enable_feature static
|
||||
enable_feature optimizations
|
||||
enable_feature dependency_tracking
|
||||
enable_feature spatial_resampling
|
||||
enable_feature multithread
|
||||
enable_feature os_support
|
||||
enable_feature temporal_denoising
|
||||
|
||||
CODECS="
|
||||
vp8_encoder
|
||||
vp8_decoder
|
||||
vp9_encoder
|
||||
vp9_decoder
|
||||
"
|
||||
CODEC_FAMILIES="
|
||||
vp8
|
||||
vp9
|
||||
"
|
||||
|
||||
ARCH_LIST="
|
||||
arm
|
||||
mips
|
||||
x86
|
||||
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="
|
||||
neon
|
||||
neon_asm
|
||||
|
||||
mips32
|
||||
dspr2
|
||||
msa
|
||||
mips64
|
||||
|
||||
${ARCH_EXT_LIST_X86}
|
||||
|
||||
vsx
|
||||
|
||||
${ARCH_EXT_LIST_LOONGSON}
|
||||
"
|
||||
HAVE_LIST="
|
||||
${ARCH_EXT_LIST}
|
||||
vpx_ports
|
||||
pthread_h
|
||||
unistd_h
|
||||
"
|
||||
EXPERIMENT_LIST="
|
||||
fp_mb_stats
|
||||
emulate_hardware
|
||||
"
|
||||
CONFIG_LIST="
|
||||
dependency_tracking
|
||||
external_build
|
||||
install_docs
|
||||
install_bins
|
||||
install_libs
|
||||
install_srcs
|
||||
debug
|
||||
gprof
|
||||
gcov
|
||||
rvct
|
||||
gcc
|
||||
msvs
|
||||
pic
|
||||
big_endian
|
||||
|
||||
codec_srcs
|
||||
debug_libs
|
||||
|
||||
dequant_tokens
|
||||
dc_recon
|
||||
runtime_cpu_detect
|
||||
postproc
|
||||
vp9_postproc
|
||||
multithread
|
||||
internal_stats
|
||||
${CODECS}
|
||||
${CODEC_FAMILIES}
|
||||
encoders
|
||||
decoders
|
||||
static_msvcrt
|
||||
spatial_resampling
|
||||
realtime_only
|
||||
onthefly_bitpacking
|
||||
error_concealment
|
||||
shared
|
||||
static
|
||||
small
|
||||
postproc_visualizer
|
||||
os_support
|
||||
unit_tests
|
||||
webm_io
|
||||
libyuv
|
||||
decode_perf_tests
|
||||
encode_perf_tests
|
||||
multi_res_encoding
|
||||
temporal_denoising
|
||||
vp9_temporal_denoising
|
||||
coefficient_range_checking
|
||||
vp9_highbitdepth
|
||||
better_hw_compatibility
|
||||
experimental
|
||||
size_limit
|
||||
always_adjust_bpm
|
||||
${EXPERIMENT_LIST}
|
||||
"
|
||||
CMDLINE_SELECT="
|
||||
dependency_tracking
|
||||
external_build
|
||||
extra_warnings
|
||||
werror
|
||||
install_docs
|
||||
install_bins
|
||||
install_libs
|
||||
install_srcs
|
||||
debug
|
||||
gprof
|
||||
gcov
|
||||
pic
|
||||
optimizations
|
||||
ccache
|
||||
runtime_cpu_detect
|
||||
thumb
|
||||
|
||||
libs
|
||||
examples
|
||||
tools
|
||||
docs
|
||||
libc
|
||||
as
|
||||
size_limit
|
||||
codec_srcs
|
||||
debug_libs
|
||||
|
||||
dequant_tokens
|
||||
dc_recon
|
||||
postproc
|
||||
vp9_postproc
|
||||
multithread
|
||||
internal_stats
|
||||
${CODECS}
|
||||
${CODEC_FAMILIES}
|
||||
static_msvcrt
|
||||
spatial_resampling
|
||||
realtime_only
|
||||
onthefly_bitpacking
|
||||
error_concealment
|
||||
shared
|
||||
static
|
||||
small
|
||||
postproc_visualizer
|
||||
unit_tests
|
||||
webm_io
|
||||
libyuv
|
||||
decode_perf_tests
|
||||
encode_perf_tests
|
||||
multi_res_encoding
|
||||
temporal_denoising
|
||||
vp9_temporal_denoising
|
||||
coefficient_range_checking
|
||||
better_hw_compatibility
|
||||
vp9_highbitdepth
|
||||
experimental
|
||||
always_adjust_bpm
|
||||
"
|
||||
|
||||
process_cmdline() {
|
||||
for opt do
|
||||
optval="${opt#*=}"
|
||||
case "$opt" in
|
||||
--disable-codecs)
|
||||
for c in ${CODEC_FAMILIES}; do disable_codec $c; done
|
||||
;;
|
||||
--enable-?*|--disable-?*)
|
||||
eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'`
|
||||
if is_in ${option} ${EXPERIMENT_LIST}; then
|
||||
if enabled experimental; then
|
||||
${action}_feature $option
|
||||
else
|
||||
log_echo "Ignoring $opt -- not in experimental mode."
|
||||
fi
|
||||
elif is_in ${option} "${CODECS} ${CODEC_FAMILIES}"; then
|
||||
${action}_codec ${option}
|
||||
else
|
||||
process_common_cmdline $opt
|
||||
fi
|
||||
;;
|
||||
*) process_common_cmdline "$opt"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
post_process_cmdline() {
|
||||
c=""
|
||||
|
||||
# Enable all detected codecs, if they haven't been disabled
|
||||
for c in ${CODECS}; do soft_enable $c; done
|
||||
|
||||
# Enable the codec family if any component of that family is enabled
|
||||
for c in ${CODECS}; do
|
||||
enabled $c && enable_feature ${c%_*}
|
||||
done
|
||||
|
||||
# Set the {en,de}coders variable if any algorithm in that class is enabled
|
||||
for c in ${CODECS}; do
|
||||
enabled ${c} && enable_feature ${c##*_}s
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
process_targets() {
|
||||
enabled child || write_common_config_banner
|
||||
write_common_target_config_h ${BUILD_PFX}vpx_config.h
|
||||
write_common_config_targets
|
||||
|
||||
# Calculate the default distribution name, based on the enabled features
|
||||
cf=""
|
||||
DIST_DIR=vpx
|
||||
for cf in $CODEC_FAMILIES; do
|
||||
if enabled ${cf}_encoder && enabled ${cf}_decoder; then
|
||||
DIST_DIR="${DIST_DIR}-${cf}"
|
||||
elif enabled ${cf}_encoder; then
|
||||
DIST_DIR="${DIST_DIR}-${cf}cx"
|
||||
elif enabled ${cf}_decoder; then
|
||||
DIST_DIR="${DIST_DIR}-${cf}dx"
|
||||
fi
|
||||
done
|
||||
enabled debug_libs && DIST_DIR="${DIST_DIR}-debug"
|
||||
enabled codec_srcs && DIST_DIR="${DIST_DIR}-src"
|
||||
! enabled postproc && ! enabled vp9_postproc && DIST_DIR="${DIST_DIR}-nopost"
|
||||
! enabled multithread && DIST_DIR="${DIST_DIR}-nomt"
|
||||
! enabled install_docs && DIST_DIR="${DIST_DIR}-nodocs"
|
||||
DIST_DIR="${DIST_DIR}-${tgt_isa}-${tgt_os}"
|
||||
case "${tgt_os}" in
|
||||
win*) enabled static_msvcrt && DIST_DIR="${DIST_DIR}mt" || DIST_DIR="${DIST_DIR}md"
|
||||
DIST_DIR="${DIST_DIR}-${tgt_cc}"
|
||||
;;
|
||||
esac
|
||||
if [ -f "${source_path}/build/make/version.sh" ]; then
|
||||
ver=`"$source_path/build/make/version.sh" --bare "$source_path"`
|
||||
DIST_DIR="${DIST_DIR}-${ver}"
|
||||
VERSION_STRING=${ver}
|
||||
ver=${ver%%-*}
|
||||
VERSION_PATCH=${ver##*.}
|
||||
ver=${ver%.*}
|
||||
VERSION_MINOR=${ver##*.}
|
||||
ver=${ver#v}
|
||||
VERSION_MAJOR=${ver%.*}
|
||||
fi
|
||||
enabled child || cat <<EOF >> config.mk
|
||||
|
||||
PREFIX=${prefix}
|
||||
ifeq (\$(MAKECMDGOALS),dist)
|
||||
DIST_DIR?=${DIST_DIR}
|
||||
else
|
||||
DIST_DIR?=\$(DESTDIR)${prefix}
|
||||
endif
|
||||
LIBSUBDIR=${libdir##${prefix}/}
|
||||
|
||||
VERSION_STRING=${VERSION_STRING}
|
||||
|
||||
VERSION_MAJOR=${VERSION_MAJOR}
|
||||
VERSION_MINOR=${VERSION_MINOR}
|
||||
VERSION_PATCH=${VERSION_PATCH}
|
||||
|
||||
CONFIGURE_ARGS=${CONFIGURE_ARGS}
|
||||
EOF
|
||||
enabled child || echo "CONFIGURE_ARGS?=${CONFIGURE_ARGS}" >> config.mk
|
||||
|
||||
#
|
||||
# Write makefiles for all enabled targets
|
||||
#
|
||||
for tgt in libs examples tools docs solution; do
|
||||
tgt_fn="$tgt-$toolchain.mk"
|
||||
|
||||
if enabled $tgt; then
|
||||
echo "Creating makefiles for ${toolchain} ${tgt}"
|
||||
write_common_target_config_mk $tgt_fn ${BUILD_PFX}vpx_config.h
|
||||
#write_${tgt}_config
|
||||
fi
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
process_detect() {
|
||||
if enabled shared; then
|
||||
# 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
|
||||
# magic happens after the command line has been parsed.
|
||||
case "${tgt_os}" in
|
||||
linux|os2|darwin*|iphonesimulator*)
|
||||
# Supported platforms
|
||||
;;
|
||||
*)
|
||||
if enabled gnu; then
|
||||
echo "--enable-shared is only supported on ELF; assuming this is OK"
|
||||
else
|
||||
die "--enable-shared only supported on ELF, OS/2, and Darwin for now"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ -z "$CC" ] || enabled external_build; then
|
||||
echo "Bypassing toolchain for environment detection."
|
||||
enable_feature external_build
|
||||
check_header() {
|
||||
log fake_check_header "$@"
|
||||
header=$1
|
||||
shift
|
||||
var=`echo $header | sed 's/[^A-Za-z0-9_]/_/g'`
|
||||
disable_feature $var
|
||||
# Headers common to all environments
|
||||
case $header in
|
||||
stdio.h)
|
||||
true;
|
||||
;;
|
||||
*)
|
||||
result=false
|
||||
for d in "$@"; do
|
||||
[ -f "${d##-I}/$header" ] && result=true && break
|
||||
done
|
||||
${result:-true}
|
||||
esac && enable_feature $var
|
||||
|
||||
# Specialize windows and POSIX environments.
|
||||
case $toolchain in
|
||||
*-win*-*)
|
||||
# Don't check for any headers in Windows builds.
|
||||
false
|
||||
;;
|
||||
*)
|
||||
case $header in
|
||||
pthread.h) true;;
|
||||
unistd.h) true;;
|
||||
*) false;;
|
||||
esac && enable_feature $var
|
||||
esac
|
||||
enabled $var
|
||||
}
|
||||
check_ld() {
|
||||
true
|
||||
}
|
||||
fi
|
||||
check_header stdio.h || die "Unable to invoke compiler: ${CC} ${CFLAGS}"
|
||||
check_ld <<EOF || die "Toolchain is unable to link executables"
|
||||
int main(void) {return 0;}
|
||||
EOF
|
||||
# check system headers
|
||||
check_header pthread.h
|
||||
check_header unistd.h # for sysconf(3) and friends.
|
||||
|
||||
check_header vpx/vpx_integer.h -I${source_path} && enable_feature vpx_ports
|
||||
}
|
||||
|
||||
process_toolchain() {
|
||||
process_common_toolchain
|
||||
|
||||
# Enable some useful compiler flags
|
||||
if enabled gcc; then
|
||||
enabled werror && check_add_cflags -Werror
|
||||
check_add_cflags -Wall
|
||||
check_add_cflags -Wdeclaration-after-statement
|
||||
check_add_cflags -Wdisabled-optimization
|
||||
check_add_cflags -Wfloat-conversion
|
||||
check_add_cflags -Wparentheses-equality
|
||||
check_add_cflags -Wpointer-arith
|
||||
check_add_cflags -Wtype-limits
|
||||
check_add_cflags -Wcast-qual
|
||||
check_add_cflags -Wvla
|
||||
check_add_cflags -Wimplicit-function-declaration
|
||||
check_add_cflags -Wuninitialized
|
||||
check_add_cflags -Wunused
|
||||
# -Wextra has some tricky cases. Rather than fix them all now, get the
|
||||
# flag for as many files as possible and fix the remaining issues
|
||||
# piecemeal.
|
||||
# https://bugs.chromium.org/p/webm/issues/detail?id=1069
|
||||
check_add_cflags -Wextra
|
||||
# check_add_cflags also adds to cxxflags. gtest does not do well with
|
||||
# these flags so add them explicitly to CFLAGS only.
|
||||
check_cflags -Wundef && add_cflags_only -Wundef
|
||||
check_cflags -Wframe-larger-than=52000 && \
|
||||
add_cflags_only -Wframe-larger-than=52000
|
||||
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
|
||||
|
||||
if enabled icc; then
|
||||
enabled werror && check_add_cflags -Werror
|
||||
check_add_cflags -Wall
|
||||
check_add_cflags -Wpointer-arith
|
||||
|
||||
# ICC has a number of floating point optimizations that we disable
|
||||
# in favor of deterministic output WRT to other compilers
|
||||
add_cflags -fp-model precise
|
||||
fi
|
||||
|
||||
# Enable extra, harmless warnings. These might provide additional insight
|
||||
# to what the compiler is doing and why, but in general, but they shouldn't
|
||||
# be treated as fatal, even if we're treating warnings as errors.
|
||||
GCC_EXTRA_WARNINGS="
|
||||
-Wdisabled-optimization
|
||||
-Winline
|
||||
"
|
||||
enabled gcc && EXTRA_WARNINGS="${GCC_EXTRA_WARNINGS}"
|
||||
RVCT_EXTRA_WARNINGS="
|
||||
--remarks
|
||||
"
|
||||
enabled rvct && EXTRA_WARNINGS="${RVCT_EXTRA_WARNINGS}"
|
||||
if enabled extra_warnings; then
|
||||
for w in ${EXTRA_WARNINGS}; do
|
||||
check_add_cflags ${w}
|
||||
enabled gcc && enabled werror && check_add_cflags -Wno-error=${w}
|
||||
done
|
||||
fi
|
||||
|
||||
# ccache only really works on gcc toolchains
|
||||
enabled gcc || soft_disable ccache
|
||||
if enabled mips; then
|
||||
enable_feature dequant_tokens
|
||||
enable_feature dc_recon
|
||||
fi
|
||||
|
||||
if enabled internal_stats; then
|
||||
enable_feature vp9_postproc
|
||||
fi
|
||||
|
||||
# Enable the postbuild target if building for visual studio.
|
||||
case "$tgt_cc" in
|
||||
vs*) enable_feature msvs
|
||||
enable_feature solution
|
||||
vs_version=${tgt_cc##vs}
|
||||
VCPROJ_SFX=vcxproj
|
||||
gen_vcproj_cmd=${source_path}/build/make/gen_msvs_vcxproj.sh
|
||||
enabled werror && gen_vcproj_cmd="${gen_vcproj_cmd} --enable-werror"
|
||||
all_targets="${all_targets} solution"
|
||||
INLINE="__inline"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Other toolchain specific defaults
|
||||
case $toolchain in x86*) soft_enable postproc;; esac
|
||||
|
||||
if enabled postproc_visualizer; then
|
||||
enabled postproc || die "postproc_visualizer requires postproc to be enabled"
|
||||
fi
|
||||
|
||||
# Enable unit tests by default if we have a working C++ compiler.
|
||||
case "$toolchain" in
|
||||
*-vs*)
|
||||
soft_enable unit_tests
|
||||
soft_enable webm_io
|
||||
soft_enable libyuv
|
||||
;;
|
||||
*-android-*)
|
||||
soft_enable webm_io
|
||||
soft_enable libyuv
|
||||
# GTestLog must be modified to use Android logging utilities.
|
||||
;;
|
||||
*-darwin-*)
|
||||
# iOS/ARM builds do not work with gtest. This does not match
|
||||
# x86 targets.
|
||||
;;
|
||||
*-iphonesimulator-*)
|
||||
soft_enable webm_io
|
||||
soft_enable libyuv
|
||||
;;
|
||||
*-win*)
|
||||
# Some mingw toolchains don't have pthread available by default.
|
||||
# Treat these more like visual studio where threading in gtest
|
||||
# would be disabled for the same reason.
|
||||
check_cxx "$@" <<EOF && soft_enable unit_tests
|
||||
int z;
|
||||
EOF
|
||||
check_cxx "$@" <<EOF && soft_enable webm_io
|
||||
int z;
|
||||
EOF
|
||||
check_cxx "$@" <<EOF && soft_enable libyuv
|
||||
int z;
|
||||
EOF
|
||||
;;
|
||||
*)
|
||||
enabled pthread_h && check_cxx "$@" <<EOF && soft_enable unit_tests
|
||||
int z;
|
||||
EOF
|
||||
check_cxx "$@" <<EOF && soft_enable webm_io
|
||||
int z;
|
||||
EOF
|
||||
check_cxx "$@" <<EOF && soft_enable libyuv
|
||||
int z;
|
||||
EOF
|
||||
;;
|
||||
esac
|
||||
# libwebm needs to be linked with C++ standard library
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
##
|
||||
## END APPLICATION SPECIFIC CONFIGURATION
|
||||
##
|
||||
CONFIGURE_ARGS="$@"
|
||||
process "$@"
|
||||
print_webm_license ${BUILD_PFX}vpx_config.c "/*" " */"
|
||||
cat <<EOF >> ${BUILD_PFX}vpx_config.c
|
||||
#include "vpx/vpx_codec.h"
|
||||
static const char* const cfg = "$CONFIGURE_ARGS";
|
||||
const char *vpx_codec_build_config(void) {return cfg;}
|
||||
EOF
|
11
convolve/Makefile
Normal file
11
convolve/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
all : filtering horiz_filter
|
||||
|
||||
CFLAGS += -mssse3
|
||||
|
||||
filtering : filtering.c
|
||||
horiz_filter : horiz_filter.c
|
||||
|
||||
.PHONY : clean
|
||||
clean :
|
||||
$(RM) filtering horiz_filter
|
||||
|
28
convolve/convolve.c
Normal file
28
convolve/convolve.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
int height = 27;
|
||||
int x_q4 = 8;
|
||||
int x_step_q4 = 16;
|
||||
const int subpel_bits = 4;
|
||||
const int subpel_mask = (1 << subpel_bits) - 1;
|
||||
|
||||
if (3 != argc) {
|
||||
printf("Usage: convolve <q4> <step_q4>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
x_q4 = atoi(argv[1]);
|
||||
x_step_q4 = atoi(argv[2]);
|
||||
|
||||
for (i = 0; i < height; ++i) {
|
||||
printf("x_q4: 0x%X, sigidx: 0x%X, filidx: 0x%X\n",
|
||||
x_q4, x_q4 >> subpel_bits, x_q4 & subpel_mask);
|
||||
x_q4 += x_step_q4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
435
convolve/filtering.c
Normal file
435
convolve/filtering.c
Normal file
@ -0,0 +1,435 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tmmintrin.h>
|
||||
|
||||
#define RAND_SEED (0xbeef)
|
||||
unsigned int seed = RAND_SEED;
|
||||
|
||||
static inline unsigned int readtsc(void) {
|
||||
unsigned int tsc;
|
||||
__asm__ __volatile__("rdtsc\n\t":"=a"(tsc):);
|
||||
return tsc;
|
||||
}
|
||||
|
||||
int round_power_of_two(int x, int n) {
|
||||
int ret = (x + (1 << (n - 1))) >> n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t inline clip_pixel(int x) {
|
||||
uint8_t ret = x;
|
||||
if (x < 0) {
|
||||
ret = 0;
|
||||
}
|
||||
if (x > 255) {
|
||||
ret = 255;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int filtering(const uint8_t *src, const int16_t *filter, int flen) {
|
||||
int k;
|
||||
int sum = 0;
|
||||
int prod;
|
||||
for (k = 0; k < flen; ++k) {
|
||||
prod = src[k] * filter[k];
|
||||
sum += prod;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void convolve(const uint8_t *src, int w, const int16_t *filter, int flen,
|
||||
int *buffer) {
|
||||
int i;
|
||||
int sum;
|
||||
|
||||
for (i = 0; i < w; ++i) {
|
||||
sum = filtering(src, filter, flen);
|
||||
buffer[i] = sum;
|
||||
src += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void init_state(int *buf, uint8_t *pixel, int w, int block) {
|
||||
int i;
|
||||
|
||||
memset(buf, 0, sizeof(buf[0]) * block);
|
||||
memset(pixel, 0, sizeof(pixel[0]) * block);
|
||||
seed = RAND_SEED;
|
||||
for (i = 0; i < w; ++i) {
|
||||
pixel[i] = clip_pixel(rand_r(&seed) % RAND_SEED);
|
||||
}
|
||||
}
|
||||
|
||||
void check_buffer(const int *buf1, const int *buf2, int width) {
|
||||
int i;
|
||||
for (i = 0; i < width; ++i) {
|
||||
if (buf1[i] != buf2[i]) {
|
||||
printf("Not bit-exact on index %d\n", i);
|
||||
printf("Expected: %d, Actual: %d\n", buf1[i], buf2[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const int16_t filter12[12] = {
|
||||
-1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1};
|
||||
|
||||
static const int16_t filter10[10] = {
|
||||
1, -3, 7, -17, 119, 28, -11, 5, -2, 1};
|
||||
|
||||
// SSE4.1
|
||||
|
||||
const int16_t pfilter12[5][16] __attribute__ ((aligned(16))) = {
|
||||
{-1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1, 0, 0, 0, 0},
|
||||
{ 0, -1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1, 0, 0, 0},
|
||||
{ 0, 0, -1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1, 0, 0},
|
||||
{ 0, 0, 0, -1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1, 0},
|
||||
{ 0, 0, 0, 0, -1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1},
|
||||
};
|
||||
|
||||
const int16_t pfilter12_2[3][16] __attribute__ ((aligned(16))) = {
|
||||
{-1, 3, -1, 3, -1, 3, -1, 3, -4, 8, -4, 8, -4, 8, -4, 8},
|
||||
{-18, 120, -18, 120, -18, 120, -18, 120, 28, -12, 28, -12, 28, -12, 28, -12},
|
||||
{ 7, -4, 7, -4, 7, -4, 7, -4, 2, -1, 2, -1, 2, -1, 2, -1},
|
||||
};
|
||||
|
||||
const int16_t pfilter10[7][16] __attribute__ ((aligned(16))) = {
|
||||
{1, -3, 7, -17, 119, 28, -11, 5, -2, 1, 0, 0, 0, 0, 0, 0},
|
||||
{0, 1, -3, 7, -17, 119, 28, -11, 5, -2, 1, 0, 0, 0, 0, 0},
|
||||
{0, 0, 1, -3, 7, -17, 119, 28, -11, 5, -2, 1, 0, 0, 0, 0},
|
||||
{0, 0, 0, 1, -3, 7, -17, 119, 28, -11, 5, -2, 1, 0, 0, 0},
|
||||
{0, 0, 0, 0, 1, -3, 7, -17, 119, 28, -11, 5, -2, 1, 0, 0},
|
||||
{0, 0, 0, 0, 0, 1, -3, 7, -17, 119, 28, -11, 5, -2, 1, 0},
|
||||
{0, 0, 0, 0, 0, 0, 1, -3, 7, -17, 119, 28, -11, 5, -2, 1},
|
||||
};
|
||||
|
||||
// Note:
|
||||
// We can do this:
|
||||
// typedef const int16_t filter_array[16];
|
||||
//
|
||||
// struct Filter {
|
||||
// filter_array *coeffs;
|
||||
// };
|
||||
|
||||
struct Filter {
|
||||
const int16_t (*coeffs)[16];
|
||||
int tapsNum;
|
||||
int signalSpan;
|
||||
};
|
||||
|
||||
const struct Filter pfilter_12tap = {
|
||||
pfilter12, 12, 5
|
||||
};
|
||||
|
||||
const struct Filter pfilter_12tap_2 = {
|
||||
pfilter12_2, 12, 5
|
||||
};
|
||||
|
||||
const struct Filter pfilter_10tap = {
|
||||
pfilter10, 10, 7
|
||||
};
|
||||
|
||||
static inline __m128i multiply_add(const __m128i ps0, const __m128i ps1,
|
||||
const __m128i fl0, const __m128i fl1) {
|
||||
__m128i sum;
|
||||
__m128i sum0 = _mm_madd_epi16(ps0, fl0);
|
||||
__m128i sum1 = _mm_madd_epi16(ps1, fl1);
|
||||
|
||||
sum = _mm_hadd_epi32(sum0, sum1);
|
||||
sum = _mm_hadd_epi32(sum, sum);
|
||||
return _mm_hadd_epi32(sum, sum);
|
||||
}
|
||||
|
||||
// Note:
|
||||
// Instead of, const int16_t (*filter)[16],
|
||||
// we can also, const int16_t filter[][16]
|
||||
|
||||
// Note:
|
||||
// This function memory access is 4 (12-tap filter) or 6 (10-tap filter) bytes
|
||||
// more than C version
|
||||
void inline convolve_w4_sse4_1(const uint8_t *src, const __m128i *f,
|
||||
int *buffer) {
|
||||
__m128i u0, u1, x, s[4];
|
||||
__m128i pixel, pixello, pixelhi;
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
|
||||
pixel = _mm_loadu_si128((__m128i const *)src);
|
||||
pixello = _mm_unpacklo_epi8(pixel, zero);
|
||||
pixelhi = _mm_unpackhi_epi8(pixel, zero);
|
||||
|
||||
s[0] = multiply_add(pixello, pixelhi, f[0], f[1]);
|
||||
s[1] = multiply_add(pixello, pixelhi, f[2], f[3]);
|
||||
s[2] = multiply_add(pixello, pixelhi, f[4], f[5]);
|
||||
s[3] = multiply_add(pixello, pixelhi, f[6], f[7]);
|
||||
|
||||
u0 = _mm_unpacklo_epi32(s[0], s[1]);
|
||||
u1 = _mm_unpacklo_epi32(s[2], s[3]);
|
||||
x = _mm_unpacklo_epi64(u0, u1);
|
||||
_mm_storeu_si128((__m128i *)buffer, x);
|
||||
}
|
||||
|
||||
void convolve_w8_sse4_1(const uint8_t *src, const __m128i *f, int *buffer) {
|
||||
convolve_w4_sse4_1(src, f, buffer);
|
||||
src += 4;
|
||||
buffer += 4;
|
||||
convolve_w4_sse4_1(src, f, buffer);
|
||||
}
|
||||
|
||||
void convolve_w16_sse4_1(const uint8_t *src, const __m128i *f, int *buffer) {
|
||||
convolve_w8_sse4_1(src, f, buffer);
|
||||
src += 8;
|
||||
buffer += 8;
|
||||
convolve_w8_sse4_1(src, f, buffer);
|
||||
}
|
||||
|
||||
void convolve_w32_sse4_1(const uint8_t *src, const __m128i *f, int *buffer) {
|
||||
convolve_w16_sse4_1(src, f, buffer);
|
||||
src += 16;
|
||||
buffer += 16;
|
||||
convolve_w16_sse4_1(src, f, buffer);
|
||||
}
|
||||
|
||||
void convolve_w64_sse4_1(const uint8_t *src, const __m128i *f, int *buffer) {
|
||||
convolve_w32_sse4_1(src, f, buffer);
|
||||
src += 32;
|
||||
buffer += 32;
|
||||
convolve_w32_sse4_1(src, f, buffer);
|
||||
}
|
||||
|
||||
void (*convolveTab[5])(const uint8_t *, const __m128i *, int *) = {
|
||||
convolve_w4_sse4_1,
|
||||
convolve_w8_sse4_1,
|
||||
convolve_w16_sse4_1,
|
||||
convolve_w32_sse4_1,
|
||||
convolve_w64_sse4_1,
|
||||
};
|
||||
|
||||
|
||||
void convolve_sse4_1(const uint8_t *src, const struct Filter fData,
|
||||
int width, int *buffer) {
|
||||
const int16_t *filter = (const int16_t *) fData.coeffs;
|
||||
__m128i f[10];
|
||||
|
||||
f[0] = *((__m128i *)(filter + 0 * 8));
|
||||
f[1] = *((__m128i *)(filter + 1 * 8));
|
||||
f[2] = *((__m128i *)(filter + 2 * 8));
|
||||
f[3] = *((__m128i *)(filter + 3 * 8));
|
||||
f[4] = *((__m128i *)(filter + 4 * 8));
|
||||
f[5] = *((__m128i *)(filter + 5 * 8));
|
||||
f[6] = *((__m128i *)(filter + 6 * 8));
|
||||
f[7] = *((__m128i *)(filter + 7 * 8));
|
||||
f[8] = *((__m128i *)(filter + 8 * 8));
|
||||
f[9] = *((__m128i *)(filter + 9 * 8));
|
||||
|
||||
switch (width) {
|
||||
case 4:
|
||||
convolveTab[0](src, f, buffer);
|
||||
break;
|
||||
case 8:
|
||||
convolveTab[1](src, f, buffer);
|
||||
break;
|
||||
case 16:
|
||||
convolveTab[2](src, f, buffer);
|
||||
break;
|
||||
case 32:
|
||||
convolveTab[3](src, f, buffer);
|
||||
break;
|
||||
case 64:
|
||||
convolveTab[4](src, f, buffer);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Solution 2
|
||||
void inline convolve2_w4_sse4_1(const uint8_t *src, const __m128i *f,
|
||||
const __m128i *cm, int *buffer) {
|
||||
__m128i pixel;
|
||||
__m128i s0, s1, s2, s3, s4, s5;
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
|
||||
pixel = _mm_loadu_si128((__m128i const *)src);
|
||||
|
||||
__m128i y0 = _mm_shuffle_epi8(pixel, cm[0]);
|
||||
__m128i y1 = _mm_shuffle_epi8(pixel, cm[1]);
|
||||
__m128i y2 = _mm_shuffle_epi8(pixel, cm[2]);
|
||||
__m128i y3 = _mm_shuffle_epi8(pixel, cm[3]);
|
||||
__m128i y4 = _mm_shuffle_epi8(pixel, cm[4]);
|
||||
__m128i y5 = _mm_shuffle_epi8(pixel, cm[5]);
|
||||
|
||||
y0 = _mm_unpacklo_epi8(y0, zero);
|
||||
y1 = _mm_unpacklo_epi8(y1, zero);
|
||||
y2 = _mm_unpacklo_epi8(y2, zero);
|
||||
y3 = _mm_unpacklo_epi8(y3, zero);
|
||||
y4 = _mm_unpacklo_epi8(y4, zero);
|
||||
y5 = _mm_unpacklo_epi8(y5, zero);
|
||||
|
||||
s0 = _mm_madd_epi16(y0, f[0]);
|
||||
s1 = _mm_madd_epi16(y1, f[1]);
|
||||
s2 = _mm_madd_epi16(y2, f[2]);
|
||||
s3 = _mm_madd_epi16(y3, f[3]);
|
||||
s4 = _mm_madd_epi16(y4, f[4]);
|
||||
s5 = _mm_madd_epi16(y5, f[5]);
|
||||
|
||||
s0 = _mm_add_epi32(s0, s1);
|
||||
s0 = _mm_add_epi32(s0, s2);
|
||||
s0 = _mm_add_epi32(s0, s3);
|
||||
s0 = _mm_add_epi32(s0, s4);
|
||||
s0 = _mm_add_epi32(s0, s5);
|
||||
|
||||
_mm_storeu_si128((__m128i *)buffer, s0);
|
||||
}
|
||||
|
||||
void convolve2_w8_sse4_1(const uint8_t *src, const __m128i *f,
|
||||
const __m128i *cm, int *buffer) {
|
||||
convolve2_w4_sse4_1(src, f, cm, buffer);
|
||||
src += 4;
|
||||
buffer += 4;
|
||||
convolve2_w4_sse4_1(src, f, cm, buffer);
|
||||
}
|
||||
|
||||
void convolve2_w16_sse4_1(const uint8_t *src, const __m128i *f,
|
||||
const __m128i *cm, int *buffer) {
|
||||
convolve2_w8_sse4_1(src, f, cm, buffer);
|
||||
src += 8;
|
||||
buffer += 8;
|
||||
convolve2_w8_sse4_1(src, f, cm, buffer);
|
||||
}
|
||||
|
||||
void convolve2_w32_sse4_1(const uint8_t *src, const __m128i *f,
|
||||
const __m128i *cm, int *buffer) {
|
||||
convolve2_w16_sse4_1(src, f, cm, buffer);
|
||||
src += 16;
|
||||
buffer += 16;
|
||||
convolve2_w16_sse4_1(src, f, cm, buffer);
|
||||
}
|
||||
|
||||
void convolve2_w64_sse4_1(const uint8_t *src, const __m128i *f,
|
||||
const __m128i *cm, int *buffer) {
|
||||
convolve2_w32_sse4_1(src, f, cm, buffer);
|
||||
src += 32;
|
||||
buffer += 32;
|
||||
convolve2_w32_sse4_1(src, f, cm, buffer);
|
||||
}
|
||||
|
||||
void (*convolveTab2[5])(const uint8_t *, const __m128i *, const __m128i *,
|
||||
int *) = {
|
||||
convolve2_w4_sse4_1,
|
||||
convolve2_w8_sse4_1,
|
||||
convolve2_w16_sse4_1,
|
||||
convolve2_w32_sse4_1,
|
||||
convolve2_w64_sse4_1,
|
||||
};
|
||||
|
||||
void convolve2_sse4_1(const uint8_t *src, const struct Filter fData,
|
||||
int width, int *buffer) {
|
||||
__m128i f[6];
|
||||
__m128i cm[6];
|
||||
const int16_t *filter = (const int16_t *) fData.coeffs;
|
||||
|
||||
f[0] = *((__m128i *)(filter + 0 * 8));
|
||||
f[1] = *((__m128i *)(filter + 1 * 8));
|
||||
f[2] = *((__m128i *)(filter + 2 * 8));
|
||||
f[3] = *((__m128i *)(filter + 3 * 8));
|
||||
f[4] = *((__m128i *)(filter + 4 * 8));
|
||||
f[5] = *((__m128i *)(filter + 5 * 8));
|
||||
|
||||
cm[0] = _mm_setr_epi16(0x100, 0x201, 0x302, 0x403, 0, 0, 0, 0);
|
||||
cm[1] = _mm_setr_epi16(0x302, 0x403, 0x504, 0x605, 0, 0, 0, 0);
|
||||
cm[2] = _mm_setr_epi16(0x504, 0x605, 0x706, 0x807, 0, 0, 0, 0);
|
||||
cm[3] = _mm_setr_epi16(0x706, 0x807, 0x908, 0xa09, 0, 0, 0, 0);
|
||||
cm[4] = _mm_setr_epi16(0x908, 0xa09, 0xb0a, 0xc0b, 0, 0, 0, 0);
|
||||
cm[5] = _mm_setr_epi16(0xb0a, 0xc0b, 0xd0c, 0xe0d, 0, 0, 0, 0);
|
||||
|
||||
switch (width) {
|
||||
case 4:
|
||||
convolveTab2[0](src, f, cm, buffer);
|
||||
break;
|
||||
case 8:
|
||||
convolveTab2[1](src, f, cm, buffer);
|
||||
break;
|
||||
case 16:
|
||||
convolveTab2[2](src, f, cm, buffer);
|
||||
break;
|
||||
case 32:
|
||||
convolveTab2[3](src, f, cm, buffer);
|
||||
break;
|
||||
case 64:
|
||||
convolveTab2[4](src, f, cm, buffer);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_NUM (32)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const size_t block_size = 256;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: filtering <width>, where width = 4, 8, 16, 32, 64\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int width = atoi(argv[1]);
|
||||
|
||||
int *buffer = (int *) malloc(3 * sizeof(buffer[0]) * block_size);
|
||||
uint8_t *pixel = (uint8_t *) malloc(3 * sizeof(pixel[0]) * block_size);
|
||||
uint8_t *ppixel = pixel + block_size;
|
||||
int *pbuffer = buffer + block_size;
|
||||
uint8_t *ppixel2 = pixel + 2 * block_size;
|
||||
int *pbuffer2 = buffer + 2 * block_size;
|
||||
uint32_t start, end;
|
||||
int count;
|
||||
|
||||
init_state(buffer, pixel, width, block_size);
|
||||
init_state(pbuffer, ppixel, width, block_size);
|
||||
init_state(pbuffer2, ppixel2, width, block_size);
|
||||
|
||||
count = 0;
|
||||
start = readtsc();
|
||||
do {
|
||||
convolve(pixel, width, filter12, 12, buffer);
|
||||
count++;
|
||||
} while (count < TEST_NUM);
|
||||
end = readtsc();
|
||||
|
||||
printf("C version cycles: %d\n", end - start);
|
||||
|
||||
// Solution 1
|
||||
count = 0;
|
||||
start = readtsc();
|
||||
do {
|
||||
convolve_sse4_1(ppixel, pfilter_12tap, width, pbuffer);
|
||||
count++;
|
||||
} while (count < TEST_NUM);
|
||||
end = readtsc();
|
||||
|
||||
printf("SIMD version cycles: %d\n", end - start);
|
||||
|
||||
check_buffer(buffer, pbuffer, width);
|
||||
|
||||
// Solution 2
|
||||
count = 0;
|
||||
start = readtsc();
|
||||
do {
|
||||
convolve2_sse4_1(ppixel2, pfilter_12tap_2, width, pbuffer2);
|
||||
count++;
|
||||
} while (count < TEST_NUM);
|
||||
end = readtsc();
|
||||
|
||||
printf("SIMD version 2 cycles: %d\n", end - start);
|
||||
|
||||
check_buffer(buffer, pbuffer2, width);
|
||||
|
||||
free(buffer);
|
||||
free(pixel);
|
||||
return 0;
|
||||
}
|
711
convolve/horiz_filter.c
Normal file
711
convolve/horiz_filter.c
Normal file
@ -0,0 +1,711 @@
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tmmintrin.h>
|
||||
|
||||
static inline unsigned int readtsc(void) {
|
||||
unsigned int tsc;
|
||||
__asm__ __volatile__("rdtsc\n\t":"=a"(tsc):);
|
||||
return tsc;
|
||||
}
|
||||
|
||||
#define FILTER_BITS (7)
|
||||
#define TEST_NUM (32)
|
||||
#define HD_WIDTH (1920)
|
||||
#define SUPER_BLOCK_HEIGHT (128)
|
||||
#define RAND_SEED (0xabc)
|
||||
unsigned int seed = RAND_SEED;
|
||||
|
||||
int round_power_of_two(int x, int n) {
|
||||
int ret = (x + (1 << (n - 1))) >> n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t inline clip_pixel(int x) {
|
||||
uint8_t ret = x;
|
||||
if (x < 0) {
|
||||
ret = 0;
|
||||
}
|
||||
if (x > 255) {
|
||||
ret = 255;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int filtering(const uint8_t *src, const int16_t *filter, int flen) {
|
||||
int k;
|
||||
int sum = 0;
|
||||
int prod;
|
||||
for (k = 0; k < flen; ++k) {
|
||||
prod = src[k] * filter[k];
|
||||
sum += prod;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void convolve(const uint8_t *src, int w, const int16_t *filter, int flen,
|
||||
uint8_t *buffer) {
|
||||
int i;
|
||||
int sum;
|
||||
|
||||
for (i = 0; i < w; ++i) {
|
||||
sum = filtering(src, filter, flen);
|
||||
buffer[i] = clip_pixel(round_power_of_two(sum, FILTER_BITS));
|
||||
src += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void init_state(uint8_t *buf, uint8_t *pixel,
|
||||
int width, int height, int stride,
|
||||
const unsigned int random) {
|
||||
|
||||
int row, col;
|
||||
int block = HD_WIDTH * SUPER_BLOCK_HEIGHT;
|
||||
|
||||
memset(buf, 0, sizeof(buf[0]) * block);
|
||||
memset(pixel, 0, sizeof(pixel[0]) * block);
|
||||
|
||||
seed = random;
|
||||
for (row = 0; row < height; ++row) {
|
||||
for (col = 0; col < width; ++col) {
|
||||
pixel[col] = clip_pixel(rand_r(&seed) % 255);
|
||||
}
|
||||
pixel += stride;
|
||||
}
|
||||
}
|
||||
|
||||
void check_buffer(const uint8_t *buf1, const uint8_t *buf2,
|
||||
int width, int height, int stride) {
|
||||
int row, col;
|
||||
|
||||
for (row = 0; row < height; ++row) {
|
||||
for (col = 0; col < width; ++col) {
|
||||
if (buf1[col] != buf2[col]) {
|
||||
printf("Not bit-exact at col: %d row: %d\n", col, row);
|
||||
printf("Expected: 0x%x, Actual: 0x%x\n", buf1[col], buf2[col]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
buf1 += stride;
|
||||
buf2 += stride;
|
||||
}
|
||||
}
|
||||
|
||||
static const int16_t filter12[12] __attribute__ ((aligned(16))) = {
|
||||
-1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1};
|
||||
|
||||
static const int16_t filter10[10] __attribute__ ((aligned(16))) = {
|
||||
1, -3, 7, -17, 119, 28, -11, 5, -2, 1};
|
||||
|
||||
// SSSE3
|
||||
|
||||
struct Filter {
|
||||
const int8_t (*coeffs)[16];
|
||||
int tapsNum;
|
||||
};
|
||||
|
||||
// for Horiz4 method (subpixel)
|
||||
// 12-tap filter
|
||||
static const int8_t filter12_subpixel_ns[6][16] __attribute__ ((aligned(16))) = {
|
||||
{-1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3, -1, 3},
|
||||
{-4, 8, -4, 8, -4, 8, -4, 8, -4, 8, -4, 8, -4, 8, -4, 8},
|
||||
{-18, 120, -18, 120, -18, 120, -18, 120, -18, 120, -18, 120, -18, 120, -18, 120},
|
||||
{28, -12, 28, -12, 28, -12, 28, -12, 28, -12, 28, -12, 28, -12, 28, -12},
|
||||
{7, -4, 7, -4, 7, -4, 7, -4, 7, -4, 7, -4, 7, -4, 7, -4},
|
||||
{2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1, 2, -1},
|
||||
};
|
||||
|
||||
// 10-tap filter
|
||||
static const int8_t filter10_subpixel_ns[6][16] __attribute__ ((aligned(16))) = {
|
||||
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
|
||||
{-3, 7, -3, 7, -3, 7, -3, 7, -3, 7, -3, 7, -3, 7, -3, 7},
|
||||
{-17, 119, -17, 119, -17, 119, -17, 119, -17, 119, -17, 119, -17, 119, -17, 119},
|
||||
{28, -11, 28, -11, 28, -11, 28, -11, 28, -11, 28, -11, 28, -11, 28, -11},
|
||||
{5, -2, 5, -2, 5, -2, 5, -2, 5, -2, 5, -2, 5, -2, 5, -2},
|
||||
{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0},
|
||||
};
|
||||
|
||||
static const struct Filter pfilter_12tap_subpixel = {
|
||||
filter12_subpixel_ns, 12
|
||||
};
|
||||
|
||||
static const struct Filter pfilter_10tap_subpixel = {
|
||||
filter10_subpixel_ns, 10
|
||||
};
|
||||
|
||||
// for HorizP method
|
||||
// 12-tap filter
|
||||
const int8_t pfilter12[2][16] __attribute__ ((aligned(16))) = {
|
||||
{-1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1, 0, 0, 0, 0},
|
||||
{ 0, 0, -1, 3, -4, 8, -18, 120, 28, -12, 7, -4, 2, -1, 0, 0},
|
||||
};
|
||||
|
||||
// 10-tap filter
|
||||
const int8_t pfilter10[2][16] __attribute__ ((aligned(16))) = {
|
||||
{0, 1, -3, 7, -17, 119, 28, -11, 5, -2, 1, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 1, -3, 7, -17, 119, 28, -11, 5, -2, 1, 0, 0, 0},
|
||||
};
|
||||
|
||||
const struct Filter pfilter_12tap = {
|
||||
pfilter12, 12
|
||||
};
|
||||
|
||||
const struct Filter pfilter_10tap = {
|
||||
pfilter10, 10
|
||||
};
|
||||
|
||||
void inline transpose_4x8(const __m128i *in, __m128i *out) {
|
||||
__m128i t0, t1;
|
||||
|
||||
t0 = _mm_unpacklo_epi16(in[0], in[1]);
|
||||
t1 = _mm_unpacklo_epi16(in[2], in[3]);
|
||||
|
||||
out[0] = _mm_unpacklo_epi32(t0, t1);
|
||||
out[1] = _mm_srli_si128(out[0], 8);
|
||||
out[2] = _mm_unpackhi_epi32(t0, t1);
|
||||
out[3] = _mm_srli_si128(out[2], 8);
|
||||
|
||||
t0 = _mm_unpackhi_epi16(in[0], in[1]);
|
||||
t1 = _mm_unpackhi_epi16(in[2], in[3]);
|
||||
|
||||
out[4] = _mm_unpacklo_epi32(t0, t1);
|
||||
out[5] = _mm_srli_si128(out[4], 8);
|
||||
// Note: We ignore out[6] and out[7] because
|
||||
// they're zero vectors.
|
||||
}
|
||||
|
||||
void horiz_w4_ssse3(const uint8_t *src, const __m128i *f,
|
||||
int tapsNum, uint8_t *buffer) {
|
||||
__m128i sumPairRow[4];
|
||||
__m128i sumPairCol[8];
|
||||
__m128i pixel;
|
||||
const __m128i k_256 = _mm_set1_epi16(1 << 8);
|
||||
|
||||
if (10 == tapsNum) {
|
||||
src -= 1;
|
||||
}
|
||||
|
||||
pixel = _mm_loadu_si128((__m128i const *)src);
|
||||
sumPairRow[0] = _mm_maddubs_epi16(pixel, f[0]);
|
||||
sumPairRow[2] = _mm_maddubs_epi16(pixel, f[1]);
|
||||
sumPairRow[2] = _mm_srli_si128(sumPairRow[2], 2);
|
||||
|
||||
pixel = _mm_loadu_si128((__m128i const *)(src + 1));
|
||||
sumPairRow[1] = _mm_maddubs_epi16(pixel, f[0]);
|
||||
sumPairRow[3] = _mm_maddubs_epi16(pixel, f[1]);
|
||||
sumPairRow[3] = _mm_srli_si128(sumPairRow[3], 2);
|
||||
|
||||
transpose_4x8(sumPairRow, sumPairCol);
|
||||
|
||||
sumPairRow[0] = _mm_adds_epi16(sumPairCol[0], sumPairCol[1]);
|
||||
sumPairRow[1] = _mm_adds_epi16(sumPairCol[4], sumPairCol[5]);
|
||||
|
||||
sumPairRow[2] = _mm_min_epi16(sumPairCol[2], sumPairCol[3]);
|
||||
sumPairRow[3] = _mm_max_epi16(sumPairCol[2], sumPairCol[3]);
|
||||
|
||||
sumPairRow[0] = _mm_adds_epi16(sumPairRow[0], sumPairRow[1]);
|
||||
sumPairRow[0] = _mm_adds_epi16(sumPairRow[0], sumPairRow[2]);
|
||||
sumPairRow[0] = _mm_adds_epi16(sumPairRow[0], sumPairRow[3]);
|
||||
|
||||
sumPairRow[1] = _mm_mulhrs_epi16(sumPairRow[0], k_256);
|
||||
sumPairRow[2] = _mm_packus_epi16(sumPairRow[1], sumPairRow[1]);
|
||||
|
||||
*(int *)buffer = _mm_cvtsi128_si32(sumPairRow[2]);
|
||||
}
|
||||
|
||||
void horiz_w8_ssse3(const uint8_t *src, const __m128i *f, int tapsNum,
|
||||
uint8_t *buf) {
|
||||
horiz_w4_ssse3(src, f, tapsNum, buf);
|
||||
src += 4;
|
||||
buf += 4;
|
||||
horiz_w4_ssse3(src, f, tapsNum, buf);
|
||||
}
|
||||
|
||||
void horiz_w16_ssse3(const uint8_t *src, const __m128i *f, int tapsNum,
|
||||
uint8_t *buf) {
|
||||
horiz_w8_ssse3(src, f, tapsNum, buf);
|
||||
src += 8;
|
||||
buf += 8;
|
||||
horiz_w8_ssse3(src, f, tapsNum, buf);
|
||||
}
|
||||
|
||||
void horiz_w32_ssse3(const uint8_t *src, const __m128i *f, int tapsNum,
|
||||
uint8_t *buf) {
|
||||
horiz_w16_ssse3(src, f, tapsNum, buf);
|
||||
src += 16;
|
||||
buf += 16;
|
||||
horiz_w16_ssse3(src, f, tapsNum, buf);
|
||||
}
|
||||
|
||||
void horiz_w64_ssse3(const uint8_t *src, const __m128i *f, int tapsNum,
|
||||
uint8_t *buf) {
|
||||
horiz_w32_ssse3(src, f, tapsNum, buf);
|
||||
src += 32;
|
||||
buf += 32;
|
||||
horiz_w32_ssse3(src, f, tapsNum, buf);
|
||||
}
|
||||
|
||||
void horiz_w128_ssse3(const uint8_t *src, const __m128i *f, int tapsNum,
|
||||
uint8_t *buf) {
|
||||
horiz_w64_ssse3(src, f, tapsNum, buf);
|
||||
src += 64;
|
||||
buf += 64;
|
||||
horiz_w64_ssse3(src, f, tapsNum, buf);
|
||||
}
|
||||
|
||||
void (*horizTab[6])(const uint8_t *, const __m128i *, int, uint8_t *) = {
|
||||
horiz_w4_ssse3,
|
||||
horiz_w8_ssse3,
|
||||
horiz_w16_ssse3,
|
||||
horiz_w32_ssse3,
|
||||
horiz_w64_ssse3,
|
||||
horiz_w128_ssse3,
|
||||
};
|
||||
|
||||
void horiz_filter_ssse3(const uint8_t *src, const struct Filter fData,
|
||||
int width, uint8_t *buffer) {
|
||||
const int16_t *filter = (const int16_t *) fData.coeffs;
|
||||
__m128i f[2];
|
||||
|
||||
f[0] = *((__m128i *)(fData.coeffs));
|
||||
f[1] = *((__m128i *)(fData.coeffs + 1));
|
||||
|
||||
switch (width) {
|
||||
case 4:
|
||||
horizTab[0](src, f, fData.tapsNum, buffer);
|
||||
break;
|
||||
case 8:
|
||||
horizTab[1](src, f, fData.tapsNum, buffer);
|
||||
break;
|
||||
case 16:
|
||||
horizTab[2](src, f, fData.tapsNum, buffer);
|
||||
break;
|
||||
case 32:
|
||||
horizTab[3](src, f, fData.tapsNum, buffer);
|
||||
break;
|
||||
case 64:
|
||||
horizTab[4](src, f, fData.tapsNum, buffer);
|
||||
break;
|
||||
case 128:
|
||||
horizTab[5](src, f, fData.tapsNum, buffer);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
// C prototype wrapper function
|
||||
void run_prototype_filter(uint8_t *src, int width, int height, int stride,
|
||||
const int16_t *filter, int flen, uint8_t *dst) {
|
||||
uint32_t start, end;
|
||||
int count = 0;
|
||||
|
||||
start = readtsc();
|
||||
do {
|
||||
convolve(src, width, filter, flen, dst);
|
||||
src += stride;
|
||||
dst += stride;
|
||||
count++;
|
||||
} while (count < height);
|
||||
end = readtsc();
|
||||
|
||||
printf("C version cycles:\t%d\n", end - start);
|
||||
}
|
||||
|
||||
// sub-pixel 4x4 method
|
||||
static void transpose4x4_to_dst(const uint8_t *src, ptrdiff_t src_stride,
|
||||
uint8_t *dst, ptrdiff_t dst_stride) {
|
||||
__m128i A = _mm_cvtsi32_si128(*(const int *)src);
|
||||
__m128i B = _mm_cvtsi32_si128(*(const int *)(src + src_stride));
|
||||
__m128i C = _mm_cvtsi32_si128(*(const int *)(src + src_stride * 2));
|
||||
__m128i D = _mm_cvtsi32_si128(*(const int *)(src + src_stride * 3));
|
||||
// 00 10 01 11 02 12 03 13
|
||||
const __m128i tr0_0 = _mm_unpacklo_epi8(A, B);
|
||||
// 20 30 21 31 22 32 23 33
|
||||
const __m128i tr0_1 = _mm_unpacklo_epi8(C, D);
|
||||
// 00 10 20 30 01 11 21 31 02 12 22 32 03 13 23 33
|
||||
A = _mm_unpacklo_epi16(tr0_0, tr0_1);
|
||||
B = _mm_srli_si128(A, 4);
|
||||
C = _mm_srli_si128(A, 8);
|
||||
D = _mm_srli_si128(A, 12);
|
||||
|
||||
*(int *)(dst) = _mm_cvtsi128_si32(A);
|
||||
*(int *)(dst + dst_stride) = _mm_cvtsi128_si32(B);
|
||||
*(int *)(dst + dst_stride * 2) = _mm_cvtsi128_si32(C);
|
||||
*(int *)(dst + dst_stride * 3) = _mm_cvtsi128_si32(D);
|
||||
}
|
||||
|
||||
// Vertical 8-pixel parallel
|
||||
#define TRANSPOSE_8X8(in0, in1, in2, in3, in4, in5, in6, in7, \
|
||||
out0, out1, out2, out3, out4, out5, out6, out7) { \
|
||||
const __m128i tr0_0 = _mm_unpacklo_epi8(in0, in1); \
|
||||
const __m128i tr0_1 = _mm_unpacklo_epi8(in2, in3); \
|
||||
const __m128i tr0_2 = _mm_unpacklo_epi8(in4, in5); \
|
||||
const __m128i tr0_3 = _mm_unpacklo_epi8(in6, in7); \
|
||||
\
|
||||
const __m128i tr1_0 = _mm_unpacklo_epi16(tr0_0, tr0_1); \
|
||||
const __m128i tr1_1 = _mm_unpackhi_epi16(tr0_0, tr0_1); \
|
||||
const __m128i tr1_2 = _mm_unpacklo_epi16(tr0_2, tr0_3); \
|
||||
const __m128i tr1_3 = _mm_unpackhi_epi16(tr0_2, tr0_3); \
|
||||
\
|
||||
const __m128i tr2_0 = _mm_unpacklo_epi32(tr1_0, tr1_2); \
|
||||
const __m128i tr2_1 = _mm_unpackhi_epi32(tr1_0, tr1_2); \
|
||||
const __m128i tr2_2 = _mm_unpacklo_epi32(tr1_1, tr1_3); \
|
||||
const __m128i tr2_3 = _mm_unpackhi_epi32(tr1_1, tr1_3); \
|
||||
\
|
||||
out0 = _mm_unpacklo_epi64(tr2_0, tr2_0); \
|
||||
out1 = _mm_unpackhi_epi64(tr2_0, tr2_0); \
|
||||
out2 = _mm_unpacklo_epi64(tr2_1, tr2_1); \
|
||||
out3 = _mm_unpackhi_epi64(tr2_1, tr2_1); \
|
||||
out4 = _mm_unpacklo_epi64(tr2_2, tr2_2); \
|
||||
out5 = _mm_unpackhi_epi64(tr2_2, tr2_2); \
|
||||
out6 = _mm_unpacklo_epi64(tr2_3, tr2_3); \
|
||||
out7 = _mm_unpackhi_epi64(tr2_3, tr2_3); \
|
||||
}
|
||||
|
||||
static void transpose8x8_to_dst(const uint8_t *src, ptrdiff_t src_stride,
|
||||
uint8_t *dst, ptrdiff_t dst_stride) {
|
||||
__m128i A, B, C, D, E, F, G, H;
|
||||
|
||||
A = _mm_loadl_epi64((const __m128i *)src);
|
||||
B = _mm_loadl_epi64((const __m128i *)(src + src_stride));
|
||||
C = _mm_loadl_epi64((const __m128i *)(src + src_stride * 2));
|
||||
D = _mm_loadl_epi64((const __m128i *)(src + src_stride * 3));
|
||||
E = _mm_loadl_epi64((const __m128i *)(src + src_stride * 4));
|
||||
F = _mm_loadl_epi64((const __m128i *)(src + src_stride * 5));
|
||||
G = _mm_loadl_epi64((const __m128i *)(src + src_stride * 6));
|
||||
H = _mm_loadl_epi64((const __m128i *)(src + src_stride * 7));
|
||||
|
||||
TRANSPOSE_8X8(A, B, C, D, E, F, G, H,
|
||||
A, B, C, D, E, F, G, H);
|
||||
|
||||
_mm_storel_epi64((__m128i*)dst, A);
|
||||
_mm_storel_epi64((__m128i*)(dst + dst_stride * 1), B);
|
||||
_mm_storel_epi64((__m128i*)(dst + dst_stride * 2), C);
|
||||
_mm_storel_epi64((__m128i*)(dst + dst_stride * 3), D);
|
||||
_mm_storel_epi64((__m128i*)(dst + dst_stride * 4), E);
|
||||
_mm_storel_epi64((__m128i*)(dst + dst_stride * 5), F);
|
||||
_mm_storel_epi64((__m128i*)(dst + dst_stride * 6), G);
|
||||
_mm_storel_epi64((__m128i*)(dst + dst_stride * 7), H);
|
||||
}
|
||||
|
||||
void inline transpose_8x16(const __m128i *in, __m128i *out) {
|
||||
__m128i t0, t1, t2, t3, u0, u1;
|
||||
|
||||
t0 = _mm_unpacklo_epi16(in[0], in[1]);
|
||||
t1 = _mm_unpacklo_epi16(in[2], in[3]);
|
||||
t2 = _mm_unpacklo_epi16(in[4], in[5]);
|
||||
t3 = _mm_unpacklo_epi16(in[6], in[7]);
|
||||
|
||||
u0 = _mm_unpacklo_epi32(t0, t1);
|
||||
u1 = _mm_unpacklo_epi32(t2, t3);
|
||||
|
||||
out[0] = _mm_unpacklo_epi64(u0, u1);
|
||||
out[1] = _mm_unpackhi_epi64(u0, u1);
|
||||
|
||||
u0 = _mm_unpackhi_epi32(t0, t1);
|
||||
u1 = _mm_unpackhi_epi32(t2, t3);
|
||||
|
||||
out[2] = _mm_unpacklo_epi64(u0, u1);
|
||||
out[3] = _mm_unpackhi_epi64(u0, u1);
|
||||
|
||||
t0 = _mm_unpackhi_epi16(in[0], in[1]);
|
||||
t1 = _mm_unpackhi_epi16(in[2], in[3]);
|
||||
t2 = _mm_unpackhi_epi16(in[4], in[5]);
|
||||
t3 = _mm_unpackhi_epi16(in[6], in[7]);
|
||||
|
||||
u0 = _mm_unpacklo_epi32(t0, t1);
|
||||
u1 = _mm_unpacklo_epi32(t2, t3);
|
||||
|
||||
out[4] = _mm_unpacklo_epi64(u0, u1);
|
||||
out[5] = _mm_unpackhi_epi64(u0, u1);
|
||||
// Ignore out[6] and out[7]
|
||||
//u0 = _mm_unpackhi_epi32(t0, t1);
|
||||
//u1 = _mm_unpackhi_epi32(t2, t3);
|
||||
|
||||
//out[6] = _mm_unpacklo_epi64(u0, u1);
|
||||
//out[7] = _mm_unpackhi_epi64(u0, u1);
|
||||
}
|
||||
|
||||
static void filter_horiz_v8p_ssse3(const uint8_t *src_ptr, ptrdiff_t src_pitch,
|
||||
__m128i *f, int tapsNum, uint8_t *dst) {
|
||||
__m128i s[8], t[6];
|
||||
const __m128i k_256 = _mm_set1_epi16(1 << 8);
|
||||
if (tapsNum == 10) {
|
||||
src_ptr -= 1;
|
||||
}
|
||||
s[0] = _mm_loadu_si128((const __m128i *)src_ptr);
|
||||
s[1] = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch));
|
||||
s[2] = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 2));
|
||||
s[3] = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 3));
|
||||
s[4] = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 4));
|
||||
s[5] = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 5));
|
||||
s[6] = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 6));
|
||||
s[7] = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 7));
|
||||
|
||||
// TRANSPOSE...
|
||||
// Vecotor represents column pixel pairs instead of a row
|
||||
transpose_8x16(s, t);
|
||||
|
||||
// multiply 2 adjacent elements with the filter and add the result
|
||||
s[0] = _mm_maddubs_epi16(t[0], f[0]);
|
||||
s[1] = _mm_maddubs_epi16(t[1], f[1]);
|
||||
s[2] = _mm_maddubs_epi16(t[2], f[2]);
|
||||
s[3] = _mm_maddubs_epi16(t[3], f[3]);
|
||||
s[4] = _mm_maddubs_epi16(t[4], f[4]);
|
||||
s[5] = _mm_maddubs_epi16(t[5], f[5]);
|
||||
|
||||
// add and saturate the results together
|
||||
const __m128i min_x2x3 = _mm_min_epi16(s[2], s[3]);
|
||||
const __m128i max_x2x3 = _mm_max_epi16(s[2], s[3]);
|
||||
__m128i temp = _mm_adds_epi16(s[0], s[1]);
|
||||
temp = _mm_adds_epi16(temp, s[5]);
|
||||
temp = _mm_adds_epi16(temp, s[4]);
|
||||
|
||||
temp = _mm_adds_epi16(temp, min_x2x3);
|
||||
temp = _mm_adds_epi16(temp, max_x2x3);
|
||||
// round and shift by 7 bit each 16 bit
|
||||
temp = _mm_mulhrs_epi16(temp, k_256);
|
||||
// shrink to 8 bit each 16 bits
|
||||
temp = _mm_packus_epi16(temp, temp);
|
||||
// save only 8 bytes
|
||||
//*(int64_t *)dst = _mm_cvtsi128_si64(temp);
|
||||
_mm_storel_epi64((__m128i *)dst, temp);
|
||||
}
|
||||
|
||||
// Vertical 4-pixel parallel
|
||||
static void filter_horiz_v4p_ssse3(const uint8_t *src_ptr, ptrdiff_t src_pitch,
|
||||
__m128i *f, int tapsNum, uint8_t *dst) {
|
||||
const __m128i k_256 = _mm_set1_epi16(1 << 8);
|
||||
if (tapsNum == 10) {
|
||||
src_ptr -= 1;
|
||||
}
|
||||
const __m128i A = _mm_loadu_si128((const __m128i *)src_ptr);
|
||||
const __m128i B = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch));
|
||||
const __m128i C = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 2));
|
||||
const __m128i D = _mm_loadu_si128((const __m128i *)(src_ptr + src_pitch * 3));
|
||||
|
||||
// TRANSPOSE...
|
||||
// Vecotor represents column pixel pairs instead of a row
|
||||
// 00 01 10 11 02 03 12 13 04 05 14 15 06 07 16 17
|
||||
__m128i tr0_0 = _mm_unpacklo_epi16(A, B);
|
||||
// 20 21 30 31 22 23 32 33 24 25 34 35 26 27 36 37
|
||||
__m128i tr0_1 = _mm_unpacklo_epi16(C, D);
|
||||
// 00 01 10 11 20 21 30 31 02 03 12 13 22 23 32 33
|
||||
const __m128i s1s0 = _mm_unpacklo_epi32(tr0_0, tr0_1);
|
||||
// 04 05 14 15 24 25 34 35 06 07 16 17 26 27 36 37
|
||||
const __m128i s5s4 = _mm_unpackhi_epi32(tr0_0, tr0_1);
|
||||
// 02 03 12 13 22 23 32 33
|
||||
const __m128i s3s2 = _mm_srli_si128(s1s0, 8);
|
||||
// 06 07 16 17 26 27 36 37
|
||||
const __m128i s7s6 = _mm_srli_si128(s5s4, 8);
|
||||
|
||||
tr0_0 = _mm_unpackhi_epi16(A, B);
|
||||
tr0_1 = _mm_unpackhi_epi16(C, D);
|
||||
const __m128i s9s8 = _mm_unpacklo_epi32(tr0_0, tr0_1);
|
||||
const __m128i sbsa = _mm_srli_si128(s9s8, 8);
|
||||
|
||||
// multiply 2 adjacent elements with the filter and add the result
|
||||
const __m128i x0 = _mm_maddubs_epi16(s1s0, f[0]);
|
||||
const __m128i x1 = _mm_maddubs_epi16(s3s2, f[1]);
|
||||
const __m128i x2 = _mm_maddubs_epi16(s5s4, f[2]);
|
||||
const __m128i x3 = _mm_maddubs_epi16(s7s6, f[3]);
|
||||
const __m128i x4 = _mm_maddubs_epi16(s9s8, f[4]);
|
||||
const __m128i x5 = _mm_maddubs_epi16(sbsa, f[5]);
|
||||
// add and saturate the results together
|
||||
const __m128i min_x2x3 = _mm_min_epi16(x2, x3);
|
||||
const __m128i max_x2x3 = _mm_max_epi16(x2, x3);
|
||||
__m128i temp = _mm_adds_epi16(x0, x1);
|
||||
temp = _mm_adds_epi16(temp, x5);
|
||||
temp = _mm_adds_epi16(temp, x4);
|
||||
|
||||
temp = _mm_adds_epi16(temp, min_x2x3);
|
||||
temp = _mm_adds_epi16(temp, max_x2x3);
|
||||
// round and shift by 7 bit each 16 bit
|
||||
temp = _mm_mulhrs_epi16(temp, k_256);
|
||||
// shrink to 8 bit each 16 bits
|
||||
temp = _mm_packus_epi16(temp, temp);
|
||||
// save only 4 bytes
|
||||
*(int *)dst = _mm_cvtsi128_si32(temp);
|
||||
}
|
||||
|
||||
// Testing wrapper functions
|
||||
|
||||
void run_target_filter(uint8_t *src, int width, int height, int stride,
|
||||
struct Filter filter, uint8_t *dst) {
|
||||
uint32_t start, end;
|
||||
int count = 0;
|
||||
|
||||
start = readtsc();
|
||||
do {
|
||||
horiz_filter_ssse3(src, filter, width, dst);
|
||||
src += stride;
|
||||
dst += stride;
|
||||
count++;
|
||||
} while (count < height);
|
||||
end = readtsc();
|
||||
|
||||
printf("SIMD HorizP cycles:\t%d\n\n", end - start);
|
||||
}
|
||||
|
||||
// for Horiz4 method (subpixel)
|
||||
void run_subpixel_v4p_filter(uint8_t *src, int width, int height, int stride,
|
||||
const struct Filter filter, uint8_t *dst) {
|
||||
uint8_t temp[4 * 4] __attribute__ ((aligned(16)));
|
||||
__m128i f[6];
|
||||
int tapsNum;
|
||||
uint8_t *src_ptr;
|
||||
uint32_t start, end;
|
||||
int count;
|
||||
int block_height;
|
||||
int col, i;
|
||||
|
||||
start = readtsc();
|
||||
|
||||
tapsNum = filter.tapsNum;
|
||||
count = 0;
|
||||
block_height = height >> 2;
|
||||
src_ptr = src;
|
||||
f[0] = *((__m128i *)(filter.coeffs));
|
||||
f[1] = *((__m128i *)(filter.coeffs + 1));
|
||||
f[2] = *((__m128i *)(filter.coeffs + 2));
|
||||
f[3] = *((__m128i *)(filter.coeffs + 3));
|
||||
f[4] = *((__m128i *)(filter.coeffs + 4));
|
||||
f[5] = *((__m128i *)(filter.coeffs + 5));
|
||||
|
||||
do {
|
||||
for (col = 0; col < width; col += 4) {
|
||||
for (i = 0; i < 4; ++i) {
|
||||
filter_horiz_v4p_ssse3(src_ptr, stride, f, tapsNum, temp + (i * 4));
|
||||
src_ptr += 1;
|
||||
}
|
||||
transpose4x4_to_dst(temp, 4, dst + col, stride);
|
||||
}
|
||||
count++;
|
||||
src_ptr = src + count * stride * 4;
|
||||
dst += stride * 4;
|
||||
} while (count < block_height);
|
||||
end = readtsc();
|
||||
|
||||
printf("SIMD Horiz4 cycles:\t%d\n\n", end - start);
|
||||
}
|
||||
|
||||
// for Horiz8 method (subpixel)
|
||||
void run_subpixel_v8p_filter(uint8_t *src, int width, int height, int stride,
|
||||
const struct Filter filter, uint8_t *dst) {
|
||||
uint8_t temp[8 * 8] __attribute__ ((aligned(16)));
|
||||
__m128i f[6];
|
||||
int tapsNum;
|
||||
uint8_t *src_ptr;
|
||||
uint32_t start, end;
|
||||
int count;
|
||||
int block_height;
|
||||
int col, i;
|
||||
|
||||
start = readtsc();
|
||||
|
||||
tapsNum = filter.tapsNum;
|
||||
count = 0;
|
||||
block_height = height >> 3;
|
||||
src_ptr = src;
|
||||
f[0] = *((__m128i *)(filter.coeffs));
|
||||
f[1] = *((__m128i *)(filter.coeffs + 1));
|
||||
f[2] = *((__m128i *)(filter.coeffs + 2));
|
||||
f[3] = *((__m128i *)(filter.coeffs + 3));
|
||||
f[4] = *((__m128i *)(filter.coeffs + 4));
|
||||
f[5] = *((__m128i *)(filter.coeffs + 5));
|
||||
|
||||
do {
|
||||
for (col = 0; col < width; col += 8) {
|
||||
for (i = 0; i < 8; ++i) {
|
||||
filter_horiz_v8p_ssse3(src_ptr, stride, f, tapsNum, temp + (i * 8));
|
||||
src_ptr += 1;
|
||||
}
|
||||
transpose8x8_to_dst(temp, 8, dst + col, stride);
|
||||
}
|
||||
count++;
|
||||
src_ptr = src + count * stride * 8;
|
||||
dst += stride * 8;
|
||||
} while (count < block_height);
|
||||
end = readtsc();
|
||||
|
||||
printf("SIMD Horiz8 cycles:\t%d\n\n", end - start);
|
||||
}
|
||||
|
||||
// Test driver main()
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// We simulate HD width (1920) and max super block height (128)
|
||||
const size_t block_size = HD_WIDTH * SUPER_BLOCK_HEIGHT;
|
||||
|
||||
if (argc != 4) {
|
||||
printf("Usage: horiz_filter <seed> <width> <height>\n");
|
||||
printf("width/height = 4, 8, 16, 32, 64, 128, seed = random seed number.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int width = atoi(argv[2]);
|
||||
const unsigned int random_seed = atoi(argv[1]);
|
||||
const int height = atoi(argv[3]);
|
||||
const int stride = HD_WIDTH;
|
||||
|
||||
assert(0 == width % 4);
|
||||
assert(0 == height % 4);
|
||||
|
||||
uint8_t *buffer = (uint8_t *) malloc(2 * sizeof(buffer[0]) * block_size);
|
||||
uint8_t *pixel = (uint8_t *) malloc(2 * sizeof(pixel[0]) * block_size);
|
||||
uint8_t *ppixel = pixel + block_size;
|
||||
uint8_t *pbuffer = buffer + block_size;
|
||||
|
||||
init_state(buffer, pixel, 8 + width, height, stride, random_seed);
|
||||
init_state(pbuffer, ppixel, 8 + width, height, stride, random_seed);
|
||||
|
||||
if (width >= 8 && height >= 8) {
|
||||
run_prototype_filter(pixel, width, height, stride, filter10, 10, buffer);
|
||||
run_target_filter(ppixel, width, height, stride, pfilter_10tap, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
|
||||
run_subpixel_v4p_filter(ppixel, width, height, stride,
|
||||
pfilter_10tap_subpixel, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
|
||||
run_subpixel_v8p_filter(ppixel, width, height, stride,
|
||||
pfilter_10tap_subpixel, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
|
||||
run_prototype_filter(pixel, width, height, stride, filter12, 12, buffer);
|
||||
run_target_filter(ppixel, width, height, stride, pfilter_12tap, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
|
||||
run_subpixel_v4p_filter(ppixel, width, height, stride,
|
||||
pfilter_12tap_subpixel, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
|
||||
run_subpixel_v8p_filter(ppixel, width, height, stride,
|
||||
pfilter_12tap_subpixel, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
} else {
|
||||
run_prototype_filter(pixel, width, height, stride, filter12, 12, buffer);
|
||||
run_target_filter(ppixel, width, height, stride, pfilter_12tap, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
|
||||
run_subpixel_v4p_filter(ppixel, width, height, stride,
|
||||
pfilter_12tap_subpixel, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
|
||||
run_prototype_filter(pixel, width, height, stride, filter10, 10, buffer);
|
||||
run_target_filter(ppixel, width, height, stride, pfilter_10tap, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
|
||||
run_subpixel_v4p_filter(ppixel, width, height, stride,
|
||||
pfilter_10tap_subpixel, pbuffer);
|
||||
check_buffer(buffer, pbuffer, width, height, stride);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
free(pixel);
|
||||
return 0;
|
||||
}
|
48
docs.mk
48
docs.mk
@ -1,48 +0,0 @@
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
|
||||
INSTALL_MAPS += docs/% docs/%
|
||||
INSTALL_MAPS += src/% %
|
||||
INSTALL_MAPS += % %
|
||||
|
||||
# Static documentation authored in doxygen
|
||||
CODEC_DOX := mainpage.dox \
|
||||
keywords.dox \
|
||||
usage.dox \
|
||||
usage_cx.dox \
|
||||
usage_dx.dox \
|
||||
|
||||
# Other doxy files sourced in Markdown
|
||||
TXT_DOX = $(call enabled,TXT_DOX)
|
||||
|
||||
EXAMPLE_PATH += $(SRC_PATH_BARE) #for CHANGELOG, README, etc
|
||||
EXAMPLE_PATH += $(SRC_PATH_BARE)/examples
|
||||
|
||||
doxyfile: $(if $(findstring examples, $(ALL_TARGETS)),examples.doxy)
|
||||
doxyfile: libs.doxy_template libs.doxy
|
||||
@echo " [CREATE] $@"
|
||||
@cat $^ > $@
|
||||
@echo "STRIP_FROM_PATH += $(SRC_PATH_BARE) $(BUILD_ROOT)" >> $@
|
||||
@echo "INPUT += $(addprefix $(SRC_PATH_BARE)/,$(CODEC_DOX))" >> $@;
|
||||
@echo "INPUT += $(TXT_DOX)" >> $@;
|
||||
@echo "EXAMPLE_PATH += $(EXAMPLE_PATH)" >> $@
|
||||
|
||||
CLEAN-OBJS += doxyfile $(wildcard docs/html/*)
|
||||
docs/html/index.html: doxyfile $(CODEC_DOX) $(TXT_DOX)
|
||||
@echo " [DOXYGEN] $<"
|
||||
@doxygen $<
|
||||
DOCS-yes += docs/html/index.html
|
||||
|
||||
DIST-DOCS-yes = $(wildcard docs/html/*)
|
||||
DIST-DOCS-$(CONFIG_CODEC_SRCS) += $(addprefix src/,$(CODEC_DOX))
|
||||
DIST-DOCS-$(CONFIG_CODEC_SRCS) += src/libs.doxy_template
|
||||
DIST-DOCS-yes += CHANGELOG
|
||||
DIST-DOCS-yes += README
|
404
examples.mk
404
examples.mk
@ -1,404 +0,0 @@
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
LIBYUV_SRCS += third_party/libyuv/include/libyuv/basic_types.h \
|
||||
third_party/libyuv/include/libyuv/convert.h \
|
||||
third_party/libyuv/include/libyuv/convert_argb.h \
|
||||
third_party/libyuv/include/libyuv/convert_from.h \
|
||||
third_party/libyuv/include/libyuv/cpu_id.h \
|
||||
third_party/libyuv/include/libyuv/planar_functions.h \
|
||||
third_party/libyuv/include/libyuv/rotate.h \
|
||||
third_party/libyuv/include/libyuv/row.h \
|
||||
third_party/libyuv/include/libyuv/scale.h \
|
||||
third_party/libyuv/include/libyuv/scale_row.h \
|
||||
third_party/libyuv/source/cpu_id.cc \
|
||||
third_party/libyuv/source/planar_functions.cc \
|
||||
third_party/libyuv/source/row_any.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_neon.cc \
|
||||
third_party/libyuv/source/row_neon64.cc \
|
||||
third_party/libyuv/source/row_win.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_gcc.cc \
|
||||
third_party/libyuv/source/scale_mips.cc \
|
||||
third_party/libyuv/source/scale_neon.cc \
|
||||
third_party/libyuv/source/scale_neon64.cc \
|
||||
third_party/libyuv/source/scale_win.cc \
|
||||
|
||||
LIBWEBM_COMMON_SRCS += third_party/libwebm/common/hdr_util.cc \
|
||||
third_party/libwebm/common/hdr_util.h \
|
||||
third_party/libwebm/common/webmids.h
|
||||
|
||||
LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer/mkvmuxer.cc \
|
||||
third_party/libwebm/mkvmuxer/mkvmuxerutil.cc \
|
||||
third_party/libwebm/mkvmuxer/mkvwriter.cc \
|
||||
third_party/libwebm/mkvmuxer/mkvmuxer.h \
|
||||
third_party/libwebm/mkvmuxer/mkvmuxertypes.h \
|
||||
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
|
||||
|
||||
|
||||
# List of examples to build. UTILS are tools meant for distribution
|
||||
# while EXAMPLES demonstrate specific portions of the API.
|
||||
UTILS-$(CONFIG_DECODERS) += vpxdec.c
|
||||
vpxdec.SRCS += md5_utils.c md5_utils.h
|
||||
vpxdec.SRCS += vpx_ports/mem_ops.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/vpx_integer.h
|
||||
vpxdec.SRCS += args.c args.h
|
||||
vpxdec.SRCS += ivfdec.c ivfdec.h
|
||||
vpxdec.SRCS += tools_common.c tools_common.h
|
||||
vpxdec.SRCS += y4menc.c y4menc.h
|
||||
ifeq ($(CONFIG_LIBYUV),yes)
|
||||
vpxdec.SRCS += $(LIBYUV_SRCS)
|
||||
$(BUILD_PFX)third_party/libyuv/%.cc.o: CXXFLAGS += -Wno-unused-parameter
|
||||
endif
|
||||
ifeq ($(CONFIG_WEBM_IO),yes)
|
||||
vpxdec.SRCS += $(LIBWEBM_COMMON_SRCS)
|
||||
vpxdec.SRCS += $(LIBWEBM_MUXER_SRCS)
|
||||
vpxdec.SRCS += $(LIBWEBM_PARSER_SRCS)
|
||||
vpxdec.SRCS += webmdec.cc webmdec.h
|
||||
endif
|
||||
vpxdec.GUID = BA5FE66F-38DD-E034-F542-B1578C5FB950
|
||||
vpxdec.DESCRIPTION = Full featured decoder
|
||||
UTILS-$(CONFIG_ENCODERS) += vpxenc.c
|
||||
vpxenc.SRCS += args.c args.h y4minput.c y4minput.h vpxenc.h
|
||||
vpxenc.SRCS += ivfdec.c ivfdec.h
|
||||
vpxenc.SRCS += ivfenc.c ivfenc.h
|
||||
vpxenc.SRCS += rate_hist.c rate_hist.h
|
||||
vpxenc.SRCS += tools_common.c tools_common.h
|
||||
vpxenc.SRCS += warnings.c warnings.h
|
||||
vpxenc.SRCS += vpx_ports/mem_ops.h
|
||||
vpxenc.SRCS += vpx_ports/mem_ops_aligned.h
|
||||
vpxenc.SRCS += vpx_ports/msvc.h
|
||||
vpxenc.SRCS += vpx_ports/vpx_timer.h
|
||||
vpxenc.SRCS += vpxstats.c vpxstats.h
|
||||
ifeq ($(CONFIG_LIBYUV),yes)
|
||||
vpxenc.SRCS += $(LIBYUV_SRCS)
|
||||
endif
|
||||
ifeq ($(CONFIG_WEBM_IO),yes)
|
||||
vpxenc.SRCS += $(LIBWEBM_COMMON_SRCS)
|
||||
vpxenc.SRCS += $(LIBWEBM_MUXER_SRCS)
|
||||
vpxenc.SRCS += $(LIBWEBM_PARSER_SRCS)
|
||||
vpxenc.SRCS += webmenc.cc webmenc.h
|
||||
endif
|
||||
vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
|
||||
vpxenc.DESCRIPTION = Full featured encoder
|
||||
|
||||
EXAMPLES-$(CONFIG_VP9_ENCODER) += vp9_spatial_svc_encoder.c
|
||||
vp9_spatial_svc_encoder.SRCS += args.c args.h
|
||||
vp9_spatial_svc_encoder.SRCS += ivfenc.c ivfenc.h
|
||||
vp9_spatial_svc_encoder.SRCS += tools_common.c tools_common.h
|
||||
vp9_spatial_svc_encoder.SRCS += video_common.h
|
||||
vp9_spatial_svc_encoder.SRCS += video_writer.h video_writer.c
|
||||
vp9_spatial_svc_encoder.SRCS += vpx_ports/msvc.h
|
||||
vp9_spatial_svc_encoder.SRCS += vpxstats.c vpxstats.h
|
||||
vp9_spatial_svc_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D
|
||||
vp9_spatial_svc_encoder.DESCRIPTION = VP9 Spatial SVC Encoder
|
||||
|
||||
ifneq ($(CONFIG_SHARED),yes)
|
||||
EXAMPLES-$(CONFIG_VP9_ENCODER) += resize_util.c
|
||||
endif
|
||||
|
||||
EXAMPLES-$(CONFIG_ENCODERS) += vpx_temporal_svc_encoder.c
|
||||
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 += video_common.h
|
||||
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.DESCRIPTION = Temporal SVC Encoder
|
||||
EXAMPLES-$(CONFIG_DECODERS) += simple_decoder.c
|
||||
simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC
|
||||
simple_decoder.SRCS += ivfdec.h ivfdec.c
|
||||
simple_decoder.SRCS += tools_common.h tools_common.c
|
||||
simple_decoder.SRCS += video_common.h
|
||||
simple_decoder.SRCS += video_reader.h video_reader.c
|
||||
simple_decoder.SRCS += vpx_ports/mem_ops.h
|
||||
simple_decoder.SRCS += vpx_ports/mem_ops_aligned.h
|
||||
simple_decoder.SRCS += vpx_ports/msvc.h
|
||||
simple_decoder.DESCRIPTION = Simplified decoder loop
|
||||
EXAMPLES-$(CONFIG_DECODERS) += postproc.c
|
||||
postproc.SRCS += ivfdec.h ivfdec.c
|
||||
postproc.SRCS += tools_common.h tools_common.c
|
||||
postproc.SRCS += video_common.h
|
||||
postproc.SRCS += video_reader.h video_reader.c
|
||||
postproc.SRCS += vpx_ports/mem_ops.h
|
||||
postproc.SRCS += vpx_ports/mem_ops_aligned.h
|
||||
postproc.SRCS += vpx_ports/msvc.h
|
||||
postproc.GUID = 65E33355-F35E-4088-884D-3FD4905881D7
|
||||
postproc.DESCRIPTION = Decoder postprocessor control
|
||||
EXAMPLES-$(CONFIG_DECODERS) += decode_to_md5.c
|
||||
decode_to_md5.SRCS += md5_utils.h md5_utils.c
|
||||
decode_to_md5.SRCS += ivfdec.h ivfdec.c
|
||||
decode_to_md5.SRCS += tools_common.h tools_common.c
|
||||
decode_to_md5.SRCS += video_common.h
|
||||
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_aligned.h
|
||||
decode_to_md5.SRCS += vpx_ports/msvc.h
|
||||
decode_to_md5.GUID = 59120B9B-2735-4BFE-B022-146CA340FE42
|
||||
decode_to_md5.DESCRIPTION = Frame by frame MD5 checksum
|
||||
EXAMPLES-$(CONFIG_ENCODERS) += simple_encoder.c
|
||||
simple_encoder.SRCS += ivfenc.h ivfenc.c
|
||||
simple_encoder.SRCS += tools_common.h tools_common.c
|
||||
simple_encoder.SRCS += video_common.h
|
||||
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.DESCRIPTION = Simplified encoder loop
|
||||
EXAMPLES-$(CONFIG_VP9_ENCODER) += vp9_lossless_encoder.c
|
||||
vp9_lossless_encoder.SRCS += ivfenc.h ivfenc.c
|
||||
vp9_lossless_encoder.SRCS += tools_common.h tools_common.c
|
||||
vp9_lossless_encoder.SRCS += video_common.h
|
||||
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.DESCRIPTION = Simplified lossless VP9 encoder
|
||||
EXAMPLES-$(CONFIG_ENCODERS) += twopass_encoder.c
|
||||
twopass_encoder.SRCS += ivfenc.h ivfenc.c
|
||||
twopass_encoder.SRCS += tools_common.h tools_common.c
|
||||
twopass_encoder.SRCS += video_common.h
|
||||
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.DESCRIPTION = Two-pass encoder loop
|
||||
EXAMPLES-$(CONFIG_DECODERS) += decode_with_drops.c
|
||||
decode_with_drops.SRCS += ivfdec.h ivfdec.c
|
||||
decode_with_drops.SRCS += tools_common.h tools_common.c
|
||||
decode_with_drops.SRCS += video_common.h
|
||||
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_aligned.h
|
||||
decode_with_drops.SRCS += vpx_ports/msvc.h
|
||||
decode_with_drops.GUID = CE5C53C4-8DDA-438A-86ED-0DDD3CDB8D26
|
||||
decode_with_drops.DESCRIPTION = Drops frames while decoding
|
||||
EXAMPLES-$(CONFIG_ENCODERS) += set_maps.c
|
||||
set_maps.SRCS += ivfenc.h ivfenc.c
|
||||
set_maps.SRCS += tools_common.h tools_common.c
|
||||
set_maps.SRCS += video_common.h
|
||||
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.DESCRIPTION = Set active and ROI maps
|
||||
EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8cx_set_ref.c
|
||||
vp8cx_set_ref.SRCS += ivfenc.h ivfenc.c
|
||||
vp8cx_set_ref.SRCS += tools_common.h tools_common.c
|
||||
vp8cx_set_ref.SRCS += video_common.h
|
||||
vp8cx_set_ref.SRCS += video_writer.h video_writer.c
|
||||
vp8cx_set_ref.SRCS += vpx_ports/msvc.h
|
||||
vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A
|
||||
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_LIBYUV),yes)
|
||||
EXAMPLES-$(CONFIG_VP8_ENCODER) += vp8_multi_resolution_encoder.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 += 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.GUID = 04f8738e-63c8-423b-90fa-7c2703a374de
|
||||
vp8_multi_resolution_encoder.DESCRIPTION = VP8 Multiple-resolution Encoding
|
||||
endif
|
||||
endif
|
||||
|
||||
# Handle extra library flags depending on codec configuration
|
||||
|
||||
# We should not link to math library (libm) on RVCT
|
||||
# when building for bare-metal targets
|
||||
ifeq ($(CONFIG_OS_SUPPORT), yes)
|
||||
CODEC_EXTRA_LIBS-$(CONFIG_VP8) += m
|
||||
CODEC_EXTRA_LIBS-$(CONFIG_VP9) += m
|
||||
else
|
||||
ifeq ($(CONFIG_GCC), yes)
|
||||
CODEC_EXTRA_LIBS-$(CONFIG_VP8) += m
|
||||
CODEC_EXTRA_LIBS-$(CONFIG_VP9) += m
|
||||
endif
|
||||
endif
|
||||
#
|
||||
# End of specified files. The rest of the build rules should happen
|
||||
# automagically from here.
|
||||
#
|
||||
|
||||
|
||||
# Examples need different flags based on whether we're building
|
||||
# from an installed tree or a version controlled tree. Determine
|
||||
# the proper paths.
|
||||
ifeq ($(HAVE_ALT_TREE_LAYOUT),yes)
|
||||
LIB_PATH-yes := $(SRC_PATH_BARE)/../lib
|
||||
INC_PATH-yes := $(SRC_PATH_BARE)/../include
|
||||
else
|
||||
LIB_PATH-yes += $(if $(BUILD_PFX),$(BUILD_PFX),.)
|
||||
INC_PATH-$(CONFIG_VP8_DECODER) += $(SRC_PATH_BARE)/vp8
|
||||
INC_PATH-$(CONFIG_VP8_ENCODER) += $(SRC_PATH_BARE)/vp8
|
||||
INC_PATH-$(CONFIG_VP9_DECODER) += $(SRC_PATH_BARE)/vp9
|
||||
INC_PATH-$(CONFIG_VP9_ENCODER) += $(SRC_PATH_BARE)/vp9
|
||||
endif
|
||||
INC_PATH-$(CONFIG_LIBYUV) += $(SRC_PATH_BARE)/third_party/libyuv/include
|
||||
LIB_PATH := $(call enabled,LIB_PATH)
|
||||
INC_PATH := $(call enabled,INC_PATH)
|
||||
INTERNAL_CFLAGS = $(addprefix -I,$(INC_PATH))
|
||||
INTERNAL_LDFLAGS += $(addprefix -L,$(LIB_PATH))
|
||||
|
||||
|
||||
# Expand list of selected examples to build (as specified above)
|
||||
UTILS = $(call enabled,UTILS)
|
||||
EXAMPLES = $(addprefix examples/,$(call enabled,EXAMPLES))
|
||||
ALL_EXAMPLES = $(UTILS) $(EXAMPLES)
|
||||
UTIL_SRCS = $(foreach ex,$(UTILS),$($(ex:.c=).SRCS))
|
||||
ALL_SRCS = $(foreach ex,$(ALL_EXAMPLES),$($(notdir $(ex:.c=)).SRCS))
|
||||
CODEC_EXTRA_LIBS=$(sort $(call enabled,CODEC_EXTRA_LIBS))
|
||||
|
||||
|
||||
# Expand all example sources into a variable containing all sources
|
||||
# for that example (not just them main one specified in UTILS/EXAMPLES)
|
||||
# and add this file to the list (for MSVS workspace generation)
|
||||
$(foreach ex,$(ALL_EXAMPLES),$(eval $(notdir $(ex:.c=)).SRCS += $(ex) examples.mk))
|
||||
|
||||
|
||||
# Create build/install dependencies for all examples. The common case
|
||||
# is handled here. The MSVS case is handled below.
|
||||
NOT_MSVS = $(if $(CONFIG_MSVS),,yes)
|
||||
DIST-BINS-$(NOT_MSVS) += $(addprefix bin/,$(ALL_EXAMPLES:.c=$(EXE_SFX)))
|
||||
INSTALL-BINS-$(NOT_MSVS) += $(addprefix bin/,$(UTILS:.c=$(EXE_SFX)))
|
||||
DIST-SRCS-yes += $(ALL_SRCS)
|
||||
INSTALL-SRCS-yes += $(UTIL_SRCS)
|
||||
OBJS-$(NOT_MSVS) += $(call objs,$(ALL_SRCS))
|
||||
BINS-$(NOT_MSVS) += $(addprefix $(BUILD_PFX),$(ALL_EXAMPLES:.c=$(EXE_SFX)))
|
||||
|
||||
|
||||
# Instantiate linker template for all examples.
|
||||
CODEC_LIB=$(if $(CONFIG_DEBUG_LIBS),vpx_g,vpx)
|
||||
ifneq ($(filter darwin%,$(TGT_OS)),)
|
||||
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)
|
||||
$(foreach bin,$(BINS-yes),\
|
||||
$(eval $(bin):$(LIB_PATH)/lib$(CODEC_LIB)$(CODEC_LIB_SUF))\
|
||||
$(eval $(call linker_template,$(bin),\
|
||||
$(call objs,$($(notdir $(bin:$(EXE_SFX)=)).SRCS)) \
|
||||
-l$(CODEC_LIB) $(addprefix -l,$(CODEC_EXTRA_LIBS))\
|
||||
)))
|
||||
|
||||
# The following pairs define a mapping of locations in the distribution
|
||||
# tree to locations in the source/build trees.
|
||||
INSTALL_MAPS += src/%.c %.c
|
||||
INSTALL_MAPS += src/% $(SRC_PATH_BARE)/%
|
||||
INSTALL_MAPS += bin/% %
|
||||
INSTALL_MAPS += % %
|
||||
|
||||
|
||||
# Set up additional MSVS environment
|
||||
ifeq ($(CONFIG_MSVS),yes)
|
||||
CODEC_LIB=$(if $(CONFIG_SHARED),vpx,$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd))
|
||||
# This variable uses deferred expansion intentionally, since the results of
|
||||
# $(wildcard) may change during the course of the Make.
|
||||
VS_PLATFORMS = $(foreach d,$(wildcard */Release/$(CODEC_LIB).lib),$(word 1,$(subst /, ,$(d))))
|
||||
INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),bin/$(p)/% $(p)/Release/%)
|
||||
endif
|
||||
|
||||
# Build Visual Studio Projects. We use a template here to instantiate
|
||||
# explicit rules rather than using an implicit rule because we want to
|
||||
# leverage make's VPATH searching rather than specifying the paths on
|
||||
# each file in ALL_EXAMPLES. This has the unfortunate side effect that
|
||||
# touching the source files trigger a rebuild of the project files
|
||||
# even though there is no real dependency there (the dependency is on
|
||||
# the makefiles). We may want to revisit this.
|
||||
define vcproj_template
|
||||
$(1): $($(1:.$(VCPROJ_SFX)=).SRCS) vpx.$(VCPROJ_SFX)
|
||||
$(if $(quiet),@echo " [vcproj] $$@")
|
||||
$(qexec)$$(GEN_VCPROJ)\
|
||||
--exe\
|
||||
--target=$$(TOOLCHAIN)\
|
||||
--name=$$(@:.$(VCPROJ_SFX)=)\
|
||||
--ver=$$(CONFIG_VS_VERSION)\
|
||||
--proj-guid=$$($$(@:.$(VCPROJ_SFX)=).GUID)\
|
||||
--src-path-bare="$(SRC_PATH_BARE)" \
|
||||
$$(if $$(CONFIG_STATIC_MSVCRT),--static-crt) \
|
||||
--out=$$@ $$(INTERNAL_CFLAGS) $$(CFLAGS) \
|
||||
$$(INTERNAL_LDFLAGS) $$(LDFLAGS) -l$$(CODEC_LIB) $$^
|
||||
endef
|
||||
ALL_EXAMPLES_BASENAME := $(notdir $(ALL_EXAMPLES))
|
||||
PROJECTS-$(CONFIG_MSVS) += $(ALL_EXAMPLES_BASENAME:.c=.$(VCPROJ_SFX))
|
||||
INSTALL-BINS-$(CONFIG_MSVS) += $(foreach p,$(VS_PLATFORMS),\
|
||||
$(addprefix bin/$(p)/,$(ALL_EXAMPLES_BASENAME:.c=.exe)))
|
||||
$(foreach proj,$(call enabled,PROJECTS),\
|
||||
$(eval $(call vcproj_template,$(proj))))
|
||||
|
||||
#
|
||||
# Documentation Rules
|
||||
#
|
||||
%.dox: %.c
|
||||
@echo " [DOXY] $@"
|
||||
@mkdir -p $(dir $@)
|
||||
@echo "/*!\page example_$(@F:.dox=) $(@F:.dox=)" > $@
|
||||
@echo " \includelineno $(<F)" >> $@
|
||||
@echo "*/" >> $@
|
||||
|
||||
samples.dox: examples.mk
|
||||
@echo " [DOXY] $@"
|
||||
@echo "/*!\page samples Sample Code" > $@
|
||||
@echo " This SDK includes a number of sample applications."\
|
||||
"Each sample documents a feature of the SDK in both prose"\
|
||||
"and the associated C code."\
|
||||
"The following samples are included: ">>$@
|
||||
@$(foreach ex,$(sort $(notdir $(EXAMPLES:.c=))),\
|
||||
echo " - \subpage example_$(ex) $($(ex).DESCRIPTION)" >> $@;)
|
||||
@echo >> $@
|
||||
@echo " In addition, the SDK contains a number of utilities."\
|
||||
"Since these utilities are built upon the concepts described"\
|
||||
"in the sample code listed above, they are not documented in"\
|
||||
"pieces like the samples are. Their source is included here"\
|
||||
"for reference. The following utilities are included:" >> $@
|
||||
@$(foreach ex,$(sort $(UTILS:.c=)),\
|
||||
echo " - \subpage example_$(ex) $($(ex).DESCRIPTION)" >> $@;)
|
||||
@echo "*/" >> $@
|
||||
|
||||
CLEAN-OBJS += examples.doxy samples.dox $(ALL_EXAMPLES:.c=.dox)
|
||||
DOCS-yes += examples.doxy samples.dox
|
||||
examples.doxy: samples.dox $(ALL_EXAMPLES:.c=.dox)
|
||||
@echo "INPUT += $^" > $@
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Frame-by-frame MD5 Checksum
|
||||
// ===========================
|
||||
//
|
||||
// This example builds upon the simple decoder loop to show how checksums
|
||||
// of the decoded output can be generated. These are used for validating
|
||||
// decoder implementations against the reference implementation, for example.
|
||||
//
|
||||
// MD5 algorithm
|
||||
// -------------
|
||||
// The Message-Digest 5 (MD5) is a well known hash function. We have provided
|
||||
// an implementation derived from the RSA Data Security, Inc. MD5 Message-Digest
|
||||
// Algorithm for your use. Our implmentation only changes the interface of this
|
||||
// reference code. You must include the `md5_utils.h` header for access to these
|
||||
// functions.
|
||||
//
|
||||
// Processing The Decoded Data
|
||||
// ---------------------------
|
||||
// Each row of the image is passed to the MD5 accumulator. First the Y plane
|
||||
// is processed, then U, then V. It is important to honor the image's `stride`
|
||||
// values.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx/vp8dx.h"
|
||||
#include "vpx/vpx_decoder.h"
|
||||
|
||||
#include "../md5_utils.h"
|
||||
#include "../tools_common.h"
|
||||
#include "../video_reader.h"
|
||||
#include "./vpx_config.h"
|
||||
|
||||
static void get_image_md5(const vpx_image_t *img, unsigned char digest[16]) {
|
||||
int plane, y;
|
||||
MD5Context md5;
|
||||
|
||||
MD5Init(&md5);
|
||||
|
||||
for (plane = 0; plane < 3; ++plane) {
|
||||
const unsigned char *buf = img->planes[plane];
|
||||
const int stride = img->stride[plane];
|
||||
const int w = plane ? (img->d_w + 1) >> 1 : img->d_w;
|
||||
const int h = plane ? (img->d_h + 1) >> 1 : img->d_h;
|
||||
|
||||
for (y = 0; y < h; ++y) {
|
||||
MD5Update(&md5, buf, w);
|
||||
buf += stride;
|
||||
}
|
||||
}
|
||||
|
||||
MD5Final(digest, &md5);
|
||||
}
|
||||
|
||||
static void print_md5(FILE *stream, unsigned char digest[16]) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i) fprintf(stream, "%02x", digest[i]);
|
||||
}
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr, "Usage: %s <infile> <outfile>\n", exec_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt = 0;
|
||||
FILE *outfile = NULL;
|
||||
vpx_codec_ctx_t codec;
|
||||
VpxVideoReader *reader = NULL;
|
||||
const VpxVideoInfo *info = NULL;
|
||||
const VpxInterface *decoder = NULL;
|
||||
|
||||
exec_name = argv[0];
|
||||
|
||||
if (argc != 3) die("Invalid number of arguments.");
|
||||
|
||||
reader = vpx_video_reader_open(argv[1]);
|
||||
if (!reader) die("Failed to open %s for reading.", argv[1]);
|
||||
|
||||
if (!(outfile = fopen(argv[2], "wb")))
|
||||
die("Failed to open %s for writing.", argv[2]);
|
||||
|
||||
info = vpx_video_reader_get_info(reader);
|
||||
|
||||
decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc);
|
||||
if (!decoder) die("Unknown input codec.");
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface()));
|
||||
|
||||
if (vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
|
||||
die_codec(&codec, "Failed to initialize decoder");
|
||||
|
||||
while (vpx_video_reader_read_frame(reader)) {
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
vpx_image_t *img = NULL;
|
||||
size_t frame_size = 0;
|
||||
const unsigned char *frame =
|
||||
vpx_video_reader_get_frame(reader, &frame_size);
|
||||
if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0))
|
||||
die_codec(&codec, "Failed to decode frame");
|
||||
|
||||
while ((img = vpx_codec_get_frame(&codec, &iter)) != NULL) {
|
||||
unsigned char digest[16];
|
||||
|
||||
get_image_md5(img, digest);
|
||||
print_md5(outfile, digest);
|
||||
fprintf(outfile, " img-%dx%d-%04d.i420\n", img->d_w, img->d_h,
|
||||
++frame_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Processed %d frames.\n", frame_cnt);
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
|
||||
|
||||
vpx_video_reader_close(reader);
|
||||
|
||||
fclose(outfile);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Decode With Drops Example
|
||||
// =========================
|
||||
//
|
||||
// This is an example utility which drops a series of frames, as specified
|
||||
// on the command line. This is useful for observing the error recovery
|
||||
// features of the codec.
|
||||
//
|
||||
// Usage
|
||||
// -----
|
||||
// This example adds a single argument to the `simple_decoder` example,
|
||||
// which specifies the range or pattern of frames to drop. The parameter is
|
||||
// parsed as follows:
|
||||
//
|
||||
// Dropping A Range Of Frames
|
||||
// --------------------------
|
||||
// To drop a range of frames, specify the starting frame and the ending
|
||||
// frame to drop, separated by a dash. The following command will drop
|
||||
// frames 5 through 10 (base 1).
|
||||
//
|
||||
// $ ./decode_with_drops in.ivf out.i420 5-10
|
||||
//
|
||||
//
|
||||
// Dropping A Pattern Of Frames
|
||||
// ----------------------------
|
||||
// To drop a pattern of frames, specify the number of frames to drop and
|
||||
// the number of frames after which to repeat the pattern, separated by
|
||||
// a forward-slash. The following command will drop 3 of 7 frames.
|
||||
// Specifically, it will decode 4 frames, then drop 3 frames, and then
|
||||
// repeat.
|
||||
//
|
||||
// $ ./decode_with_drops in.ivf out.i420 3/7
|
||||
//
|
||||
//
|
||||
// Extra Variables
|
||||
// ---------------
|
||||
// This example maintains the pattern passed on the command line in the
|
||||
// `n`, `m`, and `is_range` variables:
|
||||
//
|
||||
//
|
||||
// Making The Drop Decision
|
||||
// ------------------------
|
||||
// The example decides whether to drop the frame based on the current
|
||||
// frame number, immediately before decoding the frame.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx/vp8dx.h"
|
||||
#include "vpx/vpx_decoder.h"
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../video_reader.h"
|
||||
#include "./vpx_config.h"
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr, "Usage: %s <infile> <outfile> <N-M|N/M>\n", exec_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt = 0;
|
||||
FILE *outfile = NULL;
|
||||
vpx_codec_ctx_t codec;
|
||||
const VpxInterface *decoder = NULL;
|
||||
VpxVideoReader *reader = NULL;
|
||||
const VpxVideoInfo *info = NULL;
|
||||
int n = 0;
|
||||
int m = 0;
|
||||
int is_range = 0;
|
||||
char *nptr = NULL;
|
||||
|
||||
exec_name = argv[0];
|
||||
|
||||
if (argc != 4) die("Invalid number of arguments.");
|
||||
|
||||
reader = vpx_video_reader_open(argv[1]);
|
||||
if (!reader) die("Failed to open %s for reading.", argv[1]);
|
||||
|
||||
if (!(outfile = fopen(argv[2], "wb")))
|
||||
die("Failed to open %s for writing.", argv[2]);
|
||||
|
||||
n = (int)strtol(argv[3], &nptr, 0);
|
||||
m = (int)strtol(nptr + 1, NULL, 0);
|
||||
is_range = (*nptr == '-');
|
||||
if (!n || !m || (*nptr != '-' && *nptr != '/'))
|
||||
die("Couldn't parse pattern %s.\n", argv[3]);
|
||||
|
||||
info = vpx_video_reader_get_info(reader);
|
||||
|
||||
decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc);
|
||||
if (!decoder) die("Unknown input codec.");
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface()));
|
||||
|
||||
if (vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
|
||||
die_codec(&codec, "Failed to initialize decoder.");
|
||||
|
||||
while (vpx_video_reader_read_frame(reader)) {
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
vpx_image_t *img = NULL;
|
||||
size_t frame_size = 0;
|
||||
int skip;
|
||||
const unsigned char *frame =
|
||||
vpx_video_reader_get_frame(reader, &frame_size);
|
||||
if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0))
|
||||
die_codec(&codec, "Failed to decode frame.");
|
||||
|
||||
++frame_cnt;
|
||||
|
||||
skip = (is_range && frame_cnt >= n && frame_cnt <= m) ||
|
||||
(!is_range && m - (frame_cnt - 1) % m <= n);
|
||||
|
||||
if (!skip) {
|
||||
putc('.', stdout);
|
||||
|
||||
while ((img = vpx_codec_get_frame(&codec, &iter)) != NULL)
|
||||
vpx_img_write(img, outfile);
|
||||
} else {
|
||||
putc('X', stdout);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
printf("Processed %d frames.\n", frame_cnt);
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
|
||||
|
||||
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
|
||||
info->frame_width, info->frame_height, argv[2]);
|
||||
|
||||
vpx_video_reader_close(reader);
|
||||
fclose(outfile);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// Postprocessing Decoder
|
||||
// ======================
|
||||
//
|
||||
// This example adds postprocessing to the simple decoder loop.
|
||||
//
|
||||
// Initializing Postprocessing
|
||||
// ---------------------------
|
||||
// You must inform the codec that you might request postprocessing at
|
||||
// initialization time. This is done by passing the VPX_CODEC_USE_POSTPROC
|
||||
// flag to `vpx_codec_dec_init`. If the codec does not support
|
||||
// postprocessing, this call will return VPX_CODEC_INCAPABLE. For
|
||||
// demonstration purposes, we also fall back to default initialization if
|
||||
// the codec does not provide support.
|
||||
//
|
||||
// Using Adaptive Postprocessing
|
||||
// -----------------------------
|
||||
// VP6 provides "adaptive postprocessing." It will automatically select the
|
||||
// best postprocessing filter on a frame by frame basis based on the amount
|
||||
// of time remaining before the user's specified deadline expires. The
|
||||
// special value 0 indicates that the codec should take as long as
|
||||
// necessary to provide the best quality frame. This example gives the
|
||||
// codec 15ms (15000us) to return a frame. Remember that this is a soft
|
||||
// deadline, and the codec may exceed it doing its regular processing. In
|
||||
// these cases, no additional postprocessing will be done.
|
||||
//
|
||||
// Codec Specific Postprocessing Controls
|
||||
// --------------------------------------
|
||||
// Some codecs provide fine grained controls over their built-in
|
||||
// postprocessors. VP8 is one example. The following sample code toggles
|
||||
// postprocessing on and off every 15 frames.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx/vp8dx.h"
|
||||
#include "vpx/vpx_decoder.h"
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../video_reader.h"
|
||||
#include "./vpx_config.h"
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr, "Usage: %s <infile> <outfile>\n", exec_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt = 0;
|
||||
FILE *outfile = NULL;
|
||||
vpx_codec_ctx_t codec;
|
||||
vpx_codec_err_t res;
|
||||
VpxVideoReader *reader = NULL;
|
||||
const VpxInterface *decoder = NULL;
|
||||
const VpxVideoInfo *info = NULL;
|
||||
|
||||
exec_name = argv[0];
|
||||
|
||||
if (argc != 3) die("Invalid number of arguments.");
|
||||
|
||||
reader = vpx_video_reader_open(argv[1]);
|
||||
if (!reader) die("Failed to open %s for reading.", argv[1]);
|
||||
|
||||
if (!(outfile = fopen(argv[2], "wb")))
|
||||
die("Failed to open %s for writing", argv[2]);
|
||||
|
||||
info = vpx_video_reader_get_info(reader);
|
||||
|
||||
decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc);
|
||||
if (!decoder) die("Unknown input codec.");
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface()));
|
||||
|
||||
res = vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL,
|
||||
VPX_CODEC_USE_POSTPROC);
|
||||
if (res == VPX_CODEC_INCAPABLE)
|
||||
die_codec(&codec, "Postproc not supported by this decoder.");
|
||||
|
||||
if (res) die_codec(&codec, "Failed to initialize decoder.");
|
||||
|
||||
while (vpx_video_reader_read_frame(reader)) {
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
vpx_image_t *img = NULL;
|
||||
size_t frame_size = 0;
|
||||
const unsigned char *frame =
|
||||
vpx_video_reader_get_frame(reader, &frame_size);
|
||||
|
||||
++frame_cnt;
|
||||
|
||||
if (frame_cnt % 30 == 1) {
|
||||
vp8_postproc_cfg_t pp = { 0, 0, 0 };
|
||||
|
||||
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
|
||||
die_codec(&codec, "Failed to turn off postproc.");
|
||||
} else if (frame_cnt % 30 == 16) {
|
||||
vp8_postproc_cfg_t pp = { VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE, 4,
|
||||
0 };
|
||||
if (vpx_codec_control(&codec, VP8_SET_POSTPROC, &pp))
|
||||
die_codec(&codec, "Failed to turn on postproc.");
|
||||
};
|
||||
|
||||
// Decode the frame with 15ms deadline
|
||||
if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 15000))
|
||||
die_codec(&codec, "Failed to decode frame");
|
||||
|
||||
while ((img = vpx_codec_get_frame(&codec, &iter)) != NULL) {
|
||||
vpx_img_write(img, outfile);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Processed %d frames.\n", frame_cnt);
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
|
||||
|
||||
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
|
||||
info->frame_width, info->frame_height, argv[2]);
|
||||
|
||||
vpx_video_reader_close(reader);
|
||||
|
||||
fclose(outfile);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../vp9/encoder/vp9_resize.h"
|
||||
|
||||
static const char *exec_name = NULL;
|
||||
|
||||
static void usage() {
|
||||
printf("Usage:\n");
|
||||
printf("%s <input_yuv> <width>x<height> <target_width>x<target_height> ",
|
||||
exec_name);
|
||||
printf("<output_yuv> [<frames>]\n");
|
||||
}
|
||||
|
||||
void usage_exit(void) {
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int parse_dim(char *v, int *width, int *height) {
|
||||
char *x = strchr(v, 'x');
|
||||
if (x == NULL) x = strchr(v, 'X');
|
||||
if (x == NULL) return 0;
|
||||
*width = atoi(v);
|
||||
*height = atoi(&x[1]);
|
||||
if (*width <= 0 || *height <= 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *fin, *fout;
|
||||
FILE *fpin, *fpout;
|
||||
uint8_t *inbuf, *outbuf;
|
||||
uint8_t *inbuf_u, *outbuf_u;
|
||||
uint8_t *inbuf_v, *outbuf_v;
|
||||
int f, frames;
|
||||
int width, height, target_width, target_height;
|
||||
|
||||
exec_name = argv[0];
|
||||
|
||||
if (argc < 5) {
|
||||
printf("Incorrect parameters:\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
fin = argv[1];
|
||||
fout = argv[4];
|
||||
if (!parse_dim(argv[2], &width, &height)) {
|
||||
printf("Incorrect parameters: %s\n", argv[2]);
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if (!parse_dim(argv[3], &target_width, &target_height)) {
|
||||
printf("Incorrect parameters: %s\n", argv[3]);
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
fpin = fopen(fin, "rb");
|
||||
if (fpin == NULL) {
|
||||
printf("Can't open file %s to read\n", fin);
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
fpout = fopen(fout, "wb");
|
||||
if (fpout == NULL) {
|
||||
printf("Can't open file %s to write\n", fout);
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if (argc >= 6)
|
||||
frames = atoi(argv[5]);
|
||||
else
|
||||
frames = INT_MAX;
|
||||
|
||||
printf("Input size: %dx%d\n", width, height);
|
||||
printf("Target size: %dx%d, Frames: ", target_width, target_height);
|
||||
if (frames == INT_MAX)
|
||||
printf("All\n");
|
||||
else
|
||||
printf("%d\n", frames);
|
||||
|
||||
inbuf = (uint8_t *)malloc(width * height * 3 / 2);
|
||||
outbuf = (uint8_t *)malloc(target_width * target_height * 3 / 2);
|
||||
inbuf_u = inbuf + width * height;
|
||||
inbuf_v = inbuf_u + width * height / 4;
|
||||
outbuf_u = outbuf + target_width * target_height;
|
||||
outbuf_v = outbuf_u + target_width * target_height / 4;
|
||||
f = 0;
|
||||
while (f < frames) {
|
||||
if (fread(inbuf, width * height * 3 / 2, 1, fpin) != 1) break;
|
||||
vp9_resize_frame420(inbuf, width, inbuf_u, inbuf_v, width / 2, 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);
|
||||
f++;
|
||||
}
|
||||
printf("%d frames processed\n", f);
|
||||
fclose(fpin);
|
||||
fclose(fpout);
|
||||
|
||||
free(inbuf);
|
||||
free(outbuf);
|
||||
return 0;
|
||||
}
|
@ -1,243 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// VP8 Set Active and ROI Maps
|
||||
// ===========================
|
||||
//
|
||||
// This is an example demonstrating how to control the VP8 encoder's
|
||||
// ROI and Active maps.
|
||||
//
|
||||
// ROI (Reigon of Interest) maps are a way for the application to assign
|
||||
// each macroblock in the image to a region, and then set quantizer and
|
||||
// filtering parameters on that image.
|
||||
//
|
||||
// Active maps are a way for the application to specify on a
|
||||
// macroblock-by-macroblock basis whether there is any activity in that
|
||||
// macroblock.
|
||||
//
|
||||
//
|
||||
// Configuration
|
||||
// -------------
|
||||
// An ROI map is set on frame 22. If the width of the image in macroblocks
|
||||
// is evenly divisble by 4, then the output will appear to have distinct
|
||||
// columns, where the quantizer, loopfilter, and static threshold differ
|
||||
// from column to column.
|
||||
//
|
||||
// An active map is set on frame 33. If the width of the image in macroblocks
|
||||
// is evenly divisble by 4, then the output will appear to have distinct
|
||||
// columns, where one column will have motion and the next will not.
|
||||
//
|
||||
// The active map is cleared on frame 44.
|
||||
//
|
||||
// Observing The Effects
|
||||
// ---------------------
|
||||
// Use the `simple_decoder` example to decode this sample, and observe
|
||||
// the change in the image at frames 22, 33, and 44.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx/vp8cx.h"
|
||||
#include "vpx/vpx_encoder.h"
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../video_writer.h"
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr, "Usage: %s <codec> <width> <height> <infile> <outfile>\n",
|
||||
exec_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void set_roi_map(const vpx_codec_enc_cfg_t *cfg,
|
||||
vpx_codec_ctx_t *codec) {
|
||||
unsigned int i;
|
||||
vpx_roi_map_t roi;
|
||||
memset(&roi, 0, sizeof(roi));
|
||||
|
||||
roi.rows = (cfg->g_h + 15) / 16;
|
||||
roi.cols = (cfg->g_w + 15) / 16;
|
||||
|
||||
roi.delta_q[0] = 0;
|
||||
roi.delta_q[1] = -2;
|
||||
roi.delta_q[2] = -4;
|
||||
roi.delta_q[3] = -6;
|
||||
|
||||
roi.delta_lf[0] = 0;
|
||||
roi.delta_lf[1] = 1;
|
||||
roi.delta_lf[2] = 2;
|
||||
roi.delta_lf[3] = 3;
|
||||
|
||||
roi.static_threshold[0] = 1500;
|
||||
roi.static_threshold[1] = 1000;
|
||||
roi.static_threshold[2] = 500;
|
||||
roi.static_threshold[3] = 0;
|
||||
|
||||
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;
|
||||
|
||||
if (vpx_codec_control(codec, VP8E_SET_ROI_MAP, &roi))
|
||||
die_codec(codec, "Failed to set ROI map");
|
||||
|
||||
free(roi.roi_map);
|
||||
}
|
||||
|
||||
static void set_active_map(const vpx_codec_enc_cfg_t *cfg,
|
||||
vpx_codec_ctx_t *codec) {
|
||||
unsigned int i;
|
||||
vpx_active_map_t map = { 0, 0, 0 };
|
||||
|
||||
map.rows = (cfg->g_h + 15) / 16;
|
||||
map.cols = (cfg->g_w + 15) / 16;
|
||||
|
||||
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;
|
||||
|
||||
if (vpx_codec_control(codec, VP8E_SET_ACTIVEMAP, &map))
|
||||
die_codec(codec, "Failed to set active map");
|
||||
|
||||
free(map.active_map);
|
||||
}
|
||||
|
||||
static void unset_active_map(const vpx_codec_enc_cfg_t *cfg,
|
||||
vpx_codec_ctx_t *codec) {
|
||||
vpx_active_map_t map = { 0, 0, 0 };
|
||||
|
||||
map.rows = (cfg->g_h + 15) / 16;
|
||||
map.cols = (cfg->g_w + 15) / 16;
|
||||
map.active_map = NULL;
|
||||
|
||||
if (vpx_codec_control(codec, VP8E_SET_ACTIVEMAP, &map))
|
||||
die_codec(codec, "Failed to set active map");
|
||||
}
|
||||
|
||||
static int encode_frame(vpx_codec_ctx_t *codec, vpx_image_t *img,
|
||||
int frame_index, VpxVideoWriter *writer) {
|
||||
int got_pkts = 0;
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
const vpx_codec_cx_pkt_t *pkt = NULL;
|
||||
const vpx_codec_err_t res =
|
||||
vpx_codec_encode(codec, img, frame_index, 1, 0, VPX_DL_GOOD_QUALITY);
|
||||
if (res != VPX_CODEC_OK) die_codec(codec, "Failed to encode frame");
|
||||
|
||||
while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) {
|
||||
got_pkts = 1;
|
||||
|
||||
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
|
||||
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
|
||||
if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
|
||||
pkt->data.frame.sz,
|
||||
pkt->data.frame.pts)) {
|
||||
die_codec(codec, "Failed to write compressed frame");
|
||||
}
|
||||
|
||||
printf(keyframe ? "K" : ".");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
return got_pkts;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
FILE *infile = NULL;
|
||||
vpx_codec_ctx_t codec;
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
int frame_count = 0;
|
||||
vpx_image_t raw;
|
||||
vpx_codec_err_t res;
|
||||
VpxVideoInfo info;
|
||||
VpxVideoWriter *writer = NULL;
|
||||
const VpxInterface *encoder = NULL;
|
||||
const int fps = 2; // TODO(dkovalev) add command line argument
|
||||
const double bits_per_pixel_per_frame = 0.067;
|
||||
|
||||
exec_name = argv[0];
|
||||
if (argc != 6) die("Invalid number of arguments");
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
encoder = get_vpx_encoder_by_name(argv[1]);
|
||||
if (encoder == NULL) {
|
||||
die("Unsupported codec.");
|
||||
}
|
||||
assert(encoder != NULL);
|
||||
info.codec_fourcc = encoder->fourcc;
|
||||
info.frame_width = (int)strtol(argv[2], NULL, 0);
|
||||
info.frame_height = (int)strtol(argv[3], NULL, 0);
|
||||
info.time_base.numerator = 1;
|
||||
info.time_base.denominator = fps;
|
||||
|
||||
if (info.frame_width <= 0 || info.frame_height <= 0 ||
|
||||
(info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) {
|
||||
die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
|
||||
}
|
||||
|
||||
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
|
||||
info.frame_height, 1)) {
|
||||
die("Failed to allocate image.");
|
||||
}
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
|
||||
|
||||
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
|
||||
if (res) die_codec(&codec, "Failed to get default codec config.");
|
||||
|
||||
cfg.g_w = info.frame_width;
|
||||
cfg.g_h = info.frame_height;
|
||||
cfg.g_timebase.num = info.time_base.numerator;
|
||||
cfg.g_timebase.den = info.time_base.denominator;
|
||||
cfg.rc_target_bitrate =
|
||||
(unsigned int)(bits_per_pixel_per_frame * cfg.g_w * cfg.g_h * fps / 1000);
|
||||
cfg.g_lag_in_frames = 0;
|
||||
|
||||
writer = vpx_video_writer_open(argv[5], kContainerIVF, &info);
|
||||
if (!writer) die("Failed to open %s for writing.", argv[5]);
|
||||
|
||||
if (!(infile = fopen(argv[4], "rb")))
|
||||
die("Failed to open %s for reading.", argv[4]);
|
||||
|
||||
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
|
||||
die_codec(&codec, "Failed to initialize encoder");
|
||||
|
||||
// Encode frames.
|
||||
while (vpx_img_read(&raw, infile)) {
|
||||
++frame_count;
|
||||
|
||||
if (frame_count == 22 && encoder->fourcc == VP8_FOURCC) {
|
||||
set_roi_map(&cfg, &codec);
|
||||
} else if (frame_count == 33) {
|
||||
set_active_map(&cfg, &codec);
|
||||
} else if (frame_count == 44) {
|
||||
unset_active_map(&cfg, &codec);
|
||||
}
|
||||
|
||||
encode_frame(&codec, &raw, frame_count, writer);
|
||||
}
|
||||
|
||||
// Flush encoder.
|
||||
while (encode_frame(&codec, NULL, -1, writer)) {
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fclose(infile);
|
||||
printf("Processed %d frames.\n", frame_count);
|
||||
|
||||
vpx_img_free(&raw);
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
|
||||
|
||||
vpx_video_writer_close(writer);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Simple Decoder
|
||||
// ==============
|
||||
//
|
||||
// This is an example of a simple decoder loop. It takes an input file
|
||||
// containing the compressed data (in IVF format), passes it through the
|
||||
// decoder, and writes the decompressed frames to disk. Other decoder
|
||||
// examples build upon this one.
|
||||
//
|
||||
// The details of the IVF format have been elided from this example for
|
||||
// simplicity of presentation, as IVF files will not generally be used by
|
||||
// your application. In general, an IVF file consists of a file header,
|
||||
// followed by a variable number of frames. Each frame consists of a frame
|
||||
// header followed by a variable length payload. The length of the payload
|
||||
// is specified in the first four bytes of the frame header. The payload is
|
||||
// the raw compressed data.
|
||||
//
|
||||
// Standard Includes
|
||||
// -----------------
|
||||
// For decoders, you only have to include `vpx_decoder.h` and then any
|
||||
// header files for the specific codecs you use. In this case, we're using
|
||||
// vp8.
|
||||
//
|
||||
// Initializing The Codec
|
||||
// ----------------------
|
||||
// The libvpx decoder is initialized by the call to vpx_codec_dec_init().
|
||||
// Determining the codec interface to use is handled by VpxVideoReader and the
|
||||
// functions prefixed with vpx_video_reader_. Discussion of those functions is
|
||||
// beyond the scope of this example, but the main gist is to open the input file
|
||||
// and parse just enough of it to determine if it's a VPx file and which VPx
|
||||
// codec is contained within the file.
|
||||
// Note the NULL pointer passed to vpx_codec_dec_init(). We do that in this
|
||||
// example because we want the algorithm to determine the stream configuration
|
||||
// (width/height) and allocate memory automatically.
|
||||
//
|
||||
// Decoding A Frame
|
||||
// ----------------
|
||||
// Once the frame has been read into memory, it is decoded using the
|
||||
// `vpx_codec_decode` function. The call takes a pointer to the data
|
||||
// (`frame`) and the length of the data (`frame_size`). No application data
|
||||
// is associated with the frame in this example, so the `user_priv`
|
||||
// parameter is NULL. The `deadline` parameter is left at zero for this
|
||||
// example. This parameter is generally only used when doing adaptive post
|
||||
// processing.
|
||||
//
|
||||
// Codecs may produce a variable number of output frames for every call to
|
||||
// `vpx_codec_decode`. These frames are retrieved by the
|
||||
// `vpx_codec_get_frame` iterator function. The iterator variable `iter` is
|
||||
// initialized to NULL each time `vpx_codec_decode` is called.
|
||||
// `vpx_codec_get_frame` is called in a loop, returning a pointer to a
|
||||
// decoded image or NULL to indicate the end of list.
|
||||
//
|
||||
// Processing The Decoded Data
|
||||
// ---------------------------
|
||||
// In this example, we simply write the encoded data to disk. It is
|
||||
// important to honor the image's `stride` values.
|
||||
//
|
||||
// Cleanup
|
||||
// -------
|
||||
// The `vpx_codec_destroy` call frees any memory allocated by the codec.
|
||||
//
|
||||
// Error Handling
|
||||
// --------------
|
||||
// This example does not special case any error return codes. If there was
|
||||
// an error, a descriptive message is printed and the program exits. With
|
||||
// few exceptions, vpx_codec functions return an enumerated error status,
|
||||
// with the value `0` indicating success.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx/vpx_decoder.h"
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../video_reader.h"
|
||||
#include "./vpx_config.h"
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr, "Usage: %s <infile> <outfile>\n", exec_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt = 0;
|
||||
FILE *outfile = NULL;
|
||||
vpx_codec_ctx_t codec;
|
||||
VpxVideoReader *reader = NULL;
|
||||
const VpxInterface *decoder = NULL;
|
||||
const VpxVideoInfo *info = NULL;
|
||||
|
||||
exec_name = argv[0];
|
||||
|
||||
if (argc != 3) die("Invalid number of arguments.");
|
||||
|
||||
reader = vpx_video_reader_open(argv[1]);
|
||||
if (!reader) die("Failed to open %s for reading.", argv[1]);
|
||||
|
||||
if (!(outfile = fopen(argv[2], "wb")))
|
||||
die("Failed to open %s for writing.", argv[2]);
|
||||
|
||||
info = vpx_video_reader_get_info(reader);
|
||||
|
||||
decoder = get_vpx_decoder_by_fourcc(info->codec_fourcc);
|
||||
if (!decoder) die("Unknown input codec.");
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(decoder->codec_interface()));
|
||||
|
||||
if (vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
|
||||
die_codec(&codec, "Failed to initialize decoder.");
|
||||
|
||||
while (vpx_video_reader_read_frame(reader)) {
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
vpx_image_t *img = NULL;
|
||||
size_t frame_size = 0;
|
||||
const unsigned char *frame =
|
||||
vpx_video_reader_get_frame(reader, &frame_size);
|
||||
if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0))
|
||||
die_codec(&codec, "Failed to decode frame.");
|
||||
|
||||
while ((img = vpx_codec_get_frame(&codec, &iter)) != NULL) {
|
||||
vpx_img_write(img, outfile);
|
||||
++frame_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Processed %d frames.\n", frame_cnt);
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
|
||||
|
||||
printf("Play: ffplay -f rawvideo -pix_fmt yuv420p -s %dx%d %s\n",
|
||||
info->frame_width, info->frame_height, argv[2]);
|
||||
|
||||
vpx_video_reader_close(reader);
|
||||
|
||||
fclose(outfile);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,247 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Simple Encoder
|
||||
// ==============
|
||||
//
|
||||
// This is an example of a simple encoder loop. It takes an input file in
|
||||
// YV12 format, passes it through the encoder, and writes the compressed
|
||||
// frames to disk in IVF format. Other decoder examples build upon this
|
||||
// one.
|
||||
//
|
||||
// The details of the IVF format have been elided from this example for
|
||||
// simplicity of presentation, as IVF files will not generally be used by
|
||||
// your application. In general, an IVF file consists of a file header,
|
||||
// followed by a variable number of frames. Each frame consists of a frame
|
||||
// header followed by a variable length payload. The length of the payload
|
||||
// is specified in the first four bytes of the frame header. The payload is
|
||||
// the raw compressed data.
|
||||
//
|
||||
// Standard Includes
|
||||
// -----------------
|
||||
// For encoders, you only have to include `vpx_encoder.h` and then any
|
||||
// header files for the specific codecs you use. In this case, we're using
|
||||
// vp8.
|
||||
//
|
||||
// Getting The Default Configuration
|
||||
// ---------------------------------
|
||||
// Encoders have the notion of "usage profiles." For example, an encoder
|
||||
// may want to publish default configurations for both a video
|
||||
// conferencing application and a best quality offline encoder. These
|
||||
// obviously have very different default settings. Consult the
|
||||
// documentation for your codec to see if it provides any default
|
||||
// configurations. All codecs provide a default configuration, number 0,
|
||||
// which is valid for material in the vacinity of QCIF/QVGA.
|
||||
//
|
||||
// Updating The Configuration
|
||||
// ---------------------------------
|
||||
// Almost all applications will want to update the default configuration
|
||||
// with settings specific to their usage. Here we set the width and height
|
||||
// of the video file to that specified on the command line. We also scale
|
||||
// the default bitrate based on the ratio between the default resolution
|
||||
// and the resolution specified on the command line.
|
||||
//
|
||||
// Initializing The Codec
|
||||
// ----------------------
|
||||
// The encoder is initialized by the following code.
|
||||
//
|
||||
// Encoding A Frame
|
||||
// ----------------
|
||||
// The frame is read as a continuous block (size width * height * 3 / 2)
|
||||
// from the input file. If a frame was read (the input file has not hit
|
||||
// EOF) then the frame is passed to the encoder. Otherwise, a NULL
|
||||
// is passed, indicating the End-Of-Stream condition to the encoder. The
|
||||
// `frame_cnt` is reused as the presentation time stamp (PTS) and each
|
||||
// frame is shown for one frame-time in duration. The flags parameter is
|
||||
// unused in this example. The deadline is set to VPX_DL_REALTIME to
|
||||
// make the example run as quickly as possible.
|
||||
|
||||
// Forced Keyframes
|
||||
// ----------------
|
||||
// Keyframes can be forced by setting the VPX_EFLAG_FORCE_KF bit of the
|
||||
// flags passed to `vpx_codec_control()`. In this example, we force a
|
||||
// keyframe every <keyframe-interval> frames. Note, the output stream can
|
||||
// contain additional keyframes beyond those that have been forced using the
|
||||
// VPX_EFLAG_FORCE_KF flag because of automatic keyframe placement by the
|
||||
// encoder.
|
||||
//
|
||||
// Processing The Encoded Data
|
||||
// ---------------------------
|
||||
// Each packet of type `VPX_CODEC_CX_FRAME_PKT` contains the encoded data
|
||||
// for this frame. We write a IVF frame header, followed by the raw data.
|
||||
//
|
||||
// Cleanup
|
||||
// -------
|
||||
// The `vpx_codec_destroy` call frees any memory allocated by the codec.
|
||||
//
|
||||
// Error Handling
|
||||
// --------------
|
||||
// This example does not special case any error return codes. If there was
|
||||
// an error, a descriptive message is printed and the program exits. With
|
||||
// few exeptions, vpx_codec functions return an enumerated error status,
|
||||
// with the value `0` indicating success.
|
||||
//
|
||||
// Error Resiliency Features
|
||||
// -------------------------
|
||||
// Error resiliency is controlled by the g_error_resilient member of the
|
||||
// configuration structure. Use the `decode_with_drops` example to decode with
|
||||
// frames 5-10 dropped. Compare the output for a file encoded with this example
|
||||
// versus one encoded with the `simple_encoder` example.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx/vpx_encoder.h"
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../video_writer.h"
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s <codec> <width> <height> <infile> <outfile> "
|
||||
"<keyframe-interval> <error-resilient> <frames to encode>\n"
|
||||
"See comments in simple_encoder.c for more information.\n",
|
||||
exec_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int encode_frame(vpx_codec_ctx_t *codec, vpx_image_t *img,
|
||||
int frame_index, int flags, VpxVideoWriter *writer) {
|
||||
int got_pkts = 0;
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
const vpx_codec_cx_pkt_t *pkt = NULL;
|
||||
const vpx_codec_err_t res =
|
||||
vpx_codec_encode(codec, img, frame_index, 1, flags, VPX_DL_GOOD_QUALITY);
|
||||
if (res != VPX_CODEC_OK) die_codec(codec, "Failed to encode frame");
|
||||
|
||||
while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) {
|
||||
got_pkts = 1;
|
||||
|
||||
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
|
||||
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
|
||||
if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
|
||||
pkt->data.frame.sz,
|
||||
pkt->data.frame.pts)) {
|
||||
die_codec(codec, "Failed to write compressed frame");
|
||||
}
|
||||
printf(keyframe ? "K" : ".");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
return got_pkts;
|
||||
}
|
||||
|
||||
// TODO(tomfinegan): Improve command line parsing and add args for bitrate/fps.
|
||||
int main(int argc, char **argv) {
|
||||
FILE *infile = NULL;
|
||||
vpx_codec_ctx_t codec;
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
int frame_count = 0;
|
||||
vpx_image_t raw;
|
||||
vpx_codec_err_t res;
|
||||
VpxVideoInfo info = { 0, 0, 0, { 0, 0 } };
|
||||
VpxVideoWriter *writer = NULL;
|
||||
const VpxInterface *encoder = NULL;
|
||||
const int fps = 30;
|
||||
const int bitrate = 200;
|
||||
int keyframe_interval = 0;
|
||||
int max_frames = 0;
|
||||
int frames_encoded = 0;
|
||||
const char *codec_arg = NULL;
|
||||
const char *width_arg = NULL;
|
||||
const char *height_arg = NULL;
|
||||
const char *infile_arg = NULL;
|
||||
const char *outfile_arg = NULL;
|
||||
const char *keyframe_interval_arg = NULL;
|
||||
|
||||
exec_name = argv[0];
|
||||
|
||||
if (argc != 9) die("Invalid number of arguments");
|
||||
|
||||
codec_arg = argv[1];
|
||||
width_arg = argv[2];
|
||||
height_arg = argv[3];
|
||||
infile_arg = argv[4];
|
||||
outfile_arg = argv[5];
|
||||
keyframe_interval_arg = argv[6];
|
||||
max_frames = (int)strtol(argv[8], NULL, 0);
|
||||
|
||||
encoder = get_vpx_encoder_by_name(codec_arg);
|
||||
if (!encoder) die("Unsupported codec.");
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
keyframe_interval = (int)strtol(keyframe_interval_arg, NULL, 0);
|
||||
if (keyframe_interval < 0) die("Invalid keyframe interval value.");
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
|
||||
|
||||
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
|
||||
if (res) die_codec(&codec, "Failed to get default codec config.");
|
||||
|
||||
cfg.g_w = info.frame_width;
|
||||
cfg.g_h = info.frame_height;
|
||||
cfg.g_timebase.num = info.time_base.numerator;
|
||||
cfg.g_timebase.den = info.time_base.denominator;
|
||||
cfg.rc_target_bitrate = bitrate;
|
||||
cfg.g_error_resilient = (vpx_codec_er_flags_t)strtoul(argv[7], NULL, 0);
|
||||
|
||||
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(&codec, encoder->codec_interface(), &cfg, 0))
|
||||
die_codec(&codec, "Failed to initialize encoder");
|
||||
|
||||
// Encode frames.
|
||||
while (vpx_img_read(&raw, infile)) {
|
||||
int flags = 0;
|
||||
if (keyframe_interval > 0 && frame_count % keyframe_interval == 0)
|
||||
flags |= VPX_EFLAG_FORCE_KF;
|
||||
encode_frame(&codec, &raw, frame_count++, flags, writer);
|
||||
frames_encoded++;
|
||||
if (max_frames > 0 && frames_encoded >= max_frames) break;
|
||||
}
|
||||
|
||||
// Flush encoder.
|
||||
while (encode_frame(&codec, NULL, -1, 0, writer)) {
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fclose(infile);
|
||||
printf("Processed %d frames.\n", frame_count);
|
||||
|
||||
vpx_img_free(&raw);
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
|
||||
|
||||
vpx_video_writer_close(writer);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,256 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Two Pass Encoder
|
||||
// ================
|
||||
//
|
||||
// This is an example of a two pass encoder loop. It takes an input file in
|
||||
// YV12 format, passes it through the encoder twice, and writes the compressed
|
||||
// frames to disk in IVF format. It builds upon the simple_encoder example.
|
||||
//
|
||||
// Twopass Variables
|
||||
// -----------------
|
||||
// Twopass mode needs to track the current pass number and the buffer of
|
||||
// statistics packets.
|
||||
//
|
||||
// Updating The Configuration
|
||||
// ---------------------------------
|
||||
// In two pass mode, the configuration has to be updated on each pass. The
|
||||
// statistics buffer is passed on the last pass.
|
||||
//
|
||||
// Encoding A Frame
|
||||
// ----------------
|
||||
// Encoding a frame in two pass mode is identical to the simple encoder
|
||||
// example. To increase the quality while sacrificing encoding speed,
|
||||
// VPX_DL_BEST_QUALITY can be used in place of VPX_DL_GOOD_QUALITY.
|
||||
//
|
||||
// Processing Statistics Packets
|
||||
// -----------------------------
|
||||
// Each packet of type `VPX_CODEC_CX_FRAME_PKT` contains the encoded data
|
||||
// for this frame. We write a IVF frame header, followed by the raw data.
|
||||
//
|
||||
//
|
||||
// Pass Progress Reporting
|
||||
// -----------------------------
|
||||
// It's sometimes helpful to see when each pass completes.
|
||||
//
|
||||
//
|
||||
// Clean-up
|
||||
// -----------------------------
|
||||
// Destruction of the encoder instance must be done on each pass. The
|
||||
// raw image should be destroyed at the end as usual.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx/vpx_encoder.h"
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../video_writer.h"
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s <codec> <width> <height> <infile> <outfile> "
|
||||
"<frame limit>\n",
|
||||
exec_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int get_frame_stats(vpx_codec_ctx_t *ctx, const vpx_image_t *img,
|
||||
vpx_codec_pts_t pts, unsigned int duration,
|
||||
vpx_enc_frame_flags_t flags, unsigned int deadline,
|
||||
vpx_fixed_buf_t *stats) {
|
||||
int got_pkts = 0;
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
const vpx_codec_cx_pkt_t *pkt = NULL;
|
||||
const vpx_codec_err_t res =
|
||||
vpx_codec_encode(ctx, img, pts, duration, flags, deadline);
|
||||
if (res != VPX_CODEC_OK) die_codec(ctx, "Failed to get frame stats.");
|
||||
|
||||
while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
|
||||
got_pkts = 1;
|
||||
|
||||
if (pkt->kind == VPX_CODEC_STATS_PKT) {
|
||||
const uint8_t *const pkt_buf = pkt->data.twopass_stats.buf;
|
||||
const size_t pkt_size = pkt->data.twopass_stats.sz;
|
||||
stats->buf = realloc(stats->buf, stats->sz + pkt_size);
|
||||
memcpy((uint8_t *)stats->buf + stats->sz, pkt_buf, pkt_size);
|
||||
stats->sz += pkt_size;
|
||||
}
|
||||
}
|
||||
|
||||
return got_pkts;
|
||||
}
|
||||
|
||||
static int encode_frame(vpx_codec_ctx_t *ctx, const vpx_image_t *img,
|
||||
vpx_codec_pts_t pts, unsigned int duration,
|
||||
vpx_enc_frame_flags_t flags, unsigned int deadline,
|
||||
VpxVideoWriter *writer) {
|
||||
int got_pkts = 0;
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
const vpx_codec_cx_pkt_t *pkt = NULL;
|
||||
const vpx_codec_err_t res =
|
||||
vpx_codec_encode(ctx, img, pts, duration, flags, deadline);
|
||||
if (res != VPX_CODEC_OK) die_codec(ctx, "Failed to encode frame.");
|
||||
|
||||
while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
|
||||
got_pkts = 1;
|
||||
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
|
||||
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
|
||||
|
||||
if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
|
||||
pkt->data.frame.sz,
|
||||
pkt->data.frame.pts))
|
||||
die_codec(ctx, "Failed to write compressed frame.");
|
||||
printf(keyframe ? "K" : ".");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
return got_pkts;
|
||||
}
|
||||
|
||||
static vpx_fixed_buf_t pass0(vpx_image_t *raw, FILE *infile,
|
||||
const VpxInterface *encoder,
|
||||
const vpx_codec_enc_cfg_t *cfg, int max_frames) {
|
||||
vpx_codec_ctx_t codec;
|
||||
int frame_count = 0;
|
||||
vpx_fixed_buf_t stats = { NULL, 0 };
|
||||
|
||||
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0))
|
||||
die_codec(&codec, "Failed to initialize encoder");
|
||||
|
||||
// Calculate frame statistics.
|
||||
while (vpx_img_read(raw, infile)) {
|
||||
++frame_count;
|
||||
get_frame_stats(&codec, raw, frame_count, 1, 0, VPX_DL_GOOD_QUALITY,
|
||||
&stats);
|
||||
if (max_frames > 0 && frame_count >= max_frames) break;
|
||||
}
|
||||
|
||||
// Flush encoder.
|
||||
while (get_frame_stats(&codec, NULL, frame_count, 1, 0, VPX_DL_GOOD_QUALITY,
|
||||
&stats)) {
|
||||
}
|
||||
|
||||
printf("Pass 0 complete. Processed %d frames.\n", frame_count);
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
static void pass1(vpx_image_t *raw, FILE *infile, const char *outfile_name,
|
||||
const VpxInterface *encoder, const vpx_codec_enc_cfg_t *cfg,
|
||||
int max_frames) {
|
||||
VpxVideoInfo info = { encoder->fourcc,
|
||||
cfg->g_w,
|
||||
cfg->g_h,
|
||||
{ cfg->g_timebase.num, cfg->g_timebase.den } };
|
||||
VpxVideoWriter *writer = NULL;
|
||||
vpx_codec_ctx_t codec;
|
||||
int frame_count = 0;
|
||||
|
||||
writer = vpx_video_writer_open(outfile_name, kContainerIVF, &info);
|
||||
if (!writer) die("Failed to open %s for writing", outfile_name);
|
||||
|
||||
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0))
|
||||
die_codec(&codec, "Failed to initialize encoder");
|
||||
|
||||
// Encode frames.
|
||||
while (vpx_img_read(raw, infile)) {
|
||||
++frame_count;
|
||||
encode_frame(&codec, raw, frame_count, 1, 0, VPX_DL_GOOD_QUALITY, writer);
|
||||
|
||||
if (max_frames > 0 && frame_count >= max_frames) break;
|
||||
}
|
||||
|
||||
// Flush encoder.
|
||||
while (encode_frame(&codec, NULL, -1, 1, 0, VPX_DL_GOOD_QUALITY, writer)) {
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
|
||||
|
||||
vpx_video_writer_close(writer);
|
||||
|
||||
printf("Pass 1 complete. Processed %d frames.\n", frame_count);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
FILE *infile = NULL;
|
||||
int w, h;
|
||||
vpx_codec_ctx_t codec;
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
vpx_image_t raw;
|
||||
vpx_codec_err_t res;
|
||||
vpx_fixed_buf_t stats;
|
||||
|
||||
const VpxInterface *encoder = NULL;
|
||||
const int fps = 30; // 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 width_arg = argv[2];
|
||||
const char *const height_arg = argv[3];
|
||||
const char *const infile_arg = argv[4];
|
||||
const char *const outfile_arg = argv[5];
|
||||
int max_frames = 0;
|
||||
exec_name = argv[0];
|
||||
|
||||
if (argc != 7) die("Invalid number of arguments.");
|
||||
|
||||
max_frames = (int)strtol(argv[6], NULL, 0);
|
||||
|
||||
encoder = get_vpx_encoder_by_name(codec_arg);
|
||||
if (!encoder) die("Unsupported codec.");
|
||||
|
||||
w = (int)strtol(width_arg, NULL, 0);
|
||||
h = (int)strtol(height_arg, NULL, 0);
|
||||
|
||||
if (w <= 0 || h <= 0 || (w % 2) != 0 || (h % 2) != 0)
|
||||
die("Invalid frame size: %dx%d", w, h);
|
||||
|
||||
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, w, h, 1))
|
||||
die("Failed to allocate image", w, h);
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
|
||||
|
||||
// Configuration
|
||||
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
|
||||
if (res) die_codec(&codec, "Failed to get default codec config.");
|
||||
|
||||
cfg.g_w = w;
|
||||
cfg.g_h = h;
|
||||
cfg.g_timebase.num = 1;
|
||||
cfg.g_timebase.den = fps;
|
||||
cfg.rc_target_bitrate = bitrate;
|
||||
|
||||
if (!(infile = fopen(infile_arg, "rb")))
|
||||
die("Failed to open %s for reading", infile_arg);
|
||||
|
||||
// Pass 0
|
||||
cfg.g_pass = VPX_RC_FIRST_PASS;
|
||||
stats = pass0(&raw, infile, encoder, &cfg, max_frames);
|
||||
|
||||
// Pass 1
|
||||
rewind(infile);
|
||||
cfg.g_pass = VPX_RC_LAST_PASS;
|
||||
cfg.rc_twopass_stats_in = stats;
|
||||
pass1(&raw, infile, outfile_arg, encoder, &cfg, max_frames);
|
||||
free(stats.buf);
|
||||
|
||||
vpx_img_free(&raw);
|
||||
fclose(infile);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,666 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is an example demonstrating multi-resolution encoding in VP8.
|
||||
* High-resolution input video is down-sampled to lower-resolutions. The
|
||||
* encoder then encodes the video and outputs multiple bitstreams with
|
||||
* different resolutions.
|
||||
*
|
||||
* This test also allows for settings temporal layers for each spatial layer.
|
||||
* Different number of temporal layers per spatial stream may be used.
|
||||
* Currently up to 3 temporal layers per spatial stream (encoder) are supported
|
||||
* in this test.
|
||||
*/
|
||||
|
||||
#include "./vpx_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include "vpx_ports/vpx_timer.h"
|
||||
#include "vpx/vpx_encoder.h"
|
||||
#include "vpx/vp8cx.h"
|
||||
#include "vpx_ports/mem_ops.h"
|
||||
#include "../tools_common.h"
|
||||
#define interface (vpx_codec_vp8_cx())
|
||||
#define fourcc 0x30385056
|
||||
|
||||
void usage_exit(void) { exit(EXIT_FAILURE); }
|
||||
|
||||
/*
|
||||
* The input video frame is downsampled several times to generate a multi-level
|
||||
* hierarchical structure. NUM_ENCODERS is defined as the number of encoding
|
||||
* levels required. For example, if the size of input video is 1280x720,
|
||||
* NUM_ENCODERS is 3, and down-sampling factor is 2, the encoder outputs 3
|
||||
* bitstreams with resolution of 1280x720(level 0), 640x360(level 1), and
|
||||
* 320x180(level 2) respectively.
|
||||
*/
|
||||
|
||||
/* Number of encoders (spatial resolutions) used in this test. */
|
||||
#define NUM_ENCODERS 3
|
||||
|
||||
/* Maximum number of temporal layers allowed for this test. */
|
||||
#define MAX_NUM_TEMPORAL_LAYERS 3
|
||||
|
||||
/* This example uses the scaler function in libyuv. */
|
||||
#include "third_party/libyuv/include/libyuv/basic_types.h"
|
||||
#include "third_party/libyuv/include/libyuv/scale.h"
|
||||
#include "third_party/libyuv/include/libyuv/cpu_id.h"
|
||||
|
||||
int (*read_frame_p)(FILE *f, vpx_image_t *img);
|
||||
|
||||
static int read_frame(FILE *f, vpx_image_t *img) {
|
||||
size_t nbytes, to_read;
|
||||
int res = 1;
|
||||
|
||||
to_read = img->w * img->h * 3 / 2;
|
||||
nbytes = fread(img->planes[0], 1, to_read, f);
|
||||
if (nbytes != to_read) {
|
||||
res = 0;
|
||||
if (nbytes > 0)
|
||||
printf("Warning: Read partial frame. Check your width & height!\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int read_frame_by_row(FILE *f, vpx_image_t *img) {
|
||||
size_t nbytes, to_read;
|
||||
int res = 1;
|
||||
int plane;
|
||||
|
||||
for (plane = 0; plane < 3; plane++) {
|
||||
unsigned char *ptr;
|
||||
int w = (plane ? (1 + img->d_w) / 2 : img->d_w);
|
||||
int h = (plane ? (1 + img->d_h) / 2 : img->d_h);
|
||||
int r;
|
||||
|
||||
/* Determine the correct plane based on the image format. The for-loop
|
||||
* always counts in Y,U,V order, but this may not match the order of
|
||||
* the data on disk.
|
||||
*/
|
||||
switch (plane) {
|
||||
case 1:
|
||||
ptr = img->planes[img->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_V
|
||||
: VPX_PLANE_U];
|
||||
break;
|
||||
case 2:
|
||||
ptr = img->planes[img->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_U
|
||||
: VPX_PLANE_V];
|
||||
break;
|
||||
default: ptr = img->planes[plane];
|
||||
}
|
||||
|
||||
for (r = 0; r < h; r++) {
|
||||
to_read = w;
|
||||
|
||||
nbytes = fread(ptr, 1, to_read, f);
|
||||
if (nbytes != to_read) {
|
||||
res = 0;
|
||||
if (nbytes > 0)
|
||||
printf("Warning: Read partial frame. Check your width & height!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ptr += img->stride[plane];
|
||||
}
|
||||
if (!res) break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void write_ivf_file_header(FILE *outfile, const vpx_codec_enc_cfg_t *cfg,
|
||||
int frame_cnt) {
|
||||
char header[32];
|
||||
|
||||
if (cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) return;
|
||||
header[0] = 'D';
|
||||
header[1] = 'K';
|
||||
header[2] = 'I';
|
||||
header[3] = 'F';
|
||||
mem_put_le16(header + 4, 0); /* version */
|
||||
mem_put_le16(header + 6, 32); /* headersize */
|
||||
mem_put_le32(header + 8, fourcc); /* headersize */
|
||||
mem_put_le16(header + 12, cfg->g_w); /* width */
|
||||
mem_put_le16(header + 14, cfg->g_h); /* height */
|
||||
mem_put_le32(header + 16, cfg->g_timebase.den); /* rate */
|
||||
mem_put_le32(header + 20, cfg->g_timebase.num); /* scale */
|
||||
mem_put_le32(header + 24, frame_cnt); /* length */
|
||||
mem_put_le32(header + 28, 0); /* unused */
|
||||
|
||||
(void)fwrite(header, 1, 32, outfile);
|
||||
}
|
||||
|
||||
static void write_ivf_frame_header(FILE *outfile,
|
||||
const vpx_codec_cx_pkt_t *pkt) {
|
||||
char header[12];
|
||||
vpx_codec_pts_t pts;
|
||||
|
||||
if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) return;
|
||||
|
||||
pts = pkt->data.frame.pts;
|
||||
mem_put_le32(header, (int)pkt->data.frame.sz);
|
||||
mem_put_le32(header + 4, pts & 0xFFFFFFFF);
|
||||
mem_put_le32(header + 8, pts >> 32);
|
||||
|
||||
(void)fwrite(header, 1, 12, outfile);
|
||||
}
|
||||
|
||||
/* Temporal scaling parameters */
|
||||
/* This sets all the temporal layer parameters given |num_temporal_layers|,
|
||||
* including the target bit allocation across temporal layers. Bit allocation
|
||||
* parameters will be passed in as user parameters in another version.
|
||||
*/
|
||||
static void set_temporal_layer_pattern(int num_temporal_layers,
|
||||
vpx_codec_enc_cfg_t *cfg, int bitrate,
|
||||
int *layer_flags) {
|
||||
assert(num_temporal_layers <= MAX_NUM_TEMPORAL_LAYERS);
|
||||
switch (num_temporal_layers) {
|
||||
case 1: {
|
||||
/* 1-layer */
|
||||
cfg->ts_number_layers = 1;
|
||||
cfg->ts_periodicity = 1;
|
||||
cfg->ts_rate_decimator[0] = 1;
|
||||
cfg->ts_layer_id[0] = 0;
|
||||
cfg->ts_target_bitrate[0] = bitrate;
|
||||
|
||||
// Update L only.
|
||||
layer_flags[0] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
/* 2-layers, with sync point at first frame of layer 1. */
|
||||
cfg->ts_number_layers = 2;
|
||||
cfg->ts_periodicity = 2;
|
||||
cfg->ts_rate_decimator[0] = 2;
|
||||
cfg->ts_rate_decimator[1] = 1;
|
||||
cfg->ts_layer_id[0] = 0;
|
||||
cfg->ts_layer_id[1] = 1;
|
||||
// Use 60/40 bit allocation as example.
|
||||
cfg->ts_target_bitrate[0] = (int)(0.6f * bitrate);
|
||||
cfg->ts_target_bitrate[1] = bitrate;
|
||||
|
||||
/* 0=L, 1=GF */
|
||||
// ARF is used as predictor for all frames, and is only updated on
|
||||
// key frame. Sync point every 8 frames.
|
||||
|
||||
// Layer 0: predict from L and ARF, update L and G.
|
||||
layer_flags[0] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF;
|
||||
|
||||
// Layer 1: sync point: predict from L and ARF, and update G.
|
||||
layer_flags[1] =
|
||||
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
|
||||
|
||||
// Layer 0, predict from L and ARF, update L.
|
||||
layer_flags[2] =
|
||||
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
|
||||
|
||||
// Layer 1: predict from L, G and ARF, and update G.
|
||||
layer_flags[3] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
|
||||
VP8_EFLAG_NO_UPD_ENTROPY;
|
||||
|
||||
// Layer 0
|
||||
layer_flags[4] = layer_flags[2];
|
||||
|
||||
// Layer 1
|
||||
layer_flags[5] = layer_flags[3];
|
||||
|
||||
// Layer 0
|
||||
layer_flags[6] = layer_flags[4];
|
||||
|
||||
// Layer 1
|
||||
layer_flags[7] = layer_flags[5];
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
default: {
|
||||
// 3-layers structure where ARF is used as predictor for all frames,
|
||||
// and is only updated on key frame.
|
||||
// Sync points for layer 1 and 2 every 8 frames.
|
||||
cfg->ts_number_layers = 3;
|
||||
cfg->ts_periodicity = 4;
|
||||
cfg->ts_rate_decimator[0] = 4;
|
||||
cfg->ts_rate_decimator[1] = 2;
|
||||
cfg->ts_rate_decimator[2] = 1;
|
||||
cfg->ts_layer_id[0] = 0;
|
||||
cfg->ts_layer_id[1] = 2;
|
||||
cfg->ts_layer_id[2] = 1;
|
||||
cfg->ts_layer_id[3] = 2;
|
||||
// Use 45/20/35 bit allocation as example.
|
||||
cfg->ts_target_bitrate[0] = (int)(0.45f * bitrate);
|
||||
cfg->ts_target_bitrate[1] = (int)(0.65f * bitrate);
|
||||
cfg->ts_target_bitrate[2] = bitrate;
|
||||
|
||||
/* 0=L, 1=GF, 2=ARF */
|
||||
|
||||
// Layer 0: predict from L and ARF; update L and G.
|
||||
layer_flags[0] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF;
|
||||
|
||||
// Layer 2: sync point: predict from L and ARF; update none.
|
||||
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_ENTROPY;
|
||||
|
||||
// Layer 1: sync point: predict from L and ARF; update G.
|
||||
layer_flags[2] =
|
||||
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
|
||||
|
||||
// Layer 2: predict from L, G, ARF; update none.
|
||||
layer_flags[3] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
|
||||
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY;
|
||||
|
||||
// Layer 0: predict from L and ARF; update L.
|
||||
layer_flags[4] =
|
||||
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF;
|
||||
|
||||
// Layer 2: predict from L, G, ARF; update none.
|
||||
layer_flags[5] = layer_flags[3];
|
||||
|
||||
// Layer 1: predict from L, G, ARF; update G.
|
||||
layer_flags[6] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
|
||||
|
||||
// Layer 2: predict from L, G, ARF; update none.
|
||||
layer_flags[7] = layer_flags[3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The periodicity of the pattern given the number of temporal layers. */
|
||||
static int periodicity_to_num_layers[MAX_NUM_TEMPORAL_LAYERS] = { 1, 8, 8 };
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
FILE *infile, *outfile[NUM_ENCODERS];
|
||||
FILE *downsampled_input[NUM_ENCODERS - 1];
|
||||
char filename[50];
|
||||
vpx_codec_ctx_t codec[NUM_ENCODERS];
|
||||
vpx_codec_enc_cfg_t cfg[NUM_ENCODERS];
|
||||
int frame_cnt = 0;
|
||||
vpx_image_t raw[NUM_ENCODERS];
|
||||
vpx_codec_err_t res[NUM_ENCODERS];
|
||||
|
||||
int i;
|
||||
int width;
|
||||
int height;
|
||||
int length_frame;
|
||||
int frame_avail;
|
||||
int got_data;
|
||||
int flags = 0;
|
||||
int layer_id = 0;
|
||||
|
||||
int layer_flags[VPX_TS_MAX_PERIODICITY * NUM_ENCODERS] = { 0 };
|
||||
int flag_periodicity;
|
||||
|
||||
/*Currently, only realtime mode is supported in multi-resolution encoding.*/
|
||||
int arg_deadline = VPX_DL_REALTIME;
|
||||
|
||||
/* Set show_psnr to 1/0 to show/not show PSNR. Choose show_psnr=0 if you
|
||||
don't need to know PSNR, which will skip PSNR calculation and save
|
||||
encoding time. */
|
||||
int show_psnr = 0;
|
||||
int key_frame_insert = 0;
|
||||
uint64_t psnr_sse_total[NUM_ENCODERS] = { 0 };
|
||||
uint64_t psnr_samples_total[NUM_ENCODERS] = { 0 };
|
||||
double psnr_totals[NUM_ENCODERS][4] = { { 0, 0 } };
|
||||
int psnr_count[NUM_ENCODERS] = { 0 };
|
||||
|
||||
int64_t cx_time = 0;
|
||||
|
||||
/* Set the required target bitrates for each resolution level.
|
||||
* If target bitrate for highest-resolution level is set to 0,
|
||||
* (i.e. target_bitrate[0]=0), we skip encoding at that level.
|
||||
*/
|
||||
unsigned int target_bitrate[NUM_ENCODERS] = { 1000, 500, 100 };
|
||||
|
||||
/* Enter the frame rate of the input video */
|
||||
int framerate = 30;
|
||||
|
||||
/* Set down-sampling factor for each resolution level.
|
||||
dsf[0] controls down sampling from level 0 to level 1;
|
||||
dsf[1] controls down sampling from level 1 to level 2;
|
||||
dsf[2] is not used. */
|
||||
vpx_rational_t dsf[NUM_ENCODERS] = { { 2, 1 }, { 2, 1 }, { 1, 1 } };
|
||||
|
||||
/* Set the number of temporal layers for each encoder/resolution level,
|
||||
* starting from highest resoln down to lowest resoln. */
|
||||
unsigned int num_temporal_layers[NUM_ENCODERS] = { 3, 3, 3 };
|
||||
|
||||
if (argc != (7 + 3 * NUM_ENCODERS))
|
||||
die("Usage: %s <width> <height> <frame_rate> <infile> <outfile(s)> "
|
||||
"<rate_encoder(s)> <temporal_layer(s)> <key_frame_insert> <output "
|
||||
"psnr?> \n",
|
||||
argv[0]);
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(interface));
|
||||
|
||||
width = (int)strtol(argv[1], NULL, 0);
|
||||
height = (int)strtol(argv[2], NULL, 0);
|
||||
framerate = (int)strtol(argv[3], NULL, 0);
|
||||
|
||||
if (width < 16 || width % 2 || height < 16 || height % 2)
|
||||
die("Invalid resolution: %ldx%ld", width, height);
|
||||
|
||||
/* Open input video file for encoding */
|
||||
if (!(infile = fopen(argv[4], "rb")))
|
||||
die("Failed to open %s for reading", argv[4]);
|
||||
|
||||
/* Open output file for each encoder to output bitstreams */
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
if (!target_bitrate[i]) {
|
||||
outfile[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(outfile[i] = fopen(argv[i + 5], "wb")))
|
||||
die("Failed to open %s for writing", argv[i + 4]);
|
||||
}
|
||||
|
||||
// Bitrates per spatial layer: overwrite default rates above.
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
target_bitrate[i] = (int)strtol(argv[NUM_ENCODERS + 5 + i], NULL, 0);
|
||||
}
|
||||
|
||||
// Temporal layers per spatial layers: overwrite default settings above.
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
num_temporal_layers[i] =
|
||||
(int)strtol(argv[2 * NUM_ENCODERS + 5 + i], NULL, 0);
|
||||
if (num_temporal_layers[i] < 1 || num_temporal_layers[i] > 3)
|
||||
die("Invalid temporal layers: %d, Must be 1, 2, or 3. \n",
|
||||
num_temporal_layers);
|
||||
}
|
||||
|
||||
/* Open file to write out each spatially downsampled input stream. */
|
||||
for (i = 0; i < NUM_ENCODERS - 1; i++) {
|
||||
// Highest resoln is encoder 0.
|
||||
if (sprintf(filename, "ds%d.yuv", NUM_ENCODERS - i) < 0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
downsampled_input[i] = fopen(filename, "wb");
|
||||
}
|
||||
|
||||
key_frame_insert = (int)strtol(argv[3 * NUM_ENCODERS + 5], NULL, 0);
|
||||
|
||||
show_psnr = (int)strtol(argv[3 * NUM_ENCODERS + 6], NULL, 0);
|
||||
|
||||
/* Populate default encoder configuration */
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
res[i] = vpx_codec_enc_config_default(interface, &cfg[i], 0);
|
||||
if (res[i]) {
|
||||
printf("Failed to get config: %s\n", vpx_codec_err_to_string(res[i]));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the default configuration according to needs of the application.
|
||||
*/
|
||||
/* Highest-resolution encoder settings */
|
||||
cfg[0].g_w = width;
|
||||
cfg[0].g_h = height;
|
||||
cfg[0].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;
|
||||
|
||||
/* Disable automatic keyframe placement */
|
||||
/* Note: These 3 settings are copied to all levels. But, except the lowest
|
||||
* resolution level, all other levels are set to VPX_KF_DISABLED internally.
|
||||
*/
|
||||
cfg[0].kf_mode = VPX_KF_AUTO;
|
||||
cfg[0].kf_min_dist = 3000;
|
||||
cfg[0].kf_max_dist = 3000;
|
||||
|
||||
cfg[0].rc_target_bitrate = target_bitrate[0]; /* Set target bitrate */
|
||||
cfg[0].g_timebase.num = 1; /* Set fps */
|
||||
cfg[0].g_timebase.den = framerate;
|
||||
|
||||
/* Other-resolution encoder settings */
|
||||
for (i = 1; i < NUM_ENCODERS; i++) {
|
||||
memcpy(&cfg[i], &cfg[0], sizeof(vpx_codec_enc_cfg_t));
|
||||
|
||||
cfg[i].rc_target_bitrate = target_bitrate[i];
|
||||
|
||||
/* Note: Width & height of other-resolution encoders are calculated
|
||||
* from the highest-resolution encoder's size and the corresponding
|
||||
* down_sampling_factor.
|
||||
*/
|
||||
{
|
||||
unsigned int iw = cfg[i - 1].g_w * dsf[i - 1].den + dsf[i - 1].num - 1;
|
||||
unsigned int ih = cfg[i - 1].g_h * dsf[i - 1].den + dsf[i - 1].num - 1;
|
||||
cfg[i].g_w = iw / dsf[i - 1].num;
|
||||
cfg[i].g_h = ih / dsf[i - 1].num;
|
||||
}
|
||||
|
||||
/* Make width & height to be multiplier of 2. */
|
||||
// Should support odd size ???
|
||||
if ((cfg[i].g_w) % 2) cfg[i].g_w++;
|
||||
if ((cfg[i].g_h) % 2) cfg[i].g_h++;
|
||||
}
|
||||
|
||||
// Set the number of threads per encode/spatial layer.
|
||||
// (1, 1, 1) means no encoder threading.
|
||||
cfg[0].g_threads = 1;
|
||||
cfg[1].g_threads = 1;
|
||||
cfg[2].g_threads = 1;
|
||||
|
||||
/* Allocate image for each encoder */
|
||||
for (i = 0; i < NUM_ENCODERS; i++)
|
||||
if (!vpx_img_alloc(&raw[i], VPX_IMG_FMT_I420, cfg[i].g_w, cfg[i].g_h, 32))
|
||||
die("Failed to allocate image", cfg[i].g_w, cfg[i].g_h);
|
||||
|
||||
if (raw[0].stride[VPX_PLANE_Y] == (int)raw[0].d_w)
|
||||
read_frame_p = read_frame;
|
||||
else
|
||||
read_frame_p = read_frame_by_row;
|
||||
|
||||
for (i = 0; i < NUM_ENCODERS; i++)
|
||||
if (outfile[i]) write_ivf_file_header(outfile[i], &cfg[i], 0);
|
||||
|
||||
/* Temporal layers settings */
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
set_temporal_layer_pattern(num_temporal_layers[i], &cfg[i],
|
||||
cfg[i].rc_target_bitrate,
|
||||
&layer_flags[i * VPX_TS_MAX_PERIODICITY]);
|
||||
}
|
||||
|
||||
/* Initialize multi-encoder */
|
||||
if (vpx_codec_enc_init_multi(&codec[0], interface, &cfg[0], NUM_ENCODERS,
|
||||
(show_psnr ? VPX_CODEC_USE_PSNR : 0), &dsf[0]))
|
||||
die_codec(&codec[0], "Failed to initialize encoder");
|
||||
|
||||
/* The extra encoding configuration parameters can be set as follows. */
|
||||
/* Set encoding speed */
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
int speed = -6;
|
||||
/* Lower speed for the lowest resolution. */
|
||||
if (i == NUM_ENCODERS - 1) speed = -4;
|
||||
if (vpx_codec_control(&codec[i], VP8E_SET_CPUUSED, speed))
|
||||
die_codec(&codec[i], "Failed to set cpu_used");
|
||||
}
|
||||
|
||||
/* Set static threshold = 1 for all encoders */
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
if (vpx_codec_control(&codec[i], VP8E_SET_STATIC_THRESHOLD, 1))
|
||||
die_codec(&codec[i], "Failed to set static threshold");
|
||||
}
|
||||
|
||||
/* Set NOISE_SENSITIVITY to do TEMPORAL_DENOISING */
|
||||
/* Enable denoising for the highest-resolution encoder. */
|
||||
if (vpx_codec_control(&codec[0], VP8E_SET_NOISE_SENSITIVITY, 1))
|
||||
die_codec(&codec[0], "Failed to set noise_sensitivity");
|
||||
if (vpx_codec_control(&codec[1], VP8E_SET_NOISE_SENSITIVITY, 1))
|
||||
die_codec(&codec[1], "Failed to set noise_sensitivity");
|
||||
for (i = 2; i < NUM_ENCODERS; i++) {
|
||||
if (vpx_codec_control(&codec[i], VP8E_SET_NOISE_SENSITIVITY, 0))
|
||||
die_codec(&codec[i], "Failed to set noise_sensitivity");
|
||||
}
|
||||
|
||||
/* Set the number of token partitions */
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
if (vpx_codec_control(&codec[i], VP8E_SET_TOKEN_PARTITIONS, 1))
|
||||
die_codec(&codec[i], "Failed to set static threshold");
|
||||
}
|
||||
|
||||
/* Set the max intra target bitrate */
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
unsigned int max_intra_size_pct =
|
||||
(int)(((double)cfg[0].rc_buf_optimal_sz * 0.5) * framerate / 10);
|
||||
if (vpx_codec_control(&codec[i], VP8E_SET_MAX_INTRA_BITRATE_PCT,
|
||||
max_intra_size_pct))
|
||||
die_codec(&codec[i], "Failed to set static threshold");
|
||||
// printf("%d %d \n",i,max_intra_size_pct);
|
||||
}
|
||||
|
||||
frame_avail = 1;
|
||||
got_data = 0;
|
||||
|
||||
while (frame_avail || got_data) {
|
||||
struct vpx_usec_timer timer;
|
||||
vpx_codec_iter_t iter[NUM_ENCODERS] = { NULL };
|
||||
const vpx_codec_cx_pkt_t *pkt[NUM_ENCODERS];
|
||||
|
||||
flags = 0;
|
||||
frame_avail = read_frame_p(infile, &raw[0]);
|
||||
|
||||
if (frame_avail) {
|
||||
for (i = 1; i < NUM_ENCODERS; i++) {
|
||||
/*Scale the image down a number of times by downsampling factor*/
|
||||
/* FilterMode 1 or 2 give better psnr than FilterMode 0. */
|
||||
I420Scale(
|
||||
raw[i - 1].planes[VPX_PLANE_Y], raw[i - 1].stride[VPX_PLANE_Y],
|
||||
raw[i - 1].planes[VPX_PLANE_U], raw[i - 1].stride[VPX_PLANE_U],
|
||||
raw[i - 1].planes[VPX_PLANE_V], raw[i - 1].stride[VPX_PLANE_V],
|
||||
raw[i - 1].d_w, raw[i - 1].d_h, raw[i].planes[VPX_PLANE_Y],
|
||||
raw[i].stride[VPX_PLANE_Y], raw[i].planes[VPX_PLANE_U],
|
||||
raw[i].stride[VPX_PLANE_U], raw[i].planes[VPX_PLANE_V],
|
||||
raw[i].stride[VPX_PLANE_V], raw[i].d_w, raw[i].d_h, 1);
|
||||
/* Write out down-sampled input. */
|
||||
length_frame = cfg[i].g_w * cfg[i].g_h * 3 / 2;
|
||||
if (fwrite(raw[i].planes[0], 1, length_frame,
|
||||
downsampled_input[NUM_ENCODERS - i - 1]) !=
|
||||
(unsigned int)length_frame) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the flags (reference and update) for all the encoders.*/
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
layer_id = cfg[i].ts_layer_id[frame_cnt % cfg[i].ts_periodicity];
|
||||
flags = 0;
|
||||
flag_periodicity = periodicity_to_num_layers[num_temporal_layers[i] - 1];
|
||||
flags = layer_flags[i * VPX_TS_MAX_PERIODICITY +
|
||||
frame_cnt % flag_periodicity];
|
||||
// Key frame flag for first frame.
|
||||
if (frame_cnt == 0) {
|
||||
flags |= VPX_EFLAG_FORCE_KF;
|
||||
}
|
||||
if (frame_cnt > 0 && frame_cnt == key_frame_insert) {
|
||||
flags = VPX_EFLAG_FORCE_KF;
|
||||
}
|
||||
|
||||
vpx_codec_control(&codec[i], VP8E_SET_FRAME_FLAGS, flags);
|
||||
vpx_codec_control(&codec[i], VP8E_SET_TEMPORAL_LAYER_ID, layer_id);
|
||||
}
|
||||
|
||||
/* Encode each frame at multi-levels */
|
||||
/* Note the flags must be set to 0 in the encode call if they are set
|
||||
for each frame with the vpx_codec_control(), as done above. */
|
||||
vpx_usec_timer_start(&timer);
|
||||
if (vpx_codec_encode(&codec[0], frame_avail ? &raw[0] : NULL, frame_cnt, 1,
|
||||
0, arg_deadline)) {
|
||||
die_codec(&codec[0], "Failed to encode frame");
|
||||
}
|
||||
vpx_usec_timer_mark(&timer);
|
||||
cx_time += vpx_usec_timer_elapsed(&timer);
|
||||
|
||||
for (i = NUM_ENCODERS - 1; i >= 0; i--) {
|
||||
got_data = 0;
|
||||
while ((pkt[i] = vpx_codec_get_cx_data(&codec[i], &iter[i]))) {
|
||||
got_data = 1;
|
||||
switch (pkt[i]->kind) {
|
||||
case VPX_CODEC_CX_FRAME_PKT:
|
||||
write_ivf_frame_header(outfile[i], pkt[i]);
|
||||
(void)fwrite(pkt[i]->data.frame.buf, 1, pkt[i]->data.frame.sz,
|
||||
outfile[i]);
|
||||
break;
|
||||
case VPX_CODEC_PSNR_PKT:
|
||||
if (show_psnr) {
|
||||
int j;
|
||||
|
||||
psnr_sse_total[i] += pkt[i]->data.psnr.sse[0];
|
||||
psnr_samples_total[i] += pkt[i]->data.psnr.samples[0];
|
||||
for (j = 0; j < 4; j++) {
|
||||
psnr_totals[i][j] += pkt[i]->data.psnr.psnr[j];
|
||||
}
|
||||
psnr_count[i]++;
|
||||
}
|
||||
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
frame_cnt++;
|
||||
}
|
||||
printf("\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),
|
||||
1000000 * (double)frame_cnt / (double)cx_time);
|
||||
|
||||
fclose(infile);
|
||||
|
||||
printf("Processed %ld frames.\n", (long int)frame_cnt - 1);
|
||||
for (i = 0; i < NUM_ENCODERS; i++) {
|
||||
/* Calculate PSNR and print it out */
|
||||
if ((show_psnr) && (psnr_count[i] > 0)) {
|
||||
int j;
|
||||
double ovpsnr =
|
||||
sse_to_psnr(psnr_samples_total[i], 255.0, psnr_sse_total[i]);
|
||||
|
||||
fprintf(stderr, "\n ENC%d PSNR (Overall/Avg/Y/U/V)", i);
|
||||
|
||||
fprintf(stderr, " %.3lf", ovpsnr);
|
||||
for (j = 0; j < 4; j++) {
|
||||
fprintf(stderr, " %.3lf", psnr_totals[i][j] / psnr_count[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vpx_codec_destroy(&codec[i]))
|
||||
die_codec(&codec[i], "Failed to destroy codec");
|
||||
|
||||
vpx_img_free(&raw[i]);
|
||||
|
||||
if (!outfile[i]) continue;
|
||||
|
||||
/* Try to rewrite the file header with the actual frame count */
|
||||
if (!fseek(outfile[i], 0, SEEK_SET))
|
||||
write_ivf_file_header(outfile[i], &cfg[i], frame_cnt - 1);
|
||||
fclose(outfile[i]);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// VP8 Set Reference Frame
|
||||
// =======================
|
||||
//
|
||||
// This is an example demonstrating how to overwrite the VP8 encoder's
|
||||
// internal reference frame. In the sample we set the last frame to the
|
||||
// current frame. If this is done at a cut scene it will avoid a keyframe.
|
||||
// This technique could be used to bounce between two cameras.
|
||||
//
|
||||
// Note that the decoder would also have to set the reference frame to the
|
||||
// same value on the same frame, or the video will become corrupt.
|
||||
//
|
||||
// Usage
|
||||
// -----
|
||||
// This example adds a single argument to the `simple_encoder` example,
|
||||
// which specifies the frame number to update the reference frame on.
|
||||
// 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
|
||||
// ---------------------
|
||||
// Use the `simple_encoder` example to encode a sample with a cut scene.
|
||||
// Determine the frame number of the cut scene by looking for a generated
|
||||
// key-frame (indicated by a 'K'). Supply that frame number as an argument
|
||||
// to this example, and observe that no key-frame is generated.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx/vp8cx.h"
|
||||
#include "vpx/vpx_encoder.h"
|
||||
#include "vp8/common/common.h"
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../video_writer.h"
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile> <frame>\n",
|
||||
exec_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int encode_frame(vpx_codec_ctx_t *codec, vpx_image_t *img,
|
||||
int frame_index, VpxVideoWriter *writer) {
|
||||
int got_pkts = 0;
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
const vpx_codec_cx_pkt_t *pkt = NULL;
|
||||
const vpx_codec_err_t res =
|
||||
vpx_codec_encode(codec, img, frame_index, 1, 0, VPX_DL_GOOD_QUALITY);
|
||||
if (res != VPX_CODEC_OK) die_codec(codec, "Failed to encode frame");
|
||||
|
||||
while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) {
|
||||
got_pkts = 1;
|
||||
|
||||
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
|
||||
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
|
||||
if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
|
||||
pkt->data.frame.sz,
|
||||
pkt->data.frame.pts)) {
|
||||
die_codec(codec, "Failed to write compressed frame");
|
||||
}
|
||||
|
||||
printf(keyframe ? "K" : ".");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
return got_pkts;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
FILE *infile = NULL;
|
||||
vpx_codec_ctx_t codec;
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
int frame_count = 0;
|
||||
vpx_image_t raw;
|
||||
vpx_codec_err_t res;
|
||||
VpxVideoInfo info;
|
||||
VpxVideoWriter *writer = NULL;
|
||||
const VpxInterface *encoder = NULL;
|
||||
int update_frame_num = 0;
|
||||
const int fps = 30; // 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];
|
||||
|
||||
if (argc != 6) die("Invalid number of arguments");
|
||||
|
||||
// TODO(dkovalev): add vp9 support and rename the file accordingly
|
||||
encoder = get_vpx_encoder_by_name("vp8");
|
||||
if (!encoder) die("Unsupported codec.");
|
||||
|
||||
update_frame_num = atoi(argv[5]);
|
||||
if (!update_frame_num) die("Couldn't parse frame number '%s'\n", argv[5]);
|
||||
|
||||
info.codec_fourcc = encoder->fourcc;
|
||||
info.frame_width = (int)strtol(argv[1], NULL, 0);
|
||||
info.frame_height = (int)strtol(argv[2], NULL, 0);
|
||||
info.time_base.numerator = 1;
|
||||
info.time_base.denominator = fps;
|
||||
|
||||
if (info.frame_width <= 0 || info.frame_height <= 0 ||
|
||||
(info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) {
|
||||
die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
|
||||
}
|
||||
|
||||
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
|
||||
info.frame_height, 1)) {
|
||||
die("Failed to allocate image.");
|
||||
}
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
|
||||
|
||||
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
|
||||
if (res) die_codec(&codec, "Failed to get default codec config.");
|
||||
|
||||
cfg.g_w = info.frame_width;
|
||||
cfg.g_h = info.frame_height;
|
||||
cfg.g_timebase.num = info.time_base.numerator;
|
||||
cfg.g_timebase.den = info.time_base.denominator;
|
||||
cfg.rc_target_bitrate = bitrate;
|
||||
|
||||
writer = vpx_video_writer_open(argv[4], kContainerIVF, &info);
|
||||
if (!writer) die("Failed to open %s for writing.", argv[4]);
|
||||
|
||||
if (!(infile = fopen(argv[3], "rb")))
|
||||
die("Failed to open %s for reading.", argv[3]);
|
||||
|
||||
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
|
||||
die_codec(&codec, "Failed to initialize encoder");
|
||||
|
||||
// Encode frames.
|
||||
while (vpx_img_read(&raw, infile)) {
|
||||
if (frame_count + 1 == update_frame_num) {
|
||||
vpx_ref_frame_t ref;
|
||||
ref.frame_type = VP8_LAST_FRAME;
|
||||
ref.img = raw;
|
||||
if (vpx_codec_control(&codec, VP8_SET_REFERENCE, &ref))
|
||||
die_codec(&codec, "Failed to set reference frame");
|
||||
}
|
||||
|
||||
encode_frame(&codec, &raw, frame_count++, writer);
|
||||
}
|
||||
|
||||
// Flush encoder.
|
||||
while (encode_frame(&codec, NULL, -1, writer)) {
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fclose(infile);
|
||||
printf("Processed %d frames.\n", frame_count);
|
||||
|
||||
vpx_img_free(&raw);
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
|
||||
|
||||
vpx_video_writer_close(writer);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx/vpx_encoder.h"
|
||||
#include "vpx/vp8cx.h"
|
||||
#include "vp9/common/vp9_common.h"
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../video_writer.h"
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr,
|
||||
"vp9_lossless_encoder: Example demonstrating VP9 lossless "
|
||||
"encoding feature. Supports raw input only.\n");
|
||||
fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile>\n", exec_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int encode_frame(vpx_codec_ctx_t *codec, vpx_image_t *img,
|
||||
int frame_index, int flags, VpxVideoWriter *writer) {
|
||||
int got_pkts = 0;
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
const vpx_codec_cx_pkt_t *pkt = NULL;
|
||||
const vpx_codec_err_t res =
|
||||
vpx_codec_encode(codec, img, frame_index, 1, flags, VPX_DL_GOOD_QUALITY);
|
||||
if (res != VPX_CODEC_OK) die_codec(codec, "Failed to encode frame");
|
||||
|
||||
while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) {
|
||||
got_pkts = 1;
|
||||
|
||||
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
|
||||
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
|
||||
if (!vpx_video_writer_write_frame(writer, pkt->data.frame.buf,
|
||||
pkt->data.frame.sz,
|
||||
pkt->data.frame.pts)) {
|
||||
die_codec(codec, "Failed to write compressed frame");
|
||||
}
|
||||
printf(keyframe ? "K" : ".");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
return got_pkts;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
FILE *infile = NULL;
|
||||
vpx_codec_ctx_t codec;
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
int frame_count = 0;
|
||||
vpx_image_t raw;
|
||||
vpx_codec_err_t res;
|
||||
VpxVideoInfo info;
|
||||
VpxVideoWriter *writer = NULL;
|
||||
const VpxInterface *encoder = NULL;
|
||||
const int fps = 30;
|
||||
|
||||
vp9_zero(info);
|
||||
|
||||
exec_name = argv[0];
|
||||
|
||||
if (argc < 5) die("Invalid number of arguments");
|
||||
|
||||
encoder = get_vpx_encoder_by_name("vp9");
|
||||
if (!encoder) die("Unsupported codec.");
|
||||
|
||||
info.codec_fourcc = encoder->fourcc;
|
||||
info.frame_width = (int)strtol(argv[1], NULL, 0);
|
||||
info.frame_height = (int)strtol(argv[2], NULL, 0);
|
||||
info.time_base.numerator = 1;
|
||||
info.time_base.denominator = fps;
|
||||
|
||||
if (info.frame_width <= 0 || info.frame_height <= 0 ||
|
||||
(info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) {
|
||||
die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
|
||||
}
|
||||
|
||||
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
|
||||
info.frame_height, 1)) {
|
||||
die("Failed to allocate image.");
|
||||
}
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
|
||||
|
||||
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
|
||||
if (res) die_codec(&codec, "Failed to get default codec config.");
|
||||
|
||||
cfg.g_w = info.frame_width;
|
||||
cfg.g_h = info.frame_height;
|
||||
cfg.g_timebase.num = info.time_base.numerator;
|
||||
cfg.g_timebase.den = info.time_base.denominator;
|
||||
|
||||
writer = vpx_video_writer_open(argv[4], kContainerIVF, &info);
|
||||
if (!writer) die("Failed to open %s for writing.", argv[4]);
|
||||
|
||||
if (!(infile = fopen(argv[3], "rb")))
|
||||
die("Failed to open %s for reading.", argv[3]);
|
||||
|
||||
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
|
||||
die_codec(&codec, "Failed to initialize encoder");
|
||||
|
||||
if (vpx_codec_control_(&codec, VP9E_SET_LOSSLESS, 1))
|
||||
die_codec(&codec, "Failed to use lossless mode");
|
||||
|
||||
// Encode frames.
|
||||
while (vpx_img_read(&raw, infile)) {
|
||||
encode_frame(&codec, &raw, frame_count++, 0, writer);
|
||||
}
|
||||
|
||||
// Flush encoder.
|
||||
while (encode_frame(&codec, NULL, -1, 0, writer)) {
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fclose(infile);
|
||||
printf("Processed %d frames.\n", frame_count);
|
||||
|
||||
vpx_img_free(&raw);
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
|
||||
|
||||
vpx_video_writer_close(writer);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,966 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is an example demonstrating how to implement a multi-layer
|
||||
* VP9 encoding scheme based on spatial scalability for video applications
|
||||
* that benefit from a scalable bitstream.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../args.h"
|
||||
#include "../tools_common.h"
|
||||
#include "../video_writer.h"
|
||||
|
||||
#include "../vpx_ports/vpx_timer.h"
|
||||
#include "vpx/svc_context.h"
|
||||
#include "vpx/vp8cx.h"
|
||||
#include "vpx/vpx_encoder.h"
|
||||
#include "../vpxstats.h"
|
||||
#include "vp9/encoder/vp9_encoder.h"
|
||||
#define OUTPUT_RC_STATS 1
|
||||
|
||||
static const arg_def_t skip_frames_arg =
|
||||
ARG_DEF("s", "skip-frames", 1, "input frames to skip");
|
||||
static const arg_def_t frames_arg =
|
||||
ARG_DEF("f", "frames", 1, "number of frames to encode");
|
||||
static const arg_def_t 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 height_arg = ARG_DEF("h", "height", 1, "source height");
|
||||
static const arg_def_t timebase_arg =
|
||||
ARG_DEF("t", "timebase", 1, "timebase (num/den)");
|
||||
static const arg_def_t bitrate_arg = ARG_DEF(
|
||||
"b", "target-bitrate", 1, "encoding bitrate, in kilobits per second");
|
||||
static const arg_def_t spatial_layers_arg =
|
||||
ARG_DEF("sl", "spatial-layers", 1, "number of spatial SVC layers");
|
||||
static const arg_def_t temporal_layers_arg =
|
||||
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 =
|
||||
ARG_DEF("k", "kf-dist", 1, "number of frames between keyframes");
|
||||
static const arg_def_t scale_factors_arg =
|
||||
ARG_DEF("r", "scale-factors", 1, "scale factors (lowest to highest layer)");
|
||||
static const arg_def_t passes_arg =
|
||||
ARG_DEF("p", "passes", 1, "Number of passes (1/2)");
|
||||
static const arg_def_t pass_arg =
|
||||
ARG_DEF(NULL, "pass", 1, "Pass to execute (1/2)");
|
||||
static const arg_def_t fpf_name_arg =
|
||||
ARG_DEF(NULL, "fpf", 1, "First pass statistics file name");
|
||||
static const arg_def_t min_q_arg =
|
||||
ARG_DEF(NULL, "min-q", 1, "Minimum quantizer");
|
||||
static const arg_def_t max_q_arg =
|
||||
ARG_DEF(NULL, "max-q", 1, "Maximum quantizer");
|
||||
static const arg_def_t min_bitrate_arg =
|
||||
ARG_DEF(NULL, "min-bitrate", 1, "Minimum bitrate");
|
||||
static const arg_def_t max_bitrate_arg =
|
||||
ARG_DEF(NULL, "max-bitrate", 1, "Maximum bitrate");
|
||||
static const arg_def_t lag_in_frame_arg =
|
||||
ARG_DEF(NULL, "lag-in-frames", 1,
|
||||
"Number of frame to input before "
|
||||
"generating any outputs");
|
||||
static const arg_def_t rc_end_usage_arg =
|
||||
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
|
||||
static const struct arg_enum_list bitdepth_enum[] = {
|
||||
{ "8", VPX_BITS_8 }, { "10", VPX_BITS_10 }, { "12", VPX_BITS_12 }, { NULL, 0 }
|
||||
};
|
||||
|
||||
static const arg_def_t bitdepth_arg = ARG_DEF_ENUM(
|
||||
"d", "bit-depth", 1, "Bit depth for codec 8, 10 or 12. ", bitdepth_enum);
|
||||
#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
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
&bitdepth_arg,
|
||||
#endif
|
||||
&speed_arg,
|
||||
&rc_end_usage_arg,
|
||||
&bitrates_arg,
|
||||
NULL };
|
||||
|
||||
static const uint32_t default_frames_to_skip = 0;
|
||||
static const uint32_t default_frames_to_code = 60 * 60;
|
||||
static const uint32_t default_width = 1920;
|
||||
static const uint32_t default_height = 1080;
|
||||
static const uint32_t default_timebase_num = 1;
|
||||
static const uint32_t default_timebase_den = 60;
|
||||
static const uint32_t default_bitrate = 1000;
|
||||
static const uint32_t default_spatial_layers = 5;
|
||||
static const uint32_t default_temporal_layers = 1;
|
||||
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 {
|
||||
const char *input_filename;
|
||||
const char *output_filename;
|
||||
uint32_t frames_to_code;
|
||||
uint32_t frames_to_skip;
|
||||
struct VpxInputContext input_ctx;
|
||||
stats_io_t rc_stats;
|
||||
int passes;
|
||||
int pass;
|
||||
} AppInput;
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) {
|
||||
fprintf(stderr, "Usage: %s <options> input_filename output_filename\n",
|
||||
exec_name);
|
||||
fprintf(stderr, "Options:\n");
|
||||
arg_show_usage(stderr, svc_args);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void parse_command_line(int argc, const char **argv_,
|
||||
AppInput *app_input, SvcContext *svc_ctx,
|
||||
vpx_codec_enc_cfg_t *enc_cfg) {
|
||||
struct arg arg;
|
||||
char **argv = NULL;
|
||||
char **argi = NULL;
|
||||
char **argj = NULL;
|
||||
vpx_codec_err_t res;
|
||||
int passes = 0;
|
||||
int pass = 0;
|
||||
const char *fpf_file_name = NULL;
|
||||
unsigned int min_bitrate = 0;
|
||||
unsigned int max_bitrate = 0;
|
||||
char string_options[1024] = { 0 };
|
||||
|
||||
// initialize SvcContext with parameters that will be passed to vpx_svc_init
|
||||
svc_ctx->log_level = SVC_LOG_DEBUG;
|
||||
svc_ctx->spatial_layers = default_spatial_layers;
|
||||
svc_ctx->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
|
||||
res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0);
|
||||
if (res) {
|
||||
die("Failed to get config: %s\n", vpx_codec_err_to_string(res));
|
||||
}
|
||||
// update enc_cfg with app default values
|
||||
enc_cfg->g_w = default_width;
|
||||
enc_cfg->g_h = default_height;
|
||||
enc_cfg->g_timebase.num = default_timebase_num;
|
||||
enc_cfg->g_timebase.den = default_timebase_den;
|
||||
enc_cfg->rc_target_bitrate = default_bitrate;
|
||||
enc_cfg->kf_min_dist = default_kf_dist;
|
||||
enc_cfg->kf_max_dist = default_kf_dist;
|
||||
enc_cfg->rc_end_usage = VPX_CQ;
|
||||
|
||||
// initialize AppInput with default values
|
||||
app_input->frames_to_code = default_frames_to_code;
|
||||
app_input->frames_to_skip = default_frames_to_skip;
|
||||
|
||||
// process command line options
|
||||
argv = argv_dup(argc - 1, argv_ + 1);
|
||||
for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
|
||||
arg.argv_step = 1;
|
||||
|
||||
if (arg_match(&arg, &frames_arg, argi)) {
|
||||
app_input->frames_to_code = arg_parse_uint(&arg);
|
||||
} else if (arg_match(&arg, &width_arg, argi)) {
|
||||
enc_cfg->g_w = arg_parse_uint(&arg);
|
||||
} else if (arg_match(&arg, &height_arg, argi)) {
|
||||
enc_cfg->g_h = arg_parse_uint(&arg);
|
||||
} else if (arg_match(&arg, &timebase_arg, argi)) {
|
||||
enc_cfg->g_timebase = arg_parse_rational(&arg);
|
||||
} else if (arg_match(&arg, &bitrate_arg, argi)) {
|
||||
enc_cfg->rc_target_bitrate = arg_parse_uint(&arg);
|
||||
} else if (arg_match(&arg, &skip_frames_arg, argi)) {
|
||||
app_input->frames_to_skip = arg_parse_uint(&arg);
|
||||
} else if (arg_match(&arg, &spatial_layers_arg, argi)) {
|
||||
svc_ctx->spatial_layers = arg_parse_uint(&arg);
|
||||
} else if (arg_match(&arg, &temporal_layers_arg, argi)) {
|
||||
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)) {
|
||||
enc_cfg->kf_min_dist = arg_parse_uint(&arg);
|
||||
enc_cfg->kf_max_dist = enc_cfg->kf_min_dist;
|
||||
} else if (arg_match(&arg, &scale_factors_arg, argi)) {
|
||||
snprintf(string_options, sizeof(string_options), "%s scale-factors=%s",
|
||||
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)) {
|
||||
passes = arg_parse_uint(&arg);
|
||||
if (passes < 1 || passes > 2) {
|
||||
die("Error: Invalid number of passes (%d)\n", passes);
|
||||
}
|
||||
} else if (arg_match(&arg, &pass_arg, argi)) {
|
||||
pass = arg_parse_uint(&arg);
|
||||
if (pass < 1 || pass > 2) {
|
||||
die("Error: Invalid pass selected (%d)\n", pass);
|
||||
}
|
||||
} else if (arg_match(&arg, &fpf_name_arg, argi)) {
|
||||
fpf_file_name = arg.val;
|
||||
} else if (arg_match(&arg, &min_q_arg, argi)) {
|
||||
snprintf(string_options, sizeof(string_options), "%s min-quantizers=%s",
|
||||
string_options, arg.val);
|
||||
} else if (arg_match(&arg, &max_q_arg, argi)) {
|
||||
snprintf(string_options, sizeof(string_options), "%s max-quantizers=%s",
|
||||
string_options, arg.val);
|
||||
} else if (arg_match(&arg, &min_bitrate_arg, argi)) {
|
||||
min_bitrate = arg_parse_uint(&arg);
|
||||
} else if (arg_match(&arg, &max_bitrate_arg, argi)) {
|
||||
max_bitrate = arg_parse_uint(&arg);
|
||||
} else if (arg_match(&arg, &lag_in_frame_arg, argi)) {
|
||||
enc_cfg->g_lag_in_frames = arg_parse_uint(&arg);
|
||||
} else if (arg_match(&arg, &rc_end_usage_arg, argi)) {
|
||||
enc_cfg->rc_end_usage = arg_parse_uint(&arg);
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
} else if (arg_match(&arg, &bitdepth_arg, argi)) {
|
||||
enc_cfg->g_bit_depth = arg_parse_enum_or_int(&arg);
|
||||
switch (enc_cfg->g_bit_depth) {
|
||||
case VPX_BITS_8:
|
||||
enc_cfg->g_input_bit_depth = 8;
|
||||
enc_cfg->g_profile = 0;
|
||||
break;
|
||||
case VPX_BITS_10:
|
||||
enc_cfg->g_input_bit_depth = 10;
|
||||
enc_cfg->g_profile = 2;
|
||||
break;
|
||||
case VPX_BITS_12:
|
||||
enc_cfg->g_input_bit_depth = 12;
|
||||
enc_cfg->g_profile = 2;
|
||||
break;
|
||||
default:
|
||||
die("Error: Invalid bit depth selected (%d)\n", enc_cfg->g_bit_depth);
|
||||
break;
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
} else {
|
||||
++argj;
|
||||
}
|
||||
}
|
||||
|
||||
// There will be a space in front of the string options
|
||||
if (strlen(string_options) > 0)
|
||||
vpx_svc_set_options(svc_ctx, string_options + 1);
|
||||
|
||||
if (passes == 0 || passes == 1) {
|
||||
if (pass) {
|
||||
fprintf(stderr, "pass is ignored since there's only one pass\n");
|
||||
}
|
||||
enc_cfg->g_pass = VPX_RC_ONE_PASS;
|
||||
} else {
|
||||
if (pass == 0) {
|
||||
die("pass must be specified when passes is 2\n");
|
||||
}
|
||||
|
||||
if (fpf_file_name == NULL) {
|
||||
die("fpf must be specified when passes is 2\n");
|
||||
}
|
||||
|
||||
if (pass == 1) {
|
||||
enc_cfg->g_pass = VPX_RC_FIRST_PASS;
|
||||
if (!stats_open_file(&app_input->rc_stats, fpf_file_name, 0)) {
|
||||
fatal("Failed to open statistics store");
|
||||
}
|
||||
} else {
|
||||
enc_cfg->g_pass = VPX_RC_LAST_PASS;
|
||||
if (!stats_open_file(&app_input->rc_stats, fpf_file_name, 1)) {
|
||||
fatal("Failed to open statistics store");
|
||||
}
|
||||
enc_cfg->rc_twopass_stats_in = stats_get(&app_input->rc_stats);
|
||||
}
|
||||
app_input->passes = passes;
|
||||
app_input->pass = pass;
|
||||
}
|
||||
|
||||
if (enc_cfg->rc_target_bitrate > 0) {
|
||||
if (min_bitrate > 0) {
|
||||
enc_cfg->rc_2pass_vbr_minsection_pct =
|
||||
min_bitrate * 100 / enc_cfg->rc_target_bitrate;
|
||||
}
|
||||
if (max_bitrate > 0) {
|
||||
enc_cfg->rc_2pass_vbr_maxsection_pct =
|
||||
max_bitrate * 100 / enc_cfg->rc_target_bitrate;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for unrecognized options
|
||||
for (argi = argv; *argi; ++argi)
|
||||
if (argi[0][0] == '-' && strlen(argi[0]) > 1)
|
||||
die("Error: Unrecognized option %s\n", *argi);
|
||||
|
||||
if (argv[0] == NULL || argv[1] == 0) {
|
||||
usage_exit();
|
||||
}
|
||||
app_input->input_filename = argv[0];
|
||||
app_input->output_filename = argv[1];
|
||||
free(argv);
|
||||
|
||||
if (enc_cfg->g_w < 16 || enc_cfg->g_w % 2 || enc_cfg->g_h < 16 ||
|
||||
enc_cfg->g_h % 2)
|
||||
die("Invalid resolution: %d x %d\n", enc_cfg->g_w, enc_cfg->g_h);
|
||||
|
||||
printf(
|
||||
"Codec %s\nframes: %d, skip: %d\n"
|
||||
"layers: %d\n"
|
||||
"width %d, height: %d,\n"
|
||||
"num: %d, den: %d, bitrate: %d,\n"
|
||||
"gop size: %d\n",
|
||||
vpx_codec_iface_name(vpx_codec_vp9_cx()), app_input->frames_to_code,
|
||||
app_input->frames_to_skip, svc_ctx->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);
|
||||
}
|
||||
|
||||
#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) {
|
||||
AppInput app_input;
|
||||
VpxVideoWriter *writer = NULL;
|
||||
VpxVideoInfo info;
|
||||
vpx_codec_ctx_t codec;
|
||||
vpx_codec_enc_cfg_t enc_cfg;
|
||||
SvcContext svc_ctx;
|
||||
uint32_t i;
|
||||
uint32_t frame_cnt = 0;
|
||||
vpx_image_t raw;
|
||||
vpx_codec_err_t res;
|
||||
int pts = 0; /* PTS starts at 0 */
|
||||
int frame_duration = 1; /* 1 timebase tick per frame */
|
||||
FILE *infile = NULL;
|
||||
int end_of_stream = 0;
|
||||
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(&app_input, 0, sizeof(AppInput));
|
||||
memset(&info, 0, sizeof(VpxVideoInfo));
|
||||
exec_name = argv[0];
|
||||
parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg);
|
||||
|
||||
// Allocate image buffer
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (!vpx_img_alloc(&raw,
|
||||
enc_cfg.g_input_bit_depth == 8 ? VPX_IMG_FMT_I420
|
||||
: VPX_IMG_FMT_I42016,
|
||||
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);
|
||||
}
|
||||
#else
|
||||
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32)) {
|
||||
die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h);
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
if (!(infile = fopen(app_input.input_filename, "rb")))
|
||||
die("Failed to open %s for reading\n", app_input.input_filename);
|
||||
|
||||
// Initialize codec
|
||||
if (vpx_svc_init(&svc_ctx, &codec, vpx_codec_vp9_cx(), &enc_cfg) !=
|
||||
VPX_CODEC_OK)
|
||||
die("Failed to initialize encoder\n");
|
||||
|
||||
#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.time_base.numerator = enc_cfg.g_timebase.num;
|
||||
info.time_base.denominator = enc_cfg.g_timebase.den;
|
||||
|
||||
if (!(app_input.passes == 2 && app_input.pass == 1)) {
|
||||
// We don't save the bitstream for the 1st pass on two pass rate control
|
||||
writer =
|
||||
vpx_video_writer_open(app_input.output_filename, kContainerIVF, &info);
|
||||
if (!writer)
|
||||
die("Failed to open %s for writing\n", app_input.output_filename);
|
||||
}
|
||||
#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
|
||||
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
|
||||
while (!end_of_stream) {
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
const vpx_codec_cx_pkt_t *cx_pkt;
|
||||
if (frame_cnt >= app_input.frames_to_code || !vpx_img_read(&raw, infile)) {
|
||||
// We need one extra vpx_svc_encode call at end of stream to flush
|
||||
// encoder and get remaining data
|
||||
end_of_stream = 1;
|
||||
}
|
||||
|
||||
// For BYPASS/FLEXIBLE mode, set the frame flags (reference and updates)
|
||||
// and the buffer indices for each spatial layer of the current
|
||||
// (super)frame to be encoded. The temporal layer_id for the current frame
|
||||
// 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) {
|
||||
die_codec(&codec, "Failed to encode frame");
|
||||
}
|
||||
|
||||
while ((cx_pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) {
|
||||
switch (cx_pkt->kind) {
|
||||
case VPX_CODEC_CX_FRAME_PKT: {
|
||||
SvcInternal_t *const si = (SvcInternal_t *)svc_ctx.internal;
|
||||
if (cx_pkt->data.frame.sz > 0) {
|
||||
#if OUTPUT_RC_STATS
|
||||
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.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,
|
||||
!!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY),
|
||||
(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;
|
||||
break;
|
||||
}
|
||||
case VPX_CODEC_STATS_PKT: {
|
||||
stats_write(&app_input.rc_stats, cx_pkt->data.twopass_stats.buf,
|
||||
cx_pkt->data.twopass_stats.sz);
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
|
||||
if (!end_of_stream) {
|
||||
++frame_cnt;
|
||||
pts += frame_duration;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
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 (app_input.passes == 2) stats_close(&app_input.rc_stats, 1);
|
||||
if (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);
|
||||
// display average size, psnr
|
||||
vpx_svc_dump_statistics(&svc_ctx);
|
||||
vpx_svc_release(&svc_ctx);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -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;
|
||||
}
|
@ -1,952 +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.
|
||||
*/
|
||||
|
||||
// This is an example demonstrating how to implement a multi-layer VPx
|
||||
// encoding scheme based on temporal scalability for video applications
|
||||
// that benefit from a scalable bitstream.
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "./vpx_config.h"
|
||||
#include "../vpx_ports/vpx_timer.h"
|
||||
#include "vpx/vp8cx.h"
|
||||
#include "vpx/vpx_encoder.h"
|
||||
#include "vpx_ports/bitops.h"
|
||||
|
||||
#include "../tools_common.h"
|
||||
#include "../video_writer.h"
|
||||
|
||||
#define ROI_MAP 0
|
||||
|
||||
#define zero(Dest) memset(&Dest, 0, sizeof(Dest));
|
||||
|
||||
static const char *exec_name;
|
||||
|
||||
void usage_exit(void) { exit(EXIT_FAILURE); }
|
||||
|
||||
// Denoiser states for vp8, for temporal denoising.
|
||||
enum denoiserStateVp8 {
|
||||
kVp8DenoiserOff,
|
||||
kVp8DenoiserOnYOnly,
|
||||
kVp8DenoiserOnYUV,
|
||||
kVp8DenoiserOnYUVAggressive,
|
||||
kVp8DenoiserOnAdaptive
|
||||
};
|
||||
|
||||
// Denoiser states for vp9, for temporal denoising.
|
||||
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.
|
||||
struct RateControlMetrics {
|
||||
// Number of input frames per layer.
|
||||
int layer_input_frames[VPX_TS_MAX_LAYERS];
|
||||
// Total (cumulative) number of encoded frames per layer.
|
||||
int layer_tot_enc_frames[VPX_TS_MAX_LAYERS];
|
||||
// Number of encoded non-key frames per layer.
|
||||
int layer_enc_frames[VPX_TS_MAX_LAYERS];
|
||||
// Framerate per layer layer (cumulative).
|
||||
double layer_framerate[VPX_TS_MAX_LAYERS];
|
||||
// Target average frame size per layer (per-frame-bandwidth per layer).
|
||||
double layer_pfb[VPX_TS_MAX_LAYERS];
|
||||
// Actual average frame size per layer.
|
||||
double layer_avg_frame_size[VPX_TS_MAX_LAYERS];
|
||||
// Average rate mismatch per layer (|target - actual| / target).
|
||||
double layer_avg_rate_mismatch[VPX_TS_MAX_LAYERS];
|
||||
// Actual encoding bitrate per layer (cumulative).
|
||||
double layer_encoding_bitrate[VPX_TS_MAX_LAYERS];
|
||||
// Average of the short-time encoder actual bitrate.
|
||||
// TODO(marpan): Should we add these short-time stats for each layer?
|
||||
double avg_st_encoding_bitrate;
|
||||
// Variance of the short-time encoder actual bitrate.
|
||||
double variance_st_encoding_bitrate;
|
||||
// Window (number of frames) for computing short-timee encoding bitrate.
|
||||
int window_size;
|
||||
// Number of window measurements.
|
||||
int window_count;
|
||||
int layer_target_bitrate[VPX_MAX_LAYERS];
|
||||
};
|
||||
|
||||
// Note: these rate control metrics assume only 1 key frame in the
|
||||
// sequence (i.e., first frame only). So for temporal pattern# 7
|
||||
// (which has key frame for every frame on base layer), the metrics
|
||||
// computation will be off/wrong.
|
||||
// TODO(marpan): Update these metrics to account for multiple key frames
|
||||
// in the stream.
|
||||
static void set_rate_control_metrics(struct RateControlMetrics *rc,
|
||||
vpx_codec_enc_cfg_t *cfg) {
|
||||
unsigned int i = 0;
|
||||
// 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;
|
||||
rc->layer_framerate[0] = framerate / cfg->ts_rate_decimator[0];
|
||||
rc->layer_pfb[0] =
|
||||
1000.0 * rc->layer_target_bitrate[0] / rc->layer_framerate[0];
|
||||
for (i = 0; i < cfg->ts_number_layers; ++i) {
|
||||
if (i > 0) {
|
||||
rc->layer_framerate[i] = framerate / cfg->ts_rate_decimator[i];
|
||||
rc->layer_pfb[i] =
|
||||
1000.0 *
|
||||
(rc->layer_target_bitrate[i] - rc->layer_target_bitrate[i - 1]) /
|
||||
(rc->layer_framerate[i] - rc->layer_framerate[i - 1]);
|
||||
}
|
||||
rc->layer_input_frames[i] = 0;
|
||||
rc->layer_enc_frames[i] = 0;
|
||||
rc->layer_tot_enc_frames[i] = 0;
|
||||
rc->layer_encoding_bitrate[i] = 0.0;
|
||||
rc->layer_avg_frame_size[i] = 0.0;
|
||||
rc->layer_avg_rate_mismatch[i] = 0.0;
|
||||
}
|
||||
rc->window_count = 0;
|
||||
rc->window_size = 15;
|
||||
rc->avg_st_encoding_bitrate = 0.0;
|
||||
rc->variance_st_encoding_bitrate = 0.0;
|
||||
}
|
||||
|
||||
static void printout_rate_control_summary(struct RateControlMetrics *rc,
|
||||
vpx_codec_enc_cfg_t *cfg,
|
||||
int frame_cnt) {
|
||||
unsigned int i = 0;
|
||||
int tot_num_frames = 0;
|
||||
double perc_fluctuation = 0.0;
|
||||
printf("Total number of processed frames: %d\n\n", frame_cnt - 1);
|
||||
printf("Rate control layer stats for %d layer(s):\n\n",
|
||||
cfg->ts_number_layers);
|
||||
for (i = 0; i < cfg->ts_number_layers; ++i) {
|
||||
const int num_dropped =
|
||||
(i > 0) ? (rc->layer_input_frames[i] - rc->layer_enc_frames[i])
|
||||
: (rc->layer_input_frames[i] - rc->layer_enc_frames[i] - 1);
|
||||
tot_num_frames += rc->layer_input_frames[i];
|
||||
rc->layer_encoding_bitrate[i] = 0.001 * rc->layer_framerate[i] *
|
||||
rc->layer_encoding_bitrate[i] /
|
||||
tot_num_frames;
|
||||
rc->layer_avg_frame_size[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_enc_frames[i];
|
||||
printf("For layer#: %d \n", i);
|
||||
printf("Bitrate (target vs actual): %d %f \n", rc->layer_target_bitrate[i],
|
||||
rc->layer_encoding_bitrate[i]);
|
||||
printf("Average frame size (target vs actual): %f %f \n", rc->layer_pfb[i],
|
||||
rc->layer_avg_frame_size[i]);
|
||||
printf("Average rate_mismatch: %f \n", rc->layer_avg_rate_mismatch[i]);
|
||||
printf(
|
||||
"Number of input frames, encoded (non-key) frames, "
|
||||
"and perc dropped frames: %d %d %f \n",
|
||||
rc->layer_input_frames[i], rc->layer_enc_frames[i],
|
||||
100.0 * num_dropped / rc->layer_input_frames[i]);
|
||||
printf("\n");
|
||||
}
|
||||
rc->avg_st_encoding_bitrate = rc->avg_st_encoding_bitrate / rc->window_count;
|
||||
rc->variance_st_encoding_bitrate =
|
||||
rc->variance_st_encoding_bitrate / rc->window_count -
|
||||
(rc->avg_st_encoding_bitrate * rc->avg_st_encoding_bitrate);
|
||||
perc_fluctuation = 100.0 * sqrt(rc->variance_st_encoding_bitrate) /
|
||||
rc->avg_st_encoding_bitrate;
|
||||
printf("Short-time stats, for window of %d frames: \n", rc->window_size);
|
||||
printf("Average, rms-variance, and percent-fluct: %f %f %f \n",
|
||||
rc->avg_st_encoding_bitrate, sqrt(rc->variance_st_encoding_bitrate),
|
||||
perc_fluctuation);
|
||||
if ((frame_cnt - 1) != tot_num_frames)
|
||||
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:
|
||||
// NOTE: The 3 prediction frames cannot be used interchangeably due to
|
||||
// differences in the way they are handled throughout the code. The
|
||||
// frames should be allocated to layers in the order LAST, GF, ARF.
|
||||
// Other combinations work, but may produce slightly inferior results.
|
||||
static void set_temporal_layer_pattern(int layering_mode,
|
||||
vpx_codec_enc_cfg_t *cfg,
|
||||
int *layer_flags,
|
||||
int *flag_periodicity) {
|
||||
switch (layering_mode) {
|
||||
case 0: {
|
||||
// 1-layer.
|
||||
int ids[1] = { 0 };
|
||||
cfg->ts_periodicity = 1;
|
||||
*flag_periodicity = 1;
|
||||
cfg->ts_number_layers = 1;
|
||||
cfg->ts_rate_decimator[0] = 1;
|
||||
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
|
||||
// Update L only.
|
||||
layer_flags[0] =
|
||||
VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// 2-layers, 2-frame period.
|
||||
int ids[2] = { 0, 1 };
|
||||
cfg->ts_periodicity = 2;
|
||||
*flag_periodicity = 2;
|
||||
cfg->ts_number_layers = 2;
|
||||
cfg->ts_rate_decimator[0] = 2;
|
||||
cfg->ts_rate_decimator[1] = 1;
|
||||
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
|
||||
#if 1
|
||||
// 0=L, 1=GF, Intra-layer prediction enabled.
|
||||
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;
|
||||
#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
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// 2-layers, 3-frame period.
|
||||
int ids[3] = { 0, 1, 1 };
|
||||
cfg->ts_periodicity = 3;
|
||||
*flag_periodicity = 3;
|
||||
cfg->ts_number_layers = 2;
|
||||
cfg->ts_rate_decimator[0] = 3;
|
||||
cfg->ts_rate_decimator[1] = 1;
|
||||
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
|
||||
// 0=L, 1=GF, Intra-layer prediction enabled.
|
||||
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_UPD_ARF;
|
||||
layer_flags[1] = layer_flags[2] =
|
||||
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
|
||||
VP8_EFLAG_NO_UPD_LAST;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// 3-layers, 6-frame period.
|
||||
int ids[6] = { 0, 2, 2, 1, 2, 2 };
|
||||
cfg->ts_periodicity = 6;
|
||||
*flag_periodicity = 6;
|
||||
cfg->ts_number_layers = 3;
|
||||
cfg->ts_rate_decimator[0] = 6;
|
||||
cfg->ts_rate_decimator[1] = 3;
|
||||
cfg->ts_rate_decimator[2] = 1;
|
||||
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
|
||||
// 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled.
|
||||
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_UPD_ARF;
|
||||
layer_flags[3] =
|
||||
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
|
||||
layer_flags[1] = layer_flags[2] = layer_flags[4] = layer_flags[5] =
|
||||
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
// 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] = VPX_EFLAG_FORCE_KF | 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] = layer_flags[3] =
|
||||
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
|
||||
VP8_EFLAG_NO_UPD_ARF;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
// 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 enabled in layer 1, disabled
|
||||
// in layer 2.
|
||||
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_UPD_ARF;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
// 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 enabled.
|
||||
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_UPD_ARF;
|
||||
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_UPD_LAST | VP8_EFLAG_NO_UPD_GF;
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
// NOTE: Probably of academic interest only.
|
||||
// 5-layers, 16-frame period.
|
||||
int ids[16] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4 };
|
||||
cfg->ts_periodicity = 16;
|
||||
*flag_periodicity = 16;
|
||||
cfg->ts_number_layers = 5;
|
||||
cfg->ts_rate_decimator[0] = 16;
|
||||
cfg->ts_rate_decimator[1] = 8;
|
||||
cfg->ts_rate_decimator[2] = 4;
|
||||
cfg->ts_rate_decimator[3] = 2;
|
||||
cfg->ts_rate_decimator[4] = 1;
|
||||
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
|
||||
layer_flags[0] = VPX_EFLAG_FORCE_KF;
|
||||
layer_flags[1] = layer_flags[3] = layer_flags[5] = layer_flags[7] =
|
||||
layer_flags[9] = layer_flags[11] = layer_flags[13] = layer_flags[15] =
|
||||
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_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;
|
||||
}
|
||||
case 8: {
|
||||
// 2-layers, with sync point at first frame of layer 1.
|
||||
int ids[2] = { 0, 1 };
|
||||
cfg->ts_periodicity = 2;
|
||||
*flag_periodicity = 8;
|
||||
cfg->ts_number_layers = 2;
|
||||
cfg->ts_rate_decimator[0] = 2;
|
||||
cfg->ts_rate_decimator[1] = 1;
|
||||
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
|
||||
// 0=L, 1=GF.
|
||||
// ARF is used as predictor for all frames, and is only updated on
|
||||
// key frame. Sync point every 8 frames.
|
||||
|
||||
// Layer 0: predict from L and ARF, update L and G.
|
||||
layer_flags[0] =
|
||||
VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF;
|
||||
// Layer 1: sync point: predict from L and ARF, and update G.
|
||||
layer_flags[1] =
|
||||
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
|
||||
// Layer 0, predict from L and ARF, update L.
|
||||
layer_flags[2] =
|
||||
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
|
||||
// Layer 1: predict from L, G and ARF, and update G.
|
||||
layer_flags[3] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
|
||||
VP8_EFLAG_NO_UPD_ENTROPY;
|
||||
// Layer 0.
|
||||
layer_flags[4] = layer_flags[2];
|
||||
// Layer 1.
|
||||
layer_flags[5] = layer_flags[3];
|
||||
// Layer 0.
|
||||
layer_flags[6] = layer_flags[4];
|
||||
// Layer 1.
|
||||
layer_flags[7] = layer_flags[5];
|
||||
break;
|
||||
}
|
||||
case 9: {
|
||||
// 3-layers: Sync points for layer 1 and 2 every 8 frames.
|
||||
int ids[4] = { 0, 2, 1, 2 };
|
||||
cfg->ts_periodicity = 4;
|
||||
*flag_periodicity = 8;
|
||||
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.
|
||||
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_UPD_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;
|
||||
layer_flags[4] = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
|
||||
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
|
||||
layer_flags[6] =
|
||||
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ARF;
|
||||
layer_flags[7] = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
|
||||
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_ENTROPY;
|
||||
break;
|
||||
}
|
||||
case 10: {
|
||||
// 3-layers structure where ARF is used as predictor for all frames,
|
||||
// and is only updated on key frame.
|
||||
// Sync points for layer 1 and 2 every 8 frames.
|
||||
|
||||
int ids[4] = { 0, 2, 1, 2 };
|
||||
cfg->ts_periodicity = 4;
|
||||
*flag_periodicity = 8;
|
||||
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.
|
||||
// Layer 0: predict from L and ARF; update L and G.
|
||||
layer_flags[0] =
|
||||
VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF;
|
||||
// Layer 2: sync point: predict from L and ARF; update none.
|
||||
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_ENTROPY;
|
||||
// Layer 1: sync point: predict from L and ARF; update G.
|
||||
layer_flags[2] =
|
||||
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
|
||||
// Layer 2: predict from L, G, ARF; update none.
|
||||
layer_flags[3] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
|
||||
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY;
|
||||
// Layer 0: predict from L and ARF; update L.
|
||||
layer_flags[4] =
|
||||
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF;
|
||||
// Layer 2: predict from L, G, ARF; update none.
|
||||
layer_flags[5] = layer_flags[3];
|
||||
// Layer 1: predict from L, G, ARF; update G.
|
||||
layer_flags[6] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
|
||||
// Layer 2: predict from L, G, ARF; update none.
|
||||
layer_flags[7] = layer_flags[3];
|
||||
break;
|
||||
}
|
||||
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: {
|
||||
// 3-layers structure as in case 10, but no sync/refresh points for
|
||||
// layer 1 and 2.
|
||||
int ids[4] = { 0, 2, 1, 2 };
|
||||
cfg->ts_periodicity = 4;
|
||||
*flag_periodicity = 8;
|
||||
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.
|
||||
// Layer 0: predict from L and ARF; update L.
|
||||
layer_flags[0] =
|
||||
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF;
|
||||
layer_flags[4] = layer_flags[0];
|
||||
// Layer 1: predict from L, G, ARF; update G.
|
||||
layer_flags[2] = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
|
||||
layer_flags[6] = layer_flags[2];
|
||||
// Layer 2: predict from L, G, ARF; update none.
|
||||
layer_flags[1] = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
|
||||
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_ENTROPY;
|
||||
layer_flags[3] = layer_flags[1];
|
||||
layer_flags[5] = layer_flags[1];
|
||||
layer_flags[7] = layer_flags[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS] = { NULL };
|
||||
vpx_codec_ctx_t codec;
|
||||
vpx_codec_enc_cfg_t cfg;
|
||||
int frame_cnt = 0;
|
||||
vpx_image_t raw;
|
||||
vpx_codec_err_t res;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
uint32_t error_resilient = 0;
|
||||
int speed;
|
||||
int frame_avail;
|
||||
int got_data;
|
||||
int flags = 0;
|
||||
unsigned int i;
|
||||
int pts = 0; // PTS starts at 0.
|
||||
int frame_duration = 1; // 1 timebase tick per frame.
|
||||
int layering_mode = 0;
|
||||
int layer_flags[VPX_TS_MAX_PERIODICITY] = { 0 };
|
||||
int flag_periodicity = 1;
|
||||
#if ROI_MAP
|
||||
vpx_roi_map_t roi;
|
||||
#endif
|
||||
vpx_svc_layer_id_t layer_id = { 0, 0 };
|
||||
const VpxInterface *encoder = NULL;
|
||||
FILE *infile = NULL;
|
||||
struct RateControlMetrics rc;
|
||||
int64_t cx_time = 0;
|
||||
const int min_args_base = 13;
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
vpx_bit_depth_t bit_depth = VPX_BITS_8;
|
||||
int input_bit_depth = 8;
|
||||
const int min_args = min_args_base + 1;
|
||||
#else
|
||||
const int min_args = min_args_base;
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
double sum_bitrate = 0.0;
|
||||
double sum_bitrate2 = 0.0;
|
||||
double framerate = 30.0;
|
||||
|
||||
zero(rc.layer_target_bitrate);
|
||||
|
||||
exec_name = argv[0];
|
||||
// Check usage and arguments.
|
||||
if (argc < min_args) {
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> "
|
||||
"<rate_num> <rate_den> <speed> <frame_drop_threshold> "
|
||||
"<error_resilient> <threads> <mode> "
|
||||
"<Rate_0> ... <Rate_nlayers-1> <bit-depth> \n",
|
||||
argv[0]);
|
||||
#else
|
||||
die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> "
|
||||
"<rate_num> <rate_den> <speed> <frame_drop_threshold> "
|
||||
"<error_resilient> <threads> <mode> "
|
||||
"<Rate_0> ... <Rate_nlayers-1> \n",
|
||||
argv[0]);
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
}
|
||||
|
||||
encoder = get_vpx_encoder_by_name(argv[3]);
|
||||
if (!encoder) die("Unsupported codec.");
|
||||
|
||||
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
|
||||
|
||||
width = (unsigned int)strtoul(argv[4], NULL, 0);
|
||||
height = (unsigned int)strtoul(argv[5], NULL, 0);
|
||||
if (width < 16 || width % 2 || height < 16 || height % 2) {
|
||||
die("Invalid resolution: %d x %d", width, height);
|
||||
}
|
||||
|
||||
layering_mode = (int)strtol(argv[12], NULL, 0);
|
||||
if (layering_mode < 0 || layering_mode > 13) {
|
||||
die("Invalid layering mode (0..12) %s", argv[12]);
|
||||
}
|
||||
|
||||
if (argc != min_args + mode_to_num_layers[layering_mode]) {
|
||||
die("Invalid number of arguments");
|
||||
}
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
switch (strtol(argv[argc - 1], NULL, 0)) {
|
||||
case 8:
|
||||
bit_depth = VPX_BITS_8;
|
||||
input_bit_depth = 8;
|
||||
break;
|
||||
case 10:
|
||||
bit_depth = VPX_BITS_10;
|
||||
input_bit_depth = 10;
|
||||
break;
|
||||
case 12:
|
||||
bit_depth = VPX_BITS_12;
|
||||
input_bit_depth = 12;
|
||||
break;
|
||||
default: die("Invalid bit depth (8, 10, 12) %s", argv[argc - 1]);
|
||||
}
|
||||
if (!vpx_img_alloc(
|
||||
&raw, bit_depth == VPX_BITS_8 ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_I42016,
|
||||
width, height, 32)) {
|
||||
die("Failed to allocate image", width, height);
|
||||
}
|
||||
#else
|
||||
if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 32)) {
|
||||
die("Failed to allocate image", width, height);
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
// Populate encoder configuration.
|
||||
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
|
||||
if (res) {
|
||||
printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Update the default configuration with our settings.
|
||||
cfg.g_w = width;
|
||||
cfg.g_h = height;
|
||||
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (bit_depth != VPX_BITS_8) {
|
||||
cfg.g_bit_depth = bit_depth;
|
||||
cfg.g_input_bit_depth = input_bit_depth;
|
||||
cfg.g_profile = 2;
|
||||
}
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
|
||||
// Timebase format e.g. 30fps: numerator=1, demoninator = 30.
|
||||
cfg.g_timebase.num = (int)strtol(argv[6], NULL, 0);
|
||||
cfg.g_timebase.den = (int)strtol(argv[7], NULL, 0);
|
||||
|
||||
speed = (int)strtol(argv[8], NULL, 0);
|
||||
if (speed < 0) {
|
||||
die("Invalid speed setting: must be positive");
|
||||
}
|
||||
|
||||
for (i = min_args_base;
|
||||
(int)i < min_args_base + mode_to_num_layers[layering_mode]; ++i) {
|
||||
rc.layer_target_bitrate[i - 13] = (int)strtol(argv[i], NULL, 0);
|
||||
if (strncmp(encoder->name, "vp8", 3) == 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.
|
||||
cfg.rc_dropframe_thresh = (unsigned int)strtoul(argv[9], NULL, 0);
|
||||
cfg.rc_end_usage = VPX_CBR;
|
||||
cfg.rc_min_quantizer = 2;
|
||||
cfg.rc_max_quantizer = 56;
|
||||
if (strncmp(encoder->name, "vp9", 3) == 0) cfg.rc_max_quantizer = 52;
|
||||
cfg.rc_undershoot_pct = 50;
|
||||
cfg.rc_overshoot_pct = 50;
|
||||
cfg.rc_buf_initial_sz = 600;
|
||||
cfg.rc_buf_optimal_sz = 600;
|
||||
cfg.rc_buf_sz = 1000;
|
||||
|
||||
// Disable dynamic resizing by default.
|
||||
cfg.rc_resize_allowed = 0;
|
||||
|
||||
// Use 1 thread as default.
|
||||
cfg.g_threads = (unsigned int)strtoul(argv[11], NULL, 0);
|
||||
|
||||
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.
|
||||
cfg.g_error_resilient = error_resilient;
|
||||
cfg.g_lag_in_frames = 0;
|
||||
cfg.kf_mode = VPX_KF_AUTO;
|
||||
|
||||
// Disable automatic keyframe placement.
|
||||
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, layer_flags,
|
||||
&flag_periodicity);
|
||||
|
||||
set_rate_control_metrics(&rc, &cfg);
|
||||
|
||||
// Target bandwidth for the whole stream.
|
||||
// Set to layer_target_bitrate for highest layer (total bitrate).
|
||||
cfg.rc_target_bitrate = rc.layer_target_bitrate[cfg.ts_number_layers - 1];
|
||||
|
||||
// Open input file.
|
||||
if (!(infile = fopen(argv[1], "rb"))) {
|
||||
die("Failed to open %s for reading", argv[1]);
|
||||
}
|
||||
|
||||
framerate = cfg.g_timebase.den / cfg.g_timebase.num;
|
||||
// Open an output file for each stream.
|
||||
for (i = 0; i < cfg.ts_number_layers; ++i) {
|
||||
char file_name[PATH_MAX];
|
||||
VpxVideoInfo info;
|
||||
info.codec_fourcc = encoder->fourcc;
|
||||
info.frame_width = cfg.g_w;
|
||||
info.frame_height = cfg.g_h;
|
||||
info.time_base.numerator = cfg.g_timebase.num;
|
||||
info.time_base.denominator = cfg.g_timebase.den;
|
||||
|
||||
snprintf(file_name, sizeof(file_name), "%s_%d.ivf", argv[2], i);
|
||||
outfile[i] = vpx_video_writer_open(file_name, kContainerIVF, &info);
|
||||
if (!outfile[i]) die("Failed to open %s for writing", file_name);
|
||||
|
||||
assert(outfile[i] != NULL);
|
||||
}
|
||||
// No spatial layers in this encoder.
|
||||
cfg.ss_number_layers = 1;
|
||||
|
||||
// Initialize codec.
|
||||
#if CONFIG_VP9_HIGHBITDEPTH
|
||||
if (vpx_codec_enc_init(
|
||||
&codec, encoder->codec_interface(), &cfg,
|
||||
bit_depth == VPX_BITS_8 ? 0 : VPX_CODEC_USE_HIGHBITDEPTH))
|
||||
#else
|
||||
if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
|
||||
#endif // CONFIG_VP9_HIGHBITDEPTH
|
||||
die_codec(&codec, "Failed to initialize encoder");
|
||||
|
||||
if (strncmp(encoder->name, "vp8", 3) == 0) {
|
||||
vpx_codec_control(&codec, VP8E_SET_CPUUSED, -speed);
|
||||
vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kVp8DenoiserOff);
|
||||
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
|
||||
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) {
|
||||
vpx_svc_extra_cfg_t svc_params;
|
||||
memset(&svc_params, 0, sizeof(svc_params));
|
||||
vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed);
|
||||
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
|
||||
vpx_codec_control(&codec, VP9E_SET_GF_CBR_BOOST_PCT, 0);
|
||||
vpx_codec_control(&codec, VP9E_SET_FRAME_PARALLEL_DECODING, 0);
|
||||
vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0);
|
||||
vpx_codec_control(&codec, VP9E_SET_NOISE_SENSITIVITY, kVp9DenoiserOff);
|
||||
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) {
|
||||
vpx_codec_control(&codec, VP8E_SET_SCREEN_CONTENT_MODE, 0);
|
||||
}
|
||||
vpx_codec_control(&codec, VP8E_SET_TOKEN_PARTITIONS, 1);
|
||||
// This controls the maximum target size of the key frame.
|
||||
// For generating smaller key frames, use a smaller max_intra_size_pct
|
||||
// value, like 100 or 200.
|
||||
{
|
||||
const int max_intra_size_pct = 1000;
|
||||
vpx_codec_control(&codec, VP8E_SET_MAX_INTRA_BITRATE_PCT,
|
||||
max_intra_size_pct);
|
||||
}
|
||||
|
||||
frame_avail = 1;
|
||||
while (frame_avail || got_data) {
|
||||
struct vpx_usec_timer timer;
|
||||
vpx_codec_iter_t iter = NULL;
|
||||
const vpx_codec_cx_pkt_t *pkt;
|
||||
// Update the temporal layer_id. No spatial layers in this test.
|
||||
layer_id.spatial_layer_id = 0;
|
||||
layer_id.temporal_layer_id =
|
||||
cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
|
||||
if (strncmp(encoder->name, "vp9", 3) == 0) {
|
||||
vpx_codec_control(&codec, VP9E_SET_SVC_LAYER_ID, &layer_id);
|
||||
} else if (strncmp(encoder->name, "vp8", 3) == 0) {
|
||||
vpx_codec_control(&codec, VP8E_SET_TEMPORAL_LAYER_ID,
|
||||
layer_id.temporal_layer_id);
|
||||
}
|
||||
flags = layer_flags[frame_cnt % flag_periodicity];
|
||||
if (layering_mode == 0) flags = 0;
|
||||
frame_avail = vpx_img_read(&raw, infile);
|
||||
if (frame_avail) ++rc.layer_input_frames[layer_id.temporal_layer_id];
|
||||
vpx_usec_timer_start(&timer);
|
||||
if (vpx_codec_encode(&codec, frame_avail ? &raw : NULL, pts, 1, flags,
|
||||
VPX_DL_REALTIME)) {
|
||||
die_codec(&codec, "Failed to encode frame");
|
||||
}
|
||||
vpx_usec_timer_mark(&timer);
|
||||
cx_time += vpx_usec_timer_elapsed(&timer);
|
||||
// Reset KF flag.
|
||||
if (layering_mode != 7) {
|
||||
layer_flags[0] &= ~VPX_EFLAG_FORCE_KF;
|
||||
}
|
||||
got_data = 0;
|
||||
while ((pkt = vpx_codec_get_cx_data(&codec, &iter))) {
|
||||
got_data = 1;
|
||||
switch (pkt->kind) {
|
||||
case VPX_CODEC_CX_FRAME_PKT:
|
||||
for (i = cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
|
||||
i < cfg.ts_number_layers; ++i) {
|
||||
vpx_video_writer_write_frame(outfile[i], pkt->data.frame.buf,
|
||||
pkt->data.frame.sz, pts);
|
||||
++rc.layer_tot_enc_frames[i];
|
||||
rc.layer_encoding_bitrate[i] += 8.0 * pkt->data.frame.sz;
|
||||
// Keep count of rate control stats per layer (for non-key frames).
|
||||
if (i == cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity] &&
|
||||
!(pkt->data.frame.flags & VPX_FRAME_IS_KEY)) {
|
||||
rc.layer_avg_frame_size[i] += 8.0 * pkt->data.frame.sz;
|
||||
rc.layer_avg_rate_mismatch[i] +=
|
||||
fabs(8.0 * pkt->data.frame.sz - rc.layer_pfb[i]) /
|
||||
rc.layer_pfb[i];
|
||||
++rc.layer_enc_frames[i];
|
||||
}
|
||||
}
|
||||
// Update for short-time encoding bitrate states, for moving window
|
||||
// of size rc->window, shifted by rc->window / 2.
|
||||
// Ignore first window segment, due to key frame.
|
||||
if (frame_cnt > rc.window_size) {
|
||||
sum_bitrate += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
|
||||
if (frame_cnt % rc.window_size == 0) {
|
||||
rc.window_count += 1;
|
||||
rc.avg_st_encoding_bitrate += sum_bitrate / rc.window_size;
|
||||
rc.variance_st_encoding_bitrate +=
|
||||
(sum_bitrate / rc.window_size) *
|
||||
(sum_bitrate / rc.window_size);
|
||||
sum_bitrate = 0.0;
|
||||
}
|
||||
}
|
||||
// Second shifted window.
|
||||
if (frame_cnt > rc.window_size + rc.window_size / 2) {
|
||||
sum_bitrate2 += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
|
||||
if (frame_cnt > 2 * rc.window_size &&
|
||||
frame_cnt % rc.window_size == 0) {
|
||||
rc.window_count += 1;
|
||||
rc.avg_st_encoding_bitrate += sum_bitrate2 / rc.window_size;
|
||||
rc.variance_st_encoding_bitrate +=
|
||||
(sum_bitrate2 / rc.window_size) *
|
||||
(sum_bitrate2 / rc.window_size);
|
||||
sum_bitrate2 = 0.0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
++frame_cnt;
|
||||
pts += frame_duration;
|
||||
}
|
||||
fclose(infile);
|
||||
printout_rate_control_summary(&rc, &cfg, frame_cnt);
|
||||
printf("\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),
|
||||
1000000 * (double)frame_cnt / (double)cx_time);
|
||||
|
||||
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
|
||||
|
||||
// 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]);
|
||||
|
||||
vpx_img_free(&raw);
|
||||
#if ROI_MAP
|
||||
free(roi.roi_map);
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
112
ivfdec.c
112
ivfdec.c
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vpx_ports/mem_ops.h"
|
||||
|
||||
#include "./ivfdec.h"
|
||||
|
||||
static const char *IVF_SIGNATURE = "DKIF";
|
||||
|
||||
static void fix_framerate(int *num, int *den) {
|
||||
// Some versions of vpxenc used 1/(2*fps) for the timebase, so
|
||||
// we can guess the framerate using only the timebase in this
|
||||
// case. Other files would require reading ahead to guess the
|
||||
// timebase, like we do for webm.
|
||||
if (*den > 0 && *den < 1000000000 && *num > 0 && *num < 1000) {
|
||||
// Correct for the factor of 2 applied to the timebase in the encoder.
|
||||
if (*num & 1)
|
||||
*den *= 2;
|
||||
else
|
||||
*num /= 2;
|
||||
} else {
|
||||
// Don't know FPS for sure, and don't have readahead code
|
||||
// (yet?), so just default to 30fps.
|
||||
*num = 30;
|
||||
*den = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int file_is_ivf(struct VpxInputContext *input_ctx) {
|
||||
char raw_hdr[32];
|
||||
int is_ivf = 0;
|
||||
|
||||
if (fread(raw_hdr, 1, 32, input_ctx->file) == 32) {
|
||||
if (memcmp(IVF_SIGNATURE, raw_hdr, 4) == 0) {
|
||||
is_ivf = 1;
|
||||
|
||||
if (mem_get_le16(raw_hdr + 4) != 0) {
|
||||
fprintf(stderr,
|
||||
"Error: Unrecognized IVF version! This file may not"
|
||||
" decode properly.");
|
||||
}
|
||||
|
||||
input_ctx->fourcc = mem_get_le32(raw_hdr + 8);
|
||||
input_ctx->width = mem_get_le16(raw_hdr + 12);
|
||||
input_ctx->height = mem_get_le16(raw_hdr + 14);
|
||||
input_ctx->framerate.numerator = mem_get_le32(raw_hdr + 16);
|
||||
input_ctx->framerate.denominator = mem_get_le32(raw_hdr + 20);
|
||||
fix_framerate(&input_ctx->framerate.numerator,
|
||||
&input_ctx->framerate.denominator);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_ivf) {
|
||||
rewind(input_ctx->file);
|
||||
input_ctx->detect.buf_read = 0;
|
||||
} else {
|
||||
input_ctx->detect.position = 4;
|
||||
}
|
||||
return is_ivf;
|
||||
}
|
||||
|
||||
int ivf_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read,
|
||||
size_t *buffer_size) {
|
||||
char raw_header[IVF_FRAME_HDR_SZ] = { 0 };
|
||||
size_t frame_size = 0;
|
||||
|
||||
if (fread(raw_header, IVF_FRAME_HDR_SZ, 1, infile) != 1) {
|
||||
if (!feof(infile)) warn("Failed to read frame size\n");
|
||||
} else {
|
||||
frame_size = mem_get_le32(raw_header);
|
||||
|
||||
if (frame_size > 256 * 1024 * 1024) {
|
||||
warn("Read invalid frame size (%u)\n", (unsigned int)frame_size);
|
||||
frame_size = 0;
|
||||
}
|
||||
|
||||
if (frame_size > *buffer_size) {
|
||||
uint8_t *new_buffer = realloc(*buffer, 2 * frame_size);
|
||||
|
||||
if (new_buffer) {
|
||||
*buffer = new_buffer;
|
||||
*buffer_size = 2 * frame_size;
|
||||
} else {
|
||||
warn("Failed to allocate compressed data buffer\n");
|
||||
frame_size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!feof(infile)) {
|
||||
if (fread(*buffer, 1, frame_size, infile) != frame_size) {
|
||||
warn("Failed to read full frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
*bytes_read = frame_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
28
ivfdec.h
28
ivfdec.h
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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 IVFDEC_H_
|
||||
#define IVFDEC_H_
|
||||
|
||||
#include "./tools_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int file_is_ivf(struct VpxInputContext *input);
|
||||
|
||||
int ivf_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read,
|
||||
size_t *buffer_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif // IVFDEC_H_
|
51
ivfenc.c
51
ivfenc.c
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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 "./ivfenc.h"
|
||||
|
||||
#include "vpx/vpx_encoder.h"
|
||||
#include "vpx_ports/mem_ops.h"
|
||||
|
||||
void ivf_write_file_header(FILE *outfile, const struct vpx_codec_enc_cfg *cfg,
|
||||
unsigned int fourcc, int frame_cnt) {
|
||||
char header[32];
|
||||
|
||||
header[0] = 'D';
|
||||
header[1] = 'K';
|
||||
header[2] = 'I';
|
||||
header[3] = 'F';
|
||||
mem_put_le16(header + 4, 0); // version
|
||||
mem_put_le16(header + 6, 32); // header size
|
||||
mem_put_le32(header + 8, fourcc); // fourcc
|
||||
mem_put_le16(header + 12, cfg->g_w); // width
|
||||
mem_put_le16(header + 14, cfg->g_h); // height
|
||||
mem_put_le32(header + 16, cfg->g_timebase.den); // rate
|
||||
mem_put_le32(header + 20, cfg->g_timebase.num); // scale
|
||||
mem_put_le32(header + 24, frame_cnt); // length
|
||||
mem_put_le32(header + 28, 0); // unused
|
||||
|
||||
fwrite(header, 1, 32, outfile);
|
||||
}
|
||||
|
||||
void ivf_write_frame_header(FILE *outfile, int64_t pts, size_t frame_size) {
|
||||
char header[12];
|
||||
|
||||
mem_put_le32(header, (int)frame_size);
|
||||
mem_put_le32(header + 4, (int)(pts & 0xFFFFFFFF));
|
||||
mem_put_le32(header + 8, (int)(pts >> 32));
|
||||
fwrite(header, 1, 12, outfile);
|
||||
}
|
||||
|
||||
void ivf_write_frame_size(FILE *outfile, size_t frame_size) {
|
||||
char header[4];
|
||||
|
||||
mem_put_le32(header, (int)frame_size);
|
||||
fwrite(header, 1, 4, outfile);
|
||||
}
|
33
ivfenc.h
33
ivfenc.h
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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 IVFENC_H_
|
||||
#define IVFENC_H_
|
||||
|
||||
#include "./tools_common.h"
|
||||
|
||||
struct vpx_codec_enc_cfg;
|
||||
struct vpx_codec_cx_pkt;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void ivf_write_file_header(FILE *outfile, 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_size(FILE *outfile, size_t frame_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif // IVFENC_H_
|
51
keywords.dox
51
keywords.dox
@ -1,51 +0,0 @@
|
||||
/*!\page rfc2119 RFC2119 Keywords
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
|
||||
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
|
||||
"OPTIONAL" in this document are to be interpreted as described in
|
||||
<a href="http://www.ietf.org/rfc/rfc2119.txt">RFC 2119.</a>
|
||||
|
||||
Specifically, the following definitions are used:
|
||||
|
||||
\section MUST
|
||||
\anchor REQUIRED
|
||||
\anchor SHALL
|
||||
This word, or the terms "REQUIRED" or "SHALL", mean that the
|
||||
definition is an absolute requirement of the specification.
|
||||
|
||||
\section MUSTNOT MUST NOT
|
||||
\anchor SHALLNOT
|
||||
This phrase, or the phrase "SHALL NOT", mean that the
|
||||
definition is an absolute prohibition of the specification.
|
||||
|
||||
\section SHOULD
|
||||
\anchor RECOMMENDED
|
||||
This word, or the adjective "RECOMMENDED", mean that there
|
||||
may exist valid reasons in particular circumstances to ignore a
|
||||
particular item, but the full implications must be understood and
|
||||
carefully weighed before choosing a different course.
|
||||
|
||||
\section SHOULDNOT SHOULD NOT
|
||||
\anchor NOTRECOMMENDED
|
||||
This phrase, or the phrase "NOT RECOMMENDED" mean that
|
||||
there may exist valid reasons in particular circumstances when the
|
||||
particular behavior is acceptable or even useful, but the full
|
||||
implications should be understood and the case carefully weighed
|
||||
before implementing any behavior described with this label.
|
||||
|
||||
\section MAY
|
||||
\anchor OPTIONAL
|
||||
This word, or the adjective "OPTIONAL", mean that an item is
|
||||
truly optional. One vendor may choose to include the item because a
|
||||
particular marketplace requires it or because the vendor feels that
|
||||
it enhances the product while another vendor may omit the same item.
|
||||
An implementation which does not include a particular option \ref MUST be
|
||||
prepared to interoperate with another implementation which does
|
||||
include the option, though perhaps with reduced functionality. In the
|
||||
same vein an implementation which does include a particular option
|
||||
\ref MUST be prepared to interoperate with another implementation which
|
||||
does not include the option (except, of course, for the feature the
|
||||
option provides.)
|
||||
|
||||
|
||||
*/
|
1284
libs.doxy_template
1284
libs.doxy_template
File diff suppressed because it is too large
Load Diff
635
libs.mk
635
libs.mk
@ -1,635 +0,0 @@
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
|
||||
# ARM assembly files are written in RVCT-style. We use some make magic to
|
||||
# filter those files to allow GCC compilation
|
||||
ifeq ($(ARCH_ARM),yes)
|
||||
ASM:=$(if $(filter yes,$(CONFIG_GCC)$(CONFIG_MSVS)),.asm.S,.asm)
|
||||
else
|
||||
ASM:=.asm
|
||||
endif
|
||||
|
||||
#
|
||||
# Rule to generate runtime cpu detection files
|
||||
#
|
||||
define rtcd_h_template
|
||||
$$(BUILD_PFX)$(1).h: $$(SRC_PATH_BARE)/$(2)
|
||||
@echo " [CREATE] $$@"
|
||||
$$(qexec)$$(SRC_PATH_BARE)/build/make/rtcd.pl --arch=$$(TGT_ISA) \
|
||||
--sym=$(1) \
|
||||
--config=$$(CONFIG_DIR)$$(target)-$$(TOOLCHAIN).mk \
|
||||
$$(RTCD_OPTIONS) $$^ > $$@
|
||||
CLEAN-OBJS += $$(BUILD_PFX)$(1).h
|
||||
RTCD += $$(BUILD_PFX)$(1).h
|
||||
endef
|
||||
|
||||
CODEC_SRCS-yes += CHANGELOG
|
||||
CODEC_SRCS-yes += libs.mk
|
||||
|
||||
include $(SRC_PATH_BARE)/vpx/vpx_codec.mk
|
||||
CODEC_SRCS-yes += $(addprefix vpx/,$(call enabled,API_SRCS))
|
||||
CODEC_DOC_SRCS += $(addprefix vpx/,$(call enabled,API_DOC_SRCS))
|
||||
|
||||
include $(SRC_PATH_BARE)/vpx_mem/vpx_mem.mk
|
||||
CODEC_SRCS-yes += $(addprefix vpx_mem/,$(call enabled,MEM_SRCS))
|
||||
|
||||
include $(SRC_PATH_BARE)/vpx_scale/vpx_scale.mk
|
||||
CODEC_SRCS-yes += $(addprefix vpx_scale/,$(call enabled,SCALE_SRCS))
|
||||
|
||||
include $(SRC_PATH_BARE)/vpx_ports/vpx_ports.mk
|
||||
CODEC_SRCS-yes += $(addprefix vpx_ports/,$(call enabled,PORTS_SRCS))
|
||||
|
||||
include $(SRC_PATH_BARE)/vpx_dsp/vpx_dsp.mk
|
||||
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/
|
||||
include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8_common.mk
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_VP8_ENCODER),yes)
|
||||
include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8cx.mk
|
||||
CODEC_SRCS-yes += $(addprefix $(VP8_PREFIX),$(call enabled,VP8_CX_SRCS))
|
||||
CODEC_EXPORTS-yes += $(addprefix $(VP8_PREFIX),$(VP8_CX_EXPORTS))
|
||||
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h
|
||||
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP8_PREFIX)/%
|
||||
CODEC_DOC_SECTIONS += vp8 vp8_encoder
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_VP8_DECODER),yes)
|
||||
include $(SRC_PATH_BARE)/$(VP8_PREFIX)vp8dx.mk
|
||||
CODEC_SRCS-yes += $(addprefix $(VP8_PREFIX),$(call enabled,VP8_DX_SRCS))
|
||||
CODEC_EXPORTS-yes += $(addprefix $(VP8_PREFIX),$(VP8_DX_EXPORTS))
|
||||
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8dx.h
|
||||
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP8_PREFIX)/%
|
||||
CODEC_DOC_SECTIONS += vp8 vp8_decoder
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_VP9),yes)
|
||||
VP9_PREFIX=vp9/
|
||||
include $(SRC_PATH_BARE)/$(VP9_PREFIX)vp9_common.mk
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_VP9_ENCODER),yes)
|
||||
VP9_PREFIX=vp9/
|
||||
include $(SRC_PATH_BARE)/$(VP9_PREFIX)vp9cx.mk
|
||||
CODEC_SRCS-yes += $(addprefix $(VP9_PREFIX),$(call enabled,VP9_CX_SRCS))
|
||||
CODEC_EXPORTS-yes += $(addprefix $(VP9_PREFIX),$(VP9_CX_EXPORTS))
|
||||
CODEC_SRCS-yes += $(VP9_PREFIX)vp9cx.mk vpx/vp8.h vpx/vp8cx.h
|
||||
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h
|
||||
INSTALL-LIBS-yes += include/vpx/svc_context.h
|
||||
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_PREFIX)/%
|
||||
CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h
|
||||
CODEC_DOC_SECTIONS += vp9 vp9_encoder
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_VP9_DECODER),yes)
|
||||
VP9_PREFIX=vp9/
|
||||
include $(SRC_PATH_BARE)/$(VP9_PREFIX)vp9dx.mk
|
||||
CODEC_SRCS-yes += $(addprefix $(VP9_PREFIX),$(call enabled,VP9_DX_SRCS))
|
||||
CODEC_EXPORTS-yes += $(addprefix $(VP9_PREFIX),$(VP9_DX_EXPORTS))
|
||||
CODEC_SRCS-yes += $(VP9_PREFIX)vp9dx.mk vpx/vp8.h vpx/vp8dx.h
|
||||
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8dx.h
|
||||
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_PREFIX)/%
|
||||
CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8dx.h
|
||||
CODEC_DOC_SECTIONS += vp9 vp9_decoder
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ENCODERS),yes)
|
||||
CODEC_DOC_SECTIONS += encoder
|
||||
endif
|
||||
ifeq ($(CONFIG_DECODERS),yes)
|
||||
CODEC_DOC_SECTIONS += decoder
|
||||
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)
|
||||
CODEC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd)
|
||||
GTEST_LIB=$(if $(CONFIG_STATIC_MSVCRT),gtestmt,gtestmd)
|
||||
# This variable uses deferred expansion intentionally, since the results of
|
||||
# $(wildcard) may change during the course of the Make.
|
||||
VS_PLATFORMS = $(foreach d,$(wildcard */Release/$(CODEC_LIB).lib),$(word 1,$(subst /, ,$(d))))
|
||||
endif
|
||||
|
||||
# The following pairs define a mapping of locations in the distribution
|
||||
# tree to locations in the source/build trees.
|
||||
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/vpx/%
|
||||
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/vpx_ports/%
|
||||
INSTALL_MAPS += $(LIBSUBDIR)/% %
|
||||
INSTALL_MAPS += src/% $(SRC_PATH_BARE)/%
|
||||
ifeq ($(CONFIG_MSVS),yes)
|
||||
INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/% $(p)/Release/%)
|
||||
INSTALL_MAPS += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/% $(p)/Debug/%)
|
||||
endif
|
||||
|
||||
CODEC_SRCS-yes += build/make/version.sh
|
||||
CODEC_SRCS-yes += build/make/rtcd.pl
|
||||
CODEC_SRCS-yes += vpx_ports/emmintrin_compat.h
|
||||
CODEC_SRCS-yes += vpx_ports/mem_ops.h
|
||||
CODEC_SRCS-yes += vpx_ports/mem_ops_aligned.h
|
||||
CODEC_SRCS-yes += vpx_ports/vpx_once.h
|
||||
CODEC_SRCS-yes += $(BUILD_PFX)vpx_config.c
|
||||
INSTALL-SRCS-no += $(BUILD_PFX)vpx_config.c
|
||||
ifeq ($(ARCH_X86)$(ARCH_X86_64),yes)
|
||||
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += third_party/x86inc/x86inc.asm
|
||||
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += vpx_dsp/x86/bitdepth_conversion_sse2.asm
|
||||
endif
|
||||
CODEC_EXPORTS-yes += vpx/exports_com
|
||||
CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_enc
|
||||
CODEC_EXPORTS-$(CONFIG_VP9_ENCODER) += vpx/exports_spatial_svc
|
||||
CODEC_EXPORTS-$(CONFIG_DECODERS) += vpx/exports_dec
|
||||
|
||||
INSTALL-LIBS-yes += include/vpx/vpx_codec.h
|
||||
INSTALL-LIBS-yes += include/vpx/vpx_frame_buffer.h
|
||||
INSTALL-LIBS-yes += include/vpx/vpx_image.h
|
||||
INSTALL-LIBS-yes += include/vpx/vpx_integer.h
|
||||
INSTALL-LIBS-$(CONFIG_DECODERS) += include/vpx/vpx_decoder.h
|
||||
INSTALL-LIBS-$(CONFIG_ENCODERS) += include/vpx/vpx_encoder.h
|
||||
ifeq ($(CONFIG_EXTERNAL_BUILD),yes)
|
||||
ifeq ($(CONFIG_MSVS),yes)
|
||||
INSTALL-LIBS-yes += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/$(CODEC_LIB).lib)
|
||||
INSTALL-LIBS-$(CONFIG_DEBUG_LIBS) += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/$(CODEC_LIB)d.lib)
|
||||
INSTALL-LIBS-$(CONFIG_SHARED) += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/vpx.dll)
|
||||
INSTALL-LIBS-$(CONFIG_SHARED) += $(foreach p,$(VS_PLATFORMS),$(LIBSUBDIR)/$(p)/vpx.exp)
|
||||
endif
|
||||
else
|
||||
INSTALL-LIBS-$(CONFIG_STATIC) += $(LIBSUBDIR)/libvpx.a
|
||||
INSTALL-LIBS-$(CONFIG_DEBUG_LIBS) += $(LIBSUBDIR)/libvpx_g.a
|
||||
endif
|
||||
|
||||
CODEC_SRCS=$(call enabled,CODEC_SRCS)
|
||||
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(CODEC_SRCS)
|
||||
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(call enabled,CODEC_EXPORTS)
|
||||
|
||||
|
||||
# Generate a list of all enabled sources, in particular for exporting to gyp
|
||||
# based build systems.
|
||||
libvpx_srcs.txt:
|
||||
@echo " [CREATE] $@"
|
||||
@echo $(CODEC_SRCS) | xargs -n1 echo | LC_ALL=C sort -u > $@
|
||||
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_MSVS),yes)
|
||||
|
||||
vpx.def: $(call enabled,CODEC_EXPORTS)
|
||||
@echo " [CREATE] $@"
|
||||
$(qexec)$(SRC_PATH_BARE)/build/make/gen_msvs_def.sh\
|
||||
--name=vpx\
|
||||
--out=$@ $^
|
||||
CLEAN-OBJS += vpx.def
|
||||
|
||||
vpx.$(VCPROJ_SFX): VCPROJ_SRCS=$(filter-out $(addprefix %, $(ASM_INCLUDES)), $^)
|
||||
|
||||
vpx.$(VCPROJ_SFX): $(CODEC_SRCS) vpx.def
|
||||
@echo " [CREATE] $@"
|
||||
$(qexec)$(GEN_VCPROJ) \
|
||||
$(if $(CONFIG_SHARED),--dll,--lib) \
|
||||
--target=$(TOOLCHAIN) \
|
||||
$(if $(CONFIG_STATIC_MSVCRT),--static-crt) \
|
||||
--name=vpx \
|
||||
--proj-guid=DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74 \
|
||||
--module-def=vpx.def \
|
||||
--ver=$(CONFIG_VS_VERSION) \
|
||||
--src-path-bare="$(SRC_PATH_BARE)" \
|
||||
--out=$@ $(CFLAGS) \
|
||||
$(filter $(SRC_PATH_BARE)/vp8/%.c, $(VCPROJ_SRCS)) \
|
||||
$(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)" \
|
||||
|
||||
PROJECTS-yes += vpx.$(VCPROJ_SFX)
|
||||
|
||||
vpx.$(VCPROJ_SFX): vpx_config.asm
|
||||
vpx.$(VCPROJ_SFX): $(RTCD)
|
||||
|
||||
endif
|
||||
else
|
||||
LIBVPX_OBJS=$(call objs, $(filter-out $(ASM_INCLUDES), $(CODEC_SRCS)))
|
||||
OBJS-yes += $(LIBVPX_OBJS)
|
||||
LIBS-$(if yes,$(CONFIG_STATIC)) += $(BUILD_PFX)libvpx.a $(BUILD_PFX)libvpx_g.a
|
||||
$(BUILD_PFX)libvpx_g.a: $(LIBVPX_OBJS)
|
||||
|
||||
SO_VERSION_MAJOR := 5
|
||||
SO_VERSION_MINOR := 0
|
||||
SO_VERSION_PATCH := 0
|
||||
ifeq ($(filter darwin%,$(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 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)
|
||||
SHARED_LIB_SUF := .so
|
||||
EXPORT_FILE := libvpx.ver
|
||||
LIBVPX_SO_SYMLINKS := $(addprefix $(LIBSUBDIR)/, \
|
||||
libvpx.so libvpx.so.$(SO_VERSION_MAJOR) \
|
||||
libvpx.so.$(SO_VERSION_MAJOR).$(SO_VERSION_MINOR))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
LIBS-$(CONFIG_SHARED) += $(BUILD_PFX)$(LIBVPX_SO)\
|
||||
$(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): extralibs += -lm
|
||||
$(BUILD_PFX)$(LIBVPX_SO): SONAME = libvpx.so.$(SO_VERSION_MAJOR)
|
||||
$(BUILD_PFX)$(LIBVPX_SO): EXPORTS_FILE = $(EXPORT_FILE)
|
||||
|
||||
libvpx.ver: $(call enabled,CODEC_EXPORTS)
|
||||
@echo " [CREATE] $@"
|
||||
$(qexec)echo "{ global:" > $@
|
||||
$(qexec)for f in $?; do awk '{print $$2";"}' < $$f >>$@; done
|
||||
$(qexec)echo "local: *; };" >> $@
|
||||
CLEAN-OBJS += libvpx.ver
|
||||
|
||||
libvpx.syms: $(call enabled,CODEC_EXPORTS)
|
||||
@echo " [CREATE] $@"
|
||||
$(qexec)awk '{print "_"$$2}' $^ >$@
|
||||
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
|
||||
$(1): $(2)
|
||||
@echo " [LN] $(2) $$@"
|
||||
$(qexec)mkdir -p $$(dir $$@)
|
||||
$(qexec)ln -sf $(2) $$@
|
||||
endef
|
||||
|
||||
$(eval $(call libvpx_symlink_template,\
|
||||
$(addprefix $(BUILD_PFX),$(notdir $(LIBVPX_SO_SYMLINKS))),\
|
||||
$(BUILD_PFX)$(LIBVPX_SO)))
|
||||
$(eval $(call libvpx_symlink_template,\
|
||||
$(addprefix $(DIST_DIR)/,$(LIBVPX_SO_SYMLINKS)),\
|
||||
$(LIBVPX_SO)))
|
||||
|
||||
|
||||
INSTALL-LIBS-$(CONFIG_SHARED) += $(LIBVPX_SO_SYMLINKS)
|
||||
INSTALL-LIBS-$(CONFIG_SHARED) += $(LIBSUBDIR)/$(LIBVPX_SO)
|
||||
INSTALL-LIBS-$(CONFIG_SHARED) += $(if $(LIBVPX_SO_IMPLIB),$(LIBSUBDIR)/$(LIBVPX_SO_IMPLIB))
|
||||
|
||||
|
||||
LIBS-yes += vpx.pc
|
||||
vpx.pc: config.mk libs.mk
|
||||
@echo " [CREATE] $@"
|
||||
$(qexec)echo '# pkg-config file from libvpx $(VERSION_STRING)' > $@
|
||||
$(qexec)echo 'prefix=$(PREFIX)' >> $@
|
||||
$(qexec)echo 'exec_prefix=$${prefix}' >> $@
|
||||
$(qexec)echo 'libdir=$${prefix}/$(LIBSUBDIR)' >> $@
|
||||
$(qexec)echo 'includedir=$${prefix}/include' >> $@
|
||||
$(qexec)echo '' >> $@
|
||||
$(qexec)echo 'Name: vpx' >> $@
|
||||
$(qexec)echo 'Description: WebM Project VPx codec implementation' >> $@
|
||||
$(qexec)echo 'Version: $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)' >> $@
|
||||
$(qexec)echo 'Requires:' >> $@
|
||||
$(qexec)echo 'Conflicts:' >> $@
|
||||
$(qexec)echo 'Libs: -L$${libdir} -lvpx -lm' >> $@
|
||||
ifeq ($(HAVE_PTHREAD_H),yes)
|
||||
$(qexec)echo 'Libs.private: -lm -lpthread' >> $@
|
||||
else
|
||||
$(qexec)echo 'Libs.private: -lm' >> $@
|
||||
endif
|
||||
$(qexec)echo 'Cflags: -I$${includedir}' >> $@
|
||||
INSTALL-LIBS-yes += $(LIBSUBDIR)/pkgconfig/vpx.pc
|
||||
INSTALL_MAPS += $(LIBSUBDIR)/pkgconfig/%.pc %.pc
|
||||
CLEAN-OBJS += vpx.pc
|
||||
endif
|
||||
|
||||
#
|
||||
# Rule to make assembler configuration file from C configuration file
|
||||
#
|
||||
ifeq ($(ARCH_X86)$(ARCH_X86_64),yes)
|
||||
# YASM
|
||||
$(BUILD_PFX)vpx_config.asm: $(BUILD_PFX)vpx_config.h
|
||||
@echo " [CREATE] $@"
|
||||
@egrep "#define [A-Z0-9_]+ [01]" $< \
|
||||
| awk '{print $$2 " equ " $$3}' > $@
|
||||
else
|
||||
ADS2GAS=$(if $(filter yes,$(CONFIG_GCC)),| $(ASM_CONVERSION))
|
||||
$(BUILD_PFX)vpx_config.asm: $(BUILD_PFX)vpx_config.h
|
||||
@echo " [CREATE] $@"
|
||||
@egrep "#define [A-Z0-9_]+ [01]" $< \
|
||||
| awk '{print $$2 " EQU " $$3}' $(ADS2GAS) > $@
|
||||
@echo " END" $(ADS2GAS) >> $@
|
||||
CLEAN-OBJS += $(BUILD_PFX)vpx_config.asm
|
||||
endif
|
||||
|
||||
#
|
||||
# Add assembler dependencies for configuration.
|
||||
#
|
||||
$(filter %.S.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)
|
||||
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
|
||||
##
|
||||
ifeq ($(CONFIG_UNIT_TESTS),yes)
|
||||
LIBVPX_TEST_DATA_PATH ?= .
|
||||
|
||||
include $(SRC_PATH_BARE)/test/test.mk
|
||||
LIBVPX_TEST_SRCS=$(addprefix test/,$(call enabled,LIBVPX_TEST_SRCS))
|
||||
LIBVPX_TEST_BIN=./test_libvpx$(EXE_SFX)
|
||||
LIBVPX_TEST_DATA=$(addprefix $(LIBVPX_TEST_DATA_PATH)/,\
|
||||
$(call enabled,LIBVPX_TEST_DATA))
|
||||
libvpx_test_data_url=https://storage.googleapis.com/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:
|
||||
@echo " [CREATE] $@"
|
||||
@echo $(LIBVPX_TEST_SRCS) | xargs -n1 echo | LC_ALL=C sort -u > $@
|
||||
CLEAN-OBJS += libvpx_test_srcs.txt
|
||||
|
||||
$(LIBVPX_TEST_DATA): $(SRC_PATH_BARE)/test/test-data.sha1
|
||||
@echo " [DOWNLOAD] $@"
|
||||
# Attempt to download the file using curl, retrying once if it fails for a
|
||||
# partial file (18).
|
||||
$(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)
|
||||
$(qexec)[ -x "$$(which sha1sum)" ] && sha1sum=sha1sum;\
|
||||
[ -x "$$(which shasum)" ] && sha1sum=shasum;\
|
||||
[ -x "$$(which sha1)" ] && sha1sum=sha1;\
|
||||
if [ -n "$${sha1sum}" ]; then\
|
||||
set -e;\
|
||||
echo "Checking test data:";\
|
||||
for f in $(call enabled,LIBVPX_TEST_DATA); do\
|
||||
grep $$f $(SRC_PATH_BARE)/test/test-data.sha1 |\
|
||||
(cd $(LIBVPX_TEST_DATA_PATH); $${sha1sum} -c);\
|
||||
done; \
|
||||
else\
|
||||
echo "Skipping test data integrity check, sha1sum not found.";\
|
||||
fi
|
||||
|
||||
ifeq ($(CONFIG_EXTERNAL_BUILD),yes)
|
||||
ifeq ($(CONFIG_MSVS),yes)
|
||||
|
||||
gtest.$(VCPROJ_SFX): $(SRC_PATH_BARE)/third_party/googletest/src/src/gtest-all.cc
|
||||
@echo " [CREATE] $@"
|
||||
$(qexec)$(GEN_VCPROJ) \
|
||||
--lib \
|
||||
--target=$(TOOLCHAIN) \
|
||||
$(if $(CONFIG_STATIC_MSVCRT),--static-crt) \
|
||||
--name=gtest \
|
||||
--proj-guid=EC00E1EC-AF68-4D92-A255-181690D1C9B1 \
|
||||
--ver=$(CONFIG_VS_VERSION) \
|
||||
--src-path-bare="$(SRC_PATH_BARE)" \
|
||||
-D_VARIADIC_MAX=10 \
|
||||
--out=gtest.$(VCPROJ_SFX) $(SRC_PATH_BARE)/third_party/googletest/src/src/gtest-all.cc \
|
||||
-I. -I"$(SRC_PATH_BARE)/third_party/googletest/src/include" -I"$(SRC_PATH_BARE)/third_party/googletest/src"
|
||||
|
||||
PROJECTS-$(CONFIG_MSVS) += gtest.$(VCPROJ_SFX)
|
||||
|
||||
test_libvpx.$(VCPROJ_SFX): $(LIBVPX_TEST_SRCS) vpx.$(VCPROJ_SFX) gtest.$(VCPROJ_SFX)
|
||||
@echo " [CREATE] $@"
|
||||
$(qexec)$(GEN_VCPROJ) \
|
||||
--exe \
|
||||
--target=$(TOOLCHAIN) \
|
||||
--name=test_libvpx \
|
||||
-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" \
|
||||
$(if $(CONFIG_WEBM_IO),-I"$(SRC_PATH_BARE)/third_party/libwebm") \
|
||||
-L. -l$(CODEC_LIB) -l$(GTEST_LIB) $^
|
||||
|
||||
PROJECTS-$(CONFIG_MSVS) += test_libvpx.$(VCPROJ_SFX)
|
||||
|
||||
LIBVPX_TEST_BIN := $(addprefix $(TGT_OS:win64=x64)/Release/,$(notdir $(LIBVPX_TEST_BIN)))
|
||||
|
||||
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
|
||||
else
|
||||
|
||||
include $(SRC_PATH_BARE)/third_party/googletest/gtest.mk
|
||||
GTEST_SRCS := $(addprefix third_party/googletest/src/,$(call enabled,GTEST_SRCS))
|
||||
GTEST_OBJS=$(call objs,$(GTEST_SRCS))
|
||||
ifeq ($(filter win%,$(TGT_OS)),$(TGT_OS))
|
||||
# Disabling pthreads globally will cause issues on darwin and possibly elsewhere
|
||||
$(GTEST_OBJS) $(GTEST_OBJS:.o=.d): CXXFLAGS += -DGTEST_HAS_PTHREAD=0
|
||||
endif
|
||||
GTEST_INCLUDES := -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 += $(GTEST_INCLUDES)
|
||||
OBJS-yes += $(GTEST_OBJS)
|
||||
LIBS-yes += $(BUILD_PFX)libgtest.a $(BUILD_PFX)libgtest_g.a
|
||||
$(BUILD_PFX)libgtest_g.a: $(GTEST_OBJS)
|
||||
|
||||
LIBVPX_TEST_OBJS=$(sort $(call objs,$(LIBVPX_TEST_SRCS)))
|
||||
$(LIBVPX_TEST_OBJS) $(LIBVPX_TEST_OBJS:.o=.d): CXXFLAGS += $(GTEST_INCLUDES)
|
||||
OBJS-yes += $(LIBVPX_TEST_OBJS)
|
||||
BINS-yes += $(LIBVPX_TEST_BIN)
|
||||
|
||||
CODEC_LIB=$(if $(CONFIG_DEBUG_LIBS),vpx_g,vpx)
|
||||
CODEC_LIB_SUF=$(if $(CONFIG_SHARED),$(SHARED_LIB_SUF),.a)
|
||||
TEST_LIBS := lib$(CODEC_LIB)$(CODEC_LIB_SUF) libgtest.a
|
||||
$(LIBVPX_TEST_BIN): $(TEST_LIBS)
|
||||
$(eval $(call linkerxx_template,$(LIBVPX_TEST_BIN), \
|
||||
$(LIBVPX_TEST_OBJS) \
|
||||
-L. -lvpx -lgtest $(extralibs) -lm))
|
||||
|
||||
ifneq ($(strip $(TEST_INTRA_PRED_SPEED_OBJS)),)
|
||||
$(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-SRCS-$(CONFIG_CODEC_SRCS) += $(patsubst $(SRC_PATH_BARE)/%,%,\
|
||||
$(shell find $(SRC_PATH_BARE)/third_party/googletest -type f))
|
||||
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(LIBVPX_TEST_SRCS)
|
||||
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(TEST_INTRA_PRED_SPEED_SRCS)
|
||||
|
||||
define test_shard_template
|
||||
test:: test_shard.$(1)
|
||||
test-no-data-check:: test_shard_ndc.$(1)
|
||||
test_shard.$(1) test_shard_ndc.$(1): $(LIBVPX_TEST_BIN)
|
||||
@set -e; \
|
||||
export GTEST_SHARD_INDEX=$(1); \
|
||||
export GTEST_TOTAL_SHARDS=$(2); \
|
||||
$(LIBVPX_TEST_BIN)
|
||||
test_shard.$(1): testdata
|
||||
.PHONY: test_shard.$(1)
|
||||
endef
|
||||
|
||||
NUM_SHARDS := 10
|
||||
SHARDS := 0 1 2 3 4 5 6 7 8 9
|
||||
$(foreach s,$(SHARDS),$(eval $(call test_shard_template,$(s),$(NUM_SHARDS))))
|
||||
|
||||
endif
|
||||
|
||||
##
|
||||
## documentation directives
|
||||
##
|
||||
CLEAN-OBJS += libs.doxy
|
||||
DOCS-yes += libs.doxy
|
||||
libs.doxy: $(CODEC_DOC_SRCS)
|
||||
@echo " [CREATE] $@"
|
||||
@rm -f $@
|
||||
@echo "INPUT += $^" >> $@
|
||||
@echo "INCLUDE_PATH += ." >> $@;
|
||||
@echo "ENABLED_SECTIONS += $(sort $(CODEC_DOC_SECTIONS))" >> $@
|
||||
|
||||
## Generate rtcd.h for all objects
|
||||
ifeq ($(CONFIG_DEPENDENCY_TRACKING),yes)
|
||||
$(OBJS-yes:.o=.d): $(RTCD)
|
||||
else
|
||||
$(OBJS-yes): $(RTCD)
|
||||
endif
|
||||
|
||||
## Update the global src list
|
||||
SRCS += $(CODEC_SRCS) $(LIBVPX_TEST_SRCS) $(GTEST_SRCS)
|
||||
|
||||
##
|
||||
## vpxdec/vpxenc tests.
|
||||
##
|
||||
ifeq ($(CONFIG_UNIT_TESTS),yes)
|
||||
TEST_BIN_PATH = .
|
||||
ifeq ($(CONFIG_MSVS),yes)
|
||||
# MSVC will build both Debug and Release configurations of tools in a
|
||||
# sub directory named for the current target. Assume the user wants to
|
||||
# run the Release tools, and assign TEST_BIN_PATH accordingly.
|
||||
# TODO(tomfinegan): Is this adequate for ARM?
|
||||
# TODO(tomfinegan): Support running the debug versions of tools?
|
||||
TEST_BIN_PATH := $(addsuffix /$(TGT_OS:win64=x64)/Release, $(TEST_BIN_PATH))
|
||||
endif
|
||||
utiltest utiltest-no-data-check:
|
||||
$(qexec)$(SRC_PATH_BARE)/test/vpxdec.sh \
|
||||
--test-data-path $(LIBVPX_TEST_DATA_PATH) \
|
||||
--bin-path $(TEST_BIN_PATH)
|
||||
$(qexec)$(SRC_PATH_BARE)/test/vpxenc.sh \
|
||||
--test-data-path $(LIBVPX_TEST_DATA_PATH) \
|
||||
--bin-path $(TEST_BIN_PATH)
|
||||
utiltest: testdata
|
||||
else
|
||||
utiltest utiltest-no-data-check:
|
||||
@echo Unit tests must be enabled to make the utiltest target.
|
||||
endif
|
||||
|
||||
##
|
||||
## Example tests.
|
||||
##
|
||||
ifeq ($(CONFIG_UNIT_TESTS),yes)
|
||||
# All non-MSVC targets output example targets in a sub dir named examples.
|
||||
EXAMPLES_BIN_PATH = examples
|
||||
ifeq ($(CONFIG_MSVS),yes)
|
||||
# MSVC will build both Debug and Release configurations of the examples in a
|
||||
# sub directory named for the current target. Assume the user wants to
|
||||
# run the Release tools, and assign EXAMPLES_BIN_PATH accordingly.
|
||||
# TODO(tomfinegan): Is this adequate for ARM?
|
||||
# TODO(tomfinegan): Support running the debug versions of tools?
|
||||
EXAMPLES_BIN_PATH := $(TGT_OS:win64=x64)/Release
|
||||
endif
|
||||
exampletest exampletest-no-data-check: examples
|
||||
$(qexec)$(SRC_PATH_BARE)/test/examples.sh \
|
||||
--test-data-path $(LIBVPX_TEST_DATA_PATH) \
|
||||
--bin-path $(EXAMPLES_BIN_PATH)
|
||||
exampletest: testdata
|
||||
else
|
||||
exampletest exampletest-no-data-check:
|
||||
@echo Unit tests must be enabled to make the exampletest target.
|
||||
endif
|
368
loopfilter/alloccommon.c
Normal file
368
loopfilter/alloccommon.c
Normal file
@ -0,0 +1,368 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "./aom_config.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
|
||||
#include "av1/common/alloccommon.h"
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/entropymode.h"
|
||||
#include "av1/common/entropymv.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
|
||||
int av1_get_MBs(int width, int height) {
|
||||
const int aligned_width = ALIGN_POWER_OF_TWO(width, 3);
|
||||
const int aligned_height = ALIGN_POWER_OF_TWO(height, 3);
|
||||
const int mi_cols = aligned_width >> MI_SIZE_LOG2;
|
||||
const int mi_rows = aligned_height >> MI_SIZE_LOG2;
|
||||
|
||||
const int mb_cols = (mi_cols + 2) >> 2;
|
||||
const int mb_rows = (mi_rows + 2) >> 2;
|
||||
return mb_rows * mb_cols;
|
||||
}
|
||||
|
||||
void av1_set_mb_mi(AV1_COMMON *cm, int width, int height) {
|
||||
// Ensure that the decoded width and height are both multiples of
|
||||
// 8 luma pixels (note: this may only be a multiple of 4 chroma pixels if
|
||||
// subsampling is used).
|
||||
// This simplifies the implementation of various experiments,
|
||||
// eg. cdef, which operates on units of 8x8 luma pixels.
|
||||
const int aligned_width = ALIGN_POWER_OF_TWO(width, 3);
|
||||
const int aligned_height = ALIGN_POWER_OF_TWO(height, 3);
|
||||
|
||||
cm->mi_cols = aligned_width >> MI_SIZE_LOG2;
|
||||
cm->mi_rows = aligned_height >> MI_SIZE_LOG2;
|
||||
cm->mi_stride = calc_mi_size(cm->mi_cols);
|
||||
|
||||
cm->mb_cols = (cm->mi_cols + 2) >> 2;
|
||||
cm->mb_rows = (cm->mi_rows + 2) >> 2;
|
||||
cm->MBs = cm->mb_rows * cm->mb_cols;
|
||||
}
|
||||
|
||||
#if !CONFIG_SEGMENT_PRED_LAST
|
||||
static int alloc_seg_map(AV1_COMMON *cm, int rows, int cols) {
|
||||
int i;
|
||||
int seg_map_size = rows * cols;
|
||||
|
||||
for (i = 0; i < NUM_PING_PONG_BUFFERS; ++i) {
|
||||
cm->seg_map_array[i] = (uint8_t *)aom_calloc(seg_map_size, 1);
|
||||
if (cm->seg_map_array[i] == NULL) return 1;
|
||||
}
|
||||
cm->seg_map_alloc_size = seg_map_size;
|
||||
|
||||
// Init the index.
|
||||
cm->seg_map_idx = 0;
|
||||
cm->prev_seg_map_idx = 1;
|
||||
|
||||
cm->current_frame_seg_map = cm->seg_map_array[cm->seg_map_idx];
|
||||
if (!cm->frame_parallel_decode)
|
||||
cm->last_frame_seg_map = cm->seg_map_array[cm->prev_seg_map_idx];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_seg_map(AV1_COMMON *cm) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_PING_PONG_BUFFERS; ++i) {
|
||||
aom_free(cm->seg_map_array[i]);
|
||||
cm->seg_map_array[i] = NULL;
|
||||
}
|
||||
|
||||
cm->current_frame_seg_map = NULL;
|
||||
|
||||
if (!cm->frame_parallel_decode) {
|
||||
cm->last_frame_seg_map = NULL;
|
||||
}
|
||||
cm->seg_map_alloc_size = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void av1_free_ref_frame_buffers(BufferPool *pool) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FRAME_BUFFERS; ++i) {
|
||||
if (pool->frame_bufs[i].ref_count > 0 &&
|
||||
pool->frame_bufs[i].raw_frame_buffer.data != NULL) {
|
||||
pool->release_fb_cb(pool->cb_priv, &pool->frame_bufs[i].raw_frame_buffer);
|
||||
pool->frame_bufs[i].ref_count = 0;
|
||||
}
|
||||
aom_free(pool->frame_bufs[i].mvs);
|
||||
pool->frame_bufs[i].mvs = NULL;
|
||||
#if CONFIG_SEGMENT_PRED_LAST
|
||||
aom_free(pool->frame_bufs[i].seg_map);
|
||||
pool->frame_bufs[i].seg_map = NULL;
|
||||
#endif
|
||||
aom_free_frame_buffer(&pool->frame_bufs[i].buf);
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_LOOP_RESTORATION
|
||||
// Assumes cm->rst_info[p].restoration_unit_size is already initialized
|
||||
void av1_alloc_restoration_buffers(AV1_COMMON *cm) {
|
||||
const int num_planes = av1_num_planes(cm);
|
||||
for (int p = 0; p < num_planes; ++p)
|
||||
av1_alloc_restoration_struct(cm, &cm->rst_info[p], p > 0);
|
||||
aom_free(cm->rst_tmpbuf);
|
||||
CHECK_MEM_ERROR(cm, cm->rst_tmpbuf,
|
||||
(int32_t *)aom_memalign(16, RESTORATION_TMPBUF_SIZE));
|
||||
|
||||
#if CONFIG_STRIPED_LOOP_RESTORATION
|
||||
// For striped loop restoration, we divide each row of tiles into "stripes",
|
||||
// of height 64 luma pixels but with an offset by RESTORATION_TILE_OFFSET
|
||||
// luma pixels to match the output from CDEF. We will need to store 2 *
|
||||
// RESTORATION_CTX_VERT lines of data for each stripe, and also need to be
|
||||
// able to quickly answer the question "Where is the <n>'th stripe for tile
|
||||
// row <m>?" To make that efficient, we generate the rst_last_stripe array.
|
||||
int num_stripes = 0;
|
||||
for (int i = 0; i < cm->tile_rows; ++i) {
|
||||
#if CONFIG_MAX_TILE
|
||||
TileInfo tile_info;
|
||||
av1_tile_set_row(&tile_info, cm, i);
|
||||
const int mi_h = tile_info.mi_row_end - tile_info.mi_row_start;
|
||||
#else
|
||||
const int mi_h = ((i + 1) < cm->tile_rows)
|
||||
? cm->tile_height
|
||||
: (cm->mi_rows - i * cm->tile_height);
|
||||
#endif
|
||||
const int ext_h = RESTORATION_TILE_OFFSET + (mi_h << MI_SIZE_LOG2);
|
||||
const int tile_stripes = (ext_h + 63) / 64;
|
||||
num_stripes += tile_stripes;
|
||||
cm->rst_end_stripe[i] = num_stripes;
|
||||
}
|
||||
|
||||
// Now we need to allocate enough space to store the line buffers for the
|
||||
// stripes
|
||||
#if CONFIG_HORZONLY_FRAME_SUPERRES
|
||||
const int frame_w = cm->superres_upscaled_width;
|
||||
#else
|
||||
const int frame_w = cm->width;
|
||||
#endif // CONFIG_HORZONLY_FRAME_SUPERRES
|
||||
const int use_highbd = cm->use_highbitdepth ? 1 : 0;
|
||||
|
||||
for (int p = 0; p < num_planes; ++p) {
|
||||
const int is_uv = p > 0;
|
||||
const int ss_x = is_uv && cm->subsampling_x;
|
||||
const int plane_w = ((frame_w + ss_x) >> ss_x) + 2 * RESTORATION_EXTRA_HORZ;
|
||||
const int stride = ALIGN_POWER_OF_TWO(plane_w, 5);
|
||||
const int buf_size = num_stripes * stride * RESTORATION_CTX_VERT
|
||||
<< use_highbd;
|
||||
RestorationStripeBoundaries *boundaries = &cm->rst_info[p].boundaries;
|
||||
aom_free(boundaries->stripe_boundary_above);
|
||||
aom_free(boundaries->stripe_boundary_below);
|
||||
|
||||
CHECK_MEM_ERROR(cm, boundaries->stripe_boundary_above,
|
||||
(uint8_t *)aom_memalign(32, buf_size));
|
||||
CHECK_MEM_ERROR(cm, boundaries->stripe_boundary_below,
|
||||
(uint8_t *)aom_memalign(32, buf_size));
|
||||
|
||||
boundaries->stripe_boundary_stride = stride;
|
||||
}
|
||||
#endif // CONFIG_STRIPED_LOOP_RESTORATION
|
||||
}
|
||||
|
||||
void av1_free_restoration_buffers(AV1_COMMON *cm) {
|
||||
const int num_planes = av1_num_planes(cm);
|
||||
int p;
|
||||
for (p = 0; p < num_planes; ++p)
|
||||
av1_free_restoration_struct(&cm->rst_info[p]);
|
||||
aom_free(cm->rst_tmpbuf);
|
||||
cm->rst_tmpbuf = NULL;
|
||||
#if CONFIG_STRIPED_LOOP_RESTORATION
|
||||
for (p = 0; p < num_planes; ++p) {
|
||||
RestorationStripeBoundaries *boundaries = &cm->rst_info[p].boundaries;
|
||||
aom_free(boundaries->stripe_boundary_above);
|
||||
aom_free(boundaries->stripe_boundary_below);
|
||||
boundaries->stripe_boundary_above = NULL;
|
||||
boundaries->stripe_boundary_below = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // CONFIG_LOOP_RESTORATION
|
||||
|
||||
void av1_free_context_buffers(AV1_COMMON *cm) {
|
||||
const int num_planes = av1_num_planes(cm);
|
||||
int i;
|
||||
cm->free_mi(cm);
|
||||
|
||||
aom_free(cm->boundary_info);
|
||||
cm->boundary_info_alloc_size = 0;
|
||||
cm->boundary_info = NULL;
|
||||
|
||||
#if !CONFIG_SEGMENT_PRED_LAST
|
||||
free_seg_map(cm);
|
||||
#endif
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
aom_free(cm->above_context[i]);
|
||||
cm->above_context[i] = NULL;
|
||||
}
|
||||
aom_free(cm->above_seg_context);
|
||||
cm->above_seg_context = NULL;
|
||||
cm->above_context_alloc_cols = 0;
|
||||
aom_free(cm->above_txfm_context);
|
||||
cm->above_txfm_context = NULL;
|
||||
|
||||
for (i = 0; i < num_planes; ++i) {
|
||||
aom_free(cm->top_txfm_context[i]);
|
||||
cm->top_txfm_context[i] = NULL;
|
||||
}
|
||||
|
||||
aom_free(cm->lf.lfm);
|
||||
cm->lf.lfm = NULL;
|
||||
cm->lf.lfm_num = 0;
|
||||
cm->lf.lfm_stride = 0;
|
||||
cm->lf.curr_frame_offset = 0;
|
||||
|
||||
aom_free(cm->lf.neighbor);
|
||||
cm->lf.neighbor = NULL;
|
||||
cm->lf.neighbor_width = 0;
|
||||
cm->lf.neighbor_height = 0;
|
||||
}
|
||||
|
||||
static int alloc_loop_filter(AV1_COMMON *cm) {
|
||||
aom_free(cm->lf.lfm);
|
||||
// Each lfm holds bit masks for all the 4x4 blocks in a max
|
||||
// 64x64 (128x128 for ext_partitions) region. The stride
|
||||
// and rows are rounded up / truncated to a multiple of 16
|
||||
// (32 for ext_partition).
|
||||
cm->lf.lfm_stride = (cm->mi_cols + (MAX_MIB_SIZE - 1)) >> MAX_MIB_SIZE_LOG2;
|
||||
cm->lf.lfm_num = ((cm->mi_rows + (MAX_MIB_SIZE - 1)) >> MAX_MIB_SIZE_LOG2) *
|
||||
cm->lf.lfm_stride;
|
||||
cm->lf.curr_frame_offset = 0xbeef;
|
||||
cm->lf.lfm = (LpfMask *)aom_calloc(cm->lf.lfm_num, sizeof(*cm->lf.lfm));
|
||||
if (!cm->lf.lfm) return 1;
|
||||
|
||||
// Neighbor information
|
||||
aom_free(cm->lf.neighbor);
|
||||
cm->lf.neighbor_width = cm->mi_cols + (MAX_MIB_SIZE - 1);
|
||||
cm->lf.neighbor_height = cm->mi_rows + (MAX_MIB_SIZE - 1);
|
||||
// Total 6 neighbor info, each has width and height info, respectively.
|
||||
// ------------------------------------------------------------
|
||||
// top zone left zone
|
||||
// neighbor_width neighbor_height
|
||||
// Y tx_size |--------------|---------------|
|
||||
// UV tx_size |--------------|---------------|
|
||||
// Y level |--------------|---------------|
|
||||
// U level |--------------|---------------|
|
||||
// V level |--------------|---------------|
|
||||
// skip |--------------|---------------|
|
||||
// ------------------------------------------------------------
|
||||
cm->lf.neighbor = (uint8_t *)aom_calloc(
|
||||
6 * (cm->lf.neighbor_width + cm->lf.neighbor_height), sizeof(uint8_t));
|
||||
if (!cm->lf.neighbor) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int av1_alloc_context_buffers(AV1_COMMON *cm, int width, int height) {
|
||||
const int num_planes = av1_num_planes(cm);
|
||||
int new_mi_size;
|
||||
|
||||
av1_set_mb_mi(cm, width, height);
|
||||
new_mi_size = cm->mi_stride * calc_mi_size(cm->mi_rows);
|
||||
if (cm->mi_alloc_size < new_mi_size) {
|
||||
cm->free_mi(cm);
|
||||
if (cm->alloc_mi(cm, new_mi_size)) goto fail;
|
||||
}
|
||||
|
||||
const int new_boundary_info_alloc_size = cm->mi_rows * cm->mi_stride;
|
||||
if (cm->boundary_info_alloc_size < new_boundary_info_alloc_size) {
|
||||
aom_free(cm->boundary_info);
|
||||
cm->boundary_info = (BOUNDARY_TYPE *)aom_calloc(
|
||||
new_boundary_info_alloc_size, sizeof(BOUNDARY_TYPE));
|
||||
cm->boundary_info_alloc_size = 0;
|
||||
if (!cm->boundary_info) goto fail;
|
||||
cm->boundary_info_alloc_size = new_boundary_info_alloc_size;
|
||||
}
|
||||
|
||||
#if !CONFIG_SEGMENT_PRED_LAST
|
||||
if (cm->seg_map_alloc_size < cm->mi_rows * cm->mi_cols) {
|
||||
// Create the segmentation map structure and set to 0.
|
||||
free_seg_map(cm);
|
||||
if (alloc_seg_map(cm, cm->mi_rows, cm->mi_cols)) goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cm->above_context_alloc_cols < cm->mi_cols) {
|
||||
// TODO(geza.lore): These are bigger than they need to be.
|
||||
// cm->tile_width would be enough but it complicates indexing a
|
||||
// little elsewhere.
|
||||
const int aligned_mi_cols =
|
||||
ALIGN_POWER_OF_TWO(cm->mi_cols, MAX_MIB_SIZE_LOG2);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
aom_free(cm->above_context[i]);
|
||||
cm->above_context[i] = (ENTROPY_CONTEXT *)aom_calloc(
|
||||
aligned_mi_cols << (MI_SIZE_LOG2 - tx_size_wide_log2[0]),
|
||||
sizeof(*cm->above_context[0]));
|
||||
if (!cm->above_context[i]) goto fail;
|
||||
}
|
||||
|
||||
aom_free(cm->above_seg_context);
|
||||
cm->above_seg_context = (PARTITION_CONTEXT *)aom_calloc(
|
||||
aligned_mi_cols, sizeof(*cm->above_seg_context));
|
||||
if (!cm->above_seg_context) goto fail;
|
||||
|
||||
aom_free(cm->above_txfm_context);
|
||||
cm->above_txfm_context = (TXFM_CONTEXT *)aom_calloc(
|
||||
aligned_mi_cols << TX_UNIT_WIDE_LOG2, sizeof(*cm->above_txfm_context));
|
||||
if (!cm->above_txfm_context) goto fail;
|
||||
|
||||
for (i = 0; i < num_planes; ++i) {
|
||||
aom_free(cm->top_txfm_context[i]);
|
||||
cm->top_txfm_context[i] =
|
||||
(TXFM_CONTEXT *)aom_calloc(aligned_mi_cols << TX_UNIT_WIDE_LOG2,
|
||||
sizeof(*cm->top_txfm_context[0]));
|
||||
if (!cm->top_txfm_context[i]) goto fail;
|
||||
}
|
||||
|
||||
cm->above_context_alloc_cols = aligned_mi_cols;
|
||||
}
|
||||
|
||||
if (alloc_loop_filter(cm)) goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
// clear the mi_* values to force a realloc on resync
|
||||
av1_set_mb_mi(cm, 0, 0);
|
||||
av1_free_context_buffers(cm);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void av1_remove_common(AV1_COMMON *cm) {
|
||||
av1_free_context_buffers(cm);
|
||||
|
||||
aom_free(cm->fc);
|
||||
cm->fc = NULL;
|
||||
aom_free(cm->frame_contexts);
|
||||
cm->frame_contexts = NULL;
|
||||
}
|
||||
|
||||
void av1_init_context_buffers(AV1_COMMON *cm) {
|
||||
cm->setup_mi(cm);
|
||||
#if !CONFIG_SEGMENT_PRED_LAST
|
||||
if (cm->last_frame_seg_map && !cm->frame_parallel_decode)
|
||||
memset(cm->last_frame_seg_map, 0, cm->mi_rows * cm->mi_cols);
|
||||
#endif
|
||||
}
|
||||
#if !CONFIG_SEGMENT_PRED_LAST
|
||||
void av1_swap_current_and_last_seg_map(AV1_COMMON *cm) {
|
||||
// Swap indices.
|
||||
const int tmp = cm->seg_map_idx;
|
||||
cm->seg_map_idx = cm->prev_seg_map_idx;
|
||||
cm->prev_seg_map_idx = tmp;
|
||||
|
||||
cm->current_frame_seg_map = cm->seg_map_array[cm->seg_map_idx];
|
||||
cm->last_frame_seg_map = cm->seg_map_array[cm->prev_seg_map_idx];
|
||||
}
|
||||
#endif
|
4244
loopfilter/av1_loopfilter.c
Normal file
4244
loopfilter/av1_loopfilter.c
Normal file
File diff suppressed because it is too large
Load Diff
213
loopfilter/av1_loopfilter.h
Normal file
213
loopfilter/av1_loopfilter.h
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AV1_COMMON_LOOPFILTER_H_
|
||||
#define AV1_COMMON_LOOPFILTER_H_
|
||||
|
||||
#include "aom_ports/mem.h"
|
||||
#include "./aom_config.h"
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/seg_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_LOOP_FILTER 63
|
||||
#define MAX_SHARPNESS 7
|
||||
|
||||
#define SIMD_WIDTH 16
|
||||
|
||||
#define MAX_MODE_LF_DELTAS 2
|
||||
|
||||
enum lf_path {
|
||||
LF_PATH_420,
|
||||
LF_PATH_444,
|
||||
LF_PATH_SLOW,
|
||||
};
|
||||
|
||||
typedef struct { uint64_t bits[4]; } FilterMaskY;
|
||||
|
||||
typedef uint64_t FilterMaskUV;
|
||||
|
||||
// This structure holds bit masks for all 8x8 blocks in a 64x64 region.
|
||||
// Each 1 bit represents a position in which we want to apply the loop filter.
|
||||
// Left_ entries refer to whether we apply a filter on the border to the
|
||||
// left of the block. Above_ entries refer to whether or not to apply a
|
||||
// filter on the above border. Int_ entries refer to whether or not to
|
||||
// apply borders on the 4x4 edges within the 8x8 block that each bit
|
||||
// represents.
|
||||
// Since each transform is accompanied by a potentially different type of
|
||||
// loop filter there is a different entry in the array for each transform size.
|
||||
typedef struct {
|
||||
FilterMaskY left_y[TX_SIZES];
|
||||
FilterMaskY above_y[TX_SIZES];
|
||||
FilterMaskUV left_u[TX_SIZES];
|
||||
FilterMaskUV above_u[TX_SIZES];
|
||||
FilterMaskUV left_v[TX_SIZES];
|
||||
FilterMaskUV above_v[TX_SIZES];
|
||||
|
||||
// Y plane vertical edge and horizontal edge filter level
|
||||
uint8_t lfl_y_hor[MAX_MIB_SIZE / 2][MAX_MIB_SIZE / 2];
|
||||
uint8_t lfl_y_ver[MAX_MIB_SIZE / 2][MAX_MIB_SIZE / 2];
|
||||
|
||||
// UV plane vertical edge and horizontal edge shares the same level
|
||||
uint8_t lfl_u[MAX_MIB_SIZE / 4][MAX_MIB_SIZE / 4];
|
||||
uint8_t lfl_v[MAX_MIB_SIZE / 4][MAX_MIB_SIZE / 4];
|
||||
} LoopFilterMask;
|
||||
|
||||
// Loopfilter bit mask per super block
|
||||
#define LOOP_FILTER_MASK_NUM 4
|
||||
typedef struct {
|
||||
LoopFilterMask lfm[LOOP_FILTER_MASK_NUM];
|
||||
int is_setup;
|
||||
} LpfMask;
|
||||
|
||||
struct loopfilter {
|
||||
LpfMask *lfm;
|
||||
// Neighbor block information for loopfilter bit mask setup
|
||||
uint8_t *neighbor;
|
||||
size_t lfm_num;
|
||||
int lfm_stride;
|
||||
unsigned int curr_frame_offset;
|
||||
unsigned int neighbor_width;
|
||||
unsigned int neighbor_height;
|
||||
#if CONFIG_LOOPFILTER_LEVEL
|
||||
int filter_level[2];
|
||||
int filter_level_u;
|
||||
int filter_level_v;
|
||||
#else
|
||||
int filter_level;
|
||||
#endif
|
||||
|
||||
int sharpness_level;
|
||||
int last_sharpness_level;
|
||||
|
||||
uint8_t mode_ref_delta_enabled;
|
||||
uint8_t mode_ref_delta_update;
|
||||
|
||||
// 0 = Intra, Last, Last2+Last3,
|
||||
// GF, BRF, ARF2, ARF
|
||||
int8_t ref_deltas[TOTAL_REFS_PER_FRAME];
|
||||
int8_t last_ref_deltas[TOTAL_REFS_PER_FRAME];
|
||||
|
||||
// 0 = ZERO_MV, MV
|
||||
int8_t mode_deltas[MAX_MODE_LF_DELTAS];
|
||||
int8_t last_mode_deltas[MAX_MODE_LF_DELTAS];
|
||||
};
|
||||
|
||||
// Need to align this structure so when it is declared and
|
||||
// passed it can be loaded into vector registers.
|
||||
typedef struct {
|
||||
DECLARE_ALIGNED(SIMD_WIDTH, uint8_t, mblim[SIMD_WIDTH]);
|
||||
DECLARE_ALIGNED(SIMD_WIDTH, uint8_t, lim[SIMD_WIDTH]);
|
||||
DECLARE_ALIGNED(SIMD_WIDTH, uint8_t, hev_thr[SIMD_WIDTH]);
|
||||
} loop_filter_thresh;
|
||||
|
||||
typedef struct {
|
||||
loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
|
||||
#if CONFIG_LOOPFILTER_LEVEL
|
||||
uint8_t lvl[MAX_SEGMENTS][2][TOTAL_REFS_PER_FRAME][MAX_MODE_LF_DELTAS];
|
||||
#else
|
||||
uint8_t lvl[MAX_SEGMENTS][TOTAL_REFS_PER_FRAME][MAX_MODE_LF_DELTAS];
|
||||
#endif
|
||||
} loop_filter_info_n;
|
||||
|
||||
/* assorted loopfilter functions which get used elsewhere */
|
||||
struct AV1Common;
|
||||
struct macroblockd;
|
||||
struct AV1LfSyncData;
|
||||
|
||||
// This function sets up the bit masks for the entire 64x64 region represented
|
||||
// by mi_row, mi_col.
|
||||
void av1_setup_mask(struct AV1Common *const cm, const int mi_row,
|
||||
const int mi_col, MODE_INFO **mi_4x4,
|
||||
const int mode_info_stride, LpfMask *lfm);
|
||||
|
||||
void av1_filter_block_plane_ss00_ver(struct AV1Common *const cm,
|
||||
struct macroblockd_plane *const plane,
|
||||
int mi_row, LoopFilterMask *lfm);
|
||||
void av1_filter_block_plane_ss00_hor(struct AV1Common *const cm,
|
||||
struct macroblockd_plane *const plane,
|
||||
int mi_row, LoopFilterMask *lfm);
|
||||
void av1_filter_block_plane_ss11_u_ver(struct AV1Common *const cm,
|
||||
struct macroblockd_plane *const plane,
|
||||
int mi_row, LoopFilterMask *lfm);
|
||||
void av1_filter_block_plane_ss11_u_hor(struct AV1Common *const cm,
|
||||
struct macroblockd_plane *const plane,
|
||||
int mi_row, LoopFilterMask *lfm);
|
||||
|
||||
void av1_filter_block_plane_ss11_v_ver(struct AV1Common *const cm,
|
||||
struct macroblockd_plane *const plane,
|
||||
int mi_row, LoopFilterMask *lfm);
|
||||
void av1_filter_block_plane_ss11_v_hor(struct AV1Common *const cm,
|
||||
struct macroblockd_plane *const plane,
|
||||
int mi_row, LoopFilterMask *lfm);
|
||||
|
||||
void av1_filter_block_plane_non420_ver(struct AV1Common *const cm,
|
||||
struct macroblockd_plane *plane,
|
||||
MODE_INFO **mi_8x8, int mi_row,
|
||||
int mi_col, int pl);
|
||||
void av1_filter_block_plane_non420_hor(struct AV1Common *const cm,
|
||||
struct macroblockd_plane *plane,
|
||||
MODE_INFO **mi_8x8, int mi_row,
|
||||
int mi_col, int pl);
|
||||
|
||||
void av1_loop_filter_init(struct AV1Common *cm);
|
||||
|
||||
// Update the loop filter for the current frame.
|
||||
// This should be called before av1_loop_filter_rows(),
|
||||
// av1_loop_filter_frame()
|
||||
// calls this function directly.
|
||||
void av1_loop_filter_frame_init(struct AV1Common *cm, int default_filt_lvl,
|
||||
int default_filt_lvl_r
|
||||
#if CONFIG_LOOPFILTER_LEVEL
|
||||
,
|
||||
int plane
|
||||
#endif
|
||||
);
|
||||
|
||||
void av1_loop_filter_frame(YV12_BUFFER_CONFIG *frame, struct AV1Common *cm,
|
||||
struct macroblockd *mbd, int filter_level,
|
||||
#if CONFIG_LOOPFILTER_LEVEL
|
||||
int filter_level_r,
|
||||
#endif
|
||||
int y_only, int partial_frame);
|
||||
|
||||
// Apply the loop filter to [start, stop) macro block rows in frame_buffer.
|
||||
void av1_loop_filter_rows(YV12_BUFFER_CONFIG *frame_buffer,
|
||||
struct AV1Common *cm,
|
||||
struct macroblockd_plane *planes, int start, int stop,
|
||||
int y_only);
|
||||
|
||||
typedef struct LoopFilterWorkerData {
|
||||
YV12_BUFFER_CONFIG *frame_buffer;
|
||||
struct AV1Common *cm;
|
||||
struct macroblockd_plane planes[MAX_MB_PLANE];
|
||||
|
||||
int start;
|
||||
int stop;
|
||||
int y_only;
|
||||
} LFWorkerData;
|
||||
|
||||
void av1_loop_filter_data_reset(LFWorkerData *lf_data,
|
||||
YV12_BUFFER_CONFIG *frame_buffer,
|
||||
struct AV1Common *cm,
|
||||
const struct macroblockd_plane *planes);
|
||||
|
||||
// Operates on the rows described by 'lf_data'.
|
||||
int av1_loop_filter_worker(LFWorkerData *const lf_data, void *unused);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AV1_COMMON_LOOPFILTER_H_
|
150
loopfilter/shift.c
Normal file
150
loopfilter/shift.c
Normal file
@ -0,0 +1,150 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Note:
|
||||
// Establish 64x64 block, contructed by 256 (16x16) 4x4 sub-block.
|
||||
// Every 4 rows would be represented by one uint64_t mask. Hence,
|
||||
// there are 4 uint64_t bitmask[4] to represent the whole 64x64.
|
||||
//
|
||||
// Given a location by (idx, idy), This function returns the index
|
||||
// 0, 1, 2, 3 to select which bitmask[] to use.
|
||||
// Then the pointer y_shift contains the shift value in the bit mask.
|
||||
// Function returns y_shift; y_index contains the index.
|
||||
//
|
||||
int get_y_index_shift(int idx, int idy, int *y_index) {
|
||||
*y_index = idy >> 4;
|
||||
const int y_idy = (idy >> 2) % 4;
|
||||
return (y_idy << 4) + (idx >> 2);
|
||||
}
|
||||
|
||||
// Note:
|
||||
// For 4:2:0 format sampling, establish 32x32 block, constructed by
|
||||
// 64 (8x8), 4x4 sub-block. We need one uint64_t bitmask to present
|
||||
// all edge information
|
||||
// Function returns uv_shift.
|
||||
//
|
||||
int get_uv_index_shift(int idx, int idy) {
|
||||
return ((idy >> 3) << 3) + (idx >> 3);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// AV1 has 4x4 coding block
|
||||
// I use 4 uint64_t integer to describe block edge information by a bit mask
|
||||
//
|
||||
void get_y_shift_value(int size) {
|
||||
int x, y;
|
||||
|
||||
for (y = 0; y < size; y += 4) {
|
||||
for (x = 0; x < size; x += 4) {
|
||||
printf("[%02d,%02d] ", x, y);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
int v_index;
|
||||
int y_shift;
|
||||
for (y = 0; y < size; y += 4) {
|
||||
for (x = 0; x < size; x += 4) {
|
||||
// cb8x8
|
||||
//int shift = ((y >> 3) << 3) + (x >> 3);
|
||||
//printf("%02d ", shift);
|
||||
|
||||
// cb4x4
|
||||
y_shift = get_y_index_shift(x, y, &v_index);
|
||||
printf("%02d ", y_shift);
|
||||
}
|
||||
printf("Index %d\n", v_index);
|
||||
}
|
||||
}
|
||||
|
||||
void get_uv_shift_value(int size) {
|
||||
int x, y;
|
||||
|
||||
int uv_shift = 0;
|
||||
const int step = 4;
|
||||
for (y = 0; y < size; y += step) {
|
||||
for (x = 0; x < size; x += step) {
|
||||
// cb8x8
|
||||
// int uv_shift = ((y >> 3) << 2) + (x >> 3);
|
||||
|
||||
// cb4x4
|
||||
uv_shift = get_uv_index_shift(x, y);
|
||||
printf("%02d ", uv_shift);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int get_uv_shift(int idx, int idy) {
|
||||
return (((idy - 2) >> 2) << 3) + (idx >> 2);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// AV1: AV1=1
|
||||
// VP9: AV1=0
|
||||
#define AV1 1
|
||||
|
||||
#if AV1
|
||||
#define MAX_MIB_SIZE_LOG2 (4)
|
||||
const int num = 16;
|
||||
typedef struct {
|
||||
uint64_t bits[4];
|
||||
} FilterMaskY;
|
||||
#else
|
||||
#define MAX_MIB_SIZE_LOG2 (3)
|
||||
const int num = 8;
|
||||
#endif
|
||||
|
||||
|
||||
int main() {
|
||||
get_y_shift_value(64);
|
||||
printf("\n");
|
||||
get_uv_shift_value(64);
|
||||
printf("\n");
|
||||
|
||||
int y_index = 0;
|
||||
const int x = 0;
|
||||
int y;
|
||||
int i;
|
||||
|
||||
// Remaining rows are 1, 2, ..., num - 1
|
||||
// VP9 : 1-7
|
||||
// AV1 : 1-15
|
||||
for (i = 1; i < num; ++i) {
|
||||
#if AV1
|
||||
y = i << 2;
|
||||
int y_shift = get_y_index_shift(x, y, &y_index);
|
||||
int uv_shift = get_uv_shift(x >> 1, y >> 1);
|
||||
|
||||
printf("[%02d,%02d] index=%d y_shift=%02d uv_shift=%02d mask_y ",
|
||||
x, y, y_index, y_shift, uv_shift);
|
||||
|
||||
FilterMaskY mask = {0, 0, 0, 0};
|
||||
int j;
|
||||
for (j = 0; j < y_index; ++j) {
|
||||
mask.bits[j] = 0xffffffffffffffffULL;
|
||||
}
|
||||
mask.bits[y_index] = ((uint64_t)1 << y_shift) - 1;
|
||||
for (j = 0; j < 4; ++j) {
|
||||
printf("0x%016llx ", (unsigned long long int)mask.bits[j]);
|
||||
}
|
||||
|
||||
uint64_t mask_uv = (((uint64_t)1 << (uv_shift + 8)) - 1);
|
||||
if (uv_shift + 8 == 64) mask_uv = 0xffffffffffffffffULL;
|
||||
|
||||
printf("mask_uv 0x%016llx", (unsigned long long int)mask_uv);
|
||||
printf("\n");
|
||||
#else
|
||||
const uint64_t mask_y = (((uint64_t)1 << (i << MAX_MIB_SIZE_LOG2)) - 1);
|
||||
const uint16_t mask_uv =
|
||||
(((uint16_t)1 << (((i + 1) >> 1) << (MAX_MIB_SIZE_LOG2 - 1))) - 1);
|
||||
printf("mask_y=%016llx, mask_uv=%04x\n", (long long unsigned int)mask_y, mask_uv);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
538
loopfilter/thread_common.c
Normal file
538
loopfilter/thread_common.c
Normal file
@ -0,0 +1,538 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "./aom_config.h"
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "av1/common/entropymode.h"
|
||||
#include "av1/common/thread_common.h"
|
||||
#include "av1/common/reconinter.h"
|
||||
|
||||
#if CONFIG_MULTITHREAD
|
||||
static INLINE void mutex_lock(pthread_mutex_t *const mutex) {
|
||||
const int kMaxTryLocks = 4000;
|
||||
int locked = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kMaxTryLocks; ++i) {
|
||||
if (!pthread_mutex_trylock(mutex)) {
|
||||
locked = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!locked) pthread_mutex_lock(mutex);
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
|
||||
static INLINE void sync_read(AV1LfSync *const lf_sync, int r, int c) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
const int nsync = lf_sync->sync_range;
|
||||
|
||||
if (r && !(c & (nsync - 1))) {
|
||||
pthread_mutex_t *const mutex = &lf_sync->mutex_[r - 1];
|
||||
mutex_lock(mutex);
|
||||
|
||||
while (c > lf_sync->cur_sb_col[r - 1] - nsync) {
|
||||
pthread_cond_wait(&lf_sync->cond_[r - 1], mutex);
|
||||
}
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
#else
|
||||
(void)lf_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
}
|
||||
|
||||
static INLINE void sync_write(AV1LfSync *const lf_sync, int r, int c,
|
||||
const int sb_cols) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
const int nsync = lf_sync->sync_range;
|
||||
int cur;
|
||||
// Only signal when there are enough filtered SB for next row to run.
|
||||
int sig = 1;
|
||||
|
||||
if (c < sb_cols - 1) {
|
||||
cur = c;
|
||||
if (c % nsync) sig = 0;
|
||||
} else {
|
||||
cur = sb_cols + nsync;
|
||||
}
|
||||
|
||||
if (sig) {
|
||||
mutex_lock(&lf_sync->mutex_[r]);
|
||||
|
||||
lf_sync->cur_sb_col[r] = cur;
|
||||
|
||||
pthread_cond_signal(&lf_sync->cond_[r]);
|
||||
pthread_mutex_unlock(&lf_sync->mutex_[r]);
|
||||
}
|
||||
#else
|
||||
(void)lf_sync;
|
||||
(void)r;
|
||||
(void)c;
|
||||
(void)sb_cols;
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
}
|
||||
|
||||
#if !CONFIG_EXT_PARTITION_TYPES
|
||||
static INLINE enum lf_path get_loop_filter_path(
|
||||
int y_only, struct macroblockd_plane planes[MAX_MB_PLANE]) {
|
||||
if (y_only)
|
||||
return LF_PATH_444;
|
||||
else if (planes[1].subsampling_y == 1 && planes[1].subsampling_x == 1)
|
||||
return LF_PATH_420;
|
||||
else if (planes[1].subsampling_y == 0 && planes[1].subsampling_x == 0)
|
||||
return LF_PATH_444;
|
||||
else
|
||||
return LF_PATH_SLOW;
|
||||
}
|
||||
|
||||
static INLINE void loop_filter_block_plane_ver(
|
||||
AV1_COMMON *cm, struct macroblockd_plane planes[MAX_MB_PLANE], int plane,
|
||||
MODE_INFO **mi, int mi_row, int mi_col, enum lf_path path,
|
||||
LoopFilterMask *lfm) {
|
||||
if (plane == 0) {
|
||||
av1_filter_block_plane_ss00_ver(cm, &planes[0], mi_row, lfm);
|
||||
} else {
|
||||
switch (path) {
|
||||
case LF_PATH_420:
|
||||
av1_filter_block_plane_ss11_ver(cm, &planes[plane], mi_row, lfm);
|
||||
break;
|
||||
case LF_PATH_444:
|
||||
av1_filter_block_plane_ss00_ver(cm, &planes[plane], mi_row, lfm);
|
||||
break;
|
||||
case LF_PATH_SLOW:
|
||||
av1_filter_block_plane_non420_ver(cm, &planes[plane], mi, mi_row,
|
||||
mi_col, plane);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void loop_filter_block_plane_hor(
|
||||
AV1_COMMON *cm, struct macroblockd_plane planes[MAX_MB_PLANE], int plane,
|
||||
MODE_INFO **mi, int mi_row, int mi_col, enum lf_path path,
|
||||
LoopFilterMask *lfm) {
|
||||
if (plane == 0) {
|
||||
av1_filter_block_plane_ss00_hor(cm, &planes[0], mi_row, lfm);
|
||||
} else {
|
||||
switch (path) {
|
||||
case LF_PATH_420:
|
||||
av1_filter_block_plane_ss11_hor(cm, &planes[plane], mi_row, lfm);
|
||||
break;
|
||||
case LF_PATH_444:
|
||||
av1_filter_block_plane_ss00_hor(cm, &planes[plane], mi_row, lfm);
|
||||
break;
|
||||
case LF_PATH_SLOW:
|
||||
av1_filter_block_plane_non420_hor(cm, &planes[plane], mi, mi_row,
|
||||
mi_col, plane);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Row-based multi-threaded loopfilter hook
|
||||
#if CONFIG_PARALLEL_DEBLOCKING
|
||||
static int loop_filter_ver_row_worker(AV1LfSync *const lf_sync,
|
||||
LFWorkerData *const lf_data) {
|
||||
const int num_planes = lf_data->y_only ? 1 : MAX_MB_PLANE;
|
||||
int mi_row, mi_col;
|
||||
#if !CONFIG_EXT_PARTITION_TYPES
|
||||
enum lf_path path = get_loop_filter_path(lf_data->y_only, lf_data->planes);
|
||||
#endif
|
||||
for (mi_row = lf_data->start; mi_row < lf_data->stop;
|
||||
mi_row += lf_sync->num_workers * lf_data->cm->mib_size) {
|
||||
MODE_INFO **const mi =
|
||||
lf_data->cm->mi_grid_visible + mi_row * lf_data->cm->mi_stride;
|
||||
|
||||
for (mi_col = 0; mi_col < lf_data->cm->mi_cols;
|
||||
mi_col += lf_data->cm->mib_size) {
|
||||
LpfMask lfm;
|
||||
int plane;
|
||||
|
||||
av1_setup_dst_planes(lf_data->planes, lf_data->cm->sb_size,
|
||||
lf_data->frame_buffer, mi_row, mi_col,
|
||||
av1_num_planes(lf_data->cm));
|
||||
av1_setup_mask(lf_data->cm, mi_row, mi_col, mi + mi_col,
|
||||
lf_data->cm->mi_stride, &lfm);
|
||||
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
for (plane = 0; plane < num_planes; ++plane)
|
||||
av1_filter_block_plane_non420_ver(lf_data->cm, &lf_data->planes[plane],
|
||||
mi + mi_col, mi_row, mi_col, plane);
|
||||
#else
|
||||
|
||||
for (plane = 0; plane < num_planes; ++plane)
|
||||
loop_filter_block_plane_ver(lf_data->cm, lf_data->planes, plane,
|
||||
mi + mi_col, mi_row, mi_col, path, &lfm);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int loop_filter_hor_row_worker(AV1LfSync *const lf_sync,
|
||||
LFWorkerData *const lf_data) {
|
||||
const int num_planes = lf_data->y_only ? 1 : MAX_MB_PLANE;
|
||||
const int sb_cols =
|
||||
mi_cols_aligned_to_sb(lf_data->cm) >> lf_data->cm->mib_size_log2;
|
||||
int mi_row, mi_col;
|
||||
#if !CONFIG_EXT_PARTITION_TYPES
|
||||
enum lf_path path = get_loop_filter_path(lf_data->y_only, lf_data->planes);
|
||||
#endif
|
||||
|
||||
for (mi_row = lf_data->start; mi_row < lf_data->stop;
|
||||
mi_row += lf_sync->num_workers * lf_data->cm->mib_size) {
|
||||
MODE_INFO **const mi =
|
||||
lf_data->cm->mi_grid_visible + mi_row * lf_data->cm->mi_stride;
|
||||
|
||||
for (mi_col = 0; mi_col < lf_data->cm->mi_cols;
|
||||
mi_col += lf_data->cm->mib_size) {
|
||||
const int r = mi_row >> lf_data->cm->mib_size_log2;
|
||||
const int c = mi_col >> lf_data->cm->mib_size_log2;
|
||||
LpfMask lfm;
|
||||
int plane;
|
||||
|
||||
// TODO(wenhao.zhang@intel.com): For better parallelization, reorder
|
||||
// the outer loop to column-based and remove the synchronizations here.
|
||||
sync_read(lf_sync, r, c);
|
||||
|
||||
av1_setup_dst_planes(lf_data->planes, lf_data->cm->sb_size,
|
||||
lf_data->frame_buffer, mi_row, mi_col,
|
||||
av1_num_planes(lf_data->cm));
|
||||
av1_setup_mask(lf_data->cm, mi_row, mi_col, mi + mi_col,
|
||||
lf_data->cm->mi_stride, &lfm);
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
for (plane = 0; plane < num_planes; ++plane)
|
||||
av1_filter_block_plane_non420_hor(lf_data->cm, &lf_data->planes[plane],
|
||||
mi + mi_col, mi_row, mi_col, plane);
|
||||
#else
|
||||
for (plane = 0; plane < num_planes; ++plane)
|
||||
loop_filter_block_plane_hor(lf_data->cm, lf_data->planes, plane,
|
||||
mi + mi_col, mi_row, mi_col, path, &lfm);
|
||||
#endif
|
||||
sync_write(lf_sync, r, c, sb_cols);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#else // CONFIG_PARALLEL_DEBLOCKING
|
||||
static int loop_filter_row_worker(AV1LfSync *const lf_sync,
|
||||
LFWorkerData *const lf_data) {
|
||||
const int num_planes = lf_data->y_only ? 1 : MAX_MB_PLANE;
|
||||
const int sb_cols =
|
||||
mi_cols_aligned_to_sb(lf_data->cm) >> lf_data->cm->mib_size_log2;
|
||||
int mi_row, mi_col;
|
||||
#if !CONFIG_EXT_PARTITION_TYPES
|
||||
enum lf_path path = get_loop_filter_path(lf_data->y_only, lf_data->planes);
|
||||
#endif // !CONFIG_EXT_PARTITION_TYPES
|
||||
|
||||
#if CONFIG_EXT_PARTITION
|
||||
printf(
|
||||
"STOPPING: This code has not been modified to work with the "
|
||||
"extended coding unit size experiment");
|
||||
exit(EXIT_FAILURE);
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
|
||||
for (mi_row = lf_data->start; mi_row < lf_data->stop;
|
||||
mi_row += lf_sync->num_workers * lf_data->cm->mib_size) {
|
||||
MODE_INFO **const mi =
|
||||
lf_data->cm->mi_grid_visible + mi_row * lf_data->cm->mi_stride;
|
||||
|
||||
for (mi_col = 0; mi_col < lf_data->cm->mi_cols;
|
||||
mi_col += lf_data->cm->mib_size) {
|
||||
const int r = mi_row >> lf_data->cm->mib_size_log2;
|
||||
const int c = mi_col >> lf_data->cm->mib_size_log2;
|
||||
#if !CONFIG_EXT_PARTITION_TYPES
|
||||
LpfMask lfm;
|
||||
#endif
|
||||
int plane;
|
||||
|
||||
sync_read(lf_sync, r, c);
|
||||
|
||||
av1_setup_dst_planes(lf_data->planes, lf_data->cm->sb_size,
|
||||
lf_data->frame_buffer, mi_row, mi_col);
|
||||
#if CONFIG_EXT_PARTITION_TYPES
|
||||
for (plane = 0; plane < num_planes; ++plane) {
|
||||
av1_filter_block_plane_non420_ver(lf_data->cm, &lf_data->planes[plane],
|
||||
mi + mi_col, mi_row, mi_col, plane);
|
||||
av1_filter_block_plane_non420_hor(lf_data->cm, &lf_data->planes[plane],
|
||||
mi + mi_col, mi_row, mi_col, plane);
|
||||
}
|
||||
#else
|
||||
av1_setup_mask(lf_data->cm, mi_row, mi_col, mi + mi_col,
|
||||
lf_data->cm->mi_stride, &lfm);
|
||||
|
||||
for (plane = 0; plane < num_planes; ++plane) {
|
||||
loop_filter_block_plane_ver(lf_data->cm, lf_data->planes, plane,
|
||||
mi + mi_col, mi_row, mi_col, path, &lfm);
|
||||
loop_filter_block_plane_hor(lf_data->cm, lf_data->planes, plane,
|
||||
mi + mi_col, mi_row, mi_col, path, &lfm);
|
||||
}
|
||||
#endif // CONFIG_EXT_PARTITION_TYPES
|
||||
sync_write(lf_sync, r, c, sb_cols);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif // CONFIG_PARALLEL_DEBLOCKING
|
||||
|
||||
static void loop_filter_rows_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
|
||||
struct macroblockd_plane *planes, int start,
|
||||
int stop, int y_only, AVxWorker *workers,
|
||||
int nworkers, AV1LfSync *lf_sync) {
|
||||
#if CONFIG_EXT_PARTITION
|
||||
printf(
|
||||
"STOPPING: This code has not been modified to work with the "
|
||||
"extended coding unit size experiment");
|
||||
exit(EXIT_FAILURE);
|
||||
#endif // CONFIG_EXT_PARTITION
|
||||
|
||||
const AVxWorkerInterface *const winterface = aom_get_worker_interface();
|
||||
// Number of superblock rows and cols
|
||||
const int sb_rows = mi_rows_aligned_to_sb(cm) >> cm->mib_size_log2;
|
||||
// Decoder may allocate more threads than number of tiles based on user's
|
||||
// input.
|
||||
const int tile_cols = cm->tile_cols;
|
||||
const int num_workers = AOMMIN(nworkers, tile_cols);
|
||||
int i;
|
||||
|
||||
if (!lf_sync->sync_range || sb_rows != lf_sync->rows ||
|
||||
num_workers > lf_sync->num_workers) {
|
||||
av1_loop_filter_dealloc(lf_sync);
|
||||
av1_loop_filter_alloc(lf_sync, cm, sb_rows, cm->width, num_workers);
|
||||
}
|
||||
|
||||
// Set up loopfilter thread data.
|
||||
// The decoder is capping num_workers because it has been observed that
|
||||
// using more threads on the loopfilter than there are cores will hurt
|
||||
// performance on Android. This is because the system will only schedule the
|
||||
// tile decode workers on cores equal to the number of tile columns. Then if
|
||||
// the decoder tries to use more threads for the loopfilter, it will hurt
|
||||
// performance because of contention. If the multithreading code changes in
|
||||
// the future then the number of workers used by the loopfilter should be
|
||||
// revisited.
|
||||
|
||||
#if CONFIG_PARALLEL_DEBLOCKING
|
||||
// Initialize cur_sb_col to -1 for all SB rows.
|
||||
memset(lf_sync->cur_sb_col, -1, sizeof(*lf_sync->cur_sb_col) * sb_rows);
|
||||
|
||||
// Filter all the vertical edges in the whole frame
|
||||
for (i = 0; i < num_workers; ++i) {
|
||||
AVxWorker *const worker = &workers[i];
|
||||
LFWorkerData *const lf_data = &lf_sync->lfdata[i];
|
||||
|
||||
worker->hook = (AVxWorkerHook)loop_filter_ver_row_worker;
|
||||
worker->data1 = lf_sync;
|
||||
worker->data2 = lf_data;
|
||||
|
||||
// Loopfilter data
|
||||
av1_loop_filter_data_reset(lf_data, frame, cm, planes);
|
||||
lf_data->start = start + i * cm->mib_size;
|
||||
lf_data->stop = stop;
|
||||
lf_data->y_only = y_only;
|
||||
|
||||
// Start loopfiltering
|
||||
if (i == num_workers - 1) {
|
||||
winterface->execute(worker);
|
||||
} else {
|
||||
winterface->launch(worker);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait till all rows are finished
|
||||
for (i = 0; i < num_workers; ++i) {
|
||||
winterface->sync(&workers[i]);
|
||||
}
|
||||
|
||||
memset(lf_sync->cur_sb_col, -1, sizeof(*lf_sync->cur_sb_col) * sb_rows);
|
||||
// Filter all the horizontal edges in the whole frame
|
||||
for (i = 0; i < num_workers; ++i) {
|
||||
AVxWorker *const worker = &workers[i];
|
||||
LFWorkerData *const lf_data = &lf_sync->lfdata[i];
|
||||
|
||||
worker->hook = (AVxWorkerHook)loop_filter_hor_row_worker;
|
||||
worker->data1 = lf_sync;
|
||||
worker->data2 = lf_data;
|
||||
|
||||
// Loopfilter data
|
||||
av1_loop_filter_data_reset(lf_data, frame, cm, planes);
|
||||
lf_data->start = start + i * cm->mib_size;
|
||||
lf_data->stop = stop;
|
||||
lf_data->y_only = y_only;
|
||||
|
||||
// Start loopfiltering
|
||||
if (i == num_workers - 1) {
|
||||
winterface->execute(worker);
|
||||
} else {
|
||||
winterface->launch(worker);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait till all rows are finished
|
||||
for (i = 0; i < num_workers; ++i) {
|
||||
winterface->sync(&workers[i]);
|
||||
}
|
||||
#else // CONFIG_PARALLEL_DEBLOCKING
|
||||
// Initialize cur_sb_col to -1 for all SB rows.
|
||||
memset(lf_sync->cur_sb_col, -1, sizeof(*lf_sync->cur_sb_col) * sb_rows);
|
||||
|
||||
for (i = 0; i < num_workers; ++i) {
|
||||
AVxWorker *const worker = &workers[i];
|
||||
LFWorkerData *const lf_data = &lf_sync->lfdata[i];
|
||||
|
||||
worker->hook = (AVxWorkerHook)loop_filter_row_worker;
|
||||
worker->data1 = lf_sync;
|
||||
worker->data2 = lf_data;
|
||||
|
||||
// Loopfilter data
|
||||
av1_loop_filter_data_reset(lf_data, frame, cm, planes);
|
||||
lf_data->start = start + i * cm->mib_size;
|
||||
lf_data->stop = stop;
|
||||
lf_data->y_only = y_only;
|
||||
|
||||
// Start loopfiltering
|
||||
if (i == num_workers - 1) {
|
||||
winterface->execute(worker);
|
||||
} else {
|
||||
winterface->launch(worker);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait till all rows are finished
|
||||
for (i = 0; i < num_workers; ++i) {
|
||||
winterface->sync(&workers[i]);
|
||||
}
|
||||
#endif // CONFIG_PARALLEL_DEBLOCKING
|
||||
}
|
||||
|
||||
void av1_loop_filter_frame_mt(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
|
||||
struct macroblockd_plane *planes,
|
||||
int frame_filter_level,
|
||||
#if CONFIG_LOOPFILTER_LEVEL
|
||||
int frame_filter_level_r,
|
||||
#endif
|
||||
int y_only, int partial_frame, AVxWorker *workers,
|
||||
int num_workers, AV1LfSync *lf_sync) {
|
||||
int start_mi_row, end_mi_row, mi_rows_to_filter;
|
||||
|
||||
if (!frame_filter_level) return;
|
||||
|
||||
start_mi_row = 0;
|
||||
mi_rows_to_filter = cm->mi_rows;
|
||||
if (partial_frame && cm->mi_rows > 8) {
|
||||
start_mi_row = cm->mi_rows >> 1;
|
||||
start_mi_row &= 0xfffffff8;
|
||||
mi_rows_to_filter = AOMMAX(cm->mi_rows / 8, 8);
|
||||
}
|
||||
end_mi_row = start_mi_row + mi_rows_to_filter;
|
||||
#if CONFIG_LOOPFILTER_LEVEL
|
||||
av1_loop_filter_frame_init(cm, frame_filter_level, frame_filter_level_r,
|
||||
y_only);
|
||||
#else
|
||||
av1_loop_filter_frame_init(cm, frame_filter_level, frame_filter_level);
|
||||
#endif // CONFIG_LOOPFILTER_LEVEL
|
||||
loop_filter_rows_mt(frame, cm, planes, start_mi_row, end_mi_row, y_only,
|
||||
workers, num_workers, lf_sync);
|
||||
}
|
||||
|
||||
// Set up nsync by width.
|
||||
static INLINE int get_sync_range(int width) {
|
||||
// nsync numbers are picked by testing. For example, for 4k
|
||||
// video, using 4 gives best performance.
|
||||
if (width < 640)
|
||||
return 1;
|
||||
else if (width <= 1280)
|
||||
return 2;
|
||||
else if (width <= 4096)
|
||||
return 4;
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
|
||||
// Allocate memory for lf row synchronization
|
||||
void av1_loop_filter_alloc(AV1LfSync *lf_sync, AV1_COMMON *cm, int rows,
|
||||
int width, int num_workers) {
|
||||
lf_sync->rows = rows;
|
||||
#if CONFIG_MULTITHREAD
|
||||
{
|
||||
int i;
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->mutex_,
|
||||
aom_malloc(sizeof(*lf_sync->mutex_) * rows));
|
||||
if (lf_sync->mutex_) {
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_mutex_init(&lf_sync->mutex_[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->cond_,
|
||||
aom_malloc(sizeof(*lf_sync->cond_) * rows));
|
||||
if (lf_sync->cond_) {
|
||||
for (i = 0; i < rows; ++i) {
|
||||
pthread_cond_init(&lf_sync->cond_[i], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->lfdata,
|
||||
aom_malloc(num_workers * sizeof(*lf_sync->lfdata)));
|
||||
lf_sync->num_workers = num_workers;
|
||||
|
||||
CHECK_MEM_ERROR(cm, lf_sync->cur_sb_col,
|
||||
aom_malloc(sizeof(*lf_sync->cur_sb_col) * rows));
|
||||
|
||||
// Set up nsync.
|
||||
lf_sync->sync_range = get_sync_range(width);
|
||||
}
|
||||
|
||||
// Deallocate lf synchronization related mutex and data
|
||||
void av1_loop_filter_dealloc(AV1LfSync *lf_sync) {
|
||||
if (lf_sync != NULL) {
|
||||
#if CONFIG_MULTITHREAD
|
||||
int i;
|
||||
|
||||
if (lf_sync->mutex_ != NULL) {
|
||||
for (i = 0; i < lf_sync->rows; ++i) {
|
||||
pthread_mutex_destroy(&lf_sync->mutex_[i]);
|
||||
}
|
||||
aom_free(lf_sync->mutex_);
|
||||
}
|
||||
if (lf_sync->cond_ != NULL) {
|
||||
for (i = 0; i < lf_sync->rows; ++i) {
|
||||
pthread_cond_destroy(&lf_sync->cond_[i]);
|
||||
}
|
||||
aom_free(lf_sync->cond_);
|
||||
}
|
||||
#endif // CONFIG_MULTITHREAD
|
||||
aom_free(lf_sync->lfdata);
|
||||
aom_free(lf_sync->cur_sb_col);
|
||||
// clear the structure as the source of this call may be a resize in which
|
||||
// case this call will be followed by an _alloc() which may fail.
|
||||
av1_zero(*lf_sync);
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate frame counts. FRAME_COUNTS consist solely of 'unsigned int'
|
||||
// members, so we treat it as an array, and sum over the whole length.
|
||||
void av1_accumulate_frame_counts(FRAME_COUNTS *acc_counts,
|
||||
FRAME_COUNTS *counts) {
|
||||
unsigned int *const acc = (unsigned int *)acc_counts;
|
||||
const unsigned int *const cnt = (unsigned int *)counts;
|
||||
|
||||
const unsigned int n_counts = sizeof(FRAME_COUNTS) / sizeof(unsigned int);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < n_counts; i++) acc[i] += cnt[i];
|
||||
}
|
53
mainpage.dox
53
mainpage.dox
@ -1,53 +0,0 @@
|
||||
/*!\mainpage WebM Codec SDK
|
||||
|
||||
\section main_contents Page Contents
|
||||
- \ref main_intro
|
||||
- \ref main_startpoints
|
||||
- \ref main_support
|
||||
|
||||
\section main_intro Introduction
|
||||
Welcome to the WebM Codec SDK. This SDK allows you to integrate your
|
||||
applications with the VP8 and VP9 video codecs, high quality, royalty free,
|
||||
open source codecs deployed on billions of computers and devices worldwide.
|
||||
|
||||
This distribution of the WebM Codec SDK includes the following support:
|
||||
|
||||
\if vp8_encoder
|
||||
- \ref vp8_encoder
|
||||
\endif
|
||||
\if vp8_decoder
|
||||
- \ref vp8_decoder
|
||||
\endif
|
||||
|
||||
|
||||
\section main_startpoints Starting Points
|
||||
- Consult the \ref changelog for a complete list of improvements in this
|
||||
release.
|
||||
- The \ref readme contains instructions on recompiling the sample applications.
|
||||
- Read the \ref usage "usage" for a narrative on codec usage.
|
||||
- Read the \ref samples "sample code" for examples of how to interact with the
|
||||
codec.
|
||||
- \ref codec reference
|
||||
\if encoder
|
||||
- \ref encoder reference
|
||||
\endif
|
||||
\if decoder
|
||||
- \ref decoder reference
|
||||
\endif
|
||||
|
||||
\section main_support Support Options & FAQ
|
||||
The WebM project is an open source project supported by its community. For
|
||||
questions about this SDK, please mail the apps-devel@webmproject.org list.
|
||||
To contribute, see http://www.webmproject.org/code/contribute and mail
|
||||
codec-devel@webmproject.org.
|
||||
*/
|
||||
|
||||
/*!\page changelog CHANGELOG
|
||||
\verbinclude CHANGELOG
|
||||
*/
|
||||
|
||||
/*!\page readme README
|
||||
\verbinclude README
|
||||
*/
|
||||
|
||||
/*!\defgroup codecs Supported Codecs */
|
249
md5_utils.c
249
md5_utils.c
@ -1,249 +0,0 @@
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*
|
||||
* Changed so as no longer to depend on Colin Plumb's `usual.h' header
|
||||
* definitions
|
||||
* - Ian Jackson <ian@chiark.greenend.org.uk>.
|
||||
* Still in the public domain.
|
||||
*/
|
||||
|
||||
#include <string.h> /* for memcpy() */
|
||||
|
||||
#include "md5_utils.h"
|
||||
|
||||
static void byteSwap(UWORD32 *buf, unsigned words) {
|
||||
md5byte *p;
|
||||
|
||||
/* Only swap bytes for big endian machines */
|
||||
int i = 1;
|
||||
|
||||
if (*(char *)&i == 1) return;
|
||||
|
||||
p = (md5byte *)buf;
|
||||
|
||||
do {
|
||||
*buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
|
||||
((unsigned)p[1] << 8 | p[0]);
|
||||
p += 4;
|
||||
} while (--words);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
void MD5Init(struct MD5Context *ctx) {
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bytes[0] = 0;
|
||||
ctx->bytes[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
void MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) {
|
||||
UWORD32 t;
|
||||
|
||||
/* Update byte count */
|
||||
|
||||
t = ctx->bytes[0];
|
||||
|
||||
if ((ctx->bytes[0] = t + len) < t)
|
||||
ctx->bytes[1]++; /* Carry from low to high */
|
||||
|
||||
t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
|
||||
|
||||
if (t > len) {
|
||||
memcpy((md5byte *)ctx->in + 64 - t, buf, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* First chunk is an odd size */
|
||||
memcpy((md5byte *)ctx->in + 64 - t, buf, t);
|
||||
byteSwap(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
|
||||
/* Process data in 64-byte chunks */
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
byteSwap(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
void MD5Final(md5byte digest[16], struct MD5Context *ctx) {
|
||||
int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
|
||||
md5byte *p = (md5byte *)ctx->in + count;
|
||||
|
||||
/* Set the first char of padding to 0x80. There is always room. */
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 56 bytes (-8..55) */
|
||||
count = 56 - 1 - count;
|
||||
|
||||
if (count < 0) { /* Padding forces an extra block */
|
||||
memset(p, 0, count + 8);
|
||||
byteSwap(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
p = (md5byte *)ctx->in;
|
||||
count = 56;
|
||||
}
|
||||
|
||||
memset(p, 0, count);
|
||||
byteSwap(ctx->in, 14);
|
||||
|
||||
/* Append length in bits and transform */
|
||||
ctx->in[14] = ctx->bytes[0] << 3;
|
||||
ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
|
||||
MD5Transform(ctx->buf, ctx->in);
|
||||
|
||||
byteSwap(ctx->buf, 4);
|
||||
memcpy(digest, ctx->buf, 16);
|
||||
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
#ifndef ASM_MD5
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, in, s) \
|
||||
(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
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
VPX_NO_UNSIGNED_OVERFLOW_CHECK void MD5Transform(UWORD32 buf[4],
|
||||
UWORD32 const in[16]) {
|
||||
register UWORD32 a, b, c, d;
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
#undef VPX_NO_UNSIGNED_OVERFLOW_CHECK
|
||||
|
||||
#endif
|
49
md5_utils.h
49
md5_utils.h
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* This is the header file for the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*
|
||||
* Changed so as no longer to depend on Colin Plumb's `usual.h'
|
||||
* header definitions
|
||||
* - Ian Jackson <ian@chiark.greenend.org.uk>.
|
||||
* Still in the public domain.
|
||||
*/
|
||||
|
||||
#ifndef MD5_UTILS_H_
|
||||
#define MD5_UTILS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define md5byte unsigned char
|
||||
#define UWORD32 unsigned int
|
||||
|
||||
typedef struct MD5Context MD5Context;
|
||||
struct MD5Context {
|
||||
UWORD32 buf[4];
|
||||
UWORD32 bytes[2];
|
||||
UWORD32 in[16];
|
||||
};
|
||||
|
||||
void MD5Init(struct MD5Context *context);
|
||||
void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
||||
void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // MD5_UTILS_H_
|
289
rate_hist.c
289
rate_hist.c
@ -1,289 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "./rate_hist.h"
|
||||
|
||||
#define RATE_BINS 100
|
||||
#define HIST_BAR_MAX 40
|
||||
|
||||
struct hist_bucket {
|
||||
int low;
|
||||
int high;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct rate_hist {
|
||||
int64_t *pts;
|
||||
int *sz;
|
||||
int samples;
|
||||
int frames;
|
||||
struct hist_bucket bucket[RATE_BINS];
|
||||
int total;
|
||||
};
|
||||
|
||||
struct rate_hist *init_rate_histogram(const vpx_codec_enc_cfg_t *cfg,
|
||||
const vpx_rational_t *fps) {
|
||||
int i;
|
||||
struct rate_hist *hist = calloc(1, 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
|
||||
// to determine the number of frames in rc_buf_sz milliseconds, with an
|
||||
// adjustment (5/4) to account for alt-refs
|
||||
hist->samples = cfg->rc_buf_sz * 5 / 4 * fps->num / fps->den / 1000;
|
||||
|
||||
// prevent division by zero
|
||||
if (hist->samples == 0) hist->samples = 1;
|
||||
|
||||
hist->frames = 0;
|
||||
hist->total = 0;
|
||||
|
||||
hist->pts = calloc(hist->samples, sizeof(*hist->pts));
|
||||
hist->sz = calloc(hist->samples, sizeof(*hist->sz));
|
||||
for (i = 0; i < RATE_BINS; i++) {
|
||||
hist->bucket[i].low = INT_MAX;
|
||||
hist->bucket[i].high = 0;
|
||||
hist->bucket[i].count = 0;
|
||||
}
|
||||
|
||||
return hist;
|
||||
}
|
||||
|
||||
void destroy_rate_histogram(struct rate_hist *hist) {
|
||||
if (hist) {
|
||||
free(hist->pts);
|
||||
free(hist->sz);
|
||||
free(hist);
|
||||
}
|
||||
}
|
||||
|
||||
void update_rate_histogram(struct rate_hist *hist,
|
||||
const vpx_codec_enc_cfg_t *cfg,
|
||||
const vpx_codec_cx_pkt_t *pkt) {
|
||||
int i;
|
||||
int64_t then = 0;
|
||||
int64_t avg_bitrate = 0;
|
||||
int64_t sum_sz = 0;
|
||||
const int64_t now = pkt->data.frame.pts * 1000 *
|
||||
(uint64_t)cfg->g_timebase.num /
|
||||
(uint64_t)cfg->g_timebase.den;
|
||||
|
||||
int idx;
|
||||
|
||||
if (hist == NULL || cfg == NULL || pkt == NULL) return;
|
||||
|
||||
idx = hist->frames++ % hist->samples;
|
||||
hist->pts[idx] = now;
|
||||
hist->sz[idx] = (int)pkt->data.frame.sz;
|
||||
|
||||
if (now < cfg->rc_buf_initial_sz) return;
|
||||
|
||||
if (!cfg->rc_target_bitrate) return;
|
||||
|
||||
then = now;
|
||||
|
||||
/* Sum the size over the past rc_buf_sz ms */
|
||||
for (i = hist->frames; i > 0 && hist->frames - i < hist->samples; i--) {
|
||||
const int i_idx = (i - 1) % hist->samples;
|
||||
|
||||
then = hist->pts[i_idx];
|
||||
if (now - then > cfg->rc_buf_sz) break;
|
||||
sum_sz += hist->sz[i_idx];
|
||||
}
|
||||
|
||||
if (now == then) return;
|
||||
|
||||
avg_bitrate = sum_sz * 8 * 1000 / (now - then);
|
||||
idx = (int)(avg_bitrate * (RATE_BINS / 2) / (cfg->rc_target_bitrate * 1000));
|
||||
if (idx < 0) idx = 0;
|
||||
if (idx > RATE_BINS - 1) idx = RATE_BINS - 1;
|
||||
if (hist->bucket[idx].low > avg_bitrate)
|
||||
hist->bucket[idx].low = (int)avg_bitrate;
|
||||
if (hist->bucket[idx].high < avg_bitrate)
|
||||
hist->bucket[idx].high = (int)avg_bitrate;
|
||||
hist->bucket[idx].count++;
|
||||
hist->total++;
|
||||
}
|
||||
|
||||
static int merge_hist_buckets(struct hist_bucket *bucket, int max_buckets,
|
||||
int *num_buckets) {
|
||||
int small_bucket = 0, merge_bucket = INT_MAX, big_bucket = 0;
|
||||
int buckets;
|
||||
int i;
|
||||
|
||||
assert(bucket != NULL);
|
||||
assert(num_buckets != NULL);
|
||||
|
||||
buckets = *num_buckets;
|
||||
|
||||
/* Find the extrema for this list of buckets */
|
||||
big_bucket = small_bucket = 0;
|
||||
for (i = 0; i < buckets; i++) {
|
||||
if (bucket[i].count < bucket[small_bucket].count) 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
|
||||
* bucket.
|
||||
*/
|
||||
while (buckets > max_buckets) {
|
||||
int last_bucket = buckets - 1;
|
||||
|
||||
/* merge the small bucket with an adjacent one. */
|
||||
if (small_bucket == 0)
|
||||
merge_bucket = 1;
|
||||
else if (small_bucket == last_bucket)
|
||||
merge_bucket = last_bucket - 1;
|
||||
else if (bucket[small_bucket - 1].count < bucket[small_bucket + 1].count)
|
||||
merge_bucket = small_bucket - 1;
|
||||
else
|
||||
merge_bucket = small_bucket + 1;
|
||||
|
||||
assert(abs(merge_bucket - small_bucket) <= 1);
|
||||
assert(small_bucket < buckets);
|
||||
assert(big_bucket < buckets);
|
||||
assert(merge_bucket < buckets);
|
||||
|
||||
if (merge_bucket < small_bucket) {
|
||||
bucket[merge_bucket].high = bucket[small_bucket].high;
|
||||
bucket[merge_bucket].count += bucket[small_bucket].count;
|
||||
} else {
|
||||
bucket[small_bucket].high = bucket[merge_bucket].high;
|
||||
bucket[small_bucket].count += bucket[merge_bucket].count;
|
||||
merge_bucket = small_bucket;
|
||||
}
|
||||
|
||||
assert(bucket[merge_bucket].low != bucket[merge_bucket].high);
|
||||
|
||||
buckets--;
|
||||
|
||||
/* Remove the merge_bucket from the list, and find the new small
|
||||
* and big buckets while we're at it
|
||||
*/
|
||||
big_bucket = small_bucket = 0;
|
||||
for (i = 0; i < buckets; i++) {
|
||||
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[big_bucket].count) big_bucket = i;
|
||||
}
|
||||
}
|
||||
|
||||
*num_buckets = buckets;
|
||||
return bucket[big_bucket].count;
|
||||
}
|
||||
|
||||
static void show_histogram(const struct hist_bucket *bucket, int buckets,
|
||||
int total, int scale) {
|
||||
const char *pat1, *pat2;
|
||||
int i;
|
||||
|
||||
assert(bucket != NULL);
|
||||
|
||||
switch ((int)(log(bucket[buckets - 1].high) / log(10)) + 1) {
|
||||
case 1:
|
||||
case 2:
|
||||
pat1 = "%4d %2s: ";
|
||||
pat2 = "%4d-%2d: ";
|
||||
break;
|
||||
case 3:
|
||||
pat1 = "%5d %3s: ";
|
||||
pat2 = "%5d-%3d: ";
|
||||
break;
|
||||
case 4:
|
||||
pat1 = "%6d %4s: ";
|
||||
pat2 = "%6d-%4d: ";
|
||||
break;
|
||||
case 5:
|
||||
pat1 = "%7d %5s: ";
|
||||
pat2 = "%7d-%5d: ";
|
||||
break;
|
||||
case 6:
|
||||
pat1 = "%8d %6s: ";
|
||||
pat2 = "%8d-%6d: ";
|
||||
break;
|
||||
case 7:
|
||||
pat1 = "%9d %7s: ";
|
||||
pat2 = "%9d-%7d: ";
|
||||
break;
|
||||
default:
|
||||
pat1 = "%12d %10s: ";
|
||||
pat2 = "%12d-%10d: ";
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < buckets; i++) {
|
||||
int len;
|
||||
int j;
|
||||
float pct;
|
||||
|
||||
pct = (float)(100.0 * bucket[i].count / total);
|
||||
len = HIST_BAR_MAX * bucket[i].count / scale;
|
||||
if (len < 1) len = 1;
|
||||
assert(len <= HIST_BAR_MAX);
|
||||
|
||||
if (bucket[i].low == bucket[i].high)
|
||||
fprintf(stderr, pat1, bucket[i].low, "");
|
||||
else
|
||||
fprintf(stderr, pat2, bucket[i].low, bucket[i].high);
|
||||
|
||||
for (j = 0; j < HIST_BAR_MAX; j++) fprintf(stderr, j < len ? "=" : " ");
|
||||
fprintf(stderr, "\t%5d (%6.2f%%)\n", bucket[i].count, pct);
|
||||
}
|
||||
}
|
||||
|
||||
void show_q_histogram(const int counts[64], int max_buckets) {
|
||||
struct hist_bucket bucket[64];
|
||||
int buckets = 0;
|
||||
int total = 0;
|
||||
int scale;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (counts[i]) {
|
||||
bucket[buckets].low = bucket[buckets].high = i;
|
||||
bucket[buckets].count = counts[i];
|
||||
buckets++;
|
||||
total += counts[i];
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\nQuantizer Selection:\n");
|
||||
scale = merge_hist_buckets(bucket, max_buckets, &buckets);
|
||||
show_histogram(bucket, buckets, total, scale);
|
||||
}
|
||||
|
||||
void show_rate_histogram(struct rate_hist *hist, const vpx_codec_enc_cfg_t *cfg,
|
||||
int max_buckets) {
|
||||
int i, scale;
|
||||
int buckets = 0;
|
||||
|
||||
if (hist == NULL || cfg == NULL) return;
|
||||
|
||||
for (i = 0; i < RATE_BINS; i++) {
|
||||
if (hist->bucket[i].low == INT_MAX) continue;
|
||||
hist->bucket[buckets++] = hist->bucket[i];
|
||||
}
|
||||
|
||||
fprintf(stderr, "\nRate (over %dms window):\n", cfg->rc_buf_sz);
|
||||
scale = merge_hist_buckets(hist->bucket, max_buckets, &buckets);
|
||||
show_histogram(hist->bucket, buckets, hist->total, scale);
|
||||
}
|
40
rate_hist.h
40
rate_hist.h
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef RATE_HIST_H_
|
||||
#define RATE_HIST_H_
|
||||
|
||||
#include "vpx/vpx_encoder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct rate_hist;
|
||||
|
||||
struct rate_hist *init_rate_histogram(const vpx_codec_enc_cfg_t *cfg,
|
||||
const vpx_rational_t *fps);
|
||||
|
||||
void destroy_rate_histogram(struct rate_hist *hist);
|
||||
|
||||
void update_rate_histogram(struct rate_hist *hist,
|
||||
const vpx_codec_enc_cfg_t *cfg,
|
||||
const vpx_codec_cx_pkt_t *pkt);
|
||||
|
||||
void show_q_histogram(const int counts[64], int max_buckets);
|
||||
|
||||
void show_rate_histogram(struct rate_hist *hist, const vpx_codec_enc_cfg_t *cfg,
|
||||
int max_buckets);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // RATE_HIST_H_
|
4
scripts/BQTerrace_1080p60.sh
Normal file
4
scripts/BQTerrace_1080p60.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
video=~/Dev/samples/videos/hevc/hd/BQTerrace_1920x1080_60.y4m
|
||||
fps="60/1"
|
8
scripts/BasketballDrill_480p.sh
Normal file
8
scripts/BasketballDrill_480p.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
video=~/Dev/samples/videos/midres/BasketballDrill_832x480_50.y4m
|
||||
frames=60
|
||||
bitrate=800
|
||||
fps="50/1"
|
||||
wide=
|
||||
high=
|
8
scripts/BasketballDrive_1080p.sh
Normal file
8
scripts/BasketballDrive_1080p.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
video=~/Dev/samples/videos/speed-set/BasketballDrive_1920x1080_50.y4m
|
||||
wi=1920
|
||||
he=1080
|
||||
frames=150
|
||||
bitrate=4000
|
||||
fps="50/1"
|
4
scripts/BasketballDrive_1080p50.sh
Normal file
4
scripts/BasketballDrive_1080p50.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
video=~/Dev/samples/videos/speed-set/BasketballDrive_1920x1080_50.y4m
|
||||
fps="50/1"
|
4
scripts/ParkScene_1080p24.sh
Normal file
4
scripts/ParkScene_1080p24.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
video=~/Dev/samples/videos/hevc/hd/ParkScene_1920x1080_24.y4m
|
||||
fps="24/1"
|
8
scripts/aerial_4k.sh
Normal file
8
scripts/aerial_4k.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
video=~/Dev/samples/videos/Netflix/Netflix_Aerial_4096x2160_60fps_8bit_420.y4m
|
||||
wi=4096
|
||||
he=2160
|
||||
frames=150
|
||||
bitrate=12000
|
||||
fps="60/1"
|
22
scripts/aom_conf_build.sh
Executable file
22
scripts/aom_conf_build.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
#set -x
|
||||
|
||||
root_dir=$1
|
||||
build_dir=$root_dir/release
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
exp_tool=
|
||||
|
||||
cd $build_dir
|
||||
make clean > /dev/null
|
||||
rm -fr ./*
|
||||
$script_dir/aom_nightly_config.sh
|
||||
make -j > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "AV1 build failed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test_dir=~/Dev/nightly
|
||||
|
||||
cp -f ./aomenc $test_dir/.
|
||||
cp -f ./aomdec $test_dir/.
|
13
scripts/aom_nightly_config.sh
Executable file
13
scripts/aom_nightly_config.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
#set -x
|
||||
|
||||
libsrc=aom
|
||||
test_dir=~/Dev/nightly
|
||||
|
||||
echo "cmake ../$libsrc -DCONFIG_UNIT_TESTS=0 -DENABLE_DOCS=0"
|
||||
|
||||
~/bin/cmake ../$libsrc -DCONFIG_UNIT_TESTS=0 -DENABLE_DOCS=0 > /dev/null 2>&1
|
||||
# if [ $? -ne 0 ]; then
|
||||
# echo "Error: cmake configure fails!" > $test_dir/aom_error_config.txt
|
||||
# exit 1
|
||||
# fi
|
122
scripts/aom_nightly_speed.sh
Executable file
122
scripts/aom_nightly_speed.sh
Executable file
@ -0,0 +1,122 @@
|
||||
#!/bin/sh
|
||||
# File:
|
||||
# nightly_speed.sh
|
||||
# Decription:
|
||||
# Configure, build, and run AV1 encoder/decoder for each experimental tool.
|
||||
# Display the encoder/decode run time
|
||||
# Preassumption:
|
||||
# 1) Assume all script files are in ~/Dev/sandbox/libvpx/scripts
|
||||
# Note:
|
||||
# See encoder config output if set,
|
||||
# verbose=-v
|
||||
#set -x
|
||||
|
||||
if [ "$#" -ne 5 ]; then
|
||||
root_dir=~/Dev/av1d
|
||||
pdfps=1
|
||||
petime=1
|
||||
speed=0
|
||||
html_log_file=log.html
|
||||
else
|
||||
root_dir=$1
|
||||
pdfps=$2
|
||||
petime=$3
|
||||
speed=$4
|
||||
html_log_file=$5
|
||||
fi
|
||||
log_path=~/Dev/log
|
||||
|
||||
if [ "$profile" == "2" ]; then
|
||||
bitdepth="--bit-depth=10"
|
||||
fi
|
||||
|
||||
if [ "$profile" == "0" ]; then
|
||||
bitdepth=
|
||||
fi
|
||||
|
||||
code_dir=$root_dir/aom
|
||||
build_dir=$root_dir/release
|
||||
test_dir=~/Dev/nightly
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
. $script_dir/BasketballDrill_480p.sh
|
||||
|
||||
# General options
|
||||
codec="--codec=av1"
|
||||
verbose=
|
||||
core_id=1
|
||||
exp_tool=experimental
|
||||
|
||||
cd $root_dir/aom
|
||||
commit=`git log --pretty=%h -1`
|
||||
|
||||
cd $test_dir
|
||||
|
||||
profile=0
|
||||
tune_content=
|
||||
col_num=0
|
||||
laginframes=19
|
||||
|
||||
elog=av1enc_log_p_$profile.$speed.txt
|
||||
dlog=av1dec_log_p_$profile.$speed.txt
|
||||
bstream=av1_p_$profile.$speed.$commit.webm
|
||||
|
||||
taskset -c $core_id ./aomenc $verbose -o /dev/shm/"$bstream" $video $codec --limit=$frames --profile=$profile $bitdepth --fps=$fps $tune_content --target-bitrate=$bitrate --skip=0 -p 2 --cpu-used=$speed --lag-in-frames=$laginframes --min-q=0 --max-q=63 --auto-alt-ref=1 --kf-max-dist=150 --kf-min-dist=0 --drop-frame=0 --static-thresh=0 --bias-pct=50 --minsection-pct=0 --maxsection-pct=2000 --arnr-maxframes=7 --arnr-strength=5 --sharpness=0 --undershoot-pct=100 --overshoot-pct=100 --frame-parallel=0 --tile-columns=$col_num --psnr &>> $elog
|
||||
|
||||
# Note: $2 is the time unit, ms or us
|
||||
etime=`cat $elog | awk 'NR==2 {NF-=3; print $NF}'`
|
||||
# efps=`cat $elog | grep 'Pass 2/2' | grep 'fps)' | sed -e 's/^.*b\/s//' | awk '{print $3}'`
|
||||
# efps=`echo $efps | sed 's/(//'`
|
||||
|
||||
psnr=`cat $elog | grep 'PSNR' | awk '{print $5, $6, $7, $8, $9}'`
|
||||
tmp=`cat $elog | grep mismatch`
|
||||
if [ "$?" -ne 0 ]; then
|
||||
eflag=e_ok
|
||||
else
|
||||
eflag=mismatch
|
||||
fi
|
||||
|
||||
echo "AV1: $(basename $video), profile=$profile bitrate=$bitrate frames=$frames speed=$speed"
|
||||
|
||||
taskset -c $core_id ./aomdec /dev/shm/"$bstream" $codec --i420 --noblit --summary 2>&1 &>> $dlog
|
||||
if [ "$?" -ne 0 ]; then
|
||||
dflag=fault
|
||||
else
|
||||
dflag=d_ok
|
||||
fi
|
||||
|
||||
# Note: $8 is the time unit ms or us
|
||||
dfps=`awk '{print $9}' < $dlog`
|
||||
dfps=`echo $dfps | sed 's/(//'`
|
||||
|
||||
dpercent=`echo "($dfps - $pdfps) / $pdfps * 100" | bc -l`
|
||||
dpercent=${dpercent:0:5}
|
||||
|
||||
epercent=`echo "($petime - $etime) / $petime * 100" | bc -l`
|
||||
epercent=${epercent:0:5}
|
||||
|
||||
echo -e '\t'"Enc fps Dec fps PSNR"'\t\t\t\t'"Enc status Dec status dup(%) eup(%)"
|
||||
echo -e '\t'$etime" "$dfps" "$psnr'\t'$eflag" "$dflag" "$dpercent" "$epercent
|
||||
printf "\n"
|
||||
|
||||
# Output a html log file for email
|
||||
echo "<p> AV1: $(basename $video), bitrate=$bitrate profile=$profile frames=$frames speed=$speed </p>" >> $log_path/$html_log_file
|
||||
echo "<table style=\"width:100%\">" >> $log_path/$html_log_file
|
||||
echo " <tr>" >> $log_path/$html_log_file
|
||||
echo " <th>Enc Time (ms)</th>" >> $log_path/$html_log_file
|
||||
echo " <th>Enc Speedup(%)</th>" >> $log_path/$html_log_file
|
||||
echo " <th>Dec FPS</th>" >> $log_path/$html_log_file
|
||||
echo " <th>Dec Speedup(%)</th>" >> $log_path/$html_log_file
|
||||
echo " <th>PSNR</th>" >> $log_path/$html_log_file
|
||||
echo " </tr>" >> $log_path/$html_log_file
|
||||
echo " <tr>" >> $log_path/$html_log_file
|
||||
echo " <td>$etime</td>" >> $log_path/$html_log_file
|
||||
echo " <td>$epercent</td>" >> $log_path/$html_log_file
|
||||
echo " <td>$dfps</td>" >> $log_path/$html_log_file
|
||||
echo " <td>$dpercent</td>" >> $log_path/$html_log_file
|
||||
echo " <td>$psnr</td>" >> $log_path/$html_log_file
|
||||
echo " </tr>" >> $log_path/$html_log_file
|
||||
echo "</table>" >> $log_path/$html_log_file
|
||||
|
||||
# Copy bitstream file to cns
|
||||
fileutil cp /run/shm/"$bstream" /cns/yv-d/home/on2-prod/luoyi/Nightly/.
|
3
scripts/aom_push.sh
Executable file
3
scripts/aom_push.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
git push https://aomedia-review.googlesource.com/aom HEAD:refs/for/master
|
41
scripts/aomenc_auto_720p.sh
Normal file
41
scripts/aomenc_auto_720p.sh
Normal file
@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
# Unique calling argument: frame number
|
||||
#
|
||||
#set -x
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
frames=25
|
||||
else
|
||||
frames=$1
|
||||
fi
|
||||
|
||||
prof=0
|
||||
if [ "$prof" == "2" ]; then
|
||||
bitdepth="--bit-depth=10"
|
||||
fi
|
||||
|
||||
if [ "$prof" == "0" ]; then
|
||||
bitdepth=
|
||||
fi
|
||||
|
||||
# In a release direcotry
|
||||
cd ../aom
|
||||
#git pull
|
||||
commithash=`git log --pretty=%h -1`
|
||||
cd ../release
|
||||
|
||||
#../aom/configure --disable-docs --disable-unit-tests
|
||||
#make clean;make
|
||||
|
||||
rm -fr ./*
|
||||
cmake ../aom -DCONFIG_UNIT_TESTS=0 -DENABLE_DOCS=0
|
||||
make
|
||||
|
||||
date_str=`date +%b_%d_%Y`
|
||||
bitstream=night_720p30_av1_$commithash.$date_str.f$frames.webm
|
||||
|
||||
fps=30
|
||||
bitrate=2500
|
||||
laginframes=19
|
||||
|
||||
taskset -c 0 ./aomenc -o /run/shm/$bitstream ~/Dev/samples/videos/speed-set/night_720p30.y4m --codec=av1 --fps=$fps/1 --skip=0 -p 2 --cpu-used=0 --target-bitrate=$bitrate --lag-in-frames=$laginframes --profile=$prof $bitdepth --limit=$frames --enable-cdef=0 --min-q=0 --max-q=63 --auto-alt-ref=1 --kf-max-dist=150 --kf-min-dist=0 --drop-frame=0 --static-thresh=0 --bias-pct=50 --minsection-pct=0 --maxsection-pct=2000 --arnr-maxframes=7 --arnr-strength=5 --sharpness=0 --undershoot-pct=100 --overshoot-pct=100 --frame-parallel=0 -t 1 --psnr --test-decode=warn -D
|
51
scripts/aomenc_nightly_speed.sh
Executable file
51
scripts/aomenc_nightly_speed.sh
Executable file
@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
#set -x
|
||||
|
||||
script_path=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
av1_code=~/Dev/av1d
|
||||
log_path=~/Dev/log
|
||||
|
||||
date_str=`date -d tomorrow +%b_%d_%Y`
|
||||
|
||||
html_log_file=aomenc_$date_str.html
|
||||
|
||||
s0_log_file=av1_s0_$date_str.txt
|
||||
s1_log_file=av1_s1_$date_str.txt
|
||||
|
||||
prev_date_str=`date +%b_%d_%Y`
|
||||
prev_s0_log_file=av1_s0_$prev_date_str.txt
|
||||
prev_s1_log_file=av1_s1_$prev_date_str.txt
|
||||
|
||||
test_dir=~/Dev/nightly
|
||||
rm $test_dir/*
|
||||
|
||||
$script_path/gen_html_header.sh > $log_path/$html_log_file
|
||||
|
||||
echo "<p>" >> $log_path/$html_log_file
|
||||
$script_path/sync_codebase.sh $av1_code/aom >> $log_path/$html_log_file 2>&1
|
||||
echo "</p>" >> $log_path/$html_log_file
|
||||
|
||||
echo "<p>" >> $log_path/$html_log_file
|
||||
$script_path/aom_conf_build.sh $av1_code >> $log_path/$html_log_file 2>&1
|
||||
echo "</p>" >> $log_path/$html_log_file
|
||||
|
||||
pdfps=`cat $log_path/$prev_s0_log_file | grep e_ok | awk '{print $2}' | awk 'NR==1 {print $1}'`
|
||||
petime=`cat $log_path/$prev_s0_log_file | grep e_ok | awk '{print $1}' | awk 'NR==1 {print $1}'`
|
||||
speed=0
|
||||
$script_path/aom_nightly_speed.sh $av1_code $pdfps $petime $speed $html_log_file >> $log_path/$s0_log_file 2>&1
|
||||
|
||||
pdfps=`cat $log_path/$prev_s1_log_file | grep e_ok | awk '{print $2}' | awk 'NR==1 {print $1}'`
|
||||
petime=`cat $log_path/$prev_s1_log_file | grep e_ok | awk '{print $1}' | awk 'NR==1 {print $1}'`
|
||||
speed=1
|
||||
$script_path/aom_nightly_speed.sh $av1_code $pdfps $petime $speed $html_log_file >> $log_path/$s1_log_file 2>&1
|
||||
|
||||
# Send an email to coworkers
|
||||
users=luoyi
|
||||
host_name=`hostname`
|
||||
sender=luoyi
|
||||
cc_list="--cc=yunqingwang,vpx-eng"
|
||||
|
||||
$script_path/gen_html_footer.sh >> $log_path/$html_log_file
|
||||
|
||||
sendgmr --to=$users $cc_list --subject="AV1 Nightly Speed Report" --from=$sender --reply_to=$sender --html_file=/usr/local/google/home/luoyi/Dev/log/$html_log_file --body_file=/usr/local/google/home/luoyi/Dev/log/$html_log_file
|
20
scripts/av1_conf_build.sh
Executable file
20
scripts/av1_conf_build.sh
Executable file
@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
root_dir=$1
|
||||
build_dir=$root_dir/release
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
exp_tool=experimental
|
||||
|
||||
cd $build_dir
|
||||
make clean > /dev/null
|
||||
$script_dir/nightly_config.sh $exp_tool
|
||||
make -j > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "AV1 build failed on experiment: " $exp_tool
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test_dir=~/Dev/nightly
|
||||
|
||||
cp -f ./aomenc $test_dir/.
|
||||
cp -f ./aomdec $test_dir/.
|
32
scripts/av1_config.sh
Executable file
32
scripts/av1_config.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
#set -x
|
||||
|
||||
if [ "$2" == "dbg" ]; then
|
||||
debug="--enable-debug --disable-optimizations"
|
||||
else
|
||||
debug=
|
||||
fi
|
||||
tool=--enable-$1
|
||||
|
||||
platform=x86_64-linux-gcc
|
||||
codec=--enable-av1
|
||||
libsrc=aom
|
||||
test_dir=~/Dev/info
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
|
||||
common="--disable-docs --enable-experimental"
|
||||
|
||||
#bd_config="--enable-lowbitdepth"
|
||||
#--disable-highbitdepth"
|
||||
|
||||
. $script_dir/disabled_list.sh
|
||||
|
||||
echo ../$libsrc/configure $debug $common $disabled $tool
|
||||
|
||||
../$libsrc/configure $debug $common $disabled $tool > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: configure fails!" > $test_dir/error_config.txt
|
||||
exit 1
|
||||
fi
|
||||
|
4
scripts/blue_sky_1080p25.sh
Normal file
4
scripts/blue_sky_1080p25.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
video=~/Dev/samples/videos/speed-set/blue_sky_1080p30.y4m
|
||||
fps="25/1"
|
28
scripts/cmake_build.txt
Normal file
28
scripts/cmake_build.txt
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
Regular build
|
||||
rm -rf ./* && cmake ../.. -DENABLE_WERROR=1 && make -j
|
||||
|
||||
Debug build without optimizations (can be used for Eclipse debugging):
|
||||
(Implies --disable-optimizations)
|
||||
|
||||
rm -rf ./* && cmake ../.. -DENABLE_WERROR=1 -DCMAKE_BUILD_TYPE=Debug && make -j
|
||||
|
||||
Debug build with optimizations on (should be used for performance analysis):
|
||||
rm -rf ./* && cmake ../.. -DENABLE_WERROR=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE='-O3 -g' -DCMAKE_CXX_FLAGS_RELEASE='-O3 -g' -DCMAKE_LD_FLAGS_RELEASE='-O3 -g' && make -j
|
||||
|
||||
Build with ASAN:
|
||||
rm -rf ./* && cmake ../.. -DSANITIZE=address -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug -DENABLE_CCACHE=1 && make -j
|
||||
|
||||
|
||||
Build with TSAN
|
||||
|
||||
rm -rf ./* && cmake ../.. -DSANITIZE=thread -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug && make -j
|
||||
|
||||
|
||||
Build with UBSAN
|
||||
|
||||
rm -rf ./* && cmake ../.. -DSANITIZE=integer -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS=-O1 -DCMAKE_CXX_FLAGS=-O1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXE_LINKER_FLAGS=-Wl,--start-group -DENABLE_CCACHE=1 && make -j
|
||||
|
||||
|
||||
rm -rf ./* && cmake ../.. -DSANITIZE=undefined -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS=-O1 -DCMAKE_CXX_FLAGS=-O1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXE_LINKER_FLAGS=-Wl,--start-group -DENABLE_CCACHE=1 && make -j
|
||||
|
22
scripts/confbuild.sh
Executable file
22
scripts/confbuild.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
root_dir=$1
|
||||
dist_dir=$2
|
||||
|
||||
build_dir=$root_dir/$dist_dir
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
exp_tool=experimental
|
||||
|
||||
cd $build_dir
|
||||
make clean > /dev/null
|
||||
$script_dir/av1_config.sh $exp_tool
|
||||
make -j > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "AV1 build failed on experiment: " $exp_tool
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# test_dir=~/Dev/nightly
|
||||
|
||||
# cp -f ./aomenc $test_dir/.
|
||||
# cp -f ./aomdec $test_dir/.
|
20
scripts/disabled_list.sh
Normal file
20
scripts/disabled_list.sh
Normal file
@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
# d2="--disable-ext_tx"
|
||||
# d3="--disable-cdef --disable-cdef-singlepass --disable-ext_intra"
|
||||
# d4="--disable-intra-edge --disable-mv_compress --disable-dual_filter"
|
||||
# #--disable-motion_var --disable-warped_motion"
|
||||
# #d5="--disable-wedge --disable-compound_segment"
|
||||
# d6="--disable-interintra --disable-one_sided_compound"
|
||||
# d7="--disable-convolve_round --disable-aom-qm --disable-dist_8x8"
|
||||
# d8="--disable-loop_restoration"
|
||||
# d9="--disable-ext-partition --disable-ext-partition-types"
|
||||
# d91="--disable-new-multisymbol"
|
||||
# d10="--disable-reference_buffer --disable-loopfiltering_across_tiles"
|
||||
# d11="--disable-palette_throughput --disable-smooth_hv --disable-tempmv_signaling"
|
||||
# d12="--disable-ext-comp-refs --disable-ext_delta_q --disable-parallel_deblocking"
|
||||
# d13="--disable-simple_bwd_adapt --disable-loopfilter-level"
|
||||
# d14="--disable-cfl --disable-deblock-13tap --disable-frame_marker --disable-kf_ctx"
|
||||
|
||||
#disabled="$d2 $d3 $d4 $d6 $d7 $d8 $d9 $91 $d10 $d11 $d12 $d13 $d14"
|
||||
disabled="--disable-adopted-experiments"
|
97
scripts/encode_exp_bs.sh
Executable file
97
scripts/encode_exp_bs.sh
Executable file
@ -0,0 +1,97 @@
|
||||
#!/bin/sh
|
||||
# File:
|
||||
# encode_exp_bs.sh
|
||||
# Decription:
|
||||
# This script fixes a video sequence and loops around an experimental list
|
||||
# defined by "exp_list"
|
||||
# see "encode_video_seq_bs.sh
|
||||
set -x
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
video_sequence=soccer_cif.sh
|
||||
else
|
||||
video_sequence=$1
|
||||
fi
|
||||
|
||||
root_dir=~/Dev/av1w
|
||||
code_dir=$root_dir/aom
|
||||
build_dir=$root_dir/release
|
||||
test_dir=~/Dev/field
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
bitstream_dir=~/Dev/samples/bitstreams/routine
|
||||
|
||||
. $script_dir/$video_sequence
|
||||
|
||||
videoname=$(basename $video_sequence .sh)
|
||||
|
||||
# General options
|
||||
Codec=av1
|
||||
codec="--codec=$Codec"
|
||||
verbose=
|
||||
|
||||
cd $code_dir
|
||||
#git checkout -q master
|
||||
#git pull -q
|
||||
commit_hash=`git log -1 --oneline | awk '{print $1}'`
|
||||
|
||||
cd $test_dir
|
||||
|
||||
d1="chroma_sub8x8 filter_7bit reference_buffer"
|
||||
d2="delta_q rect_tx global_motion ext_tx"
|
||||
d3="cdef ext_intra mv_compress ext_refs"
|
||||
d4="dual_filter motion_var warped_motion"
|
||||
d5="ext_delta_q loopfiltering_across_tiles ec_smallmul"
|
||||
d6="var_tx ext_inter wedge compound_segment"
|
||||
d7="interintra one_sided_compound smooth_hv"
|
||||
d8="parallel_deblocking rect_intra_pred convolve_round"
|
||||
d9="palette_throughput tempmv_signaling ext-comp-refs"
|
||||
|
||||
exp_list="$d1 $d2 $d3 $d4 $d5 $d6 $d7 $d8 $d9"
|
||||
#exp_list=experimental
|
||||
|
||||
constant_cmdline_options="--skip=0 -p 2 --good --cpu-used=0 --lag-in-frames=25 --min-q=0 --max-q=63 --auto-alt-ref=1 --kf-max-dist=150 --kf-min-dist=0 --drop-frame=0 --static-thresh=0 --bias-pct=50 --minsection-pct=0 --maxsection-pct=2000 --arnr-maxframes=7 --arnr-strength=5 --sharpness=0 --undershoot-pct=100 --overshoot-pct=100 --frame-parallel=0 --test-decode=warn --psnr"
|
||||
|
||||
wi=1920
|
||||
he=1080
|
||||
frames=150
|
||||
bitrate=4000
|
||||
|
||||
for exp_tool in $exp_list
|
||||
|
||||
do
|
||||
cd $build_dir
|
||||
make clean > /dev/null
|
||||
$script_dir/runconfig.sh $exp_tool
|
||||
make -j > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo Build failed on experiment: $exp_tool
|
||||
fi
|
||||
cp ./aomenc $test_dir/.
|
||||
cp ./aomdec $test_dir/.
|
||||
|
||||
cd $test_dir
|
||||
|
||||
if [ $exp_tool == intrabc ] || [ $exp_tool == palette ] || [ $exp_tool == palette_delta_encoding ] || [ $exp_tool == palette_throughput ]; then
|
||||
tune_content="--tune-content=screen"
|
||||
else
|
||||
tune_content=
|
||||
fi
|
||||
|
||||
if [ $exp_tool == ext_tile ]; then
|
||||
col_num=1
|
||||
else
|
||||
col_num=0
|
||||
fi
|
||||
|
||||
profile=0
|
||||
bs="$Codec.$exp_tool.$videoname.$commit_hash.$profile.webm"
|
||||
|
||||
./aomenc $verbose -o $bitstream_dir/$bs $video $codec --limit=$frames --profile=$profile --fps=$fps $tune_content --target-bitrate=$bitrate --tile-columns=$col_num $constant_cmdline_options
|
||||
|
||||
profile=2
|
||||
bs="$Codec.$exp_tool.$videoname.$commit_hash.$profile.webm"
|
||||
|
||||
./aomenc $verbose -o $bitstream_dir/$bs $video $codec --limit=$frames --profile=$profile --bit-depth=10 --fps=$fps $tune_content --target-bitrate=$bitrate --tile-columns=$col_num $constant_cmdline_options
|
||||
|
||||
rm ./aomenc ./aomdec
|
||||
done
|
96
scripts/encode_video_seq_bs.sh
Executable file
96
scripts/encode_video_seq_bs.sh
Executable file
@ -0,0 +1,96 @@
|
||||
#!/bin/sh
|
||||
# File:
|
||||
# encode_video_seq_bs.sh
|
||||
# Decription:
|
||||
# This script fixes an experiment and loops around on video sequences defined by
|
||||
# video_sequence_list.
|
||||
# Also see encode_exp_bs.sh
|
||||
set -x
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
exp_tool=experimental
|
||||
else
|
||||
exp_tool=$1
|
||||
fi
|
||||
|
||||
root_dir=~/Dev/aomedia
|
||||
code_dir=$root_dir/aom
|
||||
build_dir=$root_dir/release
|
||||
test_dir=~/Dev/field
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
bitstream_dir=~/Dev/samples/bitstreams/routine
|
||||
|
||||
# General options
|
||||
Codec=av1
|
||||
codec="--codec=$Codec"
|
||||
verbose=
|
||||
|
||||
cd $code_dir
|
||||
#git checkout -q master
|
||||
#git pull -q
|
||||
commit_hash=`git log -1 --oneline | awk '{print $1}'`
|
||||
|
||||
cd $test_dir
|
||||
|
||||
# d1="chroma_sub8x8 filter_7bit reference_buffer"
|
||||
# d2="delta_q rect_tx global_motion ext_tx"
|
||||
# d3="cdef ext_intra mv_compress ext_refs"
|
||||
# d4="dual_filter motion_var warped_motion"
|
||||
# d5="ext_delta_q loopfiltering_across_tiles"
|
||||
# d6="var_tx ext_inter wedge compound_segment"
|
||||
# d7="interintra one_sided_compound smooth_hv"
|
||||
# d8="parallel_deblocking rect_intra_pred convolve_round"
|
||||
# d9="palette_throughput tempmv_signaling ext-comp-refs"
|
||||
# Note: experimental list
|
||||
#exp_list="$d1 $d2 $d3 $d4 $d5 $d6 $d7 $d8 $d9"
|
||||
#exp_list=experimental
|
||||
|
||||
# Note: video sequence list
|
||||
#video_sequence_list="BQTerrace_1080p60.sh BasketballDrive_1080p50.sh ParkScene_1080p24.sh"
|
||||
#video_sequence_list="blue_sky_1080p25.sh rush_hour_1080p25.sh tennis_1080p24.sh"
|
||||
video_sequence_list="aerial_4k.sh"
|
||||
#video_sequence_list="BasketballDrive_1080p50.sh"
|
||||
|
||||
constant_cmdline_options="--skip=0 -p 2 --good --cpu-used=0 --lag-in-frames=25 --min-q=0 --max-q=63 --auto-alt-ref=1 --kf-max-dist=150 --kf-min-dist=0 --drop-frame=0 --static-thresh=0 --bias-pct=50 --minsection-pct=0 --maxsection-pct=2000 --arnr-maxframes=7 --arnr-strength=5 --sharpness=0 --undershoot-pct=100 --overshoot-pct=100 --frame-parallel=0 --test-decode=warn --psnr"
|
||||
col_num=0
|
||||
|
||||
# Note:
|
||||
# Here we have an overall chance to override the encoding input options
|
||||
# wi=1920
|
||||
# he=1080
|
||||
# frames=2
|
||||
# bitrate=4000
|
||||
|
||||
cd $build_dir
|
||||
make clean > /dev/null
|
||||
$script_dir/runconfig.sh $exp_tool
|
||||
make -j > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo Build failed on experiment: $exp_tool
|
||||
fi
|
||||
cp ./aomenc $test_dir/.
|
||||
cp ./aomdec $test_dir/.
|
||||
cd $test_dir
|
||||
|
||||
for video_sequence in $video_sequence_list
|
||||
do
|
||||
|
||||
. $script_dir/$video_sequence
|
||||
videoname=$(basename $video_sequence .sh)
|
||||
|
||||
# Note:
|
||||
# Here we have an chance to override the encoding input options per video sequence
|
||||
frames=50
|
||||
bitrate=14000
|
||||
|
||||
profile=0
|
||||
bs="$Codec.$exp_tool.$videoname.$commit_hash.f$frames.$profile.webm"
|
||||
|
||||
./aomenc $verbose -o $bitstream_dir/$bs $video $codec --limit=$frames --profile=$profile --fps=$fps $tune_content --target-bitrate=$bitrate --tile-columns=$col_num $constant_cmdline_options
|
||||
|
||||
# profile=2
|
||||
# bs="$Codec.$exp_tool.$videoname.$commit_hash.f$frames.$profile.webm"
|
||||
|
||||
# ./aomenc $verbose -o $bitstream_dir/$bs $video $codec --limit=$frames --profile=$profile --bit-depth=10 --fps=$fps $tune_content --target-bitrate=$bitrate --tile-columns=$col_num $constant_cmdline_options
|
||||
|
||||
done
|
5
scripts/gen_html_footer.sh
Executable file
5
scripts/gen_html_footer.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "</html>"
|
||||
echo "</body>"
|
||||
|
18
scripts/gen_html_header.sh
Executable file
18
scripts/gen_html_header.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "<!DOCTYPE html>"
|
||||
echo "<html>"
|
||||
echo "<head>"
|
||||
echo "<style>"
|
||||
echo "table, th, td {"
|
||||
echo " border: 1px solid black;"
|
||||
echo " border-collapse: collapse;"
|
||||
echo "}"
|
||||
echo "th, td {"
|
||||
echo " padding: 5px;"
|
||||
echo " text-align: left;"
|
||||
echo "}"
|
||||
echo "</style>"
|
||||
echo "</head>"
|
||||
echo "<body>"
|
||||
|
132
scripts/git.txt
Normal file
132
scripts/git.txt
Normal file
@ -0,0 +1,132 @@
|
||||
#########################################################
|
||||
# My personal GIT tips
|
||||
#########################################################
|
||||
|
||||
(1) Squash several commit into one (consolitation)
|
||||
# Note:
|
||||
# Between HEAD and 3 is tilde sign
|
||||
$ git rebase -i HEAD~3
|
||||
# step 1: In pop-up editor (emacs), "pick" the earliest one and squash all the rest.
|
||||
# step 2: In second pop-up editor, edit the commit message and save, exit.
|
||||
|
||||
|
||||
(2) Pull the latest changes (sometime it is a fix/required) and put it under
|
||||
# your working commit
|
||||
$ git pull --rebase
|
||||
# if there are any conflicts, you need edit the conflicted files manually. then
|
||||
$ git add <conflict and edited files>
|
||||
$ git rebase --continue
|
||||
|
||||
# Note: Don't do git commit between "git add" and "git rebase --continue",
|
||||
if you did, then you need git rebase --abort and come over.
|
||||
|
||||
# Another way (?) from Su Hui
|
||||
$ git fetch
|
||||
$ git rebase -i origin/nextgenv2
|
||||
# -i ?, the following works:
|
||||
$ git rebase origin/nextgenv2
|
||||
# if there are any conflicts, you need edit the conflicted files manually. Sometimes
|
||||
# need to diff against change in another repos or blame the conflict file to see the
|
||||
# change.
|
||||
$ git add <conflict and edited file>
|
||||
$ git rebase --continue
|
||||
|
||||
|
||||
(3) Create a branch from a older commit
|
||||
# Create a branch from the top and specify the targeted remote branch
|
||||
# Typically I need to create a branch for new code construction
|
||||
$ git checkout -b <branch_name> <origin/nextgenv2>
|
||||
|
||||
# Typically I need to create a branch for performance test base (seat)
|
||||
$ git checkout -b <branch_name> <commit>
|
||||
|
||||
|
||||
(4) Restore the local top to <commit>
|
||||
# Delete the current top commit
|
||||
$ git reset --hard <commit>
|
||||
|
||||
# Delete the current failed merge/modification
|
||||
$ git reset --hard
|
||||
|
||||
|
||||
(5) Diff a commit against its parent
|
||||
$ git diff <commit>^!
|
||||
|
||||
# Diff HEAD agaist its parent
|
||||
$ git diff HEAD^!
|
||||
|
||||
|
||||
(6) Restore one file from previous commit and fix latest commit
|
||||
$ git checkout <commit> <filename>
|
||||
$ git commit --amend
|
||||
|
||||
|
||||
(7) Merge a commit from master branch to another branch
|
||||
$ git checkout <branch>
|
||||
# use cherry pick. Please make sure the <branch> is clean and latest
|
||||
$ git fetch https://chromium.googlesource.com/webm/libvpx refs/changes/18/336818/3 && git cherry-pick FETCH_HEAD
|
||||
# if there is no conflict, it automatically merge (if successfull) with local. And
|
||||
# the commit appears if do "git log"
|
||||
# if there is conflict, need to merge manually and $ git commit -a --amend (i guess)
|
||||
|
||||
|
||||
(8) Cherry pick
|
||||
# This way we add an extra line (reference to the picked commit)
|
||||
$ git cherry-pick -x <commit hash>
|
||||
|
||||
|
||||
(9) Sandbox push
|
||||
First ask Admin to create a sandbox (remote branch) for you.
|
||||
# Work in local from git init, git commit ....
|
||||
# Initial push:
|
||||
# Here we use "head" instead of "for", "for" is for review board. Please note:
|
||||
# we use -f
|
||||
$ git push -f https://chromium-review.googlesource.com/webm/libvpx HEAD:refs/heads/sandbox/luoyi@google.com/convolve
|
||||
$ git checkout -b sandbox/luoyi@google.com/convolve
|
||||
|
||||
# check it out:
|
||||
$ git checkout -b codestore origin/sandbox/luoyi@google.com/convolve
|
||||
|
||||
# Push
|
||||
# Run git push, then the error message would show you two ways. The first way works. See following:
|
||||
$ git push origin HEAD:sandbox/luoyi@google.com/convolve
|
||||
|
||||
(10) Revert a change
|
||||
$ git checkout <commit hash> <filename>
|
||||
Revert a file at <commit hash> to index
|
||||
|
||||
(11) Diff current staged file (ready to commit) against a previous commit version
|
||||
$ git diff --cached <commit hash> <path/file>
|
||||
|
||||
(12) Setup a branch for continuing work
|
||||
# On a branch named: branch_name1,
|
||||
$ git checkout -b <branch_name2>
|
||||
$ git branch -u origin/nextgenv2
|
||||
# latest commit may not be merged yet. So after local check-in, can we do
|
||||
cherry-pick later from branch_name2 to branch_name1?
|
||||
|
||||
(13) Generate and Apply a patch
|
||||
$ git diff --no-ext-diff > my.diff
|
||||
$ git apply my.diff
|
||||
|
||||
(14) git log --pretty=format:"%h %an %cd %s" --date=short
|
||||
git log --pretty=fuller
|
||||
|
||||
(15) git rebase -i origin/master
|
||||
Remove current unwanted base patch
|
||||
Pull in latest patches
|
||||
|
||||
########################################################
|
||||
# Trivial tips now
|
||||
########################################################
|
||||
(1) Push for a review
|
||||
$ git push https://chromium-review.googlesource.com/webm/libvpx HEAD:refs/for/nextgenv2
|
||||
or
|
||||
$ review_push.sh
|
||||
|
||||
(2) Show git remote repo
|
||||
$ git remote show origin
|
||||
|
||||
(3) Check codebase's tag information
|
||||
$ git tag
|
||||
$ git rev-list -n1 v0.1.0
|
8
scripts/into_tree.sh
Normal file
8
scripts/into_tree.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
video=~/Dev/samples/videos/midres/into_tree_480p.y4m
|
||||
wide=
|
||||
high=
|
||||
frames=2
|
||||
bitrate=600
|
||||
fps="50/1"
|
110
scripts/list_exp_speed.sh
Executable file
110
scripts/list_exp_speed.sh
Executable file
@ -0,0 +1,110 @@
|
||||
#!/bin/sh
|
||||
# File:
|
||||
# list_exp_speed.sh
|
||||
# Decription:
|
||||
# Configure, build, and run encoder/decoder for each experimental tool.
|
||||
# Display the encoder/decode run time
|
||||
# Preassumption:
|
||||
# 1) Assume all script files are in ~/Dev/sandbox/libvpx/scripts
|
||||
# Note:
|
||||
# See encoder config output if set,
|
||||
# verbose=-v
|
||||
#set -x
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
root_dir=~/Dev/av1w
|
||||
else
|
||||
root_dir=$1
|
||||
fi
|
||||
|
||||
code_dir=$root_dir/aom
|
||||
build_dir=$root_dir/release
|
||||
test_dir=~/Dev/weekly
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
. $script_dir/video_sequence_weekly.sh
|
||||
|
||||
# General options
|
||||
bitstream_prefix=av1
|
||||
codec="--codec=av1"
|
||||
verbose=
|
||||
|
||||
# LBD or HBD
|
||||
# Note:
|
||||
# Standard bit depth:
|
||||
# 1) profile=0
|
||||
# 2) remove $bitdepth in encoder command line
|
||||
# 3) Change runconfig.sh, bitdepth=
|
||||
# High bit depth:
|
||||
# 1) profile=2
|
||||
# 2) Add $bitdepth in encoder command line, e.g. bitdepth="--bit-depth=10"
|
||||
# 3) Change runconfig.sh, bitdepth=--enable-highbitdepth
|
||||
|
||||
profile=0
|
||||
|
||||
cd $test_dir
|
||||
rm *.txt
|
||||
|
||||
for exp_tool in experimental chroma_sub8x8 reference_buffer rect_tx global_motion ext_tx cdef ext_intra mv_compress ext_refs dual_filter motion_var warped_motion var_tx wedge compound_segment interintra one_sided_compound ext-comp-refs smooth_hv parallel_deblocking convolve_round altref2 adapt_scan intra_edge ext_partition loop_restoration
|
||||
|
||||
# palette_throughput tempmv_signaling ext_delta_q ec_smallmul aom_qm dist_8x8 loop_restoration
|
||||
|
||||
do
|
||||
cd $build_dir
|
||||
make clean > /dev/null
|
||||
$script_dir/runconfig.sh $exp_tool
|
||||
make -j > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo Build failed on experiment: $exp_tool
|
||||
fi
|
||||
cp ./aomenc $test_dir/.
|
||||
cp ./aomdec $test_dir/.
|
||||
|
||||
cd $test_dir
|
||||
|
||||
elog=e_$exp_tool.txt
|
||||
dlog=d_$exp_tool.txt
|
||||
bs=$bitstream_prefix.$exp_tool.webm
|
||||
|
||||
if [ $exp_tool == intrabc ] || [ $exp_tool == palette ] || [ $exp_tool == palette_delta_encoding ] || [ $exp_tool == palette_throughput ]; then
|
||||
tune_content="--tune-content=screen"
|
||||
else
|
||||
tune_content=
|
||||
fi
|
||||
|
||||
if [ $exp_tool == ext_tile ]; then
|
||||
col_num=1
|
||||
else
|
||||
col_num=0
|
||||
fi
|
||||
|
||||
taskset -c 3 ./aomenc $verbose -o /dev/shm/$bs $video $codec --limit=$frames --profile=$profile --fps=$fps $tune_content --target-bitrate=$bitrate --skip=0 -p 2 --good --cpu-used=0 --lag-in-frames=25 --min-q=0 --max-q=63 --auto-alt-ref=1 --kf-max-dist=150 --kf-min-dist=0 --drop-frame=0 --static-thresh=0 --bias-pct=50 --minsection-pct=0 --maxsection-pct=2000 --arnr-maxframes=7 --arnr-strength=5 --sharpness=0 --undershoot-pct=100 --overshoot-pct=100 --frame-parallel=0 --tile-columns=$col_num --test-decode=warn --psnr &>> $elog
|
||||
|
||||
# Note: $2 is the time unit, ms or us
|
||||
#etime=`cat $elog | grep 'Pass 2/2' | grep 'fps)' | sed -e 's/^.*b\/s//' | awk '{print $1" "$2}'`
|
||||
etime=`cat $elog | grep 'Pass 2/2' | grep 'fps)' | sed -e 's/^.*b\/s//' | awk '{print $1" "}'`
|
||||
|
||||
psnr=`cat $elog | grep 'PSNR' | awk '{print $5, $6, $7, $8, $9}'`
|
||||
tmp=`cat $elog | grep mismatch`
|
||||
if [ "$?" -ne 0 ]; then
|
||||
eflag=e_ok
|
||||
else
|
||||
eflag=mismatch
|
||||
fi
|
||||
|
||||
taskset -c 3 ./aomdec /dev/shm/$bs $codec --i420 --noblit --summary 2>&1 &>> $dlog
|
||||
if [ "$?" -ne 0 ]; then
|
||||
dflag=fault
|
||||
else
|
||||
dflag=d_ok
|
||||
fi
|
||||
|
||||
# Note: $8 is the time unit ms or us
|
||||
#dtime=`awk '{print $7" "$8}' < $dlog`
|
||||
dtime=`awk '{print $7" "}' < $dlog`
|
||||
|
||||
echo -e $exp_tool '\t'$etime'\t'$dtime'\t'$psnr'\t'$eflag'\t'$dflag
|
||||
|
||||
rm ./aomenc ./aomdec
|
||||
done
|
||||
|
102
scripts/list_exp_speed_hbd.sh
Executable file
102
scripts/list_exp_speed_hbd.sh
Executable file
@ -0,0 +1,102 @@
|
||||
#!/bin/sh
|
||||
# File:
|
||||
# list_exp_speed.sh
|
||||
# Decription:
|
||||
# Configure, build, and run encoder/decoder for each experimental tool.
|
||||
# Display the encoder/decode run time
|
||||
# Note:
|
||||
# See encoder config output if set,
|
||||
# verbose=-v
|
||||
|
||||
root_dir=~/Dev/experiment
|
||||
code_dir=$root_dir/aom
|
||||
build_dir=$root_dir/release
|
||||
test_dir=~/Dev/field
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
# video=~/Dev/samples/videos/yaowu/soccer_cif.y4m
|
||||
# wi=352
|
||||
# he=288
|
||||
# frames=5
|
||||
# bitrate=500
|
||||
# fps="30/1"
|
||||
|
||||
video=~/Videos/aom/park_joy/park_joy_360p_10.y4m
|
||||
wi=640
|
||||
he=360
|
||||
frames=5
|
||||
bitrate=800
|
||||
fps="50/1"
|
||||
|
||||
# video=~/Dev/samples/videos/speed-set/touchdown_pass_480p.y4m
|
||||
# wi=854
|
||||
# he=480
|
||||
# frames=100
|
||||
# bitrate=1200
|
||||
# fps="30000/1001"
|
||||
|
||||
# video=~/Dev/samples/videos/hbd/crowd_run_1080p_10.y4m
|
||||
# wi=1920
|
||||
# he=1080
|
||||
# frames=100
|
||||
# bitrate=8000
|
||||
# fps="50/1"
|
||||
|
||||
bs=bs
|
||||
codec="--codec=av1"
|
||||
verbose=
|
||||
|
||||
# Note:
|
||||
# Standard bit depth:
|
||||
# 1) profile=0
|
||||
# 2) remove $bitdepth in encoder command line
|
||||
# 3) Change runconfig.sh, bitdepth=
|
||||
# High bit depth:
|
||||
# 1) profile=2
|
||||
# 2) Add $bitdepth in encoder command line
|
||||
# 3) Change runconfig.sh, bitdepth=--enable-aom-highbitdepth
|
||||
|
||||
profile=2
|
||||
bitdepth="--bit-depth=10"
|
||||
|
||||
rm *.txt
|
||||
# experimental ans var-tx entropy ext-intra filter-intra supertx ext-interp motion-var new-quant dual-filter ext-partition-types ext-partition ext-inter ext-tx ext-refs rect-tx global-motion loop-restoration
|
||||
|
||||
#for exp_tool in experimental var_tx tpl_mv dual_filter convolve_round ext_tx tx64x64 sub8x8_mc ext_intra intra_interp filter_intra ext_inter interintra wedge compound_segment ext_refs global_motion new_quant supertx ans new_tokenset loop_restoration ext_partition ext_partition_types unpoison_partition_ctx ext_tile motion_var ncobmc warped_motion entropy q_adapt_probs subframe_prob_update bitstream_debug rawbits pvq xiphrc cb4x4 chroma_2x2 frame_size parallel_deblocking parallel_deblocking_15tap loopfiltering_across_tiles ec_adapt tempmv_signaling coef_interleave entropy_stats masked_tx dependent_horztiles daala_dist tripred palette_throughput ref_adapt lv_map mv_compress frame_superres new_multisymbol
|
||||
|
||||
# loop-restoration new_tokenset (may have issues)
|
||||
|
||||
#compound-segment ncobmc warped_motion q_adapt_probs convolve_round var-tx ans entropy ext-intra filter-intra supertx motion-var new-quant dual-filter ext-partition-types ext-partition ext-inter ext-refs ext-tx
|
||||
# experimental global-motion cb4x4 tpl-mv sub8x8_mc interintra wedge
|
||||
for exp_tool in compound-segment ncobmc warped_motion q_adapt_probs convolve_round var-tx ans entropy ext-intra filter-intra supertx motion-var new-quant dual-filter ext-partition-types ext-partition ext-inter ext-refs ext-tx
|
||||
|
||||
do
|
||||
cd $build_dir
|
||||
make clean > /dev/null
|
||||
$script_dir/runconfig_hbd.sh $exp_tool
|
||||
make -j > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo Build failed on experiment: $exp_tool
|
||||
fi
|
||||
cp ./aomenc $test_dir/.
|
||||
cp ./aomdec $test_dir/.
|
||||
|
||||
cd $test_dir
|
||||
elog=e_$exp_tool.txt
|
||||
dlog=d_$exp_tool.txt
|
||||
bs=$bs_$exp_tool.webm
|
||||
|
||||
./aomenc -o $bs $video $codec --limit=$frames --skip=0 -p 2 --good --cpu-used=0 --target-bitrate=$bitrate --lag-in-frames=25 --min-q=0 --max-q=63 --auto-alt-ref=1 --kf-max-dist=150 --kf-min-dist=0 --drop-frame=0 --static-thresh=0 --bias-pct=50 --minsection-pct=0 --maxsection-pct=2000 --arnr-maxframes=7 --arnr-strength=5 --sharpness=0 --undershoot-pct=100 --overshoot-pct=100 --frame-parallel=0 --tile-columns=0 --profile=$profile $bitdepth --test-decode=warn $verbose --psnr &>> $elog
|
||||
|
||||
etime=`cat $elog | grep 'Pass 2/2' | grep 'fps' | sed -e 's/^.*b\/s//' | awk '{print $1" " $2}'`
|
||||
psnr=`cat $elog | grep 'PSNR' | awk '{print $5, $6, $7, $8, $9}'`
|
||||
|
||||
./aomdec $bs $codec --i420 -o frm_%wx%h_$exp_tool.yuv %w $wi %h $he --summary 2>&1 &>> $dlog
|
||||
|
||||
dtime=`awk '{print $7" "$8}' < $dlog`
|
||||
echo -e $exp_tool'\t'$etime '\t'$dtime'\t'$psnr
|
||||
|
||||
done
|
||||
|
||||
|
||||
|
11
scripts/manemail.sh
Executable file
11
scripts/manemail.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
# Note:
|
||||
# - With any path, be very careful to type the report HTML file name.
|
||||
# - Use prodcertstatus --show_expiration_time to see when ticket expires.
|
||||
#
|
||||
|
||||
report_html=$1
|
||||
report_path=/usr/local/google/home/luoyi/Dev/log
|
||||
report_send=$report_path/$report_html
|
||||
|
||||
sendgmr --to=luoyi --cc=yunqingwang,vpx-eng --from=luoyi --reply_to=luoyi --subject="AV1 Nightly Speed Report" --html_file=$report_send --body_file=$report_send
|
22
scripts/nightly_config.sh
Executable file
22
scripts/nightly_config.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
#set -x
|
||||
|
||||
platform=x86_64-linux-gcc
|
||||
codec=--enable-av1
|
||||
libsrc=aom
|
||||
test_dir=~/Dev/nightly
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
tool=--enable-$1
|
||||
common="--disable-unit-tests --disable-docs --enable-experimental"
|
||||
debug=
|
||||
|
||||
. $script_dir/disabled_list.sh
|
||||
|
||||
echo ../$libsrc/configure $debug $common $disabled $tool
|
||||
|
||||
../$libsrc/configure $debug $common $disabled $tool > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: configure fails!" > $test_dir/error_config.txt
|
||||
exit 1
|
||||
fi
|
63
scripts/nightly_run.sh
Executable file
63
scripts/nightly_run.sh
Executable file
@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
script_path=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
av1_code=~/Dev/av1d
|
||||
vp9_code=~/Dev/vp9d
|
||||
|
||||
log_path=~/Dev/log
|
||||
|
||||
date_str=`date -d tomorrow +%b_%d_%Y`
|
||||
log_file=report_$date_str.txt
|
||||
html_log_file=report_$date_str.html
|
||||
|
||||
prev_date_str=`date +%b_%d_%Y`
|
||||
prev_log_file=report_$prev_date_str.txt
|
||||
|
||||
test_dir=~/Dev/nightly
|
||||
rm $test_dir/*
|
||||
|
||||
$script_path/gen_html_header.sh > $log_path/$html_log_file
|
||||
|
||||
# AV1
|
||||
echo "<p>" >> $log_path/$html_log_file
|
||||
$script_path/sync_codebase.sh $av1_code/aom >> $log_path/$html_log_file 2>&1
|
||||
echo "</p>" >> $log_path/$html_log_file
|
||||
|
||||
echo "<p>" >> $log_path/$html_log_file
|
||||
$script_path/av1_conf_build.sh $av1_code >> $log_path/$html_log_file 2>&1
|
||||
echo "</p>" >> $log_path/$html_log_file
|
||||
|
||||
pdfps=`cat $log_path/$prev_log_file | grep e_ok | awk '{print $2}' | awk 'NR==1 {print $1}'`
|
||||
$script_path/nightly_speed.sh $av1_code 0 $pdfps $html_log_file >> $log_path/$log_file 2>&1
|
||||
|
||||
pdfps=`cat $log_path/$prev_log_file | grep e_ok | awk '{print $2}' | awk 'NR==2 {print $1}'`
|
||||
$script_path/nightly_speed.sh $av1_code 2 $pdfps $html_log_file >> $log_path/$log_file 2>&1
|
||||
|
||||
# VP9
|
||||
echo "<p>" >> $log_path/$html_log_file
|
||||
$script_path/sync_codebase.sh $vp9_code/libvpx >> $log_path/$html_log_file 2>&1
|
||||
echo "</p>" >> $log_path/$html_log_file
|
||||
|
||||
echo "<p>" >> $log_path/$html_log_file
|
||||
$script_path/vp9_conf_build.sh $vp9_code lowbitdepth >> $log_path/$html_log_file 2>&1
|
||||
echo "</p>" >> $log_path/$html_log_file
|
||||
|
||||
pdfps=`cat $log_path/$prev_log_file | grep e_ok | awk '{print $2}' | awk 'NR==3 {print $1}'`
|
||||
$script_path/vp9_nightly_speed.sh $vp9_code 0 $pdfps $html_log_file >> $log_path/$log_file 2>&1
|
||||
|
||||
echo "<p>" >> $log_path/$html_log_file
|
||||
$script_path/vp9_conf_build.sh $vp9_code highbitdepth >> $log_path/$log_file 2>&1
|
||||
echo "</p>" >> $log_path/$html_log_file
|
||||
|
||||
pdfps=`cat $log_path/$prev_log_file | grep e_ok | awk '{print $2}' | awk 'NR==4 {print $1}'`
|
||||
$script_path/vp9_nightly_speed.sh $vp9_code 2 $pdfps $html_log_file >> $log_path/$log_file 2>&1
|
||||
|
||||
users=luoyi
|
||||
host_name=`hostname`
|
||||
sender=luoyi
|
||||
cc_list="--cc=yunqingwang,vpx-eng"
|
||||
|
||||
$script_path/gen_html_footer.sh >> $log_path/$html_log_file
|
||||
|
||||
sendgmr --to=$users $cc_list --subject="Codec Daily Report" --from=$sender --reply_to=$sender --html_file=/usr/local/google/home/luoyi/Dev/log/$html_log_file --body_file=/usr/local/google/home/luoyi/Dev/log/$html_log_file
|
134
scripts/nightly_speed.sh
Executable file
134
scripts/nightly_speed.sh
Executable file
@ -0,0 +1,134 @@
|
||||
#!/bin/sh
|
||||
# File:
|
||||
# nightly_speed.sh
|
||||
# Decription:
|
||||
# Configure, build, and run AV1 encoder/decoder for each experimental tool.
|
||||
# Display the encoder/decode run time
|
||||
# Preassumption:
|
||||
# 1) Assume all script files are in ~/Dev/sandbox/libvpx/scripts
|
||||
# Note:
|
||||
# See encoder config output if set,
|
||||
# verbose=-v
|
||||
#set -x
|
||||
|
||||
# LBD or HBD
|
||||
# Note:
|
||||
# Standard bit depth:
|
||||
# 1) profile=0
|
||||
# 2) bitdepth=
|
||||
# High bit depth:
|
||||
# 1) profile=2
|
||||
# 2) bitdepth="--bit-depth=10/12"
|
||||
|
||||
if [ "$#" -ne 4 ]; then
|
||||
root_dir=~/Dev/av1d
|
||||
profile=0
|
||||
pdfps=1
|
||||
html_log_file=log.html
|
||||
else
|
||||
root_dir=$1
|
||||
profile=$2
|
||||
pdfps=$3
|
||||
html_log_file=$4
|
||||
fi
|
||||
log_path=~/Dev/log
|
||||
|
||||
if [ "$profile" == "2" ]; then
|
||||
bitdepth="--bit-depth=10"
|
||||
fi
|
||||
|
||||
if [ "$profile" == "0" ]; then
|
||||
bitdepth=
|
||||
fi
|
||||
|
||||
code_dir=$root_dir/aom
|
||||
build_dir=$root_dir/release
|
||||
test_dir=~/Dev/nightly
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
. $script_dir/video_sequence.sh
|
||||
|
||||
# General options
|
||||
codec="--codec=av1"
|
||||
verbose=
|
||||
core_id=1
|
||||
exp_tool=experimental
|
||||
|
||||
cd $root_dir/aom
|
||||
commit=`git log --pretty=%h -1`
|
||||
|
||||
cd $test_dir
|
||||
|
||||
elog=av1enc_log_p_$profile.txt
|
||||
dlog=av1dec_log_p_$profile.txt
|
||||
bstream=av1_p_$profile.$commit.webm
|
||||
|
||||
if [ $exp_tool == intrabc ] || [ $exp_tool == palette ] || [ $exp_tool == palette_delta_encoding ] || [ $exp_tool == palette_throughput ]; then
|
||||
tune_content="--tune-content=screen"
|
||||
else
|
||||
tune_content=
|
||||
fi
|
||||
|
||||
if [ $exp_tool == ext_tile ]; then
|
||||
col_num=1
|
||||
else
|
||||
col_num=0
|
||||
fi
|
||||
|
||||
laginframes=19
|
||||
|
||||
taskset -c $core_id ./aomenc $verbose -o /dev/shm/"$bstream" $video $codec --limit=$frames --profile=$profile $bitdepth --fps=$fps $tune_content --target-bitrate=$bitrate --skip=0 -p 2 --good --cpu-used=0 --lag-in-frames=$laginframes --min-q=0 --max-q=63 --auto-alt-ref=1 --kf-max-dist=150 --kf-min-dist=0 --drop-frame=0 --static-thresh=0 --bias-pct=50 --minsection-pct=0 --maxsection-pct=2000 --arnr-maxframes=7 --arnr-strength=5 --sharpness=0 --undershoot-pct=100 --overshoot-pct=100 --frame-parallel=0 --tile-columns=$col_num --psnr &>> $elog
|
||||
|
||||
# Note: $2 is the time unit, ms or us
|
||||
etime=`cat $elog | awk 'NR==2 {NF-=3; print $NF}'`
|
||||
# efps=`cat $elog | grep 'Pass 2/2' | grep 'fps)' | sed -e 's/^.*b\/s//' | awk '{print $3}'`
|
||||
# efps=`echo $efps | sed 's/(//'`
|
||||
|
||||
psnr=`cat $elog | grep 'PSNR' | awk '{print $5, $6, $7, $8, $9}'`
|
||||
tmp=`cat $elog | grep mismatch`
|
||||
if [ "$?" -ne 0 ]; then
|
||||
eflag=e_ok
|
||||
else
|
||||
eflag=mismatch
|
||||
fi
|
||||
|
||||
echo "AV1: $(basename $video), bitrate=$bitrate profile=$profile frames=$frames"
|
||||
|
||||
taskset -c $core_id ./aomdec /dev/shm/"$bstream" $codec --i420 --noblit --summary 2>&1 &>> $dlog
|
||||
if [ "$?" -ne 0 ]; then
|
||||
dflag=fault
|
||||
else
|
||||
dflag=d_ok
|
||||
fi
|
||||
|
||||
# Note: $8 is the time unit ms or us
|
||||
dfps=`awk '{print $9}' < $dlog`
|
||||
dfps=`echo $dfps | sed 's/(//'`
|
||||
|
||||
percent=`echo "($dfps - $pdfps) / $pdfps * 100" | bc -l`
|
||||
percent=${percent:0:5}
|
||||
|
||||
echo -e '\t'"Enc fps Dec fps PSNR"'\t\t\t\t\t\t\t'"Enc status Dec status Speedup(%)"
|
||||
echo -e '\t'$etime" "$dfps" "$psnr'\t'$eflag" "$dflag" "$percent
|
||||
printf "\n"
|
||||
|
||||
# Output a html log file for email
|
||||
echo "<p> AV1: $(basename $video), bitrate=$bitrate profile=$profile frames=$frames </p>" >> $log_path/$html_log_file
|
||||
echo "<table style=\"width:100%\">" >> $log_path/$html_log_file
|
||||
echo " <tr>" >> $log_path/$html_log_file
|
||||
echo " <th>Enc Time</th>" >> $log_path/$html_log_file
|
||||
echo " <th>Dec fps</th>" >> $log_path/$html_log_file
|
||||
echo " <th>Dec Speedup(%)</th>" >> $log_path/$html_log_file
|
||||
echo " <th>Enc Status</th>" >> $log_path/$html_log_file
|
||||
echo " <th>Dec Status</th>" >> $log_path/$html_log_file
|
||||
echo " <th>PSNR</th>" >> $log_path/$html_log_file
|
||||
echo " </tr>" >> $log_path/$html_log_file
|
||||
echo " <tr>" >> $log_path/$html_log_file
|
||||
echo " <td>$etime</td>" >> $log_path/$html_log_file
|
||||
echo " <td>$dfps</td>" >> $log_path/$html_log_file
|
||||
echo " <td>$percent</td>" >> $log_path/$html_log_file
|
||||
echo " <td>$eflag</td>" >> $log_path/$html_log_file
|
||||
echo " <td>$dflag</td>" >> $log_path/$html_log_file
|
||||
echo " <td>$psnr</td>" >> $log_path/$html_log_file
|
||||
echo " </tr>" >> $log_path/$html_log_file
|
||||
echo "</table>" >> $log_path/$html_log_file
|
94
scripts/profile_exp_speed_hbd.sh
Executable file
94
scripts/profile_exp_speed_hbd.sh
Executable file
@ -0,0 +1,94 @@
|
||||
#!/bin/sh
|
||||
# File:
|
||||
# profile_exp_speed_hbd.sh
|
||||
# Decription:
|
||||
# Configure, build, and run encoder/decoder perf for each experimental tool.
|
||||
# Save the decoder perf data
|
||||
# Note:
|
||||
# - use perf 4.4.0
|
||||
# - see encoder config output if set, verbose=-v
|
||||
|
||||
root_dir=~/Dev/aomedia
|
||||
code_dir=$root_dir/aom
|
||||
build_dir=$root_dir/release
|
||||
test_dir=~/Dev/field
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
# video=~/Dev/samples/videos/yaowu/soccer_cif.y4m
|
||||
# wi=352
|
||||
# he=288
|
||||
# frames=25
|
||||
# bitrate=500
|
||||
# fps="30/1"
|
||||
|
||||
# video=~/Dev/samples/videos/speed-set/touchdown_pass_480p.y4m
|
||||
# wi=854
|
||||
# he=480
|
||||
# frames=100
|
||||
# bitrate=1200
|
||||
# fps="30000/1001"
|
||||
|
||||
video=~/Dev/samples/videos/hbd/crowd_run_1080p_10.y4m
|
||||
wi=1920
|
||||
he=1080
|
||||
frames=300
|
||||
bitrate=6000
|
||||
fps="50/1"
|
||||
|
||||
codec="--codec=av1"
|
||||
verbose=
|
||||
|
||||
# Note:
|
||||
# Standard bit depth:
|
||||
# 1) profile=0
|
||||
# 2) remove $bitdepth in encoder command line
|
||||
# 3) Change runconfig.sh, bitdepth=
|
||||
# High bit depth:
|
||||
# 1) profile=2
|
||||
# 2) Add $bitdepth in encoder command line
|
||||
# 3) Change runconfig.sh, bitdepth=--enable-aom-highbitdepth
|
||||
|
||||
profile=2
|
||||
bitdepth="--bit-depth=10"
|
||||
|
||||
rm *.txt
|
||||
|
||||
#experimental var-tx ans entropy
|
||||
#ext-intra filter-intra
|
||||
#supertx ext-interp motion-var
|
||||
#new-quant dual-filter ext-partition-types
|
||||
#ext-partition ext-inter ext-refs
|
||||
#ext-tx rect-tx global-motion
|
||||
#loop-restoration alt-intra cb4x4
|
||||
|
||||
for exp_tool in supertx ext-interp motion-var new-quant dual-filter ext-partition-types ext-partition ext-inter ext-refs ext-tx rect-tx global-motion loop-restoration alt-intra cb4x4
|
||||
|
||||
do
|
||||
cd $build_dir
|
||||
make clean > /dev/null
|
||||
$script_dir/runconfig_hbd.sh $exp_tool
|
||||
make -j > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo Build failed on experiment: $exp_tool
|
||||
fi
|
||||
cp ./aomenc $test_dir/.
|
||||
cp ./aomdec $test_dir/.
|
||||
|
||||
cd $test_dir
|
||||
elog=e_$exp_tool.txt
|
||||
dlog=d_$exp_tool.txt
|
||||
|
||||
echo $exp_tool >> $elog
|
||||
bitstream=bs_$exp_tool.webm
|
||||
echo $exp_tool
|
||||
|
||||
./aomenc -o $bitstream $video $codec --limit=$frames --fps=$fps $verbose --profile=$profile $bitdepth --target-bitrate=$bitrate --skip=0 -p 2 --good --cpu-used=0 --lag-in-frames=25 --min-q=0 --max-q=63 --auto-alt-ref=1 --kf-max-dist=150 --kf-min-dist=0 --drop-frame=0 --static-thresh=0 --bias-pct=50 --minsection-pct=0 --maxsection-pct=2000 --arnr-maxframes=7 --arnr-strength=5 --sharpness=0 --undershoot-pct=100 --overshoot-pct=100 --frame-parallel=0 --tile-columns=0 --psnr
|
||||
|
||||
#perf_file=dec_perf_$exp_tool.data
|
||||
|
||||
#/usr/bin/perf record -e cycles -o $perf_file ./aomdec $bitstream -o too.yuv --summary
|
||||
|
||||
done
|
||||
|
||||
|
||||
|
88
scripts/runconfig.sh
Executable file
88
scripts/runconfig.sh
Executable file
@ -0,0 +1,88 @@
|
||||
#!/bin/sh
|
||||
|
||||
platform=x86_64-linux-gcc
|
||||
codec=--enable-av1
|
||||
libsrc=aom
|
||||
script_dir=~/Dev/sandbox/libvpx/scripts
|
||||
|
||||
experiment_dependency() {
|
||||
tool=--enable-$1
|
||||
|
||||
if [ "$1" == ec_adapt ]; then
|
||||
tool="--enable-$1 --enable-ext-inter"
|
||||
fi
|
||||
|
||||
if [ "$1" == ec_multisymbol ]; then
|
||||
tool="--enable-$1 --enable-daala-ec"
|
||||
fi
|
||||
|
||||
if [ "$1" == rect_tx ]; then
|
||||
tool="--enable-$1 --enable-ext-tx"
|
||||
fi
|
||||
|
||||
if [ "$1" == simp_mv_pred ]; then
|
||||
tool="--enable-$1 --enable-ref-mv"
|
||||
fi
|
||||
|
||||
if [ "$1" == mv_compress ]; then
|
||||
tool="--enable-$1 --enable-ref-mv"
|
||||
fi
|
||||
|
||||
if [ "$1" == var_tx ]; then
|
||||
tool="--enable-$1 --enable-cb4x4 --enable-rect-tx"
|
||||
fi
|
||||
|
||||
# if [ "$1" == ext_tx ]; then
|
||||
# tool="--enable-$1 --enable-cb4x4"
|
||||
# fi
|
||||
|
||||
# if [ "$1" == chroma_2x2 ]; then
|
||||
# tool="--enable-$1 --enable-cb4x4"
|
||||
# fi
|
||||
|
||||
if [ "$1" == ncobmc ]; then
|
||||
tool="--enable-$1 --enable-motion-var"
|
||||
fi
|
||||
|
||||
if [ "$1" == wedge ] || [ "$1" == compound_segment ] ; then
|
||||
tool="--enable-$1 --enable-ext-inter"
|
||||
fi
|
||||
|
||||
if [ "$1" == interintra ] ; then
|
||||
tool="--enable-$1 --enable-ext-inter --enable-wedge"
|
||||
fi
|
||||
|
||||
if [ "$1" == txk_sel ] ; then
|
||||
tool="--enable-$1 --enable-lv_map"
|
||||
fi
|
||||
|
||||
if [ "$1" == intra_interp ] ; then
|
||||
tool="--enable-$1 --enable-ext-intra"
|
||||
fi
|
||||
|
||||
if [ "$1" == ext_tile ] ; then
|
||||
tool="--enable-$1 --disable-cdef"
|
||||
fi
|
||||
|
||||
if [ "$1" == lv_map ] ; then
|
||||
tool="--enable-$1 --enable-cb4x4 --enable-chroma_sub8x8"
|
||||
fi
|
||||
|
||||
# if [ "$1" == chroma_sub8x8 ] ; then
|
||||
# tool="--enable-$1 --enable-cb4x4"
|
||||
# fi
|
||||
|
||||
if [ "$1" == one_sided_compound ] ; then
|
||||
tool="--enable-$1 --enable-ext-refs"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#debug="--enable-debug --disable-optimizations"
|
||||
common="--disable-unit-tests --disable-docs --enable-experimental"
|
||||
|
||||
. $script_dir/disabled_list.sh
|
||||
|
||||
experiment_dependency $1
|
||||
|
||||
../$libsrc/configure $common $debug $disabled $tool > /dev/null
|
19
scripts/runconfig_hbd.sh
Executable file
19
scripts/runconfig_hbd.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
platform=x86_64-linux-gcc
|
||||
codec=--enable-av1
|
||||
libsrc=aom
|
||||
|
||||
bitdepth=--enable-highbitdepth
|
||||
#bitdepth=
|
||||
#debug=--enable-debug
|
||||
debug=
|
||||
|
||||
if [ "$#" -eq 1 ]; then
|
||||
tool=$1
|
||||
../$libsrc/configure --target=$platform $codec $bitdepth $debug --enable-experimental --enable-$tool --disable-unit-tests > /dev/null
|
||||
else
|
||||
tool_1=$1
|
||||
tool_2=$2
|
||||
../$libsrc/configure --target=$platform $codec $bitdepth --enable-experimental --enable-$tool_1 --enable-$tool_2 --disable-unit-tests --disable-daala-ec > /dev/null
|
||||
fi
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user