Compare commits

...

385 Commits

Author SHA1 Message Date
hui su
be407e001b Adjust optimize_b RD parameters
Coding gain
lowres 0.51%
midres 0.36%

Change-Id: I1e9f2f9341bad12d9023f97c73d0e991ae5ec7f0
2016-05-06 09:56:59 -07:00
hui su
5af706210b Enable optimize_b for intra blocks
Coding gain
lowres 0.13%
midres 0.36%

Change-Id: Ia65d2d7513685dfcffbe3939fea473fb6d7036b9
2016-05-06 09:55:45 -07:00
Geza Lore
6d9bec4366 Configure tiles in tests when using row-tile.
With row-tile enabled, the encoder test driver needs to configure the
decoder in order to decode all tiles correctly.

Change-Id: I8b00a766cf5e41255625846f92fd71915c614ec1
2016-05-03 14:42:17 -07:00
Debargha Mukherjee
7a2934550b Merge "Quantization Profiles Strictly on Entropy Context" into nextgen 2016-05-02 19:15:13 +00:00
Brandon Young
43195061b7 Quantization Profiles Strictly on Entropy Context
Allow for 3 quant profiles from entropy context

Refactored dq_offset bands to allow for re-optimization based on number
of quantization profiles

Change-Id: Ib8d7e8854ad4e0bf8745038df28833d91efcfbea
2016-05-01 12:25:57 -07:00
Sarah Parker
b8bf8085be Merge "Search parameter space around gm parameters" into nextgen 2016-04-26 22:08:20 +00:00
Sarah Parker
31257e5406 Merge "Make feature based motion estimation the default" into nextgen 2016-04-22 01:21:09 +00:00
Sarah Parker
ba6423c564 Make feature based motion estimation the default
Optical flow parameters still need to be tweaked and is much slower
so feature based should be the default for now.

Change-Id: Id6cafb5a245e329f728e9c66c89c0ed1018c347c
2016-04-21 11:50:05 -07:00
Sarah Parker
70266ab130 Increase precision for gm parameters
Change-Id: I151ca8ec9b0c8a920745f4b1665d369a258f6ccb
2016-04-21 11:48:13 -07:00
Sarah Parker
7fa7f4c14a Fix comipler warnings in opticalflow.c
Change-Id: I4561c2676d8a7793ade47e1995e026ba9d521fdd
2016-04-20 17:27:13 -07:00
Debargha Mukherjee
3e3f40acb9 Fix for libwebm upgrade
To allow runborgs to run on the nextgen branch

Change-Id: Icbd425c5e65dd4bcb061a3a1ed4dbe0393dc2c5d
2016-04-19 10:27:42 -07:00
Sarah Parker
de085787ec Search parameter space around gm parameters
For each global motion parameter, search some step
size to the left and right to try and minimize warp
mse and correct for error.

Change-Id: I1f0b464b0924d56b15460e509f89736af9b7e78f
2016-04-13 17:56:25 -07:00
Brandon Young
50619bacfd Fix error with cumbins to allow multiple profiles
Change-Id: I23aadc8f7551771197b55465a3264250b40838ff
2016-04-08 13:16:34 -07:00
Debargha Mukherjee
72ee991598 Adds function to return superblock entropy context
For use with switchable quant profiles.

Change-Id: I2a4aa93204f086094457860d1646707d71f33f5e
2016-03-15 14:27:45 -07:00
Debargha Mukherjee
a399281daa Merge "Framework to incorporate switchable dequant levels" into nextgen 2016-03-14 16:34:04 +00:00
Debargha Mukherjee
b8a7d1fe02 Framework to incorporate switchable dequant levels
Changed experiment to allow switchable QUANT_PROFILES

Change-Id: I8e5e76239a4103273e9ef759d46400104ef55599
2016-03-11 23:07:26 -08:00
Geza Lore
d8739359a1 Make vpxenc --test-decode work with --enable-row-tile
Change-Id: I352c8ccdaa5faa4fd345f0cb0f7e614af669f0bc
2016-02-29 14:14:16 +00:00
Debargha Mukherjee
f90038c3a1 Remove key_frame_tile config option
Change-Id: I8ae22e9f706727ee258dc24780644b99087c8d23
2016-02-23 13:07:09 -08:00
Debargha Mukherjee
fb6bf251d4 Merge key_frame_tile experiment with row_tile
Since they are used together no need to keep them separate.

Change-Id: Ia7b4bec06ca6924fffd806f772638224292fddb2
2016-02-23 09:57:25 -08:00
Yunqing Wang
efb93f518f Merge "Implement a tile copying method in large-scale tile coding" into nextgen 2016-02-05 23:10:08 +00:00
Yunqing Wang
6e4dff92a4 Implement a tile copying method in large-scale tile coding
A tile copy mode is introduced, while allows a tile to use
another tile's coded data directly at bitstream level. This
largely reduces the bit rate in this use case. Our tests
showed that 10% - 20% bit rate reduction was achieved.

Change-Id: Icf5ae00320e27193b15ce95297720f8b6f5e7fd9
2016-02-01 11:08:30 -08:00
Sarah Parker
36cbc27587 Merge "Optical flow for computing global motion params" into nextgen 2016-01-25 22:06:32 +00:00
Yunqing Wang
990e30b8a7 Merge "Make set_reference control API work in VP9" into nextgen 2016-01-25 19:27:42 +00:00
Yunqing Wang
bcdc6befd2 Make set_reference control API work in VP9
1. Made VP8_SET_REFERENCE vpx_codec_control API work in VP9 based
on Ryan Overbeck's patch. (Thanks.)
2. Added vp9cx_set_ref example, which demonstrated how to set
VP8_SET_REFERENCE vpx_codec_control in encoder and decoder. If
we only set_reference in the encoder, the encoder/decoder
mismatch would be observed.
3. Also updated test/cx_set_ref.sh.

Change-Id: I433a6220616947ca8c73e65a5fb3694751ea84b6
2016-01-25 10:37:15 -08:00
Sarah Parker
a7aab42915 Optical flow for computing global motion params
Addressing comments, fixing style issues

Change-Id: I91b72ab5cdf80d68476858f442616ab3af41e709
2016-01-22 11:29:33 -08:00
Debargha Mukherjee
b765dc8e39 Merge "Changes to CONFIG_NEW_QUANT experiment." into nextgen 2016-01-22 00:15:05 +00:00
Brandon Young
9c9beb1c40 Changes to CONFIG_NEW_QUANT experiment.
Added dq_off_index attribute to mbmi to allow for switching between
dequantization modes.
Reduced number of different dequantization modes from 5 to 3.
Changed dequant_val_nuq to be allow for 3 dequant levels instead of 1.
Fixed lint errors

Change-Id: I7aee3548011aa4eee18adb09d835051c3108d2ee
2016-01-19 15:59:50 -08:00
Debargha Mukherjee
c20adb59b2 Merge "Rework wedge experiment to improve speed." into nextgen 2016-01-14 16:13:38 +00:00
Brandon Young
839ab586f6 Merge "Simplify new_quant experiment" into nextgen 2016-01-14 00:51:56 +00:00
Debargha Mukherjee
f93bdebcf9 Rework wedge experiment to improve speed.
Implements wedge mask generation by pre-computing arrays.
Improves encode speed by 15-20%.

Also consolidates the mask generation code for inter-inter
and inter-intra.

Change-Id: If1d4ae2babb2c05bd50cc30affce22785fd59f95
2016-01-12 15:23:54 -08:00
Yunqing Wang
15a90668a5 Adaptively determine the number of bytes used for tile-data size transmission
In large-scale tile coding, when the number of tiles is large and the tile
size is small, using a fixed number of bytes in the tile header to store
tile-data size information as done in current VP9 codec would bring high
overhead for each tile. This patch implemented 2 ways to lower that overhead
and adaptively determine the number of bytes needed for tile-data size
transmission.

The test on a test clip having the tile size of 64x64 showed that the number
of bytes used for storing tile-data size was reduced from 4 to 1, which
substantially improved the compression ratio in large-scale tile coding.

Change-Id: Ia02fc43eda67fa252fbc2554321957790f53f6fd
2016-01-11 12:46:04 -08:00
Brandon Young
604b909e06 Simplify new_quant experiment
Changes number of non-uniform bins from 5 to 3.
Changed all references to 'KNOTES' to 'KNOTS'.

Change-Id: If39d7cef00dbe07307035e44cb29194d0783b475
2015-12-17 12:25:27 -08:00
Debargha Mukherjee
e6790e30c5 Replace DST1 with DST2 for ext-tx experiment
A small gain (0.1 - 0.2%) with this experiment on derflr/hevcmr.

The DST2 can be implemened very efficiently using sign flipping
of odd indexed inputs, followed by DCT, followed by reversal of
the output. This is how it is implemented in this patch.
SIMD optimization is pending.

Change-Id: Ic2fc211ce0e6b7c6702974d76d6573f55cc4da0e
2015-12-14 13:54:41 -08:00
Debargha Mukherjee
d7eb423a72 Merge "SSSE3 optimisations of high bit depth masked variance functions" into nextgen 2015-12-08 21:54:03 +00:00
Peter de Rivaz
087a93eae5 Fix to avoid overflow in highbd_masked_variance64.
Change-Id: I98731c5f50c4821c604f53480f43110a75205d25
2015-12-08 11:12:35 -08:00
Julia Robson
711600e5f1 SSSE3 optimisations of high bit depth masked variance functions
Includes tests which compare output of new SSSE3 functions with
their C equivalents, and fixes to the C code to ensure these tests
pass.

Change-Id: Iec3980cce95a8ee6bf9421fa4793130e92c162e3
2015-12-04 11:59:30 -08:00
Julia Robson
997595e8a6 Code refactoring to remove duplication in masked sub pixel var fns
Change-Id: Idcc93ff94ed2c68367225b6bebfcae0b7952f074
2015-12-03 17:57:35 +00:00
Yunqing Wang
9227a372d3 Merge "Reduce the memset call in tile decoding" into nextgen 2015-12-02 00:24:06 +00:00
Julia Robson
ea167a5855 Adding SSSE3 accelerations of masked SAD functions
Includes tests of masked SAD function optimisations against C
versions

Change-Id: I42f198767a113b58ae9456841f4ec71075591720
2015-12-01 09:55:24 -08:00
Julia Robson
8e4d779137 SSSE3 optimisations of masked variance function (8bit ONLY)
Includes test which compares output of new SSSE3 functions with their
C equivalents

Change-Id: I4488cd7672cdb57efff93c0b3b8bff07f07ec544
2015-12-01 12:07:22 +00:00
Julia Robson
ef01ea152d Changes so other expts work with 128x128 coding unit size expt
Changes ensure wedge_partition, interintra and palette expts all
work alongside the ext_coding_unit_size experiment.

Change-Id: I18f17acb29071f6fc6784e815661c73cc21144d6
2015-11-26 17:43:00 +00:00
Yunqing Wang
7099feaeed Reduce the memset call in tile decoding
When the error resilient mode is on, the decoder resets mode info structure
to zero once per frame. This makes decoder about 10x slower if we decode
a single tile at a time. This patch resolves the issue by only memset mode
info of those decoded tiles. Currently, to decode a frame, tile decoding is
less than 2x slower than frame decoding.

Change-Id: Ia3fd88d91a4e74e7bbbc6547d87c24d085a1533e
2015-11-25 15:28:03 -08:00
Julia Robson
d52cc33891 Changes to allow 128x128 to work with copy_mode
Change-Id: I1fff46e7733e5e1d15c012d6a204536243c6e090
2015-11-24 10:15:10 -08:00
Peter de Rivaz
d79850e60c Bug fix for high bitdepth using flipped transforms.
Fixes mismatch and performance drop.

Change-Id: Ib99711eb3b78257a8105073e2b6d7031459357bb
2015-11-23 12:04:55 -08:00
Geza Lore
85ab9d56cc Flip the result of the inv transform for FLIPADST.
This is a port of 4f5108090a6047d5d4d9ce1df302da23b2ef4bc5

This commit also fixes a bug where FLIPADST transforms when combined
with a DST (that is FLIPADST_DST and DST_FLIPADST) did not actually did
a flipped transform but a straight ADST instead. This was due to the C
implementation that it fell back on not implementing flipping.  This is
now fixed as well and FLIPADST_DST and DST_FLIPADST does what it is
supposed to do.

There are 3 functions in the SR_MODE experiment that should be updated,
but given that the build of SR_MODE is broken at the upstream tip of
nextgen, I could not test these, so I have put in assertions and FIXME
notes at the problematic places.

Change-Id: I5b8175b85f944f2369b183a26256e08d97f4bdef
2015-11-17 14:31:28 -08:00
Debargha Mukherjee
f1f3a8ab14 Increase extension for ext-coding-unti-size expt
Change-Id: Ifc7fe5df6831cb7190b9b6e84125de13b9e0146f
2015-11-16 16:57:50 -08:00
Debargha Mukherjee
484c8858f0 Remove last4-ref config option
Change-Id: I12ab2f8b039e328210ae8eadc663f751e19c0c09
2015-11-13 16:22:28 -08:00
Debargha Mukherjee
0c29af2767 Merge last4_ref with multi-ref experiment
Change-Id: I9778670ff6d02fb021099b17f292edadf87603e6
2015-11-13 14:54:38 -08:00
Debargha Mukherjee
ec6d31781d Merge "Remove dst1 config option and merge with ext-tx" into nextgen 2015-11-13 21:01:21 +00:00
Debargha Mukherjee
3a45a1edfd Remove dst1 config option and merge with ext-tx
Change-Id: I0152ed352ae2a0a725a508b5c209ef2c1dc2302d
2015-11-13 11:24:38 -08:00
Julia Robson
3d9133b2a5 SSE2 optim of vp9_subtract_block for 128x128 units
Extending the SSE2 implementation of vp9_subtract_block to work
with the 128x128 coding unit experiment

Change-Id: Ib3cc16bf5801ef2c7eecc19d3cc07a8c50631580
2015-11-13 11:12:56 -08:00
Debargha Mukherjee
3436acb347 Merge "Adding encoder support for 128x128 coding units" into nextgen 2015-11-13 18:52:09 +00:00
Debargha Mukherjee
a542190830 Merge "Eliminate copying for FLIPADST in fwd transforms." into nextgen 2015-11-13 18:23:49 +00:00
Geza Lore
177ad11981 Eliminate copying for FLIPADST in fwd transforms.
This is a port of 01bb4a318dc0f9069264b7fd5641bc3014f47f32

This commit also fixes a bug where FLIPADST transforms when combined
with a DST (that is FLIPADST_DST and DST_FLIPADST) did not actually did
a flipped transform but a straight ADST instead. This was due to the C
implementation that it fell back on not implementing flipping.  This is
now fixed as well and FLIPADST_DST and DST_FLIPADST does what it is
supposed to do.

Change-Id: I89c67ca1d5e06808a1567c51e7d6bec4998182bd
2015-11-13 09:34:26 -08:00
Debargha Mukherjee
59de0c0bc7 Adding encoder support for 128x128 coding units
Changes to allow the encoder to make use of 128x128 coding units.

Change-Id: I340bd38f9d9750cb6346d83885efb00443852910
2015-11-13 09:21:22 -08:00
Debargha Mukherjee
9d9962aec9 Some fixes on context size for the 128x128 expt
Change-Id: I56f050502e3a750ce74b196d033b780218df2c1f
2015-11-13 07:06:19 -08:00
Johann Koenig
a0c13e6757 Merge "Cherry pick the rest of 661802, the important part" into nextgen 2015-11-13 00:47:05 +00:00
Julia Robson
d90a3265f0 Changes to use defined constants rather than hard-coded numbers
Also fixes a valgrind error when optimizations are disabled.
Done in preparation for the work on the extended coding unit size
experiment.

Change-Id: Ib074c5a02c94ebed7dd61ff0465d26fa89834545
2015-11-12 15:42:32 -08:00
Johann
a877c6e9a6 Cherry pick the rest of 661802, the important part
Change-Id: I85f1d2c07b89c874ea6c30df32dda9ecaa8d2c3f
2015-11-12 15:41:24 -08:00
Debargha Mukherjee
bd7a34d5a3 Merge "Fixing issue with calculation of block_idx" into nextgen 2015-11-12 23:39:35 +00:00
Johann
26272dd366 Cherry pick 661802 to fix 64bit arm build
Remove default cortex-a8 tuning.

Probably not even the dominant platform the library is being built for.
Add --cpu= option description to help. The option already exists.

Don't allow passing just --cpu as a no-op.

BUG=826

Change-Id: Iaa3f4f693ec78b18927b159b480daafeba0549c0
2015-11-12 14:51:53 -08:00
Julia Robson
598a11d04a Fixing issue with calculation of block_idx
For tall rectangular blocks, the block_idx of the lower transform
block was being mis-calculated.

Does not affect results the way this function is being used now.

Change-Id: I470464d19be0bf0f42003d0cc29793bc42db8f52
2015-11-12 08:21:53 -08:00
Julia Robson
84a5403bab Added decoder support for 128x128 coding units
Change-Id: Icf3c6b64caaf8a86cd27231aa27baf5fd99c0fde
2015-11-02 16:03:30 +00:00
Julia Robson
2a1f8c74aa Changes to use defined constants rather than hard-coded numbers
These changes have been made in preparation for the work on the
extended coding unit size experiment.

Change-Id: I83f289812426bb9aba6c4a5fedd2b0e0a4fe17cb
2015-11-02 16:02:55 +00:00
Sarah Parker
42abac9374 Fixed final style issues
WIP.

Change-Id: Iafcbcfdc2139e77eb2c6849a52a9dc94ea498d66
2015-10-27 18:39:54 -07:00
Debargha Mukherjee
9ef4023569 Remove some unused variables
Change-Id: I3ab263b4c42cc3bfd598a1fc280fbaffba2d4461
2015-10-15 12:50:15 -07:00
Julia Robson
dff4e683fd Added extended coding unit size experiment
Change-Id: I45e2efe22c8e2f23e3305d00906bc08229a85c17
2015-10-07 16:54:10 +01:00
Debargha Mukherjee
9fc51184b7 Merge "Speed up of wedge search" into nextgen 2015-10-06 00:33:50 +00:00
Debargha Mukherjee
597204298a Speed up of wedge search
Speeds up wedge search by pre-calculating single predictions
before computing the wedge combination.

About 20% speed up achieved.

Change-Id: I72f76568559d1899c8ac0afaa133d433ba388e6d
2015-10-04 23:43:25 -07:00
Debargha Mukherjee
ff6a66a0b2 Merge "tx64 prob tweaks." into nextgen 2015-10-03 17:59:54 +00:00
Debargha Mukherjee
b80a04bd63 tx64 prob tweaks.
A little improvement in results on hevchd

Change-Id: Ib71a57c4bec34bf688e1d53dbf73eb4525e7805b
2015-10-02 11:44:02 -07:00
Debargha Mukherjee
ff9aa146cb Reimplementatio of dst1 for speed
Encoder with --enable-ext-tx --enable-dst1 is now 4 times faster.

Change-Id: Ia750ad3516698ce94da4ceb566b1c51539537a95
2015-10-02 11:06:55 -07:00
Debargha Mukherjee
4f371ac4f2 Merge "64x64 idct fix." into nextgen 2015-09-25 23:36:42 +00:00
Zoe Liu
90dede3f5b Merge "Merged LAST2 and LAST3 to one experiment MULTI_REF" into nextgen 2015-09-25 16:47:28 +00:00
Debargha Mukherjee
5a25d567d7 64x64 idct fix.
Change-Id: If0e0cd7cbe71e9586657f5e8ffa87dcdebc686ba
2015-09-25 05:54:23 -07:00
Debargha Mukherjee
1e2cbf515e Merge "tx64x64 experiment fix for high-bitdepth" into nextgen 2015-09-25 03:22:54 +00:00
Zoe Liu
e8e58402f0 Merged LAST2 and LAST3 to one experiment MULTI_REF
Change-Id: I220be17af317520dccb62fa6b19da5c7ce10652d
2015-09-24 17:08:15 -07:00
Zoe Liu
a9900eb2b1 Merge "Added another reference frame LAST4_FRAME" into nextgen 2015-09-24 15:58:22 +00:00
Debargha Mukherjee
cdcebfba29 tx64x64 experiment fix for high-bitdepth
Change-Id: Ia8d769b43bad0f9ad0684ecf6925e580339c7397
2015-09-24 05:45:03 -07:00
Zoe Liu
829dbf7a79 Added another reference frame LAST4_FRAME
Under the experiment of CONFIG_LAST4_REF. On derflr testset, using
highbitdepth (HBD), in average PSNR,

(1) LAST2+LAST3+LAST4 obtained +0.361% against LAST2+LAST3;
(2) LAST2+LAST3+LAST4 obtained +1.567% against baesline.

Change-Id: Ic8b14272de6a569df2b54418fa72b505e1ed3aad
2015-09-23 17:10:44 -07:00
hui su
71d0af90f8 Adjust rd calculation in choose_tx_size_from_rd
Change-Id: I3649f28196a87663b116b9fe6446b1fbe6eeab4a
2015-09-23 14:37:45 -07:00
Zoe Liu
411c490bc3 Improved LAST3's single ref prob context design a little
On derflr testset, using 12-bit HightBitDepth mode, this CL obtained a
small gain of +0.031% by turning on LAST2+LAST3.

Change-Id: Ib6c9d595e56269634bf29d684eabcd806fc08cc9
2015-09-21 15:03:43 -07:00
Zoe Liu
9144967ca8 Fixed a couple of bugs for LAST3
Change-Id: I63126a844c255df4a447aac7f630ba54cc7d7d7a
2015-09-21 11:50:35 -07:00
Zoe Liu
c0889b9a8c Added a 3rd reference frame LAST3_FRAME
Under experiment CONFIG_LAST3_REF, which can only be turned on when
the experiment of CONFIG_MULTI_REF is on, i.e. LAST3_FRAME can only
be used when LAST2_FRAME is used. CONFIG_LAST3_REF would most likely
be combined with CONFIG_MULTI_REF once the performance improvement
is further confirmed.

On the testset of derflr, using Average PSNR metrics, with HighBitDepth
(HBD) on:

(1) LAST2 HBD obtained +0.579% against base HBD;
(2) LAST2 + LAST3 HBD obtained +0.591% against LAST2 HBD;
(3) LAST2 + LAST3 HBD obtained +1.173% against base HBD.

Change-Id: I1aa2b2e2d2c9834e5f8e61bf2d8818c7b1516669
2015-09-18 15:25:46 -07:00
Debargha Mukherjee
b6d5b0838b ext-tx extension to intra blocks
derflr: improves to 1.692%

Change-Id: Idf583216b40ed02526b9b39031eaf2fb72fed11d
2015-09-17 14:21:24 -07:00
Debargha Mukherjee
c104998b61 Merge "Redo DST1 in the ext-tx experiment" into nextgen 2015-09-16 18:38:03 +00:00
Debargha Mukherjee
4dbaf9a5ab Redo DST1 in the ext-tx experiment
Moved from nextgenv2 branch to test with other experiments.

derflr: +1.629%

Change-Id: Ie7c720053ed8b628177679c4351bb31b54716a71
2015-09-16 09:46:13 -07:00
Zoe Liu
9b0635fc75 Fixed a bug on the number of MAX_MODES in baseline
All the numbers of MAX_MODES have been changed assuming
CONFIG_MULTI_REF. Now correct numbers have been put in for both with and
without the enabling of the experiment MULTI_REF.

Change-Id: I70ffe2f1a89fa572d612dd3d311d3af19fe3a632
2015-09-15 14:12:12 -07:00
Zoe Liu
f48a159430 Added more LAST2 modes for INTERINTRA
Turning on all the other experiments, compared the RD performance
between with and without the use of LAST2_FRAME, on derflr testset,
on Average PSNR:

8-bit: +0.653% (All positive except one,
max: mobile_cif: 2.019%; min: paris_cif: -0.081%)
12-bit HBD: +0.735% (All positive,
max: bridge_far_cif: 2.416%; min: bowing_cif: 0.132%)

Change-Id: Ia0a375667e228c8ba3d2e223abff608206f2f545
2015-09-15 11:57:18 -07:00
Zoe Liu
ec8864a8bf Added MACRO for reference frame encoding
This CL introduces a few macros plus code cleaning on the encoding of
the reference frames. Coding performance remains unchanged.

For the encoding of either the compound reference or the single reference
case, since each bit has different contexts, the tree structure may not
be applied to treat the combined bits as one symbol. It is possible we may
explore the sharing of the same context for all the bits to introduce
the use of tree structure for the next step.

Change-Id: I6916ae53c66be1a0b23e6273811c0139515484df
2015-09-11 14:57:31 -07:00
Zoe Liu
897192be43 Added one more reference frame LAST2_FRAME
Under the experiment CONFIG_MULTI_REF. Current version shows
LAST2 vs base in nextgen on the testset of derflr:

(1) 8-bit: Average PSNR +0.53%
(worst: students_cif: -0.247%; best: mobile_cif: 1.902%)
(2) 12-bit HBD: Average PSNR +0.63%
(worst: pamphlet_cif: -0.213%, best: mobile_cif: 2.101%)

More tuning on the reference frame context design and default
probs are being conducted. This version does not guarantee to
work with other experiments in nextgen. A separate CL will address
the working with all other experiments.

Change-Id: I7f40d2522517afc26ca389c995bad56989587f65
2015-09-09 14:27:05 -07:00
Shunyao Li
2de18d1fd2 Super resolution mode (+CONFIG_SR_MODE)
CONFIG_SR_MODE=1, enable SR mode
USE_POST_F=1, enable SR post filter
SR_USE_MULTI_F=1, enable SR post filter family
Not compatible with other experiments yet

Change-Id: I116f1d898cc2ff7dd114d7379664304907afe0ec
2015-08-31 15:29:39 -07:00
Shunyao Li
c7d886d96a Add transform size rate for intra skip mode in rdopt
Change-Id: I81fedd99cd39c12b66b93b786cb43234c867b84b
2015-08-31 11:28:27 -07:00
Debargha Mukherjee
9c685602d0 Make tests work with new configurations
Disables some test vector tests when Vp8/Vp9 decoders are disabled
in configuration. Also moves some macros to the vpx level in
line with recent refactoring on the master branch.

Change-Id: Iaac8008992110398ae096c36b9726f723164c207
2015-08-27 14:05:59 -07:00
Debargha Mukherjee
4525961d80 Some tweaks to probabilities for ext-tx with dst1
derflr: up to 1.429% from a little less than 1.3% when
--enable-dst1 is also enabled with --enable-ext-tx.

Change-Id: I301229f2239b18acb96accc4fc44b64fa6927ace
2015-08-12 14:31:31 -07:00
hui su
d5eaca7fee code cleanup in encode_block_intra
Change-Id: I376b7e9b243178d79141a96e0aeafcbc15758e97
2015-07-30 15:28:51 -07:00
Cheng Chen
cc4d523d9f Resolve bug of DST1 in ext_tx experiment.
Change-Id: I828569e3596f9b9e8487aec7c4056e66cf1fc1f2
2015-07-28 10:58:14 -07:00
Debargha Mukherjee
23690fc5d1 Adds support for DST1 transforms for inter blocks
Adds an additional transform in the ext_tx experiment that
is a 2d DST1-DST1 combination.

To enable use --enable-ext-tx --enable-dst1.

This needs to be later extended to combine DST1 with DCT
or ADST.

Change-Id: I6d29f1b778ef8294bcfb6a512a78fc5eda20723b
2015-07-24 16:23:09 -07:00
Shunyao Li
188087202c Speed up of supertx
Limited the prediction extension to 8 pixels at each edge
Fixed a bug in the combination of wedge prediction and supertx

~10% speed up in decoder
derflr:     -0.004
derflr+hbd: +0.002
hevcmr:     +0.015

Change-Id: I777518896894a612c9704d3de0e7902bf498b0ea
2015-07-24 11:19:19 -07:00
Debargha Mukherjee
4b57a8b356 Add extended transforms for 32x32 and 64x64
Framework for alternate transforms for inter 32x32 and larger based
on dwt-dct hybrid is implemented.
Further experiments are to be condcuted with different
variations of hybrid dct/dwt or plain dwt, as well as super-resolution
mode.

Change-Id: I9a2bf49ba317e7668002cf1499211d7da6fa14ad
2015-07-23 18:01:22 -07:00
Yunqing Wang
7959dd012c Nextgen branch cleanup: remove elevate_newmv_thresh feature
Code cleanup.

Change-Id: Idf00d5359e5f3d943ee39b4a00f8d40325c0f8b3
2015-07-14 14:28:56 -07:00
Yunqing Wang
527f88316c Nextgen branch cleanup: remove real-time speed features
Removed inter_mode_mask and max_intra_bsize.

Change-Id: I835d31f95af64a524b2fdb685d1d09a6b0ad5c9f
2015-07-14 14:26:17 -07:00
Yunqing Wang
6c2035744a Merge "Nextgen branch cleanup: add back some SVC functions" into nextgen 2015-07-08 23:26:35 +00:00
Yunqing Wang
da013eed3f Nextgen branch cleanup: add back some SVC functions
Several SVC functions were added back to ensure Borg test build.

Change-Id: I2cff676407fa74e2255606094ff12bd840287b6d
2015-07-08 14:13:57 -07:00
Zoe Liu
08effeaad5 A small code cleanup for the encoder workflow.
Change-Id: I543a69ad5a34cd9a0671b57131cafc541d595d9a
2015-07-08 12:12:47 -07:00
Alex Converse
7932eb014e Merge "intrabc: Allow odd pel displacement for non-444" into nextgen 2015-07-08 04:06:24 +00:00
Shunyao Li
e8885d4a50 Merge "Optimize bilateral filter to improve speed" into nextgen 2015-07-07 20:17:13 +00:00
Yunqing Wang
ca42973ea2 Nextgen branch cleanup: remove svc code
Spatial/temporal svc code was removed.

Change-Id: Ie25c7a58ee5feb662d4de526406d8cd834d19977
2015-07-06 21:19:05 -07:00
Yunqing Wang
020293588d Nextgen branch cleanup: remove unused functions
Removed unused real-time functions.

Change-Id: I0cbcee67fb8f495f87c6330e04ed6d56ed8e2625
2015-07-06 12:07:33 -07:00
Yunqing Wang
cc6dc0b7d9 Nextgen branch cleanup: remove nonrd code
Code cleanup.

Change-Id: I4d8d7fa2fc61a58b819c9a18bf25cda53e3fd88c
2015-07-06 10:03:23 -07:00
Alex Converse
5241acf6e2 intrabc: Allow odd pel displacement for non-444
intrabc:
screen_content: -0.618 derflr: +0.015

intrabc+tx_skip+palette:
screen_content: -0.124 derflr: -0.048

Change-Id: Iabea4be19dce2f6fdab8f639e585a424c90c81b4
2015-06-30 10:11:46 -07:00
Shunyao Li
dac589d6d4 Optimize bilateral filter to improve speed
Optimization of bilateral filter:
1) Pre-calculate the bilateral filters at all the
levels at the initialization.
2) Convert 1D matrix to 2D matrix, avoid too many
multiplications in the bilateral filter loop.
3) Fix a bug in "loop_bilateral_filter_highbd".
The right-shifted range index can be larger than 255.

Change-Id: I42f6177e896706948e2403bd9edce46e3eb5cbf8
2015-06-29 14:48:59 -07:00
Alex Converse
a4f4ed60cf Merge "intrabc: displacement vector prediction" into nextgen 2015-06-25 20:55:21 +00:00
Alex Converse
93cd5cf3f4 intrabc: displacement vector prediction
Predict displacement vector with the same logic as NEARESTMV. If no
neighbors are available fall back to the current one block left or up
prediction.

vp9+intrabc+tx_skip+palette: -0.489
vp9+intrabc: -0.771

Change-Id: If67d08b54f1a3b847cf7ab8c7b800c55baa1a86b
2015-06-24 10:02:50 -07:00
Peter de Rivaz
fbfeb03f02 Fix for copy-mode with segmentation
Change-Id: Icfc97826e494b856aa80fbefe4811dff99f3a0b4
2015-06-24 09:25:23 +01:00
Debargha Mukherjee
567e4c754f Merge "Removing some compiler warnings" into nextgen 2015-06-23 19:13:09 +00:00
Peter de Rivaz
269f6e2cb1 Added support for extended partitions with copy_mode
Change-Id: I815374bd89e3faf2bac1b4155dbbe7366f0a1d29
2015-06-23 11:09:34 -07:00
hui su
ffcd76e328 Merge "Fix a bug induced by qctx-tprobs experiment" into nextgen 2015-06-23 17:54:35 +00:00
hui su
2f1325049a Merge "Bug fix in tx-skip" into nextgen 2015-06-23 17:42:41 +00:00
hui su
591b03a915 Fix a bug induced by qctx-tprobs experiment
Change-Id: I8d31b8e6037464c36b514fddccd5d7edee024a47
2015-06-23 10:20:27 -07:00
Debargha Mukherjee
3a18fc6784 Removing some compiler warnings
Change-Id: I572594a9c00ba5a2b8000d3b4c86ec5757aa586c
2015-06-22 15:26:25 -07:00
Peter de Rivaz
bad321d9e4 Added palette support to extended partitions
Change-Id: Ide11bd3fcc9fb26b27ae39cdf216a2c32b853348
2015-06-22 20:34:26 +01:00
Julia Robson
84d0da63d0 Palette high bit depth functionality
Changes to allow high bit depth and palette to be enabled at the
same time by using a 16 bit (instead of 8bit) palette when high
bit depth is enabled and modifying related functions accordingly.

Change-Id: I97d30b4d9338d3a51db02c94bc568eba60a8905d
2015-06-22 18:53:34 +01:00
hui su
c96afa256f Merge "Add q-index as context for initial token probs" into nextgen 2015-06-22 17:44:26 +00:00
Debargha Mukherjee
1c96a0bb09 Merge "Fix for supertx decode with segments" into nextgen 2015-06-22 17:28:31 +00:00
Debargha Mukherjee
adc9ed5a87 Merge "Fix supertx HORZ and VERT partitioning." into nextgen 2015-06-22 17:11:39 +00:00
hui su
315351e9de Bug fix in tx-skip
This patch avoids using tx_size larger than 16x16 in lossless mode.
Big block quantization (32x32 or larger) is not lossless.

Change-Id: I69cd84d4f3fd06d641048d6096da1bfde18ad24e
2015-06-22 09:54:42 -07:00
hui su
5963fd35dd Add q-index as context for initial token probs
There are 4 entropy tables to select for initial entropy table,
depending on the frame base q-index. The entropy tables are
trained with derf, yt, and stdhd sets. About 0.2% gain on
the following test sets:

derflr       0.227%
yt           0.277%
stdhd        0.233%
hevclr       0.221%
hevcmr       0.155%
hevchr       0.182%

Change-Id: I3fde846c47fc020e80c814897690b4cda1da569c

Change-Id: I460408372586c823974f945ed9fd8dcb0360fbaf
2015-06-21 13:09:57 -07:00
Peter de Rivaz
3b09cc1945 Fix for supertx decode with segments
Change-Id: I5e07b0b9fafd2578ecfacf20fb70b07fd6977d98
2015-06-18 18:16:07 +00:00
Peter de Rivaz
bdbae2520a Fix supertx HORZ and VERT partitioning.
Change-Id: I9a44d70dc2514baf679025335badc2744eeb4b88
2015-06-17 22:02:58 -07:00
Peter de Rivaz
100fff09b6 Added ext_partitions to supertx
Change-Id: I0e2a0253e5a8dcdb5b765836a3301299409e9d0a
2015-06-17 20:28:32 +00:00
Peter de Rivaz
3a3fb8d100 Fix seg fault in count_segs_sb with ext_partitions
Change-Id: I609f429006e7d2b849fe0a509f5d9f5123ecf0ec
2015-06-17 08:25:58 +00:00
Pieter Kapsenberg
d0e9499f94 Fixing skip simplifcation with SuperTX experiment
Combination of MISC_ENTROPY and SUPERTX resulted in compilation error

Change-Id: Ibcf28216712d93f00f38f3786fce8fcdca3f835e
2015-06-15 16:50:10 -07:00
hui su
0809dc09cb Merge "Fix tx-skip warnings on Windows" into nextgen 2015-06-15 19:41:24 +00:00
Alex Converse
a046bece1e Merge changes I9d80152b,I4e13da4b into nextgen
* changes:
  intrabc: Add a frame level flag
  intrabc: Remove NEWDV from the intra mode tree.
2015-06-15 16:57:05 +00:00
Debargha Mukherjee
ec8b957efe Merge "Added tests for high bit depth quantize functions" into nextgen 2015-06-12 20:59:16 +00:00
Debargha Mukherjee
dcb3d7f398 Bug fix in highbd psnr computation with postproc
Change-Id: I6944a5fc38d6a89e1bb739938c6ecae7ec731b8d
2015-06-12 11:57:40 -07:00
Peter de Rivaz
3bf31c4c98 Allow extended partition support to encode
Change-Id: I75246e2ee35a1b7c1ad46669c464e582e3a9961c
2015-06-11 11:52:45 -07:00
Debargha Mukherjee
e0617385d6 Merge "Add extended partition support to decode" into nextgen 2015-06-11 18:47:29 +00:00
hui su
c80386a5ab Fix tx-skip warnings on Windows
Change-Id: I2a515abe20e6989de233fc8ae2c31d8ee462add2
2015-06-11 11:20:16 -07:00
hui su
0c8bcb43a0 Merge "Fix palette build on windows" into nextgen 2015-06-11 17:56:26 +00:00
hui su
5d132c799e Fix palette build on windows
Change-Id: I2a90e235ab5bdf95eb83f684e46ef844553ba629
2015-06-11 10:44:05 -07:00
Peter de Rivaz
31d17053f3 Add extended partition support to decode
Change-Id: I65f7aed37d65dbba76999d2b9585129c48e70b11
2015-06-11 09:37:00 -07:00
Peter de Rivaz
999fabc183 Added extended partition experiment
Change-Id: Ife89c95f04212e9dceb4c4e663280a85b5718c13
2015-06-11 09:37:00 -07:00
Debargha Mukherjee
db90b74c1a Merge "Fix copy mode bug: searches made outside of the current tile" into nextgen 2015-06-11 16:30:23 +00:00
Jack Haughton
286983b8c6 Fix copy mode bug: searches made outside of the current tile
Change-Id: Ib3cf4bf4da0a575053493609956e133d1ce028a1
2015-06-11 09:23:32 +01:00
Debargha Mukherjee
ee5f9c7181 Merge "Fix to loopfilter tests" into nextgen 2015-06-11 05:30:50 +00:00
Debargha Mukherjee
278de7b73a Merge "Fix cost array overrun bug in search_bilateral_level()" into nextgen 2015-06-11 05:28:43 +00:00
Alex Converse
c3e884f5be intrabc: Add a frame level flag
For the combination of this and removing NEWDV from the tree:
derflr: -0.101 screen_content: +0.053

The bulk of the decline in screen content effecincy is from the liquify
clip. These should be recoverable by further entropy tweaks.

Change-Id: I9d80152b8492e60a0367c31797fb6932fb09bba9
2015-06-09 11:23:23 -07:00
Debargha Mukherjee
36eec6a9b1 Merge "Fix masked_variance overflow for non-highbitdepth" into nextgen 2015-06-09 17:07:13 +00:00
Jack Haughton
fa4b1ca714 Fix cost array overrun bug in search_bilateral_level()
Change-Id: I9b7b727cb45328040a82477a2ce8eb3d15feec77
2015-06-09 14:21:55 +01:00
Julia Robson
ece7479208 Fix to loopfilter tests
Ensuring the random numbers used by the loopfilter tests
are in a valid range

Change-Id: If8130145c413dbe7e29180046eca3e4f7d941706
2015-06-09 13:09:09 +01:00
Debargha Mukherjee
b433dd4443 Adds wavelet transforms + hybrid dct/dwt variants
The wavelets implemented are 2/6, 5/3 and 9/7 each with
a lifting based scheme for even block sizes. The 9/7
one is a double implementation currently.

This is to start experiments with:
1. Replacing large transforms (32x32 and 64x64) with wavelets
or wavelet-dct hybrids that can hopefully localize errors better
spatially. (Will also need alternate entropy coder)
2. Super-resolution modes where the higher sub-bands may be
selectively skipped from being conveyed, while a smart
reconstruction recovers the lost frequencies.

The current patch includes two types of 32x32 and 64x64
transforms: one where only wavelets are used, and another
where a single level wavelet decomposition is followed
by a lower resolution dct on the low-low band.

Change-Id: I2d6755c4e6c8ec9386a04633dacbe0de3b0043ec
2015-06-08 23:30:38 -07:00
Jack Haughton
2799fad98c Fix masked_variance overflow for non-highbitdepth
Change-Id: I668b034111ccc877c70cf65035a9c748fe00aeba
2015-06-08 12:09:48 -07:00
Debargha Mukherjee
5a69abc66b Merge "Windows build fix" into nextgen 2015-06-05 17:40:06 +00:00
Debargha Mukherjee
ad2cf9b444 Windows build fix
Change-Id: I663e0d61c4115a5297baeb25f39743e1eea95fbf
2015-06-05 10:24:24 -07:00
hui su
507857786d Fix lossless mode in tx-skip experiment
Change-Id: I205fa8614a9079ce7e6ca87d7b08fe3602bbd376
2015-06-04 15:13:37 -07:00
Julia Robson
33199783ea Added tests for high bit depth quantize functions
This was originally part of change-id:Idef18f90b111a0d0c9546543d3347e551908fd78
but the rest of that patch has previously been incorporated into nextgen
without these tests.

Change-Id: I6ac491ed1cfc153e0ed3cb999c76feac9d5e74e3
2015-06-04 16:00:39 +01:00
Debargha Mukherjee
b8a793458a Fix lossless mode with new_quant experiment
Change-Id: Ia0b00746e3f7aacf8d9488db3522ab72d9dc22fd
2015-06-04 02:45:54 -07:00
Alex Converse
1f537e3818 intrabc: Remove NEWDV from the intra mode tree.
Change-Id: I4e13da4bf70386f6f70ea733fb9adeb41682c735
2015-06-03 13:26:03 -07:00
Alex Converse
f35fb46c48 intrabc: Fix mismatch introduced by 85a7485.
Change-Id: I1ea51ebbd1e3cb60a13a30e3252253493c28baec
2015-06-03 13:07:49 -07:00
Alex Converse
783d18d22a Merge "intrabc: Include NEWDV in mode_2_counter" into nextgen 2015-06-03 16:09:36 +00:00
Debargha Mukherjee
d6ff3b3b22 Merge "Implied skip is 0 for intra blocks" into nextgen 2015-06-02 21:10:18 +00:00
Alex Converse
7944249b80 Merge "intrabc: Add odd-pel support for 444." into nextgen 2015-06-02 19:03:15 +00:00
Alex Converse
8cbed23cdf intrabc: Include NEWDV in mode_2_counter
This fixes a failure to decode as VP9 with frame level signalling
patched in and removed to implictly force it off.

This is primarily a correctness fix, but there were small coding gains.
0.074% smaller on derlf
0.180% smaller on screen_content

Change-Id: I4cc264bf4d9016201924be198a0c5b8374020fd9
2015-06-02 11:01:00 -07:00
Pieter Kapsenberg
ec1e91847c Implied skip is 0 for intra blocks
Skip flag is removed from the bitstream for all blocks coded in intra
mode. Very minor coding gain in derf and stdhd sets (0.048 and 0.1)

Change-Id: I79f03300f16d6fa84ce54405cafecab8a021cd7d
2015-06-01 18:27:34 -07:00
Jingning Han
b71176b477 Fix the upper limit of row/column tile index
If the decoder is configured to decode a tile indexed above the
upper limit, the internal codec will clip the index to the upper
limits.

Change-Id: Icbc1bb7b14069ac009e0a2042dd66a46d6f76679
2015-05-29 09:12:05 -07:00
Jingning Han
f5660af165 Allow vpxdec to produce target tile reconstruction
This commit allows the vpxdec to produce the target tile
reconstruction as its output. When the provided tile index is -1,
the entire corresponding row/column tiles will be reconstructed.
If the tile index is over the upper limit, the decoder will decode
left-most/bottom tile.

Change-Id: I4c18bdb32099f736f99b8842f7f177a32b3fee09
2015-05-28 23:20:24 -07:00
Jingning Han
89747d09cc Enable selective key frame tile decoding
This commit allows the decoder to decode selective tiles according
to decoder configuration settings. To decode a single tile out of
the provided key frame bit-stream (test_kf.webm), set compiler
configuration:

--enable-experimental --enable-row-tile --enable-key-frame-tile

use the command:

vpxdec -o test_dec.y4m test_kf.webm --tile-row=1 --tile-column=2

where the tile's row and column indexes are 1 and 2, respectively.

To decode all row tiles inside a provided column index, use:
--tile-row=-1 --tile-column=2

To decode all column tiles inside a provided row index, use:
--tile-row=2 --tile-column=-1

Change-Id: Ib73c266414dcee7eaab5d741b90d0058970dae56
2015-05-28 16:10:13 -07:00
Alex Converse
85a7485137 intrabc: Add odd-pel support for 444.
Odd pel still needs more testing on 4:2:0.

0.2% smaller on the PNG set. 4095 better, 1324 worse.

Change-Id: Idf2f108a96462c7696e63d533605e4a926a8b203
2015-05-28 15:44:15 -07:00
Debargha Mukherjee
fe79548bc8 Merge "Intrabc high bit depth functionality" into nextgen 2015-05-28 22:40:38 +00:00
Debargha Mukherjee
8f82bc172c Merge "Turn on global rotation-zoom warping prediction" into nextgen 2015-05-28 22:07:29 +00:00
Julia Robson
153d824207 Intrabc high bit depth functionality
Fixing compile errors when intrabc and vp9_highbitdepth are both enabled.
Error arose because intrabc uses vp9_setup_scale_factors_for_frame()
which takes an additional argument (use_highbitdepth) when
vp9_highbitdepth is enabled.

Change-Id: I6a15b09dcea0d35525f4c25efb6848804ae5cfab
2015-05-28 12:05:37 +01:00
Alex Converse
f80879d452 Merge "palette: don't repeat calc_dist for j = 0" into nextgen 2015-05-28 01:55:05 +00:00
Jingning Han
30fb5831da Merge "Fix a memory overflow issue in large scale tile use case" into nextgen 2015-05-28 01:53:56 +00:00
Jingning Han
d8d30cfb9b Merge "Configure selective tile decoding" into nextgen 2015-05-28 01:53:38 +00:00
Alex Converse
3df4a571a4 palette: don't repeat calc_dist for j = 0
Change-Id: I043c3b9696dbfa76436763ef871600cb54ade212
2015-05-27 11:45:00 -07:00
Debargha Mukherjee
5930a90cc9 Turn on global rotation-zoom warping prediction
With this patch, the ZEROMV mode is overloaded to represent
a single global dominant motion using one of three models:
1. True zero translation motion (as before)
2. A translation motion different from 0
3. A Rotation-zoom affine model where the predictor is warped
The actual model used is indicated at the frame level for
each reference frame.
A metric that computes the ratio of the error with a global
non-zero model to the error for zero motion, is used to
determine on the encoder side whether to use one of the two
non-zero models or not.

Change-Id: I1f3d235b8860e543191237024a89041ff3aad689
2015-05-27 11:33:33 -07:00
Jingning Han
ceda343d0b Fix a memory overflow issue in large scale tile use case
Increase the tok_count array size defined in VP9_COMP to avoid
out of boundary memory access.

Change-Id: Ib277c1102cb5f8355b1d69991532a94e24a2242e
2015-05-27 11:18:06 -07:00
hui su
c4f04808eb Merge "Fixed a bug in palette expt for 444 video format" into nextgen 2015-05-27 18:14:16 +00:00
hui su
f3f2645f24 Fixed a bug in palette expt for 444 video format
The bug was that palette color map was not correctly recorded.

Change-Id: I237494d1d6449c53c5d24eed8c25dcf2f8d21e66
2015-05-27 10:53:17 -07:00
Jingning Han
3b6901730f Merge "Make the tile coding syntax support large scale tile decoding" into nextgen 2015-05-27 16:40:49 +00:00
Jingning Han
f00bf10de0 Configure selective tile decoding
Add decoder control to extract single tile from key frame.

Change-Id: Id018bf267d748bfd96a6261055de4194f632190c
2015-05-27 09:22:34 -07:00
Alex Converse
57fefc1d73 Merge "intrabc: Fix probs of illegal modes." into nextgen 2015-05-27 01:03:02 +00:00
Jingning Han
f7a39d7f08 Make the tile coding syntax support large scale tile decoding
This commit makes the bit-stream syntax support fast selective tile
decoding in a large scale tile array. It reduces the computational
complexity of computing the target tile offset in the bit-stream
from quadratic to linear scale, while maintaining relatively small
stack space requirement (in the order of 1024 bytes instead of 1M
bytes). The overhead cost due to tile separation remains identical.

Change-Id: Id60c6915733d33a627f49e167c57d2534e70aa96
2015-05-26 12:54:00 -07:00
Alex Converse
1748a59f83 intrabc: Fix probs of illegal modes.
ibc: derflr -0.069 screen_content -0.085
ibc+tx+pal: derflr +0.017 screen_content -0.029

Change-Id: I79c0ca0a5c38c53afd209286dbcd78873e070098
2015-05-26 12:51:53 -07:00
Jingning Han
7099fd12bd Fix assertion conditions for tile coding
Allow up to 1024 row/col tiles instead of 4 for row tile and 64 for
column tile.

Change-Id: I1702254e241401821f3aaab1645f6df6dbc48b8d
2015-05-26 16:38:15 +00:00
Debargha Mukherjee
a14e3616b3 Merge "Loop_postfilter high bit depth functionality" into nextgen 2015-05-25 08:04:04 +00:00
Zoe Liu
98f6f54d93 Merge "Refined the mv ref candidate selection" into nextgen 2015-05-23 00:00:15 +00:00
Zoe Liu
e84c1d24bc Refined the mv ref candidate selection
Now this is an on-going work on the re-work on the motion vector
references for all Inter coding modes. Currently implementation on
sub8x8 and BLOCK_8X8 is done. More work will be added along the way.

Essetial ideas include:

(1) Added new nearestmv algorithm through adaptive median search, out of
the four nearest neighbors: TOP, LEFT, TOPLEFT, and TOPRIGHT;

(2) Added new sheme for sub8x8 to obtain the mv ref candidates,
specially, mv ref candidates are obtained depending on the sub8x8 mode
of the current block as well as the sub8x8 mode of the neighboring
block;

(3) Added top right corner mv ref candidate whenever it is available;
The adding of the top right mv ref has showed potential in helping such
video clips as bridge_far_cif.

Change-Id: I573c04cd346ed7010f4ad87a6eaa6bab6e2caf9c
2015-05-22 16:06:45 -07:00
Julia Robson
650e12dd63 Loop_postfilter high bit depth functionality
Adding a high bit depth version of the function loop_bilateral_filter()
and ensuring the appropriate version of this function is called when
vp9_highbitdepth is enabled.

Change-Id: I7a78029c733a9a79b3b2f39af0de0824239ad5a3
2015-05-22 10:34:44 -07:00
hui su
8806e25215 Code cleanup in tx-skip expt
No effect on performance

Change-Id: I493da0d4d8fb3a7d95f07574b800cb6c85705229
2015-05-22 10:20:58 -07:00
Pieter Kapsenberg
70ddd92d9a Removing skip inferrence with all 0 TX
If a non-skipped block has all transform blocks with only 0 data, then
decoder infers skip flag. This affects the loopfilter. No real encoder
would do this though, so it is pointless. Also, it causes headaches in
HW implmentations as the loop filter cannot proceed until all TX blocks
in the block have been checked. There could be up to 768 of them in
64x64 4:4:4 with 4x4 transform.

Change-Id: I45a021d1f27ca7feefed2242605777e70ce7cabd
2015-05-21 23:03:16 +00:00
Jingning Han
c238d6cd72 Merge "Enable arbitrary tile size support" into nextgen 2015-05-21 22:56:59 +00:00
Alex Converse
feb3a14e44 Merge "intrabc: Cleanup." into nextgen 2015-05-21 22:27:56 +00:00
Alex Converse
afea20e94c Merge "intrabc: Fix costing for tx_skip." into nextgen 2015-05-21 22:27:47 +00:00
Alex Converse
57f6a6d225 Merge "intrabc: Don't double account for skip" into nextgen 2015-05-21 22:27:40 +00:00
Jingning Han
bae6229884 Merge "Make internal codec support arbitrary tile size" into nextgen 2015-05-21 22:24:28 +00:00
Jingning Han
73ca749ddb Merge "Refactor internal tile_info variables to support 1024 tiles" into nextgen 2015-05-21 22:24:05 +00:00
Jingning Han
ad5ede6e36 Merge "Support up to 64 row tile coding" into nextgen 2015-05-21 22:23:42 +00:00
Jingning Han
c604b9a86c Enable arbitrary tile size support
This commit allows the encoder to process tile coding per 64x64
block. The supported upper limit of tile resolution is the minimum
of frame size and 4096 in each dimension. To turn on, set
--experiment --row-tile
and compile.

It overwrite the old --tile-columns and --tile-rows configurations.
These two parameters now tell the encoder the width and height of
tile in the unit of 64x64 block. For example,
--tile-columns=1 --tile-rows=1
will make a tile contains a single 64x64 block.

Change-Id: Id515749a05cfeb9e9d008291b76bdfb720de0948
2015-05-21 14:57:05 -07:00
Jingning Han
a0d950345b Merge "Support up to 1024 row/column tiles in bit-stream syntax" into nextgen 2015-05-21 19:50:12 +00:00
Jingning Han
a3a3fee09f Merge "Set row and col tile number upper limit as 1024" into nextgen 2015-05-21 19:49:59 +00:00
Alex Converse
1110f09385 intrabc: Cleanup.
Change-Id: I71ad705e579a62563af8282846dbda522c3c971e
2015-05-21 12:00:05 -07:00
Alex Converse
32bec3f0ec intrabc: Fix costing for tx_skip.
ibc+tx+pal: derflr: -0.033 screen_content: -0.145

Change-Id: I446ef1c890eb9afa12454e53b24dc0ef6a80b02b
2015-05-21 12:00:05 -07:00
Alex Converse
5e6ab9935e intrabc: Don't double account for skip
ibc: derflr +0.007 screen_content -0.025
ibc+tx+pal: derflr -0.208 screen_content +0.003

Change-Id: I5e46e84fd545f3810ae7a5d13dc3618e1b077f76
2015-05-21 12:00:05 -07:00
Jingning Han
98339250c1 Make internal codec support arbitrary tile size
This commit allows the internal codec handle arbitrary tile size
in the unit of 64x64 pixel blocks.

Change-Id: I3ad24de392064645bebab887c94e1db957794916
2015-05-21 09:20:31 -07:00
Debargha Mukherjee
d43544137b Rename NEAR_FORNEW to NEW2
Change-Id: I2928b0d28dcbf9c6b705d3ebf20550aeec9b99b3
2015-05-20 17:31:20 -07:00
Jingning Han
225097a7ed Refactor internal tile_info variables to support 1024 tiles
Move the 2D tile info arrays as global variables. This resolves
the local function stack overflow issue due to excessively large
tile info variables. This allows the internal operation to support
up to 1024 row and column tiles.

Change-Id: I6644cc929e5d3a778a5c03a712ebfc0b8729f576
2015-05-20 10:19:01 -07:00
Jingning Han
8e3099aa2b Support up to 64 row tile coding
This commit allows the codec to use up to row tiles (optionally
in combination with up to 64 column tiles per row tile). The
minimum tile size is set to be 256x256 pixel block.

Change-Id: I811ca93f0c5eba41e190f6c7c0f064d1083f530f
2015-05-19 17:27:05 -07:00
Jingning Han
97adfb32bd Support up to 1024 row/column tiles in bit-stream syntax
Add syntax support to allow up to 1024 row/column tiles
respectively.

Change-Id: I84278589364b658d6c4dd05f0771795f732ad68f
2015-05-19 17:20:36 -07:00
Jingning Han
46afda0908 Set row and col tile number upper limit as 1024
Increase the supported row and col tile numbers from 4 and 64,
respectively to 1024 both.

Change-Id: Ic07435ff6783940a466a549a69a11ab3faf3247a
2015-05-19 17:20:36 -07:00
Jingning Han
f5445e124c Rename variables in tile info decoding
The max and min tile number reference should be used to support
both row and column tiles. This commit renames the previous col
prefix to avoid confusion.

Change-Id: I487bea43701af946b79023597a9a9a0516480380
2015-05-19 17:20:36 -07:00
Zoe Liu
2bbddcf0a5 Removed the unused modes newmvref and compound-modes
Change-Id: Ia51913d48a09a7ea7502e8c49ee0159492e58b96
2015-05-19 16:20:37 -07:00
Zoe Liu
6437c3cb6d Combined two experiments of NEWMVREF and COMPOUND_MODES to NEW_INTER
Runborgs results on derflr show consistent results between NEW_INTER
and the previous combination of NEWMVREF and COMPOUND_MODES.

Change-Id: Ieba239c4faa7f93bc5c05ad656a7a3b818b4fbfc
2015-05-19 14:04:22 -07:00
Julia Robson
0a1c529b26 Merge "Fix mismatch in handling of 8x4/4x8 blocks with supertx" into nextgen 2015-05-19 16:06:26 +00:00
Pieter Kapsenberg
418956690e Removing unnecessary syntax remaping for mc filter type
Change-Id: Iba067eb2bcf519dc5776976c3ab0a694ff3feb12
2015-05-18 13:56:56 -07:00
Julia Robson
8718262437 Fix mismatch in handling of 8x4/4x8 blocks with supertx
Test VP9/EndToEndTestLarge.EndtoEndPSNRTest/1 (422 stream) failed when
supertx enabled. This was because 4x8 and 8x4 blocks were not being
split into 4x4s during tokenization in the encoder. This patch
uses vp9_foreach_transformed_block() to fix this.

Change-Id: I1f1cb27474eb9e04347067f5c4aff1942bbea8d9
2015-05-18 11:59:51 +01:00
hui su
10834f4373 Merge "Fix a bug in tx-skip experiment" into nextgen 2015-05-18 04:31:27 +00:00
Debargha Mukherjee
e82fffd416 Row tile fix
Fixes mismatch with intrabc experiment.

Change-Id: I1d83a8aa5584fb35396351f7fae7f9365598d00f
2015-05-15 08:01:21 -07:00
Debargha Mukherjee
520e861e03 Merge "Global motion enhancements" into nextgen 2015-05-15 05:48:26 +00:00
Debargha Mukherjee
fb093a337f Global motion enhancements
Adds warping functions. Also includes some refactoring.

Change-Id: I909830650f29046edf108ddaddceb1a5e7c6c61c
2015-05-14 16:33:01 -07:00
Zoe Liu
987d44f5d0 Added a new experiment "NEW_INTER"
Down the road this experiment will combine and replace both NEWMVREF
and COMPOUND_MODES.

Change-Id: I383291f94f3e80e5cbbabab45e31c4b48669f2e5
2015-05-14 14:39:45 -07:00
hui su
4fcb86251d Fix a bug in tx-skip experiment
Fix potential mismatch.

Change-Id: I51f9241c73d70c0c38fd7e2c15f4381350b60388
2015-05-12 09:38:14 -07:00
Julia Robson
b4d8b235dd Changed tokenize to correct tx_size for 440 input
Change-Id: I41995cfa03038ec45b5f0d6c68195cfa36d58ec8
2015-05-12 09:34:04 -07:00
Zoe Liu
60b71edf2b Merge "Removed unused macro for INTERINTRA" into nextgen 2015-05-12 00:25:01 +00:00
Zoe Liu
d29384192c Removed unused macro for INTERINTRA
Change-Id: Ibdf4da969c17d4b1dff14a777ccb405763a62b75
2015-05-11 13:01:25 -07:00
Jingning Han
7a2f9bbda4 Add row tile coding support in bit-stream
Fix the row tile boundary detection issues. This allows to use
more resources for parallel encoding/decoding when avaiable.

Change-Id: Ifda9f66d1d7c2567dd4e0a572a99a83f179b55f9
2015-05-11 12:30:03 -07:00
Zoe Liu
9e0466d0fd Cleaned mv search code and added a few fixes on the experiments
Besides code cleaning, this patch contains 3 fixes:
(1) Fixed the COMPOUND_MODES for the NEW_NEWMV mode;
(2) Fixed the joint search when the NEAR_FORNEWMV mode (in NEWMVREF)
is being evaluated;
(3) Fixed the WEDGE_PARTITION when the NEAR_FORNEWMV mode (in NEWMVREF)
is being evaluated.
(4) Adjusted the entropy probability value for NEAR_FORNEW mode.

On derflr turning on all 14 experiments (except for global-motion), the
average gain w.r.t. PSNR is +0.07%:
Maximum on bridge_far_cif: +1.02%
Minimum on hallmonitor_cif: -0.16%

Change-Id: I4c9c6ee24a981af7e655a629580641d9f9745f91
2015-05-10 23:38:44 -07:00
hui su
bada9f0b87 Merge "Optimize entropy coding of non-transform tokens" into nextgen 2015-05-08 18:18:49 +00:00
Alex Converse
d28a10870f Merge "Try non-traditional intra prediction even when spatial isn't good." into nextgen 2015-05-08 01:27:13 +00:00
hui su
00c793ee5f Optimize entropy coding of non-transform tokens
Use separate token probabilities and counters for non-transform
blocks (pixel domain) . Initial probabilities are trained with screen_content
clips. On screen_content, it improves coding performance by about
2% (from +16.4% to +18.45%).

The initial probabilities are not optimized for natural videos. So it should
not be used for natural videos. Set FOR_SCREEN_CONTENT as 0/1 to specify
whether or not to enable this patch.

Change-Id: Ifa361c94bb62aa4b783cbfa50de08c3fecae0984
2015-05-07 07:58:19 -07:00
Debargha Mukherjee
e6889b28e9 Merge "Fix a bug in copy_mode experiment" into nextgen 2015-05-07 05:10:01 +00:00
Debargha Mukherjee
5e7bc81128 Merge "Global motion continued" into nextgen 2015-05-07 05:09:34 +00:00
Yaowu Xu
d1f04fb5b2 Fix a bug in copy_mode experiment
Change-Id: I1cf7d51ba99e5b6f5cf7e0d1a5d86ce4f19046e5
2015-05-06 17:03:32 -07:00
Peter de Rivaz
d6153aa447 Added highbitdepth sse2 acceleration for quantize and block error
This is a partial cherry-pick of db7192e

Change-Id: Idef18f90b111a0d0c9546543d3347e551908fd78
2015-05-06 15:14:01 -07:00
Debargha Mukherjee
caae13d54f Global motion continued
Implements a first version of global motion where the
existing ZEROMV mode is converted to a translation only
global motion mode.
A lot of the code for supporting a rotation-zoom affine
model is also incorporated.
WIP.

Change-Id: Ia1288a8dfe82f89484d4e291780288388e56d91b
2015-05-06 14:59:38 -07:00
Alex Converse
47cd96fb49 Try non-traditional intra prediction even when spatial isn't good.
Change-Id: I3a9b94d52cc0e962d91827a9b7ca8b65e82130ca
2015-05-06 10:23:22 -07:00
Peter de Rivaz
16add99f0d Corrected optimization of 8x8 DCT code
The 8x8 DCT uses a fast version whenever possible.
There was a mistake in the checking code which
meant sometimes the fast version was used when it
was not safe to do so.

Change-Id: I154c84c9e2d836764768a11082947ca30f4b5ab7
2015-05-06 10:10:19 -07:00
Peter de Rivaz
6aed50370c Added tests for high bitdepth variance sse2 functions
Change-Id: I72735e2e07464a0f7e44968fb14a195c84a58992
2015-05-06 10:10:19 -07:00
Peter de Rivaz
ecf677ede6 Fixed idct16x16_10 highbitdepth transform
In the case when there are only non-zero coefficients
in the first 4x4 block a special routine is called.
The highbitdepth optimized version of this routine
examined the wrong positions when deciding whether
to call an assembler or C inverse transform.

Change-Id: I62da663ca11775dadb66e402e42f4a1cb1927893
2015-05-06 10:10:18 -07:00
Deb Mukherjee
963393321c Iadst transforms to use internal low precision
Change-Id: I266777d40c300bc53b45b205144520b85b0d6e58
2015-05-06 10:10:18 -07:00
Peter de Rivaz
2dad1a7c8e Added high bitdepth sse2 transform functions
Change-Id: If359f0e9a71bca9c2ba685a87a355873536bb282
2015-05-06 10:10:18 -07:00
Peter de Rivaz
2189a51891 Added sse2 acceleration for highbitdepth variance
This is a combination of:
  4a19fa6 Added sse2 acceleration for highbitdepth variance
  c6f5d3b Fix high bit depth assembly function bugs

Change-Id: I446bdf3a405e4e9d2aa633d6281d66ea0cdfd79f
2015-05-06 10:04:08 -07:00
Peter de Rivaz
41973e0e3e Refactored idct routines and headers
This change is made in preparation for a
subsequent patch which adds acceleration
for the highbitdepth transform functions.

The highbitdepth transform functions attempt
to use 16/32bit sse instructions where possible,
but fallback to using the C implementations if
potential overflow is detected.  For this reason
the dct routines are made global so they can be
called from the acceleration functions in the
subsequent patch.

Change-Id: Ia921f191bf6936ccba4f13e8461624b120c1f665
2015-05-06 09:59:20 -07:00
Peter de Rivaz
0e82cba628 Added highbitdepth sse2 SAD acceleration and tests
Change-Id: I9f09e404e3136951e5cc15bf40b915c1fe10b620
2015-05-06 09:00:53 -07:00
Yaowu Xu
846396ddda Enable build with vs20013
Change-Id: I0592b9e92c3ca45e0a81d9ce49a9f2381bec3e39
2015-05-04 14:08:52 -07:00
Zoe Liu
9b083e8271 Changed nearmv for one of the sub8x8 partitions
It is a minor change, but the essential idea is to use the mv of the
top right block as the nearmv for the bottom left partition in the
sub8x8 block. The change is under the experiment of NEWMVREF.

When all 13 experiments are on (except for INTRABC), the gain is +0.05%:
Worse on bowing_cif: -0.17%
Best on foreman_cif: +0.42%; and bridge_far_cif: +0.40%
The total 13 experiments achieved a gain of +6.97% against base.

Change-Id: I3a51d9e28b34b0943fe16a984d62bfb38304ebca
2015-04-30 22:59:32 -07:00
Alex Converse
9b638cded6 tx_skip: Avoid undefined shift behavior.
vp9_quantize_rect did illegal shifts but didn't use the results.
The shift |a << b| is unfortunately undefined if |a < 0|, but the
more verbose |a * (1 << b)| generates the same machine code.

Change-Id: I7ceac66fa20a700630cf8ed008949146b161dab4
2015-04-30 12:56:27 -07:00
Alex Converse
aaa50de4ca Fix integer overflows in TX skipping
Change-Id: Ic1fc0f1271065180cffcbd2906e8faac6d07d08d
2015-04-30 11:42:31 -07:00
Debargha Mukherjee
4e3cf9bdfd Merge "Consolidate common count updates" into nextgen 2015-04-29 22:08:26 +00:00
Debargha Mukherjee
735360f70e Consolidate common count updates
Cleanup - does not have any change in RD performance.

Change-Id: Iaca9c7378b294bd8c780958f5e33e697690eebfa
2015-04-29 14:12:03 -07:00
Yaowu Xu
dfa47eb64b Merge "Add a necessary include file" into nextgen 2015-04-28 23:48:50 +00:00
Yaowu Xu
9d5035ce38 Add a necessary include file
The include is necessary for --enable-coefficient-range-checking

Change-Id: I5cf7b2fca0ddd610815398b1e77f17df42f9785c
2015-04-28 15:44:16 -07:00
Yaowu Xu
5652851391 Merge changes I33c72799,I3ee8974a,I38a42ed1,Iaad3dc3c into nextgen
* changes:
  usage.dox: fix doxygen warnings in 1.8.x
  Fix doxygen warning with usage.dox
  Remove obsolete doxygen tags
  Fix comments for doxygen
2015-04-28 21:16:10 +00:00
Alex Converse
8d9c600d44 Merge "palette: Add missing consts" into nextgen 2015-04-28 19:51:16 +00:00
James Zern
368f7c806a usage.dox: fix doxygen warnings in 1.8.x
use \li to denote list items with \if.

fixes the following likely visible in <1.8.3:
usage.dox: warning: Invalid list item found
usage.dox: warning: End of list marker found without any preceding list items

Change-Id: I33c72799edf9f8866596ac8f79247050b8c75681
2015-04-28 12:07:56 -07:00
Yaowu Xu
4674152287 Fix doxygen warning with usage.dox
Change-Id: I3ee8974a66f186fb0eb15b1078a3c7b9cbf5ec80
2015-04-28 12:07:56 -07:00
Yaowu Xu
856e549027 Remove obsolete doxygen tags
Change-Id: I38a42ed1d0be4fbfce6c9f3f5d021055107933d7
2015-04-28 12:07:56 -07:00
Alex Converse
cb437f800f Merge "Refactor 4:4:4 palette selection." into nextgen 2015-04-28 19:07:41 +00:00
Yaowu Xu
b1f93f56a1 Fix comments for doxygen
Change-Id: Iaad3dc3cdd25275939b475706eb7d136a5a10174
2015-04-28 12:06:56 -07:00
Alex Converse
7ae0b65f32 palette: Add missing consts
Change-Id: I83a2e57dc5dbc328c7bfea421ffbaeb83b7ca3bd
2015-04-28 11:35:17 -07:00
Alex Converse
d0cb4e75bc Refactor 4:4:4 palette selection.
Move 444 palette selection out of vp9_rd_pick_intra_mode_sb and into
a subfunction.

Change-Id: Ib323b740318626e2a68cd3d106dbd27c8f4652a6
2015-04-28 11:21:04 -07:00
hui su
1f7b49f7cd Use uniform quantization settings for non-transform blocks
Do not treat first element (dc) differently.

on screen_content
tx-skip only: +16.4% (was +15.45%)

no significant impact on natrual videos

Change-Id: I79415a9e948ebbb4a69109311c10126d8a0b96ab
2015-04-28 07:54:16 -07:00
hui su
761cd0b010 Fix bugs in palette and intrabc expt
palette expt: correctly update color buffer
intrabc expt: update zcoeff_blk so that residue coding will not
              be mistakenly skipped

Change-Id: I870f5b742c2ac394f4c871aa65e6591e293d8ef6
2015-04-27 15:27:11 -07:00
Alex Converse
98d4f09a7a Replace vp9_get_bit_depth with vp9_ceil_log2.
The current name is confusing with regard to high bit depth buffers.

Change-Id: Ieacd55ec22c81bd2f013f2e3d73a095affc93689
2015-04-23 10:26:57 -07:00
Debargha Mukherjee
96213ac5e7 Merge "Some minor improvements in bilateral filter expt." into nextgen 2015-04-23 01:14:45 +00:00
Debargha Mukherjee
425a45a45c Some minor improvements in bilateral filter expt.
Changes include:

* Uses double for RD cost computation to guard against overflow
for large resolution frames.
* Use previous frame's filter level to code the level better.
* Change precision of the filter parameters.
* Allow spatial variance for x and y to be different

Change-Id: I1669f65eb0ab1e8519962954c92d59e04f1277b7
derflr: +0.556% (a little up from before)
2015-04-22 18:09:42 -07:00
hui su
9e0750c2d2 Modify scan order for non-transform coding blocks
Use raster scan order for non-transform blocks

+15.45% (+2.1%) on screen_content
no significant change on natural videos

Change-Id: I0e264cb69e8624540639302d131f7de9c31c3ba7
2015-04-21 14:23:52 -07:00
hui su
33207fb170 Remove unused variable in new-quant expt
remove dequant_val_nuq in macroblock_plane

Change-Id: I4b4070ae2d01c2403c781433030204d6e95c3750
2015-04-20 11:14:51 -07:00
Alex Converse
90b3838fca Merge "Don't use old uv scores for NEWDV and cleanup mbmi saving." into nextgen 2015-04-17 12:47:23 -07:00
hui su
ebd3666940 Merge "Add high bit depth support for tx-skip expt" into nextgen 2015-04-17 11:37:39 -07:00
Alex Converse
e45e18593b Don't use old uv scores for NEWDV and cleanup mbmi saving.
Change-Id: Ic0fae1b348ad7659e4a41db29d075ae5eb6cdc82
2015-04-17 10:54:33 -07:00
Debargha Mukherjee
fb001c2e2f Merge "Simplify bilateral filter search for speed" into nextgen 2015-04-16 18:58:03 -07:00
Debargha Mukherjee
017baf9f4b Simplify bilateral filter search for speed
Adds an internal buffer in the encoder to store the deblocked
result to help speed up the search for the best bilateral filter.

Very small change in performance but a lot faster:
derflr: +0.518%

Change-Id: I5d37e016088e559c16317789cfb1c2f49334b2b9
2015-04-16 15:33:34 -07:00
hui su
8c00c7a9cd Fix palette expt asan failure
Account for 422 video format.

Change-Id: Ic5af661720fc5fa7142210d907dd25e1e79ff653
2015-04-16 15:08:06 -07:00
hui su
b69152db79 Add high bit depth support for tx-skip expt
+0.3% on 10-bit
+0.3% on 12-bit

With other high bit compatible experiments on 12-bit
+12.44% (+0.17) over 8-bit baseline

Change-Id: I40b4c382fa54ba4640d08d9d01950ea8c1200bc9
2015-04-16 14:54:39 -07:00
hui su
871c51b30a Fix a bug in tx_skip expt
tx_skip is not enabled for sub8x8 blocks.

Change-Id: I3797238735f85fb2bd07b50ca2845611b198bff6
2015-04-14 11:25:55 -07:00
hui su
294159d41e Merge "refactoring in tx_skip experiment" into nextgen 2015-04-14 08:12:08 -07:00
hui su
261a9bac5a refactoring in tx_skip experiment
simplify code logic

Change-Id: Ifafc712f3f85abafadb429a04e295cf8cbb185d2
2015-04-13 17:14:05 -07:00
Debargha Mukherjee
febb434356 Merge "High bit-depth support for wedge partition expt" into nextgen 2015-04-13 10:09:51 -07:00
Debargha Mukherjee
343c092e2e High bit-depth support for wedge partition expt
Change-Id: Idbd27e66d4f4a7953f888137d5752856215a6760
2015-04-13 09:28:15 -07:00
hui su
359bf925ce Fix a mismatch bug
In the tx_skip experiment, dpcm is not used for 64x64 blocks.

Change-Id: Iafbed3b5e411954b80e898f10def3757f2cf44c1
2015-04-11 09:38:49 -07:00
Debargha Mukherjee
8fa0b12cf7 Merge "An experiment introducing a bilateral loop filter" into nextgen 2015-04-10 16:46:16 -07:00
Debargha Mukherjee
fe4b6ac652 An experiment introducing a bilateral loop filter
Adds a framework to incorporate a parameterized loop
postfilter in the coding loop after the application of the
standard deblocking loop filter.

The first version uses a straight bilateral filter
where the parameters conveyed are just spatial and
intensity gaussian variances.

Results on derflr:
+0.523% (only with this experiment)
+6.714% (with all expts other than intrabc)

Change-Id: I20d47285b4d25b8c6386ff8af2a75ff88ac2b69b
2015-04-10 16:05:00 -07:00
hui su
bfc27bb614 tx-skip experiment: improve entropy coding of coeff tokens
This patch allows the prediction residues of tx-skipped blocks
to use probs that are different from regular transfrom
coefficients for token entropy coding. Prediction residues are
assumed as in band 6.

The initial value of probs is obtained with stats from limited
tests. The statistic model for constrained token nodes has not
been optimized. The probs for token extra bits have not been
optimized. These can be future work.

Certain coding improvment is observed:
derflr with all experiments:                +6.26%  (+0.10%)
screen_content with palette:               +22.48%  (+1.28%)

Change-Id: I1c0d78178ee9f3655febb6f30cdaef8ee9f8e3cc
2015-04-10 11:33:42 -07:00
Debargha Mukherjee
b19df73ce8 Preparation for end to end test turn on
Change-Id: Ibc53bf50c8164b413749aaa8baa08e2f6e928e1b
2015-04-03 16:44:40 -07:00
Alex Converse
16e5e713fa Add an intra block copy mode (NEWDV).
Change-Id: I82b261c54ac9db33706bb057613dcbe66fc71387
2015-04-03 11:59:57 -07:00
Zoe Liu
e1cae5eebf Clean the COMPOUND_MODES mv initialization for sub8x8
Change-Id: I04f4ad41c002c761d55093432d6c437c25e5bddd
2015-04-02 16:30:48 -07:00
Zoe Liu
2ae3d4f266 Add a new PREDICTION mode using NEARMV as ref mv
This experiment, referred as NEWMVREF, also merged with NEWMVREF_SUB8X8
and the latter one has been removed. Runborgs results show that:

(1) Turning on this experiment only, compared against the base:
derflf: Average PSNR 0.40%; Overall PSNR 0.40%; SSIM 0.35%
(2) Turning on all the experiments including this feature, compared against
that without this feature, on the highbitdepth case using 12-bit:
derflf: Average PSNR 0.33%; Overall PSNR 0.32%; SSIM 0.30%.

Now for highbitdepth using 12-bit, compared against base:
derflf: Average PSNR 11.12%; Overall PSNR 11.07%; SSIM 20.27%.

Change-Id: Ie61dbfd5a19b8652920d2c602201a25a018a87a6
2015-04-02 14:37:22 -07:00
hui su
9eada94a3e palette experiment: remove run-length coding
Change-Id: I1e52475d0179cf019841d09a53b3b7fc53c79336
2015-03-31 11:09:30 -07:00
hui su
65d39f9fae Merge "Palette experiment: encode color indices based on context" into nextgen 2015-03-26 18:34:43 -07:00
hui su
a3af20f56e Merge "Palette experiment: adaptly update probs" into nextgen 2015-03-26 18:34:28 -07:00
hui su
6ad18db24f Palette experiment: encode color indices based on context
The basic idea is to use a pixel’s neighboring colors as
context to predict its own color. Up to 4 neighbors are
considered here: left, left-above, above, right-above.
To reduce the number of contexts,  the combination of any
4 (or less) colors are mapped to a reduced number of
patterns. For example, 1111, 2222, 3333, … , can be mapped
to the same pattern: AAAA. SImilarly, 1122, 1133, 2233, …,
can be mapped to the pattern AABB. In this way, the total
number of color contexts is reduced to 16.

This almost doubles the gain of palette coding on screen
content videos.

on screen_content
--enable-palette                                  +14.2%
--enable-palette --enable-tx-skip                 +21.2%

on derflr
--enable-palette                                  +0.12%
with all other experiments                        +6.16%

Change-Id: I560306dae216f2ac11a9214968c2ad2319fa1718
2015-03-26 15:48:08 -07:00
Debargha Mukherjee
3d965883f4 Merge "Add palette coding mode for inter frames" into nextgen 2015-03-26 11:59:36 -07:00
hui su
e18b104462 Palette experiment: adaptly update probs
Also make changes to transmit palette-enabled flag using
neighbor blocks as context.

on screen_content
--enable-palette                            +7.35%

on derflr
with all other experiments                  +6.05%

Change-Id: Id6c2f726d21913d54a3f86ecfea474a4044c27f6
2015-03-25 09:12:57 -07:00
Zoe Liu
2a5648dca5 Cleaned the code in handle_inter_mode
borgs show consistent results as before this patch

Change-Id: I3d21623cb03ea169a031328e9dde9c26ba1bd016
2015-03-23 15:33:25 -07:00
hui su
070d635657 Add palette coding mode for inter frames
on screen_content
--enable-palette                                    +6.74%

on derflr
with all other experiments                          +6.02%
(--enable-supertx --enable-copy-mode
 --enable-ext-tx --enable-filterintra
 --enable-tx64x64 --enable-tx-skip
 --enable-interintra --enable-wedge-partition
 --enable-compound-modes --enable-new-quant
 --enable-palette)

Change-Id: Ib85049b4c3fcf52bf95efbc9d6aecf53d53ca1a3
2015-03-23 08:41:51 -07:00
Deb Mukherjee
73dcd41b72 Merge "Make interintra experiment work with highbitdepth" into nextgen 2015-03-22 22:48:56 -07:00
Deb Mukherjee
c082df2359 Make interintra experiment work with highbitdepth
Also includes some adjustments to the algorithm.
All stats look good.

Change-Id: I824ef8ecf25b34f3feb358623d14fe375c3e4eb7
2015-03-21 07:35:40 -07:00
Deb Mukherjee
8c5ac79e66 Some build fixes with highbitdepth and new quant
Highbitdepth performance about the same as 8-bit.

Change-Id: If737962d8588dd190083edae4383b731f9d22873
2015-03-21 06:53:58 -07:00
Deb Mukherjee
c8ed36432e Non-uniform quantization experiment
This framework allows lower quantization bins to be shrunk down or
expanded to match closer the source distribution (assuming a generalized
gaussian-like central peaky model for the coefficients) in an
entropy-constrained sense. Specifically, the width of the bins 0-4 are
modified as a factor of the nominal quantization step size and from 5
onwards all bins become the same as the nominal quantization step size.
Further, different bin width profiles as well as reconstruction values
can be used based on the coefficient band as well as the quantization step
size divided into 5 ranges.

A small gain currently on derflr of about 0.16% is observed with the
same paraemters for all q values.
Optimizing the parameters based on qstep value is left as a TODO for now.

Results on derflr with all expts on is +6.08% (up from 5.88%).

Experiments are in progress to tune the parameters for different
coefficient bands and quantization step ranges.

Change-Id: I88429d8cb0777021bfbb689ef69b764eafb3a1de
2015-03-17 21:42:55 -07:00
Alex Converse
9a92891ac4 interintra: wedge: Get the correct wedge params.
Fixes an asan issue.

Change-Id: I671ffc382c77c2b38673e0b148f54e7bce2ce9c2
2015-03-17 10:49:22 -07:00
Alex Converse
7ca745a2df palette: Fix an illegal read
Change-Id: I71649f0a85d98b96efd08c8a9e3ee7372fd7d327
2015-03-16 17:13:15 -07:00
Deb Mukherjee
961fe77e70 Merge "Misc changes to support high-bitdepth with supertx" into nextgen 2015-03-12 17:42:20 -07:00
Deb Mukherjee
35d38646ec Misc changes to support high-bitdepth with supertx
Change-Id: I0331646d1c55deb6e4631e64bd6b092fb892a43e
2015-03-12 16:52:25 -07:00
Zoe Liu
0337ae5218 Fixed a bug & a build warning for newmvref-sub8x8
Change-Id: I799fc3fb4c1201da14c97bf66e06dec655f6a620
2015-03-12 11:31:33 -07:00
hui su
7621c779e5 Add palette coding mode for UV
For 444 videos, a single palette of 3-d colors is
generated for YUV. For 420 videos, there may be two
palettes, one for Y, and the other for UV.

Also fixed a bug when palette and tx-skip are both on.

on derflr
--enable-palette                    +0.00%
with all experiments                +5.87% (was +5.93%)

on screen_content
--enable-palette                    +6.00%
--enable-palette --enable-tx_skip   +15.3%

on screen_content 444 version
--enable-palette                    +6.76%
--enable-palette --enable-tx_skip   +19.5%

Change-Id: I7287090aecc90eebcd4335d132a8c2c3895dfdd4
2015-03-10 13:38:19 -07:00
Debargha Mukherjee
ee2f0bdfcd Merge "Global motion work continued" into nextgen 2015-03-10 11:27:04 -07:00
Spencer Egart
faaaf85fc3 Global motion work continued
Interface change for the global Mv functions.

Change-Id: Ie4722faa638ac557f99743f7b33ff46c3d29e9a1
2015-03-10 10:47:12 -07:00
Deb Mukherjee
d835821fa1 Merge "Make filterintra experiment work with highbitdepth" into nextgen 2015-03-10 10:42:58 -07:00
Deb Mukherjee
78bcc48756 Make filterintra experiment work with highbitdepth
All stats look fine.
derflr: +0.912 with respect to 10-bit internal baseline
               (Was +0.747% w.r.t. 8 bit)
        +5.545 with respect to 8-bit baseline

Change-Id: I3c14fd17718a640ea2f6bd39534e0b5cbe04fb66
2015-03-10 07:59:59 -07:00
Alex Converse
efe2b3cbc6 Fix tx_skip debug build.
Change-Id: I20a3e4e34f10485aa5e6723cd33b0311bdbf1320
2015-03-09 14:57:13 -07:00
Yaowu Xu
41eb20d1e9 Add encoder control for setting color space
This commit adds encoder side control for vp9 to set color space info
in the output compressed bitstream.

It also amends the "vp9_encoder_params_get_to_decoder" test to verify
the correct color space information is passed from the encoder end to
decoder end.

Change-Id: Ibf5fba2edcb2a8dc37557f6fae5c7816efa52650
(cherry picked from commit e94b415c3479129944a69fafbeacf550fb9237b7)
2015-03-06 16:42:09 -08:00
Yaowu Xu
63537df4c0 Enable decoder to pass through color space info
This commit added a field to vpx_image_t for indicating color space,
the field is also added to YUV_BUFFER_CONFIG. This allows the color
space information pass through the decoder from input stream to the
output buffer.

The commit also updates compare_img() function with added verification
of matching color space to ensure the color space information to be
correctly passed from encode to decoder in compressed vp9 streams.

Change-Id: I412776ec83defd8a09d76759aeb057b8fa690371
(cherry picked from commit 6b223fcb588c865ae6f5abfd3d9de3ba2ae0540f)
2015-03-06 15:57:12 -08:00
Yaowu Xu
b7913deb7e Added plumbing for setting color space
Change-Id: If64052cc6e404abc8a64a889f42930d14fad21d3
(cherry picked from commit ce52b0f8d347224cd526dc1ba55597a2aa79c341)
2015-03-06 14:51:49 -08:00
James Zern
cd152849ea vp9_highbd_tm_predictor_16x16: fix win64
by saving xmm8; cglobal's xmm reg arg is 0-based

Change-Id: Ic8426ec9ac59ab4478716aa812452a6406794dcb
(cherry picked from commit 923cc0bf51a24d05c6aa68f80e09d485a54431f6)
2015-03-06 13:29:00 -08:00
Yaowu Xu
6fcaa06911 Correct the miscalculation in uv dimensions
The calculation of required extension used in HBD case was wrong due
to rounding for UV when y dimension is odd. This commit replace the
computation with correct version.

This fixes a crash caused by writting beyond buffer boundary.

Change-Id: Ic7c9afeb7388cd1341ec4974a611dacfb74ac6b6
(cherry picked from commit 4bca73b609bfe9a5cb86fc25b69c6128d9041504)
2015-03-06 09:47:57 -08:00
Yaowu Xu
7b4ff46175 Prevent VP8 encoding crash
This commit changes the value of highbitdepth flag to avoid conflict
with vp8 refresh_last_frame flag.

Change-Id: Idcff2cf44f0a200bd935b326f785c0cf32d7228a
(cherry picked from commit dd27307cac5ac7f346888d219877041563eea0a2)
2015-03-06 09:47:56 -08:00
Zoe Liu
cf004a0845 Merge "Fixed the build for newmvref-sub8x8" into nextgen 2015-03-06 08:54:11 -08:00
Zoe Liu
6c7b4ed355 Fixed the build for newmvref-sub8x8
Change-Id: Ie042001e69d80b1fc52368f29617ad2e51a5e250
2015-03-06 00:01:30 -08:00
Zoe Liu
756a18663c Merge "Cleaned code further for newmvref-sub8x8 and compound-modes" into nextgen 2015-03-05 15:41:28 -08:00
Zoe Liu
1192f99976 Cleaned code further for newmvref-sub8x8 and compound-modes
Change-Id: I9f869c37566aaf81910d1d6ab1b2ac0d2a2f0a23
2015-03-05 15:40:36 -08:00
Zoe Liu
e222d46658 Merge "Changed mv ref to nearestmv always for sub8x8" into nextgen 2015-03-05 11:57:21 -08:00
Zoe Liu
b359952c2c Changed mv ref to nearestmv always for sub8x8
For all sub8x8 partition, the mv ref has changed to its own nearest_mv
instead of the nearest_mv of the super 8x8 block:

--enable-newmvref-sub8x8: ~0.1% gain for derflr

Besides the above new experiment, code has been cleaned largely for the
sub8x8 motion search, such that the mv ref can be fairly easily changed to
use other options, e.g., the next step's global motion effort.

Change-Id: I8e3f4aaa8553ba8c445369692e079db5ce282593
2015-03-05 11:09:58 -08:00
Zoe Liu
a9040ea40c Corrected comment in mode_2_counter for compound
Change-Id: I5459550e62cff79182fa0ac5a24edb56cb64d608
2015-03-04 10:16:25 -08:00
Zoe Liu
30720adf6e Fixed the build for denoiser in new compound mode
Change-Id: Ifb824ce87db9c00c8c87f52d9b8718669fb39d05
2015-03-04 09:29:05 -08:00
Deb Mukherjee
4c1049d7a8 Some fixes to quantization and compiler warnings
The bugs affected only the tx64x64 experiment. This patch fixes
them.

Also fixes some compiler warnings

Change-Id: I4cf1e24a4f1fa59831bf29750cf6daa8373e8e8f
2015-03-03 14:07:17 -08:00
Deb Mukherjee
9909903229 Adds translation model to global motion estimation
Change-Id: Ie1791ab7cfdd3f7a1b03404627246c923f1bd51f
2015-02-25 09:57:33 -08:00
hui su
caccf06acd Palette-based coding experiment
Added palette coding option for Y channel only, key frame only.
Palette colors are obtained with k-means clustering algorithm.
Run-length coding is used to compress the color indices.

On screen_content:
--enable-palette                            + 5.75%
--enable-palette --enable-tx_skip           +15.04% (was 13.3%)

On derflr:
--enable-palette                            - 0.03%
with all the other expriments               + 5.95% (was 5.98%)

Change-Id: I6d1cf45c889be764d14083170fdf14a424bd31b5
2015-02-23 09:23:50 -08:00
Zoe Liu
7d8840a082 Removed redundant src_mi in mv ref candidates
Change-Id: I4eb144e7c9d2c8568388ae58001cc7b7498967e4
2015-02-19 09:44:05 -08:00
Spencer Egart
d8983f0dd7 Global Motion block-based
Uses block-based motion fields with ransac to find transformation between
frames.

Change-Id: I6293fbb690cdad854a1140fb6af76b326abfe964
2015-02-18 11:52:39 -08:00
Spencer Egart
edffe3f956 Global motion experiment
Added a function to compute a motion field for a pair of buffers, for use in
finding an affine transform or homography.

Change-Id: Id5169cc811a61037e877dfd57fccaca89d93936f
2015-02-10 11:15:39 -08:00
Deb Mukherjee
2aef964519 Merge "Adds code for corner detection and ransac" into nextgen 2015-02-10 08:18:03 -08:00
Deb Mukherjee
1fc70e47cd Adds code for corner detection and ransac
This code is to start experiments with global motion models.

The corner detection can be either fast_9 or Harris.
Corner matching is currently based on normalized correlation.
Three flavors of ransac are used to estimate either a
homography (8-param), or an affine model (6-param) or a
rotation-zoom only affine model (4-param).

The highest level API for the library is in vp9_global_motion.h,
where there are two functions - one for computing a single model
and another for computing multiple models up to a maximum number
provided or until a desired inlier probability is achieved.

Change-Id: I3f9788ec2dc0635cbc65f5c66c6ea8853cfcf2dd
2015-02-10 00:48:56 -08:00
Zoe Liu
48da7bf004 Cleaned up the COMPOUND_MODES code in sub8x8
Change-Id: I571ff39799c3257b5c6db82660364ce412c7f6e2
2015-02-09 11:58:54 -08:00
hui su
2118f66a91 Enable tx_skip for inter blocks
Enable tx_skip for inter blocks whose q-index is smaller than 64.

tx_skip experiment alone:
derflr: +0.233% (was +0.038%)

all experiments:
derflr: +5.98% (was +5.94%)

Change-Id: I35245a476ff7039fec8468a92a6aa63feaf74831
2015-02-08 17:57:51 -08:00
hui su
1ae3989558 Fix a bug in filterintra experiment
All expts together: +5.946% (up about 0.3%)

Change-Id: If686e5e97209b4cc4a8115f920e1f4f35ded5a1d
2015-01-31 00:43:06 -08:00
Yue Chen
2ed2f29d21 Fix a bug in COPY_MODE + EXT_TX experiment
Remove the duplicated step counting the overhead for ext_tx, because
it has been counted in super_block_yrd().

Change-Id: I50bc01d8166572bc0847305565cf33c14ee516e6
2015-01-27 12:02:54 -08:00
Jingning Han
50cab76f12 Removal of legacy zbin_extra / zbin_oq_value.
Change-Id: I07f77a63aa98087626e45c4e87aa5dcafc0b0b07
(cherry picked from commit d0f237702745c4bfc0297d24f9465f960fb988ed)
2015-01-21 20:37:19 -08:00
Deb Mukherjee
7a993f850e Adds inter-intra combination with wedge partitions
Also fixes some build issues with certain experimental combinations.

Results on derflr with all experiments on: +5.516%

Change-Id: I9b492f3d3556bd1f057005571dc9bee63167dd95
2015-01-21 15:45:22 -08:00
Deb Mukherjee
760219d0fd Some build fixes
Related zbin boost removal.

Change-Id: I0f34d31038c29d5cb78bc5d110159df01e41e328
2015-01-21 13:37:24 -08:00
Paul Wilkins
dfed541f21 Remove mode dependent zbin boost.
Initial patch to remove get_zbin_mode_boost() and
cpi->zbin_mode_boost.

For now sets a dummy value of 0 for zbin extra pending
a further clean up patch.

Change-Id: I64a1e1eca2d39baa8ffb0871b515a0be05c9a6af
(cherry picked from commit 60e9b731cf8945403dbcf149a0f6dc745e5cabe1)
2015-01-21 11:05:55 -08:00
Spencer Egart
347c31b48f Created COMPOUND_MODES experiment.
COMPOUND_MODES experiment encodes separate MV modes for each frame in a compound
reference prediction.  Added modes NEAREST_NEARESTMV, ZERO_ZEROMV,
NEW_NEWMV, NEAREST_NEARMV, NEAR_NEARESTMV, NEW_NEARESTMV, NEAR_NEWMV,
NEW_NEARMV, and NEAREST_NEWMV.

Also enhances the wedge-partition expt to work better with compound
modes.

Results:
derflr +0.227
All experiments on: derflr +5.218

Change-Id: I719e8a34826bf1f1fe3988dac5733a845a89ef2b
2015-01-16 14:48:56 -08:00
Deb Mukherjee
db5dd49996 Adds wedge-partitions for compound prediction
Results with this experiment only: +0.642% on derflr.
With other experiments: +4.733%

Change-Id: Ieb2022f8e49ac38a7e7129e261a6bf69ae9666b9
2015-01-15 15:59:33 -08:00
punksu
5f0093bb98 Merge "dpcm intra prediction for tx_skip" into nextgen 2015-01-15 11:53:06 -08:00
punksu
571fdbb05f dpcm intra prediction for tx_skip
Implements vertical, horizontal, and tm dpcm intra prediction for
blocks in tx_skip mode. Typical coding gain on screen content video
is 2%~5%.

Change-Id: Idd5bd84ac59daa586ec0cd724680cef695981651
2015-01-14 14:54:09 -08:00
Zoe Liu
a56ff2d323 Fixed a bug in the experiment EXT_TX.
Change-Id: I1adf0e916f9414e6dfe1d07cefc0693bc63b7e97
2015-01-14 14:27:51 -08:00
hui su
f60b844974 Merge "Turn on tx_skip for inter modes" into nextgen 2015-01-14 08:57:41 -08:00
Deb Mukherjee
3960e92c8b Merge "Some fixes in interintra expt" into nextgen 2015-01-13 12:34:24 -08:00
hui su
2c68b07d7d Turn on tx_skip for inter modes
Fixed the mismatch issue in lossless case

Change-Id: Ia2fd98865b4687e664fdc75f62b402e8289a1968
2015-01-13 11:28:08 -08:00
Deb Mukherjee
cb165354e7 Some fixes in interintra expt
Removes some redundant information when supertx and interintra
both are used.

Change-Id: I40b0fddbc1ba54607c6e8068bde128c21c14d997
2015-01-13 00:52:25 -08:00
Zoe Liu
919692d6c5 Cleaned up the code a little for the CONFIG_EXT_TX experiment on the
16x16 and 8x8 transform sizes, both for the regular case and the high
bit depth (CONFIG_VP9_HIGHBITDEPTH) case.

Change-Id: I34a9d3c73c3687f967105194ce4def48c3ec435c
2015-01-12 12:11:37 -08:00
Deb Mukherjee
b43beffc3c Merge "Adds an inter-intra combination mode" into nextgen 2015-01-12 09:22:21 -08:00
Deb Mukherjee
2dba1221b4 Adds an inter-intra combination mode
A smooth weighting scheme is used to put more weight
on the intra predictor samples near the left/top boundaries
and decaying it to favor the inter predictor samples more as
we move away from these boundaries in the direction of
prediction.

Results:
derflr: +0.609% with only this experiment
derflr: +3.901% with all experiments

Change-Id: Ic9dbe599ad6162fb05900059cbd6fc88b203a09c
2015-01-12 00:28:01 -08:00
Zoe Liu
b342c8405b Merge "Fixed a bug in the CONFIG_EXT_TX experiment for the forward 16x16 transform size when CONFIG_VP9_HIGHBITDEPTH is enabled." into nextgen 2015-01-09 13:32:53 -08:00
Deb Mukherjee
f61bcfbafa Merge "Segment id fix in tx-skip/supertx experiment" into nextgen 2015-01-09 10:37:59 -08:00
punksu
9100fe3944 Merge "Fix conflict b/w tx_skip and copy_mode in lossless mode" into nextgen 2015-01-08 17:06:41 -08:00
Zoe Liu
d7d5c75c69 Fixed a bug in the CONFIG_EXT_TX experiment for the forward 16x16
transform size when CONFIG_VP9_HIGHBITDEPTH is enabled.

Change-Id: I475f64eac2c31094a47bc0d557968940cad01c86
2015-01-08 09:03:53 -08:00
Deb Mukherjee
28258c5fe2 Segment id fix in tx-skip/supertx experiment
Change-Id: Ice9e833ad7f60e943acc011260dc3121ad3b136f
2015-01-08 02:05:11 -08:00
Deb Mukherjee
9a19ef0add Turn off tx-skip for intermodes temporarily
Will be re-enabled when a mismatch issue is resolved.

Change-Id: I303d80effa69eeb0ebf1921bbb4eaeeb34497e4b
2015-01-06 18:14:00 -08:00
punksu
42dfd9a728 Fix conflict b/w tx_skip and copy_mode in lossless mode
Change-Id: Idb12344adda99dddde8d2cd010ffffe6425aca62
2015-01-06 20:51:46 +08:00
Yue Chen
695c4bc321 Fix mismatch in SUPERTX experiment
Disable SUPERTX mode when lossless mode is enabled because the largest
lossless transform size is 4X4.

Change-Id: I4167959a282728d62354119ced99ca29febabfd1
2014-12-28 02:27:16 -08:00
punksu
b0ef621f84 Merge "Allow large tx_size in lossless coding with transform skipping" into nextgen 2014-12-27 20:52:36 -08:00
Deb Mukherjee
2b959d4ee8 Fix frame-parallel modes
This fix is already incorporated in master.

Change-Id: I7b0c048ebef4d92f041cc8727bc276843f17d50d
2014-12-27 01:55:27 -08:00
Deb Mukherjee
9aa76fdb69 Adds a copy mode experiment
Experiment to copy motion and mode from block neighbors.

Results:
--------
--enable-experimental --enable-copy-mode:
derflr: +0.727%

With other expts:
--enable-experimental --enable-copy-mode --enable-supertx
--enable-ext-tx --enable-filterintra --enable-tx-skip --enable-tx64x64
derflr: +3.43%

Change-Id: Iae74b9a855a1a690bf76131b42d247bbc54dec17
2014-12-24 17:52:55 -08:00
punksu
8a41d18bd0 Allow large tx_size in lossless coding with transform skipping
In lossless coding, tx_size can be larger than 4x4 when transform
skipping is activated. Compared to regular vp9 lossless coding,
performance improvement for derf is about 5%; gain is larger
for screen content videos.

Change-Id: Ib20ece7e117f29fb91543612757302a2400110b4
2014-12-22 22:56:52 +08:00
Debargha Mukherjee
2f7de8c887 Bug fix in rdopt
Change-Id: Ieab80902755456e97583636f13d1417269b332b5
2014-12-18 02:43:27 -08:00
Deb Mukherjee
7ec9792f96 Adds forward prob updates for supertx expt
Also refactors the supertx prob models, and includes other
cleanups.

Change-Id: I74de6c01d872ae09bf6d43a31f53d43283b6b226
2014-12-15 21:55:58 -08:00
hui su
5de9280ae9 tx_skip mode for lossy coding
This patch improves the non-transform coding mode. At this
point, the coding gain on screen content videos is about
12% for lossless, an 15% for lossy case.

1. Encode tx_skip flags with context. Y tx_skip flag context is
whether the prediction mode is inter or intra. UV flag context
is Y flag.

2. Transform skipping is less helpful when the Q-index is high.
So it is enabled only when the Q-index is smaller than a
threshold. Currently the threshold is set as 255 for intra blocks,
and 0 for inter blocks.

3. The shift of the prediction residue, when copying them to the
coeff buffer, is set as 3 when the Q-index is larger than a
threshold (currently set as 0), and 2 otherwise.

Change-Id: I372973c7518cf385f6e542b22d0f803016e693b0
2014-12-15 10:46:41 -08:00
Deb Mukherjee
625c0961ff Adds supertx experiment adopted from playground
Reimplements the supertx experiment from the playground branch.
Makes it work with other experiments.

Results:
With --enable-superttx
derflr: +0.958

With --enable-supertx --enable-ext-tx
derflr: +2.25%

With --enable-supertx --enable-ext-tx --enable-filterintra
derflr: +2.73%

Change-Id: I5012418ef2556bf2758146d90c4e2fb8a14610c7
2014-12-11 16:06:23 -08:00
Deb Mukherjee
1fdc274900 Extends ext_tx expt to include all hybrid variants
Extends the ext-tx experiment to include all 9 DST/DCT
variants.

Results with ext_tx experiment:
derflr: +1.338 derflr (improved from 1.12)

Change-Id: I24b5564f96bce6ccaa13d88ca6cb9d0c57000597
2014-11-21 07:21:38 -08:00
Deb Mukherjee
c82de3bede Extending ext_tx expt to include dst variants
Extends the ext-tx experiment to include regular and flipped
DST variants. A total of 9 transforms are thus possible for
each inter block with transform size <= 16x16.

In this patch currently only the four ADST_ADST variants
(flipped or non-flipped in both dimensions) are enabled
for inter blocks.

The gain with the ext-tx experiment grows to +1.12 on derflr.
Further experiments are underway.

Change-Id: Ia2ed19a334face6135b064748f727fdc9db278ec
2014-11-20 14:25:40 -08:00
hui su
d97fd3eef6 Non transform coding experiment
Non-transform option is enabled in both intra and inter modes.
In lossless case, the average coding gain on screen content
clips is 11.3% in my test.

Change-Id: I2e8de515fb39e74c61bb86ce0f682d5f79e15188
2014-11-19 21:20:21 -08:00
Deb Mukherjee
e2a8e90874 Misc cleanups on ext_tx expt.
Change-Id: I599d9fb00a2accdf24def65df52bef56d014a0b6
2014-11-16 00:03:18 -08:00
Deb Mukherjee
52e4dfe1b1 Merge "Adds missing EXT_TX checks" into nextgen 2014-11-13 20:13:40 -08:00
Deb Mukherjee
f62d19752d Adds missing EXT_TX checks
Change-Id: Ia0ca39c9041f17da0b7f522e55868498f31de848
2014-11-13 15:59:50 -08:00
Spencer Egart
83e50d6412 Refactoring in nonrd_ methods in vp9_encodeframe
Refactored some of the more repetitive code in the nonrd methods in
vp9_encodeframe.c.

Change-Id: Ib71dcd14f74fb6e5fd123b3ffea8f253aaa04b1a
2014-11-13 13:00:15 -08:00
hui su
cf7dc66e34 Fix lossless mismatch in EXT_TX
In lossless mode, transform should not be altered.

Change-Id: I216d1700963b4d1c35e059cd7ff7b0cefaf46133
2014-11-13 05:07:37 -08:00
Spencer Egart
1c562aebd8 Migrate EXT_TX from playground to nextgen.
Change-Id: I1cb0584104323fb3781e66bb65d44ebbe853c9c8
2014-11-11 07:55:49 -08:00
Spencer Egart
e55808d9a7 Migrated FILTERINTRA from playground to nextgen
derf +0.385
derflr +0.411
with --enable-tx64x64, derflr +0.433

Added fix for integration with TX64X64

Change-Id: Ie24825de06021d007ba215ac7f6de40638c57e12
2014-11-10 10:13:32 -08:00
Deb Mukherjee
613ea21ae7 Tx64x64 bug fixes
Change-Id: Iac595a3ae8f1466d8485c3627219b4b623efc8ad
2014-11-05 20:19:43 -08:00
Deb Mukherjee
a137e3c3ba Fixes in 64x64 transform
Extends quantizer range and some other fixes.

Change-Id: Ia9adf7848e772783365d6501efd07585bff80c15
stdhd: +0.166%, turns positive a little
derf: -0.036% (very few blocks use the 64x64 mode)
2014-11-03 17:00:43 -08:00
Deb Mukherjee
8bdf4cebb9 Merge "Adding a 64x64 transform mode" into nextgen 2014-10-30 00:51:35 -07:00
Deb Mukherjee
0c7a94f49b Adding a 64x64 transform mode
Preliminary 64x64 transform implementation.
Includes all code changes.
All mismatches resolved.

Coding results for derf and stdhd are within noise. stdhd is slightly
higher, derf is slightly lower.

To be further refined.

Change-Id: I091c183f62b156d23ed6f648202eb96c82e69b4b
2014-10-30 00:45:57 -07:00
208 changed files with 74246 additions and 16440 deletions

View File

@ -511,9 +511,8 @@ process_common_cmdline() {
;;
--force-target=*) toolchain="${toolchain:-${optval}}"; enable_feature force_toolchain
;;
--cpu)
;;
--cpu=*) tune_cpu="$optval"
--cpu=*)
tune_cpu="$optval"
;;
--extra-cflags=*)
extra_cflags="${optval}"
@ -863,10 +862,6 @@ EOF
check_add_cflags -mfpu=neon #-ftree-vectorize
check_add_asflags -mfpu=neon
fi
if [ -z "${tune_cpu}" ]; then
tune_cpu=cortex-a8
fi
else
check_add_cflags -march=${tgt_isa}
check_add_asflags -march=${tgt_isa}

25
configure vendored
View File

@ -26,6 +26,7 @@ Advanced options:
${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]
@ -282,6 +283,30 @@ EXPERIMENT_LIST="
vp9_temporal_denoising
fp_mb_stats
emulate_hardware
tx64x64
filterintra
ext_tx
tx_skip
supertx
copy_mode
interintra
wedge_partition
global_motion
palette
new_quant
intrabc
loop_postfilter
row_tile
new_inter
bitstream_fixes
newmvref
misc_entropy
wavelets
ext_partition
qctx_tprobs
sr_mode
multi_ref
ext_coding_unit_size
"
CONFIG_LIST="
external_build

View File

@ -35,20 +35,30 @@ LIBYUV_SRCS += third_party/libyuv/include/libyuv/basic_types.h \
third_party/libyuv/source/scale_posix.cc \
third_party/libyuv/source/scale_win.cc \
LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer.cpp \
third_party/libwebm/mkvmuxerutil.cpp \
third_party/libwebm/mkvwriter.cpp \
third_party/libwebm/mkvmuxer.hpp \
third_party/libwebm/mkvmuxertypes.hpp \
third_party/libwebm/mkvmuxerutil.hpp \
third_party/libwebm/mkvparser.hpp \
third_party/libwebm/mkvwriter.hpp \
third_party/libwebm/webmids.hpp
LIBWEBM_COMMON_SRCS += third_party/libwebm/common/hdr_util.cc \
third_party/libwebm/common/hdr_util.h \
third_party/libwebm/common/webmids.h
LIBWEBM_PARSER_SRCS = third_party/libwebm/mkvparser.cpp \
third_party/libwebm/mkvreader.cpp \
third_party/libwebm/mkvparser.hpp \
third_party/libwebm/mkvreader.hpp
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
CXXFLAGS += -I$(SRC_PATH_BARE)/third_party/libwebm
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.
@ -66,6 +76,8 @@ ifeq ($(CONFIG_LIBYUV),yes)
vpxdec.SRCS += $(LIBYUV_SRCS)
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
@ -86,34 +98,18 @@ 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
ifeq ($(CONFIG_SPATIAL_SVC),yes)
EXAMPLES-$(CONFIG_VP9_ENCODER) += vp9_spatial_svc_encoder.c
vp9_spatial_svc_encoder.SRCS += args.c args.h
vp9_spatial_svc_encoder.SRCS += ivfenc.c ivfenc.h
vp9_spatial_svc_encoder.SRCS += tools_common.c tools_common.h
vp9_spatial_svc_encoder.SRCS += video_common.h
vp9_spatial_svc_encoder.SRCS += video_writer.h video_writer.c
vp9_spatial_svc_encoder.SRCS += vpxstats.c vpxstats.h
vp9_spatial_svc_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D
vp9_spatial_svc_encoder.DESCRIPTION = VP9 Spatial SVC Encoder
endif
ifneq ($(CONFIG_SHARED),yes)
EXAMPLES-$(CONFIG_VP9_ENCODER) += resize_util.c
endif
EXAMPLES-$(CONFIG_ENCODERS) += vpx_temporal_svc_encoder.c
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.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
@ -186,7 +182,13 @@ vp8cx_set_ref.SRCS += video_common.h
vp8cx_set_ref.SRCS += video_writer.h video_writer.c
vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A
vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame
EXAMPLES-$(CONFIG_VP9_ENCODER) += 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
ifeq ($(CONFIG_MULTI_RES_ENCODING),yes)
ifeq ($(CONFIG_LIBYUV),yes)

View File

@ -1,439 +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 <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "./args.h"
#include "./tools_common.h"
#include "./video_writer.h"
#include "vpx/svc_context.h"
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
#include "./vpxstats.h"
static const arg_def_t skip_frames_arg =
ARG_DEF("s", "skip-frames", 1, "input frames to skip");
static const arg_def_t frames_arg =
ARG_DEF("f", "frames", 1, "number of frames to encode");
static const arg_def_t width_arg = ARG_DEF("w", "width", 1, "source width");
static const arg_def_t height_arg = ARG_DEF("h", "height", 1, "source height");
static const arg_def_t timebase_arg =
ARG_DEF("t", "timebase", 1, "timebase (num/den)");
static const arg_def_t bitrate_arg = ARG_DEF(
"b", "target-bitrate", 1, "encoding bitrate, in kilobits per second");
static const arg_def_t 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 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");
#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,
#if CONFIG_VP9_HIGHBITDEPTH
&bitdepth_arg,
#endif
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;
typedef struct {
const char *input_filename;
const char *output_filename;
uint32_t frames_to_code;
uint32_t frames_to_skip;
struct VpxInputContext input_ctx;
stats_io_t rc_stats;
int passes;
int pass;
} AppInput;
static const char *exec_name;
void usage_exit() {
fprintf(stderr, "Usage: %s <options> input_filename output_filename\n",
exec_name);
fprintf(stderr, "Options:\n");
arg_show_usage(stderr, svc_args);
exit(EXIT_FAILURE);
}
static void parse_command_line(int argc, const char **argv_,
AppInput *app_input, SvcContext *svc_ctx,
vpx_codec_enc_cfg_t *enc_cfg) {
struct arg arg = {0};
char **argv = NULL;
char **argi = NULL;
char **argj = NULL;
vpx_codec_err_t res;
int passes = 0;
int pass = 0;
const char *fpf_file_name = NULL;
unsigned int min_bitrate = 0;
unsigned int max_bitrate = 0;
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;
// 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);
} 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, &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);
#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);
}
int main(int argc, const char **argv) {
AppInput app_input = {0};
VpxVideoWriter *writer = NULL;
VpxVideoInfo info = {0};
vpx_codec_ctx_t codec;
vpx_codec_enc_cfg_t enc_cfg;
SvcContext svc_ctx;
uint32_t i;
uint32_t frame_cnt = 0;
vpx_image_t raw;
vpx_codec_err_t res;
int pts = 0; /* PTS starts at 0 */
int frame_duration = 1; /* 1 timebase tick per frame */
FILE *infile = NULL;
int end_of_stream = 0;
int frames_received = 0;
memset(&svc_ctx, 0, sizeof(svc_ctx));
svc_ctx.log_print = 1;
exec_name = argv[0];
parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg);
// Allocate image buffer
#if 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");
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);
}
// skip initial frames
for (i = 0; i < app_input.frames_to_skip; ++i)
vpx_img_read(&raw, infile);
// 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;
}
res = vpx_svc_encode(&svc_ctx, &codec, (end_of_stream ? NULL : &raw),
pts, frame_duration, VPX_DL_GOOD_QUALITY);
printf("%s", vpx_svc_get_message(&svc_ctx));
if (res != VPX_CODEC_OK) {
die_codec(&codec, "Failed to encode frame");
}
while ((cx_pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) {
switch (cx_pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT: {
if (cx_pkt->data.frame.sz > 0)
vpx_video_writer_write_frame(writer,
cx_pkt->data.frame.buf,
cx_pkt->data.frame.sz,
cx_pkt->data.frame.pts);
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);
++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;
}
}
printf("Processed %d frames\n", frame_cnt);
fclose(infile);
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
if (app_input.passes == 2)
stats_close(&app_input.rc_stats, 1);
if (writer) {
vpx_video_writer_close(writer);
}
vpx_img_free(&raw);
// display average size, psnr
printf("%s", vpx_svc_dump_statistics(&svc_ctx));
vpx_svc_release(&svc_ctx);
return EXIT_SUCCESS;
}

443
examples/vp9cx_set_ref.c Normal file
View File

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

View File

@ -1,733 +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 "./tools_common.h"
#include "./video_writer.h"
static const char *exec_name;
void usage_exit() {
exit(EXIT_FAILURE);
}
// Denoiser states, for temporal denoising.
enum denoiserState {
kDenoiserOff,
kDenoiserOnYOnly,
kDenoiserOnYUV,
kDenoiserOnYUVAggressive,
kDenoiserOnAdaptive
};
static int mode_to_num_layers[12] = {1, 2, 2, 3, 3, 3, 3, 5, 2, 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];
};
// 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 * cfg->ts_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 *
(cfg->ts_target_bitrate[i] - cfg->ts_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;
}
}
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;
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", cfg->ts_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");
}
if ((frame_cnt - 1) != tot_num_frames)
die("Error: Number of input frames not equal to output! \n");
}
// 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:
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;
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;
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 = 11;
#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
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> <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> <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 = strtol(argv[4], NULL, 0);
height = strtol(argv[5], NULL, 0);
if (width < 16 || width % 2 || height < 16 || height % 2) {
die("Invalid resolution: %d x %d", width, height);
}
layering_mode = strtol(argv[10], NULL, 0);
if (layering_mode < 0 || layering_mode > 12) {
die("Invalid layering mode (0..12) %s", argv[10]);
}
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 = strtol(argv[6], NULL, 0);
cfg.g_timebase.den = strtol(argv[7], NULL, 0);
speed = 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) {
cfg.ts_target_bitrate[i - 11] = strtol(argv[i], NULL, 0);
}
// Real time parameters.
cfg.rc_dropframe_thresh = strtol(argv[9], NULL, 0);
cfg.rc_end_usage = VPX_CBR;
cfg.rc_resize_allowed = 0;
cfg.rc_min_quantizer = 2;
cfg.rc_max_quantizer = 56;
cfg.rc_undershoot_pct = 50;
cfg.rc_overshoot_pct = 50;
cfg.rc_buf_initial_sz = 500;
cfg.rc_buf_optimal_sz = 600;
cfg.rc_buf_sz = 1000;
// Enable error resilient mode.
cfg.g_error_resilient = 1;
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;
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 ts_target_bitrate for highest layer (total bitrate).
cfg.rc_target_bitrate = cfg.ts_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]);
}
// 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, kDenoiserOnYOnly);
} else if (strncmp(encoder->name, "vp9", 3) == 0) {
vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed);
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0);
vpx_codec_control(&codec, VP9E_SET_NOISE_SENSITIVITY, 0);
if (vpx_codec_control(&codec, VP9E_SET_SVC, 1)) {
die_codec(&codec, "Failed to set SVC");
}
}
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
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 = 200;
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);
}
flags = layer_flags[frame_cnt % flag_periodicity];
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];
}
}
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);
return EXIT_SUCCESS;
}

View File

@ -415,12 +415,6 @@ MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
# If the sources in your project are distributed over multiple directories
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
# in the documentation. The default is NO.
SHOW_DIRECTORIES = NO
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from the
# version control system). Doxygen will invoke the program by executing (via
@ -715,12 +709,6 @@ HTML_FOOTER =
HTML_STYLESHEET =
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)

View File

@ -115,7 +115,6 @@ ifeq ($(CONFIG_VP9_ENCODER),yes)
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-$(CONFIG_SPATIAL_SVC) += 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
@ -386,6 +385,12 @@ $(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
@ -459,6 +464,7 @@ test_libvpx.$(VCPROJ_SFX): $(LIBVPX_TEST_SRCS) vpx.$(VCPROJ_SFX) gtest.$(VCPROJ_
$(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)

View File

@ -8,30 +8,27 @@
## in the file PATENTS. All contributing project authors may
## be found in the AUTHORS file in the root of the source tree.
##
## This file tests the libvpx vp8cx_set_ref example. To add new tests to this
## This file tests the libvpx cx_set_ref example. To add new tests to this
## file, do the following:
## 1. Write a shell function (this is your test).
## 2. Add the function to vp8cx_set_ref_tests (on a new line).
## 2. Add the function to cx_set_ref_tests (on a new line).
##
. $(dirname $0)/tools_common.sh
# Environment check: $YUV_RAW_INPUT is required.
vp8cx_set_ref_verify_environment() {
cx_set_ref_verify_environment() {
if [ ! -e "${YUV_RAW_INPUT}" ]; then
echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
return 1
fi
}
# Runs vp8cx_set_ref and updates the reference frame before encoding frame 90.
# $1 is the codec name, which vp8cx_set_ref does not support at present: It's
# currently used only to name the output file.
# TODO(tomfinegan): Pass the codec param once the example is updated to support
# VP9.
# Runs cx_set_ref and updates the reference frame before encoding frame 90.
# $1 is the codec name.
vpx_set_ref() {
local encoder="${LIBVPX_BIN_PATH}/vp8cx_set_ref${VPX_TEST_EXE_SUFFIX}"
local codec="$1"
local output_file="${VPX_TEST_OUTPUT_DIR}/vp8cx_set_ref_${codec}.ivf"
local encoder="${LIBVPX_BIN_PATH}/${codec}cx_set_ref${VPX_TEST_EXE_SUFFIX}"
local output_file="${VPX_TEST_OUTPUT_DIR}/${codec}cx_set_ref_${codec}.ivf"
local ref_frame_num=90
if [ ! -x "${encoder}" ]; then
@ -46,12 +43,18 @@ vpx_set_ref() {
[ -e "${output_file}" ] || return 1
}
vp8cx_set_ref_vp8() {
cx_set_ref_vp8() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_set_ref vp8 || return 1
fi
}
vp8cx_set_ref_tests="vp8cx_set_ref_vp8"
cx_set_ref_vp9() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_set_ref vp9 || return 1
fi
}
run_tests vp8cx_set_ref_verify_environment "${vp8cx_set_ref_tests}"
cx_set_ref_tests="cx_set_ref_vp8 cx_set_ref_vp9"
run_tests cx_set_ref_verify_environment "${cx_set_ref_tests}"

View File

@ -218,442 +218,5 @@ TEST_P(DatarateTestLarge, ChangingDropFrameThresh) {
}
}
class DatarateTestVP9Large : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
public:
DatarateTestVP9Large() : EncoderTest(GET_PARAM(0)) {}
protected:
virtual ~DatarateTestVP9Large() {}
virtual void SetUp() {
InitializeConfig();
SetMode(GET_PARAM(1));
set_cpu_used_ = GET_PARAM(2);
ResetModel();
}
virtual void ResetModel() {
last_pts_ = 0;
bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz;
frame_number_ = 0;
tot_frame_number_ = 0;
first_drop_ = 0;
num_drops_ = 0;
// Denoiser is off by default.
denoiser_on_ = 0;
// For testing up to 3 layers.
for (int i = 0; i < 3; ++i) {
bits_total_[i] = 0;
}
}
//
// Frame flags and layer id for temporal layers.
//
// For two layers, test pattern is:
// 1 3
// 0 2 .....
// For three layers, test pattern is:
// 1 3 5 7
// 2 6
// 0 4 ....
// LAST is always update on base/layer 0, GOLDEN is updated on layer 1.
// For this 3 layer example, the 2nd enhancement layer (layer 2) does not
// update any reference frames.
int SetFrameFlags(int frame_num, int num_temp_layers) {
int frame_flags = 0;
if (num_temp_layers == 2) {
if (frame_num % 2 == 0) {
// Layer 0: predict from L and ARF, update L.
frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF;
} else {
// Layer 1: predict from L, G and ARF, and update G.
frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ENTROPY;
}
} else if (num_temp_layers == 3) {
if (frame_num % 4 == 0) {
// Layer 0: predict from L and ARF; update L.
frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_REF_GF;
} else if ((frame_num - 2) % 4 == 0) {
// Layer 1: predict from L, G, ARF; update G.
frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
} else if ((frame_num - 1) % 2 == 0) {
// Layer 2: predict from L, G, ARF; update none.
frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_LAST;
}
}
return frame_flags;
}
int SetLayerId(int frame_num, int num_temp_layers) {
int layer_id = 0;
if (num_temp_layers == 2) {
if (frame_num % 2 == 0) {
layer_id = 0;
} else {
layer_id = 1;
}
} else if (num_temp_layers == 3) {
if (frame_num % 4 == 0) {
layer_id = 0;
} else if ((frame_num - 2) % 4 == 0) {
layer_id = 1;
} else if ((frame_num - 1) % 2 == 0) {
layer_id = 2;
}
}
return layer_id;
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
encoder->Control(VP9E_SET_NOISE_SENSITIVITY, denoiser_on_);
}
if (cfg_.ts_number_layers > 1) {
if (video->frame() == 1) {
encoder->Control(VP9E_SET_SVC, 1);
}
vpx_svc_layer_id_t layer_id = {0, 0};
layer_id.spatial_layer_id = 0;
frame_flags_ = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
layer_id.temporal_layer_id = SetLayerId(video->frame(),
cfg_.ts_number_layers);
if (video->frame() > 0) {
encoder->Control(VP9E_SET_SVC_LAYER_ID, &layer_id);
}
}
const vpx_rational_t tb = video->timebase();
timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0;
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
// Time since last timestamp = duration.
vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
if (duration > 1) {
// If first drop not set and we have a drop set it to this time.
if (!first_drop_)
first_drop_ = last_pts_ + 1;
// Update the number of frame drops.
num_drops_ += static_cast<int>(duration - 1);
// Update counter for total number of frames (#frames input to encoder).
// Needed for setting the proper layer_id below.
tot_frame_number_ += static_cast<int>(duration - 1);
}
int layer = SetLayerId(tot_frame_number_, cfg_.ts_number_layers);
// Add to the buffer the bits we'd expect from a constant bitrate server.
bits_in_buffer_model_ += static_cast<int64_t>(
duration * timebase_ * cfg_.rc_target_bitrate * 1000);
// Buffer should not go negative.
ASSERT_GE(bits_in_buffer_model_, 0) << "Buffer Underrun at frame "
<< pkt->data.frame.pts;
const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
// Update the total encoded bits. For temporal layers, update the cumulative
// encoded bits per layer.
for (int i = layer; i < static_cast<int>(cfg_.ts_number_layers); ++i) {
bits_total_[i] += frame_size_in_bits;
}
// Update the most recent pts.
last_pts_ = pkt->data.frame.pts;
++frame_number_;
++tot_frame_number_;
}
virtual void EndPassHook(void) {
for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers);
++layer) {
duration_ = (last_pts_ + 1) * timebase_;
if (bits_total_[layer]) {
// Effective file datarate:
effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_;
}
}
}
vpx_codec_pts_t last_pts_;
double timebase_;
int frame_number_; // Counter for number of non-dropped/encoded frames.
int tot_frame_number_; // Counter for total number of input frames.
int64_t bits_total_[3];
double duration_;
double effective_datarate_[3];
int set_cpu_used_;
int64_t bits_in_buffer_model_;
vpx_codec_pts_t first_drop_;
int num_drops_;
int denoiser_on_;
};
// Check basic rate targeting,
TEST_P(DatarateTestVP9Large, BasicRateTargeting) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
for (int i = 150; i < 800; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
<< " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
<< " The datarate for the file is greater than target by too much!";
}
}
// Check basic rate targeting,
TEST_P(DatarateTestVP9Large, BasicRateTargeting444) {
::libvpx_test::Y4mVideoSource video("rush_hour_444.y4m", 0, 140);
cfg_.g_profile = 1;
cfg_.g_timebase = video.timebase();
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
for (int i = 250; i < 900; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(static_cast<double>(cfg_.rc_target_bitrate),
effective_datarate_[0] * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(static_cast<double>(cfg_.rc_target_bitrate),
effective_datarate_[0] * 1.15)
<< " The datarate for the file missed the target!"
<< cfg_.rc_target_bitrate << " "<< effective_datarate_;
}
}
// Check that (1) the first dropped frame gets earlier and earlier
// as the drop frame threshold is increased, and (2) that the total number of
// frame drops does not decrease as we increase frame drop threshold.
// Use a lower qp-max to force some frame drops.
TEST_P(DatarateTestVP9Large, ChangingDropFrameThresh) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_undershoot_pct = 20;
cfg_.rc_undershoot_pct = 20;
cfg_.rc_dropframe_thresh = 10;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 50;
cfg_.rc_end_usage = VPX_CBR;
cfg_.rc_target_bitrate = 200;
cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
const int kDropFrameThreshTestStep = 30;
vpx_codec_pts_t last_drop = 140;
int last_num_drops = 0;
for (int i = 10; i < 100; i += kDropFrameThreshTestStep) {
cfg_.rc_dropframe_thresh = i;
ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
<< " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
<< " The datarate for the file is greater than target by too much!";
ASSERT_LE(first_drop_, last_drop)
<< " The first dropped frame for drop_thresh " << i
<< " > first dropped frame for drop_thresh "
<< i - kDropFrameThreshTestStep;
ASSERT_GE(num_drops_, last_num_drops)
<< " The number of dropped frames for drop_thresh " << i
<< " < number of dropped frames for drop_thresh "
<< i - kDropFrameThreshTestStep;
last_drop = first_drop_;
last_num_drops = num_drops_;
}
}
// Check basic rate targeting for 2 temporal layers.
TEST_P(DatarateTestVP9Large, BasicRateTargeting2TemporalLayers) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
// 2 Temporal layers, no spatial layers: Framerate decimation (2, 1).
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 2;
cfg_.ts_rate_decimator[0] = 2;
cfg_.ts_rate_decimator[1] = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
for (int i = 200; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
// 60-40 bitrate allocation for 2 temporal layers.
cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
<< " The datarate for the file is lower than target by too much, "
"for layer: " << j;
ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
<< " The datarate for the file is greater than target by too much, "
"for layer: " << j;
}
}
}
// Check basic rate targeting for 3 temporal layers.
TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayers) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
// 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1).
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
for (int i = 200; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
// 40-20-40 bitrate allocation for 3 temporal layers.
cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
// TODO(yaowu): Work out more stable rc control strategy and
// Adjust the thresholds to be tighter than .75.
ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.75)
<< " The datarate for the file is lower than target by too much, "
"for layer: " << j;
// TODO(yaowu): Work out more stable rc control strategy and
// Adjust the thresholds to be tighter than 1.25.
ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.25)
<< " The datarate for the file is greater than target by too much, "
"for layer: " << j;
}
}
}
// Check basic rate targeting for 3 temporal layers, with frame dropping.
// Only for one (low) bitrate with lower max_quantizer, and somewhat higher
// frame drop threshold, to force frame dropping.
TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayersFrameDropping) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
// Set frame drop threshold and rc_max_quantizer to force some frame drops.
cfg_.rc_dropframe_thresh = 20;
cfg_.rc_max_quantizer = 45;
cfg_.rc_min_quantizer = 0;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
// 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1).
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
cfg_.rc_target_bitrate = 200;
ResetModel();
// 40-20-40 bitrate allocation for 3 temporal layers.
cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
<< " The datarate for the file is lower than target by too much, "
"for layer: " << j;
ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
<< " The datarate for the file is greater than target by too much, "
"for layer: " << j;
// Expect some frame drops in this test: for this 200 frames test,
// expect at least 10% and not more than 60% drops.
ASSERT_GE(num_drops_, 20);
ASSERT_LE(num_drops_, 130);
}
}
#if CONFIG_VP9_TEMPORAL_DENOISING
// Check basic datarate targeting, for a single bitrate, when denoiser is on.
TEST_P(DatarateTestVP9Large, DenoiserLevels) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_min_quantizer = 2;
cfg_.rc_max_quantizer = 56;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140);
// For the temporal denoiser (#if CONFIG_VP9_TEMPORAL_DENOISING),
// there is only one denoiser mode: denoiserYonly(which is 1),
// but may add more modes in the future.
cfg_.rc_target_bitrate = 300;
ResetModel();
// Turn on the denoiser.
denoiser_on_ = 1;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
<< " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
<< " The datarate for the file is greater than target by too much!";
}
#endif // CONFIG_VP9_TEMPORAL_DENOISING
VP8_INSTANTIATE_TEST_CASE(DatarateTestLarge, ALL_TEST_MODES);
VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9Large,
::testing::Values(::libvpx_test::kOnePassGood,
::libvpx_test::kRealTime),
::testing::Range(2, 7));
} // namespace

View File

@ -264,6 +264,8 @@ typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride,
typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct16x16Param;
typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht16x16Param;
typedef std::tr1::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t>
Idct16x16Param;
void fdct16x16_ref(const int16_t *in, tran_low_t *out, int stride,
int /*tx_type*/) {
@ -311,6 +313,32 @@ void iht16x16_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
void iht16x16_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp9_highbd_iht16x16_256_add_c(in, out, stride, tx_type, 12);
}
void idct16x16_10_add_10_c(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct16x16_10_add_c(in, out, stride, 10);
}
void idct16x16_10_add_12_c(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct16x16_10_add_c(in, out, stride, 12);
}
#if HAVE_SSE2
void idct16x16_256_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct16x16_256_add_sse2(in, out, stride, 10);
}
void idct16x16_256_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct16x16_256_add_sse2(in, out, stride, 12);
}
void idct16x16_10_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct16x16_10_add_sse2(in, out, stride, 10);
}
void idct16x16_10_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct16x16_10_add_sse2(in, out, stride, 12);
}
#endif
#endif
class Trans16x16TestBase {
@ -540,7 +568,7 @@ class Trans16x16TestBase {
reference_16x16_dct_2d(in, out_r);
for (int j = 0; j < kNumCoeffs; ++j)
coeff[j] = round(out_r[j]);
coeff[j] = static_cast<tran_low_t>(round(out_r[j]));
if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, 16));
@ -565,6 +593,62 @@ class Trans16x16TestBase {
}
}
}
void CompareInvReference(IdctFunc ref_txfm, int thresh) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 10000;
const int eob = 10;
const int16_t *scan = vp9_default_scan_orders[TX_16X16].scan;
DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, ref, kNumCoeffs);
#if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref16, kNumCoeffs);
#endif
for (int i = 0; i < count_test_block; ++i) {
for (int j = 0; j < kNumCoeffs; ++j) {
if (j < eob) {
// Random values less than the threshold, either positive or negative
coeff[scan[j]] = rnd(thresh) * (1-2*(i%2));
} else {
coeff[scan[j]] = 0;
}
if (bit_depth_ == VPX_BITS_8) {
dst[j] = 0;
ref[j] = 0;
#if CONFIG_VP9_HIGHBITDEPTH
} else {
dst16[j] = 0;
ref16[j] = 0;
#endif
}
}
if (bit_depth_ == VPX_BITS_8) {
ref_txfm(coeff, ref, pitch_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
} else {
#if CONFIG_VP9_HIGHBITDEPTH
ref_txfm(coeff, CONVERT_TO_BYTEPTR(ref16), pitch_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
pitch_));
#endif
}
for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VP9_HIGHBITDEPTH
const uint32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - ref[j] : dst16[j] - ref16[j];
#else
const uint32_t diff = dst[j] - ref[j];
#endif
const uint32_t error = diff * diff;
EXPECT_EQ(0u, error)
<< "Error: 16x16 IDCT Comparison has error " << error
<< " at index " << j;
}
}
}
int pitch_;
int tx_type_;
vpx_bit_depth_t bit_depth_;
@ -590,10 +674,10 @@ class Trans16x16DCT
mask_ = (1 << bit_depth_) - 1;
#if CONFIG_VP9_HIGHBITDEPTH
switch (bit_depth_) {
case 10:
case VPX_BITS_10:
inv_txfm_ref = idct16x16_10_ref;
break;
case 12:
case VPX_BITS_12:
inv_txfm_ref = idct16x16_12_ref;
break;
default:
@ -703,6 +787,37 @@ TEST_P(Trans16x16HT, QuantCheck) {
RunQuantCheck(429, 729);
}
class InvTrans16x16DCT
: public Trans16x16TestBase,
public ::testing::TestWithParam<Idct16x16Param> {
public:
virtual ~InvTrans16x16DCT() {}
virtual void SetUp() {
ref_txfm_ = GET_PARAM(0);
inv_txfm_ = GET_PARAM(1);
thresh_ = GET_PARAM(2);
bit_depth_ = GET_PARAM(3);
pitch_ = 16;
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) {}
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride);
}
IdctFunc ref_txfm_;
IdctFunc inv_txfm_;
int thresh_;
};
TEST_P(InvTrans16x16DCT, CompareReference) {
CompareInvReference(ref_txfm_, thresh_);
}
using std::tr1::make_tuple;
#if CONFIG_VP9_HIGHBITDEPTH
@ -772,6 +887,51 @@ INSTANTIATE_TEST_CASE_P(
VPX_BITS_8)));
#endif
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16DCT,
::testing::Values(
make_tuple(&vp9_highbd_fdct16x16_sse2,
&idct16x16_10, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct16x16_c,
&idct16x16_256_add_10_sse2, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct16x16_sse2,
&idct16x16_12, 0, VPX_BITS_12),
make_tuple(&vp9_highbd_fdct16x16_c,
&idct16x16_256_add_12_sse2, 0, VPX_BITS_12),
make_tuple(&vp9_fdct16x16_sse2,
&vp9_idct16x16_256_add_c, 0, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
SSE2, Trans16x16HT,
::testing::Values(
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_10, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_10, 1, VPX_BITS_10),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_10, 2, VPX_BITS_10),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_10, 3, VPX_BITS_10),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_12, 0, VPX_BITS_12),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_12, 1, VPX_BITS_12),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_12, 2, VPX_BITS_12),
make_tuple(&vp9_highbd_fht16x16_sse2, &iht16x16_12, 3, VPX_BITS_12),
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 0, VPX_BITS_8),
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 1, VPX_BITS_8),
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 2, VPX_BITS_8),
make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_c, 3,
VPX_BITS_8)));
// Optimizations take effect at a threshold of 3155, so we use a value close to
// that to test both branches.
INSTANTIATE_TEST_CASE_P(
SSE2, InvTrans16x16DCT,
::testing::Values(
make_tuple(&idct16x16_10_add_10_c,
&idct16x16_10_add_10_sse2, 3167, VPX_BITS_10),
make_tuple(&idct16x16_10,
&idct16x16_256_add_10_sse2, 3167, VPX_BITS_10),
make_tuple(&idct16x16_10_add_12_c,
&idct16x16_10_add_12_sse2, 3167, VPX_BITS_12),
make_tuple(&idct16x16_12,
&idct16x16_256_add_12_sse2, 3167, VPX_BITS_12)));
#endif
#if HAVE_SSSE3 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
SSSE3, Trans16x16DCT,

View File

@ -79,6 +79,10 @@ typedef std::tr1::tuple<FwdTxfmFunc, InvTxfmFunc, int, vpx_bit_depth_t>
Trans32x32Param;
#if CONFIG_VP9_HIGHBITDEPTH
void idct32x32_8(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct32x32_1024_add_c(in, out, stride, 8);
}
void idct32x32_10(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct32x32_1024_add_c(in, out, stride, 10);
}
@ -114,7 +118,7 @@ TEST_P(Trans32x32Test, AccuracyCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
uint32_t max_error = 0;
int64_t total_error = 0;
const int count_test_block = 1000;
const int count_test_block = 10000;
DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, test_temp_block, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
@ -127,7 +131,7 @@ TEST_P(Trans32x32Test, AccuracyCheck) {
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-mask_, mask_].
for (int j = 0; j < kNumCoeffs; ++j) {
if (bit_depth_ == 8) {
if (bit_depth_ == VPX_BITS_8) {
src[j] = rnd.Rand8();
dst[j] = rnd.Rand8();
test_input_block[j] = src[j] - dst[j];
@ -282,7 +286,7 @@ TEST_P(Trans32x32Test, InverseAccuracy) {
reference_32x32_dct_2d(in, out_r);
for (int j = 0; j < kNumCoeffs; ++j)
coeff[j] = round(out_r[j]);
coeff[j] = static_cast<tran_low_t>(round(out_r[j]));
if (bit_depth_ == VPX_BITS_8) {
ASM_REGISTER_STATE_CHECK(inv_txfm_(coeff, dst, 32));
#if CONFIG_VP9_HIGHBITDEPTH
@ -353,6 +357,22 @@ INSTANTIATE_TEST_CASE_P(
&vp9_idct32x32_1024_add_sse2, 1, VPX_BITS_8)));
#endif
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
SSE2, Trans32x32Test,
::testing::Values(
make_tuple(&vp9_highbd_fdct32x32_sse2, &idct32x32_10, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct32x32_rd_sse2, &idct32x32_10, 1,
VPX_BITS_10),
make_tuple(&vp9_highbd_fdct32x32_sse2, &idct32x32_12, 0, VPX_BITS_12),
make_tuple(&vp9_highbd_fdct32x32_rd_sse2, &idct32x32_12, 1,
VPX_BITS_12),
make_tuple(&vp9_fdct32x32_sse2, &vp9_idct32x32_1024_add_c, 0,
VPX_BITS_8),
make_tuple(&vp9_fdct32x32_rd_sse2, &vp9_idct32x32_1024_add_c, 1,
VPX_BITS_8)));
#endif
#if HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
AVX2, Trans32x32Test,

View File

@ -110,6 +110,7 @@ void EncoderTest::SetMode(TestMode mode) {
static bool compare_img(const vpx_image_t *img1,
const vpx_image_t *img2) {
bool match = (img1->fmt == img2->fmt) &&
(img1->cs == img2->cs) &&
(img1->d_w == img2->d_w) &&
(img1->d_h == img2->d_h);
@ -141,6 +142,12 @@ void EncoderTest::MismatchHook(const vpx_image_t* /*img1*/,
void EncoderTest::RunLoop(VideoSource *video) {
vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t();
#if CONFIG_ROW_TILE
// Decode all tiles.
dec_cfg.tile_col = -1;
dec_cfg.tile_row = -1;
#endif // CONFIG_ROW_TILE
stats_.Reset();
ASSERT_TRUE(passes_ == 1 || passes_ == 2);

View File

@ -126,11 +126,6 @@ class Encoder {
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
void Control(int ctrl_id, struct vpx_svc_layer_id *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
void Control(int ctrl_id, vpx_active_map_t *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);

146
test/error_block_test.cc Normal file
View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <cmath>
#include <cstdlib>
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_integer.h"
using libvpx_test::ACMRandom;
namespace {
#if CONFIG_VP9_HIGHBITDEPTH
const int number_of_iterations = 1000;
typedef int64_t (*ErrorBlockFunc)(const tran_low_t *coeff,
const tran_low_t *dqcoeff, intptr_t block_size,
int64_t *ssz, int bps);
typedef std::tr1::tuple<ErrorBlockFunc, ErrorBlockFunc, vpx_bit_depth_t>
ErrorBlockParam;
class ErrorBlockTest
: public ::testing::TestWithParam<ErrorBlockParam> {
public:
virtual ~ErrorBlockTest() {}
virtual void SetUp() {
error_block_op_ = GET_PARAM(0);
ref_error_block_op_ = GET_PARAM(1);
bit_depth_ = GET_PARAM(2);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
vpx_bit_depth_t bit_depth_;
ErrorBlockFunc error_block_op_;
ErrorBlockFunc ref_error_block_op_;
};
TEST_P(ErrorBlockTest, OperationCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff, 4096);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, dqcoeff, 4096);
int err_count_total = 0;
int first_failure = -1;
intptr_t block_size;
int64_t ssz;
int64_t ret;
int64_t ref_ssz;
int64_t ref_ret;
for (int i = 0; i < number_of_iterations; ++i) {
int err_count = 0;
block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64
for (int j = 0; j < block_size; j++) {
coeff[j] = rnd(2<<20)-(1<<20);
dqcoeff[j] = rnd(2<<20)-(1<<20);
}
ref_ret = ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz,
bit_depth_);
ASM_REGISTER_STATE_CHECK(ret = error_block_op_(coeff, dqcoeff, block_size,
&ssz, bit_depth_));
err_count += (ref_ret != ret) | (ref_ssz != ssz);
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Error Block Test, C output doesn't match SSE2 output. "
<< "First failed at test case " << first_failure;
}
TEST_P(ErrorBlockTest, ExtremeValues) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff, 4096);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, dqcoeff, 4096);
int err_count_total = 0;
int first_failure = -1;
intptr_t block_size;
int64_t ssz;
int64_t ret;
int64_t ref_ssz;
int64_t ref_ret;
int max_val = ((1<<20)-1);
for (int i = 0; i < number_of_iterations; ++i) {
int err_count = 0;
int k = (i / 9) % 5;
// Change the maximum coeff value, to test different bit boundaries
if ( k == 4 && (i % 9) == 0 ) {
max_val >>= 1;
}
block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64
for (int j = 0; j < block_size; j++) {
if (k < 4) { // Test at maximum values
coeff[j] = k % 2 ? max_val : -max_val;
dqcoeff[j] = (k >> 1) % 2 ? max_val : -max_val;
} else {
coeff[j] = rnd(2 << 14) - (1 << 14);
dqcoeff[j] = rnd(2 << 14) - (1 << 14);
}
}
ref_ret = ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz,
bit_depth_);
ASM_REGISTER_STATE_CHECK(ret = error_block_op_(coeff, dqcoeff, block_size,
&ssz, bit_depth_));
err_count += (ref_ret != ret) | (ref_ssz != ssz);
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Error Block Test, C output doesn't match SSE2 output. "
<< "First failed at test case " << first_failure;
}
using std::tr1::make_tuple;
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(
SSE2_C_COMPARE, ErrorBlockTest,
::testing::Values(
make_tuple(&vp9_highbd_block_error_sse2,
&vp9_highbd_block_error_c, VPX_BITS_10),
make_tuple(&vp9_highbd_block_error_sse2,
&vp9_highbd_block_error_c, VPX_BITS_12),
make_tuple(&vp9_highbd_block_error_sse2,
&vp9_highbd_block_error_c, VPX_BITS_8)));
#endif // HAVE_SSE2
#endif // CONFIG_VP9_HIGHBITDEPTH
} // namespace

View File

@ -75,6 +75,16 @@ void iwht4x4_10(const tran_low_t *in, uint8_t *out, int stride) {
void iwht4x4_12(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_iwht4x4_16_add_c(in, out, stride, 12);
}
#if HAVE_SSE2
void idct4x4_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct4x4_16_add_sse2(in, out, stride, 10);
}
void idct4x4_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct4x4_16_add_sse2(in, out, stride, 12);
}
#endif
#endif
class Trans4x4TestBase {
@ -496,4 +506,31 @@ INSTANTIATE_TEST_CASE_P(
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_sse2, 3, VPX_BITS_8)));
#endif
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4DCT,
::testing::Values(
make_tuple(&vp9_highbd_fdct4x4_c, &idct4x4_10_sse2, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct4x4_sse2, &idct4x4_10_sse2, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct4x4_c, &idct4x4_12_sse2, 0, VPX_BITS_12),
make_tuple(&vp9_highbd_fdct4x4_sse2, &idct4x4_12_sse2, 0, VPX_BITS_12),
make_tuple(&vp9_fdct4x4_sse2, &vp9_idct4x4_16_add_c, 0,
VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
SSE2, Trans4x4HT,
::testing::Values(
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_10, 0, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_10, 1, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_10, 2, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_10, 3, VPX_BITS_10),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_12, 0, VPX_BITS_12),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_12, 1, VPX_BITS_12),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_12, 2, VPX_BITS_12),
make_tuple(&vp9_highbd_fht4x4_sse2, &iht4x4_12, 3, VPX_BITS_12),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_c, 0, VPX_BITS_8),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_c, 1, VPX_BITS_8),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_c, 2, VPX_BITS_8),
make_tuple(&vp9_fht4x4_sse2, &vp9_iht4x4_16_add_c, 3, VPX_BITS_8)));
#endif
} // namespace

View File

@ -71,6 +71,7 @@ typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride,
typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct8x8Param;
typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht8x8Param;
typedef std::tr1::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t> Idct8x8Param;
void fdct8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) {
vp9_fdct8x8_c(in, out, stride);
@ -96,6 +97,32 @@ void iht8x8_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
void iht8x8_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) {
vp9_highbd_iht8x8_64_add_c(in, out, stride, tx_type, 12);
}
void idct8x8_10_add_10_c(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct8x8_10_add_c(in, out, stride, 10);
}
void idct8x8_10_add_12_c(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct8x8_10_add_c(in, out, stride, 12);
}
#if HAVE_SSE2
void idct8x8_10_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct8x8_10_add_sse2(in, out, stride, 10);
}
void idct8x8_10_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct8x8_10_add_sse2(in, out, stride, 12);
}
void idct8x8_64_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct8x8_64_add_sse2(in, out, stride, 10);
}
void idct8x8_64_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) {
vp9_highbd_idct8x8_64_add_sse2(in, out, stride, 12);
}
#endif
#endif
class FwdTrans8x8TestBase {
@ -146,9 +173,10 @@ class FwdTrans8x8TestBase {
memset(count_sign_block, 0, sizeof(count_sign_block));
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-15, 15].
// Initialize a test block with input range [-mask_/16, mask_/16].
for (int j = 0; j < 64; ++j)
test_input_block[j] = (rnd.Rand8() >> 4) - (rnd.Rand8() >> 4);
test_input_block[j] = ((rnd.Rand16() & mask_) >> 4) -
((rnd.Rand16() & mask_) >> 4);
ASM_REGISTER_STATE_CHECK(
RunFwdTxfm(test_input_block, test_output_block, pitch_));
@ -188,7 +216,7 @@ class FwdTrans8x8TestBase {
#endif
for (int i = 0; i < count_test_block; ++i) {
// Initialize a test block with input range [-255, 255].
// Initialize a test block with input range [-mask_, mask_].
for (int j = 0; j < 64; ++j) {
if (bit_depth_ == VPX_BITS_8) {
src[j] = rnd.Rand8();
@ -427,6 +455,63 @@ class FwdTrans8x8TestBase {
}
}
}
void CompareInvReference(IdctFunc ref_txfm, int thresh) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
const int count_test_block = 10000;
const int eob = 12;
DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint8_t, ref, kNumCoeffs);
#if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref16, kNumCoeffs);
#endif
const int16_t *scan = vp9_default_scan_orders[TX_8X8].scan;
for (int i = 0; i < count_test_block; ++i) {
for (int j = 0; j < kNumCoeffs; ++j) {
if (j < eob) {
// Random values less than the threshold, either positive or negative
coeff[scan[j]] = rnd(thresh) * (1-2*(i%2));
} else {
coeff[scan[j]] = 0;
}
if (bit_depth_ == VPX_BITS_8) {
dst[j] = 0;
ref[j] = 0;
#if CONFIG_VP9_HIGHBITDEPTH
} else {
dst16[j] = 0;
ref16[j] = 0;
#endif
}
}
if (bit_depth_ == VPX_BITS_8) {
ref_txfm(coeff, ref, pitch_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
#if CONFIG_VP9_HIGHBITDEPTH
} else {
ref_txfm(coeff, CONVERT_TO_BYTEPTR(ref16), pitch_);
ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16),
pitch_));
#endif
}
for (int j = 0; j < kNumCoeffs; ++j) {
#if CONFIG_VP9_HIGHBITDEPTH
const uint32_t diff =
bit_depth_ == VPX_BITS_8 ? dst[j] - ref[j] : dst16[j] - ref16[j];
#else
const uint32_t diff = dst[j] - ref[j];
#endif
const uint32_t error = diff * diff;
EXPECT_EQ(0u, error)
<< "Error: 8x8 IDCT has error " << error
<< " at index " << j;
}
}
}
int pitch_;
int tx_type_;
FhtFunc fwd_txfm_ref;
@ -526,6 +611,38 @@ TEST_P(FwdTrans8x8HT, ExtremalCheck) {
RunExtremalCheck();
}
class InvTrans8x8DCT
: public FwdTrans8x8TestBase,
public ::testing::TestWithParam<Idct8x8Param> {
public:
virtual ~InvTrans8x8DCT() {}
virtual void SetUp() {
ref_txfm_ = GET_PARAM(0);
inv_txfm_ = GET_PARAM(1);
thresh_ = GET_PARAM(2);
pitch_ = 8;
bit_depth_ = GET_PARAM(3);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) {
inv_txfm_(out, dst, stride);
}
void RunFwdTxfm(int16_t *out, tran_low_t *dst, int stride) {}
IdctFunc ref_txfm_;
IdctFunc inv_txfm_;
int thresh_;
};
TEST_P(InvTrans8x8DCT, CompareReference) {
CompareInvReference(ref_txfm_, thresh_);
}
using std::tr1::make_tuple;
#if CONFIG_VP9_HIGHBITDEPTH
@ -598,6 +715,45 @@ INSTANTIATE_TEST_CASE_P(
make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 3, VPX_BITS_8)));
#endif
#if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(
SSE2, FwdTrans8x8DCT,
::testing::Values(
make_tuple(&vp9_highbd_fdct8x8_c,
&idct8x8_64_add_10_sse2, 12, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct8x8_sse2,
&idct8x8_64_add_10_sse2, 12, VPX_BITS_10),
make_tuple(&vp9_highbd_fdct8x8_c,
&idct8x8_64_add_12_sse2, 12, VPX_BITS_12),
make_tuple(&vp9_highbd_fdct8x8_sse2,
&idct8x8_64_add_12_sse2, 12, VPX_BITS_12),
make_tuple(&vp9_fdct8x8_sse2, &vp9_idct8x8_64_add_c, 0, VPX_BITS_8)));
INSTANTIATE_TEST_CASE_P(
SSE2, FwdTrans8x8HT,
::testing::Values(
make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 0, VPX_BITS_8),
make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 1, VPX_BITS_8),
make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8),
make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8)));
// Optimizations take effect at a threshold of 6201, so we use a value close to
// that to test both branches.
INSTANTIATE_TEST_CASE_P(
SSE2, InvTrans8x8DCT,
::testing::Values(
make_tuple(&idct8x8_10_add_10_c,
&idct8x8_10_add_10_sse2, 6225, VPX_BITS_10),
make_tuple(&idct8x8_10,
&idct8x8_64_add_10_sse2, 6225, VPX_BITS_10),
make_tuple(&idct8x8_10_add_12_c,
&idct8x8_10_add_12_sse2, 6225, VPX_BITS_12),
make_tuple(&idct8x8_12,
&idct8x8_64_add_12_sse2, 6225, VPX_BITS_12)));
#endif
#if HAVE_SSSE3 && ARCH_X86_64 && !CONFIG_VP9_HIGHBITDEPTH && \
!CONFIG_EMULATE_HARDWARE
INSTANTIATE_TEST_CASE_P(

View File

@ -23,6 +23,8 @@
#include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_integer.h"
#define MAX_LOOP_FILTER 63
using libvpx_test::ACMRandom;
namespace {
@ -160,11 +162,18 @@ TEST_P(Loop8Test6Param, OperationCheck) {
for (int i = 0; i < count_test_block; ++i) {
int err_count = 0;
uint8_t tmp = rnd.Rand8();
// mblim <= 3 * MAX_LOOP_FILTER + 4
while (tmp > 3 * MAX_LOOP_FILTER + 4) {
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, blimit[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
while (tmp > MAX_LOOP_FILTER) { // lim <= MAX_LOOP_FILTER
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, limit[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
@ -246,11 +255,18 @@ TEST_P(Loop8Test6Param, ValueCheck) {
for (int i = 0; i < count_test_block; ++i) {
int err_count = 0;
uint8_t tmp = rnd.Rand8();
// mblim <= 3 * MAX_LOOP_FILTER + 4
while (tmp > 3 * MAX_LOOP_FILTER + 4) {
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, blimit[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
while (tmp > MAX_LOOP_FILTER) { // lim <= MAX_LOOP_FILTER
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, limit[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
@ -305,11 +321,19 @@ TEST_P(Loop8Test9Param, OperationCheck) {
for (int i = 0; i < count_test_block; ++i) {
int err_count = 0;
uint8_t tmp = rnd.Rand8();
// mblim <= 3 * MAX_LOOP_FILTER + 4
while (tmp > 3 * MAX_LOOP_FILTER + 4) {
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, blimit0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
// lim <= MAX_LOOP_FILTER
while (tmp > MAX_LOOP_FILTER) {
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, limit0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
@ -320,11 +344,18 @@ TEST_P(Loop8Test9Param, OperationCheck) {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
// mblim <= 3 * MAX_LOOP_FILTER + 4
while (tmp > 3 * MAX_LOOP_FILTER + 4) {
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, blimit1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
while (tmp > MAX_LOOP_FILTER) { // lim <= MAX_LOOP_FILTER
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, limit1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
@ -407,11 +438,18 @@ TEST_P(Loop8Test9Param, ValueCheck) {
for (int i = 0; i < count_test_block; ++i) {
int err_count = 0;
uint8_t tmp = rnd.Rand8();
// mblim <= 3 * MAX_LOOP_FILTER + 4
while (tmp > 3 * MAX_LOOP_FILTER + 4) {
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, blimit0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
while (tmp > MAX_LOOP_FILTER) { // lim <= MAX_LOOP_FILTER
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, limit0[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
@ -422,11 +460,18 @@ TEST_P(Loop8Test9Param, ValueCheck) {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
// mblim <= 3 * MAX_LOOP_FILTER + 4
while (tmp > 3 * MAX_LOOP_FILTER + 4) {
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, blimit1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp
};
tmp = rnd.Rand8();
while (tmp > MAX_LOOP_FILTER) { // lim <= MAX_LOOP_FILTER
tmp = rnd.Rand8();
}
DECLARE_ALIGNED(16, const uint8_t, limit1[16]) = {
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp,
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp

209
test/masked_sad_test.cc Normal file
View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_integer.h"
using libvpx_test::ACMRandom;
namespace {
const int number_of_iterations = 500;
typedef unsigned int (*MaskedSADFunc)(const uint8_t *a, int a_stride,
const uint8_t *b, int b_stride,
const uint8_t *m, int m_stride);
typedef std::tr1::tuple<MaskedSADFunc, MaskedSADFunc> MaskedSADParam;
class MaskedSADTest : public ::testing::TestWithParam<MaskedSADParam> {
public:
virtual ~MaskedSADTest() {}
virtual void SetUp() {
maskedSAD_op_ = GET_PARAM(0);
ref_maskedSAD_op_ = GET_PARAM(1);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
MaskedSADFunc maskedSAD_op_;
MaskedSADFunc ref_maskedSAD_op_;
};
TEST_P(MaskedSADTest, OperationCheck) {
unsigned int ref_ret, ret;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint8_t, src_ptr, 4096);
DECLARE_ALIGNED_ARRAY(16, uint8_t, ref_ptr, 4096);
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, 4096);
int err_count = 0;
int first_failure = -1;
int src_stride = 64;
int ref_stride = 64;
int msk_stride = 64;
for (int i = 0; i < number_of_iterations; ++i) {
for (int j = 0; j < 4096; j++) {
src_ptr[j] = rnd.Rand8();
ref_ptr[j] = rnd.Rand8();
msk_ptr[j] = ((rnd.Rand8()&0x7f) > 64) ? rnd.Rand8()&0x3f : 64;
}
ref_ret = ref_maskedSAD_op_(src_ptr, src_stride, ref_ptr, ref_stride,
msk_ptr, msk_stride);
ASM_REGISTER_STATE_CHECK(ret = maskedSAD_op_(src_ptr, src_stride,
ref_ptr, ref_stride,
msk_ptr, msk_stride));
if (ret != ref_ret) {
err_count++;
if (first_failure == -1)
first_failure = i;
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked SAD Test, C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure;
}
#if CONFIG_VP9_HIGHBITDEPTH
typedef unsigned int (*HighbdMaskedSADFunc)(const uint8_t *a, int a_stride,
const uint8_t *b, int b_stride,
const uint8_t *m, int m_stride);
typedef std::tr1::tuple<HighbdMaskedSADFunc, HighbdMaskedSADFunc>
HighbdMaskedSADParam;
class HighbdMaskedSADTest : public ::testing::
TestWithParam<HighbdMaskedSADParam> {
public:
virtual ~HighbdMaskedSADTest() {}
virtual void SetUp() {
maskedSAD_op_ = GET_PARAM(0);
ref_maskedSAD_op_ = GET_PARAM(1);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
HighbdMaskedSADFunc maskedSAD_op_;
HighbdMaskedSADFunc ref_maskedSAD_op_;
};
TEST_P(HighbdMaskedSADTest, OperationCheck) {
unsigned int ref_ret, ret;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint16_t, src_ptr, 4096);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_ptr, 4096);
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, 4096);
uint8_t* src8_ptr = CONVERT_TO_BYTEPTR(src_ptr);
uint8_t* ref8_ptr = CONVERT_TO_BYTEPTR(ref_ptr);
int err_count = 0;
int first_failure = -1;
int src_stride = 64;
int ref_stride = 64;
int msk_stride = 64;
for (int i = 0; i < number_of_iterations; ++i) {
for (int j = 0; j < 4096; j++) {
src_ptr[j] = rnd.Rand16()&0xfff;
ref_ptr[j] = rnd.Rand16()&0xfff;
msk_ptr[j] = ((rnd.Rand8()&0x7f) > 64) ? rnd.Rand8()&0x3f : 64;
}
ref_ret = ref_maskedSAD_op_(src8_ptr, src_stride, ref8_ptr, ref_stride,
msk_ptr, msk_stride);
ASM_REGISTER_STATE_CHECK(ret = maskedSAD_op_(src8_ptr, src_stride,
ref8_ptr, ref_stride,
msk_ptr, msk_stride));
if (ret != ref_ret) {
err_count++;
if (first_failure == -1)
first_failure = i;
}
}
EXPECT_EQ(0, err_count)
<< "Error: High BD Masked SAD Test, C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
using std::tr1::make_tuple;
#if HAVE_SSSE3
INSTANTIATE_TEST_CASE_P(
SSSE3_C_COMPARE, MaskedSADTest,
::testing::Values(
make_tuple(&vp9_masked_sad64x64_ssse3,
&vp9_masked_sad64x64_c),
make_tuple(&vp9_masked_sad64x32_ssse3,
&vp9_masked_sad64x32_c),
make_tuple(&vp9_masked_sad32x64_ssse3,
&vp9_masked_sad32x64_c),
make_tuple(&vp9_masked_sad32x32_ssse3,
&vp9_masked_sad32x32_c),
make_tuple(&vp9_masked_sad32x16_ssse3,
&vp9_masked_sad32x16_c),
make_tuple(&vp9_masked_sad16x32_ssse3,
&vp9_masked_sad16x32_c),
make_tuple(&vp9_masked_sad16x16_ssse3,
&vp9_masked_sad16x16_c),
make_tuple(&vp9_masked_sad16x8_ssse3,
&vp9_masked_sad16x8_c),
make_tuple(&vp9_masked_sad8x16_ssse3,
&vp9_masked_sad8x16_c),
make_tuple(&vp9_masked_sad8x8_ssse3,
&vp9_masked_sad8x8_c),
make_tuple(&vp9_masked_sad8x4_ssse3,
&vp9_masked_sad8x4_c),
make_tuple(&vp9_masked_sad4x8_ssse3,
&vp9_masked_sad4x8_c),
make_tuple(&vp9_masked_sad4x4_ssse3,
&vp9_masked_sad4x4_c)));
#if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
SSSE3_C_COMPARE, HighbdMaskedSADTest,
::testing::Values(
make_tuple(&vp9_highbd_masked_sad64x64_ssse3,
&vp9_highbd_masked_sad64x64_c),
make_tuple(&vp9_highbd_masked_sad64x32_ssse3,
&vp9_highbd_masked_sad64x32_c),
make_tuple(&vp9_highbd_masked_sad32x64_ssse3,
&vp9_highbd_masked_sad32x64_c),
make_tuple(&vp9_highbd_masked_sad32x32_ssse3,
&vp9_highbd_masked_sad32x32_c),
make_tuple(&vp9_highbd_masked_sad32x16_ssse3,
&vp9_highbd_masked_sad32x16_c),
make_tuple(&vp9_highbd_masked_sad16x32_ssse3,
&vp9_highbd_masked_sad16x32_c),
make_tuple(&vp9_highbd_masked_sad16x16_ssse3,
&vp9_highbd_masked_sad16x16_c),
make_tuple(&vp9_highbd_masked_sad16x8_ssse3,
&vp9_highbd_masked_sad16x8_c),
make_tuple(&vp9_highbd_masked_sad8x16_ssse3,
&vp9_highbd_masked_sad8x16_c),
make_tuple(&vp9_highbd_masked_sad8x8_ssse3,
&vp9_highbd_masked_sad8x8_c),
make_tuple(&vp9_highbd_masked_sad8x4_ssse3,
&vp9_highbd_masked_sad8x4_c),
make_tuple(&vp9_highbd_masked_sad4x8_ssse3,
&vp9_highbd_masked_sad4x8_c),
make_tuple(&vp9_highbd_masked_sad4x4_ssse3,
&vp9_highbd_masked_sad4x4_c)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // HAVE_SSSE3
} // namespace

View File

@ -0,0 +1,753 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_integer.h"
#include "vp9/common/vp9_filter.h"
#define MAX_SIZE 64
using libvpx_test::ACMRandom;
namespace {
const int number_of_iterations = 500;
typedef unsigned int (*MaskedVarianceFunc)(const uint8_t *a, int a_stride,
const uint8_t *b, int b_stride,
const uint8_t *m, int m_stride,
unsigned int *sse);
typedef std::tr1::tuple<MaskedVarianceFunc,
MaskedVarianceFunc> MaskedVarianceParam;
class MaskedVarianceTest :
public ::testing::TestWithParam<MaskedVarianceParam> {
public:
virtual ~MaskedVarianceTest() {}
virtual void SetUp() {
opt_func_ = GET_PARAM(0);
ref_func_ = GET_PARAM(1);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
MaskedVarianceFunc opt_func_;
MaskedVarianceFunc ref_func_;
};
TEST_P(MaskedVarianceTest, OperationCheck) {
unsigned int ref_ret, opt_ret;
unsigned int ref_sse, opt_sse;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint8_t, src_ptr, MAX_SIZE*MAX_SIZE);
DECLARE_ALIGNED_ARRAY(16, uint8_t, ref_ptr, MAX_SIZE*MAX_SIZE);
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, MAX_SIZE*MAX_SIZE);
int err_count = 0;
int first_failure = -1;
int src_stride = MAX_SIZE;
int ref_stride = MAX_SIZE;
int msk_stride = MAX_SIZE;
for (int i = 0; i < number_of_iterations; ++i) {
for (int j = 0; j < MAX_SIZE*MAX_SIZE; j++) {
src_ptr[j] = rnd.Rand8();
ref_ptr[j] = rnd.Rand8();
msk_ptr[j] = rnd(65);
}
ref_ret = ref_func_(src_ptr, src_stride,
ref_ptr, ref_stride,
msk_ptr, msk_stride,
&ref_sse);
ASM_REGISTER_STATE_CHECK(opt_ret = opt_func_(src_ptr, src_stride,
ref_ptr, ref_stride,
msk_ptr, msk_stride,
&opt_sse));
if (opt_ret != ref_ret || opt_sse != ref_sse) {
err_count++;
if (first_failure == -1)
first_failure = i;
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked Variance Test OperationCheck,"
<< "C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure;
}
TEST_P(MaskedVarianceTest, ExtremeValues) {
unsigned int ref_ret, opt_ret;
unsigned int ref_sse, opt_sse;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint8_t, src_ptr, MAX_SIZE*MAX_SIZE);
DECLARE_ALIGNED_ARRAY(16, uint8_t, ref_ptr, MAX_SIZE*MAX_SIZE);
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, MAX_SIZE*MAX_SIZE);
int err_count = 0;
int first_failure = -1;
int src_stride = MAX_SIZE;
int ref_stride = MAX_SIZE;
int msk_stride = MAX_SIZE;
for (int i = 0; i < 8; ++i) {
memset(src_ptr, (i & 0x1) ? 255 : 0, MAX_SIZE*MAX_SIZE);
memset(ref_ptr, (i & 0x2) ? 255 : 0, MAX_SIZE*MAX_SIZE);
memset(msk_ptr, (i & 0x4) ? 64 : 0, MAX_SIZE*MAX_SIZE);
ref_ret = ref_func_(src_ptr, src_stride,
ref_ptr, ref_stride,
msk_ptr, msk_stride,
&ref_sse);
ASM_REGISTER_STATE_CHECK(opt_ret = opt_func_(src_ptr, src_stride,
ref_ptr, ref_stride,
msk_ptr, msk_stride,
&opt_sse));
if (opt_ret != ref_ret || opt_sse != ref_sse) {
err_count++;
if (first_failure == -1)
first_failure = i;
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked Variance Test ExtremeValues,"
<< "C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure;
}
typedef unsigned int (*MaskedSubPixelVarianceFunc)(
const uint8_t *a, int a_stride,
int xoffset, int yoffset,
const uint8_t *b, int b_stride,
const uint8_t *m, int m_stride,
unsigned int *sse);
typedef std::tr1::tuple<MaskedSubPixelVarianceFunc,
MaskedSubPixelVarianceFunc> MaskedSubPixelVarianceParam;
class MaskedSubPixelVarianceTest :
public ::testing::TestWithParam<MaskedSubPixelVarianceParam> {
public:
virtual ~MaskedSubPixelVarianceTest() {}
virtual void SetUp() {
opt_func_ = GET_PARAM(0);
ref_func_ = GET_PARAM(1);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
MaskedSubPixelVarianceFunc opt_func_;
MaskedSubPixelVarianceFunc ref_func_;
};
TEST_P(MaskedSubPixelVarianceTest, OperationCheck) {
unsigned int ref_ret, opt_ret;
unsigned int ref_sse, opt_sse;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint8_t, src_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
DECLARE_ALIGNED_ARRAY(16, uint8_t, ref_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
int err_count = 0;
int first_failure = -1;
int src_stride = (MAX_SIZE+1);
int ref_stride = (MAX_SIZE+1);
int msk_stride = (MAX_SIZE+1);
int xoffset;
int yoffset;
for (int i = 0; i < number_of_iterations; ++i) {
int xoffsets[] = {0, 8, rnd(SUBPEL_SHIFTS)};
int yoffsets[] = {0, 8, rnd(SUBPEL_SHIFTS)};
for (int j = 0; j < (MAX_SIZE+1)*(MAX_SIZE+1); j++) {
src_ptr[j] = rnd.Rand8();
ref_ptr[j] = rnd.Rand8();
msk_ptr[j] = rnd(65);
}
for (int k = 0; k < 3; k++) {
xoffset = xoffsets[k];
for (int l = 0; l < 3; l++) {
xoffset = xoffsets[k];
yoffset = yoffsets[l];
ref_ret = ref_func_(src_ptr, src_stride,
xoffset, yoffset,
ref_ptr, ref_stride,
msk_ptr, msk_stride,
&ref_sse);
ASM_REGISTER_STATE_CHECK(opt_ret = opt_func_(src_ptr, src_stride,
xoffset, yoffset,
ref_ptr, ref_stride,
msk_ptr, msk_stride,
&opt_sse));
if (opt_ret != ref_ret || opt_sse != ref_sse) {
err_count++;
if (first_failure == -1)
first_failure = i;
}
}
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked Sub Pixel Variance Test OperationCheck,"
<< "C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure;
}
TEST_P(MaskedSubPixelVarianceTest, ExtremeValues) {
unsigned int ref_ret, opt_ret;
unsigned int ref_sse, opt_sse;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint8_t, src_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
DECLARE_ALIGNED_ARRAY(16, uint8_t, ref_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
int first_failure_x = -1;
int first_failure_y = -1;
int err_count = 0;
int first_failure = -1;
int src_stride = (MAX_SIZE+1);
int ref_stride = (MAX_SIZE+1);
int msk_stride = (MAX_SIZE+1);
for (int xoffset = 0 ; xoffset < SUBPEL_SHIFTS ; xoffset++) {
for (int yoffset = 0 ; yoffset < SUBPEL_SHIFTS ; yoffset++) {
for (int i = 0; i < 8; ++i) {
memset(src_ptr, (i & 0x1) ? 255 : 0, (MAX_SIZE+1)*(MAX_SIZE+1));
memset(ref_ptr, (i & 0x2) ? 255 : 0, (MAX_SIZE+1)*(MAX_SIZE+1));
memset(msk_ptr, (i & 0x4) ? 64 : 0, (MAX_SIZE+1)*(MAX_SIZE+1));
ref_ret = ref_func_(src_ptr, src_stride,
xoffset, yoffset,
ref_ptr, ref_stride,
msk_ptr, msk_stride,
&ref_sse);
ASM_REGISTER_STATE_CHECK(opt_ret = opt_func_(src_ptr, src_stride,
xoffset, yoffset,
ref_ptr, ref_stride,
msk_ptr, msk_stride,
&opt_sse));
if (opt_ret != ref_ret || opt_sse != ref_sse) {
err_count++;
if (first_failure == -1) {
first_failure = i;
first_failure_x = xoffset;
first_failure_y = yoffset;
}
}
}
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked Variance Test ExtremeValues,"
<< "C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure
<< " x_offset = " << first_failure_x
<< " y_offset = " << first_failure_y;
}
#if CONFIG_VP9_HIGHBITDEPTH
typedef std::tr1::tuple<MaskedVarianceFunc,
MaskedVarianceFunc,
vpx_bit_depth_t> HighbdMaskedVarianceParam;
class HighbdMaskedVarianceTest :
public ::testing::TestWithParam<HighbdMaskedVarianceParam> {
public:
virtual ~HighbdMaskedVarianceTest() {}
virtual void SetUp() {
opt_func_ = GET_PARAM(0);
ref_func_ = GET_PARAM(1);
bit_depth_ = GET_PARAM(2);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
MaskedVarianceFunc opt_func_;
MaskedVarianceFunc ref_func_;
vpx_bit_depth_t bit_depth_;
};
TEST_P(HighbdMaskedVarianceTest, OperationCheck) {
unsigned int ref_ret, opt_ret;
unsigned int ref_sse, opt_sse;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint16_t, src_ptr, MAX_SIZE*MAX_SIZE);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_ptr, MAX_SIZE*MAX_SIZE);
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, MAX_SIZE*MAX_SIZE);
uint8_t* src8_ptr = CONVERT_TO_BYTEPTR(src_ptr);
uint8_t* ref8_ptr = CONVERT_TO_BYTEPTR(ref_ptr);
int err_count = 0;
int first_failure = -1;
int src_stride = MAX_SIZE;
int ref_stride = MAX_SIZE;
int msk_stride = MAX_SIZE;
for (int i = 0; i < number_of_iterations; ++i) {
for (int j = 0; j < MAX_SIZE*MAX_SIZE; j++) {
src_ptr[j] = rnd.Rand16() & ((1 << bit_depth_) - 1);
ref_ptr[j] = rnd.Rand16() & ((1 << bit_depth_) - 1);
msk_ptr[j] = rnd(65);
}
ref_ret = ref_func_(src8_ptr, src_stride,
ref8_ptr, ref_stride,
msk_ptr, msk_stride,
&ref_sse);
ASM_REGISTER_STATE_CHECK(opt_ret = opt_func_(src8_ptr, src_stride,
ref8_ptr, ref_stride,
msk_ptr, msk_stride,
&opt_sse));
if (opt_ret != ref_ret || opt_sse != ref_sse) {
err_count++;
if (first_failure == -1)
first_failure = i;
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked Variance Test OperationCheck,"
<< "C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure;
}
TEST_P(HighbdMaskedVarianceTest, ExtremeValues) {
unsigned int ref_ret, opt_ret;
unsigned int ref_sse, opt_sse;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint16_t, src_ptr, MAX_SIZE*MAX_SIZE);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_ptr, MAX_SIZE*MAX_SIZE);
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, MAX_SIZE*MAX_SIZE);
uint8_t* src8_ptr = CONVERT_TO_BYTEPTR(src_ptr);
uint8_t* ref8_ptr = CONVERT_TO_BYTEPTR(ref_ptr);
int err_count = 0;
int first_failure = -1;
int src_stride = MAX_SIZE;
int ref_stride = MAX_SIZE;
int msk_stride = MAX_SIZE;
for (int i = 0; i < 8; ++i) {
vpx_memset16(src_ptr, (i & 0x1) ? ((1 << bit_depth_) - 1) : 0,
MAX_SIZE*MAX_SIZE);
vpx_memset16(ref_ptr, (i & 0x2) ? ((1 << bit_depth_) - 1) : 0,
MAX_SIZE*MAX_SIZE);
memset(msk_ptr, (i & 0x4) ? 64 : 0, MAX_SIZE*MAX_SIZE);
ref_ret = ref_func_(src8_ptr, src_stride,
ref8_ptr, ref_stride,
msk_ptr, msk_stride,
&ref_sse);
ASM_REGISTER_STATE_CHECK(opt_ret = opt_func_(src8_ptr, src_stride,
ref8_ptr, ref_stride,
msk_ptr, msk_stride,
&opt_sse));
if (opt_ret != ref_ret || opt_sse != ref_sse) {
err_count++;
if (first_failure == -1)
first_failure = i;
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked Variance Test ExtremeValues,"
<< "C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure;
}
typedef std::tr1::tuple<MaskedSubPixelVarianceFunc,
MaskedSubPixelVarianceFunc,
vpx_bit_depth_t> HighbdMaskedSubPixelVarianceParam;
class HighbdMaskedSubPixelVarianceTest :
public ::testing::TestWithParam<HighbdMaskedSubPixelVarianceParam> {
public:
virtual ~HighbdMaskedSubPixelVarianceTest() {}
virtual void SetUp() {
opt_func_ = GET_PARAM(0);
ref_func_ = GET_PARAM(1);
bit_depth_ = GET_PARAM(2);
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
MaskedSubPixelVarianceFunc opt_func_;
MaskedSubPixelVarianceFunc ref_func_;
vpx_bit_depth_t bit_depth_;
};
TEST_P(HighbdMaskedSubPixelVarianceTest, OperationCheck) {
unsigned int ref_ret, opt_ret;
unsigned int ref_sse, opt_sse;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint16_t, src_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
uint8_t* src8_ptr = CONVERT_TO_BYTEPTR(src_ptr);
uint8_t* ref8_ptr = CONVERT_TO_BYTEPTR(ref_ptr);
int err_count = 0;
int first_failure = -1;
int first_failure_x = -1;
int first_failure_y = -1;
int src_stride = (MAX_SIZE+1);
int ref_stride = (MAX_SIZE+1);
int msk_stride = (MAX_SIZE+1);
int xoffset, yoffset;
for (int i = 0; i < number_of_iterations; ++i) {
for (xoffset = 0; xoffset < SUBPEL_SHIFTS; xoffset++) {
for (yoffset = 0; yoffset < SUBPEL_SHIFTS; yoffset++) {
for (int j = 0; j < (MAX_SIZE+1)*(MAX_SIZE+1); j++) {
src_ptr[j] = rnd.Rand16() & ((1 << bit_depth_) - 1);
ref_ptr[j] = rnd.Rand16() & ((1 << bit_depth_) - 1);
msk_ptr[j] = rnd(65);
}
ref_ret = ref_func_(src8_ptr, src_stride,
xoffset, yoffset,
ref8_ptr, ref_stride,
msk_ptr, msk_stride,
&ref_sse);
ASM_REGISTER_STATE_CHECK(opt_ret = opt_func_(src8_ptr, src_stride,
xoffset, yoffset,
ref8_ptr, ref_stride,
msk_ptr, msk_stride,
&opt_sse));
if (opt_ret != ref_ret || opt_sse != ref_sse) {
err_count++;
if (first_failure == -1) {
first_failure = i;
first_failure_x = xoffset;
first_failure_y = yoffset;
}
}
}
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked Sub Pixel Variance Test OperationCheck,"
<< "C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure
<< " x_offset = " << first_failure_x
<< " y_offset = " << first_failure_y;
}
TEST_P(HighbdMaskedSubPixelVarianceTest, ExtremeValues) {
unsigned int ref_ret, opt_ret;
unsigned int ref_sse, opt_sse;
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, uint16_t, src_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
DECLARE_ALIGNED_ARRAY(16, uint8_t, msk_ptr, (MAX_SIZE+1)*(MAX_SIZE+1));
uint8_t* src8_ptr = CONVERT_TO_BYTEPTR(src_ptr);
uint8_t* ref8_ptr = CONVERT_TO_BYTEPTR(ref_ptr);
int first_failure_x = -1;
int first_failure_y = -1;
int err_count = 0;
int first_failure = -1;
int src_stride = (MAX_SIZE+1);
int ref_stride = (MAX_SIZE+1);
int msk_stride = (MAX_SIZE+1);
for (int xoffset = 0 ; xoffset < SUBPEL_SHIFTS ; xoffset++) {
for (int yoffset = 0 ; yoffset < SUBPEL_SHIFTS ; yoffset++) {
for (int i = 0; i < 8; ++i) {
vpx_memset16(src_ptr, (i & 0x1) ? ((1 << bit_depth_) - 1) : 0,
(MAX_SIZE+1)*(MAX_SIZE+1));
vpx_memset16(ref_ptr, (i & 0x2) ? ((1 << bit_depth_) - 1) : 0,
(MAX_SIZE+1)*(MAX_SIZE+1));
memset(msk_ptr, (i & 0x4) ? 64 : 0, (MAX_SIZE+1)*(MAX_SIZE+1));
ref_ret = ref_func_(src8_ptr, src_stride,
xoffset, yoffset,
ref8_ptr, ref_stride,
msk_ptr, msk_stride,
&ref_sse);
ASM_REGISTER_STATE_CHECK(opt_ret = opt_func_(src8_ptr, src_stride,
xoffset, yoffset,
ref8_ptr, ref_stride,
msk_ptr, msk_stride,
&opt_sse));
if (opt_ret != ref_ret || opt_sse != ref_sse) {
err_count++;
if (first_failure == -1) {
first_failure = i;
first_failure_x = xoffset;
first_failure_y = yoffset;
}
}
}
}
}
EXPECT_EQ(0, err_count)
<< "Error: Masked Variance Test ExtremeValues,"
<< "C output doesn't match SSSE3 output. "
<< "First failed at test case " << first_failure
<< " x_offset = " << first_failure_x
<< " y_offset = " << first_failure_y;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
using std::tr1::make_tuple;
#if HAVE_SSSE3
INSTANTIATE_TEST_CASE_P(
SSSE3_C_COMPARE, MaskedVarianceTest,
::testing::Values(
make_tuple(&vp9_masked_variance64x64_ssse3,
&vp9_masked_variance64x64_c),
make_tuple(&vp9_masked_variance64x32_ssse3,
&vp9_masked_variance64x32_c),
make_tuple(&vp9_masked_variance32x64_ssse3,
&vp9_masked_variance32x64_c),
make_tuple(&vp9_masked_variance32x32_ssse3,
&vp9_masked_variance32x32_c),
make_tuple(&vp9_masked_variance32x16_ssse3,
&vp9_masked_variance32x16_c),
make_tuple(&vp9_masked_variance16x32_ssse3,
&vp9_masked_variance16x32_c),
make_tuple(&vp9_masked_variance16x16_ssse3,
&vp9_masked_variance16x16_c),
make_tuple(&vp9_masked_variance16x8_ssse3,
&vp9_masked_variance16x8_c),
make_tuple(&vp9_masked_variance8x16_ssse3,
&vp9_masked_variance8x16_c),
make_tuple(&vp9_masked_variance8x8_ssse3,
&vp9_masked_variance8x8_c),
make_tuple(&vp9_masked_variance8x4_ssse3,
&vp9_masked_variance8x4_c),
make_tuple(&vp9_masked_variance4x8_ssse3,
&vp9_masked_variance4x8_c),
make_tuple(&vp9_masked_variance4x4_ssse3,
&vp9_masked_variance4x4_c)));
INSTANTIATE_TEST_CASE_P(
SSSE3_C_COMPARE, MaskedSubPixelVarianceTest,
::testing::Values(
make_tuple(&vp9_masked_sub_pixel_variance64x64_ssse3,
&vp9_masked_sub_pixel_variance64x64_c),
make_tuple(&vp9_masked_sub_pixel_variance64x32_ssse3,
&vp9_masked_sub_pixel_variance64x32_c),
make_tuple(&vp9_masked_sub_pixel_variance32x64_ssse3,
&vp9_masked_sub_pixel_variance32x64_c),
make_tuple(&vp9_masked_sub_pixel_variance32x32_ssse3,
&vp9_masked_sub_pixel_variance32x32_c),
make_tuple(&vp9_masked_sub_pixel_variance32x16_ssse3,
&vp9_masked_sub_pixel_variance32x16_c),
make_tuple(&vp9_masked_sub_pixel_variance16x32_ssse3,
&vp9_masked_sub_pixel_variance16x32_c),
make_tuple(&vp9_masked_sub_pixel_variance16x16_ssse3,
&vp9_masked_sub_pixel_variance16x16_c),
make_tuple(&vp9_masked_sub_pixel_variance16x8_ssse3,
&vp9_masked_sub_pixel_variance16x8_c),
make_tuple(&vp9_masked_sub_pixel_variance8x16_ssse3,
&vp9_masked_sub_pixel_variance8x16_c),
make_tuple(&vp9_masked_sub_pixel_variance8x8_ssse3,
&vp9_masked_sub_pixel_variance8x8_c),
make_tuple(&vp9_masked_sub_pixel_variance8x4_ssse3,
&vp9_masked_sub_pixel_variance8x4_c),
make_tuple(&vp9_masked_sub_pixel_variance4x8_ssse3,
&vp9_masked_sub_pixel_variance4x8_c),
make_tuple(&vp9_masked_sub_pixel_variance4x4_ssse3,
&vp9_masked_sub_pixel_variance4x4_c)));
#if CONFIG_VP9_HIGHBITDEPTH
INSTANTIATE_TEST_CASE_P(
SSSE3_C_COMPARE, HighbdMaskedVarianceTest,
::testing::Values(
make_tuple(&vp9_highbd_masked_variance64x64_ssse3,
&vp9_highbd_masked_variance64x64_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance64x32_ssse3,
&vp9_highbd_masked_variance64x32_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance32x64_ssse3,
&vp9_highbd_masked_variance32x64_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance32x32_ssse3,
&vp9_highbd_masked_variance32x32_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance32x16_ssse3,
&vp9_highbd_masked_variance32x16_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance16x32_ssse3,
&vp9_highbd_masked_variance16x32_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance16x16_ssse3,
&vp9_highbd_masked_variance16x16_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance16x8_ssse3,
&vp9_highbd_masked_variance16x8_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance8x16_ssse3,
&vp9_highbd_masked_variance8x16_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance8x8_ssse3,
&vp9_highbd_masked_variance8x8_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance8x4_ssse3,
&vp9_highbd_masked_variance8x4_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance4x8_ssse3,
&vp9_highbd_masked_variance4x8_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_variance4x4_ssse3,
&vp9_highbd_masked_variance4x4_c, VPX_BITS_8),
make_tuple(&vp9_highbd_10_masked_variance64x64_ssse3,
&vp9_highbd_10_masked_variance64x64_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance64x32_ssse3,
&vp9_highbd_10_masked_variance64x32_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance32x64_ssse3,
&vp9_highbd_10_masked_variance32x64_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance32x32_ssse3,
&vp9_highbd_10_masked_variance32x32_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance32x16_ssse3,
&vp9_highbd_10_masked_variance32x16_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance16x32_ssse3,
&vp9_highbd_10_masked_variance16x32_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance16x16_ssse3,
&vp9_highbd_10_masked_variance16x16_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance16x8_ssse3,
&vp9_highbd_10_masked_variance16x8_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance8x16_ssse3,
&vp9_highbd_10_masked_variance8x16_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance8x8_ssse3,
&vp9_highbd_10_masked_variance8x8_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance8x4_ssse3,
&vp9_highbd_10_masked_variance8x4_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance4x8_ssse3,
&vp9_highbd_10_masked_variance4x8_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_variance4x4_ssse3,
&vp9_highbd_10_masked_variance4x4_c, VPX_BITS_10),
make_tuple(&vp9_highbd_12_masked_variance64x64_ssse3,
&vp9_highbd_12_masked_variance64x64_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance64x32_ssse3,
&vp9_highbd_12_masked_variance64x32_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance32x64_ssse3,
&vp9_highbd_12_masked_variance32x64_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance32x32_ssse3,
&vp9_highbd_12_masked_variance32x32_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance32x16_ssse3,
&vp9_highbd_12_masked_variance32x16_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance16x32_ssse3,
&vp9_highbd_12_masked_variance16x32_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance16x16_ssse3,
&vp9_highbd_12_masked_variance16x16_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance16x8_ssse3,
&vp9_highbd_12_masked_variance16x8_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance8x16_ssse3,
&vp9_highbd_12_masked_variance8x16_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance8x8_ssse3,
&vp9_highbd_12_masked_variance8x8_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance8x4_ssse3,
&vp9_highbd_12_masked_variance8x4_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance4x8_ssse3,
&vp9_highbd_12_masked_variance4x8_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_variance4x4_ssse3,
&vp9_highbd_12_masked_variance4x4_c, VPX_BITS_12)));
INSTANTIATE_TEST_CASE_P(
SSSE3_C_COMPARE, HighbdMaskedSubPixelVarianceTest,
::testing::Values(
make_tuple(&vp9_highbd_masked_sub_pixel_variance64x64_ssse3,
&vp9_highbd_masked_sub_pixel_variance64x64_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance64x32_ssse3,
&vp9_highbd_masked_sub_pixel_variance64x32_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance32x64_ssse3,
&vp9_highbd_masked_sub_pixel_variance32x64_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance32x32_ssse3,
&vp9_highbd_masked_sub_pixel_variance32x32_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance32x16_ssse3,
&vp9_highbd_masked_sub_pixel_variance32x16_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance16x32_ssse3,
&vp9_highbd_masked_sub_pixel_variance16x32_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance16x16_ssse3,
&vp9_highbd_masked_sub_pixel_variance16x16_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance16x8_ssse3,
&vp9_highbd_masked_sub_pixel_variance16x8_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance8x16_ssse3,
&vp9_highbd_masked_sub_pixel_variance8x16_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance8x8_ssse3,
&vp9_highbd_masked_sub_pixel_variance8x8_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance8x4_ssse3,
&vp9_highbd_masked_sub_pixel_variance8x4_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance4x8_ssse3,
&vp9_highbd_masked_sub_pixel_variance4x8_c, VPX_BITS_8),
make_tuple(&vp9_highbd_masked_sub_pixel_variance4x4_ssse3,
&vp9_highbd_masked_sub_pixel_variance4x4_c, VPX_BITS_8),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance64x64_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance64x64_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance64x32_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance64x32_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance32x64_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance32x64_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance32x32_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance32x32_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance32x16_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance32x16_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance16x32_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance16x32_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance16x16_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance16x16_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance16x8_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance16x8_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance8x16_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance8x16_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance8x8_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance8x8_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance8x4_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance8x4_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance4x8_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance4x8_c, VPX_BITS_10),
make_tuple(&vp9_highbd_10_masked_sub_pixel_variance4x4_ssse3,
&vp9_highbd_10_masked_sub_pixel_variance4x4_c, VPX_BITS_10),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance64x64_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance64x64_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance64x32_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance64x32_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance32x64_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance32x64_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance32x32_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance32x32_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance32x16_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance32x16_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance16x32_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance16x32_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance16x16_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance16x16_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance16x8_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance16x8_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance8x16_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance8x16_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance8x8_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance8x8_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance8x4_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance8x4_c, VPX_BITS_12) ,
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance4x8_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance4x8_c, VPX_BITS_12),
make_tuple(&vp9_highbd_12_masked_sub_pixel_variance4x4_ssse3,
&vp9_highbd_12_masked_sub_pixel_variance4x4_c, VPX_BITS_12)));
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // HAVE_SSSE3
} // namespace

344
test/quantize_test.cc Normal file
View File

@ -0,0 +1,344 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/register_state_check.h"
#include "test/util.h"
#include "./vpx_config.h"
#include "./vp9_rtcd.h"
#include "vp9/common/vp9_entropy.h"
#include "vpx/vpx_integer.h"
using libvpx_test::ACMRandom;
namespace {
#if CONFIG_VP9_HIGHBITDEPTH
const int number_of_iterations = 100;
typedef void (*QuantizeFunc)(const tran_low_t *coeff, intptr_t count,
int skip_block, const int16_t *zbin,
const int16_t *round, const int16_t *quant,
const int16_t *quant_shift,
tran_low_t *qcoeff, tran_low_t *dqcoeff,
const int16_t *dequant, uint16_t *eob,
const int16_t *scan, const int16_t *iscan);
typedef std::tr1::tuple<QuantizeFunc, QuantizeFunc, int>
QuantizeParam;
class QuantizeTest : public ::testing::TestWithParam<QuantizeParam> {
public:
virtual ~QuantizeTest() {}
virtual void SetUp() {
quantize_op_ = GET_PARAM(0);
ref_quantize_op_ = GET_PARAM(1);
bit_depth_ = GET_PARAM(2);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
int bit_depth_;
int mask_;
QuantizeFunc quantize_op_;
QuantizeFunc ref_quantize_op_;
};
class Quantize32Test : public ::testing::TestWithParam<QuantizeParam> {
public:
virtual ~Quantize32Test() {}
virtual void SetUp() {
quantize_op_ = GET_PARAM(0);
ref_quantize_op_ = GET_PARAM(1);
bit_depth_ = GET_PARAM(2);
mask_ = (1 << bit_depth_) - 1;
}
virtual void TearDown() { libvpx_test::ClearSystemState(); }
protected:
int bit_depth_;
int mask_;
QuantizeFunc quantize_op_;
QuantizeFunc ref_quantize_op_;
};
TEST_P(QuantizeTest, OperationCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, int16_t, zbin_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, round_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, quant_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, quant_shift_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, qcoeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, dqcoeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, ref_qcoeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, ref_dqcoeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, int16_t, dequant_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, uint16_t, eob_ptr, 1);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_eob_ptr, 1);
int err_count_total = 0;
int first_failure = -1;
for (int i = 0; i < number_of_iterations; ++i) {
int skip_block = i == 0;
TX_SIZE sz = (TX_SIZE)(i % 3); // TX_4X4, TX_8X8 TX_16X16
TX_TYPE tx_type = (TX_TYPE)((i >> 2) % 3);
const scan_order *scan_order = &vp9_intra_scan_orders[sz][tx_type];
int count = (4 << sz) * (4 << sz); // 16, 64, 256
int err_count = 0;
*eob_ptr = rnd.Rand16();
*ref_eob_ptr = *eob_ptr;
for (int j = 0; j < count; j++) {
coeff_ptr[j] = rnd.Rand16()&mask_;
}
for (int j = 0; j < 2; j++) {
zbin_ptr[j] = rnd.Rand16()&mask_;
round_ptr[j] = rnd.Rand16();
quant_ptr[j] = rnd.Rand16();
quant_shift_ptr[j] = rnd.Rand16();
dequant_ptr[j] = rnd.Rand16();
}
ref_quantize_op_(coeff_ptr, count, skip_block, zbin_ptr, round_ptr,
quant_ptr, quant_shift_ptr, ref_qcoeff_ptr,
ref_dqcoeff_ptr, dequant_ptr,
ref_eob_ptr, scan_order->scan, scan_order->iscan);
ASM_REGISTER_STATE_CHECK(quantize_op_(coeff_ptr, count, skip_block,
zbin_ptr, round_ptr, quant_ptr,
quant_shift_ptr, qcoeff_ptr,
dqcoeff_ptr, dequant_ptr, eob_ptr,
scan_order->scan, scan_order->iscan));
for (int j = 0; j < sz; ++j) {
err_count += (ref_qcoeff_ptr[j] != qcoeff_ptr[j]) |
(ref_dqcoeff_ptr[j] != dqcoeff_ptr[j]);
}
err_count += (*ref_eob_ptr != *eob_ptr);
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Quantization Test, C output doesn't match SSE2 output. "
<< "First failed at test case " << first_failure;
}
TEST_P(Quantize32Test, OperationCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, int16_t, zbin_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, round_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, quant_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, quant_shift_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, qcoeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, dqcoeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, ref_qcoeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, ref_dqcoeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, int16_t, dequant_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, uint16_t, eob_ptr, 1);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_eob_ptr, 1);
int err_count_total = 0;
int first_failure = -1;
for (int i = 0; i < number_of_iterations; ++i) {
int skip_block = i == 0;
TX_SIZE sz = TX_32X32;
TX_TYPE tx_type = (TX_TYPE)(i % 4);
const scan_order *scan_order = &vp9_intra_scan_orders[sz][tx_type];
int count = (4 << sz) * (4 << sz); // 1024
int err_count = 0;
*eob_ptr = rnd.Rand16();
*ref_eob_ptr = *eob_ptr;
for (int j = 0; j < count; j++) {
coeff_ptr[j] = rnd.Rand16()&mask_;
}
for (int j = 0; j < 2; j++) {
zbin_ptr[j] = rnd.Rand16()&mask_;
round_ptr[j] = rnd.Rand16();
quant_ptr[j] = rnd.Rand16();
quant_shift_ptr[j] = rnd.Rand16();
dequant_ptr[j] = rnd.Rand16();
}
ref_quantize_op_(coeff_ptr, count, skip_block, zbin_ptr, round_ptr,
quant_ptr, quant_shift_ptr, ref_qcoeff_ptr,
ref_dqcoeff_ptr, dequant_ptr,
ref_eob_ptr, scan_order->scan, scan_order->iscan);
ASM_REGISTER_STATE_CHECK(quantize_op_(coeff_ptr, count, skip_block,
zbin_ptr, round_ptr, quant_ptr,
quant_shift_ptr, qcoeff_ptr,
dqcoeff_ptr, dequant_ptr, eob_ptr,
scan_order->scan, scan_order->iscan));
for (int j = 0; j < sz; ++j) {
err_count += (ref_qcoeff_ptr[j] != qcoeff_ptr[j]) |
(ref_dqcoeff_ptr[j] != dqcoeff_ptr[j]);
}
err_count += (*ref_eob_ptr != *eob_ptr);
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Quantization Test, C output doesn't match SSE2 output. "
<< "First failed at test case " << first_failure;
}
TEST_P(QuantizeTest, EOBCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, int16_t, zbin_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, round_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, quant_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, quant_shift_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, qcoeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, dqcoeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, ref_qcoeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, ref_dqcoeff_ptr, 256);
DECLARE_ALIGNED_ARRAY(16, int16_t, dequant_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, uint16_t, eob_ptr, 1);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_eob_ptr, 1);
int err_count_total = 0;
int first_failure = -1;
for (int i = 0; i < number_of_iterations; ++i) {
int skip_block = i == 0;
TX_SIZE sz = (TX_SIZE)(i % 3); // TX_4X4, TX_8X8 TX_16X16
TX_TYPE tx_type = (TX_TYPE)((i >> 2) % 3);
const scan_order *scan_order = &vp9_intra_scan_orders[sz][tx_type];
int count = (4 << sz) * (4 << sz); // 16, 64, 256
int err_count = 0;
*eob_ptr = rnd.Rand16();
*ref_eob_ptr = *eob_ptr;
// Two random entries
for (int j = 0; j < count; j++) {
coeff_ptr[j] = 0;
}
coeff_ptr[rnd(count)] = rnd.Rand16()&mask_;
coeff_ptr[rnd(count)] = rnd.Rand16()&mask_;
for (int j = 0; j < 2; j++) {
zbin_ptr[j] = rnd.Rand16()&mask_;
round_ptr[j] = rnd.Rand16();
quant_ptr[j] = rnd.Rand16();
quant_shift_ptr[j] = rnd.Rand16();
dequant_ptr[j] = rnd.Rand16();
}
ref_quantize_op_(coeff_ptr, count, skip_block, zbin_ptr, round_ptr,
quant_ptr, quant_shift_ptr, ref_qcoeff_ptr,
ref_dqcoeff_ptr, dequant_ptr,
ref_eob_ptr, scan_order->scan, scan_order->iscan);
ASM_REGISTER_STATE_CHECK(quantize_op_(coeff_ptr, count, skip_block,
zbin_ptr, round_ptr, quant_ptr,
quant_shift_ptr, qcoeff_ptr,
dqcoeff_ptr, dequant_ptr, eob_ptr,
scan_order->scan, scan_order->iscan));
for (int j = 0; j < sz; ++j) {
err_count += (ref_qcoeff_ptr[j] != qcoeff_ptr[j]) |
(ref_dqcoeff_ptr[j] != dqcoeff_ptr[j]);
}
err_count += (*ref_eob_ptr != *eob_ptr);
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Quantization Test, C output doesn't match SSE2 output. "
<< "First failed at test case " << first_failure;
}
TEST_P(Quantize32Test, EOBCheck) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, int16_t, zbin_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, round_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, quant_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, int16_t, quant_shift_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, qcoeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, dqcoeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, ref_qcoeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, tran_low_t, ref_dqcoeff_ptr, 1024);
DECLARE_ALIGNED_ARRAY(16, int16_t, dequant_ptr, 2);
DECLARE_ALIGNED_ARRAY(16, uint16_t, eob_ptr, 1);
DECLARE_ALIGNED_ARRAY(16, uint16_t, ref_eob_ptr, 1);
int err_count_total = 0;
int first_failure = -1;
for (int i = 0; i < number_of_iterations; ++i) {
int skip_block = i == 0;
TX_SIZE sz = TX_32X32;
TX_TYPE tx_type = (TX_TYPE)(i % 4);
const scan_order *scan_order = &vp9_intra_scan_orders[sz][tx_type];
int count = (4 << sz) * (4 << sz); // 1024
int err_count = 0;
*eob_ptr = rnd.Rand16();
*ref_eob_ptr = *eob_ptr;
for (int j = 0; j < count; j++) {
coeff_ptr[j] = 0;
}
// Two random entries
coeff_ptr[rnd(count)] = rnd.Rand16()&mask_;
coeff_ptr[rnd(count)] = rnd.Rand16()&mask_;
for (int j = 0; j < 2; j++) {
zbin_ptr[j] = rnd.Rand16()&mask_;
round_ptr[j] = rnd.Rand16();
quant_ptr[j] = rnd.Rand16();
quant_shift_ptr[j] = rnd.Rand16();
dequant_ptr[j] = rnd.Rand16();
}
ref_quantize_op_(coeff_ptr, count, skip_block, zbin_ptr, round_ptr,
quant_ptr, quant_shift_ptr, ref_qcoeff_ptr,
ref_dqcoeff_ptr, dequant_ptr,
ref_eob_ptr, scan_order->scan, scan_order->iscan);
ASM_REGISTER_STATE_CHECK(quantize_op_(coeff_ptr, count, skip_block,
zbin_ptr, round_ptr, quant_ptr,
quant_shift_ptr, qcoeff_ptr,
dqcoeff_ptr, dequant_ptr, eob_ptr,
scan_order->scan, scan_order->iscan));
for (int j = 0; j < sz; ++j) {
err_count += (ref_qcoeff_ptr[j] != qcoeff_ptr[j]) |
(ref_dqcoeff_ptr[j] != dqcoeff_ptr[j]);
}
err_count += (*ref_eob_ptr != *eob_ptr);
if (err_count && !err_count_total) {
first_failure = i;
}
err_count_total += err_count;
}
EXPECT_EQ(0, err_count_total)
<< "Error: Quantization Test, C output doesn't match SSE2 output. "
<< "First failed at test case " << first_failure;
}
using std::tr1::make_tuple;
#if HAVE_SSE2
INSTANTIATE_TEST_CASE_P(
SSE2_C_COMPARE, QuantizeTest,
::testing::Values(
make_tuple(&vp9_highbd_quantize_b_sse2,
&vp9_highbd_quantize_b_c, 8),
make_tuple(&vp9_highbd_quantize_b_sse2,
&vp9_highbd_quantize_b_c, 10),
make_tuple(&vp9_highbd_quantize_b_sse2,
&vp9_highbd_quantize_b_c, 12)));
INSTANTIATE_TEST_CASE_P(
SSE2_C_COMPARE, Quantize32Test,
::testing::Values(
make_tuple(&vp9_highbd_quantize_b_32x32_sse2,
&vp9_highbd_quantize_b_32x32_c, 8),
make_tuple(&vp9_highbd_quantize_b_32x32_sse2,
&vp9_highbd_quantize_b_32x32_c, 10),
make_tuple(&vp9_highbd_quantize_b_32x32_sse2,
&vp9_highbd_quantize_b_32x32_c, 12)));
#endif // HAVE_SSE2
#endif // CONFIG_VP9_HIGHBITDEPTH
} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -1,740 +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 <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/i420_video_source.h"
#include "vp9/decoder/vp9_decoder.h"
#include "vpx/svc_context.h"
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
namespace {
using libvpx_test::CodecFactory;
using libvpx_test::Decoder;
using libvpx_test::DxDataIterator;
using libvpx_test::VP9CodecFactory;
class SvcTest : public ::testing::Test {
protected:
static const uint32_t kWidth = 352;
static const uint32_t kHeight = 288;
SvcTest()
: codec_iface_(0),
test_file_name_("hantro_collage_w352h288.yuv"),
codec_initialized_(false),
decoder_(0) {
memset(&svc_, 0, sizeof(svc_));
memset(&codec_, 0, sizeof(codec_));
memset(&codec_enc_, 0, sizeof(codec_enc_));
}
virtual ~SvcTest() {}
virtual void SetUp() {
svc_.log_level = SVC_LOG_DEBUG;
svc_.log_print = 0;
codec_iface_ = vpx_codec_vp9_cx();
const vpx_codec_err_t res =
vpx_codec_enc_config_default(codec_iface_, &codec_enc_, 0);
EXPECT_EQ(VPX_CODEC_OK, res);
codec_enc_.g_w = kWidth;
codec_enc_.g_h = kHeight;
codec_enc_.g_timebase.num = 1;
codec_enc_.g_timebase.den = 60;
codec_enc_.kf_min_dist = 100;
codec_enc_.kf_max_dist = 100;
vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t();
VP9CodecFactory codec_factory;
decoder_ = codec_factory.CreateDecoder(dec_cfg, 0);
}
virtual void TearDown() {
ReleaseEncoder();
delete(decoder_);
}
void InitializeEncoder() {
const vpx_codec_err_t res =
vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
vpx_codec_control(&codec_, VP8E_SET_CPUUSED, 4); // Make the test faster
codec_initialized_ = true;
}
void ReleaseEncoder() {
vpx_svc_release(&svc_);
if (codec_initialized_) vpx_codec_destroy(&codec_);
codec_initialized_ = false;
}
void GetStatsData(std::string *const stats_buf) {
vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *cx_pkt;
while ((cx_pkt = vpx_codec_get_cx_data(&codec_, &iter)) != NULL) {
if (cx_pkt->kind == VPX_CODEC_STATS_PKT) {
EXPECT_GT(cx_pkt->data.twopass_stats.sz, 0U);
ASSERT_TRUE(cx_pkt->data.twopass_stats.buf != NULL);
stats_buf->append(static_cast<char*>(cx_pkt->data.twopass_stats.buf),
cx_pkt->data.twopass_stats.sz);
}
}
}
void Pass1EncodeNFrames(const int n, const int layers,
std::string *const stats_buf) {
vpx_codec_err_t res;
ASSERT_GT(n, 0);
ASSERT_GT(layers, 0);
svc_.spatial_layers = layers;
codec_enc_.g_pass = VPX_RC_FIRST_PASS;
InitializeEncoder();
libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
codec_enc_.g_timebase.den,
codec_enc_.g_timebase.num, 0, 30);
video.Begin();
for (int i = 0; i < n; ++i) {
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_GOOD_QUALITY);
ASSERT_EQ(VPX_CODEC_OK, res);
GetStatsData(stats_buf);
video.Next();
}
// Flush encoder and test EOS packet.
res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(),
video.duration(), VPX_DL_GOOD_QUALITY);
ASSERT_EQ(VPX_CODEC_OK, res);
GetStatsData(stats_buf);
ReleaseEncoder();
}
void StoreFrames(const size_t max_frame_received,
struct vpx_fixed_buf *const outputs,
size_t *const frame_received) {
vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *cx_pkt;
while ((cx_pkt = vpx_codec_get_cx_data(&codec_, &iter)) != NULL) {
if (cx_pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
const size_t frame_size = cx_pkt->data.frame.sz;
EXPECT_GT(frame_size, 0U);
ASSERT_TRUE(cx_pkt->data.frame.buf != NULL);
ASSERT_LT(*frame_received, max_frame_received);
if (*frame_received == 0)
EXPECT_EQ(1, !!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY));
outputs[*frame_received].buf = malloc(frame_size + 16);
ASSERT_TRUE(outputs[*frame_received].buf != NULL);
memcpy(outputs[*frame_received].buf, cx_pkt->data.frame.buf,
frame_size);
outputs[*frame_received].sz = frame_size;
++(*frame_received);
}
}
}
void Pass2EncodeNFrames(std::string *const stats_buf,
const int n, const int layers,
struct vpx_fixed_buf *const outputs) {
vpx_codec_err_t res;
size_t frame_received = 0;
ASSERT_TRUE(outputs != NULL);
ASSERT_GT(n, 0);
ASSERT_GT(layers, 0);
svc_.spatial_layers = layers;
codec_enc_.rc_target_bitrate = 500;
if (codec_enc_.g_pass == VPX_RC_LAST_PASS) {
ASSERT_TRUE(stats_buf != NULL);
ASSERT_GT(stats_buf->size(), 0U);
codec_enc_.rc_twopass_stats_in.buf = &(*stats_buf)[0];
codec_enc_.rc_twopass_stats_in.sz = stats_buf->size();
}
InitializeEncoder();
libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
codec_enc_.g_timebase.den,
codec_enc_.g_timebase.num, 0, 30);
video.Begin();
for (int i = 0; i < n; ++i) {
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_GOOD_QUALITY);
ASSERT_EQ(VPX_CODEC_OK, res);
StoreFrames(n, outputs, &frame_received);
video.Next();
}
// Flush encoder.
res = vpx_svc_encode(&svc_, &codec_, NULL, 0,
video.duration(), VPX_DL_GOOD_QUALITY);
EXPECT_EQ(VPX_CODEC_OK, res);
StoreFrames(n, outputs, &frame_received);
EXPECT_EQ(frame_received, static_cast<size_t>(n));
ReleaseEncoder();
}
void DecodeNFrames(const struct vpx_fixed_buf *const inputs, const int n) {
int decoded_frames = 0;
int received_frames = 0;
ASSERT_TRUE(inputs != NULL);
ASSERT_GT(n, 0);
for (int i = 0; i < n; ++i) {
ASSERT_TRUE(inputs[i].buf != NULL);
ASSERT_GT(inputs[i].sz, 0U);
const vpx_codec_err_t res_dec =
decoder_->DecodeFrame(static_cast<const uint8_t *>(inputs[i].buf),
inputs[i].sz);
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
++decoded_frames;
DxDataIterator dec_iter = decoder_->GetDxData();
while (dec_iter.Next() != NULL) {
++received_frames;
}
}
EXPECT_EQ(decoded_frames, n);
EXPECT_EQ(received_frames, n);
}
void DropEnhancementLayers(struct vpx_fixed_buf *const inputs,
const int num_super_frames,
const int remained_spatial_layers) {
ASSERT_TRUE(inputs != NULL);
ASSERT_GT(num_super_frames, 0);
ASSERT_GT(remained_spatial_layers, 0);
for (int i = 0; i < num_super_frames; ++i) {
uint32_t frame_sizes[8] = {0};
int frame_count = 0;
int frames_found = 0;
int frame;
ASSERT_TRUE(inputs[i].buf != NULL);
ASSERT_GT(inputs[i].sz, 0U);
vpx_codec_err_t res =
vp9_parse_superframe_index(static_cast<const uint8_t*>(inputs[i].buf),
inputs[i].sz, frame_sizes, &frame_count,
NULL, NULL);
ASSERT_EQ(VPX_CODEC_OK, res);
if (frame_count == 0) {
// There's no super frame but only a single frame.
ASSERT_EQ(1, remained_spatial_layers);
} else {
// Found a super frame.
uint8_t *frame_data = static_cast<uint8_t*>(inputs[i].buf);
uint8_t *frame_start = frame_data;
for (frame = 0; frame < frame_count; ++frame) {
// Looking for a visible frame.
if (frame_data[0] & 0x02) {
++frames_found;
if (frames_found == remained_spatial_layers)
break;
}
frame_data += frame_sizes[frame];
}
ASSERT_LT(frame, frame_count) << "Couldn't find a visible frame. "
<< "remained_spatial_layers: " << remained_spatial_layers
<< " super_frame: " << i;
if (frame == frame_count - 1)
continue;
frame_data += frame_sizes[frame];
// We need to add one more frame for multiple frame contexts.
uint8_t marker =
static_cast<const uint8_t*>(inputs[i].buf)[inputs[i].sz - 1];
const uint32_t mag = ((marker >> 3) & 0x3) + 1;
const size_t index_sz = 2 + mag * frame_count;
const size_t new_index_sz = 2 + mag * (frame + 1);
marker &= 0x0f8;
marker |= frame;
// Copy existing frame sizes.
memmove(frame_data + 1, frame_start + inputs[i].sz - index_sz + 1,
new_index_sz - 2);
// New marker.
frame_data[0] = marker;
frame_data += (mag * (frame + 1) + 1);
*frame_data++ = marker;
inputs[i].sz = frame_data - frame_start;
}
}
}
void FreeBitstreamBuffers(struct vpx_fixed_buf *const inputs, const int n) {
ASSERT_TRUE(inputs != NULL);
ASSERT_GT(n, 0);
for (int i = 0; i < n; ++i) {
free(inputs[i].buf);
inputs[i].buf = NULL;
inputs[i].sz = 0;
}
}
SvcContext svc_;
vpx_codec_ctx_t codec_;
struct vpx_codec_enc_cfg codec_enc_;
vpx_codec_iface_t *codec_iface_;
std::string test_file_name_;
bool codec_initialized_;
Decoder *decoder_;
};
TEST_F(SvcTest, SvcInit) {
// test missing parameters
vpx_codec_err_t res = vpx_svc_init(NULL, &codec_, codec_iface_, &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_init(&svc_, NULL, codec_iface_, &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_init(&svc_, &codec_, NULL, &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_init(&svc_, &codec_, codec_iface_, NULL);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
svc_.spatial_layers = 6; // too many layers
res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
svc_.spatial_layers = 0; // use default layers
InitializeEncoder();
EXPECT_EQ(VPX_SS_DEFAULT_LAYERS, svc_.spatial_layers);
}
TEST_F(SvcTest, InitTwoLayers) {
svc_.spatial_layers = 2;
InitializeEncoder();
}
TEST_F(SvcTest, InvalidOptions) {
vpx_codec_err_t res = vpx_svc_set_options(&svc_, NULL);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "not-an-option=1");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
}
TEST_F(SvcTest, SetLayersOption) {
vpx_codec_err_t res = vpx_svc_set_options(&svc_, "spatial-layers=3");
EXPECT_EQ(VPX_CODEC_OK, res);
InitializeEncoder();
EXPECT_EQ(3, svc_.spatial_layers);
}
TEST_F(SvcTest, SetMultipleOptions) {
vpx_codec_err_t res =
vpx_svc_set_options(&svc_, "spatial-layers=2 scale-factors=1/3,2/3");
EXPECT_EQ(VPX_CODEC_OK, res);
InitializeEncoder();
EXPECT_EQ(2, svc_.spatial_layers);
}
TEST_F(SvcTest, SetScaleFactorsOption) {
svc_.spatial_layers = 2;
vpx_codec_err_t res =
vpx_svc_set_options(&svc_, "scale-factors=not-scale-factors");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "scale-factors=1/3, 3*3");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "scale-factors=1/3");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3");
EXPECT_EQ(VPX_CODEC_OK, res);
InitializeEncoder();
}
TEST_F(SvcTest, SetQuantizersOption) {
svc_.spatial_layers = 2;
vpx_codec_err_t res = vpx_svc_set_options(&svc_, "max-quantizers=nothing");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "min-quantizers=nothing");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "max-quantizers=40");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "min-quantizers=40");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "max-quantizers=30,30 min-quantizers=40,40");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "max-quantizers=40,40 min-quantizers=30,30");
InitializeEncoder();
}
TEST_F(SvcTest, SetAutoAltRefOption) {
svc_.spatial_layers = 5;
vpx_codec_err_t res = vpx_svc_set_options(&svc_, "auto-alt-refs=none");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1,1,0");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0");
InitializeEncoder();
}
// Test that decoder can handle an SVC frame as the first frame in a sequence.
TEST_F(SvcTest, OnePassEncodeOneFrame) {
codec_enc_.g_pass = VPX_RC_ONE_PASS;
vpx_fixed_buf output = {0};
Pass2EncodeNFrames(NULL, 1, 2, &output);
DecodeNFrames(&output, 1);
FreeBitstreamBuffers(&output, 1);
}
TEST_F(SvcTest, OnePassEncodeThreeFrames) {
codec_enc_.g_pass = VPX_RC_ONE_PASS;
vpx_fixed_buf outputs[3];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(NULL, 3, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 3);
FreeBitstreamBuffers(&outputs[0], 3);
}
TEST_F(SvcTest, TwoPassEncode10Frames) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode20FramesWithAltRef) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(20, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
vpx_svc_set_options(&svc_, "auto-alt-refs=1,1");
vpx_fixed_buf outputs[20];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 20);
FreeBitstreamBuffers(&outputs[0], 20);
}
TEST_F(SvcTest, TwoPassEncode2SpatialLayersDecodeBaseLayerOnly) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
vpx_svc_set_options(&svc_, "auto-alt-refs=1,1");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DropEnhancementLayers(&outputs[0], 10, 1);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode5SpatialLayersDecode54321Layers) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 5, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 5, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 4);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 3);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 2);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 1);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2SNRLayers) {
// First pass encode
std::string stats_buf;
vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1");
Pass1EncodeNFrames(20, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
vpx_svc_set_options(&svc_,
"auto-alt-refs=1,1 scale-factors=1/1,1/1");
vpx_fixed_buf outputs[20];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 20);
FreeBitstreamBuffers(&outputs[0], 20);
}
TEST_F(SvcTest, TwoPassEncode3SNRLayersDecode321Layers) {
// First pass encode
std::string stats_buf;
vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1");
Pass1EncodeNFrames(20, 3, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
vpx_svc_set_options(&svc_,
"auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1");
vpx_fixed_buf outputs[20];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 20, 3, &outputs[0]);
DecodeNFrames(&outputs[0], 20);
DropEnhancementLayers(&outputs[0], 20, 2);
DecodeNFrames(&outputs[0], 20);
DropEnhancementLayers(&outputs[0], 20, 1);
DecodeNFrames(&outputs[0], 20);
FreeBitstreamBuffers(&outputs[0], 20);
}
TEST_F(SvcTest, SetMultipleFrameContextsOption) {
svc_.spatial_layers = 5;
vpx_codec_err_t res =
vpx_svc_set_options(&svc_, "multi-frame-contexts=1");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
svc_.spatial_layers = 2;
res = vpx_svc_set_options(&svc_, "multi-frame-contexts=1");
InitializeEncoder();
}
TEST_F(SvcTest, TwoPassEncode2SpatialLayersWithMultipleFrameContexts) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
codec_enc_.g_error_resilient = 0;
vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest,
TwoPassEncode2SpatialLayersWithMultipleFrameContextsDecodeBaselayer) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
codec_enc_.g_error_resilient = 0;
vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DropEnhancementLayers(&outputs[0], 10, 1);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2SNRLayersWithMultipleFrameContexts) {
// First pass encode
std::string stats_buf;
vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1");
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
codec_enc_.g_error_resilient = 0;
vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 scale-factors=1/1,1/1 "
"multi-frame-contexts=1");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest,
TwoPassEncode3SNRLayersWithMultipleFrameContextsDecode321Layer) {
// First pass encode
std::string stats_buf;
vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1");
Pass1EncodeNFrames(10, 3, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
codec_enc_.g_error_resilient = 0;
vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1 "
"multi-frame-contexts=1");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 3, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 2);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 1);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2TemporalLayers) {
// First pass encode
std::string stats_buf;
vpx_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
svc_.temporal_layers = 2;
vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2TemporalLayersWithMultipleFrameContexts) {
// First pass encode
std::string stats_buf;
vpx_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
svc_.temporal_layers = 2;
codec_enc_.g_error_resilient = 0;
vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1 "
"multi-frame-contexts=1");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2TemporalLayersDecodeBaseLayer) {
// First pass encode
std::string stats_buf;
vpx_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
svc_.temporal_layers = 2;
vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
vpx_fixed_buf base_layer[5];
for (int i = 0; i < 5; ++i)
base_layer[i] = outputs[i * 2];
DecodeNFrames(&base_layer[0], 5);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest,
TwoPassEncode2TemporalLayersWithMultipleFrameContextsDecodeBaseLayer) {
// First pass encode
std::string stats_buf;
vpx_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = VPX_RC_LAST_PASS;
svc_.temporal_layers = 2;
codec_enc_.g_error_resilient = 0;
vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1 "
"multi-frame-contexts=1");
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
vpx_fixed_buf base_layer[5];
for (int i = 0; i < 5; ++i)
base_layer[i] = outputs[i * 2];
DecodeNFrames(&base_layer[0], 5);
FreeBitstreamBuffers(&outputs[0], 10);
}
} // namespace

View File

@ -51,10 +51,10 @@ LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += y4m_test.cc ../y4menc.c ../y4menc.h
## WebM Parsing
ifeq ($(CONFIG_WEBM_IO), yes)
LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser.cpp
LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvreader.cpp
LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser.hpp
LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvreader.hpp
LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvparser.cc
LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvreader.cc
LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvparser.h
LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvreader.h
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += $(LIBWEBM_PARSER_SRCS)
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ../tools_common.h
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ../webmdec.cc
@ -86,7 +86,7 @@ endif
ifeq ($(CONFIG_SHARED),)
## VP8
ifneq ($(CONFIG_VP8_ENCODER)$(CONFIG_VP8_DECODER),)
ifeq ($(CONFIG_VP8),yes)
# These tests require both the encoder and decoder to be built.
ifeq ($(CONFIG_VP8_ENCODER)$(CONFIG_VP8_DECODER),yesyes)
@ -112,7 +112,7 @@ endif
endif # VP8
## VP9
ifneq ($(CONFIG_VP9_ENCODER)$(CONFIG_VP9_DECODER),)
ifeq ($(CONFIG_VP9),yes)
# These tests require both the encoder and decoder to be built.
ifeq ($(CONFIG_VP9_ENCODER)$(CONFIG_VP9_DECODER),yesyes)
@ -136,16 +136,22 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += variance_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_subtract_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += lpf_8_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_avg_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += quantize_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += error_block_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9) += vp9_intrapred_test.cc
ifeq ($(CONFIG_VP9_ENCODER),yes)
LIBVPX_TEST_SRCS-$(CONFIG_SPATIAL_SVC) += svc_test.cc
endif
ifeq ($(CONFIG_VP9_ENCODER)$(CONFIG_VP9_TEMPORAL_DENOISING),yesyes)
LIBVPX_TEST_SRCS-$(HAVE_SSE2) += vp9_denoiser_sse2_test.cc
endif
ifeq ($(CONFIG_VP9)$(CONFIG_WEDGE_PARTITION),yesyes)
LIBVPX_TEST_SRCS-$(HAVE_SSSE3) += masked_variance_test.cc
endif
ifeq ($(CONFIG_VP9)$(CONFIG_WEDGE_PARTITION),yesyes)
LIBVPX_TEST_SRCS-$(HAVE_SSSE3) += masked_sad_test.cc
endif
endif # VP9
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += sad_test.cc

View File

@ -97,13 +97,18 @@ TEST_P(TestVectorTest, MD5Match) {
delete video;
}
#if CONFIG_VP8_DECODER
VP8_INSTANTIATE_TEST_CASE(TestVectorTest,
::testing::ValuesIn(libvpx_test::kVP8TestVectors,
libvpx_test::kVP8TestVectors +
libvpx_test::kNumVP8TestVectors));
#endif // CONFIG_VP8_DECODER
#if CONFIG_VP9_DECODER
VP9_INSTANTIATE_TEST_CASE(TestVectorTest,
::testing::ValuesIn(libvpx_test::kVP9TestVectors,
libvpx_test::kVP9TestVectors +
libvpx_test::kNumVP9TestVectors));
#endif // CONFIG_VP9_DECODER
} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ const unsigned int kHeight = 90;
const unsigned int kFramerate = 50;
const unsigned int kFrames = 10;
const int kBitrate = 500;
const int kCpuUsed = 2;
const int kCpuUsed = 0;
const double psnr_threshold = 35.0;
typedef struct {

View File

@ -1,72 +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 file tests the libvpx vp9_spatial_svc_encoder example. To add new
## tests to to this file, do the following:
## 1. Write a shell function (this is your test).
## 2. Add the function to vp9_spatial_svc_tests (on a new line).
##
. $(dirname $0)/tools_common.sh
# Environment check: $YUV_RAW_INPUT is required.
vp9_spatial_svc_encoder_verify_environment() {
if [ ! -e "${YUV_RAW_INPUT}" ]; then
echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
return 1
fi
}
# Runs vp9_spatial_svc_encoder. $1 is the test name.
vp9_spatial_svc_encoder() {
local readonly \
encoder="${LIBVPX_BIN_PATH}/vp9_spatial_svc_encoder${VPX_TEST_EXE_SUFFIX}"
local readonly test_name="$1"
local readonly \
output_file="${VPX_TEST_OUTPUT_DIR}/vp9_ssvc_encoder${test_name}.ivf"
local readonly frames_to_encode=10
local readonly max_kf=9999
shift
if [ ! -x "${encoder}" ]; then
elog "${encoder} does not exist or is not executable."
return 1
fi
eval "${VPX_TEST_PREFIX}" "${encoder}" -w "${YUV_RAW_INPUT_WIDTH}" \
-h "${YUV_RAW_INPUT_HEIGHT}" -k "${max_kf}" -f "${frames_to_encode}" \
"$@" "${YUV_RAW_INPUT}" "${output_file}" ${devnull}
[ -e "${output_file}" ] || return 1
}
# Each test is run with layer count 1-$vp9_ssvc_test_layers.
vp9_ssvc_test_layers=5
vp9_spatial_svc() {
if [ "$(vp9_encode_available)" = "yes" ]; then
local readonly test_name="vp9_spatial_svc"
for layers in $(seq 1 ${vp9_ssvc_test_layers}); do
vp9_spatial_svc_encoder "${test_name}" -l ${layers}
done
fi
}
readonly vp9_spatial_svc_tests="DISABLED_vp9_spatial_svc_mode_i
DISABLED_vp9_spatial_svc_mode_altip
DISABLED_vp9_spatial_svc_mode_ip
DISABLED_vp9_spatial_svc_mode_gf
vp9_spatial_svc"
if [ "$(vpx_config_option_enabled CONFIG_SPATIAL_SVC)" = "yes" ]; then
run_tests \
vp9_spatial_svc_encoder_verify_environment \
"${vp9_spatial_svc_tests}"
fi

View File

@ -1,290 +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 file tests the libvpx vpx_temporal_svc_encoder example. To add new
## tests to this file, do the following:
## 1. Write a shell function (this is your test).
## 2. Add the function to vpx_tsvc_encoder_tests (on a new line).
##
. $(dirname $0)/tools_common.sh
# Environment check: $YUV_RAW_INPUT is required.
vpx_tsvc_encoder_verify_environment() {
if [ ! -e "${YUV_RAW_INPUT}" ]; then
echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
return 1
fi
if [ "$(vpx_config_option_enabled CONFIG_TEMPORAL_DENOISING)" != "yes" ]; then
elog "Warning: Temporal denoising is disabled! Spatial denoising will be " \
"used instead, which is probably not what you want for this test."
fi
}
# Runs vpx_temporal_svc_encoder using the codec specified by $1 and output file
# name by $2. Additional positional parameters are passed directly to
# vpx_temporal_svc_encoder.
vpx_tsvc_encoder() {
local encoder="${LIBVPX_BIN_PATH}/vpx_temporal_svc_encoder"
encoder="${encoder}${VPX_TEST_EXE_SUFFIX}"
local codec="$1"
local output_file_base="$2"
local output_file="${VPX_TEST_OUTPUT_DIR}/${output_file_base}"
local timebase_num="1"
local timebase_den="1000"
local speed="6"
local frame_drop_thresh="30"
shift 2
if [ ! -x "${encoder}" ]; then
elog "${encoder} does not exist or is not executable."
return 1
fi
eval "${VPX_TEST_PREFIX}" "${encoder}" "${YUV_RAW_INPUT}" "${output_file}" \
"${codec}" "${YUV_RAW_INPUT_WIDTH}" "${YUV_RAW_INPUT_HEIGHT}" \
"${timebase_num}" "${timebase_den}" "${speed}" "${frame_drop_thresh}" \
"$@" \
${devnull}
}
# Confirms that all expected output files exist given the output file name
# passed to vpx_temporal_svc_encoder.
# The file name passed to vpx_temporal_svc_encoder is joined with the stream
# number and the extension .ivf to produce per stream output files. Here $1 is
# file name, and $2 is expected number of files.
files_exist() {
local file_name="${VPX_TEST_OUTPUT_DIR}/$1"
local num_files="$(($2 - 1))"
for stream_num in $(seq 0 ${num_files}); do
[ -e "${file_name}_${stream_num}.ivf" ] || return 1
done
}
# Run vpx_temporal_svc_encoder in all supported modes for vp8 and vp9.
vpx_tsvc_encoder_vp8_mode_0() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 0 200 || return 1
# Mode 0 produces 1 stream
files_exist "${FUNCNAME}" 1 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_1() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 1 200 400 || return 1
# Mode 1 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_2() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 2 200 400 || return 1
# Mode 2 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_3() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 3 200 400 600 || return 1
# Mode 3 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_4() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 4 200 400 600 || return 1
# Mode 4 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_5() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 5 200 400 600 || return 1
# Mode 5 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_6() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 6 200 400 600 || return 1
# Mode 6 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_7() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 7 200 400 600 800 1000 || return 1
# Mode 7 produces 5 streams
files_exist "${FUNCNAME}" 5 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_8() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 8 200 400 || return 1
# Mode 8 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_9() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 9 200 400 600 || return 1
# Mode 9 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_10() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 10 200 400 600 || return 1
# Mode 10 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp8_mode_11() {
if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp8 "${FUNCNAME}" 11 200 400 600 || return 1
# Mode 11 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_0() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 0 200 || return 1
# Mode 0 produces 1 stream
files_exist "${FUNCNAME}" 1 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_1() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 1 200 400 || return 1
# Mode 1 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_2() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 2 200 400 || return 1
# Mode 2 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_3() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 3 200 400 600 || return 1
# Mode 3 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_4() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 4 200 400 600 || return 1
# Mode 4 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_5() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 5 200 400 600 || return 1
# Mode 5 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_6() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 6 200 400 600 || return 1
# Mode 6 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_7() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 7 200 400 600 800 1000 || return 1
# Mode 7 produces 5 streams
files_exist "${FUNCNAME}" 5 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_8() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 8 200 400 || return 1
# Mode 8 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_9() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 9 200 400 600 || return 1
# Mode 9 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_10() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 10 200 400 600 || return 1
# Mode 10 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_vp9_mode_11() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_tsvc_encoder vp9 "${FUNCNAME}" 11 200 400 600 || return 1
# Mode 11 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
vpx_tsvc_encoder_tests="vpx_tsvc_encoder_vp8_mode_0
vpx_tsvc_encoder_vp8_mode_1
vpx_tsvc_encoder_vp8_mode_2
vpx_tsvc_encoder_vp8_mode_3
vpx_tsvc_encoder_vp8_mode_4
vpx_tsvc_encoder_vp8_mode_5
vpx_tsvc_encoder_vp8_mode_6
vpx_tsvc_encoder_vp8_mode_7
vpx_tsvc_encoder_vp8_mode_8
vpx_tsvc_encoder_vp8_mode_9
vpx_tsvc_encoder_vp8_mode_10
vpx_tsvc_encoder_vp8_mode_11
vpx_tsvc_encoder_vp9_mode_0
vpx_tsvc_encoder_vp9_mode_1
vpx_tsvc_encoder_vp9_mode_2
vpx_tsvc_encoder_vp9_mode_3
vpx_tsvc_encoder_vp9_mode_4
vpx_tsvc_encoder_vp9_mode_5
vpx_tsvc_encoder_vp9_mode_6
vpx_tsvc_encoder_vp9_mode_7
vpx_tsvc_encoder_vp9_mode_8
vpx_tsvc_encoder_vp9_mode_9
vpx_tsvc_encoder_vp9_mode_10
vpx_tsvc_encoder_vp9_mode_11"
run_tests vpx_tsvc_encoder_verify_environment "${vpx_tsvc_encoder_tests}"

View File

@ -1,11 +1,17 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PATH:= $(call my-dir)
LOCAL_CPP_EXTENSION := .cpp
LOCAL_SRC_FILES := mkvmuxer.cpp \
mkvmuxerutil.cpp \
mkvparser.cpp \
mkvreader.cpp \
mkvwriter.cpp
LOCAL_MODULE := libwebm
include $(CLEAR_VARS)
LOCAL_MODULE:= libwebm
LOCAL_CPPFLAGS:=-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
LOCAL_CPPFLAGS+=-D__STDC_LIMIT_MACROS -Wno-extern-c-compat
LOCAL_C_INCLUDES:= $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)
LOCAL_SRC_FILES:= common/file_util.cc \
common/hdr_util.cc \
mkvparser/mkvparser.cc \
mkvparser/mkvreader.cc \
mkvmuxer/mkvmuxer.cc \
mkvmuxer/mkvmuxerutil.cc \
mkvmuxer/mkvwriter.cc
include $(BUILD_STATIC_LIBRARY)

View File

@ -17,7 +17,7 @@ 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
constitutes direct or contributory patent infringement, or inducement of
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.

View File

@ -1,7 +1,10 @@
URL: https://chromium.googlesource.com/webm/libwebm
Version: 249629d46c6e9391f25a90cff6d19075f47474cb
Version: 32d5ac49414a8914ec1e1f285f3f927c6e8ec29d
License: BSD
License File: LICENSE.txt
Description:
libwebm is used to handle WebM container I/O.
Local Changes:
* <none>

View File

@ -1,34 +0,0 @@
1.0.0.5
* Handled case when no duration
* Handled empty clusters
* Handled empty clusters when seeking
* Implemented check lacing bits
1.0.0.4
* Made Cues member variables mutables
* Defined against badly-formatted cue points
* Segment::GetCluster returns CuePoint too
* Separated cue-based searches
1.0.0.3
* Added Block::GetOffset() to get a frame's offset in a block
* Changed cluster count type from size_t to long
* Parsed SeekHead to find cues
* Allowed seeking beyond end of cluster cache
* Added not to attempt to reparse cues element
* Restructured Segment::LoadCluster
* Marked position of cues without parsing cues element
* Allowed cue points to be loaded incrementally
* Implemented to load lazily cue points as they're searched
* Merged Cues::LoadCuePoint into Cues::Find
* Lazy init cues
* Loaded cue point during find
1.0.0.2
* added support for Cues element
* seeking was improved
1.0.0.1
* fixed item 141
* added item 142
* added this file, RELEASE.TXT, to repository

67
third_party/libwebm/common/file_util.cc vendored Normal file
View File

@ -0,0 +1,67 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "common/file_util.h"
#include <sys/stat.h>
#ifndef _MSC_VER
#include <unistd.h> // close()
#endif
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <ios>
namespace libwebm {
std::string GetTempFileName() {
#if !defined _MSC_VER && !defined __MINGW32__
char temp_file_name_template[] = "libwebm_temp.XXXXXX";
int fd = mkstemp(temp_file_name_template);
if (fd != -1) {
close(fd);
return std::string(temp_file_name_template);
}
return std::string();
#else
char tmp_file_name[_MAX_PATH];
errno_t err = tmpnam_s(tmp_file_name);
if (err == 0) {
return std::string(tmp_file_name);
}
return std::string();
#endif
}
uint64_t GetFileSize(const std::string& file_name) {
uint64_t file_size = 0;
#ifndef _MSC_VER
struct stat st;
st.st_size = 0;
if (stat(file_name.c_str(), &st) == 0) {
#else
struct _stat st;
st.st_size = 0;
if (_stat(file_name.c_str(), &st) == 0) {
#endif
file_size = st.st_size;
}
return file_size;
}
TempFileDeleter::TempFileDeleter() { file_name_ = GetTempFileName(); }
TempFileDeleter::~TempFileDeleter() {
std::ifstream file(file_name_.c_str());
if (file.good()) {
file.close();
std::remove(file_name_.c_str());
}
}
} // namespace libwebm

41
third_party/libwebm/common/file_util.h vendored Normal file
View File

@ -0,0 +1,41 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#ifndef LIBWEBM_COMMON_FILE_UTIL_H_
#define LIBWEBM_COMMON_FILE_UTIL_H_
#include <stdint.h>
#include <string>
#include "mkvmuxer/mkvmuxertypes.h" // LIBWEBM_DISALLOW_COPY_AND_ASSIGN()
namespace libwebm {
// Returns a temporary file name.
std::string GetTempFileName();
// Returns size of file specified by |file_name|, or 0 upon failure.
uint64_t GetFileSize(const std::string& file_name);
// Manages life of temporary file specified at time of construction. Deletes
// file upon destruction.
class TempFileDeleter {
public:
TempFileDeleter();
explicit TempFileDeleter(std::string file_name) : file_name_(file_name) {}
~TempFileDeleter();
const std::string& name() const { return file_name_; }
private:
std::string file_name_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TempFileDeleter);
};
} // namespace libwebm
#endif // LIBWEBM_COMMON_FILE_UTIL_H_

182
third_party/libwebm/common/hdr_util.cc vendored Normal file
View File

@ -0,0 +1,182 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "hdr_util.h"
#include <cstddef>
#include <new>
#include "mkvparser/mkvparser.h"
namespace libwebm {
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
PrimaryChromaticityPtr* muxer_pc) {
muxer_pc->reset(new (std::nothrow)
mkvmuxer::PrimaryChromaticity(parser_pc.x, parser_pc.y));
if (!muxer_pc->get())
return false;
return true;
}
bool MasteringMetadataValuePresent(double value) {
return value != mkvparser::MasteringMetadata::kValueNotPresent;
}
bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm,
mkvmuxer::MasteringMetadata* muxer_mm) {
if (MasteringMetadataValuePresent(parser_mm.luminance_max))
muxer_mm->luminance_max = parser_mm.luminance_max;
if (MasteringMetadataValuePresent(parser_mm.luminance_min))
muxer_mm->luminance_min = parser_mm.luminance_min;
PrimaryChromaticityPtr r_ptr(NULL);
PrimaryChromaticityPtr g_ptr(NULL);
PrimaryChromaticityPtr b_ptr(NULL);
PrimaryChromaticityPtr wp_ptr(NULL);
if (parser_mm.r) {
if (!CopyPrimaryChromaticity(*parser_mm.r, &r_ptr))
return false;
}
if (parser_mm.g) {
if (!CopyPrimaryChromaticity(*parser_mm.g, &g_ptr))
return false;
}
if (parser_mm.b) {
if (!CopyPrimaryChromaticity(*parser_mm.b, &b_ptr))
return false;
}
if (parser_mm.white_point) {
if (!CopyPrimaryChromaticity(*parser_mm.white_point, &wp_ptr))
return false;
}
if (!muxer_mm->SetChromaticity(r_ptr.get(), g_ptr.get(), b_ptr.get(),
wp_ptr.get())) {
return false;
}
return true;
}
bool ColourValuePresent(long long value) {
return value != mkvparser::Colour::kValueNotPresent;
}
bool CopyColour(const mkvparser::Colour& parser_colour,
mkvmuxer::Colour* muxer_colour) {
if (!muxer_colour)
return false;
if (ColourValuePresent(parser_colour.matrix_coefficients))
muxer_colour->matrix_coefficients = parser_colour.matrix_coefficients;
if (ColourValuePresent(parser_colour.bits_per_channel))
muxer_colour->bits_per_channel = parser_colour.bits_per_channel;
if (ColourValuePresent(parser_colour.chroma_subsampling_horz))
muxer_colour->chroma_subsampling_horz =
parser_colour.chroma_subsampling_horz;
if (ColourValuePresent(parser_colour.chroma_subsampling_vert))
muxer_colour->chroma_subsampling_vert =
parser_colour.chroma_subsampling_vert;
if (ColourValuePresent(parser_colour.cb_subsampling_horz))
muxer_colour->cb_subsampling_horz = parser_colour.cb_subsampling_horz;
if (ColourValuePresent(parser_colour.cb_subsampling_vert))
muxer_colour->cb_subsampling_vert = parser_colour.cb_subsampling_vert;
if (ColourValuePresent(parser_colour.chroma_siting_horz))
muxer_colour->chroma_siting_horz = parser_colour.chroma_siting_horz;
if (ColourValuePresent(parser_colour.chroma_siting_vert))
muxer_colour->chroma_siting_vert = parser_colour.chroma_siting_vert;
if (ColourValuePresent(parser_colour.range))
muxer_colour->range = parser_colour.range;
if (ColourValuePresent(parser_colour.transfer_characteristics))
muxer_colour->transfer_characteristics =
parser_colour.transfer_characteristics;
if (ColourValuePresent(parser_colour.primaries))
muxer_colour->primaries = parser_colour.primaries;
if (ColourValuePresent(parser_colour.max_cll))
muxer_colour->max_cll = parser_colour.max_cll;
if (ColourValuePresent(parser_colour.max_fall))
muxer_colour->max_fall = parser_colour.max_fall;
if (parser_colour.mastering_metadata) {
mkvmuxer::MasteringMetadata muxer_mm;
if (!CopyMasteringMetadata(*parser_colour.mastering_metadata, &muxer_mm))
return false;
if (!muxer_colour->SetMasteringMetadata(muxer_mm))
return false;
}
return true;
}
// Format of VPx private data:
//
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID Byte | Length | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
// | |
// : Bytes 1..Length of Codec Feature :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// ID Byte Format
// ID byte is an unsigned byte.
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// |X| ID |
// +-+-+-+-+-+-+-+-+
//
// The X bit is reserved.
//
// Currently only profile level is supported. ID byte must be set to 1, and
// length must be 1. Supported values are:
//
// 10: Level 1
// 11: Level 1.1
// 20: Level 2
// 21: Level 2.1
// 30: Level 3
// 31: Level 3.1
// 40: Level 4
// 41: Level 4.1
// 50: Level 5
// 51: Level 5.1
// 52: Level 5.2
// 60: Level 6
// 61: Level 6.1
// 62: Level 6.2
//
// See the following link for more information:
// http://www.webmproject.org/vp9/profiles/
int ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length) {
const int kVpxCodecPrivateLength = 3;
if (!private_data || length != kVpxCodecPrivateLength)
return 0;
const uint8_t id_byte = *private_data;
if (id_byte != 1)
return 0;
const int kVpxProfileLength = 1;
const uint8_t length_byte = private_data[1];
if (length_byte != kVpxProfileLength)
return 0;
const int level = static_cast<int>(private_data[2]);
const int kNumLevels = 14;
const int levels[kNumLevels] = {10, 11, 20, 21, 30, 31, 40,
41, 50, 51, 52, 60, 61, 62};
for (int i = 0; i < kNumLevels; ++i) {
if (level == levels[i])
return level;
}
return 0;
}
} // namespace libwebm

51
third_party/libwebm/common/hdr_util.h vendored Normal file
View File

@ -0,0 +1,51 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#ifndef LIBWEBM_COMMON_HDR_UTIL_H_
#define LIBWEBM_COMMON_HDR_UTIL_H_
#include <stdint.h>
#include <memory>
#include "mkvmuxer/mkvmuxer.h"
namespace mkvparser {
struct Colour;
struct MasteringMetadata;
struct PrimaryChromaticity;
} // namespace mkvparser
namespace libwebm {
// Utility types and functions for working with the Colour element and its
// children. Copiers return true upon success. Presence functions return true
// when the specified element is present.
// TODO(tomfinegan): These should be moved to libwebm_utils once c++11 is
// required by libwebm.
typedef std::auto_ptr<mkvmuxer::PrimaryChromaticity> PrimaryChromaticityPtr;
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
PrimaryChromaticityPtr* muxer_pc);
bool MasteringMetadataValuePresent(double value);
bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm,
mkvmuxer::MasteringMetadata* muxer_mm);
bool ColourValuePresent(long long value);
bool CopyColour(const mkvparser::Colour& parser_colour,
mkvmuxer::Colour* muxer_colour);
// Returns VP9 profile upon success or 0 upon failure.
int ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length);
} // namespace libwebm
#endif // LIBWEBM_COMMON_HDR_UTIL_H_

View File

@ -6,10 +6,10 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#ifndef WEBMIDS_HPP
#define WEBMIDS_HPP
#ifndef COMMON_WEBMIDS_H_
#define COMMON_WEBMIDS_H_
namespace mkvmuxer {
namespace libwebm {
enum MkvId {
kMkvEBML = 0x1A45DFA3,
@ -41,6 +41,7 @@ enum MkvId {
kMkvTimecodeScale = 0x2AD7B1,
kMkvDuration = 0x4489,
kMkvDateUTC = 0x4461,
kMkvTitle = 0x7BA9,
kMkvMuxingApp = 0x4D80,
kMkvWritingApp = 0x5741,
// Cluster
@ -94,6 +95,35 @@ enum MkvId {
kMkvAspectRatioType = 0x54B3,
kMkvFrameRate = 0x2383E3,
// end video
// colour
kMkvColour = 0x55B0,
kMkvMatrixCoefficients = 0x55B1,
kMkvBitsPerChannel = 0x55B2,
kMkvChromaSubsamplingHorz = 0x55B3,
kMkvChromaSubsamplingVert = 0x55B4,
kMkvCbSubsamplingHorz = 0x55B5,
kMkvCbSubsamplingVert = 0x55B6,
kMkvChromaSitingHorz = 0x55B7,
kMkvChromaSitingVert = 0x55B8,
kMkvRange = 0x55B9,
kMkvTransferCharacteristics = 0x55BA,
kMkvPrimaries = 0x55BB,
kMkvMaxCLL = 0x55BC,
kMkvMaxFALL = 0x55BD,
// mastering metadata
kMkvMasteringMetadata = 0x55D0,
kMkvPrimaryRChromaticityX = 0x55D1,
kMkvPrimaryRChromaticityY = 0x55D2,
kMkvPrimaryGChromaticityX = 0x55D3,
kMkvPrimaryGChromaticityY = 0x55D4,
kMkvPrimaryBChromaticityX = 0x55D5,
kMkvPrimaryBChromaticityY = 0x55D6,
kMkvWhitePointChromaticityX = 0x55D7,
kMkvWhitePointChromaticityY = 0x55D8,
kMkvLuminanceMax = 0x55D9,
kMkvLuminanceMin = 0x55DA,
// end mastering metadata
// end colour
// audio
kMkvAudio = 0xE1,
kMkvSamplingFrequency = 0xB5,
@ -107,9 +137,16 @@ enum MkvId {
kMkvContentEncodingOrder = 0x5031,
kMkvContentEncodingScope = 0x5032,
kMkvContentEncodingType = 0x5033,
kMkvContentCompression = 0x5034,
kMkvContentCompAlgo = 0x4254,
kMkvContentCompSettings = 0x4255,
kMkvContentEncryption = 0x5035,
kMkvContentEncAlgo = 0x47E1,
kMkvContentEncKeyID = 0x47E2,
kMkvContentSignature = 0x47E3,
kMkvContentSigKeyID = 0x47E4,
kMkvContentSigAlgo = 0x47E5,
kMkvContentSigHashAlgo = 0x47E6,
kMkvContentEncAESSettings = 0x47E7,
kMkvAESSettingsCipherMode = 0x47E8,
kMkvAESSettingsCipherInitData = 0x47E9,
@ -133,9 +170,15 @@ enum MkvId {
kMkvChapterDisplay = 0x80,
kMkvChapString = 0x85,
kMkvChapLanguage = 0x437C,
kMkvChapCountry = 0x437E
kMkvChapCountry = 0x437E,
// Tags
kMkvTags = 0x1254C367,
kMkvTag = 0x7373,
kMkvSimpleTag = 0x67C8,
kMkvTagName = 0x45A3,
kMkvTagString = 0x4487
};
} // end namespace mkvmuxer
} // namespace libwebm
#endif // WEBMIDS_HPP
#endif // COMMON_WEBMIDS_H_

File diff suppressed because it is too large Load Diff

3769
third_party/libwebm/mkvmuxer/mkvmuxer.cc vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,17 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#ifndef MKVMUXERTYPES_HPP
#define MKVMUXERTYPES_HPP
#ifndef MKVMUXER_MKVMUXERTYPES_H_
#define MKVMUXER_MKVMUXERTYPES_H_
namespace mkvmuxer {
typedef unsigned char uint8;
typedef short int16;
typedef int int32;
typedef unsigned int uint32;
typedef long long int64;
typedef unsigned long long uint64;
} // namespace mkvmuxer
// Copied from Chromium basictypes.h
// A macro to disallow the copy constructor and operator= functions
@ -16,15 +25,4 @@
TypeName(const TypeName&); \
void operator=(const TypeName&)
namespace mkvmuxer {
typedef unsigned char uint8;
typedef short int16;
typedef int int32;
typedef unsigned int uint32;
typedef long long int64;
typedef unsigned long long uint64;
} // end namespace mkvmuxer
#endif // MKVMUXERTYPES_HPP
#endif // MKVMUXER_MKVMUXERTYPES_HPP_

View File

@ -0,0 +1,650 @@
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "mkvmuxer/mkvmuxerutil.h"
#ifdef __ANDROID__
#include <fcntl.h>
#endif
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <new>
#include "common/webmids.h"
#include "mkvmuxer/mkvmuxer.h"
#include "mkvmuxer/mkvwriter.h"
namespace mkvmuxer {
namespace {
// Date elements are always 8 octets in size.
const int kDateElementSize = 8;
uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame,
int64_t timecode, uint64_t timecode_scale) {
uint64_t block_additional_elem_size = 0;
uint64_t block_addid_elem_size = 0;
uint64_t block_more_payload_size = 0;
uint64_t block_more_elem_size = 0;
uint64_t block_additions_payload_size = 0;
uint64_t block_additions_elem_size = 0;
if (frame->additional()) {
block_additional_elem_size =
EbmlElementSize(libwebm::kMkvBlockAdditional, frame->additional(),
frame->additional_length());
block_addid_elem_size =
EbmlElementSize(libwebm::kMkvBlockAddID, frame->add_id());
block_more_payload_size =
block_addid_elem_size + block_additional_elem_size;
block_more_elem_size =
EbmlMasterElementSize(libwebm::kMkvBlockMore, block_more_payload_size) +
block_more_payload_size;
block_additions_payload_size = block_more_elem_size;
block_additions_elem_size =
EbmlMasterElementSize(libwebm::kMkvBlockAdditions,
block_additions_payload_size) +
block_additions_payload_size;
}
uint64_t discard_padding_elem_size = 0;
if (frame->discard_padding() != 0) {
discard_padding_elem_size =
EbmlElementSize(libwebm::kMkvDiscardPadding, frame->discard_padding());
}
const uint64_t reference_block_timestamp =
frame->reference_block_timestamp() / timecode_scale;
uint64_t reference_block_elem_size = 0;
if (!frame->is_key()) {
reference_block_elem_size =
EbmlElementSize(libwebm::kMkvReferenceBlock, reference_block_timestamp);
}
const uint64_t duration = frame->duration() / timecode_scale;
uint64_t block_duration_elem_size = 0;
if (duration > 0)
block_duration_elem_size =
EbmlElementSize(libwebm::kMkvBlockDuration, duration);
const uint64_t block_payload_size = 4 + frame->length();
const uint64_t block_elem_size =
EbmlMasterElementSize(libwebm::kMkvBlock, block_payload_size) +
block_payload_size;
const uint64_t block_group_payload_size =
block_elem_size + block_additions_elem_size + block_duration_elem_size +
discard_padding_elem_size + reference_block_elem_size;
if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockGroup,
block_group_payload_size)) {
return 0;
}
if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlock, block_payload_size))
return 0;
if (WriteUInt(writer, frame->track_number()))
return 0;
if (SerializeInt(writer, timecode, 2))
return 0;
// For a Block, flags is always 0.
if (SerializeInt(writer, 0, 1))
return 0;
if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length())))
return 0;
if (frame->additional()) {
if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockAdditions,
block_additions_payload_size)) {
return 0;
}
if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockMore,
block_more_payload_size))
return 0;
if (!WriteEbmlElement(writer, libwebm::kMkvBlockAddID, frame->add_id()))
return 0;
if (!WriteEbmlElement(writer, libwebm::kMkvBlockAdditional,
frame->additional(), frame->additional_length())) {
return 0;
}
}
if (frame->discard_padding() != 0 &&
!WriteEbmlElement(writer, libwebm::kMkvDiscardPadding,
frame->discard_padding())) {
return false;
}
if (!frame->is_key() &&
!WriteEbmlElement(writer, libwebm::kMkvReferenceBlock,
reference_block_timestamp)) {
return false;
}
if (duration > 0 &&
!WriteEbmlElement(writer, libwebm::kMkvBlockDuration, duration)) {
return false;
}
return EbmlMasterElementSize(libwebm::kMkvBlockGroup,
block_group_payload_size) +
block_group_payload_size;
}
uint64_t WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
int64_t timecode) {
if (WriteID(writer, libwebm::kMkvSimpleBlock))
return 0;
const int32_t size = static_cast<int32_t>(frame->length()) + 4;
if (WriteUInt(writer, size))
return 0;
if (WriteUInt(writer, static_cast<uint64_t>(frame->track_number())))
return 0;
if (SerializeInt(writer, timecode, 2))
return 0;
uint64_t flags = 0;
if (frame->is_key())
flags |= 0x80;
if (SerializeInt(writer, flags, 1))
return 0;
if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length())))
return 0;
return static_cast<uint64_t>(GetUIntSize(libwebm::kMkvSimpleBlock) +
GetCodedUIntSize(size) + 4 + frame->length());
}
} // namespace
int32_t GetCodedUIntSize(uint64_t value) {
if (value < 0x000000000000007FULL)
return 1;
else if (value < 0x0000000000003FFFULL)
return 2;
else if (value < 0x00000000001FFFFFULL)
return 3;
else if (value < 0x000000000FFFFFFFULL)
return 4;
else if (value < 0x00000007FFFFFFFFULL)
return 5;
else if (value < 0x000003FFFFFFFFFFULL)
return 6;
else if (value < 0x0001FFFFFFFFFFFFULL)
return 7;
return 8;
}
int32_t GetUIntSize(uint64_t value) {
if (value < 0x0000000000000100ULL)
return 1;
else if (value < 0x0000000000010000ULL)
return 2;
else if (value < 0x0000000001000000ULL)
return 3;
else if (value < 0x0000000100000000ULL)
return 4;
else if (value < 0x0000010000000000ULL)
return 5;
else if (value < 0x0001000000000000ULL)
return 6;
else if (value < 0x0100000000000000ULL)
return 7;
return 8;
}
int32_t GetIntSize(int64_t value) {
// Doubling the requested value ensures positive values with their high bit
// set are written with 0-padding to avoid flipping the signedness.
const uint64_t v = (value < 0) ? value ^ -1LL : value;
return GetUIntSize(2 * v);
}
uint64_t EbmlMasterElementSize(uint64_t type, uint64_t value) {
// Size of EBML ID
int32_t ebml_size = GetUIntSize(type);
// Datasize
ebml_size += GetCodedUIntSize(value);
return static_cast<uint64_t>(ebml_size);
}
uint64_t EbmlElementSize(uint64_t type, int64_t value) {
// Size of EBML ID
int32_t ebml_size = GetUIntSize(type);
// Datasize
ebml_size += GetIntSize(value);
// Size of Datasize
ebml_size++;
return static_cast<uint64_t>(ebml_size);
}
uint64_t EbmlElementSize(uint64_t type, uint64_t value) {
return EbmlElementSize(type, value, 0);
}
uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size) {
// Size of EBML ID
uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
// Datasize
ebml_size +=
(fixed_size > 0) ? fixed_size : static_cast<uint64_t>(GetUIntSize(value));
// Size of Datasize
ebml_size++;
return ebml_size;
}
uint64_t EbmlElementSize(uint64_t type, float /* value */) {
// Size of EBML ID
uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
// Datasize
ebml_size += sizeof(float);
// Size of Datasize
ebml_size++;
return ebml_size;
}
uint64_t EbmlElementSize(uint64_t type, const char* value) {
if (!value)
return 0;
// Size of EBML ID
uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
// Datasize
ebml_size += strlen(value);
// Size of Datasize
ebml_size++;
return ebml_size;
}
uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size) {
if (!value)
return 0;
// Size of EBML ID
uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
// Datasize
ebml_size += size;
// Size of Datasize
ebml_size += GetCodedUIntSize(size);
return ebml_size;
}
uint64_t EbmlDateElementSize(uint64_t type) {
// Size of EBML ID
uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
// Datasize
ebml_size += kDateElementSize;
// Size of Datasize
ebml_size++;
return ebml_size;
}
int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size) {
if (!writer || size < 1 || size > 8)
return -1;
for (int32_t i = 1; i <= size; ++i) {
const int32_t byte_count = size - i;
const int32_t bit_count = byte_count * 8;
const int64_t bb = value >> bit_count;
const uint8_t b = static_cast<uint8_t>(bb);
const int32_t status = writer->Write(&b, 1);
if (status < 0)
return status;
}
return 0;
}
int32_t SerializeFloat(IMkvWriter* writer, float f) {
if (!writer)
return -1;
assert(sizeof(uint32_t) == sizeof(float));
// This union is merely used to avoid a reinterpret_cast from float& to
// uint32& which will result in violation of strict aliasing.
union U32 {
uint32_t u32;
float f;
} value;
value.f = f;
for (int32_t i = 1; i <= 4; ++i) {
const int32_t byte_count = 4 - i;
const int32_t bit_count = byte_count * 8;
const uint8_t byte = static_cast<uint8_t>(value.u32 >> bit_count);
const int32_t status = writer->Write(&byte, 1);
if (status < 0)
return status;
}
return 0;
}
int32_t WriteUInt(IMkvWriter* writer, uint64_t value) {
if (!writer)
return -1;
int32_t size = GetCodedUIntSize(value);
return WriteUIntSize(writer, value, size);
}
int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size) {
if (!writer || size < 0 || size > 8)
return -1;
if (size > 0) {
const uint64_t bit = 1LL << (size * 7);
if (value > (bit - 2))
return -1;
value |= bit;
} else {
size = 1;
int64_t bit;
for (;;) {
bit = 1LL << (size * 7);
const uint64_t max = bit - 2;
if (value <= max)
break;
++size;
}
if (size > 8)
return false;
value |= bit;
}
return SerializeInt(writer, value, size);
}
int32_t WriteID(IMkvWriter* writer, uint64_t type) {
if (!writer)
return -1;
writer->ElementStartNotify(type, writer->Position());
const int32_t size = GetUIntSize(type);
return SerializeInt(writer, type, size);
}
bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t type, uint64_t size) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
if (WriteUInt(writer, size))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value) {
return WriteEbmlElement(writer, type, value, 0);
}
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value,
uint64_t fixed_size) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
uint64_t size = static_cast<uint64_t>(GetUIntSize(value));
if (fixed_size > 0) {
if (size > fixed_size)
return false;
size = fixed_size;
}
if (WriteUInt(writer, size))
return false;
if (SerializeInt(writer, value, static_cast<int32_t>(size)))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value) {
if (!writer)
return false;
if (WriteID(writer, type))
return 0;
const uint64_t size = GetIntSize(value);
if (WriteUInt(writer, size))
return false;
if (SerializeInt(writer, value, static_cast<int32_t>(size)))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
if (WriteUInt(writer, 4))
return false;
if (SerializeFloat(writer, value))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value) {
if (!writer || !value)
return false;
if (WriteID(writer, type))
return false;
const uint64_t length = strlen(value);
if (WriteUInt(writer, length))
return false;
if (writer->Write(value, static_cast<const uint32_t>(length)))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value,
uint64_t size) {
if (!writer || !value || size < 1)
return false;
if (WriteID(writer, type))
return false;
if (WriteUInt(writer, size))
return false;
if (writer->Write(value, static_cast<uint32_t>(size)))
return false;
return true;
}
bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
if (WriteUInt(writer, kDateElementSize))
return false;
if (SerializeInt(writer, value, kDateElementSize))
return false;
return true;
}
uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame,
Cluster* cluster) {
if (!writer || !frame || !frame->IsValid() || !cluster ||
!cluster->timecode_scale())
return 0;
// Technically the timecode for a block can be less than the
// timecode for the cluster itself (remember that block timecode
// is a signed, 16-bit integer). However, as a simplification we
// only permit non-negative cluster-relative timecodes for blocks.
const int64_t relative_timecode = cluster->GetRelativeTimecode(
frame->timestamp() / cluster->timecode_scale());
if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
return 0;
return frame->CanBeSimpleBlock() ?
WriteSimpleBlock(writer, frame, relative_timecode) :
WriteBlock(writer, frame, relative_timecode,
cluster->timecode_scale());
}
uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size) {
if (!writer)
return false;
// Subtract one for the void ID and the coded size.
uint64_t void_entry_size = size - 1 - GetCodedUIntSize(size - 1);
uint64_t void_size =
EbmlMasterElementSize(libwebm::kMkvVoid, void_entry_size) +
void_entry_size;
if (void_size != size)
return 0;
const int64_t payload_position = writer->Position();
if (payload_position < 0)
return 0;
if (WriteID(writer, libwebm::kMkvVoid))
return 0;
if (WriteUInt(writer, void_entry_size))
return 0;
const uint8_t value = 0;
for (int32_t i = 0; i < static_cast<int32_t>(void_entry_size); ++i) {
if (writer->Write(&value, 1))
return 0;
}
const int64_t stop_position = writer->Position();
if (stop_position < 0 ||
stop_position - payload_position != static_cast<int64_t>(void_size))
return 0;
return void_size;
}
void GetVersion(int32_t* major, int32_t* minor, int32_t* build,
int32_t* revision) {
*major = 0;
*minor = 2;
*build = 1;
*revision = 0;
}
uint64_t MakeUID(unsigned int* seed) {
uint64_t uid = 0;
#ifdef __MINGW32__
srand(*seed);
#endif
for (int i = 0; i < 7; ++i) { // avoid problems with 8-byte values
uid <<= 8;
// TODO(fgalligan): Move random number generation to platform specific code.
#ifdef _MSC_VER
(void)seed;
const int32_t nn = rand();
#elif __ANDROID__
int32_t temp_num = 1;
int fd = open("/dev/urandom", O_RDONLY);
if (fd != -1) {
read(fd, &temp_num, sizeof(temp_num));
close(fd);
}
const int32_t nn = temp_num;
#elif defined __MINGW32__
const int32_t nn = rand();
#else
const int32_t nn = rand_r(seed);
#endif
const int32_t n = 0xFF & (nn >> 4); // throw away low-order bits
uid |= n;
}
return uid;
}
} // namespace mkvmuxer

View File

@ -0,0 +1,95 @@
// 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.
#ifndef MKVMUXER_MKVMUXERUTIL_H_
#define MKVMUXER_MKVMUXERUTIL_H_
#include <stdint.h>
namespace mkvmuxer {
class Cluster;
class Frame;
class IMkvWriter;
const uint64_t kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
const int64_t kMaxBlockTimecode = 0x07FFFLL;
// Writes out |value| in Big Endian order. Returns 0 on success.
int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size);
// Returns the size in bytes of the element.
int32_t GetUIntSize(uint64_t value);
int32_t GetIntSize(int64_t value);
int32_t GetCodedUIntSize(uint64_t value);
uint64_t EbmlMasterElementSize(uint64_t type, uint64_t value);
uint64_t EbmlElementSize(uint64_t type, int64_t value);
uint64_t EbmlElementSize(uint64_t type, uint64_t value);
uint64_t EbmlElementSize(uint64_t type, float value);
uint64_t EbmlElementSize(uint64_t type, const char* value);
uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size);
uint64_t EbmlDateElementSize(uint64_t type);
// Returns the size in bytes of the element assuming that the element was
// written using |fixed_size| bytes. If |fixed_size| is set to zero, then it
// computes the necessary number of bytes based on |value|.
uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size);
// Creates an EBML coded number from |value| and writes it out. The size of
// the coded number is determined by the value of |value|. |value| must not
// be in a coded form. Returns 0 on success.
int32_t WriteUInt(IMkvWriter* writer, uint64_t value);
// Creates an EBML coded number from |value| and writes it out. The size of
// the coded number is determined by the value of |size|. |value| must not
// be in a coded form. Returns 0 on success.
int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size);
// Output an Mkv master element. Returns true if the element was written.
bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t value, uint64_t size);
// Outputs an Mkv ID, calls |IMkvWriter::ElementStartNotify|, and passes the
// ID to |SerializeInt|. Returns 0 on success.
int32_t WriteID(IMkvWriter* writer, uint64_t type);
// Output an Mkv non-master element. Returns true if the element was written.
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value);
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value);
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value);
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value);
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value,
uint64_t size);
bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value);
// Output an Mkv non-master element using fixed size. The element will be
// written out using exactly |fixed_size| bytes. If |fixed_size| is set to zero
// then it computes the necessary number of bytes based on |value|. Returns true
// if the element was written.
bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value,
uint64_t fixed_size);
// Output a Mkv Frame. It decides the correct element to write (Block vs
// SimpleBlock) based on the parameters of the Frame.
uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame,
Cluster* cluster);
// Output a void element. |size| must be the entire size in bytes that will be
// void. The function will calculate the size of the void header and subtract
// it from |size|.
uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size);
// Returns the version number of the muxer in |major|, |minor|, |build|,
// and |revision|.
void GetVersion(int32_t* major, int32_t* minor, int32_t* build,
int32_t* revision);
// Returns a random number to be used for UID, using |seed| to seed
// the random-number generator (see POSIX rand_r() for semantics).
uint64_t MakeUID(unsigned int* seed);
} // namespace mkvmuxer
#endif // MKVMUXER_MKVMUXERUTIL_H_

View File

@ -6,14 +6,12 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "mkvwriter.hpp"
#include "mkvmuxer/mkvwriter.h"
#ifdef _MSC_VER
#include <share.h> // for _SH_DENYWR
#endif
#include <new>
namespace mkvmuxer {
MkvWriter::MkvWriter() : file_(NULL), writer_owns_file_(true) {}

View File

@ -6,13 +6,13 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#ifndef MKVWRITER_HPP
#define MKVWRITER_HPP
#ifndef MKVMUXER_MKVWRITER_H_
#define MKVMUXER_MKVWRITER_H_
#include <stdio.h>
#include "mkvmuxer.hpp"
#include "mkvmuxertypes.hpp"
#include "mkvmuxer/mkvmuxer.h"
#include "mkvmuxer/mkvmuxertypes.h"
namespace mkvmuxer {
@ -46,6 +46,6 @@ class MkvWriter : public IMkvWriter {
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
};
} // end namespace mkvmuxer
} // namespace mkvmuxer
#endif // MKVWRITER_HPP
#endif // MKVMUXER_MKVWRITER_H_

View File

@ -1,724 +0,0 @@
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "mkvmuxerutil.hpp"
#ifdef __ANDROID__
#include <fcntl.h>
#endif
#include <cassert>
#include <cmath>
#include <cstdio>
#ifdef _MSC_VER
#define _CRT_RAND_S
#endif
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <new>
#include "mkvwriter.hpp"
#include "webmids.hpp"
namespace mkvmuxer {
namespace {
// Date elements are always 8 octets in size.
const int kDateElementSize = 8;
} // namespace
int32 GetCodedUIntSize(uint64 value) {
if (value < 0x000000000000007FULL)
return 1;
else if (value < 0x0000000000003FFFULL)
return 2;
else if (value < 0x00000000001FFFFFULL)
return 3;
else if (value < 0x000000000FFFFFFFULL)
return 4;
else if (value < 0x00000007FFFFFFFFULL)
return 5;
else if (value < 0x000003FFFFFFFFFFULL)
return 6;
else if (value < 0x0001FFFFFFFFFFFFULL)
return 7;
return 8;
}
int32 GetUIntSize(uint64 value) {
if (value < 0x0000000000000100ULL)
return 1;
else if (value < 0x0000000000010000ULL)
return 2;
else if (value < 0x0000000001000000ULL)
return 3;
else if (value < 0x0000000100000000ULL)
return 4;
else if (value < 0x0000010000000000ULL)
return 5;
else if (value < 0x0001000000000000ULL)
return 6;
else if (value < 0x0100000000000000ULL)
return 7;
return 8;
}
uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
// Size of EBML ID
int32 ebml_size = GetUIntSize(type);
// Datasize
ebml_size += GetCodedUIntSize(value);
return ebml_size;
}
uint64 EbmlElementSize(uint64 type, int64 value) {
return EbmlElementSize(type, static_cast<uint64>(value));
}
uint64 EbmlElementSize(uint64 type, uint64 value) {
// Size of EBML ID
int32 ebml_size = GetUIntSize(type);
// Datasize
ebml_size += GetUIntSize(value);
// Size of Datasize
ebml_size++;
return ebml_size;
}
uint64 EbmlElementSize(uint64 type, float /* value */) {
// Size of EBML ID
uint64 ebml_size = GetUIntSize(type);
// Datasize
ebml_size += sizeof(float);
// Size of Datasize
ebml_size++;
return ebml_size;
}
uint64 EbmlElementSize(uint64 type, const char* value) {
if (!value)
return 0;
// Size of EBML ID
uint64 ebml_size = GetUIntSize(type);
// Datasize
ebml_size += strlen(value);
// Size of Datasize
ebml_size++;
return ebml_size;
}
uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
if (!value)
return 0;
// Size of EBML ID
uint64 ebml_size = GetUIntSize(type);
// Datasize
ebml_size += size;
// Size of Datasize
ebml_size += GetCodedUIntSize(size);
return ebml_size;
}
uint64 EbmlDateElementSize(uint64 type, int64 value) {
// Size of EBML ID
uint64 ebml_size = GetUIntSize(type);
// Datasize
ebml_size += kDateElementSize;
// Size of Datasize
ebml_size++;
return ebml_size;
}
int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size) {
if (!writer || size < 1 || size > 8)
return -1;
for (int32 i = 1; i <= size; ++i) {
const int32 byte_count = size - i;
const int32 bit_count = byte_count * 8;
const int64 bb = value >> bit_count;
const uint8 b = static_cast<uint8>(bb);
const int32 status = writer->Write(&b, 1);
if (status < 0)
return status;
}
return 0;
}
int32 SerializeFloat(IMkvWriter* writer, float f) {
if (!writer)
return -1;
assert(sizeof(uint32) == sizeof(float));
// This union is merely used to avoid a reinterpret_cast from float& to
// uint32& which will result in violation of strict aliasing.
union U32 {
uint32 u32;
float f;
} value;
value.f = f;
for (int32 i = 1; i <= 4; ++i) {
const int32 byte_count = 4 - i;
const int32 bit_count = byte_count * 8;
const uint8 byte = static_cast<uint8>(value.u32 >> bit_count);
const int32 status = writer->Write(&byte, 1);
if (status < 0)
return status;
}
return 0;
}
int32 WriteUInt(IMkvWriter* writer, uint64 value) {
if (!writer)
return -1;
int32 size = GetCodedUIntSize(value);
return WriteUIntSize(writer, value, size);
}
int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
if (!writer || size < 0 || size > 8)
return -1;
if (size > 0) {
const uint64 bit = 1LL << (size * 7);
if (value > (bit - 2))
return -1;
value |= bit;
} else {
size = 1;
int64 bit;
for (;;) {
bit = 1LL << (size * 7);
const uint64 max = bit - 2;
if (value <= max)
break;
++size;
}
if (size > 8)
return false;
value |= bit;
}
return SerializeInt(writer, value, size);
}
int32 WriteID(IMkvWriter* writer, uint64 type) {
if (!writer)
return -1;
writer->ElementStartNotify(type, writer->Position());
const int32 size = GetUIntSize(type);
return SerializeInt(writer, type, size);
}
bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
if (WriteUInt(writer, size))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
const uint64 size = GetUIntSize(value);
if (WriteUInt(writer, size))
return false;
if (SerializeInt(writer, value, static_cast<int32>(size)))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
if (WriteUInt(writer, 4))
return false;
if (SerializeFloat(writer, value))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value) {
if (!writer || !value)
return false;
if (WriteID(writer, type))
return false;
const uint64 length = strlen(value);
if (WriteUInt(writer, length))
return false;
if (writer->Write(value, static_cast<const uint32>(length)))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
uint64 size) {
if (!writer || !value || size < 1)
return false;
if (WriteID(writer, type))
return false;
if (WriteUInt(writer, size))
return false;
if (writer->Write(value, static_cast<uint32>(size)))
return false;
return true;
}
bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
if (WriteUInt(writer, kDateElementSize))
return false;
if (SerializeInt(writer, value, kDateElementSize))
return false;
return true;
}
uint64 WriteSimpleBlock(IMkvWriter* writer, const uint8* data, uint64 length,
uint64 track_number, int64 timecode, uint64 is_key) {
if (!writer)
return false;
if (!data || length < 1)
return false;
// Here we only permit track number values to be no greater than
// 126, which the largest value we can store having a Matroska
// integer representation of only 1 byte.
if (track_number < 1 || track_number > 126)
return false;
// Technically the timestamp for a block can be less than the
// timestamp for the cluster itself (remember that block timestamp
// is a signed, 16-bit integer). However, as a simplification we
// only permit non-negative cluster-relative timestamps for blocks.
if (timecode < 0 || timecode > kMaxBlockTimecode)
return false;
if (WriteID(writer, kMkvSimpleBlock))
return 0;
const int32 size = static_cast<int32>(length) + 4;
if (WriteUInt(writer, size))
return 0;
if (WriteUInt(writer, static_cast<uint64>(track_number)))
return 0;
if (SerializeInt(writer, timecode, 2))
return 0;
uint64 flags = 0;
if (is_key)
flags |= 0x80;
if (SerializeInt(writer, flags, 1))
return 0;
if (writer->Write(data, static_cast<uint32>(length)))
return 0;
const uint64 element_size =
GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 + length;
return element_size;
}
// We must write the metadata (key)frame as a BlockGroup element,
// because we need to specify a duration for the frame. The
// BlockGroup element comprises the frame itself and its duration,
// and is laid out as follows:
//
// BlockGroup tag
// BlockGroup size
// Block tag
// Block size
// (the frame is the block payload)
// Duration tag
// Duration size
// (duration payload)
//
uint64 WriteMetadataBlock(IMkvWriter* writer, const uint8* data, uint64 length,
uint64 track_number, int64 timecode,
uint64 duration) {
// We don't backtrack when writing to the stream, so we must
// pre-compute the BlockGroup size, by summing the sizes of each
// sub-element (the block and the duration).
// We use a single byte for the track number of the block, which
// means the block header is exactly 4 bytes.
// TODO(matthewjheaney): use EbmlMasterElementSize and WriteEbmlMasterElement
const uint64 block_payload_size = 4 + length;
const int32 block_size = GetCodedUIntSize(block_payload_size);
const uint64 block_elem_size = 1 + block_size + block_payload_size;
const int32 duration_payload_size = GetUIntSize(duration);
const int32 duration_size = GetCodedUIntSize(duration_payload_size);
const uint64 duration_elem_size = 1 + duration_size + duration_payload_size;
const uint64 blockg_payload_size = block_elem_size + duration_elem_size;
const int32 blockg_size = GetCodedUIntSize(blockg_payload_size);
const uint64 blockg_elem_size = 1 + blockg_size + blockg_payload_size;
if (WriteID(writer, kMkvBlockGroup)) // 1-byte ID size
return 0;
if (WriteUInt(writer, blockg_payload_size))
return 0;
// Write Block element
if (WriteID(writer, kMkvBlock)) // 1-byte ID size
return 0;
if (WriteUInt(writer, block_payload_size))
return 0;
// Byte 1 of 4
if (WriteUInt(writer, track_number))
return 0;
// Bytes 2 & 3 of 4
if (SerializeInt(writer, timecode, 2))
return 0;
// Byte 4 of 4
const uint64 flags = 0;
if (SerializeInt(writer, flags, 1))
return 0;
// Now write the actual frame (of metadata)
if (writer->Write(data, static_cast<uint32>(length)))
return 0;
// Write Duration element
if (WriteID(writer, kMkvBlockDuration)) // 1-byte ID size
return 0;
if (WriteUInt(writer, duration_payload_size))
return 0;
if (SerializeInt(writer, duration, duration_payload_size))
return 0;
// Note that we don't write a reference time as part of the block
// group; no reference time(s) indicates that this block is a
// keyframe. (Unlike the case for a SimpleBlock element, the header
// bits of the Block sub-element of a BlockGroup element do not
// indicate keyframe status. The keyframe status is inferred from
// the absence of reference time sub-elements.)
return blockg_elem_size;
}
// Writes a WebM BlockGroup with BlockAdditional data. The structure is as
// follows:
// Indentation shows sub-levels
// BlockGroup
// Block
// Data
// BlockAdditions
// BlockMore
// BlockAddID
// 1 (Denotes Alpha)
// BlockAdditional
// Data
uint64 WriteBlockWithAdditional(IMkvWriter* writer, const uint8* data,
uint64 length, const uint8* additional,
uint64 additional_length, uint64 add_id,
uint64 track_number, int64 timecode,
uint64 is_key) {
if (!data || !additional || length < 1 || additional_length < 1)
return 0;
const uint64 block_payload_size = 4 + length;
const uint64 block_elem_size =
EbmlMasterElementSize(kMkvBlock, block_payload_size) + block_payload_size;
const uint64 block_additional_elem_size =
EbmlElementSize(kMkvBlockAdditional, additional, additional_length);
const uint64 block_addid_elem_size = EbmlElementSize(kMkvBlockAddID, add_id);
const uint64 block_more_payload_size =
block_addid_elem_size + block_additional_elem_size;
const uint64 block_more_elem_size =
EbmlMasterElementSize(kMkvBlockMore, block_more_payload_size) +
block_more_payload_size;
const uint64 block_additions_payload_size = block_more_elem_size;
const uint64 block_additions_elem_size =
EbmlMasterElementSize(kMkvBlockAdditions, block_additions_payload_size) +
block_additions_payload_size;
const uint64 block_group_payload_size =
block_elem_size + block_additions_elem_size;
const uint64 block_group_elem_size =
EbmlMasterElementSize(kMkvBlockGroup, block_group_payload_size) +
block_group_payload_size;
if (!WriteEbmlMasterElement(writer, kMkvBlockGroup, block_group_payload_size))
return 0;
if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
return 0;
if (WriteUInt(writer, track_number))
return 0;
if (SerializeInt(writer, timecode, 2))
return 0;
uint64 flags = 0;
if (is_key)
flags |= 0x80;
if (SerializeInt(writer, flags, 1))
return 0;
if (writer->Write(data, static_cast<uint32>(length)))
return 0;
if (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
block_additions_payload_size))
return 0;
if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
return 0;
if (!WriteEbmlElement(writer, kMkvBlockAddID, add_id))
return 0;
if (!WriteEbmlElement(writer, kMkvBlockAdditional, additional,
additional_length))
return 0;
return block_group_elem_size;
}
// Writes a WebM BlockGroup with DiscardPadding. The structure is as follows:
// Indentation shows sub-levels
// BlockGroup
// Block
// Data
// DiscardPadding
uint64 WriteBlockWithDiscardPadding(IMkvWriter* writer, const uint8* data,
uint64 length, int64 discard_padding,
uint64 track_number, int64 timecode,
uint64 is_key) {
if (!data || length < 1 || discard_padding <= 0)
return 0;
const uint64 block_payload_size = 4 + length;
const uint64 block_elem_size =
EbmlMasterElementSize(kMkvBlock, block_payload_size) + block_payload_size;
const uint64 discard_padding_elem_size =
EbmlElementSize(kMkvDiscardPadding, discard_padding);
const uint64 block_group_payload_size =
block_elem_size + discard_padding_elem_size;
const uint64 block_group_elem_size =
EbmlMasterElementSize(kMkvBlockGroup, block_group_payload_size) +
block_group_payload_size;
if (!WriteEbmlMasterElement(writer, kMkvBlockGroup, block_group_payload_size))
return 0;
if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
return 0;
if (WriteUInt(writer, track_number))
return 0;
if (SerializeInt(writer, timecode, 2))
return 0;
uint64 flags = 0;
if (is_key)
flags |= 0x80;
if (SerializeInt(writer, flags, 1))
return 0;
if (writer->Write(data, static_cast<uint32>(length)))
return 0;
if (WriteID(writer, kMkvDiscardPadding))
return 0;
const uint64 size = GetUIntSize(discard_padding);
if (WriteUInt(writer, size))
return false;
if (SerializeInt(writer, discard_padding, static_cast<int32>(size)))
return false;
return block_group_elem_size;
}
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
if (!writer)
return false;
// Subtract one for the void ID and the coded size.
uint64 void_entry_size = size - 1 - GetCodedUIntSize(size - 1);
uint64 void_size =
EbmlMasterElementSize(kMkvVoid, void_entry_size) + void_entry_size;
if (void_size != size)
return 0;
const int64 payload_position = writer->Position();
if (payload_position < 0)
return 0;
if (WriteID(writer, kMkvVoid))
return 0;
if (WriteUInt(writer, void_entry_size))
return 0;
const uint8 value = 0;
for (int32 i = 0; i < static_cast<int32>(void_entry_size); ++i) {
if (writer->Write(&value, 1))
return 0;
}
const int64 stop_position = writer->Position();
if (stop_position < 0 ||
stop_position - payload_position != static_cast<int64>(void_size))
return 0;
return void_size;
}
void GetVersion(int32* major, int32* minor, int32* build, int32* revision) {
*major = 0;
*minor = 2;
*build = 1;
*revision = 0;
}
} // namespace mkvmuxer
mkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int* seed) {
uint64 uid = 0;
#ifdef __MINGW32__
srand(*seed);
#endif
for (int i = 0; i < 7; ++i) { // avoid problems with 8-byte values
uid <<= 8;
// TODO(fgalligan): Move random number generation to platform specific code.
#ifdef _MSC_VER
(void)seed;
unsigned int random_value;
const errno_t e = rand_s(&random_value);
(void)e;
const int32 nn = random_value;
#elif __ANDROID__
int32 temp_num = 1;
int fd = open("/dev/urandom", O_RDONLY);
if (fd != -1) {
read(fd, &temp_num, sizeof(int32));
close(fd);
}
const int32 nn = temp_num;
#elif defined __MINGW32__
const int32 nn = rand();
#else
const int32 nn = rand_r(seed);
#endif
const int32 n = 0xFF & (nn >> 4); // throw away low-order bits
uid |= n;
}
return uid;
}

View File

@ -1,137 +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.
#ifndef MKVMUXERUTIL_HPP
#define MKVMUXERUTIL_HPP
#include "mkvmuxertypes.hpp"
namespace mkvmuxer {
class IMkvWriter;
const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
const int64 kMaxBlockTimecode = 0x07FFFLL;
// Writes out |value| in Big Endian order. Returns 0 on success.
int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
// Returns the size in bytes of the element.
int32 GetUIntSize(uint64 value);
int32 GetCodedUIntSize(uint64 value);
uint64 EbmlMasterElementSize(uint64 type, uint64 value);
uint64 EbmlElementSize(uint64 type, int64 value);
uint64 EbmlElementSize(uint64 type, uint64 value);
uint64 EbmlElementSize(uint64 type, float value);
uint64 EbmlElementSize(uint64 type, const char* value);
uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size);
uint64 EbmlDateElementSize(uint64 type, int64 value);
// Creates an EBML coded number from |value| and writes it out. The size of
// the coded number is determined by the value of |value|. |value| must not
// be in a coded form. Returns 0 on success.
int32 WriteUInt(IMkvWriter* writer, uint64 value);
// Creates an EBML coded number from |value| and writes it out. The size of
// the coded number is determined by the value of |size|. |value| must not
// be in a coded form. Returns 0 on success.
int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size);
// Output an Mkv master element. Returns true if the element was written.
bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 value, uint64 size);
// Outputs an Mkv ID, calls |IMkvWriter::ElementStartNotify|, and passes the
// ID to |SerializeInt|. Returns 0 on success.
int32 WriteID(IMkvWriter* writer, uint64 type);
// Output an Mkv non-master element. Returns true if the element was written.
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value);
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value);
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value);
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
uint64 size);
bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value);
// Output an Mkv Simple Block.
// Inputs:
// data: Pointer to the data.
// length: Length of the data.
// track_number: Track to add the data to. Value returned by Add track
// functions. Only values in the range [1, 126] are
// permitted.
// timecode: Relative timecode of the Block. Only values in the
// range [0, 2^15) are permitted.
// is_key: Non-zero value specifies that frame is a key frame.
uint64 WriteSimpleBlock(IMkvWriter* writer, const uint8* data, uint64 length,
uint64 track_number, int64 timecode, uint64 is_key);
// Output a metadata keyframe, using a Block Group element.
// Inputs:
// data: Pointer to the (meta)data.
// length: Length of the (meta)data.
// track_number: Track to add the data to. Value returned by Add track
// functions. Only values in the range [1, 126] are
// permitted.
// timecode Timecode of frame, relative to cluster timecode. Only
// values in the range [0, 2^15) are permitted.
// duration_timecode Duration of frame, using timecode units.
uint64 WriteMetadataBlock(IMkvWriter* writer, const uint8* data, uint64 length,
uint64 track_number, int64 timecode,
uint64 duration_timecode);
// Output an Mkv Block with BlockAdditional data.
// Inputs:
// data: Pointer to the data.
// length: Length of the data.
// additional: Pointer to the additional data
// additional_length: Length of the additional data.
// add_id: Value of BlockAddID element.
// track_number: Track to add the data to. Value returned by Add track
// functions. Only values in the range [1, 126] are
// permitted.
// timecode: Relative timecode of the Block. Only values in the
// range [0, 2^15) are permitted.
// is_key: Non-zero value specifies that frame is a key frame.
uint64 WriteBlockWithAdditional(IMkvWriter* writer, const uint8* data,
uint64 length, const uint8* additional,
uint64 additional_length, uint64 add_id,
uint64 track_number, int64 timecode,
uint64 is_key);
// Output an Mkv Block with a DiscardPadding element.
// Inputs:
// data: Pointer to the data.
// length: Length of the data.
// discard_padding: DiscardPadding value.
// track_number: Track to add the data to. Value returned by Add track
// functions. Only values in the range [1, 126] are
// permitted.
// timecode: Relative timecode of the Block. Only values in the
// range [0, 2^15) are permitted.
// is_key: Non-zero value specifies that frame is a key frame.
uint64 WriteBlockWithDiscardPadding(IMkvWriter* writer, const uint8* data,
uint64 length, int64 discard_padding,
uint64 track_number, int64 timecode,
uint64 is_key);
// Output a void element. |size| must be the entire size in bytes that will be
// void. The function will calculate the size of the void header and subtract
// it from |size|.
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size);
// Returns the version number of the muxer in |major|, |minor|, |build|,
// and |revision|.
void GetVersion(int32* major, int32* minor, int32* build, int32* revision);
// Returns a random number to be used for UID, using |seed| to seed
// the random-number generator (see POSIX rand_r() for semantics).
uint64 MakeUID(unsigned int* seed);
} // end namespace mkvmuxer
#endif // MKVMUXERUTIL_HPP

View File

@ -5,16 +5,14 @@
// 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 MKVPARSER_MKVPARSER_H_
#define MKVPARSER_MKVPARSER_H_
#ifndef MKVPARSER_HPP
#define MKVPARSER_HPP
#include <cstdlib>
#include <cstdio>
#include <cstddef>
namespace mkvparser {
const int E_PARSE_FAILED = -1;
const int E_FILE_FORMAT_INVALID = -2;
const int E_BUFFER_NOT_FULL = -3;
@ -27,12 +25,17 @@ class IMkvReader {
virtual ~IMkvReader();
};
template <typename Type>
Type* SafeArrayAlloc(unsigned long long num_elements,
unsigned long long element_size);
long long GetUIntLength(IMkvReader*, long long, long&);
long long ReadUInt(IMkvReader*, long long, long&);
long long ReadID(IMkvReader* pReader, long long pos, long& len);
long long UnserializeUInt(IMkvReader*, long long pos, long long size);
long UnserializeFloat(IMkvReader*, long long pos, long long size, double&);
long UnserializeInt(IMkvReader*, long long pos, long len, long long& result);
long UnserializeInt(IMkvReader*, long long pos, long long size,
long long& result);
long UnserializeString(IMkvReader*, long long pos, long long size, char*& str);
@ -123,7 +126,7 @@ class BlockEntry {
public:
virtual ~BlockEntry();
bool EOS() const;
bool EOS() const { return (GetKind() == kBlockEOS); }
const Cluster* GetCluster() const;
long GetIndex() const;
virtual const Block* GetBlock() const = 0;
@ -386,6 +389,90 @@ class Track {
ContentEncoding** content_encoding_entries_end_;
};
struct PrimaryChromaticity {
PrimaryChromaticity() : x(0), y(0) {}
~PrimaryChromaticity() {}
static bool Parse(IMkvReader* reader, long long read_pos,
long long value_size, bool is_x,
PrimaryChromaticity** chromaticity);
float x;
float y;
};
struct MasteringMetadata {
static const float kValueNotPresent;
MasteringMetadata()
: r(NULL),
g(NULL),
b(NULL),
white_point(NULL),
luminance_max(kValueNotPresent),
luminance_min(kValueNotPresent) {}
~MasteringMetadata() {
delete r;
delete g;
delete b;
delete white_point;
}
static bool Parse(IMkvReader* reader, long long element_start,
long long element_size,
MasteringMetadata** mastering_metadata);
PrimaryChromaticity* r;
PrimaryChromaticity* g;
PrimaryChromaticity* b;
PrimaryChromaticity* white_point;
float luminance_max;
float luminance_min;
};
struct Colour {
static const long long kValueNotPresent;
// Unless otherwise noted all values assigned upon construction are the
// equivalent of unspecified/default.
Colour()
: matrix_coefficients(kValueNotPresent),
bits_per_channel(kValueNotPresent),
chroma_subsampling_horz(kValueNotPresent),
chroma_subsampling_vert(kValueNotPresent),
cb_subsampling_horz(kValueNotPresent),
cb_subsampling_vert(kValueNotPresent),
chroma_siting_horz(kValueNotPresent),
chroma_siting_vert(kValueNotPresent),
range(kValueNotPresent),
transfer_characteristics(kValueNotPresent),
primaries(kValueNotPresent),
max_cll(kValueNotPresent),
max_fall(kValueNotPresent),
mastering_metadata(NULL) {}
~Colour() {
delete mastering_metadata;
mastering_metadata = NULL;
}
static bool Parse(IMkvReader* reader, long long element_start,
long long element_size, Colour** colour);
long long matrix_coefficients;
long long bits_per_channel;
long long chroma_subsampling_horz;
long long chroma_subsampling_vert;
long long cb_subsampling_horz;
long long cb_subsampling_vert;
long long chroma_siting_horz;
long long chroma_siting_vert;
long long range;
long long transfer_characteristics;
long long primaries;
long long max_cll;
long long max_fall;
MasteringMetadata* mastering_metadata;
};
class VideoTrack : public Track {
VideoTrack(const VideoTrack&);
VideoTrack& operator=(const VideoTrack&);
@ -393,20 +480,34 @@ class VideoTrack : public Track {
VideoTrack(Segment*, long long element_start, long long element_size);
public:
virtual ~VideoTrack();
static long Parse(Segment*, const Info&, long long element_start,
long long element_size, VideoTrack*&);
long long GetWidth() const;
long long GetHeight() const;
long long GetDisplayWidth() const;
long long GetDisplayHeight() const;
long long GetDisplayUnit() const;
long long GetStereoMode() const;
double GetFrameRate() const;
bool VetEntry(const BlockEntry*) const;
long Seek(long long time_ns, const BlockEntry*&) const;
Colour* GetColour() const;
private:
long long m_width;
long long m_height;
long long m_display_width;
long long m_display_height;
long long m_display_unit;
long long m_stereo_mode;
double m_rate;
Colour* m_colour;
};
class AudioTrack : public Track {
@ -582,6 +683,85 @@ class Chapters {
int m_editions_count;
};
class Tags {
Tags(const Tags&);
Tags& operator=(const Tags&);
public:
Segment* const m_pSegment;
const long long m_start;
const long long m_size;
const long long m_element_start;
const long long m_element_size;
Tags(Segment*, long long payload_start, long long payload_size,
long long element_start, long long element_size);
~Tags();
long Parse();
class Tag;
class SimpleTag;
class SimpleTag {
friend class Tag;
SimpleTag();
SimpleTag(const SimpleTag&);
~SimpleTag();
SimpleTag& operator=(const SimpleTag&);
public:
const char* GetTagName() const;
const char* GetTagString() const;
private:
void Init();
void ShallowCopy(SimpleTag&) const;
void Clear();
long Parse(IMkvReader*, long long pos, long long size);
char* m_tag_name;
char* m_tag_string;
};
class Tag {
friend class Tags;
Tag();
Tag(const Tag&);
~Tag();
Tag& operator=(const Tag&);
public:
int GetSimpleTagCount() const;
const SimpleTag* GetSimpleTag(int index) const;
private:
void Init();
void ShallowCopy(Tag&) const;
void Clear();
long Parse(IMkvReader*, long long pos, long long size);
long ParseSimpleTag(IMkvReader*, long long pos, long long size);
bool ExpandSimpleTagsArray();
SimpleTag* m_simple_tags;
int m_simple_tags_size;
int m_simple_tags_count;
};
int GetTagCount() const;
const Tag* GetTag(int index) const;
private:
long ParseTag(long long pos, long long size);
bool ExpandTagsArray();
Tag* m_tags;
int m_tags_size;
int m_tags_count;
};
class SegmentInfo {
SegmentInfo(const SegmentInfo&);
SegmentInfo& operator=(const SegmentInfo&);
@ -684,7 +864,7 @@ class CuePoint {
long long m_element_start;
long long m_element_size;
void Load(IMkvReader*);
bool Load(IMkvReader*);
long long GetTimeCode() const; // absolute but unscaled
long long GetTime(const Segment*) const; // absolute and scaled (ns units)
@ -697,7 +877,7 @@ class CuePoint {
// reference = clusters containing req'd referenced blocks
// reftime = timecode of the referenced block
void Parse(IMkvReader*, long long, long long);
bool Parse(IMkvReader*, long long, long long);
};
const TrackPosition* Find(const Track*) const;
@ -730,14 +910,6 @@ class Cues {
long long time_ns, const Track*, const CuePoint*&,
const CuePoint::TrackPosition*&) const;
#if 0
bool FindNext( //upper_bound of time_ns
long long time_ns,
const Track*,
const CuePoint*&,
const CuePoint::TrackPosition*&) const;
#endif
const CuePoint* GetFirst() const;
const CuePoint* GetLast() const;
const CuePoint* GetNext(const CuePoint*) const;
@ -751,8 +923,8 @@ class Cues {
bool DoneParsing() const;
private:
void Init() const;
void PreloadCuePoint(long&, long long) const;
bool Init() const;
bool PreloadCuePoint(long&, long long) const;
mutable CuePoint** m_cue_points;
mutable long m_count;
@ -877,18 +1049,12 @@ class Segment {
long ParseNext(const Cluster* pCurr, const Cluster*& pNext, long long& pos,
long& size);
#if 0
//This pair parses one cluster, but only changes the state of the
//segment object when the cluster is actually added to the index.
long ParseCluster(long long& cluster_pos, long long& new_pos) const;
bool AddCluster(long long cluster_pos, long long new_pos);
#endif
const SeekHead* GetSeekHead() const;
const Tracks* GetTracks() const;
const SegmentInfo* GetInfo() const;
const Cues* GetCues() const;
const Chapters* GetChapters() const;
const Tags* GetTags() const;
long long GetDuration() const;
@ -914,6 +1080,7 @@ class Segment {
Tracks* m_pTracks;
Cues* m_pCues;
Chapters* m_pChapters;
Tags* m_pTags;
Cluster** m_clusters;
long m_clusterCount; // number of entries for which m_index >= 0
long m_clusterPreloadCount; // number of entries for which m_index < 0
@ -923,8 +1090,8 @@ class Segment {
long DoLoadClusterUnknownSize(long long&, long&);
long DoParseNext(const Cluster*&, long long&, long&);
void AppendCluster(Cluster*);
void PreloadCluster(Cluster*, ptrdiff_t);
bool AppendCluster(Cluster*);
bool PreloadCluster(Cluster*, ptrdiff_t);
// void ParseSeekHead(long long pos, long long size);
// void ParseSeekEntry(long long pos, long long size);
@ -933,7 +1100,7 @@ class Segment {
const BlockEntry* GetBlock(const CuePoint&, const CuePoint::TrackPosition&);
};
} // end namespace mkvparser
} // namespace mkvparser
inline long mkvparser::Segment::LoadCluster() {
long long pos;
@ -942,4 +1109,4 @@ inline long mkvparser::Segment::LoadCluster() {
return LoadCluster(pos, size);
}
#endif // MKVPARSER_HPP
#endif // MKVPARSER_MKVPARSER_H_

View File

@ -5,8 +5,7 @@
// 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 "mkvreader.hpp"
#include "mkvparser/mkvreader.h"
#include <cassert>
@ -129,4 +128,4 @@ int MkvReader::Read(long long offset, long len, unsigned char* buffer) {
return 0; // success
}
} // end namespace mkvparser
} // namespace mkvparser

View File

@ -5,13 +5,13 @@
// 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 MKVPARSER_MKVREADER_H_
#define MKVPARSER_MKVREADER_H_
#ifndef MKVREADER_HPP
#define MKVREADER_HPP
#include "mkvparser.hpp"
#include <cstdio>
#include "mkvparser/mkvparser.h"
namespace mkvparser {
class MkvReader : public IMkvReader {
@ -40,6 +40,6 @@ class MkvReader : public IMkvReader {
bool reader_owns_file_;
};
} // end namespace mkvparser
} // namespace mkvparser
#endif // MKVREADER_HPP
#endif // MKVPARSER_MKVREADER_H_

View File

@ -80,10 +80,13 @@
The available initialization methods are:
\if encoder - #vpx_codec_enc_init (calls vpx_codec_enc_init_ver()) \endif
\if multi-encoder - #vpx_codec_enc_init_multi (calls vpx_codec_enc_init_multi_ver()) \endif
\if decoder - #vpx_codec_dec_init (calls vpx_codec_dec_init_ver()) \endif
\if encoder
\li #vpx_codec_enc_init (calls vpx_codec_enc_init_ver())
\li #vpx_codec_enc_init_multi (calls vpx_codec_enc_init_multi_ver())
\endif
\if decoder
\li #vpx_codec_dec_init (calls vpx_codec_dec_init_ver())
\endif
\section usage_errors Error Handling

View File

@ -71,9 +71,34 @@ static int alloc_mi(VP9_COMMON *cm, int mi_size) {
return 0;
}
#if CONFIG_PALETTE
void vp9_free_palette_map(VP9_COMMON *cm) {
int i, j;
MODE_INFO *mi;
for (i = 0; i < cm->mi_rows; i++)
for (j = 0; j < cm->mi_cols; j++) {
mi = cm->mip + cm->mi_stride + 1 + (i * cm->mi_stride + j);
if (mi->mbmi.palette_color_map != NULL) {
vpx_free(mi->mbmi.palette_color_map);
mi->mbmi.palette_color_map = NULL;
}
if (mi->mbmi.palette_uv_color_map != NULL) {
vpx_free(mi->mbmi.palette_uv_color_map);
mi->mbmi.palette_uv_color_map = NULL;
}
}
}
#endif // CONFIG_PALETTE
static void free_mi(VP9_COMMON *cm) {
int i;
#if CONFIG_PALETTE
if (cm && cm->mip)
vp9_free_palette_map(cm);
#endif // CONFIG_PALETTE
for (i = 0; i < 2; ++i) {
vpx_free(cm->mip_array[i]);
cm->mip_array[i] = NULL;
@ -97,6 +122,9 @@ void vp9_free_ref_frame_buffers(VP9_COMMON *cm) {
}
vp9_free_frame_buffer(&cm->post_proc_buffer);
#if CONFIG_LOOP_POSTFILTER
vp9_free_frame_buffer(&cm->tmp_loop_buf);
#endif
}
void vp9_free_context_buffers(VP9_COMMON *cm) {

View File

@ -37,4 +37,8 @@ void vp9_swap_mi_and_prev_mi(struct VP9Common *cm);
} // extern "C"
#endif
#if CONFIG_PALETTE
void vp9_free_palette_map(struct VP9Common *cm);
#endif // CONFIG_PALETTE
#endif // VP9_COMMON_VP9_ALLOCCOMMON_H_

View File

@ -20,6 +20,7 @@
#include "vp9/common/vp9_common_data.h"
#include "vp9/common/vp9_filter.h"
#include "vp9/common/vp9_mv.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_scale.h"
#ifdef __cplusplus
@ -30,6 +31,34 @@ extern "C" {
#define SKIP_CONTEXTS 3
#define INTER_MODE_CONTEXTS 7
#if CONFIG_SR_MODE
#define SR_CONTEXTS 3 // number of enalbed tx_size for sr mode
#define USE_POST_F 0 // 1: use post filters
#define SR_USE_MULTI_F 0 // 1: choose from multiple post filters
// SR_USFILTER_NUM_D: Number of 1D filters to choose in the post filter family
// SR_USFILTER_NUM: Number of combined 2D filters to choose
// If change this number, please change "idx_to_v","idx_to_h","hv_to_idx",
// and the prob model ("vp9_sr_usfilter_tree", "default_sr_usfilter_probs")
#define SR_USFILTER_NUM_D 4
#define SR_USFILTER_NUM (SR_USFILTER_NUM_D * SR_USFILTER_NUM_D)
#define SR_USFILTER_CONTEXTS 1
// SR_USFILTER_CONTEXTS: Depends on the post filters of upper and left blocks
#endif // CONFIG_SR_MODE
#if CONFIG_COPY_MODE
#define COPY_MODE_CONTEXTS 5
#endif // CONFIG_COPY_MODE
#if CONFIG_PALETTE
#define PALETTE_BUF_SIZE 16
#define PALETTE_MAX_SIZE 8
#define PALETTE_DELTA_BIT 0
#define PALETTE_COLOR_CONTEXTS 16
#endif // CONFIG_PALETTE
/* Segment Feature Masks */
#define MAX_MV_REF_CANDIDATES 2
@ -37,6 +66,31 @@ extern "C" {
#define COMP_INTER_CONTEXTS 5
#define REF_CONTEXTS 5
#if CONFIG_MULTI_REF
#define SINGLE_REFS 6
#define COMP_REFS 5
#else // CONFIG_MULTI_REF
#define SINGLE_REFS 3
#define COMP_REFS 2
#endif // CONFIG_MULTI_REF
#if CONFIG_NEW_QUANT
#define QUANT_PROFILES 3
#define Q_CTX_BASED_PROFILES 1
#if QUANT_PROFILES > 1
#define Q_THRESHOLD_MIN 0
#define Q_THRESHOLD_MAX 1000
static INLINE int switchable_dq_profile_used(int q_ctx, BLOCK_SIZE bsize) {
return ((bsize >= BLOCK_32X32) * q_ctx);
}
#endif // QUANT_PROFILES > 1
#endif // CONFIG_NEW_QUANT
typedef enum {
PLANE_TYPE_Y = 0,
PLANE_TYPE_UV = 1,
@ -69,23 +123,95 @@ typedef enum {
D207_PRED, // Directional 207 deg = 180 + 27
D63_PRED, // Directional 63 deg = round(arctan(2/1) * 180/pi)
TM_PRED, // True-motion
#if CONFIG_INTRABC
NEWDV, // New displacement vector within the same frame buffer
#endif // CONFIG_INTRABC
NEARESTMV,
NEARMV,
ZEROMV,
NEWMV,
#if CONFIG_NEW_INTER
NEW2MV,
NEAREST_NEARESTMV,
NEAREST_NEARMV,
NEAR_NEARESTMV,
NEAREST_NEWMV,
NEW_NEARESTMV,
NEAR_NEWMV,
NEW_NEARMV,
ZERO_ZEROMV,
NEW_NEWMV,
#endif // CONFIG_NEW_INTER
MB_MODE_COUNT
} PREDICTION_MODE;
#if CONFIG_COPY_MODE
typedef enum {
NOREF,
REF0,
REF1,
REF2,
COPY_MODE_COUNT
} COPY_MODE;
#endif // CONFIG_COPY_MODE
static INLINE int is_inter_mode(PREDICTION_MODE mode) {
#if CONFIG_NEW_INTER
return mode >= NEARESTMV && mode <= NEW2MV;
#else
return mode >= NEARESTMV && mode <= NEWMV;
#endif // CONFIG_NEW_INTER
}
#define INTRA_MODES (TM_PRED + 1)
#if CONFIG_NEW_INTER
static INLINE int is_inter_compound_mode(PREDICTION_MODE mode) {
return mode >= NEAREST_NEARESTMV && mode <= NEW_NEWMV;
}
#endif // CONFIG_NEW_INTER
static INLINE int have_newmv_in_inter_mode(PREDICTION_MODE mode) {
#if CONFIG_NEW_INTER
return (mode == NEWMV ||
mode == NEW2MV ||
mode == NEW_NEWMV ||
mode == NEAREST_NEWMV ||
mode == NEW_NEARESTMV ||
mode == NEAR_NEWMV ||
mode == NEW_NEARMV);
#else
return (mode == NEWMV);
#endif // CONFIG_NEW_INTER
}
#if CONFIG_INTRABC
static INLINE int is_intrabc_mode(PREDICTION_MODE mode) {
return mode == NEWDV;
}
#endif // CONFIG_INTRABC
#define INTRA_MODES (TM_PRED + 1)
#if CONFIG_NEW_INTER
#define INTER_MODES (1 + NEW2MV - NEARESTMV)
#else
#define INTER_MODES (1 + NEWMV - NEARESTMV)
#endif // CONFIG_NEW_INTER
#define INTER_OFFSET(mode) ((mode) - NEARESTMV)
#if CONFIG_NEW_INTER
#define INTER_COMPOUND_MODES (1 + NEW_NEWMV - NEAREST_NEARESTMV)
#define INTER_COMPOUND_OFFSET(mode) ((mode) - NEAREST_NEARESTMV)
#endif // CONFIG_NEW_INTER
#if CONFIG_TX64X64
#define MAXTXLEN 64
#else
#define MAXTXLEN 32
#endif
/* For keyframes, intra block modes are predicted by the (already decoded)
modes for the Y blocks to the left and above us; for interframes, there
is a single probability table. */
@ -93,6 +219,9 @@ static INLINE int is_inter_mode(PREDICTION_MODE mode) {
typedef struct {
PREDICTION_MODE as_mode;
int_mv as_mv[2]; // first, second inter predictor motion vectors
#if CONFIG_NEW_INTER
int_mv ref_mv[2];
#endif // CONFIG_NEW_INTER
} b_mode_info;
// Note that the rate-distortion optimization loop, bit-stream writer, and
@ -102,9 +231,17 @@ typedef enum {
NONE = -1,
INTRA_FRAME = 0,
LAST_FRAME = 1,
#if CONFIG_MULTI_REF
LAST2_FRAME = 2,
LAST3_FRAME = 3,
LAST4_FRAME = 4,
GOLDEN_FRAME = 5,
ALTREF_FRAME = 6,
#else // CONFIG_MULTI_REF
GOLDEN_FRAME = 2,
ALTREF_FRAME = 3,
MAX_REF_FRAMES = 4
#endif // CONFIG_MULTI_REF
MAX_REF_FRAMES
} MV_REFERENCE_FRAME;
// This structure now relates to 8x8 block regions.
@ -112,6 +249,13 @@ typedef struct {
// Common for both INTER and INTRA blocks
BLOCK_SIZE sb_type;
PREDICTION_MODE mode;
#if CONFIG_FILTERINTRA
int filterbit, uv_filterbit;
#endif
#if CONFIG_SR_MODE
int sr;
int us_filter_idx;
#endif // CONFIG_SR_MODE
TX_SIZE tx_size;
int8_t skip;
int8_t segment_id;
@ -126,11 +270,62 @@ typedef struct {
int_mv ref_mvs[MAX_REF_FRAMES][MAX_MV_REF_CANDIDATES];
uint8_t mode_context[MAX_REF_FRAMES];
INTERP_FILTER interp_filter;
#if CONFIG_EXT_TX
EXT_TX_TYPE ext_txfrm;
#endif
#if CONFIG_TX_SKIP
int tx_skip[PLANE_TYPES];
int tx_skip_shift;
#endif // CONFIG_TX_SKIP
#if CONFIG_COPY_MODE
COPY_MODE copy_mode;
int inter_ref_count;
#endif // CONFIG_COPY_MODE
#if CONFIG_INTERINTRA
PREDICTION_MODE interintra_mode;
PREDICTION_MODE interintra_uv_mode;
#if CONFIG_WEDGE_PARTITION
int use_wedge_interintra;
int interintra_wedge_index;
int interintra_uv_wedge_index;
#endif // CONFIG_WEDGE_PARTITION
#endif // CONFIG_INTERINTRA
#if CONFIG_WEDGE_PARTITION
int use_wedge_interinter;
int interinter_wedge_index;
#endif // CONFIG_WEDGE_PARTITION
#if CONFIG_PALETTE
int palette_enabled[2];
int palette_size[2];
int palette_indexed_size;
int palette_literal_size;
int current_palette_size;
int palette_delta_bitdepth;
uint8_t palette_indexed_colors[PALETTE_MAX_SIZE];
int8_t palette_color_delta[PALETTE_MAX_SIZE];
uint8_t *palette_color_map;
uint8_t *palette_uv_color_map;
#if CONFIG_VP9_HIGHBITDEPTH
uint16_t palette_colors[3 * PALETTE_MAX_SIZE];
uint16_t palette_literal_colors[PALETTE_MAX_SIZE];
#else
uint8_t palette_colors[3 * PALETTE_MAX_SIZE];
uint8_t palette_literal_colors[PALETTE_MAX_SIZE];
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // CONFIG_PALETTE
#if CONFIG_NEW_QUANT
int dq_off_index;
int send_dq_bit;
#endif // CONFIG_NEW_QUANT
} MB_MODE_INFO;
typedef struct MODE_INFO {
struct MODE_INFO *src_mi;
MB_MODE_INFO mbmi;
#if CONFIG_FILTERINTRA
int b_filter_info[4];
#endif
b_mode_info bmi[4];
} MODE_INFO;
@ -139,6 +334,21 @@ static INLINE PREDICTION_MODE get_y_mode(const MODE_INFO *mi, int block) {
: mi->mbmi.mode;
}
#if CONFIG_FILTERINTRA
static INLINE int is_filter_allowed(PREDICTION_MODE mode) {
#if CONFIG_INTRABC
return !is_intrabc_mode(mode);
#else
(void)mode;
return 1;
#endif // CONFIG_INTRABC
}
static INLINE int is_filter_enabled(TX_SIZE txsize) {
return (txsize < TX_SIZES);
}
#endif
static INLINE int is_inter_block(const MB_MODE_INFO *mbmi) {
return mbmi->ref_frame[0] > INTRA_FRAME;
}
@ -160,6 +370,9 @@ enum mv_precision {
struct buf_2d {
uint8_t *buf;
uint8_t *buf0;
int width;
int height;
int stride;
};
@ -171,8 +384,20 @@ struct macroblockd_plane {
struct buf_2d dst;
struct buf_2d pre[2];
const int16_t *dequant;
#if CONFIG_NEW_QUANT
const dequant_val_type_nuq* dequant_val_nuq[QUANT_PROFILES];
#endif // CONFIG_NEW_QUANT
#if CONFIG_TX_SKIP
const int16_t *dequant_pxd;
#if CONFIG_NEW_QUANT
const dequant_val_type_nuq* dequant_val_nuq_pxd[QUANT_PROFILES];
#endif // CONFIG_NEW_QUANT
#endif // CONFIG_TX_SKIP
ENTROPY_CONTEXT *above_context;
ENTROPY_CONTEXT *left_context;
#if CONFIG_PALETTE
uint8_t *color_index_map;
#endif
};
#define BLOCK_OFFSET(x, i) ((x) + (i) * 16)
@ -207,26 +432,39 @@ typedef struct macroblockd {
/* pointer to current frame */
const YV12_BUFFER_CONFIG *cur_buf;
// The size of mc_buf contains a x2 for each dimension because the image may
// be no less than 2x smaller
/* mc buffer */
DECLARE_ALIGNED(16, uint8_t, mc_buf[80 * 2 * 80 * 2]);
DECLARE_ALIGNED(16, uint8_t, mc_buf[(CODING_UNIT_SIZE + 16) * 2 *
(CODING_UNIT_SIZE + 16) * 2]);
#if CONFIG_VP9_HIGHBITDEPTH
/* Bit depth: 8, 10, 12 */
int bd;
DECLARE_ALIGNED(16, uint16_t, mc_buf_high[80 * 2 * 80 * 2]);
DECLARE_ALIGNED(16, uint16_t, mc_buf_high[(CODING_UNIT_SIZE + 16) * 2 *
(CODING_UNIT_SIZE + 16) * 2]);
#endif
int lossless;
int corrupted;
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[MAX_MB_PLANE][64 * 64]);
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[MAX_MB_PLANE][CODING_UNIT_SIZE *
CODING_UNIT_SIZE]);
#if CONFIG_PALETTE
DECLARE_ALIGNED(16, uint8_t, color_index_map[2][CODING_UNIT_SIZE *
CODING_UNIT_SIZE]);
DECLARE_ALIGNED(16, uint8_t, palette_map_buffer[CODING_UNIT_SIZE *
CODING_UNIT_SIZE]);
#endif // CONFIG_PALETTE
ENTROPY_CONTEXT *above_context[MAX_MB_PLANE];
ENTROPY_CONTEXT left_context[MAX_MB_PLANE][16];
ENTROPY_CONTEXT left_context[MAX_MB_PLANE][2 * MI_BLOCK_SIZE];
PARTITION_CONTEXT *above_seg_context;
PARTITION_CONTEXT left_seg_context[8];
PARTITION_CONTEXT left_seg_context[MI_BLOCK_SIZE];
#if CONFIG_GLOBAL_MOTION
Global_Motion_Params (*global_motion)[MAX_GLOBAL_MOTION_MODELS];
#endif // CONFIG_GLOBAL_MOTION
} MACROBLOCKD;
static INLINE BLOCK_SIZE get_subsize(BLOCK_SIZE bsize,
@ -234,25 +472,204 @@ static INLINE BLOCK_SIZE get_subsize(BLOCK_SIZE bsize,
return subsize_lookup[partition][bsize];
}
#if CONFIG_EXT_PARTITION
static INLINE PARTITION_TYPE get_partition(const MODE_INFO *const mi,
int mi_stride, int mi_rows,
int mi_cols, int mi_row,
int mi_col, BLOCK_SIZE bsize) {
const int bsl = b_width_log2_lookup[bsize];
const int bs = (1 << bsl) / 4;
MODE_INFO *m = mi[mi_row * mi_stride + mi_col].src_mi;
PARTITION_TYPE partition = partition_lookup[bsl][m->mbmi.sb_type];
if (partition != PARTITION_NONE && bsize > BLOCK_8X8 &&
mi_row + bs < mi_rows && mi_col + bs < mi_cols) {
BLOCK_SIZE h = get_subsize(bsize, PARTITION_HORZ_A);
BLOCK_SIZE v = get_subsize(bsize, PARTITION_VERT_A);
MODE_INFO *m_right = mi[mi_row * mi_stride + mi_col + bs].src_mi;
MODE_INFO *m_below = mi[(mi_row + bs) * mi_stride + mi_col].src_mi;
if (m->mbmi.sb_type == h) {
return m_below->mbmi.sb_type == h ? PARTITION_HORZ : PARTITION_HORZ_B;
} else if (m_below->mbmi.sb_type == h) {
return m->mbmi.sb_type == h ? PARTITION_HORZ : PARTITION_HORZ_A;
} else if (m->mbmi.sb_type == v) {
return m_right->mbmi.sb_type == v ? PARTITION_VERT : PARTITION_VERT_B;
} else if (m_right->mbmi.sb_type == v) {
return m->mbmi.sb_type == v ? PARTITION_VERT : PARTITION_VERT_A;
} else {
return PARTITION_SPLIT;
}
}
return partition;
}
#endif
extern const TX_TYPE intra_mode_to_tx_type_lookup[INTRA_MODES];
#if CONFIG_SUPERTX
#define PARTITION_SUPERTX_CONTEXTS 2
#if CONFIG_TX64X64
#define MAX_SUPERTX_BLOCK_SIZE BLOCK_64X64
#else
#define MAX_SUPERTX_BLOCK_SIZE BLOCK_32X32
#endif // CONFIG_TX64X64
static INLINE TX_SIZE bsize_to_tx_size(BLOCK_SIZE bsize) {
const TX_SIZE bsize_to_tx_size_lookup[BLOCK_SIZES] = {
TX_4X4, TX_4X4, TX_4X4,
TX_8X8, TX_8X8, TX_8X8,
TX_16X16, TX_16X16, TX_16X16,
TX_32X32, TX_32X32, TX_32X32,
#if CONFIG_TX64X64
TX_64X64
#if CONFIG_EXT_CODING_UNIT_SIZE
, TX_64X64, TX_64X64, TX_64X64
#endif // CONFIG_EXT_CODING_UNIT_SIZE
#else
TX_32X32
#if CONFIG_EXT_CODING_UNIT_SIZE
, TX_32X32, TX_32X32, TX_32X32
#endif // CONFIG_EXT_CODING_UNIT_SIZE
#endif // CONFIG_TX64X64
};
return bsize_to_tx_size_lookup[bsize];
}
static INLINE int supertx_enabled(const MB_MODE_INFO *mbmi) {
return (int)mbmi->tx_size >
MIN(b_width_log2_lookup[mbmi->sb_type],
b_height_log2_lookup[mbmi->sb_type]);
}
#endif // CONFIG_SUPERTX
#if CONFIG_EXT_TX
#if CONFIG_WAVELETS
#define GET_EXT_TX_TYPES(tx_size) \
((tx_size) >= TX_32X32 ? EXT_TX_TYPES_LARGE : EXT_TX_TYPES)
#define GET_EXT_TX_TREE(tx_size) \
((tx_size) >= TX_32X32 ? vp9_ext_tx_large_tree : vp9_ext_tx_tree)
#define GET_EXT_TX_ENCODINGS(tx_size) \
((tx_size) >= TX_32X32 ? ext_tx_large_encodings : ext_tx_encodings)
#else
#define GET_EXT_TX_TYPES(tx_size) \
((tx_size) >= TX_32X32 ? 1 : EXT_TX_TYPES)
#define GET_EXT_TX_TREE(tx_size) \
((tx_size) >= TX_32X32 ? NULL : vp9_ext_tx_tree)
#define GET_EXT_TX_ENCODINGS(tx_size) \
((tx_size) >= TX_32X32 ? NULL : ext_tx_encodings)
#endif // CONFIG_WAVELETS
static TX_TYPE ext_tx_to_txtype[EXT_TX_TYPES] = {
DCT_DCT,
ADST_DCT,
DCT_ADST,
ADST_ADST,
FLIPADST_DCT,
DCT_FLIPADST,
FLIPADST_FLIPADST,
ADST_FLIPADST,
FLIPADST_ADST,
DST_DST,
DST_DCT,
DCT_DST,
DST_ADST,
ADST_DST,
DST_FLIPADST,
FLIPADST_DST,
};
static INLINE int is_dst_used(TX_TYPE tx_type) {
return (tx_type == DST_DST ||
tx_type == DST_DCT || tx_type == DCT_DST ||
tx_type == DST_ADST || tx_type == ADST_DST ||
tx_type == DST_FLIPADST || tx_type == FLIPADST_DST);
}
#if CONFIG_WAVELETS
static TX_TYPE ext_tx_to_txtype_large[EXT_TX_TYPES_LARGE] = {
DCT_DCT,
WAVELET1_DCT_DCT
};
#endif // CONFIG_WAVELETS
#endif // CONFIG_EXT_TX
static INLINE TX_TYPE get_tx_type_large(PLANE_TYPE plane_type,
const MACROBLOCKD *xd) {
#if CONFIG_EXT_TX && CONFIG_WAVELETS
const MB_MODE_INFO *const mbmi = &xd->mi[0].src_mi->mbmi;
if (plane_type != PLANE_TYPE_Y || xd->lossless)
return DCT_DCT;
if (is_inter_block(mbmi)) {
return ext_tx_to_txtype_large[mbmi->ext_txfrm];
}
#endif // CONFIG_EXT_TX && CONFIG_WAVELETS
(void) plane_type;
(void) xd;
return DCT_DCT;
}
static INLINE TX_TYPE get_tx_type(PLANE_TYPE plane_type,
const MACROBLOCKD *xd) {
const MB_MODE_INFO *const mbmi = &xd->mi[0].src_mi->mbmi;
(void) plane_type;
if (plane_type != PLANE_TYPE_Y || is_inter_block(mbmi))
#if CONFIG_EXT_TX
if (xd->lossless)
return DCT_DCT;
if (is_inter_block(mbmi)) {
return ext_tx_to_txtype[mbmi->ext_txfrm];
}
#if CONFIG_INTRABC
if (is_intrabc_mode(mbmi->mode))
return DCT_DCT;
#endif // CONFIG_INTRABC
return intra_mode_to_tx_type_lookup[plane_type == PLANE_TYPE_Y ?
mbmi->mode : mbmi->uv_mode];
#else // CONFIG_EXT_TX
if (plane_type != PLANE_TYPE_Y || xd->lossless || is_inter_block(mbmi))
return DCT_DCT;
#if CONFIG_INTRABC
if (is_intrabc_mode(mbmi->mode))
return DCT_DCT;
#endif // CONFIG_INTRABC
return intra_mode_to_tx_type_lookup[mbmi->mode];
#endif // CONFIG_EXT_TX
}
static INLINE TX_TYPE get_tx_type_4x4(PLANE_TYPE plane_type,
const MACROBLOCKD *xd, int ib) {
const MODE_INFO *const mi = xd->mi[0].src_mi;
PREDICTION_MODE mode;
(void) plane_type;
#if CONFIG_EXT_TX
if (xd->lossless)
return DCT_DCT;
if (is_inter_block(&mi->mbmi)) {
return ext_tx_to_txtype[mi->mbmi.ext_txfrm];
}
mode = get_y_mode(mi, ib);
#if CONFIG_INTRABC
if (is_intrabc_mode(mode))
return DCT_DCT;
#endif // CONFIG_INTRABC
return intra_mode_to_tx_type_lookup[plane_type == PLANE_TYPE_Y ?
mode : mi->mbmi.uv_mode];
#else // CONFIG_EXT_TX
if (plane_type != PLANE_TYPE_Y || xd->lossless || is_inter_block(&mi->mbmi))
return DCT_DCT;
mode = get_y_mode(mi, ib);
#if CONFIG_INTRABC
if (is_intrabc_mode(mode))
return DCT_DCT;
#endif // CONFIG_INTRABC
return intra_mode_to_tx_type_lookup[get_y_mode(mi, ib)];
return intra_mode_to_tx_type_lookup[mode];
#endif // CONFIG_EXT_TX
}
void vp9_setup_block_planes(MACROBLOCKD *xd, int ss_x, int ss_y);
@ -269,8 +686,18 @@ static INLINE TX_SIZE get_uv_tx_size_impl(TX_SIZE y_tx_size, BLOCK_SIZE bsize,
static INLINE TX_SIZE get_uv_tx_size(const MB_MODE_INFO *mbmi,
const struct macroblockd_plane *pd) {
#if CONFIG_SUPERTX
if (!supertx_enabled(mbmi)) {
return get_uv_tx_size_impl(mbmi->tx_size, mbmi->sb_type, pd->subsampling_x,
pd->subsampling_y);
} else {
return uvsupertx_size_lookup[mbmi->tx_size][pd->subsampling_x]
[pd->subsampling_y];
}
#else
return get_uv_tx_size_impl(mbmi->tx_size, mbmi->sb_type, pd->subsampling_x,
pd->subsampling_y);
#endif // CONFIG_SUPERTX
}
static INLINE BLOCK_SIZE get_plane_block_size(BLOCK_SIZE bsize,
@ -307,6 +734,46 @@ void vp9_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd,
BLOCK_SIZE plane_bsize, TX_SIZE tx_size, int has_eob,
int aoff, int loff);
#if CONFIG_INTERINTRA
static INLINE int is_interintra_allowed(BLOCK_SIZE sb_type) {
return ((sb_type >= BLOCK_8X8) && (sb_type < BLOCK_64X64));
}
#endif // CONFIG_INTERINTRA
#if CONFIG_WEDGE_PARTITION
#define WEDGE_BITS_SML 3
#define WEDGE_BITS_MED 4
#define WEDGE_BITS_BIG 5
#define WEDGE_NONE -1
#define WEDGE_WEIGHT_BITS 6
static INLINE int get_wedge_bits(BLOCK_SIZE sb_type) {
if (sb_type < BLOCK_8X8)
return 0;
if (sb_type <= BLOCK_8X8)
return WEDGE_BITS_SML;
else if (sb_type <= BLOCK_32X32)
return WEDGE_BITS_MED;
else
return WEDGE_BITS_BIG;
}
#endif // CONFIG_WEDGE_PARTITION
#if CONFIG_NEW_QUANT && CONFIG_TX_SKIP
static INLINE int is_rect_quant_used(const MB_MODE_INFO *mbmi,
int plane) {
return
mbmi->tx_skip[plane != 0] &&
((plane == 0 && (mbmi->mode == V_PRED ||
mbmi->mode == H_PRED ||
mbmi->mode == TM_PRED)) ||
(plane != 0 && (mbmi->uv_mode == V_PRED ||
mbmi->uv_mode == H_PRED ||
mbmi->uv_mode == TM_PRED)));
}
#endif // CONFIG_NEW_QUANT && CONFIG_TX_SKIP
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -16,8 +16,9 @@
#include <assert.h>
#include "./vpx_config.h"
#include "vpx_mem/vpx_mem.h"
#include "vpx/vpx_integer.h"
#include "vpx_mem/vpx_mem.h"
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_systemdependent.h"
#ifdef __cplusplus
@ -27,12 +28,6 @@ extern "C" {
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define ROUND_POWER_OF_TWO(value, n) \
(((value) + (1 << ((n) - 1))) >> (n))
#define ALIGN_POWER_OF_TWO(value, n) \
(((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1))
// Only need this for fixed-size arrays, for structs just assign.
#define vp9_copy(dest, src) { \
assert(sizeof(dest) == sizeof(src)); \
@ -83,9 +78,6 @@ static INLINE uint16_t clip_pixel_highbd(int val, int bd) {
typedef int64_t tran_high_t;
typedef int32_t tran_low_t;
#define CONVERT_TO_SHORTPTR(x) ((uint16_t*)(((uintptr_t)x) << 1))
#define CONVERT_TO_BYTEPTR(x) ((uint8_t*)(((uintptr_t)x) >> 1 ))
#else
// Note:
@ -118,6 +110,17 @@ typedef int16_t tran_low_t;
#define VP9_FRAME_MARKER 0x2
static INLINE int get_unsigned_bits_gen(unsigned int num_values) {
int cat = 0;
if (num_values <= 1)
return 0;
num_values--;
while (num_values > 0) {
cat++;
num_values >>= 1;
}
return cat;
}
#ifdef __cplusplus
} // extern "C"

View File

@ -12,27 +12,63 @@
// Log 2 conversion lookup tables for block width and height
const int b_width_log2_lookup[BLOCK_SIZES] =
{0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4};
{0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4,
#if CONFIG_EXT_CODING_UNIT_SIZE
4, 5, 5
#endif
};
const int b_height_log2_lookup[BLOCK_SIZES] =
{0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4};
{0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4,
#if CONFIG_EXT_CODING_UNIT_SIZE
5, 4, 5
#endif
};
const int num_4x4_blocks_wide_lookup[BLOCK_SIZES] =
{1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16};
{1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16,
#if CONFIG_EXT_CODING_UNIT_SIZE
16, 32, 32
#endif
};
const int num_4x4_blocks_high_lookup[BLOCK_SIZES] =
{1, 2, 1, 2, 4, 2, 4, 8, 4, 8, 16, 8, 16};
{1, 2, 1, 2, 4, 2, 4, 8, 4, 8, 16, 8, 16,
#if CONFIG_EXT_CODING_UNIT_SIZE
32, 16, 32
#endif
};
// Log 2 conversion lookup tables for modeinfo width and height
const int mi_width_log2_lookup[BLOCK_SIZES] =
{0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3};
{0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3,
#if CONFIG_EXT_CODING_UNIT_SIZE
3, 4, 4
#endif
};
const int num_8x8_blocks_wide_lookup[BLOCK_SIZES] =
{1, 1, 1, 1, 1, 2, 2, 2, 4, 4, 4, 8, 8};
{1, 1, 1, 1, 1, 2, 2, 2, 4, 4, 4, 8, 8,
#if CONFIG_EXT_CODING_UNIT_SIZE
8, 16, 16
#endif
};
const int num_8x8_blocks_high_lookup[BLOCK_SIZES] =
{1, 1, 1, 1, 2, 1, 2, 4, 2, 4, 8, 4, 8};
{1, 1, 1, 1, 2, 1, 2, 4, 2, 4, 8, 4, 8,
#if CONFIG_EXT_CODING_UNIT_SIZE
16, 8, 16
#endif
};
// MIN(3, MIN(b_width_log2(bsize), b_height_log2(bsize)))
const int size_group_lookup[BLOCK_SIZES] =
{0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3};
{0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3,
#if CONFIG_EXT_CODING_UNIT_SIZE
3, 3, 3
#endif
};
const int num_pels_log2_lookup[BLOCK_SIZES] =
{4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12};
{4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12,
#if CONFIG_EXT_CODING_UNIT_SIZE
13, 13, 14
#endif
};
const PARTITION_TYPE partition_lookup[][BLOCK_SIZES] = {
{ // 4X4
@ -41,34 +77,141 @@ const PARTITION_TYPE partition_lookup[][BLOCK_SIZES] = {
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
PARTITION_INVALID
PARTITION_INVALID,
#if CONFIG_EXT_CODING_UNIT_SIZE
// 64x128,128x64,128x128
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
#endif
}, { // 8X8
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
PARTITION_SPLIT, PARTITION_VERT, PARTITION_HORZ, PARTITION_NONE,
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
#if CONFIG_EXT_CODING_UNIT_SIZE
// 64x128,128x64,128x128
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
#endif
}, { // 16X16
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
PARTITION_VERT, PARTITION_HORZ, PARTITION_NONE, PARTITION_INVALID,
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
PARTITION_INVALID, PARTITION_INVALID
PARTITION_INVALID, PARTITION_INVALID,
#if CONFIG_EXT_CODING_UNIT_SIZE
// 64x128,128x64,128x128
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
#endif
}, { // 32X32
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_VERT,
PARTITION_HORZ, PARTITION_NONE, PARTITION_INVALID,
PARTITION_INVALID, PARTITION_INVALID
PARTITION_INVALID, PARTITION_INVALID,
#if CONFIG_EXT_CODING_UNIT_SIZE
// 64x128,128x64,128x128
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
#endif
}, { // 64X64
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_VERT, PARTITION_HORZ,
PARTITION_NONE
PARTITION_NONE,
#if CONFIG_EXT_CODING_UNIT_SIZE
// 64x128,128x64,128x128
PARTITION_INVALID, PARTITION_INVALID, PARTITION_INVALID,
#endif
},
#if CONFIG_EXT_CODING_UNIT_SIZE
{ // 128x128
// 4X4, 4X8,8X4,8X8,8X16,16X8,16X16,16X32,32X16,32X32,32X64,64X32,64X64
// 64x128,128x64,128x128
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT, PARTITION_SPLIT,
PARTITION_SPLIT, PARTITION_VERT, PARTITION_HORZ, PARTITION_NONE
}
#endif
};
#if CONFIG_EXT_PARTITION
const BLOCK_SIZE subsize_lookup[EXT_PARTITION_TYPES][BLOCK_SIZES] = {
{ // PARTITION_NONE
BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
BLOCK_8X8, BLOCK_8X16, BLOCK_16X8,
BLOCK_16X16, BLOCK_16X32, BLOCK_32X16,
BLOCK_32X32, BLOCK_32X64, BLOCK_64X32,
BLOCK_64X64,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_64X128, BLOCK_128X64, BLOCK_128X128,
#endif
}, { // PARTITION_HORZ
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X4, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_64X32,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_128X64,
#endif
}, { // PARTITION_VERT
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_4X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X32, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X64,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X128,
#endif
}, { // PARTITION_SPLIT
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_4X4, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X32,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X64,
#endif
}, { // PARTITION_HORZ_A
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X4, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_64X32,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_128X64,
#endif
}, { // PARTITION_HORZ_B
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X4, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_64X32,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_128X64,
#endif
}, { // PARTITION_VERT_A
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_4X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X32, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X64,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X128,
#endif
}, { // PARTITION_VERT_B
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_4X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X32, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X64,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X128,
#endif
}
};
#else
const BLOCK_SIZE subsize_lookup[PARTITION_TYPES][BLOCK_SIZES] = {
{ // PARTITION_NONE
BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
@ -76,47 +219,79 @@ const BLOCK_SIZE subsize_lookup[PARTITION_TYPES][BLOCK_SIZES] = {
BLOCK_16X16, BLOCK_16X32, BLOCK_32X16,
BLOCK_32X32, BLOCK_32X64, BLOCK_64X32,
BLOCK_64X64,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_64X128, BLOCK_128X64, BLOCK_128X128,
#endif
}, { // PARTITION_HORZ
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X4, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_64X32,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_128X64,
#endif
}, { // PARTITION_VERT
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_4X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X32, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X64,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X128,
#endif
}, { // PARTITION_SPLIT
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_4X4, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_8X8, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_16X16, BLOCK_INVALID, BLOCK_INVALID,
BLOCK_32X32,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X64,
#endif
}
};
#endif // CONFIG_EXT_PARTITION
const TX_SIZE max_txsize_lookup[BLOCK_SIZES] = {
TX_4X4, TX_4X4, TX_4X4,
TX_8X8, TX_8X8, TX_8X8,
TX_16X16, TX_16X16, TX_16X16,
TX_32X32, TX_32X32, TX_32X32, TX_32X32
TX_32X32, TX_32X32, TX_32X32,
#if CONFIG_TX64X64
TX_64X64,
#if CONFIG_EXT_CODING_UNIT_SIZE
TX_64X64, TX_64X64, TX_64X64,
#endif
#else
TX_32X32,
#if CONFIG_EXT_CODING_UNIT_SIZE
TX_32X32, TX_32X32, TX_32X32,
#endif
#endif // CONFIG_TX64X64
};
const BLOCK_SIZE txsize_to_bsize[TX_SIZES] = {
BLOCK_4X4, // TX_4X4
BLOCK_8X8, // TX_8X8
BLOCK_4X4, // TX_4X4
BLOCK_8X8, // TX_8X8
BLOCK_16X16, // TX_16X16
BLOCK_32X32, // TX_32X32
#if CONFIG_TX64X64
BLOCK_64X64, // TX_64X64
#endif
};
const TX_SIZE tx_mode_to_biggest_tx_size[TX_MODES] = {
TX_4X4, // ONLY_4X4
TX_8X8, // ALLOW_8X8
TX_4X4, // ONLY_4X4
TX_8X8, // ALLOW_8X8
TX_16X16, // ALLOW_16X16
TX_32X32, // ALLOW_32X32
#if CONFIG_TX64X64
TX_64X64, // ALLOW_64X64
TX_64X64, // TX_MODE_SELECT
#else
TX_32X32, // TX_MODE_SELECT
#endif
};
const BLOCK_SIZE ss_size_lookup[BLOCK_SIZES][2][2] = {
@ -135,6 +310,11 @@ const BLOCK_SIZE ss_size_lookup[BLOCK_SIZES][2][2] = {
{{BLOCK_32X64, BLOCK_32X32}, {BLOCK_INVALID, BLOCK_16X32}},
{{BLOCK_64X32, BLOCK_INVALID}, {BLOCK_32X32, BLOCK_32X16}},
{{BLOCK_64X64, BLOCK_64X32}, {BLOCK_32X64, BLOCK_32X32}},
#if CONFIG_EXT_CODING_UNIT_SIZE
{{BLOCK_64X128, BLOCK_64X64}, {BLOCK_INVALID, BLOCK_32X64}},
{{BLOCK_128X64, BLOCK_INVALID}, {BLOCK_64X64, BLOCK_64X32}},
{{BLOCK_128X128, BLOCK_128X64}, {BLOCK_64X128, BLOCK_64X64}},
#endif // CONFIG_EXT_CODING_UNIT_SIZE
};
// Generates 4 bit field in which each bit set to 1 represents
@ -144,6 +324,24 @@ const struct {
PARTITION_CONTEXT above;
PARTITION_CONTEXT left;
} partition_context_lookup[BLOCK_SIZES]= {
#if CONFIG_EXT_CODING_UNIT_SIZE
{31, 31}, // 4X4 - {0b11111, 0b11111}
{31, 30}, // 4X8 - {0b11111, 0b11110}
{30, 31}, // 8X4 - {0b11110, 0b11111}
{30, 30}, // 8X8 - {0b11110, 0b11110}
{30, 28}, // 8X16 - {0b11110, 0b11100}
{28, 30}, // 16X8 - {0b11100, 0b11110}
{28, 28}, // 16X16 - {0b11100, 0b11100}
{28, 24}, // 16X32 - {0b11100, 0b11000}
{24, 28}, // 32X16 - {0b11000, 0b11100}
{24, 24}, // 32X32 - {0b11000, 0b11000}
{24, 16}, // 32X64 - {0b11000, 0b10000}
{16, 24}, // 64X32 - {0b10000, 0b11000}
{16, 16}, // 64X64 - {0b10000, 0b10000}
{16, 0}, // 64X128- {0b10000, 0b00000}
{0, 16}, // 128X64- {0b00000, 0b10000}
{0, 0 }, // 128X128-{0b00000, 0b00000}
#else
{15, 15}, // 4X4 - {0b1111, 0b1111}
{15, 14}, // 4X8 - {0b1111, 0b1110}
{14, 15}, // 8X4 - {0b1110, 0b1111}
@ -157,4 +355,31 @@ const struct {
{8, 0 }, // 32X64 - {0b1000, 0b0000}
{0, 8 }, // 64X32 - {0b0000, 0b1000}
{0, 0 }, // 64X64 - {0b0000, 0b0000}
#endif
};
#if CONFIG_SUPERTX
const TX_SIZE uvsupertx_size_lookup[TX_SIZES][2][2] = {
// ss_x == 0 ss_x == 0 ss_x == 1 ss_x == 1
// ss_y == 0 ss_y == 1 ss_y == 0 ss_y == 1
{{TX_4X4, TX_4X4}, {TX_4X4, TX_4X4}},
{{TX_8X8, TX_4X4}, {TX_4X4, TX_4X4}},
{{TX_16X16, TX_8X8}, {TX_8X8, TX_8X8}},
{{TX_32X32, TX_16X16}, {TX_16X16, TX_16X16}},
#if CONFIG_TX64X64
{{TX_64X64, TX_32X32}, {TX_32X32, TX_32X32}},
#endif // CONFIG_TX64X64
};
#if CONFIG_EXT_PARTITION
const int partition_supertx_context_lookup[EXT_PARTITION_TYPES] = {
-1, 0, 0, 1, 0, 0, 0, 0
};
#else
const int partition_supertx_context_lookup[PARTITION_TYPES] = {
-1, 0, 0, 1
};
#endif
#endif // CONFIG_SUPERTX

View File

@ -27,11 +27,23 @@ extern const int num_4x4_blocks_wide_lookup[BLOCK_SIZES];
extern const int size_group_lookup[BLOCK_SIZES];
extern const int num_pels_log2_lookup[BLOCK_SIZES];
extern const PARTITION_TYPE partition_lookup[][BLOCK_SIZES];
#if CONFIG_EXT_PARTITION
extern const BLOCK_SIZE subsize_lookup[EXT_PARTITION_TYPES][BLOCK_SIZES];
#else
extern const BLOCK_SIZE subsize_lookup[PARTITION_TYPES][BLOCK_SIZES];
#endif
extern const TX_SIZE max_txsize_lookup[BLOCK_SIZES];
extern const BLOCK_SIZE txsize_to_bsize[TX_SIZES];
extern const TX_SIZE tx_mode_to_biggest_tx_size[TX_MODES];
extern const BLOCK_SIZE ss_size_lookup[BLOCK_SIZES][2][2];
#if CONFIG_SUPERTX
extern const TX_SIZE uvsupertx_size_lookup[TX_SIZES][2][2];
#if CONFIG_EXT_PARTITION
extern const int partition_supertx_context_lookup[EXT_PARTITION_TYPES];
#else
extern const int partition_supertx_context_lookup[PARTITION_TYPES];
#endif
#endif
#ifdef __cplusplus
} // extern "C"

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@ extern "C" {
#endif
#define DIFF_UPDATE_PROB 252
#define GROUP_DIFF_UPDATE_PROB 252
// Coefficient token alphabet
#define ZERO_TOKEN 0 // 0 Extra Bits 0+0
@ -50,13 +51,35 @@ DECLARE_ALIGNED(16, extern const uint8_t, vp9_pt_energy_class[ENTROPY_TOKENS]);
#define CAT5_MIN_VAL 35
#define CAT6_MIN_VAL 67
#if CONFIG_TX64X64
#define DCT_MAX_VALUE 32768
#define NUM_CAT6_BITS 15
#else
#define DCT_MAX_VALUE 16384
#define NUM_CAT6_BITS 14
#endif // CONFIG_TX64X64
#if CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_TX64X64
#define DCT_MAX_VALUE_HIGH10 131072
#define DCT_MAX_VALUE_HIGH12 524288
#define NUM_CAT6_BITS_HIGH10 17
#define NUM_CAT6_BITS_HIGH12 19
#else
#define DCT_MAX_VALUE_HIGH10 65536
#define DCT_MAX_VALUE_HIGH12 262144
#define NUM_CAT6_BITS_HIGH10 16
#define NUM_CAT6_BITS_HIGH12 18
#endif // CONFIG_TX64X64
#endif // CONFIG_VP9_HIGHBITDEPTH
// Extra bit probabilities.
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat1_prob[1]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat2_prob[2]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat3_prob[3]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat4_prob[4]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat5_prob[5]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat6_prob[14]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat6_prob[NUM_CAT6_BITS]);
#if CONFIG_VP9_HIGHBITDEPTH
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat1_prob_high10[1]);
@ -64,13 +87,15 @@ DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat2_prob_high10[2]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat3_prob_high10[3]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat4_prob_high10[4]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat5_prob_high10[5]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat6_prob_high10[16]);
DECLARE_ALIGNED(16, extern const uint8_t,
vp9_cat6_prob_high10[NUM_CAT6_BITS_HIGH10]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat1_prob_high12[1]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat2_prob_high12[2]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat3_prob_high12[3]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat4_prob_high12[4]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat5_prob_high12[5]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_cat6_prob_high12[18]);
DECLARE_ALIGNED(16, extern const uint8_t,
vp9_cat6_prob_high12[NUM_CAT6_BITS_HIGH12]);
#endif // CONFIG_VP9_HIGHBITDEPTH
#define EOB_MODEL_TOKEN 3
@ -90,18 +115,18 @@ extern const vp9_extra_bit vp9_extra_bits_high10[ENTROPY_TOKENS];
extern const vp9_extra_bit vp9_extra_bits_high12[ENTROPY_TOKENS];
#endif // CONFIG_VP9_HIGHBITDEPTH
#define DCT_MAX_VALUE 16384
#if CONFIG_VP9_HIGHBITDEPTH
#define DCT_MAX_VALUE_HIGH10 65536
#define DCT_MAX_VALUE_HIGH12 262144
#endif // CONFIG_VP9_HIGHBITDEPTH
/* Coefficients are predicted via a 3-dimensional probability table. */
#define REF_TYPES 2 // intra=0, inter=1
/* Middle dimension reflects the coefficient position within the transform. */
#if CONFIG_TX_SKIP
#define FOR_SCREEN_CONTENT 0
#define COEF_BANDS 7
#define TX_SKIP_COEFF_BAND 6
#else
#define COEF_BANDS 6
#endif // CONFIG_TX_SKIP
/* Inside dimension is measure of nearby complexity, that reflects the energy
of nearby coefficients are nonzero. For the first coefficient (DC, unless
@ -128,6 +153,10 @@ typedef unsigned int vp9_coeff_count[REF_TYPES][COEF_BANDS][COEFF_CONTEXTS]
[ENTROPY_TOKENS];
typedef unsigned int vp9_coeff_stats[REF_TYPES][COEF_BANDS][COEFF_CONTEXTS]
[ENTROPY_NODES][2];
#if CONFIG_TX_SKIP
typedef unsigned int vp9_coeff_stats_pxd[REF_TYPES][COEFF_CONTEXTS]
[ENTROPY_NODES][2];
#endif // CONFIG_TX_SKIP
#define SUBEXP_PARAM 4 /* Subexponential code parameter */
#define MODULUS_PARAM 13 /* Modulus parameter */
@ -153,8 +182,19 @@ static INLINE void reset_skip_context(MACROBLOCKD *xd, BLOCK_SIZE bsize) {
// This macro is currently unused but may be used by certain implementations
#define MAXBAND_INDEX 21
DECLARE_ALIGNED(16, extern const uint8_t, vp9_coefband_trans_8x8plus[1024]);
#if CONFIG_TX64X64
#define MAX_NUM_COEFS 4096
#else
#define MAX_NUM_COEFS 1024
#endif
DECLARE_ALIGNED(16, extern const uint8_t,
vp9_coefband_trans_8x8plus[MAX_NUM_COEFS]);
DECLARE_ALIGNED(16, extern const uint8_t, vp9_coefband_trans_4x4[16]);
#if CONFIG_TX_SKIP
DECLARE_ALIGNED(16, extern uint8_t,
vp9_coefband_tx_skip[MAX_NUM_COEFS]);
#endif // CONFIG_TX_SKIP
static INLINE const uint8_t *get_band_translate(TX_SIZE tx_size) {
return tx_size == TX_4X4 ? vp9_coefband_trans_4x4
@ -183,6 +223,12 @@ typedef unsigned int vp9_coeff_count_model[REF_TYPES][COEF_BANDS]
void vp9_model_to_full_probs(const vp9_prob *model, vp9_prob *full);
#if CONFIG_TX_SKIP
typedef vp9_prob vp9_coeff_probs_pxd[REF_TYPES][COEFF_CONTEXTS][ENTROPY_NODES];
typedef unsigned int vp9_coeff_counts_pxd[REF_TYPES][COEFF_CONTEXTS]
[ENTROPY_TOKENS];
#endif // CONFIG_TX_SKIP
static INLINE int get_entropy_context(TX_SIZE tx_size, const ENTROPY_CONTEXT *a,
const ENTROPY_CONTEXT *l) {
ENTROPY_CONTEXT above_ec = 0, left_ec = 0;
@ -204,24 +250,68 @@ static INLINE int get_entropy_context(TX_SIZE tx_size, const ENTROPY_CONTEXT *a,
above_ec = !!*(const uint64_t *)a;
left_ec = !!*(const uint64_t *)l;
break;
#if CONFIG_TX64X64
case TX_64X64:
above_ec = !!*(const uint64_t *)a;
left_ec = !!*(const uint64_t *)l;
break;
#endif
default:
assert(0 && "Invalid transform size.");
break;
}
return combine_entropy_contexts(above_ec, left_ec);
}
static INLINE int get_entropy_context_sb(const MACROBLOCKD *xd,
BLOCK_SIZE bsize) {
const struct macroblockd_plane *pd = &xd->plane[0];
const TX_SIZE max_tx_size = max_txsize_lookup[bsize];
return get_entropy_context(max_tx_size, pd->above_context, pd->left_context);
}
static INLINE const scan_order *get_scan(const MACROBLOCKD *xd, TX_SIZE tx_size,
PLANE_TYPE type, int block_idx) {
const MODE_INFO *const mi = xd->mi[0].src_mi;
if (is_inter_block(&mi->mbmi) || type != PLANE_TYPE_Y || xd->lossless) {
#if CONFIG_TX_SKIP
if (mi->mbmi.tx_skip[type])
return &vp9_default_scan_orders_pxd[tx_size];
#endif // CONFIG_TX_SKIP
#if CONFIG_EXT_TX
if (xd->lossless
#if CONFIG_INTRABC
|| is_intrabc_mode(mi->mbmi.mode)
#endif
) {
return &vp9_default_scan_orders[tx_size];
} else if (is_inter_block(&mi->mbmi)) {
TX_TYPE tx_type = (tx_size <= TX_16X16) ?
get_tx_type_4x4(type, xd, block_idx) : get_tx_type_large(type, xd);
return &vp9_inter_scan_orders[tx_size][tx_type];
} else {
const PREDICTION_MODE mode =
(type == PLANE_TYPE_Y ? get_y_mode(mi, block_idx) : mi->mbmi.uv_mode);
return &vp9_intra_scan_orders[tx_size][intra_mode_to_tx_type_lookup[mode]];
}
#else // CONFIG_EXT_TX
if (type != PLANE_TYPE_Y || xd->lossless
#if CONFIG_INTRABC
|| is_intrabc_mode(mi->mbmi.mode)
#endif
) {
return &vp9_default_scan_orders[tx_size];
} else if (is_inter_block(&mi->mbmi)) {
return &vp9_default_scan_orders[tx_size];
} else {
const PREDICTION_MODE mode = get_y_mode(mi, block_idx);
return &vp9_scan_orders[tx_size][intra_mode_to_tx_type_lookup[mode]];
return &vp9_intra_scan_orders[tx_size][intra_mode_to_tx_type_lookup[mode]];
}
#endif // CONFIG_EXT_TX
}
#ifdef __cplusplus

File diff suppressed because it is too large Load Diff

View File

@ -19,75 +19,267 @@
extern "C" {
#endif
#if CONFIG_INTRABC
#define INTRABC_PROB 192
#endif // CONFIG_INTRABC
#define TX_SIZE_CONTEXTS 2
struct VP9Common;
struct tx_probs {
vp9_prob p32x32[TX_SIZE_CONTEXTS][TX_SIZES - 1];
vp9_prob p16x16[TX_SIZE_CONTEXTS][TX_SIZES - 2];
vp9_prob p8x8[TX_SIZE_CONTEXTS][TX_SIZES - 3];
#if CONFIG_TX64X64
vp9_prob p64x64[TX_SIZE_CONTEXTS][4];
#endif
vp9_prob p32x32[TX_SIZE_CONTEXTS][3];
vp9_prob p16x16[TX_SIZE_CONTEXTS][2];
vp9_prob p8x8[TX_SIZE_CONTEXTS][1];
};
struct tx_counts {
unsigned int p32x32[TX_SIZE_CONTEXTS][TX_SIZES];
unsigned int p16x16[TX_SIZE_CONTEXTS][TX_SIZES - 1];
unsigned int p8x8[TX_SIZE_CONTEXTS][TX_SIZES - 2];
#if CONFIG_TX64X64
// counter for entropy coding
// (In some case, tx_size may be not written to the bitstream)
unsigned int p64x64[TX_SIZE_CONTEXTS][5];
#endif
unsigned int p32x32[TX_SIZE_CONTEXTS][4];
unsigned int p16x16[TX_SIZE_CONTEXTS][3];
unsigned int p8x8[TX_SIZE_CONTEXTS][2];
#if CONFIG_SR_MODE
// counter for tx_size actual usage (to determine ALLOW_16X16, etc.)
#if CONFIG_TX64X64
unsigned int real_p64x64[TX_SIZE_CONTEXTS][5];
#endif // CONFIG_TX64X64
unsigned int real_p32x32[TX_SIZE_CONTEXTS][4];
unsigned int real_p16x16[TX_SIZE_CONTEXTS][3];
unsigned int real_p8x8[TX_SIZE_CONTEXTS][2];
#endif // CONFIG_SR_MODE
};
typedef struct frame_contexts {
vp9_prob y_mode_prob[BLOCK_SIZE_GROUPS][INTRA_MODES - 1];
vp9_prob uv_mode_prob[INTRA_MODES][INTRA_MODES - 1];
#if CONFIG_EXT_PARTITION
vp9_prob partition_prob[PARTITION_CONTEXTS][EXT_PARTITION_TYPES - 1];
#else
vp9_prob partition_prob[PARTITION_CONTEXTS][PARTITION_TYPES - 1];
#endif
vp9_coeff_probs_model coef_probs[TX_SIZES][PLANE_TYPES];
vp9_prob switchable_interp_prob[SWITCHABLE_FILTER_CONTEXTS]
[SWITCHABLE_FILTERS - 1];
vp9_prob inter_mode_probs[INTER_MODE_CONTEXTS][INTER_MODES - 1];
#if CONFIG_NEW_INTER
vp9_prob inter_compound_mode_probs[INTER_MODE_CONTEXTS]
[INTER_COMPOUND_MODES - 1];
#endif // CONFIG_NEW_INTER
vp9_prob intra_inter_prob[INTRA_INTER_CONTEXTS];
vp9_prob comp_inter_prob[COMP_INTER_CONTEXTS];
vp9_prob single_ref_prob[REF_CONTEXTS][2];
vp9_prob comp_ref_prob[REF_CONTEXTS];
vp9_prob single_ref_probs[REF_CONTEXTS][SINGLE_REFS - 1];
vp9_prob comp_ref_probs[REF_CONTEXTS][COMP_REFS - 1];
struct tx_probs tx_probs;
vp9_prob skip_probs[SKIP_CONTEXTS];
nmv_context nmvc;
#if CONFIG_SR_MODE
vp9_prob sr_probs[SR_CONTEXTS];
#if SR_USE_MULTI_F
vp9_prob sr_usfilter_probs[SR_USFILTER_CONTEXTS][SR_USFILTER_NUM - 1];
#endif // SR_USE_MULTI_F
#endif // CONFIG_SR_MODE
#if CONFIG_INTRABC
nmv_context ndvc;
#endif // CONFIG_INTRABC
#if CONFIG_FILTERINTRA
vp9_prob filterintra_prob[TX_SIZES][INTRA_MODES];
#endif // CONFIG_FILTERINTRA
#if CONFIG_EXT_TX
#if CONFIG_WAVELETS
vp9_prob ext_tx_prob[TX_SIZES][EXT_TX_TYPES - 1];
#else
vp9_prob ext_tx_prob[3][EXT_TX_TYPES - 1];
#endif // CONFIG_WAVELETS
#endif // CONFIG_EXT_TX
#if CONFIG_PALETTE
vp9_prob palette_enabled_prob[10][3];
vp9_prob palette_uv_enabled_prob[2];
vp9_prob palette_size_prob[10][PALETTE_SIZES - 1];
vp9_prob palette_uv_size_prob[10][PALETTE_SIZES - 1];
vp9_prob palette_color_prob[PALETTE_MAX_SIZE - 1][PALETTE_COLOR_CONTEXTS]
[PALETTE_COLORS - 1];
vp9_prob palette_uv_color_prob[PALETTE_MAX_SIZE - 1][PALETTE_COLOR_CONTEXTS]
[PALETTE_COLORS - 1];
#endif // CONFIG_PALETTE
#if CONFIG_SUPERTX
vp9_prob supertx_prob[PARTITION_SUPERTX_CONTEXTS][TX_SIZES];
#endif // CONFIG_SUPERTX
#if CONFIG_TX_SKIP
vp9_prob y_tx_skip_prob[2];
vp9_prob uv_tx_skip_prob[2];
vp9_coeff_probs_pxd coef_probs_pxd[TX_SIZES][PLANE_TYPES];
#endif // CONFIG_TX_SKIP
#if CONFIG_COPY_MODE
vp9_prob copy_noref_prob[COPY_MODE_CONTEXTS][BLOCK_SIZES];
vp9_prob copy_mode_probs_l2[COPY_MODE_CONTEXTS][1];
vp9_prob copy_mode_probs[COPY_MODE_CONTEXTS][COPY_MODE_COUNT - 2];
#endif // CONFIG_COPY_MODE
#if CONFIG_INTERINTRA
vp9_prob interintra_prob[BLOCK_SIZES];
#if CONFIG_WEDGE_PARTITION
vp9_prob wedge_interintra_prob[BLOCK_SIZES];
#endif // CONFIG_WEDGE_PARTITION
#endif // CONFIG_INTERINTRA
#if CONFIG_WEDGE_PARTITION
vp9_prob wedge_interinter_prob[BLOCK_SIZES];
#endif // CONFIG_WEDGE_PARTITION
#if CONFIG_GLOBAL_MOTION
vp9_prob global_motion_types_prob[GLOBAL_MOTION_TYPES - 1];
#endif // CONFIG_GLOBAL_MOTION
#if CONFIG_NEW_QUANT && QUANT_PROFILES > 1 && !Q_CTX_BASED_PROFILES
vp9_prob dq_profile_prob[QUANT_PROFILES - 1];
#endif // CONFIG_NEW_QUANT && QUANT_PROFILES > 1 && !Q_CTX_BASED_PROFILES
} FRAME_CONTEXT;
typedef struct {
unsigned int y_mode[BLOCK_SIZE_GROUPS][INTRA_MODES];
unsigned int uv_mode[INTRA_MODES][INTRA_MODES];
#if CONFIG_EXT_PARTITION
unsigned int partition[PARTITION_CONTEXTS][EXT_PARTITION_TYPES];
#else
unsigned int partition[PARTITION_CONTEXTS][PARTITION_TYPES];
#endif
vp9_coeff_count_model coef[TX_SIZES][PLANE_TYPES];
unsigned int eob_branch[TX_SIZES][PLANE_TYPES][REF_TYPES]
[COEF_BANDS][COEFF_CONTEXTS];
unsigned int switchable_interp[SWITCHABLE_FILTER_CONTEXTS]
[SWITCHABLE_FILTERS];
unsigned int inter_mode[INTER_MODE_CONTEXTS][INTER_MODES];
#if CONFIG_NEW_INTER
unsigned int inter_compound_mode[INTER_MODE_CONTEXTS][INTER_COMPOUND_MODES];
#endif // CONFIG_NEW_INTER
unsigned int intra_inter[INTRA_INTER_CONTEXTS][2];
unsigned int comp_inter[COMP_INTER_CONTEXTS][2];
unsigned int single_ref[REF_CONTEXTS][2][2];
unsigned int comp_ref[REF_CONTEXTS][2];
unsigned int single_ref[REF_CONTEXTS][SINGLE_REFS-1][2];
unsigned int comp_ref[REF_CONTEXTS][COMP_REFS-1][2];
struct tx_counts tx;
unsigned int skip[SKIP_CONTEXTS][2];
nmv_context_counts mv;
#if CONFIG_SR_MODE
unsigned int sr[SR_CONTEXTS][2];
#if SR_USE_MULTI_F
unsigned int sr_usfilters[SR_USFILTER_CONTEXTS][SR_USFILTER_NUM];
#endif // SR_USE_MULTI_F
#endif // CONFIG_SR_MODE
#if CONFIG_INTRABC
nmv_context_counts dv;
#endif // CONFIG_INTRABC
#if CONFIG_FILTERINTRA
unsigned int filterintra[TX_SIZES][INTRA_MODES][2];
#endif // CONFIG_FILTERINTRA
#if CONFIG_EXT_TX
#if CONFIG_WAVELETS
unsigned int ext_tx[TX_SIZES][EXT_TX_TYPES];
#else
unsigned int ext_tx[3][EXT_TX_TYPES];
#endif // CONFIG_WAVELETS
#endif // CONFIG_EXT_TX
#if CONFIG_SUPERTX
unsigned int supertx[PARTITION_SUPERTX_CONTEXTS][TX_SIZES][2];
unsigned int supertx_size[BLOCK_SIZES];
#endif // CONFIG_SUPERTX
#if CONFIG_TX_SKIP
unsigned int y_tx_skip[2][2];
unsigned int uv_tx_skip[2][2];
vp9_coeff_counts_pxd coef_pxd[TX_SIZES][PLANE_TYPES];
unsigned int eob_branch_pxd[TX_SIZES][PLANE_TYPES][REF_TYPES][COEFF_CONTEXTS];
#endif // CONFIG_TX_SKIP
#if CONFIG_COPY_MODE
unsigned int copy_noref[COPY_MODE_CONTEXTS][BLOCK_SIZES][2];
unsigned int copy_mode_l2[COPY_MODE_CONTEXTS][2];
unsigned int copy_mode[COPY_MODE_CONTEXTS][COPY_MODE_COUNT - 1];
#endif // CONFIG_COPY_MODE
#if CONFIG_INTERINTRA
unsigned int interintra[BLOCK_SIZES][2];
#if CONFIG_WEDGE_PARTITION
unsigned int wedge_interintra[BLOCK_SIZES][2];
#endif // CONFIG_WEDGE_PARTITION
#endif // CONFIG_INTERINTRA
#if CONFIG_WEDGE_PARTITION
unsigned int wedge_interinter[BLOCK_SIZES][2];
#endif // CONFIG_WEDGE_PARTITION
#if CONFIG_PALETTE
unsigned int y_palette_enabled[10][3][2];
unsigned int uv_palette_enabled[2][2];
unsigned int y_palette_size[10][PALETTE_SIZES];
unsigned int uv_palette_size[10][PALETTE_SIZES];
#endif // CONFIG_PALETTE
#if CONFIG_GLOBAL_MOTION
unsigned int global_motion_types[GLOBAL_MOTION_TYPES];
#endif // CONFIG_GLOBAL_MOTION
#if CONFIG_NEW_QUANT && QUANT_PROFILES > 1 && !Q_CTX_BASED_PROFILES
unsigned int dq_profile[QUANT_PROFILES];
#endif // CONFIG_NEW_QUANT && QUANT_PROFILES > 1 && !Q_CTX_BASED_PROFILES
} FRAME_COUNTS;
extern const vp9_prob vp9_kf_uv_mode_prob[INTRA_MODES][INTRA_MODES - 1];
extern const vp9_prob vp9_kf_y_mode_prob[INTRA_MODES][INTRA_MODES]
[INTRA_MODES - 1];
#if CONFIG_EXT_PARTITION
extern const vp9_prob vp9_kf_partition_probs[PARTITION_CONTEXTS]
[EXT_PARTITION_TYPES - 1];
#else
extern const vp9_prob vp9_kf_partition_probs[PARTITION_CONTEXTS]
[PARTITION_TYPES - 1];
#endif
extern const vp9_tree_index vp9_intra_mode_tree[TREE_SIZE(INTRA_MODES)];
extern const vp9_tree_index vp9_inter_mode_tree[TREE_SIZE(INTER_MODES)];
extern const vp9_tree_index vp9_partition_tree[TREE_SIZE(PARTITION_TYPES)];
#if CONFIG_SR_MODE && SR_USE_MULTI_F
extern const vp9_tree_index vp9_sr_usfilter_tree[TREE_SIZE(SR_USFILTER_NUM)];
#endif // CONFIG_SR_MODE && SR_USE_MULTI_F
#if CONFIG_EXT_PARTITION
extern const vp9_tree_index vp9_ext_partition_tree
[TREE_SIZE(EXT_PARTITION_TYPES)];
#endif
extern const vp9_tree_index vp9_switchable_interp_tree
[TREE_SIZE(SWITCHABLE_FILTERS)];
#if CONFIG_EXT_TX
extern const vp9_tree_index vp9_ext_tx_tree[TREE_SIZE(EXT_TX_TYPES)];
#if CONFIG_WAVELETS
extern const
vp9_tree_index vp9_ext_tx_large_tree[TREE_SIZE(EXT_TX_TYPES_LARGE)];
#endif // CONFIG_WAVELETS
#endif // CONFIG_EXT_TX
#if CONFIG_PALETTE
extern const vp9_tree_index vp9_palette_size_tree[TREE_SIZE(PALETTE_SIZES)];
extern const vp9_tree_index vp9_palette_color_tree[TREE_SIZE(PALETTE_COLORS)];
#endif // CONFIG_PALETTE
#if CONFIG_COPY_MODE
extern const vp9_tree_index vp9_copy_mode_tree_l2[TREE_SIZE(2)];
extern const vp9_tree_index vp9_copy_mode_tree[TREE_SIZE(COPY_MODE_COUNT - 1)];
#endif // CONFIG_COPY_MODE
#if CONFIG_NEW_INTER
extern const vp9_tree_index vp9_inter_compound_mode_tree
[TREE_SIZE(INTER_COMPOUND_MODES)];
#endif // CONFIG_NEW_INTER
#if CONFIG_NEW_QUANT && QUANT_PROFILES > 1 && !Q_CTX_BASED_PROFILES
extern const vp9_tree_index vp9_dq_profile_tree[TREE_SIZE(QUANT_PROFILES)];
#endif // CONFIG_NEW_QUANT && QUANT_PROFILES > 1 && !Q_CTX_BASED_PROFILES
void vp9_setup_past_independence(struct VP9Common *cm);
#if CONFIG_ROW_TILE
void vp9_dec_setup_past_independence(struct VP9Common *cm,
int dec_tile_row, int dec_tile_col);
#endif
void vp9_init_mode_probs(FRAME_CONTEXT *fc);
void vp9_adapt_mode_probs(struct VP9Common *cm);
#if CONFIG_TX64X64
void tx_counts_to_branch_counts_64x64(const unsigned int *tx_count_64x64p,
unsigned int (*ct_64x64p)[2]);
#endif
void tx_counts_to_branch_counts_32x32(const unsigned int *tx_count_32x32p,
unsigned int (*ct_32x32p)[2]);
void tx_counts_to_branch_counts_16x16(const unsigned int *tx_count_16x16p,
@ -99,8 +291,12 @@ static INLINE const vp9_prob *get_y_mode_probs(const MODE_INFO *mi,
const MODE_INFO *above_mi,
const MODE_INFO *left_mi,
int block) {
const PREDICTION_MODE above = vp9_above_block_mode(mi, above_mi, block);
const PREDICTION_MODE left = vp9_left_block_mode(mi, left_mi, block);
PREDICTION_MODE above = vp9_above_block_mode(mi, above_mi, block);
PREDICTION_MODE left = vp9_left_block_mode(mi, left_mi, block);
#if CONFIG_INTRABC
if (is_intrabc_mode(above)) above = DC_PRED;
if (is_intrabc_mode(left)) left = DC_PRED;
#endif
return vp9_kf_y_mode_prob[above][left];
}

View File

@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include "vp9/common/vp9_onyxc_int.h"
#include "vp9/common/vp9_entropymv.h"
@ -118,6 +120,19 @@ static const uint8_t log_in_base_2[] = {
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10
};
#if CONFIG_GLOBAL_MOTION
const vp9_tree_index vp9_global_motion_types_tree
[TREE_SIZE(GLOBAL_MOTION_TYPES)] = {
-GLOBAL_ZERO, 2,
-GLOBAL_TRANSLATION, -GLOBAL_ROTZOOM
};
static const vp9_prob default_global_motion_types_prob
[GLOBAL_MOTION_TYPES - 1] = {
224, 128
};
#endif // CONFIG_GLOBAL_MOTION
static INLINE int mv_class_base(MV_CLASS_TYPE c) {
return c ? CLASS0_SIZE << (c + 2) : 0;
}
@ -142,7 +157,7 @@ int vp9_get_mv_mag(MV_CLASS_TYPE c, int offset) {
static void inc_mv_component(int v, nmv_component_counts *comp_counts,
int incr, int usehp) {
int s, z, c, o, d, e, f;
assert(v != 0); /* should not be zero */
assert(v != 0); /* should not be zero */
s = v < 0;
comp_counts->sign[s] += incr;
z = (s ? -v : v) - 1; /* magnitude - 1 */
@ -230,4 +245,10 @@ void vp9_adapt_mv_probs(VP9_COMMON *cm, int allow_hp) {
void vp9_init_mv_probs(VP9_COMMON *cm) {
cm->fc.nmvc = default_nmv_context;
#if CONFIG_INTRABC
cm->fc.ndvc = default_nmv_context;
#endif // CONFIG_INTRABC
#if CONFIG_GLOBAL_MOTION
vp9_copy(cm->fc.global_motion_types_prob, default_global_motion_types_prob);
#endif // CONFIG_GLOBAL_MOTION
}

View File

@ -14,6 +14,7 @@
#include "./vpx_config.h"
#include "vp9/common/vp9_enums.h"
#include "vp9/common/vp9_mv.h"
#include "vp9/common/vp9_prob.h"
@ -127,6 +128,11 @@ typedef struct {
void vp9_inc_mv(const MV *mv, nmv_context_counts *mvctx);
#if CONFIG_GLOBAL_MOTION
extern const vp9_tree_index vp9_global_motion_types_tree
[TREE_SIZE(GLOBAL_MOTION_TYPES)];
#endif // CONFIG_GLOBAL_MOTION
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -17,13 +17,22 @@
extern "C" {
#endif
#if CONFIG_EXT_CODING_UNIT_SIZE
#define CODING_UNIT_SIZE_LOG2 7
#else
#define CODING_UNIT_SIZE_LOG2 6
#endif
#define CODING_UNIT_SIZE (1 << CODING_UNIT_SIZE_LOG2)
#define MI_SIZE_LOG2 3
#define MI_BLOCK_SIZE_LOG2 (6 - MI_SIZE_LOG2) // 64 = 2^6
#define MI_BLOCK_SIZE_LOG2 (CODING_UNIT_SIZE_LOG2 - MI_SIZE_LOG2)
#define MI_SIZE (1 << MI_SIZE_LOG2) // pixels per mi-unit
#define MI_BLOCK_SIZE (1 << MI_BLOCK_SIZE_LOG2) // mi-units per max block
#define MI_MASK (MI_BLOCK_SIZE - 1)
#define MI_MASK_2 (MI_BLOCK_SIZE * 2 - 1)
// Bitstream profiles indicated by 2-3 bits in the uncompressed header.
// 00: Profile 0. 8-bit 4:2:0 only.
@ -54,10 +63,31 @@ typedef enum BLOCK_SIZE {
BLOCK_32X64,
BLOCK_64X32,
BLOCK_64X64,
#if CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_64X128,
BLOCK_128X64,
BLOCK_128X128,
#endif // CONFIG_EXT_CODING_UNIT_SIZE
BLOCK_SIZES,
BLOCK_INVALID = BLOCK_SIZES
BLOCK_INVALID = BLOCK_SIZES,
BLOCK_LARGEST = BLOCK_SIZES - 1
} BLOCK_SIZE;
#if CONFIG_EXT_PARTITION
typedef enum PARTITION_TYPE {
PARTITION_NONE,
PARTITION_HORZ,
PARTITION_VERT,
PARTITION_SPLIT,
PARTITION_HORZ_A, // HORZ split and the left partition is split again
PARTITION_HORZ_B, // HORZ split and the right partition is split again
PARTITION_VERT_A, // VERT split and the top partition is split again
PARTITION_VERT_B, // VERT split and the bottom partition is split again
EXT_PARTITION_TYPES,
PARTITION_TYPES = PARTITION_SPLIT + 1,
PARTITION_INVALID = EXT_PARTITION_TYPES
} PARTITION_TYPE;
#else
typedef enum PARTITION_TYPE {
PARTITION_NONE,
PARTITION_HORZ,
@ -66,10 +96,15 @@ typedef enum PARTITION_TYPE {
PARTITION_TYPES,
PARTITION_INVALID = PARTITION_TYPES
} PARTITION_TYPE;
#endif
typedef char PARTITION_CONTEXT;
#define PARTITION_PLOFFSET 4 // number of probability models per block size
#if CONFIG_EXT_CODING_UNIT_SIZE
#define PARTITION_CONTEXTS (5 * PARTITION_PLOFFSET)
#else
#define PARTITION_CONTEXTS (4 * PARTITION_PLOFFSET)
#endif
// block transform size
typedef enum {
@ -77,17 +112,28 @@ typedef enum {
TX_8X8 = 1, // 8x8 transform
TX_16X16 = 2, // 16x16 transform
TX_32X32 = 3, // 32x32 transform
#if CONFIG_TX64X64
TX_64X64 = 4, // 64x64 transform
#endif
TX_SIZES
} TX_SIZE;
#define MAX_TX_SIZE_LOG2 (TX_SIZES + 1)
#define MAX_MIN_TX_IN_BLOCK_LOG2 MAX((CODING_UNIT_SIZE_LOG2 - \
MAX_TX_SIZE_LOG2), 1)
#define MAX_MIN_TX_IN_BLOCK (1 << MAX_MIN_TX_IN_BLOCK_LOG2)
// frame transform mode
typedef enum {
ONLY_4X4 = 0, // only 4x4 transform used
ALLOW_8X8 = 1, // allow block transform size up to 8x8
ALLOW_16X16 = 2, // allow block transform size up to 16x16
ALLOW_32X32 = 3, // allow block transform size up to 32x32
TX_MODE_SELECT = 4, // transform specified for each block
TX_MODES = 5,
#if CONFIG_TX64X64
ALLOW_64X64 = 4, // allow block transform size up to 32x32
#endif
TX_MODE_SELECT, // transform specified for each block
TX_MODES,
} TX_MODE;
typedef enum {
@ -95,24 +141,89 @@ typedef enum {
ADST_DCT = 1, // ADST in vertical, DCT in horizontal
DCT_ADST = 2, // DCT in vertical, ADST in horizontal
ADST_ADST = 3, // ADST in both directions
TX_TYPES = 4
TX_TYPES,
#if CONFIG_EXT_TX
FLIPADST_DCT = 4,
DCT_FLIPADST = 5,
FLIPADST_FLIPADST = 6,
ADST_FLIPADST = 7,
FLIPADST_ADST = 8,
DST_DST = 9,
DST_DCT = 10,
DCT_DST = 11,
DST_ADST = 12,
ADST_DST = 13,
DST_FLIPADST = 14,
FLIPADST_DST = 15,
#if CONFIG_WAVELETS
WAVELET1_DCT_DCT,
#endif // CONFIG_WAVELETS
TOTAL_TX_TYPES,
#endif // CONFIG_EXT_TX
} TX_TYPE;
#if CONFIG_EXT_TX
typedef enum {
UNKNOWN = 0,
BT_601 = 1, // YUV
BT_709 = 2, // YUV
SMPTE_170 = 3, // YUV
SMPTE_240 = 4, // YUV
RESERVED_1 = 5,
RESERVED_2 = 6,
SRGB = 7 // RGB
} COLOR_SPACE;
NORM = 0,
ALT1 = 1,
#if CONFIG_WAVELETS
EXT_TX_TYPES_LARGE = 2,
#endif // CONFIG_WAVELETS
ALT2 = 2,
ALT3 = 3,
ALT4 = 4,
ALT5 = 5,
ALT6 = 6,
ALT7 = 7,
ALT8 = 8,
ALT9 = 9,
ALT10 = 10,
ALT11 = 11,
ALT12 = 12,
ALT13 = 13,
ALT14 = 14,
ALT15 = 15,
EXT_TX_TYPES
} EXT_TX_TYPE;
#endif // CONFIG_EXT_TX
#if CONFIG_PALETTE
typedef enum {
TWO_COLORS,
THREE_COLORS,
FOUR_COLORS,
FIVE_COLORS,
SIX_COLORS,
SEVEN_COLORS,
EIGHT_COLORS,
PALETTE_SIZES
} PALETTE_SIZE;
typedef enum {
PALETTE_COLOR_ONE,
PALETTE_COLOR_TWO,
PALETTE_COLOR_THREE,
PALETTE_COLOR_FOUR,
PALETTE_COLOR_FIVE,
PALETTE_COLOR_SIX,
PALETTE_COLOR_SEVEN,
PALETTE_COLOR_EIGHT,
PALETTE_COLORS
} PALETTE_COLOR;
#endif // CONFIG_PALETTE
typedef enum {
VP9_LAST_FLAG = 1 << 0,
#if CONFIG_MULTI_REF
VP9_LAST2_FLAG = 1 << 1,
VP9_LAST3_FLAG = 1 << 2,
VP9_LAST4_FLAG = 1 << 3,
VP9_GOLD_FLAG = 1 << 4,
VP9_ALT_FLAG = 1 << 5,
#else // CONFIG_MULTI_REF
VP9_GOLD_FLAG = 1 << 1,
VP9_ALT_FLAG = 1 << 2,
#endif // CONFIG_MULTI_REF
} VP9_REFFRAME;
#ifdef __cplusplus

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,11 @@ extern "C" {
#define dual_set_epi16(a, b) \
_mm_set_epi16(b, b, b, b, a, a, a, a)
#if CONFIG_TX_SKIP
#define TX_SKIP_SHIFT_LQ 2
#define TX_SKIP_SHIFT_HQ 3
#endif
// Constants:
// for (int i = 1; i< 32; ++i)
// printf("static const int cospi_%d_64 = %.0f;\n", i,
@ -116,17 +121,261 @@ typedef struct {
} highbd_transform_2d;
#endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_EMULATE_HARDWARE
// When CONFIG_EMULATE_HARDWARE is 1 the transform performs a
// non-normative method to handle overflows. A stream that causes
// overflows in the inverse transform is considered invalid in VP9,
// and a hardware implementer is free to choose any reasonable
// method to handle overflows. However to aid in hardware
// verification they can use a specific implementation of the
// WRAPLOW() macro below that is identical to their intended
// hardware implementation (and also use configure options to trigger
// the C-implementation of the transform).
//
// The particular WRAPLOW implementation below performs strict
// overflow wrapping to match common hardware implementations.
// bd of 8 uses trans_low with 16bits, need to remove 16bits
// bd of 10 uses trans_low with 18bits, need to remove 14bits
// bd of 12 uses trans_low with 20bits, need to remove 12bits
// bd of x uses trans_low with 8+x bits, need to remove 24-x bits
#define WRAPLOW(x, bd) ((((int32_t)(x)) << (24 - bd)) >> (24 - bd))
#else
#define WRAPLOW(x, bd) (x)
#endif // CONFIG_EMULATE_HARDWARE
static INLINE uint8_t clip_pixel_add(uint8_t dest, tran_high_t trans) {
trans = WRAPLOW(trans, 8);
return clip_pixel(WRAPLOW(dest + trans, 8));
}
#if CONFIG_EXT_TX
#define USE_DST2 1
#if USE_DST2
static const tran_high_t Tx4[4 * 4] = {
// dst2
6270, 15137, 15137, 6270,
11585, 11585, -11585, -11585,
15137, -6270, -6270, 15137,
11585, -11585, 11585, -11585,
};
static const tran_high_t Tx8[8 * 8] = {
// dst2
3196, 9102, 13623, 16069, 16069, 13623, 9102, 3196,
6270, 15137, 15137, 6270, -6270, -15137, -15137, -6270,
9102, 16069, 3196, -13623, -13623, 3196, 16069, 9102,
11585, 11585, -11585, -11585, 11585, 11585, -11585, -11585,
13623, 3196, -16069, 9102, 9102, -16069, 3196, 13623,
15137, -6270, -6270, 15137, -15137, 6270, 6270, -15137,
16069, -13623, 9102, -3196, -3196, 9102, -13623, 16069,
11585, -11585, 11585, -11585, 11585, -11585, 11585, -11585,
};
static const tran_high_t Tx16[16 * 16] = {
// dst2
1606, 4756, 7723, 10394, 12665, 14449, 15679, 16305,
16305, 15679, 14449, 12665, 10394, 7723, 4756, 1606,
3196, 9102, 13623, 16069, 16069, 13623, 9102, 3196,
-3196, -9102, -13623, -16069, -16069, -13623, -9102, -3196,
4756, 12665, 16305, 14449, 7723, -1606, -10394, -15679,
-15679, -10394, -1606, 7723, 14449, 16305, 12665, 4756,
6270, 15137, 15137, 6270, -6270, -15137, -15137, -6270,
6270, 15137, 15137, 6270, -6270, -15137, -15137, -6270,
7723, 16305, 10394, -4756, -15679, -12665, 1606, 14449,
14449, 1606, -12665, -15679, -4756, 10394, 16305, 7723,
9102, 16069, 3196, -13623, -13623, 3196, 16069, 9102,
-9102, -16069, -3196, 13623, 13623, -3196, -16069, -9102,
10394, 14449, -4756, -16305, -1606, 15679, 7723, -12665,
-12665, 7723, 15679, -1606, -16305, -4756, 14449, 10394,
11585, 11585, -11585, -11585, 11585, 11585, -11585, -11585,
11585, 11585, -11585, -11585, 11585, 11585, -11585, -11585,
12665, 7723, -15679, -1606, 16305, -4756, -14449, 10394,
10394, -14449, -4756, 16305, -1606, -15679, 7723, 12665,
13623, 3196, -16069, 9102, 9102, -16069, 3196, 13623,
-13623, -3196, 16069, -9102, -9102, 16069, -3196, -13623,
14449, -1606, -12665, 15679, -4756, -10394, 16305, -7723,
-7723, 16305, -10394, -4756, 15679, -12665, -1606, 14449,
15137, -6270, -6270, 15137, -15137, 6270, 6270, -15137,
15137, -6270, -6270, 15137, -15137, 6270, 6270, -15137,
15679, -10394, 1606, 7723, -14449, 16305, -12665, 4756,
4756, -12665, 16305, -14449, 7723, 1606, -10394, 15679,
16069, -13623, 9102, -3196, -3196, 9102, -13623, 16069,
-16069, 13623, -9102, 3196, 3196, -9102, 13623, -16069,
16305, -15679, 14449, -12665, 10394, -7723, 4756, -1606,
-1606, 4756, -7723, 10394, -12665, 14449, -15679, 16305,
11585, -11585, 11585, -11585, 11585, -11585, 11585, -11585,
11585, -11585, 11585, -11585, 11585, -11585, 11585, -11585,
};
#endif // USE_DST2
static INLINE void vp9_fgentx4(const tran_low_t *input, tran_low_t *output,
const tran_high_t *T) {
tran_high_t sum;
int i;
const tran_high_t *Tx = T;
for (i = 0; i < 4; ++i, Tx += 4) {
sum = Tx[0] * input[0] + Tx[1] * input[1] +
Tx[2] * input[2] + Tx[3] * input[3];
output[i] = ROUND_POWER_OF_TWO(sum, DCT_CONST_BITS);
}
}
static INLINE void vp9_fgentx8(const tran_low_t *input, tran_low_t *output,
const tran_high_t *T) {
tran_high_t sum;
int i;
const tran_high_t *Tx = T;
for (i = 0; i < 8; ++i, Tx += 8) {
sum = Tx[0] * input[0] + Tx[1] * input[1] +
Tx[2] * input[2] + Tx[3] * input[3] +
Tx[4] * input[4] + Tx[5] * input[5] +
Tx[6] * input[6] + Tx[7] * input[7];
output[i] = ROUND_POWER_OF_TWO(sum, DCT_CONST_BITS);
}
}
static INLINE void vp9_fgentx16(const tran_low_t *input, tran_low_t *output,
const tran_high_t *T) {
tran_high_t sum;
int i;
const tran_high_t *Tx = T;
for (i = 0; i < 16; ++i, Tx += 16) {
sum = Tx[0] * input[0] + Tx[1] * input[1] +
Tx[2] * input[2] + Tx[3] * input[3] +
Tx[4] * input[4] + Tx[5] * input[5] +
Tx[6] * input[6] + Tx[7] * input[7] +
Tx[8] * input[8] + Tx[9] * input[9] +
Tx[10] * input[10] + Tx[11] * input[11] +
Tx[12] * input[12] + Tx[13] * input[13] +
Tx[14] * input[14] + Tx[15] * input[15];
output[i] = ROUND_POWER_OF_TWO(sum, DCT_CONST_BITS);
}
}
static INLINE void vp9_igentx4(const tran_low_t *input, tran_low_t *output,
const tran_high_t *T) {
tran_high_t sum[4];
int i;
const tran_high_t *Tx = T;
for (i = 0; i < 4; ++i, ++Tx) {
sum[i] = Tx[0] * input[0] + Tx[4] * input[1] +
Tx[8] * input[2] + Tx[12] * input[3];
}
for (i = 0; i < 4; ++i) {
output[i] = WRAPLOW(ROUND_POWER_OF_TWO(sum[i], DCT_CONST_BITS), 8);
}
}
static INLINE void vp9_igentx8(const tran_low_t *input, tran_low_t *output,
const tran_high_t *T) {
tran_high_t sum[8];
int i;
const tran_high_t *Tx = T;
for (i = 0; i < 8; ++i, ++Tx) {
sum[i] = Tx[0] * input[0] + Tx[8] * input[1] +
Tx[16] * input[2] + Tx[24] * input[3] +
Tx[32] * input[4] + Tx[40] * input[5] +
Tx[48] * input[6] + Tx[56] * input[7];
}
for (i = 0; i < 8; ++i) {
output[i] = WRAPLOW(ROUND_POWER_OF_TWO(sum[i], DCT_CONST_BITS), 8);
}
}
static INLINE void vp9_igentx16(const tran_low_t *input, tran_low_t *output,
const tran_high_t *T) {
tran_high_t sum[16];
int i;
const tran_high_t *Tx = T;
for (i = 0; i < 16; ++i, ++Tx) {
sum[i] = Tx[0] * input[0] + Tx[16] * input[1] +
Tx[32] * input[2] + Tx[48] * input[3] +
Tx[64] * input[4] + Tx[80] * input[5] +
Tx[96] * input[6] + Tx[112] * input[7] +
Tx[128] * input[8] + Tx[144] * input[9] +
Tx[160] * input[10] + Tx[176] * input[11] +
Tx[192] * input[12] + Tx[208] * input[13] +
Tx[224] * input[14] + Tx[240] * input[15];
}
for (i = 0; i < 16; ++i) {
output[i] = WRAPLOW(ROUND_POWER_OF_TWO(sum[i], DCT_CONST_BITS), 8);
}
}
#if CONFIG_VP9_HIGHBITDEPTH
static INLINE void vp9_highbd_igentx4(const tran_low_t *input,
tran_low_t *output,
int bd, const tran_high_t *T) {
tran_high_t sum[4];
int i;
const tran_high_t *Tx = T;
(void) bd;
for (i = 0; i < 4; ++i, Tx += 1) {
sum[i] = Tx[0] * input[0] + Tx[4] * input[1] +
Tx[8] * input[2] + Tx[12] * input[3];
}
for (i = 0; i < 4; ++i) {
output[i] = WRAPLOW(ROUND_POWER_OF_TWO(sum[i], DCT_CONST_BITS), bd);
}
}
static INLINE void vp9_highbd_igentx8(const tran_low_t *input,
tran_low_t *output,
int bd, const tran_high_t *T) {
tran_high_t sum[8];
int i;
const tran_high_t *Tx = T;
(void) bd;
for (i = 0; i < 8; ++i, Tx += 1) {
sum[i] = Tx[0] * input[0] + Tx[8] * input[1] +
Tx[16] * input[2] + Tx[24] * input[3] +
Tx[32] * input[4] + Tx[40] * input[5] +
Tx[48] * input[6] + Tx[56] * input[7];
}
for (i = 0; i < 8; ++i) {
output[i] = WRAPLOW(ROUND_POWER_OF_TWO(sum[i], DCT_CONST_BITS), bd);
}
}
static INLINE void vp9_highbd_igentx16(const tran_low_t *input,
tran_low_t *output,
int bd, const tran_high_t *T) {
tran_high_t sum[16];
int i;
const tran_high_t *Tx = T;
(void) bd;
for (i = 0; i < 16; ++i, Tx += 1) {
sum[i] = Tx[0] * input[0] + Tx[16] * input[1] +
Tx[32] * input[2] + Tx[48] * input[3] +
Tx[64] * input[4] + Tx[80] * input[5] +
Tx[96] * input[6] + Tx[112] * input[7] +
Tx[128] * input[8] + Tx[144] * input[9] +
Tx[160] * input[10] + Tx[176] * input[11] +
Tx[192] * input[12] + Tx[208] * input[13] +
Tx[224] * input[14] + Tx[240] * input[15];
}
for (i = 0; i < 16; ++i) {
output[i] = WRAPLOW(ROUND_POWER_OF_TWO(sum[i], DCT_CONST_BITS), bd);
}
}
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // CONFIG_EXT_TX
void vp9_iwht4x4_add(const tran_low_t *input, uint8_t *dest, int stride,
int eob);
void vp9_idct4x4_add(const tran_low_t *input, uint8_t *dest, int stride,
int eob);
void vp9_idct8x8_add(const tran_low_t *input, uint8_t *dest, int stride,
int eob);
void vp9_idct16x16_add(const tran_low_t *input, uint8_t *dest, int stride, int
eob);
void vp9_idct16x16_add(const tran_low_t *input, uint8_t *dest, int stride,
int eob);
void vp9_idct32x32_add(const tran_low_t *input, uint8_t *dest, int stride,
int eob);
#if CONFIG_TX64X64
void vp9_idct64x64_add(const tran_low_t *input, uint8_t *dest, int stride,
int eob);
#endif // CONFIG_TX64X64
void vp9_iht4x4_add(TX_TYPE tx_type, const tran_low_t *input, uint8_t *dest,
int stride, int eob);
void vp9_iht8x8_add(TX_TYPE tx_type, const tran_low_t *input, uint8_t *dest,
@ -135,6 +384,9 @@ void vp9_iht16x16_add(TX_TYPE tx_type, const tran_low_t *input, uint8_t *dest,
int stride, int eob);
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_idct4(const tran_low_t *input, tran_low_t *output, int bd);
void vp9_highbd_idct8(const tran_low_t *input, tran_low_t *output, int bd);
void vp9_highbd_idct16(const tran_low_t *input, tran_low_t *output, int bd);
void vp9_highbd_iwht4x4_add(const tran_low_t *input, uint8_t *dest, int stride,
int eob, int bd);
void vp9_highbd_idct4x4_add(const tran_low_t *input, uint8_t *dest, int stride,
@ -145,15 +397,67 @@ void vp9_highbd_idct16x16_add(const tran_low_t *input, uint8_t *dest,
int stride, int eob, int bd);
void vp9_highbd_idct32x32_add(const tran_low_t *input, uint8_t *dest,
int stride, int eob, int bd);
#if CONFIG_TX64X64
void vp9_highbd_idct64x64_add(const tran_low_t *input, uint8_t *dest,
int stride, int eob, int bd);
#endif
void vp9_highbd_iht4x4_add(TX_TYPE tx_type, const tran_low_t *input,
uint8_t *dest, int stride, int eob, int bd);
void vp9_highbd_iht8x8_add(TX_TYPE tx_type, const tran_low_t *input,
uint8_t *dest, int stride, int eob, int bd);
void vp9_highbd_iht16x16_add(TX_TYPE tx_type, const tran_low_t *input,
uint8_t *dest, int stride, int eob, int bd);
static INLINE uint16_t highbd_clip_pixel_add(uint16_t dest, tran_high_t trans,
int bd) {
trans = WRAPLOW(trans, bd);
return clip_pixel_highbd(WRAPLOW(dest + trans, bd), bd);
}
#endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_TX_SKIP
void vp9_tx_identity_add_rect(const tran_low_t *input, uint8_t *dest,
int row, int col, int stride_in,
int stride_out, int shift);
void vp9_tx_identity_add(const tran_low_t *input, uint8_t *dest,
int stride, int bs, int shift);
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_highbd_tx_identity_add_rect(const tran_low_t *input, uint8_t *dest,
int row, int col, int stride_in,
int stride_out, int shift, int bd);
void vp9_highbd_tx_identity_add(const tran_low_t *input, uint8_t *dest,
int stride, int bs, int shift, int bd);
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // CONFIG_TX_SKIP
void vp9_dst1d_type1(int64_t *in, int64_t *out, int N);
void vp9_idst4x4_add(const tran_low_t *input, uint8_t *dest, int stride);
void vp9_idst8x8_add(const tran_low_t *input, uint8_t *dest, int stride);
void vp9_idst16x16_add(const tran_low_t *input, uint8_t *dest, int stride);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_COMMON_VP9_IDCT_H_
#if CONFIG_SR_MODE
void vp9_iwht4x4(const tran_low_t *input, int16_t *dest, int stride,
int eob);
void vp9_idct4x4(const tran_low_t *input, int16_t *dest, int stride,
int eob);
void vp9_idct8x8(const tran_low_t *input, int16_t *dest, int stride,
int eob);
void vp9_idct16x16(const tran_low_t *input, int16_t *dest, int stride,
int eob);
void vp9_idct32x32(const tran_low_t *input, int16_t *dest, int stride,
int eob);
void vp9_iht4x4(TX_TYPE tx_type, const tran_low_t *input, int16_t *dest,
int stride, int eob);
void vp9_iht8x8(TX_TYPE tx_type, const tran_low_t *input, int16_t *dest,
int stride, int eob);
void vp9_iht16x16(TX_TYPE tx_type, const tran_low_t *input, int16_t *dest,
int stride, int eob);
#if CONFIG_TX64X64
void vp9_idct64x64(const tran_low_t *input, int16_t *dest, int stride,
int eob);
#endif // CONFIG_TX64X64
#endif // CONFIG_SR_MODE

407
vp9/common/vp9_idwt.c Normal file
View File

@ -0,0 +1,407 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include "./vp9_rtcd.h"
#include "vp9/common/vp9_systemdependent.h"
#include "vp9/common/vp9_blockd.h"
#include "vp9/common/vp9_idwt.h"
// Note: block length must be even for this implementation
static void synthesis_53_row(int length,
tran_low_t *lowpass, tran_low_t *highpass,
tran_low_t *x) {
tran_low_t r, *a, *b;
int n;
n = length >> 1;
b = highpass;
a = lowpass;
r = *highpass;
while (n--) {
*a++ -= (r + (*b) + 1) >> 1;
r = *b++;
}
n = length >> 1;
b = highpass;
a = lowpass;
while (--n) {
*x++ = ((r = *a++) + 1) >> 1;
*x++ = *b++ + ((r + (*a) + 2) >> 2);
}
*x++ = ((r = *a) + 1) >> 1;
*x++ = *b + ((r + 1) >> 1);
}
static void synthesis_53_col(int length,
tran_low_t *lowpass, tran_low_t *highpass,
tran_low_t *x) {
tran_low_t r, *a, *b;
int n;
n = length >> 1;
b = highpass;
a = lowpass;
r = *highpass;
while (n--) {
*a++ -= (r + (*b) + 1) >> 1;
r = *b++;
}
n = length >> 1;
b = highpass;
a = lowpass;
while (--n) {
r = *a++;
*x++ = r;
*x++ = ((*b++) << 1) + ((r + (*a) + 1) >> 1);
}
*x++ = *a;
*x++ = ((*b) << 1) + *a;
}
static void dyadic_synthesize_53(int levels, int width, int height,
tran_low_t *c, int pitch_c,
int16_t *x, int pitch_x,
int dwt_scale_bits) {
int th[16], tw[16], lv, i, j, nh, nw, hh = height, hw = width;
tran_low_t buffer[2 * DWT_MAX_LENGTH];
const int dwt_scale_rnd = 1 << (dwt_scale_bits - 1);
th[0] = hh;
tw[0] = hw;
for (i = 1; i <= levels; i++) {
th[i] = (th[i - 1] + 1) >> 1;
tw[i] = (tw[i - 1] + 1) >> 1;
}
for (lv = levels - 1; lv >= 0; lv--) {
nh = th[lv];
nw = tw[lv];
hh = th[lv + 1];
hw = tw[lv + 1];
if ((nh < 2) || (nw < 2)) continue;
for (j = 0; j < nw; j++) {
for (i = 0; i < nh; i++)
buffer[i] = c[i * pitch_c + j];
synthesis_53_col(nh, buffer, buffer + hh, buffer + nh);
for (i = 0; i < nh; i++)
c[i * pitch_c + j] = buffer[i + nh];
}
for (i = 0; i < nh; i++) {
memcpy(buffer, &c[i * pitch_c], nw * sizeof(*buffer));
synthesis_53_row(nw, buffer, buffer + hw, &c[i * pitch_c]);
}
}
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
x[i * pitch_x + j] = c[i * pitch_c + j] >= 0 ?
((c[i * pitch_c + j] + dwt_scale_rnd) >> dwt_scale_bits) :
-((-c[i * pitch_c + j] + dwt_scale_rnd) >> dwt_scale_bits);
}
}
}
// Note: block length must be even for this implementation
static void synthesis_26_row(int length,
tran_low_t *lowpass, tran_low_t *highpass,
tran_low_t *x) {
tran_low_t r, s, *a, *b;
int i, n = length >> 1;
if (n >= 4) {
a = lowpass;
b = highpass;
r = *lowpass;
while (--n) {
*b++ += (r - a[1] + 4) >> 3;
r = *a++;
}
*b += (r - *a + 4) >> 3;
}
a = lowpass;
b = highpass;
for (i = length >> 1; i; i--) {
s = *b++;
r = *a++;
*x++ = (r + s + 1) >> 1;
*x++ = (r - s + 1) >> 1;
}
}
static void synthesis_26_col(int length,
tran_low_t *lowpass, tran_low_t *highpass,
tran_low_t *x) {
tran_low_t r, s, *a, *b;
int i, n = length >> 1;
if (n >= 4) {
a = lowpass;
b = highpass;
r = *lowpass;
while (--n) {
*b++ += (r - a[1] + 4) >> 3;
r = *a++;
}
*b += (r - *a + 4) >> 3;
}
a = lowpass;
b = highpass;
for (i = length >> 1; i; i--) {
s = *b++;
r = *a++;
*x++ = r + s;
*x++ = r - s;
}
}
static void dyadic_synthesize_26(int levels, int width, int height,
tran_low_t *c, int pitch_c,
int16_t *x, int pitch_x,
int dwt_scale_bits) {
int th[16], tw[16], lv, i, j, nh, nw, hh = height, hw = width;
tran_low_t buffer[2 * DWT_MAX_LENGTH];
const int dwt_scale_rnd = 1 << (dwt_scale_bits - 1);
th[0] = hh;
tw[0] = hw;
for (i = 1; i <= levels; i++) {
th[i] = (th[i - 1] + 1) >> 1;
tw[i] = (tw[i - 1] + 1) >> 1;
}
for (lv = levels - 1; lv >= 0; lv--) {
nh = th[lv];
nw = tw[lv];
hh = th[lv + 1];
hw = tw[lv + 1];
if ((nh < 2) || (nw < 2)) continue;
for (j = 0; j < nw; j++) {
for (i = 0; i < nh; i++)
buffer[i] = c[i * pitch_c + j];
synthesis_26_col(nh, buffer, buffer + hh, buffer + nh);
for (i = 0; i < nh; i++)
c[i * pitch_c + j] = buffer[i + nh];
}
for (i = 0; i < nh; i++) {
memcpy(buffer, &c[i * pitch_c], nw * sizeof(*buffer));
synthesis_26_row(nw, buffer, buffer + hw, &c[i * pitch_c]);
}
}
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
x[i * pitch_x + j] = c[i * pitch_c + j] >= 0 ?
((c[i * pitch_c + j] + dwt_scale_rnd) >> dwt_scale_bits) :
-((-c[i * pitch_c + j] + dwt_scale_rnd) >> dwt_scale_bits);
}
}
}
static void synthesis_97(int length, double *lowpass, double *highpass,
double *x) {
const double a_predict1 = -1.586134342;
const double a_update1 = -0.05298011854;
const double a_predict2 = 0.8829110762;
const double a_update2 = 0.4435068522;
const double s_low = 1.149604398;
const double s_high = 1/1.149604398;
const double inv_s_low = 1 / s_low;
const double inv_s_high = 1 / s_high;
int i;
double y[DWT_MAX_LENGTH];
// Undo pack and scale
for (i = 0; i < length / 2; i++) {
y[i * 2] = lowpass[i] * inv_s_low;
y[i * 2 + 1] = highpass[i] * inv_s_high;
}
memcpy(x, y, sizeof(*y) * length);
// Undo update 2
for (i = 2; i < length; i += 2) {
x[i] -= a_update2 * (x[i - 1] + x[i + 1]);
}
x[0] -= 2 * a_update2 * x[1];
// Undo predict 2
for (i = 1; i < length - 2; i += 2) {
x[i] -= a_predict2 * (x[i - 1] + x[i + 1]);
}
x[length - 1] -= 2 * a_predict2 * x[length - 2];
// Undo update 1
for (i = 2; i < length; i += 2) {
x[i] -= a_update1 * (x[i - 1] + x[i + 1]);
}
x[0] -= 2 * a_update1 * x[1];
// Undo predict 1
for (i = 1; i < length - 2; i += 2) {
x[i] -= a_predict1 * (x[i - 1] + x[i + 1]);
}
x[length - 1] -= 2 * a_predict1 * x[length - 2];
}
static void dyadic_synthesize_97(int levels, int width, int height,
tran_low_t *c, int pitch_c,
int16_t *x, int pitch_x,
int dwt_scale_bits) {
int th[16], tw[16], lv, i, j, nh, nw, hh = height, hw = width;
double buffer[2 * DWT_MAX_LENGTH];
double y[DWT_MAX_LENGTH * DWT_MAX_LENGTH];
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
y[i * DWT_MAX_LENGTH + j] = c[i * pitch_c + j];
th[0] = hh;
tw[0] = hw;
for (i = 1; i <= levels; i++) {
th[i] = (th[i - 1] + 1) >> 1;
tw[i] = (tw[i - 1] + 1) >> 1;
}
for (lv = levels - 1; lv >= 0; lv--) {
nh = th[lv];
nw = tw[lv];
hh = th[lv + 1];
hw = tw[lv + 1];
if ((nh < 2) || (nw < 2)) continue;
for (j = 0; j < nw; j++) {
for (i = 0; i < nh; i++)
buffer[i] = y[i * DWT_MAX_LENGTH + j];
synthesis_97(nh, buffer, buffer + hh, buffer + nh);
for (i = 0; i < nh; i++)
y[i * DWT_MAX_LENGTH + j] = buffer[i + nh];
}
for (i = 0; i < nh; i++) {
memcpy(buffer, &y[i * DWT_MAX_LENGTH], nw * sizeof(*buffer));
synthesis_97(nw, buffer, buffer + hw, &y[i * DWT_MAX_LENGTH]);
}
}
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
x[i * pitch_x + j] = round(y[i * DWT_MAX_LENGTH + j] /
(1 << dwt_scale_bits));
}
void vp9_idwt32x32_c(const tran_low_t *input, tran_low_t *output, int stride) {
tran_low_t in[32 * 32];
vpx_memcpy(in, input, sizeof(in));
#if DWT_TYPE == 26
dyadic_synthesize_26(4, 32, 32, in, 32, output, stride, 2);
#elif DWT_TYPE == 97
dyadic_synthesize_97(4, 32, 32, in, 32, output, stride, 2);
#elif DWT_TYPE == 53
dyadic_synthesize_53(4, 32, 32, in, 32, output, stride, 2);
#endif
}
void vp9_idwtdct32x32_c(const tran_low_t *input, tran_low_t *output,
int stride) {
const int dwt_levels = 1;
tran_low_t buffer[16 * 16];
tran_low_t buffer2[32 * 32];
int i;
for (i = 0; i < 32; ++i) {
memcpy(&buffer2[i * 32], &input[i * 32], sizeof(buffer2[0]) * 32);
}
for (i = 0; i < 16; ++i) {
memcpy(&buffer[i * 16], &input[i * 32], sizeof(buffer[0]) * 16);
}
vp9_idct16x16_noscale(buffer, buffer2, 32);
#if DWT_TYPE == 26
dyadic_synthesize_26(dwt_levels, 32, 32, buffer2, 32, output, stride, 2);
#elif DWT_TYPE == 97
dyadic_synthesize_97(dwt_levels, 32, 32, buffer2, 32, output, stride, 2);
#elif DWT_TYPE == 53
dyadic_synthesize_53(dwt_levels, 32, 32, buffer2, 32, output, stride, 2);
#endif
}
void vp9_idwt32x32_add_c(const tran_low_t *input, uint8_t *dest, int stride) {
int i, j;
tran_low_t output[32 * 32];
vp9_idwt32x32_c(input, output, 32);
for (i = 0; i < 32; ++i) {
for (j = 0; j < 32; ++j) {
dest[j * stride + i] =
clip_pixel_add(dest[j * stride + i], output[j * 32 + i]);
}
}
}
void vp9_idwtdct32x32_add_c(const tran_low_t *input, uint8_t *dest,
int stride) {
int i, j;
tran_low_t output[32 * 32];
vp9_idwtdct32x32_c(input, output, 32);
for (i = 0; i < 32; ++i) {
for (j = 0; j < 32; ++j) {
dest[j * stride + i] =
clip_pixel_add(dest[j * stride + i], output[j * 32 + i]);
}
}
}
#if CONFIG_TX64X64
void vp9_idwt64x64_c(const tran_low_t *input, tran_low_t *output, int stride) {
tran_low_t in[64 * 64];
vpx_memcpy(in, input, sizeof(in));
#if DWT_TYPE == 26
dyadic_synthesize_26(4, 64, 64, in, 64, output, stride, 1);
#elif DWT_TYPE == 97
dyadic_synthesize_97(4, 64, 64, in, 64, output, stride, 1);
#elif DWT_TYPE == 53
dyadic_synthesize_53(4, 64, 64, in, 64, output, stride, 1);
#endif
}
void vp9_idwtdct64x64_c(const tran_low_t *input, tran_low_t *output,
int stride) {
const int dwt_levels = 1;
tran_low_t buffer[32 * 32];
tran_low_t buffer2[64 * 64];
int i;
for (i = 0; i < 64; ++i) {
memcpy(&buffer2[i * 64], &input[i * 64], sizeof(buffer2[0]) * 64);
}
for (i = 0; i < 32; ++i) {
memcpy(&buffer[i * 32], &input[i * 64], sizeof(buffer[0]) * 32);
}
vp9_idct32x32_noscale(buffer, buffer2, 64);
#if DWT_TYPE == 26
dyadic_synthesize_26(dwt_levels, 64, 64, buffer2, 64, output, stride, 1);
#elif DWT_TYPE == 97
dyadic_synthesize_97(dwt_levels, 64, 64, buffer2, 64, output, stride, 1);
#elif DWT_TYPE == 53
dyadic_synthesize_53(dwt_levels, 64, 64, buffer2, 64, output, stride, 1);
#endif
}
void vp9_idwt64x64_add_c(const tran_low_t *input, uint8_t *dest, int stride) {
int i, j;
tran_low_t output[64 * 64];
vp9_idwt64x64_c(input, output, 64);
for (i = 0; i < 64; ++i) {
for (j = 0; j < 64; ++j) {
dest[j * stride + i] =
clip_pixel_add(dest[j * stride + i], output[j * 64 + i]);
}
}
}
void vp9_idwtdct64x64_add_c(const tran_low_t *input, uint8_t *dest,
int stride) {
int i, j;
tran_low_t output[64 * 64];
vp9_idwtdct64x64_c(input, output, 64);
for (i = 0; i < 64; ++i) {
for (j = 0; j < 64; ++j) {
dest[j * stride + i] =
clip_pixel_add(dest[j * stride + i], output[j * 64 + i]);
}
}
}
#endif // CONFIG_TX64X64

39
vp9/common/vp9_idwt.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VP9_COMMON_VP9_IDWT_H_
#define VP9_COMMON_VP9_IDWT_H_
#include <assert.h>
#include "./vpx_config.h"
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_enums.h"
#include "vp9/common/vp9_idct.h"
#define DWT_MAX_LENGTH 64
#define DWT_TYPE 53 // 26/53/97
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_TX64X64
void vp9_idwt64x64(tran_low_t *input, tran_low_t *output, int stride);
void vp9_idwtdct64x64(tran_low_t *input, tran_low_t *output, int stride);
#endif // CONFIG_TX64X64
void vp9_idwt32x32(tran_low_t *input, tran_low_t *output, int stride);
void vp9_idwtdct32x32(tran_low_t *input, tran_low_t *output, int stride);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_COMMON_VP9_IDWT_H_

View File

@ -8,6 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include "./vpx_config.h"
#include "vp9/common/vp9_loopfilter.h"
#include "vp9/common/vp9_onyxc_int.h"
@ -38,6 +41,9 @@ static const uint64_t left_64x64_txform_mask[TX_SIZES]= {
0xffffffffffffffff, // TX_8x8
0x5555555555555555, // TX_16x16
0x1111111111111111, // TX_32x32
#if CONFIG_TX64X64
0x0101010101010101, // TX_64x64
#endif
};
// 64 bit masks for above transform size. Each 1 represents a position where
@ -62,6 +68,9 @@ static const uint64_t above_64x64_txform_mask[TX_SIZES]= {
0xffffffffffffffff, // TX_8x8
0x00ff00ff00ff00ff, // TX_16x16
0x000000ff000000ff, // TX_32x32
#if CONFIG_TX64X64
0x00000000000000ff, // TX_64x64
#endif
};
// 64 bit masks for prediction sizes (left). Each 1 represents a position
@ -140,6 +149,9 @@ static const uint16_t left_64x64_txform_mask_uv[TX_SIZES]= {
0xffff, // TX_8x8
0x5555, // TX_16x16
0x1111, // TX_32x32
#if CONFIG_TX64X64
0x0101, // TX_64x64, never used
#endif
};
static const uint16_t above_64x64_txform_mask_uv[TX_SIZES]= {
@ -147,6 +159,9 @@ static const uint16_t above_64x64_txform_mask_uv[TX_SIZES]= {
0xffff, // TX_8x8
0x0f0f, // TX_16x16
0x000f, // TX_32x32
#if CONFIG_TX64X64
0x0003, // TX_64x64, never used
#endif
};
// 16 bit left mask to shift and set for each uv prediction size.
@ -203,9 +218,258 @@ static const uint16_t above_border_uv = 0x000f;
static const int mode_lf_lut[MB_MODE_COUNT] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // INTRA_MODES
1, 1, 0, 1 // INTER_MODES (ZEROMV == 0)
#if CONFIG_INTRABC
0,
#endif // CONFIG_INTRABC
1, 1, 0, 1, // INTER_MODES (ZEROMV == 0)
#if CONFIG_NEW_INTER
1, // NEW2MV mode
1, 1, 1, 1, 1, 1, 1, 0, 1 // INTER_COMPOUND_MODES (ZERO_ZEROMV == 0)
#endif // CONFIG_NEW_INTER
};
#if CONFIG_LOOP_POSTFILTER
#define BILATERAL_WEIGHT_BITS 4
static double bilateral_filters_r_kf[BILATERAL_LEVELS_KF + 1][513];
static double bilateral_filters_r[BILATERAL_LEVELS + 1][513];
static double bilateral_filters_s_kf[BILATERAL_LEVELS_KF + 1]
[BILATERAL_WIN][BILATERAL_WIN];
static double bilateral_filters_s[BILATERAL_LEVELS + 1]
[BILATERAL_WIN][BILATERAL_WIN];
void vp9_loop_bilateral_precal() {
int i;
for (i = 1; i < BILATERAL_LEVELS_KF + 1; i ++) {
const bilateral_params_t param = vp9_bilateral_level_to_params(i, 1);
const int sigma_x = param.sigma_x;
const int sigma_y = param.sigma_y;
const int sigma_r = param.sigma_r;
const double sigma_r_d = (double)sigma_r / BILATERAL_PRECISION;
const double sigma_x_d = (double)sigma_x / BILATERAL_PRECISION;
const double sigma_y_d = (double)sigma_y / BILATERAL_PRECISION;
double *fr = bilateral_filters_r_kf[i] + 256;
int j, x, y;
for (j = 0; j <= 256; j++) {
fr[j] = exp(-(j * j) / (2 * sigma_r_d * sigma_r_d));
fr[-j] = fr[j];
}
for (y = -BILATERAL_HALFWIN; y <= BILATERAL_HALFWIN; y++) {
for (x = -BILATERAL_HALFWIN; x <= BILATERAL_HALFWIN; x++) {
bilateral_filters_s_kf[i][y + BILATERAL_HALFWIN]
[x + BILATERAL_HALFWIN] =
exp(-(x * x) / (2 * sigma_x_d * sigma_x_d)
-(y * y) / (2 * sigma_y_d * sigma_y_d));
}
}
}
for (i = 1; i < BILATERAL_LEVELS + 1; i ++) {
const bilateral_params_t param = vp9_bilateral_level_to_params(i, 0);
const int sigma_x = param.sigma_x;
const int sigma_y = param.sigma_y;
const int sigma_r = param.sigma_r;
const double sigma_r_d = (double)sigma_r / BILATERAL_PRECISION;
const double sigma_x_d = (double)sigma_x / BILATERAL_PRECISION;
const double sigma_y_d = (double)sigma_y / BILATERAL_PRECISION;
double *fr = bilateral_filters_r[i] + 256;
int j, x, y;
for (j = 0; j <= 256; j++) {
fr[j] = exp(-(j * j) / (2 * sigma_r_d * sigma_r_d));
fr[-j] = fr[j];
}
for (y = -BILATERAL_HALFWIN; y <= BILATERAL_HALFWIN; y++) {
for (x = -BILATERAL_HALFWIN; x <= BILATERAL_HALFWIN; x++) {
bilateral_filters_s[i][y + BILATERAL_HALFWIN][x + BILATERAL_HALFWIN] =
exp(-(x * x) / (2 * sigma_x_d * sigma_x_d)
-(y * y) / (2 * sigma_y_d * sigma_y_d));
}
}
}
}
int vp9_bilateral_level_bits(const VP9_COMMON *const cm) {
return cm->frame_type == KEY_FRAME ?
BILATERAL_LEVEL_BITS_KF : BILATERAL_LEVEL_BITS;
}
int vp9_loop_bilateral_used(int level, int kf) {
const bilateral_params_t param = vp9_bilateral_level_to_params(level, kf);
return (param.sigma_x && param.sigma_y && param.sigma_r);
}
void vp9_loop_bilateral_init(loop_filter_info_n *lfi, int level, int kf) {
lfi->bilateral_used = vp9_loop_bilateral_used(level, kf);
if (lfi->bilateral_used) {
int i;
lfi->wr_lut = kf ? bilateral_filters_r_kf[level] :
bilateral_filters_r[level];
for (i = 0; i < BILATERAL_WIN; i++)
lfi->wx_lut[i] = kf ? bilateral_filters_s_kf[level][i] :
bilateral_filters_s[level][i];
}
}
static int is_in_image(int x, int y, int width, int height) {
return (x >= 0 && x < width && y >= 0 && y < height);
}
void loop_bilateral_filter(uint8_t *data, int width, int height,
int stride, loop_filter_info_n *lfi,
uint8_t *tmpdata, int tmpstride) {
int i, j;
const double *wr_lut_ = lfi->wr_lut + 256;
uint8_t *data_p = data;
uint8_t *tmpdata_p = tmpdata;
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
int x, y;
double flsum = 0, wtsum = 0, wt;
uint8_t *data_p2 = data_p + j - BILATERAL_HALFWIN * stride;
for (y = -BILATERAL_HALFWIN; y <= BILATERAL_HALFWIN; ++y) {
for (x = -BILATERAL_HALFWIN; x <= BILATERAL_HALFWIN; ++x) {
if (!is_in_image(j + x, i + y, width, height))
continue;
wt = lfi->wx_lut[y + BILATERAL_HALFWIN][x + BILATERAL_HALFWIN] *
wr_lut_[data_p2[x] - data_p[j]];
wtsum += wt;
flsum += wt * data_p2[x];
}
data_p2 += stride;
}
assert(wtsum > 0);
tmpdata_p[j] = clip_pixel((int)(flsum / wtsum + 0.5));
}
tmpdata_p += tmpstride;
data_p += stride;
}
for (i = 0; i < height; ++i) {
vpx_memcpy(data + i * stride, tmpdata + i * tmpstride,
width * sizeof(*data));
}
}
#if CONFIG_VP9_HIGHBITDEPTH
void loop_bilateral_filter_highbd(uint8_t *data8, int width, int height,
int stride, loop_filter_info_n *lfi,
uint8_t *tmpdata8, int tmpstride, int bit_depth) {
int i, j;
const double *wr_lut_ = lfi->wr_lut + 256;
uint16_t *data = CONVERT_TO_SHORTPTR(data8);
uint16_t *tmpdata = CONVERT_TO_SHORTPTR(tmpdata8);
uint16_t *data_p = data;
uint16_t *tmpdata_p = tmpdata;
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
int x, y, diff_r;
double flsum = 0, wtsum = 0, wt;
uint16_t *data_p2 = data_p + j - BILATERAL_HALFWIN * stride;
for (y = -BILATERAL_HALFWIN; y <= BILATERAL_HALFWIN; ++y) {
for (x = -BILATERAL_HALFWIN; x <= BILATERAL_HALFWIN; ++x) {
if (!is_in_image(j + x, i + y, width, height))
continue;
diff_r = (data_p2[x] - data_p[j]) >> (bit_depth - 8);
assert(diff_r >= -256 && diff_r <= 256);
wt = lfi->wx_lut[y + BILATERAL_HALFWIN][x + BILATERAL_HALFWIN] *
wr_lut_[diff_r];
wtsum += wt;
flsum += wt * data_p2[x];
}
data_p2 += stride;
}
assert(wtsum > 0);
tmpdata_p[j] = (int)(flsum / wtsum + 0.5);
}
tmpdata_p += tmpstride;
data_p += stride;
}
for (i = 0; i < height; ++i) {
vpx_memcpy(data + i * stride, tmpdata + i * tmpstride,
width * sizeof(*data));
}
}
#endif // CONFIG_VP9_HIGHBITDEPTH
void vp9_loop_bilateral_rows(YV12_BUFFER_CONFIG *frame,
VP9_COMMON *cm,
int start_mi_row, int end_mi_row,
int y_only) {
const int ywidth = frame->y_crop_width;
const int ystride = frame->y_stride;
const int uvwidth = frame->uv_crop_width;
const int uvstride = frame->uv_stride;
const int ystart = start_mi_row << MI_SIZE_LOG2;
const int uvstart = ystart >> cm->subsampling_y;
int yend = end_mi_row << MI_SIZE_LOG2;
int uvend = yend >> cm->subsampling_y;
YV12_BUFFER_CONFIG *tmp_buf;
yend = MIN(yend, cm->height);
uvend = MIN(uvend, cm->subsampling_y ? (cm->height + 1) >> 1 : cm->height);
if (vp9_realloc_frame_buffer(&cm->tmp_loop_buf, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif // CONFIG_VP9_HIGHBITDEPTH
0, NULL, NULL, NULL) < 0)
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate post-processing buffer");
tmp_buf = &cm->tmp_loop_buf;
#if CONFIG_VP9_HIGHBITDEPTH
if (cm->use_highbitdepth)
loop_bilateral_filter_highbd(frame->y_buffer + ystart * ystride,
ywidth, yend - ystart, ystride, &cm->lf_info,
tmp_buf->y_buffer + ystart * tmp_buf->y_stride,
tmp_buf->y_stride, cm->bit_depth);
else
#endif // CONFIG_VP9_HIGHBITDEPTH
loop_bilateral_filter(frame->y_buffer + ystart * ystride,
ywidth, yend - ystart, ystride, &cm->lf_info,
tmp_buf->y_buffer + ystart * tmp_buf->y_stride,
tmp_buf->y_stride);
if (!y_only) {
#if CONFIG_VP9_HIGHBITDEPTH
if (cm->use_highbitdepth) {
loop_bilateral_filter_highbd(frame->u_buffer + uvstart * uvstride,
uvwidth, uvend - uvstart, uvstride, &cm->lf_info,
tmp_buf->u_buffer + uvstart * tmp_buf->uv_stride,
tmp_buf->uv_stride, cm->bit_depth);
loop_bilateral_filter_highbd(frame->v_buffer + uvstart * uvstride,
uvwidth, uvend - uvstart, uvstride, &cm->lf_info,
tmp_buf->v_buffer + uvstart * tmp_buf->uv_stride,
tmp_buf->uv_stride, cm->bit_depth);
} else {
#endif // CONFIG_VP9_HIGHBITDEPTH
loop_bilateral_filter(frame->u_buffer + uvstart * uvstride,
uvwidth, uvend - uvstart, uvstride, &cm->lf_info,
tmp_buf->u_buffer + uvstart * tmp_buf->uv_stride,
tmp_buf->uv_stride);
loop_bilateral_filter(frame->v_buffer + uvstart * uvstride,
uvwidth, uvend - uvstart, uvstride, &cm->lf_info,
tmp_buf->v_buffer + uvstart * tmp_buf->uv_stride,
tmp_buf->uv_stride);
#if CONFIG_VP9_HIGHBITDEPTH
}
#endif // CONFIG_VP9_HIGHBITDEPTH
}
}
#endif // CONFIG_LOOP_POSTFILTER
static void update_sharpness(loop_filter_info_n *lfi, int sharpness_lvl) {
int lvl;
@ -246,6 +510,10 @@ void vp9_loop_filter_init(VP9_COMMON *cm) {
// init hev threshold const vectors
for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++)
vpx_memset(lfi->lfthr[lvl].hev_thr, (lvl >> 4), SIMD_WIDTH);
#if CONFIG_LOOP_POSTFILTER
vp9_loop_bilateral_precal();
#endif // CONFIG_LOOP_POSTFILTER
}
void vp9_loop_filter_frame_init(VP9_COMMON *cm, int default_filt_lvl) {
@ -702,14 +970,16 @@ static void highbd_filter_selectively_horiz(uint16_t *s, int pitch,
// block we are currently looking at. Shift is used to position the
// 1's we produce.
// TODO(JBB) Need another function for different resolution color..
static void build_masks(const loop_filter_info_n *const lfi_n,
static void build_masks(const VP9_COMMON *const cm,
const MODE_INFO *mi, const int shift_y,
const int shift_uv,
LOOP_FILTER_MASK *lfm) {
const loop_filter_info_n *const lfi_n = &cm->lf_info;
const MB_MODE_INFO *mbmi = &mi->mbmi;
const BLOCK_SIZE block_size = mbmi->sb_type;
const TX_SIZE tx_size_y = mbmi->tx_size;
const TX_SIZE tx_size_uv = get_uv_tx_size_impl(tx_size_y, block_size, 1, 1);
const TX_SIZE tx_size_uv = get_uv_tx_size_impl(
tx_size_y, block_size, cm->subsampling_x, cm->subsampling_y);
const int filter_level = get_filter_level(lfi_n, mbmi);
uint64_t *const left_y = &lfm->left_y[tx_size_y];
uint64_t *const above_y = &lfm->above_y[tx_size_y];
@ -782,12 +1052,21 @@ static void build_masks(const loop_filter_info_n *const lfi_n,
// This function does the same thing as the one above with the exception that
// it only affects the y masks. It exists because for blocks < 16x16 in size,
// we only update u and v masks on the first block.
static void build_y_mask(const loop_filter_info_n *const lfi_n,
static void build_y_mask(const VP9_COMMON *const cm,
const MODE_INFO *mi, const int shift_y,
#if CONFIG_SUPERTX
int supertx_enabled,
#endif
LOOP_FILTER_MASK *lfm) {
const loop_filter_info_n *const lfi_n = &cm->lf_info;
const MB_MODE_INFO *mbmi = &mi->mbmi;
const BLOCK_SIZE block_size = mbmi->sb_type;
const TX_SIZE tx_size_y = mbmi->tx_size;
#if CONFIG_SUPERTX
const BLOCK_SIZE block_size =
supertx_enabled ? (BLOCK_SIZE)(3 * tx_size_y) : mbmi->sb_type;
#else
const BLOCK_SIZE block_size = mbmi->sb_type;
#endif
const int filter_level = get_filter_level(lfi_n, mbmi);
uint64_t *const left_y = &lfm->left_y[tx_size_y];
uint64_t *const above_y = &lfm->above_y[tx_size_y];
@ -829,7 +1108,6 @@ void vp9_setup_mask(VP9_COMMON *const cm, const int mi_row, const int mi_col,
MODE_INFO *mi, const int mode_info_stride,
LOOP_FILTER_MASK *lfm) {
int idx_32, idx_16, idx_8;
const loop_filter_info_n *const lfi_n = &cm->lf_info;
MODE_INFO *mip = mi;
MODE_INFO *mip2 = mi;
@ -866,23 +1144,36 @@ void vp9_setup_mask(VP9_COMMON *const cm, const int mi_row, const int mi_col,
// through the recursive loop structure multiple times.
switch (mip->mbmi.sb_type) {
case BLOCK_64X64:
build_masks(lfi_n, mip , 0, 0, lfm);
build_masks(cm, mip, 0, 0, lfm);
break;
case BLOCK_64X32:
build_masks(lfi_n, mip, 0, 0, lfm);
build_masks(cm, mip, 0, 0, lfm);
#if CONFIG_SUPERTX && CONFIG_TX64X64
if (supertx_enabled(&mip->mbmi))
break;
#endif
mip2 = mip + mode_info_stride * 4;
if (4 >= max_rows)
break;
build_masks(lfi_n, mip2, 32, 8, lfm);
build_masks(cm, mip2, 32, 8, lfm);
break;
case BLOCK_32X64:
build_masks(lfi_n, mip, 0, 0, lfm);
build_masks(cm, mip, 0, 0, lfm);
#if CONFIG_SUPERTX && CONFIG_TX64X64
if (supertx_enabled(&mip->mbmi))
break;
#endif
mip2 = mip + 4;
if (4 >= max_cols)
break;
build_masks(lfi_n, mip2, 4, 2, lfm);
build_masks(cm, mip2, 4, 2, lfm);
break;
default:
#if CONFIG_SUPERTX && CONFIG_TX64X64
if (mip->mbmi.tx_size == TX_64X64) {
build_masks(cm, mip, 0, 0, lfm);
} else {
#endif
for (idx_32 = 0; idx_32 < 4; mip += offset_32[idx_32], ++idx_32) {
const int shift_y = shift_32_y[idx_32];
const int shift_uv = shift_32_uv[idx_32];
@ -892,23 +1183,36 @@ void vp9_setup_mask(VP9_COMMON *const cm, const int mi_row, const int mi_col,
continue;
switch (mip->mbmi.sb_type) {
case BLOCK_32X32:
build_masks(lfi_n, mip, shift_y, shift_uv, lfm);
build_masks(cm, mip, shift_y, shift_uv, lfm);
break;
case BLOCK_32X16:
build_masks(lfi_n, mip, shift_y, shift_uv, lfm);
build_masks(cm, mip, shift_y, shift_uv, lfm);
#if CONFIG_SUPERTX
if (supertx_enabled(&mip->mbmi))
break;
#endif
if (mi_32_row_offset + 2 >= max_rows)
continue;
mip2 = mip + mode_info_stride * 2;
build_masks(lfi_n, mip2, shift_y + 16, shift_uv + 4, lfm);
build_masks(cm, mip2, shift_y + 16, shift_uv + 4, lfm);
break;
case BLOCK_16X32:
build_masks(lfi_n, mip, shift_y, shift_uv, lfm);
build_masks(cm, mip, shift_y, shift_uv, lfm);
#if CONFIG_SUPERTX
if (supertx_enabled(&mip->mbmi))
break;
#endif
if (mi_32_col_offset + 2 >= max_cols)
continue;
mip2 = mip + 2;
build_masks(lfi_n, mip2, shift_y + 2, shift_uv + 1, lfm);
build_masks(cm, mip2, shift_y + 2, shift_uv + 1, lfm);
break;
default:
#if CONFIG_SUPERTX
if (mip->mbmi.tx_size == TX_32X32) {
build_masks(cm, mip, shift_y, shift_uv, lfm);
} else {
#endif
for (idx_16 = 0; idx_16 < 4; mip += offset_16[idx_16], ++idx_16) {
const int shift_y = shift_32_y[idx_32] + shift_16_y[idx_16];
const int shift_uv = shift_32_uv[idx_32] + shift_16_uv[idx_16];
@ -922,27 +1226,48 @@ void vp9_setup_mask(VP9_COMMON *const cm, const int mi_row, const int mi_col,
switch (mip->mbmi.sb_type) {
case BLOCK_16X16:
build_masks(lfi_n, mip, shift_y, shift_uv, lfm);
build_masks(cm, mip, shift_y, shift_uv, lfm);
break;
case BLOCK_16X8:
build_masks(lfi_n, mip, shift_y, shift_uv, lfm);
build_masks(cm, mip, shift_y, shift_uv, lfm);
#if CONFIG_SUPERTX
if (supertx_enabled(&mip->mbmi))
break;
#endif
if (mi_16_row_offset + 1 >= max_rows)
continue;
mip2 = mip + mode_info_stride;
build_y_mask(lfi_n, mip2, shift_y+8, lfm);
build_y_mask(cm, mip2, shift_y + 8,
#if CONFIG_SUPERTX
0,
#endif
lfm);
break;
case BLOCK_8X16:
build_masks(lfi_n, mip, shift_y, shift_uv, lfm);
build_masks(cm, mip, shift_y, shift_uv, lfm);
#if CONFIG_SUPERTX
if (supertx_enabled(&mip->mbmi))
break;
#endif
if (mi_16_col_offset +1 >= max_cols)
continue;
mip2 = mip + 1;
build_y_mask(lfi_n, mip2, shift_y+1, lfm);
build_y_mask(cm, mip2, shift_y + 1,
#if CONFIG_SUPERTX
0,
#endif
lfm);
break;
default: {
#if CONFIG_SUPERTX
if (mip->mbmi.tx_size == TX_16X16) {
build_masks(cm, mip, shift_y, shift_uv, lfm);
} else {
#endif
const int shift_y = shift_32_y[idx_32] +
shift_16_y[idx_16] +
shift_8_y[0];
build_masks(lfi_n, mip, shift_y, shift_uv, lfm);
build_masks(cm, mip, shift_y, shift_uv, lfm);
mip += offset[0];
for (idx_8 = 1; idx_8 < 4; mip += offset[idx_8], ++idx_8) {
const int shift_y = shift_32_y[idx_32] +
@ -956,15 +1281,28 @@ void vp9_setup_mask(VP9_COMMON *const cm, const int mi_row, const int mi_col,
if (mi_8_col_offset >= max_cols ||
mi_8_row_offset >= max_rows)
continue;
build_y_mask(lfi_n, mip, shift_y, lfm);
build_y_mask(cm, mip, shift_y,
#if CONFIG_SUPERTX
supertx_enabled(&mip->mbmi),
#endif
lfm);
}
#if CONFIG_SUPERTX
}
#endif
break;
}
}
}
#if CONFIG_SUPERTX
}
#endif
break;
}
}
#if CONFIG_SUPERTX && CONFIG_TX64X64
}
#endif
break;
}
// The largest loopfilter we have is 16x16 so we use the 16x16 mask
@ -1193,7 +1531,7 @@ static void filter_block_plane_non420(VP9_COMMON *cm,
const int skip_border_4x4_r = ss_y && mi_row + r == cm->mi_rows - 1;
// Filter level can vary per MI
if (!(lfl[(r << 3) + (c >> ss_x)] =
if (!(lfl[(r << MI_BLOCK_SIZE_LOG2) + (c >> ss_x)] =
get_filter_level(&cm->lf_info, &mi[0].mbmi)))
continue;
@ -1255,7 +1593,8 @@ static void filter_block_plane_non420(VP9_COMMON *cm,
mask_8x8_c & border_mask,
mask_4x4_c & border_mask,
mask_4x4_int[r],
&cm->lf_info, &lfl[r << 3],
&cm->lf_info,
&lfl[r << MI_BLOCK_SIZE_LOG2],
(int)cm->bit_depth);
} else {
filter_selectively_vert(dst->buf, dst->stride,
@ -1263,7 +1602,7 @@ static void filter_block_plane_non420(VP9_COMMON *cm,
mask_8x8_c & border_mask,
mask_4x4_c & border_mask,
mask_4x4_int[r],
&cm->lf_info, &lfl[r << 3]);
&cm->lf_info, &lfl[r << MI_BLOCK_SIZE_LOG2]);
}
#else
filter_selectively_vert(dst->buf, dst->stride,
@ -1271,7 +1610,7 @@ static void filter_block_plane_non420(VP9_COMMON *cm,
mask_8x8_c & border_mask,
mask_4x4_c & border_mask,
mask_4x4_int[r],
&cm->lf_info, &lfl[r << 3]);
&cm->lf_info, &lfl[r << MI_BLOCK_SIZE_LOG2]);
#endif // CONFIG_VP9_HIGHBITDEPTH
dst->buf += 8 * dst->stride;
mi_8x8 += row_step_stride;
@ -1304,7 +1643,8 @@ static void filter_block_plane_non420(VP9_COMMON *cm,
mask_8x8_r,
mask_4x4_r,
mask_4x4_int_r,
&cm->lf_info, &lfl[r << 3],
&cm->lf_info,
&lfl[r << MI_BLOCK_SIZE_LOG2],
(int)cm->bit_depth);
} else {
filter_selectively_horiz(dst->buf, dst->stride,
@ -1312,7 +1652,7 @@ static void filter_block_plane_non420(VP9_COMMON *cm,
mask_8x8_r,
mask_4x4_r,
mask_4x4_int_r,
&cm->lf_info, &lfl[r << 3]);
&cm->lf_info, &lfl[r << MI_BLOCK_SIZE_LOG2]);
}
#else
filter_selectively_horiz(dst->buf, dst->stride,
@ -1320,7 +1660,7 @@ static void filter_block_plane_non420(VP9_COMMON *cm,
mask_8x8_r,
mask_4x4_r,
mask_4x4_int_r,
&cm->lf_info, &lfl[r << 3]);
&cm->lf_info, &lfl[r << MI_BLOCK_SIZE_LOG2]);
#endif // CONFIG_VP9_HIGHBITDEPTH
dst->buf += 8 * dst->stride;
}
@ -1576,8 +1916,12 @@ void vp9_loop_filter_rows(YV12_BUFFER_CONFIG *frame_buffer,
struct macroblockd_plane planes[MAX_MB_PLANE],
int start, int stop, int y_only) {
const int num_planes = y_only ? 1 : MAX_MB_PLANE;
#if CONFIG_EXT_PARTITION || CONFIG_EXT_CODING_UNIT_SIZE
const int use_420 = 0;
#else
const int use_420 = y_only || (planes[1].subsampling_y == 1 &&
planes[1].subsampling_x == 1);
#endif
LOOP_FILTER_MASK lfm;
int mi_row, mi_col;
@ -1610,7 +1954,8 @@ void vp9_loop_filter_frame(YV12_BUFFER_CONFIG *frame,
int frame_filter_level,
int y_only, int partial_frame) {
int start_mi_row, end_mi_row, mi_rows_to_filter;
if (!frame_filter_level) return;
if (!frame_filter_level)
return;
start_mi_row = 0;
mi_rows_to_filter = cm->mi_rows;
if (partial_frame && cm->mi_rows > 8) {
@ -1619,15 +1964,45 @@ void vp9_loop_filter_frame(YV12_BUFFER_CONFIG *frame,
mi_rows_to_filter = MAX(cm->mi_rows / 8, 8);
}
end_mi_row = start_mi_row + mi_rows_to_filter;
vp9_loop_filter_frame_init(cm, frame_filter_level);
vp9_loop_filter_rows(frame, cm, xd->plane,
start_mi_row, end_mi_row,
y_only);
if (frame_filter_level) {
vp9_loop_filter_frame_init(cm, frame_filter_level);
vp9_loop_filter_rows(frame, cm, xd->plane,
start_mi_row, end_mi_row,
y_only);
}
}
#if CONFIG_LOOP_POSTFILTER
void vp9_loop_bilateral_frame(YV12_BUFFER_CONFIG *frame,
VP9_COMMON *cm,
int bilateral_level,
int y_only, int partial_frame) {
int start_mi_row, end_mi_row, mi_rows_to_filter;
const int loop_bilateral_used = vp9_loop_bilateral_used(
bilateral_level, cm->frame_type == KEY_FRAME);
if (!loop_bilateral_used)
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 = MAX(cm->mi_rows / 8, 8);
}
end_mi_row = start_mi_row + mi_rows_to_filter;
if (loop_bilateral_used) {
vp9_loop_bilateral_init(&cm->lf_info, bilateral_level,
cm->frame_type == KEY_FRAME);
vp9_loop_bilateral_rows(frame, cm, start_mi_row, end_mi_row, y_only);
}
}
#endif // CONFIG_LOOP_POSTFILTER
int vp9_loop_filter_worker(LFWorkerData *const lf_data, void *unused) {
(void)unused;
vp9_loop_filter_rows(lf_data->frame_buffer, lf_data->cm, lf_data->planes,
lf_data->start, lf_data->stop, lf_data->y_only);
if (lf_data->cm->lf.filter_level) {
vp9_loop_filter_rows(lf_data->frame_buffer, lf_data->cm, lf_data->planes,
lf_data->start, lf_data->stop, lf_data->y_only);
}
return 1;
}

View File

@ -26,9 +26,79 @@ extern "C" {
#define SIMD_WIDTH 16
#if CONFIG_MULTI_REF
#define MAX_REF_LF_DELTAS 7
#else // CONFIG_MULTI_REF
#define MAX_REF_LF_DELTAS 4
#endif // CONFIG_MULTI_REF
#define MAX_MODE_LF_DELTAS 2
struct VP9Common;
#if CONFIG_LOOP_POSTFILTER
#define BILATERAL_LEVEL_BITS_KF 4
#define BILATERAL_LEVELS_KF (1 << BILATERAL_LEVEL_BITS_KF)
#define BILATERAL_LEVEL_BITS 3
#define BILATERAL_LEVELS (1 << BILATERAL_LEVEL_BITS)
#define DEF_BILATERAL_LEVEL 2
#define BILATERAL_PRECISION 16
#define BILATERAL_HALFWIN 3
#define BILATERAL_WIN (2 * BILATERAL_HALFWIN + 1)
typedef struct bilateral_params {
int sigma_x; // spatial variance x
int sigma_y; // spatial variance y
int sigma_r; // range variance
} bilateral_params_t;
static bilateral_params_t
bilateral_level_to_params_arr[BILATERAL_LEVELS + 1] = {
// Values are rounded to 1/16 th precision
{0, 0, 0}, // 0 - default
{8, 9, 30},
{9, 8, 30},
{9, 11, 32},
{11, 9, 32},
{14, 14, 32},
{18, 18, 36},
{24, 24, 40},
{32, 32, 40},
};
static bilateral_params_t
bilateral_level_to_params_arr_kf[BILATERAL_LEVELS_KF + 1] = {
// Values are rounded to 1/16 th precision
{0, 0, 0}, // 0 - default
{8, 8, 30},
{9, 9, 32},
{10, 10, 32},
{12, 12, 32},
{14, 14, 32},
{18, 18, 36},
{24, 24, 40},
{30, 30, 44},
{36, 36, 48},
{42, 42, 48},
{48, 48, 48},
{48, 48, 56},
{56, 56, 48},
{56, 56, 56},
{56, 56, 64},
{64, 64, 48},
};
int vp9_bilateral_level_bits(const struct VP9Common *const cm);
int vp9_loop_bilateral_used(int level, int kf);
static INLINE bilateral_params_t vp9_bilateral_level_to_params(
int index, int kf) {
return kf ? bilateral_level_to_params_arr_kf[index] :
bilateral_level_to_params_arr[index];
}
#endif // CONFIG_LOOP_POSTFILTER
struct loopfilter {
int filter_level;
@ -38,13 +108,19 @@ struct loopfilter {
uint8_t mode_ref_delta_enabled;
uint8_t mode_ref_delta_update;
// 0 = Intra, Last, GF, ARF
// 0 = Intra, Last, Last2+Last3+Last4(CONFIG_MULTI_REF),
// GF, ARF
signed char ref_deltas[MAX_REF_LF_DELTAS];
signed char last_ref_deltas[MAX_REF_LF_DELTAS];
// 0 = ZERO_MV, MV
signed char mode_deltas[MAX_MODE_LF_DELTAS];
signed char last_mode_deltas[MAX_MODE_LF_DELTAS];
#if CONFIG_LOOP_POSTFILTER
int bilateral_level;
int last_bilateral_level;
#endif
};
// Need to align this structure so when it is declared and
@ -58,6 +134,14 @@ typedef struct {
typedef struct {
loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS];
#if CONFIG_LOOP_POSTFILTER
double * wx_lut[BILATERAL_WIN];
double * wr_lut;
int bilateral_sigma_x_set;
int bilateral_sigma_y_set;
int bilateral_sigma_r_set;
int bilateral_used;
#endif
} loop_filter_info_n;
// This structure holds bit masks for all 8x8 blocks in a 64x64 region.
@ -76,12 +160,11 @@ typedef struct {
uint16_t left_uv[TX_SIZES];
uint16_t above_uv[TX_SIZES];
uint16_t int_4x4_uv;
uint8_t lfl_y[64];
uint8_t lfl_uv[16];
uint8_t lfl_y[MI_BLOCK_SIZE * MI_BLOCK_SIZE];
uint8_t lfl_uv[MI_BLOCK_SIZE / 2 * MI_BLOCK_SIZE / 2];
} LOOP_FILTER_MASK;
/* assorted loopfilter functions which get used elsewhere */
struct VP9Common;
struct macroblockd;
struct VP9LfSyncData;
@ -115,6 +198,24 @@ void vp9_loop_filter_rows(YV12_BUFFER_CONFIG *frame_buffer,
struct VP9Common *cm,
struct macroblockd_plane planes[MAX_MB_PLANE],
int start, int stop, int y_only);
#if CONFIG_LOOP_POSTFILTER
void vp9_loop_bilateral_frame(YV12_BUFFER_CONFIG *frame,
struct VP9Common *cm,
int bilateral_level,
int y_only, int partial_frame);
void vp9_loop_filter_bilateral_frame(YV12_BUFFER_CONFIG *frame,
struct VP9Common *cm,
struct macroblockd *mbd,
int frame_filter_level,
int bilateral_level,
int y_only, int partial_frame);
void vp9_loop_bilateral_init(loop_filter_info_n *lfi, int T, int kf);
void vp9_loop_bilateral_rows(YV12_BUFFER_CONFIG *frame,
struct VP9Common *cm,
int start_mi_row, int end_mi_row,
int y_only);
#endif // CONFIG_LOOP_POSTFILTER
typedef struct LoopFilterWorkerData {
YV12_BUFFER_CONFIG *frame_buffer;

View File

@ -0,0 +1,386 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be
* found in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#include <assert.h>
#include "vp9/common/vp9_common_data.h"
#include "vp9/common/vp9_mv.h"
#include "vp9/common/vp9_motion_model.h"
inline projectPointsType get_projectPointsType(TransformationType type) {
switch (type) {
case HOMOGRAPHY:
return projectPointsHomography;
case AFFINE:
return projectPointsAffine;
case ROTZOOM:
return projectPointsRotZoom;
case TRANSLATION:
return projectPointsTranslation;
default:
assert(0);
return NULL;
}
}
void projectPointsTranslation(double *mat, double *points, double *proj,
const int n,
const int stride_points,
const int stride_proj) {
int i;
for (i = 0; i < n; ++i) {
const double x = *(points++), y = *(points++);
*(proj++) = x + mat[0];
*(proj++) = y + mat[1];
points += stride_points - 2;
proj += stride_proj - 2;
}
}
void projectPointsRotZoom(double *mat, double *points,
double *proj, const int n,
const int stride_points, const int stride_proj) {
int i;
for (i = 0; i < n; ++i) {
const double x = *(points++), y = *(points++);
*(proj++) = mat[0] * x + mat[1] * y + mat[2];
*(proj++) = -mat[1] * x + mat[0] * y + mat[3];
points += stride_points - 2;
proj += stride_proj - 2;
}
}
void projectPointsAffine(double *mat, double *points,
double *proj, const int n,
const int stride_points, const int stride_proj) {
int i;
for (i = 0; i < n; ++i) {
const double x = *(points++), y = *(points++);
*(proj++) = mat[0] * x + mat[1] * y + mat[4];
*(proj++) = mat[2] * x + mat[3] * y + mat[5];
points += stride_points - 2;
proj += stride_proj - 2;
}
}
void projectPointsHomography(double *mat, double *points,
double *proj, const int n,
const int stride_points, const int stride_proj) {
int i;
double x, y, Z;
for (i = 0; i < n; ++i) {
x = *(points++), y = *(points++);
Z = 1. / (mat[6] * x + mat[7] * y + mat[8]);
*(proj++) = (mat[0] * x + mat[1] * y + mat[2]) * Z;
*(proj++) = (mat[3] * x + mat[4] * y + mat[5]) * Z;
points += stride_points - 2;
proj += stride_proj - 2;
}
}
#define clip_pixel(v) ((v) < 0 ? 0 : ((v) > 255 ? 255 : (v)))
double getCubicValue(double p[4], double x) {
return p[1] + 0.5 * x * (p[2] - p[0]
+ x * (2.0 * p[0] - 5.0 * p[1] + 4.0 * p[2] - p[3]
+ x * (3.0 * (p[1] - p[2]) + p[3] - p[0])));
}
void get_subcolumn(unsigned char *ref, double col[4],
int stride, int x, int y_start) {
int i;
for (i = 0; i < 4; ++i) {
col[i] = ref[(i + y_start) * stride + x];
}
}
double bicubic(unsigned char *ref, double x, double y, int stride) {
double arr[4];
int k;
int i = (int) x;
int j = (int) y;
for (k = 0; k < 4; ++k) {
double arr_temp[4];
get_subcolumn(ref, arr_temp, stride, i + k - 1, j - 1);
arr[k] = getCubicValue(arr_temp, y - j);
}
return getCubicValue(arr, x - i);
}
unsigned char interpolate(unsigned char *ref, double x, double y,
int width, int height, int stride) {
if (x < 0 && y < 0) return ref[0];
else if (x < 0 && y > height - 1)
return ref[(height - 1) * stride];
else if (x > width - 1 && y < 0)
return ref[width - 1];
else if (x > width - 1 && y > height - 1)
return ref[(height - 1) * stride + (width - 1)];
else if (x < 0) {
int v;
int i = (int) y;
double a = y - i;
if (y > 1 && y < height - 2) {
double arr[4];
get_subcolumn(ref, arr, stride, 0, i - 1);
return clip_pixel(getCubicValue(arr, a));
}
v = (int)(ref[i * stride] * (1 - a) + ref[(i + 1) * stride] * a + 0.5);
return clip_pixel(v);
} else if (y < 0) {
int v;
int j = (int) x;
double b = x - j;
if (x > 1 && x < width - 2) {
double arr[4] = {ref[j - 1], ref[j], ref[j + 1], ref[j + 2]};
return clip_pixel(getCubicValue(arr, b));
}
v = (int)(ref[j] * (1 - b) + ref[j + 1] * b + 0.5);
return clip_pixel(v);
} else if (x > width - 1) {
int v;
int i = (int) y;
double a = y - i;
if (y > 1 && y < height - 2) {
double arr[4];
get_subcolumn(ref, arr, stride, width - 1, i - 1);
return clip_pixel(getCubicValue(arr, a));
}
v = (int)(ref[i * stride + width - 1] * (1 - a) +
ref[(i + 1) * stride + width - 1] * a + 0.5);
return clip_pixel(v);
} else if (y > height - 1) {
int v;
int j = (int) x;
double b = x - j;
if (x > 1 && x < width - 2) {
int row = (height - 1) * stride;
double arr[4] = {ref[row + j - 1], ref[row + j],
ref[row + j + 1], ref[row + j + 2]};
return clip_pixel(getCubicValue(arr, b));
}
v = (int)(ref[(height - 1) * stride + j] * (1 - b) +
ref[(height - 1) * stride + j + 1] * b + 0.5);
return clip_pixel(v);
} else if (x > 1 && y > 1 && x < width -2 && y < height -2) {
return clip_pixel(bicubic(ref, x, y, stride));
} else {
int i = (int) y;
int j = (int) x;
double a = y - i;
double b = x - j;
int v = (int)(ref[i * stride + j] * (1 - a) * (1 - b) +
ref[i * stride + j + 1] * (1 - a) * b +
ref[(i + 1) * stride + j] * a * (1 - b) +
ref[(i + 1) * stride + j + 1] * a * b);
return clip_pixel(v);
}
}
static void WarpImage(TransformationType type, double *H,
unsigned char *ref,
int width, int height, int stride,
unsigned char *pred,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
int i, j;
projectPointsType projectPoints = get_projectPointsType(type);
if (projectPoints == NULL)
return;
for (i = p_row; i < p_row + p_height; ++i) {
for (j = p_col; j < p_col + p_width; ++j) {
double in[2], out[2];
in[0] = subsampling_col ? 2 * j + 0.5 : j;
in[1] = subsampling_row ? 2 * i + 0.5 : i;
projectPoints(H, in, out, 1, 2, 2);
out[0] = subsampling_col ? (out[0] - 0.5) / 2.0 : out[0];
out[1] = subsampling_row ? (out[1] - 0.5) / 2.0 : out[1];
out[0] *= x_scale / 16.0;
out[1] *= y_scale / 16.0;
pred[(j - p_col) + (i - p_row) * p_stride] =
interpolate(ref, out[0], out[1], width, height, stride);
}
}
}
double compute_warp_and_error(Global_Motion_Params *gm,
projectPointsType projectPoints,
unsigned char *ref,
int width, int height, int stride,
unsigned char *src,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
double H[9];
int i, j;
int64_t sumerr = 0;
if (projectPoints == NULL)
return -1;
vp9_convert_params_to_rotzoom(gm, H);
for (i = p_row; i < p_row + p_height; ++i) {
for (j = p_col; j < p_col + p_width; ++j) {
double in[2], out[2];
uint8_t pred;
int err;
in[0] = subsampling_col ? 2 * j + 0.5 : j;
in[1] = subsampling_row ? 2 * i + 0.5 : i;
projectPoints(H, in, out, 1, 2, 2);
out[0] = subsampling_col ? (out[0] - 0.5) / 2.0 : out[0];
out[1] = subsampling_row ? (out[1] - 0.5) / 2.0 : out[1];
out[0] *= x_scale / 16.0;
out[1] *= y_scale / 16.0;
pred = interpolate(ref, out[0], out[1], width, height, stride);
err = pred - src[(j - p_col) + (i - p_row) * p_stride];
sumerr += err * err;
}
}
return sumerr/(width * height);
}
// Computes the ratio of the warp error to the zero motion error
double vp9_warp_erroradv_unq(TransformationType type, double *H,
unsigned char *ref,
int width, int height, int stride,
unsigned char *src,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
double H_z_translation[] = {0, 0};
double H_z_rotzoom[] = {1, 0, 0, 0};
double H_z_affine[] = {1, 0, 0, 1, 0, 0};
double H_z_homography[] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
double *H_z = H_z_rotzoom;
int i, j;
int64_t sumerr = 0;
int64_t sumerr_z = 0;
projectPointsType projectPoints = get_projectPointsType(type);
if (type == TRANSLATION)
H_z = H_z_translation;
else if (type == ROTZOOM)
H_z = H_z_rotzoom;
else if (type == AFFINE)
H_z = H_z_affine;
else if (type == HOMOGRAPHY)
H_z = H_z_homography;
else
assert(0 && "Unknown TransformationType");
if (projectPoints == NULL)
return -1;
for (i = p_row; i < p_row + p_height; ++i) {
for (j = p_col; j < p_col + p_width; ++j) {
double in[2], out[2], out_z[2];
uint8_t pred, pred_z;
int err, err_z;
in[0] = subsampling_col ? 2 * j + 0.5 : j;
in[1] = subsampling_row ? 2 * i + 0.5 : i;
projectPoints(H, in, out, 1, 2, 2);
out[0] = subsampling_col ? (out[0] - 0.5) / 2.0 : out[0];
out[1] = subsampling_row ? (out[1] - 0.5) / 2.0 : out[1];
out[0] *= x_scale / 16.0;
out[1] *= y_scale / 16.0;
pred = interpolate(ref, out[0], out[1], width, height, stride);
err = pred - src[(j - p_col) + (i - p_row) * p_stride];
sumerr += err * err;
projectPoints(H_z, in, out_z, 1, 2, 2);
out_z[0] = subsampling_col ? (out_z[0] - 0.5) / 2.0 : out_z[0];
out_z[1] = subsampling_row ? (out_z[1] - 0.5) / 2.0 : out_z[1];
out_z[0] *= x_scale / 16.0;
out_z[1] *= y_scale / 16.0;
pred_z = interpolate(ref, out_z[0], out_z[1], width, height, stride);
err_z = pred_z - src[(j - p_col) + (i - p_row) * p_stride];
sumerr_z += err_z * err_z;
}
}
return (double)sumerr / sumerr_z;
}
void vp9_convert_params_to_rotzoom(Global_Motion_Params *model,
double *H) {
double z = (double) model->zoom / (1 << ZOOM_PRECISION_BITS);
double r = (double) model->rotation / (1 << ROTATION_PRECISION_BITS);
H[0] = (1 + z) * cos(r * M_PI / 180.0);
H[1] = -(1 + z) * sin(r * M_PI / 180.0);
H[2] = (double) model->mv.as_mv.col / 8.0;
H[3] = (double) model->mv.as_mv.row / 8.0;
}
void vp9_warp_plane(Global_Motion_Params *gm,
unsigned char *ref,
int width, int height, int stride,
unsigned char *pred,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
double H[9];
vp9_convert_params_to_rotzoom(gm, H);
WarpImage(ROTZOOM, H,
ref, width, height, stride,
pred, p_col, p_row, p_width, p_height, p_stride,
subsampling_col, subsampling_row,
x_scale, y_scale);
}
double vp9_warp_erroradv(Global_Motion_Params *gm,
unsigned char *ref,
int width, int height, int stride,
unsigned char *src,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale) {
double H[9];
vp9_convert_params_to_rotzoom(gm, H);
return vp9_warp_erroradv_unq(ROTZOOM, H,
ref, width, height, stride,
src, p_col, p_row, p_width, p_height, p_stride,
subsampling_col, subsampling_row,
x_scale, y_scale);
}
static int_mv vp9_get_global_mv(int col, int row, Global_Motion_Params *model) {
int_mv mv;
double H[4];
double x, y;
vp9_convert_params_to_rotzoom(model, H);
x = H[0] * col + H[1] * row + H[2];
y = -H[1] * col + H[0] * row + H[3];
mv.as_mv.col = (int)floor(x * 8 + 0.5) - col;
mv.as_mv.row = (int)floor(y * 8 + 0.5) - row;
return mv;
}
int_mv vp9_get_global_sb_center_mv(int col, int row, int bw, int bh,
Global_Motion_Params *model) {
col += bw / 2;
row += bh / 2;
return vp9_get_global_mv(col, row, model);
}
int_mv vp9_get_global_sub8x8_center_mv(int col, int row, int block,
Global_Motion_Params *model) {
if (block == 0 || block == 2)
col += 2;
else
col += 6;
if (block == 0 || block == 1)
row += 2;
else
row += 6;
return vp9_get_global_mv(col, row, model);
}

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be
* found in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VP9_COMMON_VP9_MOTION_MODEL_H
#define VP9_COMMON_VP9_MOTION_MODEL_H
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#include <assert.h>
#include "./vpx_config.h"
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_enums.h"
#include "vp9/common/vp9_mv.h"
typedef void (*projectPointsType)(double *mat, double *points, double *proj,
const int n, const int stride_points,
const int stride_proj);
typedef enum {
UNKNOWN_TRANSFORM = -1,
HOMOGRAPHY, // homography, 8-parameter
AFFINE, // affine, 6-parameter
ROTZOOM, // simplified affine with rotation and zoom only, 4-parameter
TRANSLATION // translational motion 2-parameter
} TransformationType;
static INLINE int get_numparams(TransformationType type) {
switch (type) {
case HOMOGRAPHY:
return 9;
case AFFINE:
return 6;
case ROTZOOM:
return 4;
case TRANSLATION:
return 2;
default:
assert(0);
return 0;
}
}
void projectPointsHomography(double *mat, double *points, double *proj,
const int n, const int stride_points,
const int stride_proj);
void projectPointsAffine(double *mat, double *points, double *proj,
const int n, const int stride_points,
const int stride_proj);
void projectPointsRotZoom(double *mat, double *points, double *proj,
const int n, const int stride_points,
const int stride_proj);
void projectPointsTranslation(double *mat, double *points, double *proj,
const int n, const int stride_points,
const int stride_proj);
projectPointsType get_projectPointsType(TransformationType type);
void vp9_convert_params_to_rotzoom(Global_Motion_Params *model, double *H);
void vp9_warp_plane(Global_Motion_Params *gm,
unsigned char *ref,
int width, int height, int stride,
unsigned char *pred,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale);
double vp9_warp_erroradv(Global_Motion_Params *gm,
unsigned char *ref,
int width, int height, int stride,
unsigned char *src,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale);
double vp9_warp_erroradv_unq(TransformationType type, double *H,
unsigned char *ref,
int width, int height, int stride,
unsigned char *src,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale);
double compute_warp_and_error(Global_Motion_Params *gm,
projectPointsType projectPoints,
unsigned char *ref,
int width, int height, int stride,
unsigned char *src,
int p_col, int p_row,
int p_width, int p_height, int p_stride,
int subsampling_col, int subsampling_row,
int x_scale, int y_scale);
unsigned char interpolate(unsigned char *ref, double x, double y,
int width, int height, int stride);
int_mv vp9_get_global_sb_center_mv(int col, int row, int bw, int bh,
Global_Motion_Params *model);
int_mv vp9_get_global_sub8x8_center_mv(int col, int row, int block,
Global_Motion_Params *model);
#endif // VP9_COMMON_VP9_MOTION_MODEL_H

View File

@ -48,6 +48,40 @@ static INLINE void clamp_mv(MV *mv, int min_col, int max_col,
mv->row = clamp(mv->row, min_row, max_row);
}
#if CONFIG_GLOBAL_MOTION
#define MAX_GLOBAL_MOTION_MODELS 1
#define ZOOM_PRECISION_BITS 11
#define ROTATION_PRECISION_BITS 11
#define ABS_ZOOM_BITS 11
#define ABS_ROTATION_BITS 11
#define ABS_TRANSLATION_BITS 11
typedef enum {
GLOBAL_ZERO = 0,
GLOBAL_TRANSLATION = 1,
GLOBAL_ROTZOOM = 2,
GLOBAL_MOTION_TYPES
} GLOBAL_MOTION_TYPE;
// Currently this is specialized for rotzoom model only
typedef struct {
GLOBAL_MOTION_TYPE gmtype;
int rotation; // positive or negative rotation angle in degrees
int zoom; // this is actually the zoom multiplier minus 1
int_mv mv;
} Global_Motion_Params;
static INLINE GLOBAL_MOTION_TYPE get_gmtype(const Global_Motion_Params *gm) {
if (gm->rotation == 0 && gm->zoom == 0) {
return (gm->mv.as_int == 0 ? GLOBAL_ZERO : GLOBAL_TRANSLATION);
} else {
return GLOBAL_ROTZOOM;
}
}
#endif // CONFIG_GLOBAL_MOTION
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,4 +1,3 @@
/*
* Copyright (c) 2012 The WebM project authors. All Rights Reserved.
*
@ -11,6 +10,260 @@
#include "vp9/common/vp9_mvref_common.h"
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
// This function returns either the appropriate subblock or block's mv,
// depending on whether block_size < 8x8 for both current block and the
// examined candidate block.
static int_mv get_subblock_mv(const MODE_INFO *candidate,
const MODE_INFO *current,
int curr_blk_idx, int ref,
int search_row, int search_col) {
int candidate_type = candidate->mbmi.sb_type;
if (curr_blk_idx >= 0 && candidate_type < BLOCK_8X8) {
int candidate_blk_idx = 0;
assert(current->mbmi.sb_type < BLOCK_8X8);
// Both current block and the candidate block are in sub8x8 mode
if ((search_row == -1 && search_col == 0) || // top
(search_row == 0 && search_col == -1)) { // left
int i = curr_blk_idx + current->mbmi.sb_type * 4;
int j = (search_row == 0); // top: 0; left: 1
candidate_blk_idx = idx_to_subblock_top_left[i][j][candidate_type];
return (candidate_blk_idx >= 0) ?
candidate->bmi[candidate_blk_idx].as_mv[ref] :
candidate->mbmi.mv[ref];
} else if ((search_row == -1 && search_col == 1) || // top_right
(search_row == -1 && search_col == -1)) { // top_left
candidate_blk_idx =
idx_to_subblock_topright_topleft[search_col == -1][candidate_type];
return candidate->bmi[candidate_blk_idx].as_mv[ref];
}
}
return candidate->mbmi.mv[ref];
}
static int get_mvref_zone_idx(const TileInfo *const tile, int bsize,
int mi_row, int mi_col) {
int mvref_zone_idx = 0;
int row_8x8 = mi_row % 8;
int col_8x8 = mi_col % 8;
switch (bsize) {
case BLOCK_4X4:
case BLOCK_4X8:
case BLOCK_8X4:
case BLOCK_8X8:
mvref_zone_idx =
(mi_col >= (tile->mi_col_end - 1) || // right-most column
(mv_ref_topright_avail_8x8[row_8x8][col_8x8] == 0)) ? 1 : 0;
break;
default:
// Only <= BLOCK_8X8 are supported currently
assert(0);
break;
}
return mvref_zone_idx;
}
// This function searches the neighbourhood of a given MB/SB
// to try to find candidate reference vectors.
static void find_mv_refs_idx_8x8(const VP9_COMMON *cm, const MACROBLOCKD *xd,
const TileInfo *const tile,
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
int_mv *mv_ref_list,
int block, int mi_row, int mi_col) {
int_mv mv_ref_candidates[MAX_MV_REF_CANDIDATES + 1];
const int *ref_sign_bias = cm->ref_frame_sign_bias;
int i;
int refmv_count = 0;
int different_ref_found = 0;
int zone_idx = get_mvref_zone_idx(tile, mi->mbmi.sb_type, mi_row, mi_col);
int max_nearest_blks = (zone_idx == 0) ? 4 : 3;
const POSITION *mv_ref_search = mv_ref_blocks_8x8[zone_idx];
// Zero out the mv reference vector list
vpx_memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);
vpx_memset(mv_ref_candidates, 0,
sizeof(*mv_ref_candidates) * (MAX_MV_REF_CANDIDATES + 1));
// The nearest 4 (when top right is available) or 3 neighboring blocks
// are treated differently:
// If their block size < 8x8, we get the mv from the bmi substructure.
for (i = 0; i < max_nearest_blks; ++i) {
const POSITION *const mv_ref = &mv_ref_search[i];
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
const MODE_INFO *const candidate_mi =
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride].src_mi;
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
different_ref_found = 1;
if (candidate->ref_frame[0] == ref_frame) {
ADD_MV_REF_CANDIDATE(get_subblock_mv(
candidate_mi, mi, block, 0, mv_ref->row, mv_ref->col));
} else if (candidate->ref_frame[1] == ref_frame) {
ADD_MV_REF_CANDIDATE(get_subblock_mv(
candidate_mi, mi, block, 1, mv_ref->row, mv_ref->col));
}
}
}
// Check the rest of the neighbors in much the same way as before
// except we don't need to keep track of subblocks.
for (; i < MVREF_NEIGHBOURS; ++i) {
const POSITION *const mv_ref = &mv_ref_search[i];
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
const MB_MODE_INFO *const candidate =
&xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride].src_mi->mbmi;
different_ref_found = 1;
if (candidate->ref_frame[0] == ref_frame)
ADD_MV_REF_CANDIDATE(candidate->mv[0]);
else if (candidate->ref_frame[1] == ref_frame)
ADD_MV_REF_CANDIDATE(candidate->mv[1]);
}
}
// Since we couldn't find 3 mvs from the same reference frame,
// go back through the neighbors and find motion vectors from
// different reference frames.
if (different_ref_found) {
for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
const POSITION *mv_ref = &mv_ref_search[i];
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
const MB_MODE_INFO *const candidate =
&xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride].src_mi->mbmi;
// If the candidate is INTRA we don't want to consider its mv.
IF_DIFF_REF_FRAME_ADD_MV_CANDIDATE(candidate);
}
}
}
Done:
if (refmv_count == 2) {
mv_ref_list[0].as_mv.row =
(mv_ref_candidates[0].as_mv.row + mv_ref_candidates[1].as_mv.row) >> 1;
mv_ref_list[0].as_mv.col =
(mv_ref_candidates[0].as_mv.col + mv_ref_candidates[1].as_mv.col) >> 1;
mv_ref_list[1].as_int = mv_ref_candidates[2].as_int;
} else {
for (i = 0; i < 2; ++i) {
mv_ref_list[i].as_int = mv_ref_candidates[i].as_int;
}
}
// Clamp vectors
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i)
clamp_mv_ref(&mv_ref_list[i].as_mv, xd);
}
typedef enum MV_SEARCH_POS {
TOP = 0,
LEFT = 1,
TOPLEFT = 2,
TOPRIGHT = 3,
TOPRIGHT_ALT = 4,
NUM_SEARCH_POS = 5
} MV_SEARCH_POS;
// Adaptive median
static int get_adaptive_median(int topright, int left, int topleft) {
int a = topright;
int b = left;
int c = topright + left - topleft;
if (a >= b) {
if (b >= c) return b;
else if (a >= c) return c;
else return a;
} else {
if (b < c) return b;
else if (a >= c) return a;
else return c;
}
}
// This function searches the neighbourhood of a given MB/SB to try
// to find the nearestmv through adaptive median filtering.
static int find_best_mvref_8x8(const VP9_COMMON *cm, const MACROBLOCKD *xd,
const TileInfo *const tile,
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
int_mv *best_mvref,
int block, int mi_row, int mi_col) {
int i;
int zone_idx = get_mvref_zone_idx(tile, mi->mbmi.sb_type, mi_row, mi_col);
int max_nearest_blks = (zone_idx == 0) ? 4 : 3;
const POSITION adapt_median_neighbor_pos[NUM_SEARCH_POS - 1] = {
// TOP, LEFT, TOPLEFT, TOPRIGHT
{-1, 0}, {0, -1}, {-1, -1}, {-1, 1}
};
int_mv mv_ref_mvs[NUM_SEARCH_POS];
int is_avail[NUM_SEARCH_POS] = { 0, 0, 0, 0, 0 };
vpx_memset(mv_ref_mvs, 0, sizeof(mv_ref_mvs[0]) * NUM_SEARCH_POS);
// If the neighboring block size < 8x8, the mv is obtained from
// the bmi substructure.
for (i = 0; i < max_nearest_blks; ++i) {
const POSITION *const mv_ref_pos = &adapt_median_neighbor_pos[i];
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref_pos)) {
const MODE_INFO *const candidate_mi =
xd->mi[mv_ref_pos->col + mv_ref_pos->row * xd->mi_stride].src_mi;
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
if (candidate->ref_frame[0] == ref_frame) {
mv_ref_mvs[i] = get_subblock_mv(candidate_mi, mi, block, 0,
mv_ref_pos->row, mv_ref_pos->col);
is_avail[i] = 1;
} else if (candidate->ref_frame[1] == ref_frame) {
mv_ref_mvs[i] = get_subblock_mv(candidate_mi, mi, block, 1,
mv_ref_pos->row, mv_ref_pos->col);
is_avail[i] = 1;
}
}
}
if (is_avail[TOP] && is_avail[TOPRIGHT]) {
mv_ref_mvs[TOPRIGHT_ALT].as_mv.row =
(mv_ref_mvs[TOP].as_mv.row + mv_ref_mvs[TOPRIGHT].as_mv.row) >> 1;
mv_ref_mvs[TOPRIGHT_ALT].as_mv.col =
(mv_ref_mvs[TOP].as_mv.col + mv_ref_mvs[TOPRIGHT].as_mv.col) >> 1;
} else if (is_avail[TOP]) {
mv_ref_mvs[TOPRIGHT_ALT].as_int = mv_ref_mvs[TOP].as_int;
} else if (is_avail[TOPRIGHT]) {
mv_ref_mvs[TOPRIGHT_ALT].as_int = mv_ref_mvs[TOPRIGHT].as_int;
}
if (is_avail[TOP] || is_avail[LEFT] || is_avail[TOPLEFT] ||
is_avail[TOPRIGHT]) {
best_mvref->as_mv.row = get_adaptive_median(
mv_ref_mvs[TOPRIGHT_ALT].as_mv.row,
mv_ref_mvs[LEFT].as_mv.row,
mv_ref_mvs[TOPLEFT].as_mv.row);
best_mvref->as_mv.col = get_adaptive_median(
mv_ref_mvs[TOPRIGHT_ALT].as_mv.col,
mv_ref_mvs[LEFT].as_mv.col,
mv_ref_mvs[TOPLEFT].as_mv.col);
// Clamp vectors
clamp_mv_ref(&(best_mvref->as_mv), xd);
return 1;
} else {
best_mvref->as_int = 0;
return 0;
}
}
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
// This function searches the neighbourhood of a given MB/SB
// to try and find candidate reference vectors.
static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd,
@ -23,10 +276,12 @@ static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd,
const MODE_INFO *prev_mi = !cm->error_resilient_mode && cm->prev_mi
? cm->prev_mi[mi_row * xd->mi_stride + mi_col].src_mi
: NULL;
const MB_MODE_INFO *const prev_mbmi = prev_mi ? &prev_mi->src_mi->mbmi : NULL;
const MB_MODE_INFO *const prev_mbmi = prev_mi ? &prev_mi->mbmi : NULL;
const POSITION *const mv_ref_search = mv_ref_blocks[mi->mbmi.sb_type];
int different_ref_found = 0;
#if !CONFIG_NEW_INTER
int context_counter = 0;
#endif // !CONFIG_NEW_INTER
// Blank the reference vector list
vpx_memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);
@ -41,13 +296,16 @@ static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd,
xd->mi_stride].src_mi;
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
// Keep counts for entropy encoding.
#if !CONFIG_NEW_INTER
context_counter += mode_2_counter[candidate->mode];
#endif // !CONFIG_NEW_INTER
different_ref_found = 1;
if (candidate->ref_frame[0] == ref_frame)
if (candidate->ref_frame[0] == ref_frame) {
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 0, mv_ref->col, block));
else if (candidate->ref_frame[1] == ref_frame)
} else if (candidate->ref_frame[1] == ref_frame) {
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 1, mv_ref->col, block));
}
}
}
@ -98,30 +356,82 @@ static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd,
Done:
#if !CONFIG_NEW_INTER
mi->mbmi.mode_context[ref_frame] = counter_to_context[context_counter];
#endif // !CONFIG_NEW_INTER
// Clamp vectors
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i)
clamp_mv_ref(&mv_ref_list[i].as_mv, xd);
}
#if CONFIG_NEW_INTER
// This function keeps a mode count for a given MB/SB
void vp9_update_mv_context(const VP9_COMMON *cm, const MACROBLOCKD *xd,
const TileInfo *const tile,
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
int_mv *mv_ref_list,
int block, int mi_row, int mi_col) {
int i, refmv_count = 0;
const POSITION *const mv_ref_search = mv_ref_blocks[mi->mbmi.sb_type];
int context_counter = 0;
// Blank the reference vector list
vpx_memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);
// The nearest 2 blocks are examined only.
// If the size < 8x8, we get the mv from the bmi substructure;
for (i = 0; i < 2; ++i) {
const POSITION *const mv_ref = &mv_ref_search[i];
if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
const MODE_INFO *const candidate_mi =
xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride].src_mi;
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
// Keep counts for entropy encoding.
context_counter += mode_2_counter[candidate->mode];
if (candidate->ref_frame[0] == ref_frame) {
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 0, mv_ref->col, block));
} else if (candidate->ref_frame[1] == ref_frame) {
ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 1, mv_ref->col, block));
}
}
}
Done:
mi->mbmi.mode_context[ref_frame] = counter_to_context[context_counter];
}
#endif // CONFIG_NEW_INTER
void vp9_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd,
const TileInfo *const tile,
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
int_mv *mv_ref_list,
int mi_row, int mi_col) {
#if CONFIG_NEW_INTER
vp9_update_mv_context(cm, xd, tile, mi, ref_frame, mv_ref_list, -1,
mi_row, mi_col);
#if CONFIG_NEWMVREF
if (mi->mbmi.sb_type <= BLOCK_8X8) {
int_mv best_mvref;
find_best_mvref_8x8(cm, xd, tile, mi, ref_frame, &best_mvref,
-1, mi_row, mi_col);
find_mv_refs_idx_8x8(cm, xd, tile, mi, ref_frame, mv_ref_list,
-1, mi_row, mi_col);
if (best_mvref.as_int != 0) {
mv_ref_list[1].as_int = mv_ref_list[0].as_int;
mv_ref_list[0].as_int = best_mvref.as_int;
}
} else {
#endif // CONFIG_NEWMVREF
#endif // CONFIG_NEW_INTER
find_mv_refs_idx(cm, xd, tile, mi, ref_frame, mv_ref_list, -1,
mi_row, mi_col);
}
static void lower_mv_precision(MV *mv, int allow_hp) {
const int use_hp = allow_hp && vp9_use_mv_hp(mv);
if (!use_hp) {
if (mv->row & 1)
mv->row += (mv->row > 0 ? -1 : 1);
if (mv->col & 1)
mv->col += (mv->col > 0 ? -1 : 1);
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
}
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
}
void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp,
@ -129,8 +439,10 @@ void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp,
int i;
// Make sure all the candidates are properly clamped etc
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
lower_mv_precision(&mvlist[i].as_mv, allow_hp);
clamp_mv2(&mvlist[i].as_mv, xd);
MV *mv = &mvlist[i].as_mv;
const int usehp = allow_hp && vp9_use_mv_hp(mv);
vp9_lower_mv_precision(mv, usehp);
clamp_mv2(mv, xd);
}
*nearest = mvlist[0];
*near = mvlist[1];
@ -139,33 +451,151 @@ void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp,
void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd,
const TileInfo *const tile,
int block, int ref, int mi_row, int mi_col,
#if CONFIG_NEW_INTER
int_mv *mv_list,
#endif // CONFIG_NEW_INTER
int_mv *nearest, int_mv *near) {
#if CONFIG_NEW_INTER
#if CONFIG_NEWMVREF
int_mv best_mvref;
#endif // CONFIG_NEWMVREF
#else
int_mv mv_list[MAX_MV_REF_CANDIDATES];
#endif // !CONFIG_NEW_INTER
MODE_INFO *const mi = xd->mi[0].src_mi;
b_mode_info *bmi = mi->bmi;
int n;
assert(MAX_MV_REF_CANDIDATES == 2);
find_mv_refs_idx(cm, xd, tile, mi, mi->mbmi.ref_frame[ref], mv_list, block,
mi_row, mi_col);
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
find_best_mvref_8x8(cm, xd, tile, mi, mi->mbmi.ref_frame[ref],
&best_mvref, block, mi_row, mi_col);
find_mv_refs_idx_8x8(cm, xd, tile, mi, mi->mbmi.ref_frame[ref],
mv_list, block, mi_row, mi_col);
#else
find_mv_refs_idx(cm, xd, tile, mi, mi->mbmi.ref_frame[ref],
mv_list, block, mi_row, mi_col);
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
near->as_int = 0;
switch (block) {
case 0:
nearest->as_int = mv_list[0].as_int;
near->as_int = mv_list[1].as_int;
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
if (best_mvref.as_int != 0) {
nearest->as_int = best_mvref.as_int;
if (best_mvref.as_int != mv_list[0].as_int)
near->as_int = mv_list[0].as_int;
else
near->as_int = mv_list[1].as_int;
} else {
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
nearest->as_int = mv_list[0].as_int;
near->as_int = mv_list[1].as_int;
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
}
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
break;
case 1:
#if !CONFIG_NEW_INTER
case 2:
#endif // !CONFIG_NEW_INTER
nearest->as_int = bmi[0].as_mv[ref].as_int;
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
if (best_mvref.as_int != 0 &&
best_mvref.as_int != nearest->as_int)
near->as_int = best_mvref.as_int;
else
#endif // CONFIG_NEW_INTER && CONFIG_NEWMVREF
for (n = 0; n < MAX_MV_REF_CANDIDATES; ++n)
if (nearest->as_int != mv_list[n].as_int) {
near->as_int = mv_list[n].as_int;
break;
}
break;
#if CONFIG_NEW_INTER
case 2: {
#if CONFIG_NEWMVREF
if (bmi[0].as_mv[ref].as_int !=
bmi[1].as_mv[ref].as_int) {
// Average of TOP and TOPRIGHT
nearest->as_mv.row = (
bmi[0].as_mv[ref].as_mv.row +
bmi[1].as_mv[ref].as_mv.row) >> 1;
nearest->as_mv.col = (
bmi[0].as_mv[ref].as_mv.col +
bmi[1].as_mv[ref].as_mv.col) >> 1;
near->as_int = bmi[0].as_mv[ref].as_int;
} else {
nearest->as_int = bmi[0].as_mv[ref].as_int;
if (best_mvref.as_int != 0 &&
best_mvref.as_int != nearest->as_int) {
near->as_int = best_mvref.as_int;
} else {
for (n = 0; n < MAX_MV_REF_CANDIDATES; ++n)
if (nearest->as_int != mv_list[n].as_int) {
near->as_int = mv_list[n].as_int;
break;
}
}
}
#else
int_mv candidates[1 + MAX_MV_REF_CANDIDATES];
candidates[0] = bmi[1].as_mv[ref];
candidates[1] = mv_list[0];
candidates[2] = mv_list[1];
nearest->as_int = bmi[0].as_mv[ref].as_int;
for (n = 0; n < 1 + MAX_MV_REF_CANDIDATES; ++n)
if (nearest->as_int != candidates[n].as_int) {
near->as_int = candidates[n].as_int;
break;
}
#endif // CONFIG_NEWMVREF
break;
}
#endif // CONFIG_NEW_INTER
case 3: {
#if CONFIG_NEW_INTER && CONFIG_NEWMVREF
if (bmi[0].as_mv[ref].as_int != bmi[1].as_mv[ref].as_int ||
bmi[0].as_mv[ref].as_int != bmi[2].as_mv[ref].as_int ||
bmi[1].as_mv[ref].as_int != bmi[2].as_mv[ref].as_int) {
nearest->as_mv.row = get_adaptive_median(
bmi[1].as_mv[ref].as_mv.row,
bmi[2].as_mv[ref].as_mv.row,
bmi[0].as_mv[ref].as_mv.row);
nearest->as_mv.col = get_adaptive_median(
bmi[1].as_mv[ref].as_mv.col,
bmi[2].as_mv[ref].as_mv.col,
bmi[0].as_mv[ref].as_mv.col);
/*nearest->as_mv.row =
(bmi[0].as_mv[ref].as_mv.row +
bmi[1].as_mv[ref].as_mv.row +
(bmi[2].as_mv[ref].as_mv.row << 1)) >> 2;
nearest->as_mv.col =
(bmi[0].as_mv[ref].as_mv.col +
bmi[1].as_mv[ref].as_mv.col +
(bmi[2].as_mv[ref].as_mv.col << 1)) >> 2;*/
for (n = 2; n >= 0; --n)
if (nearest->as_int != bmi[n].as_mv[ref].as_int) {
near->as_int = bmi[n].as_mv[ref].as_int;
break;
}
} else {
nearest->as_int = bmi[2].as_mv[ref].as_int;
if (best_mvref.as_int != 0 &&
best_mvref.as_int != nearest->as_int) {
near->as_int = best_mvref.as_int;
} else {
for (n = 0; n < MAX_MV_REF_CANDIDATES; ++n)
if (nearest->as_int != mv_list[n].as_int) {
near->as_int = mv_list[n].as_int;
break;
}
}
}
#else
int_mv candidates[2 + MAX_MV_REF_CANDIDATES];
candidates[0] = bmi[1].as_mv[ref];
candidates[1] = bmi[0].as_mv[ref];
@ -178,9 +608,222 @@ void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd,
near->as_int = candidates[n].as_int;
break;
}
#endif // CONFIG_NEW_INTER && CONFIG_NEWMREF
break;
}
default:
assert("Invalid block index.");
assert(0 && "Invalid block index.");
}
}
#if CONFIG_COPY_MODE
static int compare_interinfo(MB_MODE_INFO *mbmi, MB_MODE_INFO *ref_mbmi) {
if (mbmi == ref_mbmi) {
return 1;
} else {
int is_same;
#if CONFIG_INTERINTRA
MV_REFERENCE_FRAME mbmi_ref1_backup = mbmi->ref_frame[1];
MV_REFERENCE_FRAME refmbmi_ref1_backup = ref_mbmi->ref_frame[1];
if (mbmi->ref_frame[1] == INTRA_FRAME)
mbmi->ref_frame[1] = NONE;
if (ref_mbmi->ref_frame[1] == INTRA_FRAME)
ref_mbmi->ref_frame[1] = NONE;
#endif // CONFIG_INTERINTRA
if (mbmi->ref_frame[0] == ref_mbmi->ref_frame[0] &&
mbmi->ref_frame[1] == ref_mbmi->ref_frame[1]) {
if (mbmi->ref_frame[1] > INTRA_FRAME)
is_same = mbmi->mv[0].as_int == ref_mbmi->mv[0].as_int &&
mbmi->mv[1].as_int == ref_mbmi->mv[1].as_int &&
mbmi->interp_filter == ref_mbmi->interp_filter;
else
is_same = mbmi->mv[0].as_int == ref_mbmi->mv[0].as_int &&
mbmi->interp_filter == ref_mbmi->interp_filter;
} else {
is_same = 0;
}
#if CONFIG_INTERINTRA
mbmi->ref_frame[1] = mbmi_ref1_backup;
ref_mbmi->ref_frame[1] = refmbmi_ref1_backup;
#endif // CONFIG_INTERINTRA
return is_same;
}
}
static int check_inside(const TileInfo *const tile, int mi_row, int mi_col) {
return mi_row >= tile->mi_row_start && mi_col >= tile->mi_col_start &&
mi_row < tile->mi_row_end && mi_col < tile->mi_col_end;
}
static int is_right_available(BLOCK_SIZE bsize,
#if CONFIG_EXT_PARTITION
PARTITION_TYPE partition,
#endif
int mi_row, int mi_col) {
int depth, max_depth = (CODING_UNIT_SIZE_LOG2 - 2) -
MIN(b_width_log2_lookup[bsize], b_height_log2_lookup[bsize]);
int block[(CODING_UNIT_SIZE_LOG2 - 2)] = {0};
if (bsize == BLOCK_LARGEST)
return 1;
mi_row = mi_row % MI_BLOCK_SIZE;
mi_col = mi_col % MI_BLOCK_SIZE;
for (depth = 1; depth <= max_depth; depth++) {
block[depth] = (mi_row >> (MI_BLOCK_SIZE_LOG2 - depth)) * 2 +
(mi_col >> (MI_BLOCK_SIZE_LOG2 - depth));
mi_row = mi_row % (MI_BLOCK_SIZE >> depth);
mi_col = mi_col % (MI_BLOCK_SIZE >> depth);
}
if (b_width_log2_lookup[bsize] < b_height_log2_lookup[bsize]) {
if (block[max_depth] == 0)
return 1;
} else if (b_width_log2_lookup[bsize] > b_height_log2_lookup[bsize]) {
if (block[max_depth] > 0)
return 0;
} else {
#if CONFIG_EXT_PARTITION
if (block[max_depth] == 0)
return 1;
if (block[max_depth] == 2)
return partition != PARTITION_VERT_A;
#else
if (block[max_depth] == 0 || block[max_depth] == 2)
return 1;
#endif
else if (block[max_depth] == 3)
return 0;
}
for (depth = max_depth - 1; depth > 0; depth--) {
if (block[depth] == 0 || block[depth] == 2)
return 1;
else if (block[depth] == 3)
return 0;
}
return 1;
}
static int is_second_rec(int mi_row, int mi_col, BLOCK_SIZE bsize) {
int bw = 4 << b_width_log2_lookup[bsize];
int bh = 4 << b_height_log2_lookup[bsize];
if (bw < bh)
return (mi_col << 3) % (bw << 1) == 0 ? 0 : 1;
else if (bh < bw)
return (mi_row << 3) % (bh << 1) == 0 ? 0 : 2;
else
return 0;
}
int vp9_construct_ref_inter_list(VP9_COMMON *cm, MACROBLOCKD *xd,
const TileInfo *const tile,
BLOCK_SIZE bsize,
#if CONFIG_EXT_PARTITION
PARTITION_TYPE partition,
#endif
int mi_row, int mi_col,
MB_MODE_INFO *ref_list[2 *
(MI_BLOCK_SIZE + 1)]) {
int bw = 4 << b_width_log2_lookup[bsize];
int bh = 4 << b_height_log2_lookup[bsize];
int row_offset, col_offset;
int mi_offset;
MB_MODE_INFO *ref_mbmi;
int ref_index, ref_num = 0;
int row_offset_cand[2 * (MI_BLOCK_SIZE + 1)];
int col_offset_cand[2 * (MI_BLOCK_SIZE + 1)];
int offset_num = 0, i, switchflag;
int is_sec_rec = is_second_rec(mi_row, mi_col, bsize);
if (is_sec_rec != 2) {
row_offset_cand[offset_num] = -1; col_offset_cand[offset_num] = 0;
offset_num++;
}
if (is_sec_rec != 1) {
row_offset_cand[offset_num] = bh / (2 * MI_SIZE);
col_offset_cand[offset_num] = -1;
offset_num++;
}
row_offset = bh / MI_SIZE - 1;
col_offset = 1;
if (is_sec_rec < 2)
switchflag = 1;
else
switchflag = 0;
while ((is_sec_rec == 0 && ((row_offset >=0) ||
col_offset < (bw / MI_SIZE + 1))) ||
(is_sec_rec == 1 && col_offset < (bw / MI_SIZE + 1)) ||
(is_sec_rec == 2 && row_offset >=0)) {
switch (switchflag) {
case 0:
if (row_offset >= 0) {
if (row_offset != bh / (2 * MI_SIZE)) {
row_offset_cand[offset_num] = row_offset;
col_offset_cand[offset_num] = -1;
offset_num++;
}
row_offset--;
}
break;
case 1:
if (col_offset < (bw / MI_SIZE + 1)) {
row_offset_cand[offset_num] = -1;
col_offset_cand[offset_num] = col_offset;
offset_num++;
col_offset++;
}
break;
default:
assert(0);
}
if (is_sec_rec == 0)
switchflag = 1 - switchflag;
}
row_offset_cand[offset_num] = -1;
col_offset_cand[offset_num] = -1;
offset_num++;
for (i = 0; i < offset_num; i++) {
row_offset = row_offset_cand[i];
col_offset = col_offset_cand[i];
if ((col_offset < (bw / MI_SIZE) ||
(col_offset == (bw / MI_SIZE) && is_right_available(bsize,
#if CONFIG_EXT_PARTITION
partition,
#endif
mi_row, mi_col)))
&& check_inside(tile, mi_row + row_offset, mi_col + col_offset)) {
mi_offset = row_offset * cm->mi_stride + col_offset;
ref_mbmi = &xd->mi[mi_offset].src_mi->mbmi;
if (is_inter_block(ref_mbmi)) {
for (ref_index = 0; ref_index < ref_num; ref_index++) {
if (compare_interinfo(ref_mbmi, ref_list[ref_index]))
break;
}
if (ref_index == ref_num) {
ref_list[ref_num] = ref_mbmi;
ref_num++;
}
}
}
}
return ref_num;
}
#endif // CONFIG_COPY_MODE
#if CONFIG_INTRABC
void vp9_find_ref_dv(int_mv *ref_dv, int mi_row, int mi_col) {
(void) mi_col;
if (mi_row < 8) {
ref_dv->as_mv.row = 0;
ref_dv->as_mv.col = -8 * 8;
} else {
ref_dv->as_mv.row = -8 * 8;
ref_dv->as_mv.col = 0;
}
}
#endif // CONFIG_INTRABC

View File

@ -22,6 +22,9 @@ extern "C" {
VP9_INTERP_EXTEND) << 3)
#define MVREF_NEIGHBOURS 8
#if CONFIG_NEWMVREF
#define MAX_ZONES 2
#endif // CONFIG_NEWMVREF
typedef struct position {
int row;
@ -55,10 +58,25 @@ static const int mode_2_counter[MB_MODE_COUNT] = {
9, // D207_PRED
9, // D63_PRED
9, // TM_PRED
#if CONFIG_INTRABC
9, // NEWDV
#endif // CONFIG_INTRABC
0, // NEARESTMV
0, // NEARMV
3, // ZEROMV
1, // NEWMV
#if CONFIG_NEW_INTER
1, // NEW2MV
0, // NEAREST_NEARESTMV
0, // NEAREST_NEARMV
0, // NEAR_NEARESTMV
1, // NEAREST_NEWMV
1, // NEW_NEARESTMV
1, // NEAR_NEWMV
1, // NEW_NEARMV
3, // ZERO_ZEROMV
1, // NEW_NEWMV
#endif // CONFIG_NEW_INTER
};
// There are 3^3 different combinations of 3 counts that can be either 0,1 or
@ -112,7 +130,15 @@ static const POSITION mv_ref_blocks[BLOCK_SIZES][MVREF_NEIGHBOURS] = {
// 64X32
{{-1, 0}, {0, -1}, {-1, 4}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-1, 2}},
// 64X64
{{-1, 3}, {3, -1}, {-1, 4}, {4, -1}, {-1, -1}, {-1, 0}, {0, -1}, {-1, 6}}
{{-1, 3}, {3, -1}, {-1, 4}, {4, -1}, {-1, -1}, {-1, 0}, {0, -1}, {-1, 6}},
#if CONFIG_EXT_CODING_UNIT_SIZE
// 64x128
{{0, -1}, {-1, 0}, {4, -1}, {-1, 2}, {-1, -1}, {0, -3}, {-3, 0}, {2, -1}},
// 128x64
{{-1, 0}, {0, -1}, {-1, 4}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-1, 2}},
// 128x128
{{-1, 3}, {3, -1}, {-1, 4}, {4, -1}, {-1, -1}, {-1, 0}, {0, -1}, {-1, 6}},
#endif
};
static const int idx_n_column_to_subblock[4][2] = {
@ -122,8 +148,92 @@ static const int idx_n_column_to_subblock[4][2] = {
{3, 3}
};
#if CONFIG_NEWMVREF
static const POSITION mv_ref_blocks_8x8[MAX_ZONES][MVREF_NEIGHBOURS] = {
{ // 8X8, Zone I, where top right neighbors are available
{-1, 0}, { 0, -1}, {-1, 1}, {-1, -1}, // nearest neighboring blocks
{-2, 0}, { 0, -2}, {-2, -1}, {-1, -2}
},
{ // 8X8, Zone II, where no top right neighbor is available
{-1, 0}, { 0, -1}, {-1, -1}, // nearest neighboring blocks
{-2, 0}, { 0, -2}, {-2, -1}, {-1, -2}, {-2, -2}
}
};
static const int mv_ref_topright_avail_8x8[8][8] = {
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 1, 0, 1, 0},
{1, 1, 1, 0, 1, 1, 1, 0},
{1, 0, 1, 0, 1, 0, 1, 0},
{1, 1, 1, 1, 1, 1, 1, 0},
{1, 0, 1, 0, 1, 0, 1, 0},
{1, 1, 1, 0, 1, 1, 1, 0},
{1, 0, 1, 0, 1, 0, 1, 0}
};
static const int idx_to_subblock_top_left[12][2][3] = {
{ // 4x4 subblock 0 (current)
{2, 0, 2}, // top: 4x4, 4x8, 8x4
{1, 1, 0} // left: 4x4, 4x8, 8x4
},
{ // 4x4 subblock 1 (current)
{3, 1, 2}, // top: 4x4, 4x8, 8x4
{1, 1, 0} // left: 4x4, 4x8, 8x4
},
{ // 4x4 subblock 2 (current)
{2, 0, 2}, // top: 4x4, 4x8, 8x4
{3, 1, 2} // left: 4x4, 4x8, 8x4
},
{ // 4x4 subblock 3 (current)
{3, 1, 2}, // top: 4x4, 4x8, 8x4
{3, 1, 2} // left: 4x4, 4x8, 8x4
},
{ // 4x8 subblock 0 (current)
{ 2, 0, 2}, // top: 4x4, 4x8, 8x4
{-1, 1, -1} // left: 4x4, 4x8, 8x4
},
{ // 4x8 subblock 1 (current)
{ 3, 1, 2}, // top: 4x4, 4x8, 8x4
{-1, 1, -1} // left: 4x4, 4x8, 8x4
},
{ // 4x8 subblock 2 (current)
{ 2, 0, 2}, // top: 4x4, 4x8, 8x4
{-1, 1, -1} // left: 4x4, 4x8, 8x4
},
{ // 4x8 subblock 3 (current)
{ 3, 1, 2}, // top: 4x4, 4x8, 8x4
{-1, 1, -1} // left: 4x4, 4x8, 8x4
},
{ // 8x4 subblock 0 (current)
{-1, -1, 2}, // top: 4x4, 4x8, 8x4
{ 1, 1, 0} // left: 4x4, 4x8, 8x4
},
{ // 8x4 subblock 1 (current)
{-1, -1, 2}, // top: 4x4, 4x8, 8x4
{ 1, 1, 0} // left: 4x4, 4x8, 8x4
},
{ // 8x4 subblock 2 (current)
{-1, -1, 2}, // top: 4x4, 4x8, 8x4
{ 3, 1, 2} // left: 4x4, 4x8, 8x4
},
{ // 8x4 subblock 3 (current)
{-1, -1, 2}, // top: 4x4, 4x8, 8x4
{ 3, 1, 2} // left: 4x4, 4x8, 8x4
}
};
static const int idx_to_subblock_topright_topleft[2][3] = {
{2, 0, 2}, // top-right: 4x4, 4x8, 8x4
{3, 1, 2} // top-left: 4x4, 4x8, 8x4
};
#endif // CONFIG_NEWMVREF
// clamp_mv_ref
#if CONFIG_EXT_CODING_UNIT_SIZE
#define MV_BORDER (32 << 3) // Allow 32 pels in 1/8th pel units
#else
#define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units
#endif
static INLINE void clamp_mv_ref(MV *mv, const MACROBLOCKD *xd) {
clamp_mv(mv, xd->mb_to_left_edge - MV_BORDER,
@ -142,7 +252,6 @@ static INLINE int_mv get_sub_block_mv(const MODE_INFO *candidate, int which_mv,
: candidate->mbmi.mv[which_mv];
}
// Performs mv sign inversion if indicated by the reference frame combination.
static INLINE int_mv scale_mv(const MB_MODE_INFO *mbmi, int ref,
const MV_REFERENCE_FRAME this_ref_frame,
@ -190,12 +299,56 @@ static INLINE int_mv scale_mv(const MB_MODE_INFO *mbmi, int ref,
static INLINE int is_inside(const TileInfo *const tile,
int mi_col, int mi_row, int mi_rows,
const POSITION *mi_pos) {
#if CONFIG_ROW_TILE
(void) mi_rows;
return !(mi_row + mi_pos->row < tile->mi_row_start ||
mi_col + mi_pos->col < tile->mi_col_start ||
mi_row + mi_pos->row >= tile->mi_row_end ||
mi_col + mi_pos->col >= tile->mi_col_end);
#else
return !(mi_row + mi_pos->row < 0 ||
mi_col + mi_pos->col < tile->mi_col_start ||
mi_row + mi_pos->row >= mi_rows ||
mi_col + mi_pos->col >= tile->mi_col_end);
#endif
}
#if CONFIG_NEWMVREF
// This macro is used to add a motion vector as a candidate for the mv ref if
// it isn't already taken. If it's the third motion vector, it will also skip
// all additional processing and jump to done!
#define ADD_MV_REF_CANDIDATE(mv) \
do { \
if (refmv_count) { \
if (refmv_count == 1 && \
(mv).as_int != mv_ref_candidates[0].as_int) { \
mv_ref_candidates[refmv_count++] = (mv); \
} else if (refmv_count == 2 && \
(mv).as_int != mv_ref_candidates[0].as_int && \
(mv).as_int != mv_ref_candidates[1].as_int) { \
mv_ref_candidates[refmv_count] = (mv); \
goto Done; \
} \
} else { \
mv_ref_candidates[refmv_count++] = (mv); \
} \
} while (0)
// If either reference frame is different, not INTRA, and they
// are different from each other scale and add the mv as candidate.
#define IF_DIFF_REF_FRAME_ADD_MV_CANDIDATE(mbmi) \
do { \
if (is_inter_block(mbmi)) { \
if ((mbmi)->ref_frame[0] != ref_frame) \
ADD_MV_REF_CANDIDATE(scale_mv((mbmi), 0, ref_frame, ref_sign_bias)); \
if (has_second_ref(mbmi) && \
(mbmi)->ref_frame[1] != ref_frame && \
(mbmi)->mv[1].as_int != (mbmi)->mv[0].as_int) \
ADD_MV_REF_CANDIDATE(scale_mv((mbmi), 1, ref_frame, ref_sign_bias)); \
} \
} while (0)
#endif // CONFIG_NEWMVREF
// TODO(jingning): this mv clamping function should be block size dependent.
static INLINE void clamp_mv2(MV *mv, const MACROBLOCKD *xd) {
clamp_mv(mv, xd->mb_to_left_edge - LEFT_TOP_MARGIN,
@ -204,11 +357,29 @@ static INLINE void clamp_mv2(MV *mv, const MACROBLOCKD *xd) {
xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN);
}
#if CONFIG_NEW_INTER
// This function keeps a mode count for a given MB/SB
void vp9_update_mv_context(const VP9_COMMON *cm, const MACROBLOCKD *xd,
const TileInfo *const tile,
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
int_mv *mv_ref_list,
int block, int mi_row, int mi_col);
#endif // CONFIG_NEW_INTER
void vp9_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd,
const TileInfo *const tile,
MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
int_mv *mv_ref_list, int mi_row, int mi_col);
static INLINE void vp9_lower_mv_precision(MV *mv, const int usehp) {
if (!usehp) {
if (mv->row & 1)
mv->row += (mv->row > 0 ? -1 : 1);
if (mv->col & 1)
mv->col += (mv->col > 0 ? -1 : 1);
}
}
// check a list of motion vectors by sad score using a number rows of pixels
// above and a number cols of pixels in the left to select the one with best
// score to use as ref motion vector
@ -218,8 +389,25 @@ void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp,
void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd,
const TileInfo *const tile,
int block, int ref, int mi_row, int mi_col,
#if CONFIG_NEW_INTER
int_mv *mv_list,
#endif // CONFIG_NEW_INTER
int_mv *nearest, int_mv *near);
#if CONFIG_COPY_MODE
int vp9_construct_ref_inter_list(VP9_COMMON *cm, MACROBLOCKD *xd,
const TileInfo *const tile,
BLOCK_SIZE bsize,
#if CONFIG_EXT_PARTITION
PARTITION_TYPE partition,
#endif
int mi_row, int mi_col,
MB_MODE_INFO *ref_list[18]);
#endif // CONFIG_COPY_MODE
#if CONFIG_INTRABC
void vp9_find_ref_dv(int_mv *ref_dv, int mi_row, int mi_col);
#endif // CONFIOG_INTRABC
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -30,7 +30,11 @@
extern "C" {
#endif
#if CONFIG_MULTI_REF
#define REFS_PER_FRAME 6
#else // CONFIG_MULTI_REF
#define REFS_PER_FRAME 3
#endif // CONFIG_MULTI_REF
#define REF_FRAMES_LOG2 3
#define REF_FRAMES (1 << REF_FRAMES_LOG2)
@ -65,11 +69,29 @@ typedef struct {
typedef struct VP9Common {
struct vpx_internal_error_info error;
DECLARE_ALIGNED(16, int16_t, y_dequant[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_dequant[QINDEX_RANGE][8]);
#if CONFIG_NEW_QUANT
DECLARE_ALIGNED(16, dequant_val_type_nuq,
y_dequant_val_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS]);
DECLARE_ALIGNED(16, dequant_val_type_nuq,
uv_dequant_val_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS]);
#endif // CONFIG_NEW_QUANT
COLOR_SPACE color_space;
#if CONFIG_TX_SKIP
DECLARE_ALIGNED(16, int16_t, y_dequant_pxd[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_dequant_pxd[QINDEX_RANGE][8]);
#if CONFIG_NEW_QUANT
DECLARE_ALIGNED(16, dequant_val_type_nuq,
y_dequant_val_nuq_pxd[QUANT_PROFILES][QINDEX_RANGE]
[COEF_BANDS]);
DECLARE_ALIGNED(16, dequant_val_type_nuq,
uv_dequant_val_nuq_pxd[QUANT_PROFILES][QINDEX_RANGE]
[COEF_BANDS]);
#endif // CONFIG_NEW_QUANT
#endif // CONFIG_TX_SKIP
vpx_color_space_t color_space;
int width;
int height;
@ -103,9 +125,18 @@ typedef struct VP9Common {
int new_fb_idx;
YV12_BUFFER_CONFIG post_proc_buffer;
#if CONFIG_LOOP_POSTFILTER
YV12_BUFFER_CONFIG tmp_loop_buf;
#endif
FRAME_TYPE last_frame_type; /* last frame's frame type for motion search.*/
FRAME_TYPE frame_type;
#if CONFIG_MULTI_REF
// frame type for the frame before the last
FRAME_TYPE last2_frame_type;
// frame type for the frame two frames before the last
FRAME_TYPE last3_frame_type;
#endif // CONFIG_MULTI_REF
int show_frame;
int last_show_frame;
@ -166,7 +197,11 @@ typedef struct VP9Common {
// Context probabilities for reference frame prediction
int allow_comp_inter_inter;
MV_REFERENCE_FRAME comp_fixed_ref;
#if CONFIG_MULTI_REF
MV_REFERENCE_FRAME comp_var_ref[5];
#else // CONFIG_MULTI_REF
MV_REFERENCE_FRAME comp_var_ref[2];
#endif // CONFIG_MULTI_REF
REFERENCE_MODE reference_mode;
FRAME_CONTEXT fc; /* this frame entropy */
@ -189,6 +224,8 @@ typedef struct VP9Common {
int frame_parallel_decoding_mode;
int log2_tile_cols, log2_tile_rows;
int tile_cols, tile_rows;
int tile_width, tile_height;
// Private data associated with the frame buffer callbacks.
void *cb_priv;
@ -200,6 +237,33 @@ typedef struct VP9Common {
PARTITION_CONTEXT *above_seg_context;
ENTROPY_CONTEXT *above_context;
#if CONFIG_PALETTE
#if CONFIG_VP9_HIGHBITDEPTH
uint16_t current_palette_colors[PALETTE_BUF_SIZE];
#else
uint8_t current_palette_colors[PALETTE_BUF_SIZE];
#endif
int current_palette_size;
int current_palette_count[PALETTE_BUF_SIZE];
int allow_palette_mode;
int palette_counter;
int palette_blocks_signalled;
#endif // CONFIG_PALETTE
#if CONFIG_INTRABC
int allow_intrabc_mode;
int intrabc_counter;
int intrabc_blocks_signalled;
#endif // CONFIG_INTRABC
#if CONFIG_GLOBAL_MOTION
int num_global_motion[MAX_REF_FRAMES];
Global_Motion_Params global_motion[MAX_REF_FRAMES][MAX_GLOBAL_MOTION_MODELS];
#endif
#if CONFIG_ROW_TILE
int tile_size_bytes;
int tile_col_size_bytes;
#endif
} VP9_COMMON;
static INLINE YV12_BUFFER_CONFIG *get_ref_frame(VP9_COMMON *cm, int index) {
@ -250,6 +314,12 @@ static INLINE void init_macroblockd(VP9_COMMON *cm, MACROBLOCKD *xd) {
i * sizeof(*cm->above_context) * 2 * mi_cols_aligned_to_sb(cm->mi_cols);
}
#if CONFIG_PALETTE
for (i = 0; i < 2; ++i) {
xd->plane[i].color_index_map = xd->color_index_map[i];
}
#endif
xd->above_seg_context = cm->above_seg_context;
xd->mi_stride = cm->mi_stride;
}
@ -266,7 +336,7 @@ static INLINE const vp9_prob* get_partition_probs(const VP9_COMMON *cm,
static INLINE void set_skip_context(MACROBLOCKD *xd, int mi_row, int mi_col) {
const int above_idx = mi_col * 2;
const int left_idx = (mi_row * 2) & 15;
const int left_idx = (mi_row * 2) & MI_MASK_2;
int i;
for (i = 0; i < MAX_MB_PLANE; ++i) {
struct macroblockd_plane *const pd = &xd->plane[i];
@ -280,7 +350,7 @@ static INLINE int calc_mi_size(int len) {
return len + MI_BLOCK_SIZE;
}
static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
static void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
int mi_row, int bh,
int mi_col, int bw,
int mi_rows, int mi_cols) {
@ -290,7 +360,11 @@ static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
xd->mb_to_right_edge = ((mi_cols - bw - mi_col) * MI_SIZE) * 8;
// Are edges available for intra prediction?
#if CONFIG_ROW_TILE
xd->up_available = (mi_row > tile->mi_row_start);
#else
xd->up_available = (mi_row != 0);
#endif
xd->left_available = (mi_col > tile->mi_col_start);
}
@ -311,7 +385,12 @@ static INLINE void update_partition_context(MACROBLOCKD *xd,
BLOCK_SIZE bsize) {
PARTITION_CONTEXT *const above_ctx = xd->above_seg_context + mi_col;
PARTITION_CONTEXT *const left_ctx = xd->left_seg_context + (mi_row & MI_MASK);
#if CONFIG_EXT_PARTITION
const int bw = num_8x8_blocks_wide_lookup[bsize];
const int bh = num_8x8_blocks_high_lookup[bsize];
vpx_memset(above_ctx, partition_context_lookup[subsize].above, bw);
vpx_memset(left_ctx, partition_context_lookup[subsize].left, bh);
#else
// num_4x4_blocks_wide_lookup[bsize] / 2
const int bs = num_8x8_blocks_wide_lookup[bsize];
@ -320,8 +399,50 @@ static INLINE void update_partition_context(MACROBLOCKD *xd,
// bits of smaller block sizes to be zero.
vpx_memset(above_ctx, partition_context_lookup[subsize].above, bs);
vpx_memset(left_ctx, partition_context_lookup[subsize].left, bs);
#endif
}
#if CONFIG_EXT_PARTITION
static INLINE void update_ext_partition_context(MACROBLOCKD *xd,
int mi_row, int mi_col,
BLOCK_SIZE subsize,
BLOCK_SIZE bsize,
PARTITION_TYPE partition) {
if (bsize >= BLOCK_8X8) {
const int bsl = b_width_log2_lookup[bsize], hbs = (1 << bsl) / 4;
BLOCK_SIZE bsize2 = get_subsize(bsize, PARTITION_SPLIT);
switch (partition) {
case PARTITION_SPLIT:
if (bsize != BLOCK_8X8)
break;
case PARTITION_NONE:
case PARTITION_HORZ:
case PARTITION_VERT:
update_partition_context(xd, mi_row, mi_col, subsize, bsize);
break;
case PARTITION_HORZ_A:
update_partition_context(xd, mi_row, mi_col, bsize2, subsize);
update_partition_context(xd, mi_row + hbs, mi_col, subsize, subsize);
break;
case PARTITION_HORZ_B:
update_partition_context(xd, mi_row, mi_col, subsize, subsize);
update_partition_context(xd, mi_row + hbs, mi_col, bsize2, subsize);
break;
case PARTITION_VERT_A:
update_partition_context(xd, mi_row, mi_col, bsize2, subsize);
update_partition_context(xd, mi_row, mi_col + hbs, subsize, subsize);
break;
case PARTITION_VERT_B:
update_partition_context(xd, mi_row, mi_col, subsize, subsize);
update_partition_context(xd, mi_row, mi_col + hbs, bsize2, subsize);
break;
default:
assert(0 && "Invalid partition type");
}
}
}
#endif
static INLINE int partition_plane_context(const MACROBLOCKD *xd,
int mi_row, int mi_col,
BLOCK_SIZE bsize) {
@ -345,6 +466,18 @@ static INLINE int partition_plane_context(const MACROBLOCKD *xd,
return (left * 2 + above) + bsl * PARTITION_PLOFFSET;
}
static INLINE int16_t vp9_get_quant(VP9_COMMON *const cm,
int qindex, int isuv, int isac) {
int quant;
if (!isuv) {
quant = isac == 0 ? vp9_dc_quant(qindex, cm->y_dc_delta_q, cm->bit_depth)
: vp9_ac_quant(qindex, 0, cm->bit_depth);
} else {
quant = isac == 0 ? vp9_dc_quant(qindex, cm->uv_dc_delta_q, cm->bit_depth)
: vp9_ac_quant(qindex, cm->uv_ac_delta_q, cm->bit_depth);
}
return quant;
}
#ifdef __cplusplus
} // extern "C"
#endif

381
vp9/common/vp9_palette.c Normal file
View File

@ -0,0 +1,381 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "vp9/common/vp9_palette.h"
#if CONFIG_PALETTE
void vp9_insertion_sort(double *data, int n) {
int i, j, k;
double val;
if (n <= 1)
return;
for (i = 1; i < n; i++) {
val = data[i];
j = 0;
while (val > data[j] && j < i)
j++;
if (j == i)
continue;
for (k = i; k > j; k--)
data[k] = data[k - 1];
data[j] = val;
}
}
int vp9_count_colors(const uint8_t *src, int stride, int rows, int cols) {
int n = 0, r, c, i, val_count[256];
uint8_t val;
vpx_memset(val_count, 0, sizeof(val_count));
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
val = src[r * stride + c];
val_count[val]++;
}
}
for (i = 0; i < 256; i++) {
if (val_count[i]) {
n++;
}
}
return n;
}
#if CONFIG_VP9_HIGHBITDEPTH
int vp9_count_colors_highbd(const uint8_t *src8, int stride, int rows, int cols,
int bit_depth) {
int n = 0, r, c, i;
uint16_t val;
uint16_t *src = CONVERT_TO_SHORTPTR(src8);
int* val_count = vpx_calloc(1 << bit_depth, sizeof(*val_count));
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
val = src[r * stride + c];
val_count[val]++;
}
}
for (i = 0; i < (1 << bit_depth); i++) {
if (val_count[i]) {
n++;
}
}
vpx_free(val_count);
return n;
}
#endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_VP9_HIGHBITDEPTH
void vp9_palette_color_insertion(uint16_t *old_colors, int *m, int *count,
const MB_MODE_INFO *mbmi) {
const uint16_t *new_colors = mbmi->palette_literal_colors;
uint16_t val;
#else
void vp9_palette_color_insertion(uint8_t *old_colors, int *m, int *count,
const MB_MODE_INFO *mbmi) {
const uint8_t *new_colors = mbmi->palette_literal_colors;
uint8_t val;
#endif // CONFIG_VP9_HIGHBITDEPTH
int k = *m, n = mbmi->palette_literal_size;
int i, j, l, min_idx = -1;
if (mbmi->palette_indexed_size > 0) {
for (i = 0; i < mbmi->palette_indexed_size; i++)
count[mbmi->palette_indexed_colors[i]] +=
(8 - abs(mbmi->palette_color_delta[i]));
}
i = 0;
while (i < k) {
count[i] -= 1;
i++;
}
if (n <= 0)
return;
for (i = 0; i < n; i++) {
val = new_colors[i];
j = 0;
while (val != old_colors[j] && j < k)
j++;
if (j < k && val == old_colors[j]) {
count[j] += 8;
continue;
}
if (k + 1 > PALETTE_BUF_SIZE) {
min_idx = 0;
for (l = 1; l < k; l++)
if (count[l] < count[min_idx])
min_idx = l;
old_colors[min_idx] = val;
count[min_idx] = 8;
} else {
old_colors[k] = val;
count[k] = 8;
k++;
}
}
*m = k;
}
#if CONFIG_VP9_HIGHBITDEPTH
int vp9_palette_color_lookup(uint16_t *dic, int n, uint16_t val, int bits) {
#else
int vp9_palette_color_lookup(uint8_t *dic, int n, uint8_t val, int bits) {
#endif // CONFIG_VP9_HIGHBITDEPTH
int j, min, arg_min = 0, i = 1;
if (n < 1)
return -1;
min = abs(val - dic[0]);
arg_min = 0;
while (i < n) {
j = abs(val - dic[i]);
if (j < min) {
min = j;
arg_min = i;
}
i++;
}
if (min < (1 << bits))
return arg_min;
else
return -1;
}
int vp9_ceil_log2(int n) {
int i = 1, p = 2;
while (p < n) {
i++;
p = p << 1;
}
return i;
}
static double calc_dist(const double *p1, const double *p2, int dim) {
double dist = 0;
int i = 0;
for (i = 0; i < dim; i++) {
dist = dist + (p1[i] - p2[i]) * (p1[i] - p2[i]);
}
return dist;
}
void vp9_calc_indices(const double *data, const double *centroids, int *indices,
int n, int k, int dim) {
int i, j;
double min_dist, this_dist;
for (i = 0; i < n; i++) {
min_dist = calc_dist(data + i * dim, centroids, dim);
indices[i] = 0;
for (j = 1; j < k; j++) {
this_dist = calc_dist(data + i * dim, centroids + j * dim, dim);
if (this_dist < min_dist) {
min_dist = this_dist;
indices[i] = j;
}
}
}
}
static void calc_centroids(const double *data, double *centroids,
const int *indices, int n, int k, int dim) {
int i, j, index;
int count[256];
srand((unsigned int) data[0]);
vpx_memset(count, 0, sizeof(count[0]) * k);
vpx_memset(centroids, 0, sizeof(centroids[0]) * k * dim);
for (i = 0; i < n; i++) {
index = indices[i];
count[index]++;
for (j = 0; j < dim; j++) {
centroids[index * dim + j] += data[i * dim + j];
}
}
for (i = 0; i < k; i++) {
if (count[i] == 0) {
vpx_memcpy(centroids + i * dim, data + (rand() % n) * dim,
sizeof(centroids[0]) * dim);
} else {
const double norm = 1.0 / count[i];
for (j = 0; j < dim; j++)
centroids[i * dim + j] *= norm;
}
}
}
static double calc_total_dist(const double *data, const double *centroids,
const int *indices, int n, int k, int dim) {
double dist = 0;
int i;
(void) k;
for (i = 0; i < n; i++) {
dist += calc_dist(data + i * dim, centroids + indices[i] * dim, dim);
}
return dist;
}
int vp9_k_means(const double *data, double *centroids, int *indices,
int n, int k, int dim, int max_itr) {
int i = 0;
int *pre_indices;
double pre_total_dist, cur_total_dist;
double pre_centroids[256];
pre_indices = vpx_memalign(16, n * sizeof(indices[0]));
vp9_calc_indices(data, centroids, indices, n, k, dim);
pre_total_dist = calc_total_dist(data, centroids, indices, n, k, dim);
vpx_memcpy(pre_centroids, centroids, sizeof(pre_centroids[0]) * k * dim);
vpx_memcpy(pre_indices, indices, sizeof(pre_indices[0]) * n);
while (i < max_itr) {
calc_centroids(data, centroids, indices, n, k, dim);
vp9_calc_indices(data, centroids, indices, n, k, dim);
cur_total_dist = calc_total_dist(data, centroids, indices, n, k, dim);
if (cur_total_dist > pre_total_dist) {
vpx_memcpy(centroids, pre_centroids, sizeof(pre_centroids[0]) * k * dim);
vpx_memcpy(indices, pre_indices, sizeof(pre_indices[0]) * n);
break;
}
if (!memcmp(centroids, pre_centroids, sizeof(pre_centroids[0]) * k * dim))
break;
vpx_memcpy(pre_centroids, centroids, sizeof(pre_centroids[0]) * k * dim);
vpx_memcpy(pre_indices, indices, sizeof(pre_indices[0]) * n);
pre_total_dist = cur_total_dist;
i++;
}
vpx_free(pre_indices);
return i;
}
void vp9_update_palette_counts(FRAME_COUNTS *counts, const MB_MODE_INFO *mbmi,
BLOCK_SIZE bsize, int palette_ctx) {
int idx = bsize - BLOCK_8X8;
counts->y_palette_enabled[idx][palette_ctx][mbmi->palette_enabled[0]]++;
counts->uv_palette_enabled[mbmi->palette_enabled[0]]
[mbmi->palette_enabled[1]]++;
if (mbmi->palette_enabled[0])
counts->y_palette_size[idx][mbmi->palette_size[0] - 2]++;
if (mbmi->palette_enabled[1])
counts->uv_palette_size[idx][mbmi->palette_size[1] - 2]++;
}
static const int palette_color_context_lookup[PALETTE_COLOR_CONTEXTS] = {
3993, 4235, 4378, 4380, // (3, 0, 0, 0), (3, 2, 0, 0),
// (3, 3, 2, 0), (3, 3, 2, 2),
5720, 6655, 7018, 7040, // (4, 3, 3, 0), (5, 0, 0, 0),
// (5, 3, 0, 0), (5, 3, 2, 0),
7260, 8228, 8250, 8470, // (5, 5, 0, 0), (6, 2, 0, 0),
// (6, 2, 2, 0), (6, 4, 0, 0),
9680, 10648, 10890, 13310 // (7, 3, 0, 0), (8, 0, 0, 0),
// (8, 2, 0, 0), (10, 0, 0, 0)
};
int vp9_get_palette_color_context(const uint8_t *color_map, int cols,
int r, int c, int n, int *color_order) {
int i, j, max, max_idx, temp;
int scores[PALETTE_MAX_SIZE + 10];
int weights[4] = {3, 2, 3, 2};
int color_ctx = 0;
int color_neighbors[4];
assert(n <= PALETTE_MAX_SIZE);
if (c - 1 >= 0)
color_neighbors[0] = color_map[r * cols + c - 1];
else
color_neighbors[0] = -1;
if (c - 1 >= 0 && r - 1 >= 0)
color_neighbors[1] = color_map[(r - 1) * cols + c - 1];
else
color_neighbors[1] = -1;
if (r - 1 >= 0)
color_neighbors[2] = color_map[(r - 1) * cols + c];
else
color_neighbors[2] = -1;
if (r - 1 >= 0 && c + 1 <= cols - 1)
color_neighbors[3] = color_map[(r - 1) * cols + c + 1];
else
color_neighbors[3] = -1;
for (i = 0; i < PALETTE_MAX_SIZE; i++)
color_order[i] = i;
memset(scores, 0, PALETTE_MAX_SIZE * sizeof(scores[0]));
for (i = 0; i < 4; i++) {
if (color_neighbors[i] >= 0)
scores[color_neighbors[i]] += weights[i];
}
for (i = 0; i < 4; i++) {
max = scores[i];
max_idx = i;
j = i + 1;
while (j < n) {
if (scores[j] > max) {
max = scores[j];
max_idx = j;
}
j++;
}
if (max_idx != i) {
temp = scores[i];
scores[i] = scores[max_idx];
scores[max_idx] = temp;
temp = color_order[i];
color_order[i] = color_order[max_idx];
color_order[max_idx] = temp;
}
}
for (i = 0; i < 4; i++)
color_ctx = color_ctx * 11 + scores[i];
for (i = 0; i < PALETTE_COLOR_CONTEXTS; i++)
if (color_ctx == palette_color_context_lookup[i]) {
color_ctx = i;
break;
}
return color_ctx;
}
#endif // CONFIG_PALETTE

42
vp9/common/vp9_palette.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VP9_COMMON_VP9_PALETTE_H_
#define VP9_COMMON_VP9_PALETTE_H_
#include "vp9/common/vp9_blockd.h"
#include "vp9/common/vp9_entropymode.h"
#if CONFIG_PALETTE
int vp9_count_colors(const uint8_t *src, int stride, int rows, int cols);
#if CONFIG_VP9_HIGHBITDEPTH
int vp9_count_colors_highbd(const uint8_t *src8, int stride, int rows, int cols,
int bit_depth);
void vp9_palette_color_insertion(uint16_t *old_colors, int *m, int *count,
const MB_MODE_INFO *mbmi);
int vp9_palette_color_lookup(uint16_t *dic, int n, uint16_t val, int bits);
#else
void vp9_palette_color_insertion(uint8_t *old_colors, int *m, int *count,
const MB_MODE_INFO *mbmi);
int vp9_palette_color_lookup(uint8_t *dic, int n, uint8_t val, int bits);
#endif // CONFIG_VP9_HIGHBITDEPTH
void vp9_insertion_sort(double *data, int n);
int vp9_ceil_log2(int n);
int vp9_k_means(const double *data, double *centroids, int *indices,
int n, int k, int dim, int max_itr);
void vp9_calc_indices(const double *data, const double *centroids, int *indices,
int n, int k, int dim);
void vp9_update_palette_counts(FRAME_COUNTS *counts, const MB_MODE_INFO *mbmi,
BLOCK_SIZE bsize, int palette_ctx);
int vp9_get_palette_color_context(const uint8_t *color_map, int cols,
int r, int c, int n, int *color_order);
#endif
#endif // VP9_COMMON_VP9_PALETTE_H_

View File

@ -109,6 +109,420 @@ int vp9_get_reference_mode_context(const VP9_COMMON *cm,
return ctx;
}
#if CONFIG_MULTI_REF
#define CHECK_LAST_OR_LAST2(ref_frame) \
((ref_frame == LAST_FRAME) || (ref_frame == LAST2_FRAME))
#define CHECK_GOLDEN_LAST3_LAST4(ref_frame) \
((ref_frame == GOLDEN_FRAME) || (ref_frame == LAST3_FRAME) || \
(ref_frame == LAST4_FRAME))
// TODO(zoeliu): Would like to create a master function.
// Returns a context number for the given MB prediction signal
// Signal the first reference frame for a compound mode is either
// GOLDEN/LAST3/LAST4, or LAST/LAST2.
//
// NOTE(zoeliu): The probability of ref_frame[0] is either
// GOLDEN_FRAME/LAST3_FRAME/LAST4_FRAME.
int vp9_get_pred_context_comp_ref_p(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int above_in_image = above_mbmi != NULL;
const int left_in_image = left_mbmi != NULL;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
const int fix_ref_idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref];
const int var_ref_idx = !fix_ref_idx;
if (above_in_image && left_in_image) { // both edges available
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) { // intra/intra (2)
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) // single pred (1/3)
pred_context = 1 +
2 * (!CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[0]));
else // comp pred (1/3)
pred_context = 1 +
2 * (!CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[var_ref_idx]));
} else { // inter/inter
const int l_sg = !has_second_ref(left_mbmi);
const int a_sg = !has_second_ref(above_mbmi);
const MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
const MV_REFERENCE_FRAME vrfl = l_sg ? left_mbmi->ref_frame[0]
: left_mbmi->ref_frame[var_ref_idx];
if (vrfa == vrfl && CHECK_GOLDEN_LAST3_LAST4(vrfa)) {
pred_context = 0;
} else if (l_sg && a_sg) { // single/single
if ((vrfa == ALTREF_FRAME && CHECK_LAST_OR_LAST2(vrfl)) ||
(vrfl == ALTREF_FRAME && CHECK_LAST_OR_LAST2(vrfa))) {
pred_context = 4;
} else if (vrfa == vrfl || (CHECK_LAST_OR_LAST2(vrfa) &&
CHECK_LAST_OR_LAST2(vrfl))) {
pred_context = 3;
} else { // Either vrfa or vrfl is GOLDEN / LAST3 / LAST4
// NOTE(zoeliu): Following assert may be removed once confirmed.
assert(CHECK_GOLDEN_LAST3_LAST4(vrfa) ||
CHECK_GOLDEN_LAST3_LAST4(vrfl));
pred_context = 1;
}
} else if (l_sg || a_sg) { // single/comp
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
const MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
if (CHECK_GOLDEN_LAST3_LAST4(vrfc) && !CHECK_GOLDEN_LAST3_LAST4(rfs))
pred_context = 1;
else if (CHECK_GOLDEN_LAST3_LAST4(rfs) &&
!CHECK_GOLDEN_LAST3_LAST4(vrfc))
pred_context = 2;
else
pred_context = 4;
} else { // comp/comp
if ((CHECK_LAST_OR_LAST2(vrfa) && CHECK_LAST_OR_LAST2(vrfl))) {
pred_context = 4;
} else {
// NOTE(zoeliu): Following assert may be removed once confirmed.
assert(CHECK_GOLDEN_LAST3_LAST4(vrfa) ||
CHECK_GOLDEN_LAST3_LAST4(vrfl));
pred_context = 2;
}
}
}
} else if (above_in_image || left_in_image) { // one edge available
const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi)) {
pred_context = 2;
} else {
if (has_second_ref(edge_mbmi))
pred_context =
4 * (!CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[var_ref_idx]));
else
pred_context = 3 * (!CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[0]));
}
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
// Returns a context number for the given MB prediction signal
// Signal the first reference frame for a compound mode is LAST,
// conditioning on that it is known either LAST/LAST2.
//
// NOTE(zoeliu): The probability of ref_frame[0] is LAST_FRAME,
// conditioning on it is either LAST_FRAME or LAST2_FRAME.
int vp9_get_pred_context_comp_ref_p1(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int above_in_image = above_mbmi != NULL;
const int left_in_image = left_mbmi != NULL;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
const int fix_ref_idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref];
const int var_ref_idx = !fix_ref_idx;
if (above_in_image && left_in_image) { // both edges available
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) { // intra/intra (2)
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) // single pred (1/3)
pred_context = 1 + 2 * (edge_mbmi->ref_frame[0] != LAST_FRAME);
else // comp pred (1/3)
pred_context = 1 + 2 * (edge_mbmi->ref_frame[var_ref_idx]
!= LAST_FRAME);
} else { // inter/inter
const int l_sg = !has_second_ref(left_mbmi);
const int a_sg = !has_second_ref(above_mbmi);
const MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
const MV_REFERENCE_FRAME vrfl = l_sg ? left_mbmi->ref_frame[0]
: left_mbmi->ref_frame[var_ref_idx];
if (vrfa == vrfl && vrfa == LAST_FRAME)
pred_context = 0;
else if (l_sg && a_sg) { // single/single
if (vrfa == LAST_FRAME || vrfl == LAST_FRAME)
pred_context = 1;
else if (CHECK_GOLDEN_LAST3_LAST4(vrfa) ||
CHECK_GOLDEN_LAST3_LAST4(vrfl))
pred_context = 2 + (vrfa != vrfl);
else if (vrfa == vrfl)
pred_context = 3;
else
pred_context = 4;
} else if (l_sg || a_sg) { // single/comp
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
const MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
if (vrfc == LAST_FRAME && rfs != LAST_FRAME)
pred_context = 1;
else if (rfs == LAST_FRAME && vrfc != LAST_FRAME)
pred_context = 2;
else
pred_context = 3 +
(vrfc == LAST2_FRAME || CHECK_GOLDEN_LAST3_LAST4(rfs));
} else { // comp/comp
if (vrfa == LAST_FRAME || vrfl == LAST_FRAME)
pred_context = 2;
else
pred_context = 3 + (CHECK_GOLDEN_LAST3_LAST4(vrfa) ||
CHECK_GOLDEN_LAST3_LAST4(vrfl));
}
}
} else if (above_in_image || left_in_image) { // one edge available
const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi)) {
pred_context = 2;
} else {
if (has_second_ref(edge_mbmi)) {
pred_context = 4 * (edge_mbmi->ref_frame[var_ref_idx] != LAST_FRAME);
} else {
if (edge_mbmi->ref_frame[0] == LAST_FRAME)
pred_context = 0;
else
pred_context = 2 + CHECK_GOLDEN_LAST3_LAST4(edge_mbmi->ref_frame[0]);
}
}
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
#define CHECK_LAST3_OR_LAST4(ref_frame) \
((ref_frame == LAST3_FRAME) || (ref_frame == LAST4_FRAME))
// Returns a context number for the given MB prediction signal
// Signal the first reference frame for a compound mode is GOLDEN,
// conditioning on that it is known either GOLDEN/LAST3/LAST4.
//
// NOTE(zoeliu): The probability of ref_frame[0] is GOLDEN_FRAME,
// conditioning on it is either GOLDEN / LAST3 / LAST4.
int vp9_get_pred_context_comp_ref_p2(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int above_in_image = above_mbmi != NULL;
const int left_in_image = left_mbmi != NULL;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
const int fix_ref_idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref];
const int var_ref_idx = !fix_ref_idx;
if (above_in_image && left_in_image) { // both edges available
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) { // intra/intra (2)
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) // single pred (1/3)
pred_context = 1 + 2 * (edge_mbmi->ref_frame[0] != GOLDEN_FRAME);
else // comp pred (1/3)
pred_context = 1 +
2 * (edge_mbmi->ref_frame[var_ref_idx] != GOLDEN_FRAME);
} else { // inter/inter
const int l_sg = !has_second_ref(left_mbmi);
const int a_sg = !has_second_ref(above_mbmi);
const MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
const MV_REFERENCE_FRAME vrfl = l_sg ? left_mbmi->ref_frame[0]
: left_mbmi->ref_frame[var_ref_idx];
if (vrfa == vrfl && vrfa == GOLDEN_FRAME)
pred_context = 0;
else if (l_sg && a_sg) { // single/single
if (vrfa == GOLDEN_FRAME || vrfl == GOLDEN_FRAME)
pred_context = 1;
else if (CHECK_LAST_OR_LAST2(vrfa) || CHECK_LAST_OR_LAST2(vrfl))
pred_context = 2 + (vrfa != vrfl);
else if (vrfa == vrfl)
pred_context = 3;
else
pred_context = 4;
} else if (l_sg || a_sg) { // single/comp
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
const MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
if (vrfc == GOLDEN_FRAME && rfs != GOLDEN_FRAME)
pred_context = 1;
else if (rfs == GOLDEN_FRAME && vrfc != GOLDEN_FRAME)
pred_context = 2;
else
pred_context = 3 +
(CHECK_LAST3_OR_LAST4(vrfc) || CHECK_LAST_OR_LAST2(rfs));
} else { // comp/comp
if (vrfa == GOLDEN_FRAME || vrfl == GOLDEN_FRAME)
pred_context = 2;
else
pred_context = 3 +
(CHECK_LAST_OR_LAST2(vrfa) || CHECK_LAST_OR_LAST2(vrfl));
}
}
} else if (above_in_image || left_in_image) { // one edge available
const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi)) {
pred_context = 2;
} else {
if (has_second_ref(edge_mbmi)) {
pred_context = 4 * (edge_mbmi->ref_frame[var_ref_idx] != GOLDEN_FRAME);
} else {
if (edge_mbmi->ref_frame[0] == GOLDEN_FRAME)
pred_context = 0;
else
pred_context = 2 + CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]);
}
}
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
#define CHECK_LAST_LAST2_GOLDEN(ref_frame) \
((ref_frame == LAST_FRAME) || (ref_frame == LAST2_FRAME) || \
(ref_frame == GOLDEN_FRAME))
// Returns a context number for the given MB prediction signal
// Signal the first reference frame for a compound mode is LAST3,
// conditioning on that it is known either LAST3/LAST4.
//
// NOTE(zoeliu): The probability of ref_frame[0] is LAST3_FRAME,
// conditioning on it is either LAST3 / LAST4.
int vp9_get_pred_context_comp_ref_p3(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int above_in_image = above_mbmi != NULL;
const int left_in_image = left_mbmi != NULL;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
const int fix_ref_idx = cm->ref_frame_sign_bias[cm->comp_fixed_ref];
const int var_ref_idx = !fix_ref_idx;
if (above_in_image && left_in_image) { // both edges available
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) { // intra/intra (2)
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) // single pred (1/3)
pred_context = 1 + 2 * (edge_mbmi->ref_frame[0] != LAST3_FRAME);
else // comp pred (1/3)
pred_context = 1 +
2 * (edge_mbmi->ref_frame[var_ref_idx] != LAST3_FRAME);
} else { // inter/inter
const int l_sg = !has_second_ref(left_mbmi);
const int a_sg = !has_second_ref(above_mbmi);
const MV_REFERENCE_FRAME vrfa = a_sg ? above_mbmi->ref_frame[0]
: above_mbmi->ref_frame[var_ref_idx];
const MV_REFERENCE_FRAME vrfl = l_sg ? left_mbmi->ref_frame[0]
: left_mbmi->ref_frame[var_ref_idx];
if (vrfa == vrfl && vrfa == LAST3_FRAME)
pred_context = 0;
else if (l_sg && a_sg) { // single/single
if (vrfa == LAST3_FRAME || vrfl == LAST3_FRAME)
pred_context = 1;
else if (CHECK_LAST_LAST2_GOLDEN(vrfa) || CHECK_LAST_LAST2_GOLDEN(vrfl))
pred_context = 2 + (vrfa != vrfl);
else if (vrfa == vrfl)
pred_context = 3;
else
pred_context = 4;
} else if (l_sg || a_sg) { // single/comp
const MV_REFERENCE_FRAME vrfc = l_sg ? vrfa : vrfl;
const MV_REFERENCE_FRAME rfs = a_sg ? vrfa : vrfl;
if (vrfc == LAST3_FRAME && rfs != LAST3_FRAME)
pred_context = 1;
else if (rfs == LAST3_FRAME && vrfc != LAST3_FRAME)
pred_context = 2;
else
pred_context = 3 +
(vrfc == LAST4_FRAME || CHECK_LAST_LAST2_GOLDEN(rfs));
} else { // comp/comp
if (vrfa == LAST3_FRAME || vrfl == LAST3_FRAME)
pred_context = 2;
else
pred_context = 3 +
(CHECK_LAST_LAST2_GOLDEN(vrfa) || CHECK_LAST_LAST2_GOLDEN(vrfl));
}
}
} else if (above_in_image || left_in_image) { // one edge available
const MB_MODE_INFO *edge_mbmi = above_in_image ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi)) {
pred_context = 2;
} else {
if (has_second_ref(edge_mbmi)) {
pred_context = 4 * (edge_mbmi->ref_frame[var_ref_idx] != LAST3_FRAME);
} else {
if (edge_mbmi->ref_frame[0] == LAST3_FRAME)
pred_context = 0;
else
pred_context = 2 + CHECK_LAST_LAST2_GOLDEN(edge_mbmi->ref_frame[0]);
}
}
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
#else // CONFIG_MULTI_REF
// Returns a context number for the given MB prediction signal
int vp9_get_pred_context_comp_ref_p(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
@ -192,6 +606,479 @@ int vp9_get_pred_context_comp_ref_p(const VP9_COMMON *cm,
return pred_context;
}
#endif // CONFIG_MULTI_REF
#if CONFIG_MULTI_REF
#define CHECK_LAST_LAST2_LAST3(ref_frame) \
((ref_frame == LAST_FRAME) || (ref_frame == LAST2_FRAME) || \
(ref_frame == LAST3_FRAME))
#define CHECK_GOLDEN_OR_ALTREF(ref_frame) \
((ref_frame == GOLDEN_FRAME) || (ref_frame == ALTREF_FRAME))
// For the bit to signal whether the single reference is a ALTREF_FRAME
// or a GOLDEN_FRAME.
//
// NOTE(zoeliu): The probability of ref_frame[0] is ALTREF/GOLDEN.
int vp9_get_pred_context_single_ref_p1(const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int has_above = above_mbmi != NULL;
const int has_left = left_mbmi != NULL;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
if (has_above && has_left) { // both edges available
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) { // intra/intra
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter or inter/intra
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi))
pred_context = 4 * (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]));
else
pred_context = 1 + (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]) ||
!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[1]));
} else { // inter/inter
const int above_has_second = has_second_ref(above_mbmi);
const int left_has_second = has_second_ref(left_mbmi);
const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1];
const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1];
if (above_has_second && left_has_second) {
pred_context = 1 + (!CHECK_GOLDEN_OR_ALTREF(above0) ||
!CHECK_GOLDEN_OR_ALTREF(above1) ||
!CHECK_GOLDEN_OR_ALTREF(left0) ||
!CHECK_GOLDEN_OR_ALTREF(left1));
} else if (above_has_second || left_has_second) {
const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1;
if (!CHECK_GOLDEN_OR_ALTREF(rfs))
pred_context = 3 + (!CHECK_GOLDEN_OR_ALTREF(crf1) ||
!CHECK_GOLDEN_OR_ALTREF(crf2));
else
pred_context = !CHECK_GOLDEN_OR_ALTREF(crf1) ||
!CHECK_GOLDEN_OR_ALTREF(crf2);
} else {
pred_context = 2 * (!CHECK_GOLDEN_OR_ALTREF(above0)) +
2 * (!CHECK_GOLDEN_OR_ALTREF(left0));
}
}
} else if (has_above || has_left) { // one edge available
const MB_MODE_INFO *edge_mbmi = has_above ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi)) { // intra
pred_context = 2;
} else { // inter
if (!has_second_ref(edge_mbmi))
pred_context = 4 * (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]));
else
pred_context = 1 + (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]) ||
!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[1]));
}
} else { // no edges available
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
// For the bit to signal whether the single reference is ALTREF_FRAME or
// GOLDEN_FRAME, knowing that it shall be either of these 2 choices.
//
// NOTE(zoeliu): The probability of ref_frame[0] is ALTREF_FRAME, conditioning
// on it is either ALTREF_FRAME/GOLDEN_FRAME.
int vp9_get_pred_context_single_ref_p2(const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int has_above = above_mbmi != NULL;
const int has_left = left_mbmi != NULL;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
if (has_above && has_left) { // both edges available
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) { // intra/intra
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter or inter/intra
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) {
if (!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]))
pred_context = 3;
else
pred_context = 4 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME);
} else {
pred_context = 1 + 2 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME ||
edge_mbmi->ref_frame[1] == GOLDEN_FRAME);
}
} else { // inter/inter
const int above_has_second = has_second_ref(above_mbmi);
const int left_has_second = has_second_ref(left_mbmi);
const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1];
const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1];
if (above_has_second && left_has_second) {
if (above0 == left0 && above1 == left1)
pred_context = 3 * (above0 == GOLDEN_FRAME ||
above1 == GOLDEN_FRAME ||
left0 == GOLDEN_FRAME ||
left1 == GOLDEN_FRAME);
else
pred_context = 2;
} else if (above_has_second || left_has_second) {
const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1;
if (rfs == GOLDEN_FRAME)
pred_context = 3 + (crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME);
else if (rfs == ALTREF_FRAME)
pred_context = (crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME);
else
pred_context = 1 + 2 * (crf1 == GOLDEN_FRAME || crf2 == GOLDEN_FRAME);
} else {
if (!CHECK_GOLDEN_OR_ALTREF(above0) && !CHECK_GOLDEN_OR_ALTREF(left0)) {
pred_context = 2 + (above0 == left0);
} else if (!CHECK_GOLDEN_OR_ALTREF(above0) ||
!CHECK_GOLDEN_OR_ALTREF(left0)) {
const MV_REFERENCE_FRAME edge0 =
!CHECK_GOLDEN_OR_ALTREF(above0) ? left0 : above0;
pred_context = 4 * (edge0 == GOLDEN_FRAME);
} else {
pred_context = 2 * (above0 == GOLDEN_FRAME) +
2 * (left0 == GOLDEN_FRAME);
}
}
}
} else if (has_above || has_left) { // one edge available
const MB_MODE_INFO *edge_mbmi = has_above ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi) ||
(!CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]) &&
!has_second_ref(edge_mbmi)))
pred_context = 2;
else if (!has_second_ref(edge_mbmi))
pred_context = 4 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME);
else
pred_context = 3 * (edge_mbmi->ref_frame[0] == GOLDEN_FRAME ||
edge_mbmi->ref_frame[1] == GOLDEN_FRAME);
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
// For the bit to signal whether the single reference is LAST3/LAST4 or
// LAST2/LAST, knowing that it shall be either of these 2 choices.
//
// NOTE(zoeliu): The probability of ref_frame[0] is LAST3/LAST4, conditioning
// on it is either LAST3/LAST4/LAST2/LAST.
int vp9_get_pred_context_single_ref_p3(const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int has_above = above_mbmi != NULL;
const int has_left = left_mbmi != NULL;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
if (has_above && has_left) { // both edges available
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) { // intra/intra
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter or inter/intra
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) {
if (CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]))
pred_context = 3;
else
pred_context = 4 * CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]);
} else {
pred_context = 1 +
2 * (CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]) ||
CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[1]));
}
} else { // inter/inter
const int above_has_second = has_second_ref(above_mbmi);
const int left_has_second = has_second_ref(left_mbmi);
const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1];
const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1];
if (above_has_second && left_has_second) {
if (above0 == left0 && above1 == left1)
pred_context = 3 * (CHECK_LAST_OR_LAST2(above0) ||
CHECK_LAST_OR_LAST2(above1) ||
CHECK_LAST_OR_LAST2(left0) ||
CHECK_LAST_OR_LAST2(left1));
else
pred_context = 2;
} else if (above_has_second || left_has_second) {
const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1;
if (CHECK_LAST_OR_LAST2(rfs))
pred_context = 3 + (CHECK_LAST_OR_LAST2(crf1) ||
CHECK_LAST_OR_LAST2(crf2));
else if (rfs == LAST3_FRAME || rfs == LAST4_FRAME)
pred_context = (CHECK_LAST_OR_LAST2(crf1) ||
CHECK_LAST_OR_LAST2(crf2));
else
pred_context = 1 + 2 * (CHECK_LAST_OR_LAST2(crf1) ||
CHECK_LAST_OR_LAST2(crf2));
} else {
if (CHECK_GOLDEN_OR_ALTREF(above0) && CHECK_GOLDEN_OR_ALTREF(left0)) {
pred_context = 2 + (above0 == left0);
} else if (CHECK_GOLDEN_OR_ALTREF(above0) ||
CHECK_GOLDEN_OR_ALTREF(left0)) {
const MV_REFERENCE_FRAME edge0 =
CHECK_GOLDEN_OR_ALTREF(above0) ? left0 : above0;
pred_context = 4 * CHECK_LAST_OR_LAST2(edge0);
} else {
pred_context = 2 * CHECK_LAST_OR_LAST2(above0) +
2 * CHECK_LAST_OR_LAST2(left0);
}
}
}
} else if (has_above || has_left) { // one edge available
const MB_MODE_INFO *edge_mbmi = has_above ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi) ||
(CHECK_GOLDEN_OR_ALTREF(edge_mbmi->ref_frame[0]) &&
!has_second_ref(edge_mbmi)))
pred_context = 2;
else if (!has_second_ref(edge_mbmi))
pred_context = 4 * (CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]));
else
pred_context = 3 * (CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]) ||
CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[1]));
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
// For the bit to signal whether the single reference is LAST2_FRAME or
// LAST_FRAME, knowing that it shall be either of these 2 choices.
//
// NOTE(zoeliu): The probability of ref_frame[0] is LAST2_FRAME, conditioning
// on it is either LAST2_FRAME/LAST_FRAME.
int vp9_get_pred_context_single_ref_p4(const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int has_above = above_mbmi != NULL;
const int has_left = left_mbmi != NULL;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
if (has_above && has_left) { // both edges available
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) { // intra/intra
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter or inter/intra
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) {
if (!CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]))
pred_context = 3;
else
pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST_FRAME);
} else {
pred_context = 1 +
2 * (edge_mbmi->ref_frame[0] == LAST_FRAME ||
edge_mbmi->ref_frame[1] == LAST_FRAME);
}
} else { // inter/inter
const int above_has_second = has_second_ref(above_mbmi);
const int left_has_second = has_second_ref(left_mbmi);
const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1];
const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1];
if (above_has_second && left_has_second) {
if (above0 == left0 && above1 == left1)
pred_context = 3 * (above0 == LAST_FRAME || above1 == LAST_FRAME ||
left0 == LAST_FRAME || left1 == LAST_FRAME);
else
pred_context = 2;
} else if (above_has_second || left_has_second) {
const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1;
if (rfs == LAST_FRAME)
pred_context = 3 + (crf1 == LAST_FRAME || crf2 == LAST_FRAME);
else if (rfs == LAST2_FRAME)
pred_context = (crf1 == LAST_FRAME || crf2 == LAST_FRAME);
else
pred_context = 1 + 2 * (crf1 == LAST_FRAME || crf2 == LAST_FRAME);
} else {
if (!CHECK_LAST_OR_LAST2(above0) &&
!CHECK_LAST_OR_LAST2(left0)) {
pred_context = 2 + (above0 == left0);
} else if (!CHECK_LAST_OR_LAST2(above0) ||
!CHECK_LAST_OR_LAST2(left0)) {
const MV_REFERENCE_FRAME edge0 =
!CHECK_LAST_OR_LAST2(above0) ? left0 : above0;
pred_context = 4 * (edge0 == LAST_FRAME);
} else {
pred_context = 2 * (above0 == LAST_FRAME) + 2 * (left0 == LAST_FRAME);
}
}
}
} else if (has_above || has_left) { // one edge available
const MB_MODE_INFO *edge_mbmi = has_above ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi) ||
(!CHECK_LAST_OR_LAST2(edge_mbmi->ref_frame[0]) &&
!has_second_ref(edge_mbmi)))
pred_context = 2;
else if (!has_second_ref(edge_mbmi))
pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST_FRAME);
else
pred_context = 3 * (edge_mbmi->ref_frame[0] == LAST_FRAME ||
edge_mbmi->ref_frame[1] == LAST_FRAME);
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
// For the bit to signal whether the single reference is LAST4_FRAME or
// LAST3_FRAME, knowing that it shall be either of these 2 choices.
//
// NOTE(zoeliu): The probability of ref_frame[0] is LAST4_FRAME, conditioning
// on it is either LAST4_FRAME/LAST3_FRAME.
int vp9_get_pred_context_single_ref_p5(const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int has_above = above_mbmi != NULL;
const int has_left = left_mbmi != NULL;
// Note:
// The mode info data structure has a one element border above and to the
// left of the entries correpsonding to real macroblocks.
// The prediction flags in these dummy entries are initialised to 0.
if (has_above && has_left) { // both edges available
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) { // intra/intra
pred_context = 2;
} else if (above_intra || left_intra) { // intra/inter or inter/intra
const MB_MODE_INFO *edge_mbmi = above_intra ? left_mbmi : above_mbmi;
if (!has_second_ref(edge_mbmi)) {
if (!CHECK_LAST3_OR_LAST4(edge_mbmi->ref_frame[0]))
pred_context = 3;
else
pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST3_FRAME);
} else {
pred_context = 1 +
2 * (edge_mbmi->ref_frame[0] == LAST3_FRAME ||
edge_mbmi->ref_frame[1] == LAST3_FRAME);
}
} else { // inter/inter
const int above_has_second = has_second_ref(above_mbmi);
const int left_has_second = has_second_ref(left_mbmi);
const MV_REFERENCE_FRAME above0 = above_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME above1 = above_mbmi->ref_frame[1];
const MV_REFERENCE_FRAME left0 = left_mbmi->ref_frame[0];
const MV_REFERENCE_FRAME left1 = left_mbmi->ref_frame[1];
if (above_has_second && left_has_second) {
if (above0 == left0 && above1 == left1)
pred_context = 3 * (above0 == LAST3_FRAME || above1 == LAST3_FRAME ||
left0 == LAST3_FRAME || left1 == LAST3_FRAME);
else
pred_context = 2;
} else if (above_has_second || left_has_second) {
const MV_REFERENCE_FRAME rfs = !above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf1 = above_has_second ? above0 : left0;
const MV_REFERENCE_FRAME crf2 = above_has_second ? above1 : left1;
if (rfs == LAST3_FRAME)
pred_context = 3 + (crf1 == LAST3_FRAME || crf2 == LAST3_FRAME);
else if (rfs == LAST4_FRAME)
pred_context = (crf1 == LAST3_FRAME || crf2 == LAST3_FRAME);
else
pred_context = 1 + 2 * (crf1 == LAST3_FRAME || crf2 == LAST3_FRAME);
} else {
if (!CHECK_LAST3_OR_LAST4(above0) &&
!CHECK_LAST3_OR_LAST4(left0)) {
pred_context = 2 + (above0 == left0);
} else if (!CHECK_LAST3_OR_LAST4(above0) ||
!CHECK_LAST3_OR_LAST4(left0)) {
const MV_REFERENCE_FRAME edge0 =
!CHECK_LAST3_OR_LAST4(above0) ? left0 : above0;
pred_context = 4 * (edge0 == LAST3_FRAME);
} else {
pred_context = 2 * (above0 == LAST3_FRAME) +
2 * (left0 == LAST3_FRAME);
}
}
}
} else if (has_above || has_left) { // one edge available
const MB_MODE_INFO *edge_mbmi = has_above ? above_mbmi : left_mbmi;
if (!is_inter_block(edge_mbmi) ||
(!CHECK_LAST3_OR_LAST4(edge_mbmi->ref_frame[0]) &&
!has_second_ref(edge_mbmi)))
pred_context = 2;
else if (!has_second_ref(edge_mbmi))
pred_context = 4 * (edge_mbmi->ref_frame[0] == LAST3_FRAME);
else
pred_context = 3 * (edge_mbmi->ref_frame[0] == LAST3_FRAME ||
edge_mbmi->ref_frame[1] == LAST3_FRAME);
} else { // no edges available (2)
pred_context = 2;
}
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
#else // CONFIG_MULTI_REF
int vp9_get_pred_context_single_ref_p1(const MACROBLOCKD *xd) {
int pred_context;
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
@ -343,6 +1230,9 @@ int vp9_get_pred_context_single_ref_p2(const MACROBLOCKD *xd) {
assert(pred_context >= 0 && pred_context < REF_CONTEXTS);
return pred_context;
}
#endif // CONFIG_MULTI_REF
// Returns a context number for the given MB prediction signal
// The mode info data structure has a one element border above and to the
// left of the entries corresponding to real blocks.
@ -383,3 +1273,47 @@ int vp9_get_segment_id(const VP9_COMMON *cm, const uint8_t *segment_ids,
assert(segment_id >= 0 && segment_id < MAX_SEGMENTS);
return segment_id;
}
#if CONFIG_COPY_MODE
int vp9_get_copy_mode_context(const MACROBLOCKD *xd) {
const MB_MODE_INFO *const above_mbmi = get_mbmi(get_above_mi(xd));
const MB_MODE_INFO *const left_mbmi = get_mbmi(get_left_mi(xd));
const int has_above = above_mbmi != NULL;
const int has_left = left_mbmi != NULL;
if (has_above && has_left) {
const int above_intra = !is_inter_block(above_mbmi);
const int left_intra = !is_inter_block(left_mbmi);
if (above_intra && left_intra) {
return 4;
} else if (above_intra || left_intra) {
return 3;
} else {
const int above_predict = above_mbmi->copy_mode != NOREF;
const int left_predict = left_mbmi->copy_mode != NOREF;
if (above_predict && left_predict)
return 0;
else if (above_predict || left_predict)
return 1;
else
return 2;
}
} else if (has_above || has_left) {
const MB_MODE_INFO *const ref_mbmi = has_above ? above_mbmi : left_mbmi;
const int ref_intra = !is_inter_block(ref_mbmi);
if (ref_intra) {
return 3;
} else {
const int ref_predict = ref_mbmi->copy_mode != NOREF;
if (ref_predict)
return 0;
else
return 1;
}
} else {
return 0;
}
}
#endif // CONFIG_COPY_MODE

View File

@ -57,6 +57,54 @@ static INLINE vp9_prob vp9_get_skip_prob(const VP9_COMMON *cm,
return cm->fc.skip_probs[vp9_get_skip_context(xd)];
}
#if CONFIG_SR_MODE
#include "vp9/common/vp9_sr_txfm.h"
static INLINE int vp9_get_sr_context(const MACROBLOCKD *xd,
BLOCK_SIZE bsize) {
TX_SIZE max_tx_size = max_txsize_lookup[bsize];
int ctx;
(void)xd;
assert(max_tx_size >= MIN_SR_TX_SIZE &&
max_tx_size <= MAX_SR_TX_SIZE);
ctx = max_tx_size - MIN_SR_TX_SIZE;
return ctx;
}
static INLINE vp9_prob vp9_get_sr_prob(const VP9_COMMON *cm,
const MACROBLOCKD *xd,
BLOCK_SIZE bsize) {
int sr_ctx = vp9_get_sr_context(xd, bsize);
assert(sr_ctx >= 0 && sr_ctx < SR_CONTEXTS);
return cm->fc.sr_probs[sr_ctx];
}
#if SR_USE_MULTI_F
static INLINE vp9_prob vp9_get_sr_usfilter_context(const MACROBLOCKD *xd) {
(void) xd;
return 0;
/*const MODE_INFO *const above_mi = get_above_mi(xd);
const MODE_INFO *const left_mi = get_left_mi(xd);
int above_sr_ver =
(above_mi != NULL && above_mi->mbmi.sr && !above_mi->mbmi.skip) ?
idx_to_v(above_mi->mbmi.us_filter_idx) : SR_USFILTER_NUM_D;
int left_sr_hor =
(left_mi != NULL && left_mi->mbmi.sr && !left_mi->mbmi.skip) ?
idx_to_h(left_mi->mbmi.us_filter_idx) : SR_USFILTER_NUM_D;
return above_sr_ver * 3 + left_sr_hor;*/
}
static INLINE const vp9_prob * vp9_get_sr_usfilter_prob(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
int sr_usfilter_ctx = vp9_get_sr_usfilter_context(xd);
assert(sr_usfilter_ctx >= 0 && sr_usfilter_ctx < SR_USFILTER_CONTEXTS);
return cm->fc.sr_usfilter_probs[sr_usfilter_ctx];
}
#endif // SR_USE_MULTI_F
#endif // CONFIG_SR_MODE
int vp9_get_pred_context_switchable_interp(const MACROBLOCKD *xd);
int vp9_get_intra_inter_context(const MACROBLOCKD *xd);
@ -79,23 +127,75 @@ int vp9_get_pred_context_comp_ref_p(const VP9_COMMON *cm,
static INLINE vp9_prob vp9_get_pred_prob_comp_ref_p(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
const int pred_context = vp9_get_pred_context_comp_ref_p(cm, xd);
return cm->fc.comp_ref_prob[pred_context];
return cm->fc.comp_ref_probs[pred_context][0];
}
#if CONFIG_MULTI_REF
int vp9_get_pred_context_comp_ref_p1(const VP9_COMMON *cm,
const MACROBLOCKD *xd);
static INLINE vp9_prob vp9_get_pred_prob_comp_ref_p1(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
const int pred_context = vp9_get_pred_context_comp_ref_p1(cm, xd);
return cm->fc.comp_ref_probs[pred_context][1];
}
int vp9_get_pred_context_comp_ref_p2(const VP9_COMMON *cm,
const MACROBLOCKD *xd);
static INLINE vp9_prob vp9_get_pred_prob_comp_ref_p2(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
const int pred_context = vp9_get_pred_context_comp_ref_p2(cm, xd);
return cm->fc.comp_ref_probs[pred_context][2];
}
int vp9_get_pred_context_comp_ref_p3(const VP9_COMMON *cm,
const MACROBLOCKD *xd);
static INLINE vp9_prob vp9_get_pred_prob_comp_ref_p3(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
const int pred_context = vp9_get_pred_context_comp_ref_p3(cm, xd);
return cm->fc.comp_ref_probs[pred_context][3];
}
#endif // CONFIG_MULTI_REF
int vp9_get_pred_context_single_ref_p1(const MACROBLOCKD *xd);
static INLINE vp9_prob vp9_get_pred_prob_single_ref_p1(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
return cm->fc.single_ref_prob[vp9_get_pred_context_single_ref_p1(xd)][0];
return cm->fc.single_ref_probs[vp9_get_pred_context_single_ref_p1(xd)][0];
}
int vp9_get_pred_context_single_ref_p2(const MACROBLOCKD *xd);
static INLINE vp9_prob vp9_get_pred_prob_single_ref_p2(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
return cm->fc.single_ref_prob[vp9_get_pred_context_single_ref_p2(xd)][1];
return cm->fc.single_ref_probs[vp9_get_pred_context_single_ref_p2(xd)][1];
}
#if CONFIG_MULTI_REF
int vp9_get_pred_context_single_ref_p3(const MACROBLOCKD *xd);
static INLINE vp9_prob vp9_get_pred_prob_single_ref_p3(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
return cm->fc.single_ref_probs[vp9_get_pred_context_single_ref_p3(xd)][2];
}
int vp9_get_pred_context_single_ref_p4(const MACROBLOCKD *xd);
static INLINE vp9_prob vp9_get_pred_prob_single_ref_p4(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
return cm->fc.single_ref_probs[vp9_get_pred_context_single_ref_p4(xd)][3];
}
int vp9_get_pred_context_single_ref_p5(const MACROBLOCKD *xd);
static INLINE vp9_prob vp9_get_pred_prob_single_ref_p5(const VP9_COMMON *cm,
const MACROBLOCKD *xd) {
return cm->fc.single_ref_probs[vp9_get_pred_context_single_ref_p5(xd)][4];
}
#endif // CONFIG_MULTI_REF
int vp9_get_tx_size_context(const MACROBLOCKD *xd);
static INLINE const vp9_prob *get_tx_probs(TX_SIZE max_tx_size, int ctx,
@ -107,6 +207,10 @@ static INLINE const vp9_prob *get_tx_probs(TX_SIZE max_tx_size, int ctx,
return tx_probs->p16x16[ctx];
case TX_32X32:
return tx_probs->p32x32[ctx];
#if CONFIG_TX64X64
case TX_64X64:
return tx_probs->p64x64[ctx];
#endif
default:
assert(0 && "Invalid max_tx_size.");
return NULL;
@ -128,12 +232,41 @@ static INLINE unsigned int *get_tx_counts(TX_SIZE max_tx_size, int ctx,
return tx_counts->p16x16[ctx];
case TX_32X32:
return tx_counts->p32x32[ctx];
#if CONFIG_TX64X64
case TX_64X64:
return tx_counts->p64x64[ctx];
#endif
default:
assert(0 && "Invalid max_tx_size.");
return NULL;
}
}
#if CONFIG_SR_MODE
static INLINE unsigned int *get_real_tx_counts(TX_SIZE max_tx_size, int ctx,
struct tx_counts *tx_counts) {
switch (max_tx_size) {
case TX_8X8:
return tx_counts->real_p8x8[ctx];
case TX_16X16:
return tx_counts->real_p16x16[ctx];
case TX_32X32:
return tx_counts->real_p32x32[ctx];
#if CONFIG_TX64X64
case TX_64X64:
return tx_counts->real_p64x64[ctx];
#endif // CONFIG_TX64X64
default:
assert(0 && "Invalid max_tx_size.");
return NULL;
}
}
#endif // CONFIG_SR_MODE
#if CONFIG_COPY_MODE
int vp9_get_copy_mode_context(const MACROBLOCKD *xd);
#endif // CONFIG_COPY_MODE
#ifdef __cplusplus
} // extern "C"
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VP9_COMMON_VP9_QCTX_TOKEN_PROBS_H_
#define VP9_COMMON_VP9_QCTX_TOKEN_PROBS_H_
#include "vp9/common/vp9_entropymode.h"
#if CONFIG_QCTX_TPROBS
#define QCTX_BINS_BITS 2
extern const vp9_coeff_probs_model
default_qctx_coef_probs[1 << QCTX_BINS_BITS][TX_SIZES][PLANE_TYPES];
#endif // CONFIG_QCTX_TPROBS
#endif // VP9_COMMON_VP9_QCTX_TOKEN_PROBS_H_

View File

@ -8,10 +8,190 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <math.h>
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_seg_common.h"
#if CONFIG_TX_SKIP
int tx_skip_q_thresh_inter = FOR_SCREEN_CONTENT ? 255 : 64;
int tx_skip_q_thresh_intra = 255;
#endif // CONFIG_TX_SKIP
#if CONFIG_NEW_QUANT
// Bin widths expressed as a fraction over 128 of the quant stepsize,
// for the quantization bins 0-4.
// So a value x indicates the bin is actually factor x/128 of the
// nominal quantization step. For the zero bin, the width is only
// for one side of zero, so the actual width is twice that.
// There are four sets of values for 4 different quantizer ranges.
//
// TODO(debargha): Optimize these tables
static const uint8_t vp9_nuq_knots_lossless[COEF_BANDS][NUQ_KNOTS] = {
{64, 128, 128}, // dc, band 0
{64, 128, 128}, // band 1
{64, 128, 128}, // band 2
{64, 128, 128}, // band 3
{64, 128, 128}, // band 4
{64, 128, 128}, // band 5
#if CONFIG_TX_SKIP
{64, 128, 128}, // band 6
#endif // CONFIG_TX_SKIP
};
static const uint8_t vp9_nuq_knots[QUANT_PROFILES][COEF_BANDS][NUQ_KNOTS] = {
{
{86, 122, 134}, // dc, band 0
{78, 122, 134}, // band 1
{78, 122, 134}, // band 2
{84, 122, 133}, // band 3
{88, 122, 134}, // band 4
{88, 122, 134}, // band 5
#if CONFIG_TX_SKIP
{86, 122, 128}, // band 6
#endif // CONFIG_TX_SKIP
},
#if QUANT_PROFILES > 1
{
{86, 122, 134}, // dc, band 0
{78, 122, 134}, // band 1
{78, 122, 134}, // band 2
{84, 122, 134}, // band 3
{88, 122, 134}, // band 4
{88, 122, 134}, // band 5
#if CONFIG_TX_SKIP
{86, 122, 128}, // band 6
#endif // CONFIG_TX_SKIP
},
#if QUANT_PROFILES > 2
{
{86, 122, 134}, // dc, band 0
{78, 122, 135}, // band 1
{78, 122, 134}, // band 2
{84, 122, 133}, // band 3
{88, 122, 134}, // band 4
{88, 122, 134}, // band 5
#if CONFIG_TX_SKIP
{86, 122, 128}, // band 6
#endif // CONFIG_TX_SKIP
}
#endif // QUANT_PROFILES > 2
#endif // QUANT_PROFILES > 1
};
static const uint8_t vp9_nuq_doff_lossless[COEF_BANDS] = { 0, 0, 0, 0, 0, 0,
#if CONFIG_TX_SKIP
0
#endif // CONFIG_TX_SKIP
};
#if QUANT_PROFILES == 1
static const uint8_t vp9_nuq_doff[QUANT_PROFILES][COEF_BANDS] = {
{ 8, 15, 16, 22, 23, 24, // dq_off_index = 0
#if CONFIG_TX_SKIP
8
#endif // CONFIG_TX_SKIP
}
};
#elif QUANT_PROFILES == 2
static const uint8_t vp9_nuq_doff[QUANT_PROFILES][COEF_BANDS] = {
{ 8, 15, 16, 22, 23, 24, // dq_off_index = 0
#if CONFIG_TX_SKIP
8
#endif // CONFIG_TX_SKIP
},
{ 13, 20, 21, 27, 28, 29, // dq_off_index = 1
#if CONFIG_TX_SKIP
8
#endif // CONFIG_TX_SKIP
},
};
#else // QUANT_PROFILES == 3
static const uint8_t vp9_nuq_doff[QUANT_PROFILES][COEF_BANDS] = {
{ 6, 14, 15, 22, 23, 27, // dq_off_index = 0
#if CONFIG_TX_SKIP
8
#endif // CONFIG_TX_SKIP
},
{ 6, 15, 17, 22, 23, 23, // dq_off_index = 1
#if CONFIG_TX_SKIP
8
#endif // CONFIG_TX_SKIP
},
{ 6, 14, 16, 22, 23, 27, // dq_off_index = 2
#if CONFIG_TX_SKIP
8
#endif // CONFIG_TX_SKIP
}
};
#endif
// Allow different quantization profiles in different q ranges,
// to enable entropy-constraints in scalar quantization.
static const uint8_t *get_nuq_knots(int lossless, int band, int dq_off_index) {
if (lossless)
return vp9_nuq_knots_lossless[band];
else
return vp9_nuq_knots[dq_off_index][band];
}
static INLINE int16_t quant_to_doff_fixed(int lossless, int band,
int dq_off_index) {
if (lossless)
return vp9_nuq_doff_lossless[band];
else
return vp9_nuq_doff[dq_off_index][band];
}
static INLINE void get_cumbins_nuq(int q, int lossless, int band,
tran_low_t *cumbins, int dq_off_index) {
const uint8_t *knots = get_nuq_knots(lossless, band, dq_off_index);
int16_t cumknots[NUQ_KNOTS];
int i;
cumknots[0] = knots[0];
for (i = 1; i < NUQ_KNOTS; ++i)
cumknots[i] = cumknots[i - 1] + knots[i];
for (i = 0; i < NUQ_KNOTS; ++i)
cumbins[i] = (cumknots[i] * q + 64) >> 7;
}
void vp9_get_dequant_val_nuq(int q, int lossless, int band,
tran_low_t *dq, tran_low_t *cumbins,
int dq_off_index) {
const uint8_t *knots = get_nuq_knots(lossless, band, dq_off_index);
tran_low_t cumbins_[NUQ_KNOTS], *cumbins_ptr;
tran_low_t doff;
int i;
cumbins_ptr = (cumbins ? cumbins : cumbins_);
get_cumbins_nuq(q, lossless, band, cumbins_ptr, dq_off_index);
dq[0] = 0;
for (i = 1; i < NUQ_KNOTS; ++i) {
const int16_t qstep = (knots[i] * q + 64) >> 7;
doff = quant_to_doff_fixed(lossless, band, dq_off_index);
doff = (2 * doff * qstep + q) / (2 * q);
dq[i] = cumbins_ptr[i - 1] + (((knots[i] - doff * 2) * q + 128) >> 8);
}
doff = quant_to_doff_fixed(lossless, band, dq_off_index);
dq[NUQ_KNOTS] =
cumbins_ptr[NUQ_KNOTS - 1] + (((64 - doff) * q + 64) >> 7);
}
tran_low_t vp9_dequant_abscoeff_nuq(int v, int q, const tran_low_t *dq) {
if (v <= NUQ_KNOTS)
return dq[v];
else
return dq[NUQ_KNOTS] + (v - NUQ_KNOTS) * q;
}
tran_low_t vp9_dequant_coeff_nuq(int v, int q, const tran_low_t *dq) {
tran_low_t dqmag = vp9_dequant_abscoeff_nuq(abs(v), q, dq);
return (v < 0 ? -dqmag : dqmag);
}
#endif // CONFIG_NEW_QUANT
static const int16_t dc_qlookup[QINDEX_RANGE] = {
4, 8, 8, 9, 10, 11, 12, 12,
13, 14, 15, 16, 17, 18, 19, 19,
@ -275,4 +455,3 @@ int vp9_get_qindex(const struct segmentation *seg, int segment_id,
return base_qindex;
}
}

View File

@ -11,7 +11,10 @@
#ifndef VP9_COMMON_VP9_QUANT_COMMON_H_
#define VP9_COMMON_VP9_QUANT_COMMON_H_
#include <stdio.h>
#include "vpx/vpx_codec.h"
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_seg_common.h"
#ifdef __cplusplus
@ -22,6 +25,12 @@ extern "C" {
#define MAXQ 255
#define QINDEX_RANGE (MAXQ - MINQ + 1)
#define QINDEX_BITS 8
#if CONFIG_TX_SKIP
#define TX_SKIP_SHIFT_THRESH 0
#define PXD_QUANT_INDEX 0
extern int tx_skip_q_thresh_inter;
extern int tx_skip_q_thresh_intra;
#endif // CONFIG_TX_SKIP
int16_t vp9_dc_quant(int qindex, int delta, vpx_bit_depth_t bit_depth);
int16_t vp9_ac_quant(int qindex, int delta, vpx_bit_depth_t bit_depth);
@ -29,6 +38,22 @@ int16_t vp9_ac_quant(int qindex, int delta, vpx_bit_depth_t bit_depth);
int vp9_get_qindex(const struct segmentation *seg, int segment_id,
int base_qindex);
static INLINE int16_t vp9_round_factor_to_round(int16_t quant,
int16_t round_factor) {
return (round_factor * quant) >> 7;
}
#if CONFIG_NEW_QUANT
#define NUQ_KNOTS 3
typedef tran_low_t dequant_val_type_nuq[NUQ_KNOTS + 1];
typedef tran_low_t cumbins_type_nuq[NUQ_KNOTS];
void vp9_get_dequant_val_nuq(int q, int lossless, int band,
tran_low_t *dq, tran_low_t *cumbins,
int dq_off_index);
tran_low_t vp9_dequant_abscoeff_nuq(int v, int q, const tran_low_t *dq);
tran_low_t vp9_dequant_coeff_nuq(int v, int q, const tran_low_t *dq);
#endif // CONFIG_NEW_QUANT
#ifdef __cplusplus
} // extern "C"
#endif

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,15 @@ void vp9_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
void vp9_dec_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
BLOCK_SIZE bsize);
#if CONFIG_SUPERTX
void vp9_build_inter_predictors_sb_sub8x8(MACROBLOCKD *xd,
int mi_row, int mi_col,
BLOCK_SIZE bsize, int block);
void vp9_dec_build_inter_predictors_sb_sub8x8(MACROBLOCKD *xd,
int mi_row, int mi_col,
BLOCK_SIZE bsize, int block);
#endif
void vp9_build_inter_predictor(const uint8_t *src, int src_stride,
uint8_t *dst, int dst_stride,
const MV *mv_q3,
@ -58,14 +67,18 @@ static INLINE int scaled_buffer_offset(int x_offset, int y_offset, int stride,
}
static INLINE void setup_pred_plane(struct buf_2d *dst,
int width, int height,
uint8_t *src, int stride,
int mi_row, int mi_col,
const struct scale_factors *scale,
int subsampling_x, int subsampling_y) {
const int x = (MI_SIZE * mi_col) >> subsampling_x;
const int y = (MI_SIZE * mi_row) >> subsampling_y;
dst->buf0 = src;
dst->buf = src + scaled_buffer_offset(x, y, stride, scale);
dst->stride = stride;
dst->width = width;
dst->height = height;
}
void vp9_setup_dst_planes(struct macroblockd_plane planes[MAX_MB_PLANE],
@ -76,6 +89,66 @@ void vp9_setup_pre_planes(MACROBLOCKD *xd, int idx,
const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col,
const struct scale_factors *sf);
#if CONFIG_WEDGE_PARTITION
#define MASK_MASTER_SIZE (2 * CODING_UNIT_SIZE)
#define MASK_MASTER_STRIDE (2 * CODING_UNIT_SIZE)
void vp9_init_wedge_masks();
const uint8_t *vp9_get_soft_mask(int wedge_index,
BLOCK_SIZE sb_type,
int h, int w);
void vp9_generate_soft_mask(int wedge_index, BLOCK_SIZE sb_type,
int h, int w, uint8_t *mask, int stride);
void vp9_generate_hard_mask(int wedge_index, BLOCK_SIZE sb_type,
int h, int w, uint8_t *mask, int stride);
void vp9_build_inter_predictors_for_planes_single_buf(
MACROBLOCKD *xd, BLOCK_SIZE bsize,
int mi_row, int mi_col, int ref,
uint8_t *ext_dst[3], int ext_dst_stride[3]);
void vp9_build_wedge_inter_predictor_from_buf(
MACROBLOCKD *xd, BLOCK_SIZE bsize,
int mi_row, int mi_col,
uint8_t *ext_dst0[3], int ext_dst_stride0[3],
uint8_t *ext_dst1[3], int ext_dst_stride1[3]);
#endif // CONFIG_WEDGE_PARTITION
#if CONFIG_SUPERTX
struct macroblockd_plane;
void vp9_build_masked_inter_predictor_complex(
MACROBLOCKD *xd,
uint8_t *dst, int dst_stride, uint8_t *dst2, int dst2_stride,
const struct macroblockd_plane *pd, int mi_row, int mi_col,
int mi_row_ori, int mi_col_ori, BLOCK_SIZE bsize, BLOCK_SIZE top_bsize,
PARTITION_TYPE partition, int plane);
#if CONFIG_WEDGE_PARTITION
void vp9_build_inter_predictors_sb_extend(MACROBLOCKD *xd,
int mi_row, int mi_col,
int mi_row_ori, int mi_col_ori,
BLOCK_SIZE bsize);
void vp9_dec_build_inter_predictors_sb_extend(MACROBLOCKD *xd,
int mi_row, int mi_col,
int mi_row_ori, int mi_col_ori,
BLOCK_SIZE bsize);
void vp9_build_inter_predictors_sb_sub8x8_extend(
MACROBLOCKD *xd,
int mi_row, int mi_col,
int mi_row_ori, int mi_col_ori,
BLOCK_SIZE bsize, int block);
void vp9_dec_build_inter_predictors_sb_sub8x8_extend(
MACROBLOCKD *xd,
int mi_row, int mi_col,
int mi_row_ori, int mi_col_ori,
BLOCK_SIZE bsize, int block);
#endif // CONFIG_WEDGE_PARTITION
#endif // CONFIG_SUPERTX
#ifdef __cplusplus
} // extern "C"
#endif

File diff suppressed because it is too large Load Diff

View File

@ -22,9 +22,32 @@ void vp9_init_intra_predictors();
void vp9_predict_intra_block(const MACROBLOCKD *xd, int block_idx, int bwl_in,
TX_SIZE tx_size, PREDICTION_MODE mode,
#if CONFIG_FILTERINTRA
int filterbit,
#endif
const uint8_t *ref, int ref_stride,
uint8_t *dst, int dst_stride,
int aoff, int loff, int plane);
#if CONFIG_INTERINTRA
void vp9_build_interintra_predictors(MACROBLOCKD *xd,
uint8_t *ypred,
uint8_t *upred,
uint8_t *vpred,
int ystride,
int ustride,
int vstride,
BLOCK_SIZE bsize);
void vp9_build_interintra_predictors_sby(MACROBLOCKD *xd,
uint8_t *ypred,
int ystride,
BLOCK_SIZE bsize);
void vp9_build_interintra_predictors_sbuv(MACROBLOCKD *xd,
uint8_t *upred,
uint8_t *vpred,
int ustride, int vstride,
BLOCK_SIZE bsize);
#endif // CONFIG_INTERINTRA
#ifdef __cplusplus
} // extern "C"
#endif

File diff suppressed because it is too large Load Diff

View File

@ -56,7 +56,7 @@ static INLINE int vp9_is_valid_scale(const struct scale_factors *sf) {
}
static INLINE int vp9_is_scaled(const struct scale_factors *sf) {
return vp9_is_valid_scale(sf) &&
return sf && vp9_is_valid_scale(sf) &&
(sf->x_scale_fp != REF_NO_SCALE || sf->y_scale_fp != REF_NO_SCALE);
}

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,36 @@ typedef struct {
} scan_order;
extern const scan_order vp9_default_scan_orders[TX_SIZES];
extern const scan_order vp9_scan_orders[TX_SIZES][TX_TYPES];
extern const scan_order vp9_intra_scan_orders[TX_SIZES][TX_TYPES];
#if CONFIG_EXT_TX
extern const scan_order vp9_inter_scan_orders[TX_SIZES][TOTAL_TX_TYPES];
#endif // CONFIG_EXT_TX
#if CONFIG_TX_SKIP
// pixel domain default scan orders
extern const scan_order vp9_default_scan_orders_pxd[TX_SIZES];
extern int16_t vp9_default_scan_pxd_4x4[16];
extern int16_t vp9_default_scan_pxd_8x8[64];
extern int16_t vp9_default_scan_pxd_16x16[256];
extern int16_t vp9_default_scan_pxd_32x32[1024];
extern int16_t vp9_default_iscan_pxd_4x4[16];
extern int16_t vp9_default_iscan_pxd_8x8[64];
extern int16_t vp9_default_iscan_pxd_16x16[256];
extern int16_t vp9_default_iscan_pxd_32x32[1024];
extern int16_t vp9_default_scan_pxd_4x4_neighbors[17 * MAX_NEIGHBORS];
extern int16_t vp9_default_scan_pxd_8x8_neighbors[65 * MAX_NEIGHBORS];
extern int16_t vp9_default_scan_pxd_16x16_neighbors[257 * MAX_NEIGHBORS];
extern int16_t vp9_default_scan_pxd_32x32_neighbors[1025 * MAX_NEIGHBORS];
#if CONFIG_TX64X64
extern int16_t vp9_default_scan_pxd_64x64[4096];
extern int16_t vp9_default_iscan_pxd_64x64[4096];
extern int16_t vp9_default_scan_pxd_64x64_neighbors[4097 * MAX_NEIGHBORS];
#endif // CONFIG_TX64X64
#endif // CONFIG_TX_SKIP
static INLINE int get_coef_context(const int16_t *neighbors,
const uint8_t *token_cache, int c) {

298
vp9/common/vp9_sr_txfm.c Normal file
View File

@ -0,0 +1,298 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "vp9/common/vp9_sr_txfm.h"
#include "vp9/common/vp9_idct.h"
#include "vp9/common/vp9_idwt.h"
#if CONFIG_SR_MODE
int is_enable_srmode(BLOCK_SIZE bsize) {
TX_SIZE max_tx_size = max_txsize_lookup[bsize];
return (max_tx_size >= MIN_SR_TX_SIZE &&
max_tx_size <= MAX_SR_TX_SIZE);
}
// Extending blocks border by copying the boundary pixels
// For convolution use
static void sr_extend(int16_t *src, int src_stride, int w, int h,
int16_t *src_ext, int src_ext_stride, int border) {
int16_t *src_ext_ori = src_ext;
int i, j;
src_ext = src_ext_ori - border;
for (i = 0; i < h; i ++) {
for (j = 0; j < border; j ++)
src_ext[j] = src[0];
vpx_memcpy(src_ext + border, src, sizeof(int16_t) * w);
for (j = 0; j < border; j ++)
src_ext[border + w + j] = src[w - 1];
src_ext += src_ext_stride;
src += src_stride;
}
src_ext = src_ext_ori - border * src_ext_stride - border;
for (i = 0; i < border; i ++)
vpx_memcpy(src_ext + i * src_ext_stride, src_ext_ori - border,
sizeof(int16_t) * (w + 2 * border));
src_ext = src_ext_ori + h * src_ext_stride - border;
for (i = 0; i < border; i ++)
vpx_memcpy(src_ext + i * src_ext_stride,
src_ext_ori + (h - 1) * src_ext_stride - border,
sizeof(int16_t) * (w + 2 * border));
}
static void convolve_horiz(int16_t *src, int src_stride, int src_offset,
int16_t *dst, int dst_stride, int dst_offset,
int *x_filter, int filter_taps, int fil_offset,
int w, int h) {
// src_offset, dst_offset: offsets to move to the next value (usually 1)
// fil_offset: offsets from filter center to the first pixel of filter
// (e.g: 3-tap filter (1, 2, 1), fil_offset=1;
// 4-tap filter (1, 2, 2, 1), fil_offset=1)
int x, y;
int round_offset = 1 << (UPSCALE_FILTER_SHIFT - 1);
// Shift the buffer to the first pixel of filter
src -= (fil_offset * src_offset);
for (y = 0; y < h; ++y) {
int16_t *src_x = src;
for (x = 0; x < w; ++x) {
int k, sum = 0;
// If the filter is symmetric, can fold it first, then multiply
for (k = 0; k < filter_taps; ++k)
sum += src_x[k * src_offset] * x_filter[k];
src_x += src_offset;
dst[x * dst_offset] = (sum + round_offset) >> UPSCALE_FILTER_SHIFT;
}
src += src_stride;
dst += dst_stride;
}
}
static void convolve_vert(int16_t *src, int src_stride, int src_offset,
int16_t *dst, int dst_stride, int dst_offset,
int *y_filter, int filter_taps, int fil_offset,
int w, int h) {
int x, y;
int round_offset = 1 << (UPSCALE_FILTER_SHIFT - 1);
// Shift the buffer to the first pixel of filter
src -= src_stride * fil_offset;
for (x = 0; x < w; ++x) {
int16_t *src_y = src;
for (y = 0; y < h; ++y) {
int k, sum = 0;
for (k = 0; k < filter_taps; ++k)
sum += src_y[k * src_stride] * y_filter[k];
src_y += src_stride;
dst[y * dst_stride] = (sum + round_offset) >> UPSCALE_FILTER_SHIFT;
}
src += src_offset;
dst += dst_offset;
}
}
/* If changing filter taps, need to change some parameters below too */
int lp_filter[UPSCALE_FILTER_TAPS - 1] = {2, -14, -2, 43, 70, 43, -2, -14, 2};
int interpl_filter[UPSCALE_FILTER_TAPS] =
// {1, -4, 10, -23, 80, 80, -23, 10, -4, 1}; // lanczos
// {0, -1, 6, -19, 78, 78, -19, 6, -1, 0}; // laplacian
{0, -4, 11, -23, 80, 80, -23, 11, -4, 0}; // DCT
// {0, -1, -4, 14, 55, 55, 14, -4, -1, 0}; // freqmultiplier = 0.5
#if SR_USE_MULTI_F
// For multiple interplation filter options
int post_filter[SR_USFILTER_NUM_D][UPSCALE_FILTER_TAPS - 1] = {
{2, 0, -7, 0, 137, 0, -7, 0, 2},
{1, 0, -7, 0, 139, 0, -7, 0, 1},
{4, 0, -5, 0, 134, 0, -5, 0, 4},
{-2, 0, -8, 0, 149, 0, -8, 0, -2}
};
#else
int post_filter[UPSCALE_FILTER_TAPS - 1] =
{2, 0, -7, 0, 137, 0, -7, 0, 2};
#endif
#define buf_size (64 + UPSCALE_FILTER_TAPS*2)
static void sr_convolution(int16_t *src, int src_stride, int src_offset,
int16_t *dst, int dst_stride, int dst_offset,
int * fil_hor, int * fil_ver,
int fil_offset_h, int fil_offset_v,
int filter_taps,
int w, int h) {
DECLARE_ALIGNED_ARRAY(16, int16_t, tmp_buf, buf_size * buf_size);
int tmp_buf_stride = buf_size;
int16_t *tmp_buf_ori = tmp_buf + fil_offset_v * tmp_buf_stride + fil_offset_h;
convolve_horiz(
src - fil_offset_v * src_stride, src_stride, src_offset,
tmp_buf_ori - fil_offset_v * tmp_buf_stride, tmp_buf_stride, 1,
fil_hor, filter_taps, fil_offset_h, w, h + filter_taps);
convolve_vert(
tmp_buf_ori, tmp_buf_stride, 1,
dst, dst_stride, dst_offset,
fil_ver, filter_taps, fil_offset_v, w, h);
}
void sr_lowpass(int16_t *src, int src_stride, int16_t *dst, int dst_stride,
int w, int h) {
int filter_taps = UPSCALE_FILTER_TAPS - 1; // odd number of taps
int border = (filter_taps - 1) >> 1;
int fil_offset = border; // see "fil_offset" in "convolve_horiz"
DECLARE_ALIGNED_ARRAY(16, int16_t, src_ext, buf_size * buf_size);
int src_ext_stride = buf_size;
int16_t *src_ext_ori = src_ext + border * src_ext_stride + border;
// extension
sr_extend(src, src_stride, w, h, src_ext_ori, src_ext_stride, border);
sr_convolution(src_ext_ori, src_ext_stride, 1, dst, dst_stride, 1,
lp_filter, lp_filter, fil_offset, fil_offset,
filter_taps, w, h);
}
static void sr_upsample(int16_t *src, int src_stride,
int16_t *dst, int dst_stride, int w, int h) {
// Apply interpolation filter
int filter_taps = UPSCALE_FILTER_TAPS; // even number of taps
int border = (filter_taps >> 1); // maximum pixels needs to extended
int fil_offset = border - 1; // see "fil_offset" in "convolve_horiz"
int i, j;
DECLARE_ALIGNED_ARRAY(16, int16_t, src_ext, buf_size * buf_size);
DECLARE_ALIGNED_ARRAY(16, int16_t, tmp_buf, buf_size * buf_size);
int src_ext_stride = buf_size, tmp_buf_stride = buf_size;
int16_t *src_ext_ori = src_ext + border * src_ext_stride + border;
int16_t *tmp_buf_ori = tmp_buf + border * tmp_buf_stride + border;
int16_t *dst_ori = dst;
// Extend the buffer
sr_extend(src, src_stride, w, h, src_ext_ori, src_ext_stride, border);
// Keep the original pixels the same
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
dst[j << 1] = src[j];
}
dst += (dst_stride << 1);
src += src_stride;
}
convolve_horiz(src_ext_ori - border * src_ext_stride, src_ext_stride, 1,
tmp_buf_ori - border * tmp_buf_stride, tmp_buf_stride, 1,
interpl_filter, filter_taps, fil_offset, w, h + (2 * border));
// Set the horizontally interpolated pixels
dst = dst_ori;
tmp_buf = tmp_buf_ori;
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
dst[(j << 1) + 1] = tmp_buf[j];
}
dst += (dst_stride << 1);
tmp_buf += tmp_buf_stride;
}
// Set the vertically interpolated pixels
convolve_vert(src_ext_ori, src_ext_stride, 1,
dst_ori + dst_stride, 2 * dst_stride, 2,
interpl_filter, filter_taps, fil_offset, w, h);
// Set the horizontally and vertically interpolated pixels
convolve_vert(tmp_buf_ori, tmp_buf_stride, 1,
dst_ori + dst_stride + 1, 2 * dst_stride, 2,
interpl_filter, filter_taps, fil_offset, w, h);
}
#if SR_USE_MULTI_F
static void sr_post_filter(int16_t *src, int src_stride,
int16_t *dst, int dst_stride,
int w, int h, int f_hor, int f_ver) {
#else
static void sr_post_filter(int16_t *src, int src_stride,
int16_t *dst, int dst_stride, int w, int h) {
#endif
int filter_taps = UPSCALE_FILTER_TAPS - 1; // odd number of taps
int border = (filter_taps - 1) >> 1;
int fil_offset = border;
DECLARE_ALIGNED_ARRAY(16, int16_t, src_ext, buf_size * buf_size);
int src_ext_stride = buf_size;
int16_t *src_ext_ori = src_ext + border * src_ext_stride + border;
// extension
sr_extend(src, src_stride, w, h, src_ext_ori, src_ext_stride, border);
sr_convolution(src_ext_ori, src_ext_stride, 1, dst, dst_stride, 1,
#if SR_USE_MULTI_F
post_filter[f_hor], post_filter[f_ver],
fil_offset, fil_offset,
#else
post_filter, post_filter, fil_offset, fil_offset,
#endif
filter_taps, w, h);
}
#if SR_USE_MULTI_F
void sr_recon(int16_t *src, int src_stride, uint8_t *dst, int dst_stride,
int w, int h, int f_hor, int f_ver) {
#else
void sr_recon(int16_t *src, int src_stride, uint8_t *dst, int dst_stride,
int w, int h) {
#endif
DECLARE_ALIGNED_ARRAY(16, int16_t, recon, 64 * 64);
DECLARE_ALIGNED_ARRAY(16, int16_t, us_resi, 64 * 64);
int i, j, us_resi_stride = 64;
int recon_stride = 64;
#if USE_POST_F
DECLARE_ALIGNED_ARRAY(16, int16_t, enh_recon, 64 * 64);
int enh_recon_stride = 64;
#endif
// Upsample residual
sr_upsample(src, src_stride, us_resi, us_resi_stride, w/2, h/2);
// Add upsampled residual to prediction
for (i = 0; i < h; i++) {
for (j = 0; j < w; j++) {
recon[i * recon_stride + j] = dst[i * dst_stride + j] +
us_resi[i * us_resi_stride + j];
}
}
#if USE_POST_F
// Do super-resolution post processing to the reconstruction
#if SR_USE_MULTI_F
sr_post_filter(recon, recon_stride, enh_recon, enh_recon_stride, w, h,
f_hor, f_ver);
#else // SR_USE_MULTI_F
sr_post_filter(recon, recon_stride, enh_recon, enh_recon_stride, w, h);
#endif // SR_USE_MULTI_F
for (i = 0; i < h; i++)
for (j = 0; j < w; j++)
dst[i * dst_stride + j] = clip_pixel(enh_recon[i * enh_recon_stride + j]);
#else // USE_POST_F
for (i = 0; i < h; i++)
for (j = 0; j < w; j++)
dst[i * dst_stride + j] = clip_pixel(recon[i * recon_stride + j]);
#endif // USE_POST_F
}
#endif // CONFIG_SR_MODE

49
vp9/common/vp9_sr_txfm.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2015 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VP9_COMMON_VP9_PALETTE_H_
#define VP9_COMMON_VP9_PALETTE_H_
#include "vp9/common/vp9_blockd.h"
#include "vp9/common/vp9_entropymode.h"
#if CONFIG_SR_MODE
#define MIN_SR_TX_SIZE 2
#if CONFIG_TX_64X64
#define MAX_SR_TX_SIZE 4
#else
#define MAX_SR_TX_SIZE 3
#endif
#define UPSCALE_FILTER_TAPS 10
#define UPSCALE_FILTER_SHIFT 7
void sr_lowpass(int16_t *src, int src_stride, int16_t *dst, int dst_stride,
int w, int h);
#if SR_USE_MULTI_F
void sr_recon(int16_t *src, int src_stride, uint8_t *dst, int dst_stride,
int w, int h, int f_hor, int f_ver);
static INLINE int idx_to_h(int idx) {
return (idx % SR_USFILTER_NUM_D);
}
static INLINE int idx_to_v(int idx) {
return (idx / SR_USFILTER_NUM_D);
}
static INLINE int hv_to_idx(int hor, int ver) {
return hor + ver * SR_USFILTER_NUM_D;
}
#else
void sr_recon(int16_t *src, int src_stride, uint8_t *dst, int dst_stride,
int w, int h);
#endif
int is_enable_srmode(BLOCK_SIZE bsize);
#endif // CONFIG_SR_MODE
#endif // VP9_COMMON_VP9_PALETTE_H_

View File

@ -31,10 +31,19 @@ void vp9_tile_set_col(TileInfo *tile, const VP9_COMMON *cm, int col) {
tile->mi_col_end = get_tile_offset(col + 1, cm->mi_cols, cm->log2_tile_cols);
}
#if CONFIG_ROW_TILE
void vp9_tile_init(TileInfo *tile, const VP9_COMMON *cm, int row, int col) {
tile->mi_row_start = row * cm->tile_height;
tile->mi_row_end = MIN(tile->mi_row_start + cm->tile_height, cm->mi_rows);
tile->mi_col_start = col * cm->tile_width;
tile->mi_col_end = MIN(tile->mi_col_start + cm->tile_width, cm->mi_cols);
}
#else
void vp9_tile_init(TileInfo *tile, const VP9_COMMON *cm, int row, int col) {
vp9_tile_set_row(tile, cm, row);
vp9_tile_set_col(tile, cm, col);
}
#endif
void vp9_get_tile_n_bits(int mi_cols,
int *min_log2_tile_cols, int *max_log2_tile_cols) {

View File

@ -345,7 +345,7 @@ cglobal highbd_tm_predictor_8x8, 5, 6, 5, dst, stride, above, left, bps, one
%if ARCH_X86_64
INIT_XMM sse2
cglobal highbd_tm_predictor_16x16, 5, 6, 8, dst, stride, above, left, bps, one
cglobal highbd_tm_predictor_16x16, 5, 6, 9, dst, stride, above, left, bps, one
movd m2, [aboveq-2]
mova m0, [aboveq]
mova m1, [aboveq+16]

View File

@ -9,6 +9,56 @@
*/
#include "vp9/common/x86/vp9_idct_intrin_sse2.h"
#include "vp9/common/vp9_idct.h"
#include "vp9/common/vp9_enums.h"
#if CONFIG_EXT_TX
// Reverse the 8 16 bit words in __m128i
static INLINE __m128i mm_reverse_epi16(const __m128i x) {
const __m128i a = _mm_shufflelo_epi16(x, 0x1b);
const __m128i b = _mm_shufflehi_epi16(a, 0x1b);
return _mm_shuffle_epi32(b, 0x4e);
}
static INLINE void fliplr_4x4(__m128i in[2]) {
in[0] = _mm_shufflelo_epi16(in[0], 0x1b);
in[0] = _mm_shufflehi_epi16(in[0], 0x1b);
in[1] = _mm_shufflelo_epi16(in[1], 0x1b);
in[1] = _mm_shufflehi_epi16(in[1], 0x1b);
}
static INLINE void fliplr_8x8(__m128i in[8]) {
in[0] = mm_reverse_epi16(in[0]);
in[1] = mm_reverse_epi16(in[1]);
in[2] = mm_reverse_epi16(in[2]);
in[3] = mm_reverse_epi16(in[3]);
in[4] = mm_reverse_epi16(in[4]);
in[5] = mm_reverse_epi16(in[5]);
in[6] = mm_reverse_epi16(in[6]);
in[7] = mm_reverse_epi16(in[7]);
}
static INLINE void fliplr_16x8(__m128i in[16]) {
fliplr_8x8(&in[0]);
fliplr_8x8(&in[8]);
}
#define FLIPLR_16x16(in0, in1) do { \
__m128i *tmp; \
fliplr_16x8(in0); \
fliplr_16x8(in1); \
tmp = (in0); \
(in0) = (in1); \
(in1) = tmp; \
} while (0)
#define FLIPUD_PTR(dest, stride, size) do { \
(dest) = (dest) + ((size) - 1) * (stride); \
(stride) = - (stride); \
} while (0)
#endif
#define RECON_AND_STORE4X4(dest, in_x) \
{ \
@ -125,12 +175,12 @@ void vp9_idct4x4_16_add_sse2(const int16_t *input, uint8_t *dest, int stride) {
// Reconstruction and Store
{
__m128i d0 = _mm_cvtsi32_si128(*(const int *)(dest));
__m128i d0 = _mm_cvtsi32_si128(*(const int *)(dest + stride * 0));
__m128i d1 = _mm_cvtsi32_si128(*(const int *)(dest + stride * 1));
__m128i d2 = _mm_cvtsi32_si128(*(const int *)(dest + stride * 2));
d0 = _mm_unpacklo_epi32(d0,
_mm_cvtsi32_si128(*(const int *) (dest + stride)));
d2 = _mm_unpacklo_epi32(_mm_cvtsi32_si128(
*(const int *) (dest + stride * 3)), d2);
__m128i d3 = _mm_cvtsi32_si128(*(const int *)(dest + stride * 3));
d0 = _mm_unpacklo_epi32(d0, d1);
d2 = _mm_unpacklo_epi32(d3, d2);
d0 = _mm_unpacklo_epi8(d0, zero);
d2 = _mm_unpacklo_epi8(d2, zero);
d0 = _mm_add_epi16(d0, input2);
@ -270,22 +320,50 @@ void vp9_iht4x4_16_add_sse2(const int16_t *input, uint8_t *dest, int stride,
in[1]= _mm_loadu_si128((const __m128i *)(input + 8));
switch (tx_type) {
case 0: // DCT_DCT
case DCT_DCT:
idct4_sse2(in);
idct4_sse2(in);
break;
case 1: // ADST_DCT
case ADST_DCT:
idct4_sse2(in);
iadst4_sse2(in);
break;
case 2: // DCT_ADST
case DCT_ADST:
iadst4_sse2(in);
idct4_sse2(in);
break;
case 3: // ADST_ADST
case ADST_ADST:
iadst4_sse2(in);
iadst4_sse2(in);
break;
#if CONFIG_EXT_TX
case FLIPADST_DCT:
idct4_sse2(in);
iadst4_sse2(in);
FLIPUD_PTR(dest, stride, 4);
break;
case DCT_FLIPADST:
iadst4_sse2(in);
idct4_sse2(in);
fliplr_4x4(in);
break;
case FLIPADST_FLIPADST:
iadst4_sse2(in);
iadst4_sse2(in);
FLIPUD_PTR(dest, stride, 4);
fliplr_4x4(in);
break;
case ADST_FLIPADST:
iadst4_sse2(in);
iadst4_sse2(in);
fliplr_4x4(in);
break;
case FLIPADST_ADST:
iadst4_sse2(in);
iadst4_sse2(in);
FLIPUD_PTR(dest, stride, 4);
break;
#endif // CONFIG_EXT_TX
default:
assert(0);
break;
@ -874,22 +952,50 @@ void vp9_iht8x8_64_add_sse2(const int16_t *input, uint8_t *dest, int stride,
in[7] = _mm_load_si128((const __m128i *)(input + 8 * 7));
switch (tx_type) {
case 0: // DCT_DCT
case DCT_DCT:
idct8_sse2(in);
idct8_sse2(in);
break;
case 1: // ADST_DCT
case ADST_DCT:
idct8_sse2(in);
iadst8_sse2(in);
break;
case 2: // DCT_ADST
case DCT_ADST:
iadst8_sse2(in);
idct8_sse2(in);
break;
case 3: // ADST_ADST
case ADST_ADST:
iadst8_sse2(in);
iadst8_sse2(in);
break;
#if CONFIG_EXT_TX
case FLIPADST_DCT:
idct8_sse2(in);
iadst8_sse2(in);
FLIPUD_PTR(dest, stride, 8);
break;
case DCT_FLIPADST:
iadst8_sse2(in);
idct8_sse2(in);
fliplr_8x8(in);
break;
case FLIPADST_FLIPADST:
iadst8_sse2(in);
iadst8_sse2(in);
FLIPUD_PTR(dest, stride, 8);
fliplr_8x8(in);
break;
case ADST_FLIPADST:
iadst8_sse2(in);
iadst8_sse2(in);
fliplr_8x8(in);
break;
case FLIPADST_ADST:
iadst8_sse2(in);
iadst8_sse2(in);
FLIPUD_PTR(dest, stride, 8);
break;
#endif // CONFIG_EXT_TX
default:
assert(0);
break;
@ -2330,29 +2436,59 @@ static void iadst16_sse2(__m128i *in0, __m128i *in1) {
void vp9_iht16x16_256_add_sse2(const int16_t *input, uint8_t *dest, int stride,
int tx_type) {
__m128i in0[16], in1[16];
__m128i in[32];
__m128i *in0 = &in[0];
__m128i *in1 = &in[16];
load_buffer_8x16(input, in0);
input += 8;
load_buffer_8x16(input, in1);
switch (tx_type) {
case 0: // DCT_DCT
case DCT_DCT:
idct16_sse2(in0, in1);
idct16_sse2(in0, in1);
break;
case 1: // ADST_DCT
case ADST_DCT:
idct16_sse2(in0, in1);
iadst16_sse2(in0, in1);
break;
case 2: // DCT_ADST
case DCT_ADST:
iadst16_sse2(in0, in1);
idct16_sse2(in0, in1);
break;
case 3: // ADST_ADST
case ADST_ADST:
iadst16_sse2(in0, in1);
iadst16_sse2(in0, in1);
break;
#if CONFIG_EXT_TX
case FLIPADST_DCT:
idct16_sse2(in0, in1);
iadst16_sse2(in0, in1);
FLIPUD_PTR(dest, stride, 16);
break;
case DCT_FLIPADST:
iadst16_sse2(in0, in1);
idct16_sse2(in0, in1);
FLIPLR_16x16(in0, in1);
break;
case FLIPADST_FLIPADST:
iadst16_sse2(in0, in1);
iadst16_sse2(in0, in1);
FLIPUD_PTR(dest, stride, 16);
FLIPLR_16x16(in0, in1);
break;
case ADST_FLIPADST:
iadst16_sse2(in0, in1);
iadst16_sse2(in0, in1);
FLIPLR_16x16(in0, in1);
break;
case FLIPADST_ADST:
iadst16_sse2(in0, in1);
iadst16_sse2(in0, in1);
FLIPUD_PTR(dest, stride, 16);
break;
#endif // CONFIG_EXT_TX
default:
assert(0);
break;
@ -3985,3 +4121,573 @@ void vp9_idct32x32_1_add_sse2(const int16_t *input, uint8_t *dest, int stride) {
dest += 8 - (stride * 32);
}
}
#if CONFIG_VP9_HIGHBITDEPTH
static INLINE __m128i clamp_high_sse2(__m128i value, int bd) {
__m128i ubounded, retval;
const __m128i zero = _mm_set1_epi16(0);
const __m128i one = _mm_set1_epi16(1);
const __m128i max = _mm_subs_epi16(_mm_slli_epi16(one, bd), one);
ubounded = _mm_cmpgt_epi16(value, max);
retval = _mm_andnot_si128(ubounded, value);
ubounded = _mm_and_si128(ubounded, max);
retval = _mm_or_si128(retval, ubounded);
retval = _mm_and_si128(retval, _mm_cmpgt_epi16(retval, zero));
return retval;
}
void vp9_highbd_idct4x4_16_add_sse2(const tran_low_t *input, uint8_t *dest8,
int stride, int bd) {
tran_low_t out[4 * 4];
tran_low_t *outptr = out;
int i, j;
__m128i inptr[4];
__m128i sign_bits[2];
__m128i temp_mm, min_input, max_input;
int test;
uint16_t * dest = CONVERT_TO_SHORTPTR(dest8);
int optimised_cols = 0;
const __m128i zero = _mm_set1_epi16(0);
const __m128i eight = _mm_set1_epi16(8);
const __m128i max = _mm_set1_epi16(12043);
const __m128i min = _mm_set1_epi16(-12043);
// Load input into __m128i
inptr[0] = _mm_loadu_si128((const __m128i *)input);
inptr[1] = _mm_loadu_si128((const __m128i *)(input + 4));
inptr[2] = _mm_loadu_si128((const __m128i *)(input + 8));
inptr[3] = _mm_loadu_si128((const __m128i *)(input + 12));
// Pack to 16 bits
inptr[0] = _mm_packs_epi32(inptr[0], inptr[1]);
inptr[1] = _mm_packs_epi32(inptr[2], inptr[3]);
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp_mm = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp_mm);
if (!test) {
// Do the row transform
idct4_sse2(inptr);
// Check the min & max values
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp_mm = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp_mm);
if (test) {
transpose_4x4(inptr);
sign_bits[0] = _mm_cmplt_epi16(inptr[0], zero);
sign_bits[1] = _mm_cmplt_epi16(inptr[1], zero);
inptr[3] = _mm_unpackhi_epi16(inptr[1], sign_bits[1]);
inptr[2] = _mm_unpacklo_epi16(inptr[1], sign_bits[1]);
inptr[1] = _mm_unpackhi_epi16(inptr[0], sign_bits[0]);
inptr[0] = _mm_unpacklo_epi16(inptr[0], sign_bits[0]);
_mm_storeu_si128((__m128i*)outptr, inptr[0]);
_mm_storeu_si128((__m128i*)(outptr + 4), inptr[1]);
_mm_storeu_si128((__m128i*)(outptr + 8), inptr[2]);
_mm_storeu_si128((__m128i*)(outptr + 12), inptr[3]);
} else {
// Set to use the optimised transform for the column
optimised_cols = 1;
}
} else {
// Run the un-optimised row transform
for (i = 0; i < 4; ++i) {
vp9_highbd_idct4(input, outptr, bd);
input += 4;
outptr += 4;
}
}
if (optimised_cols) {
idct4_sse2(inptr);
// Final round and shift
inptr[0] = _mm_add_epi16(inptr[0], eight);
inptr[1] = _mm_add_epi16(inptr[1], eight);
inptr[0] = _mm_srai_epi16(inptr[0], 4);
inptr[1] = _mm_srai_epi16(inptr[1], 4);
// Reconstruction and Store
{
__m128i d0 = _mm_loadl_epi64((const __m128i *)dest);
__m128i d2 = _mm_loadl_epi64((const __m128i *)(dest + stride * 2));
d0 = _mm_unpacklo_epi64(d0,
_mm_loadl_epi64((const __m128i *)(dest + stride)));
d2 = _mm_unpacklo_epi64(d2,
_mm_loadl_epi64((const __m128i *)(dest + stride * 3)));
d0 = clamp_high_sse2(_mm_adds_epi16(d0, inptr[0]), bd);
d2 = clamp_high_sse2(_mm_adds_epi16(d2, inptr[1]), bd);
// store input0
_mm_storel_epi64((__m128i *)dest, d0);
// store input1
d0 = _mm_srli_si128(d0, 8);
_mm_storel_epi64((__m128i *)(dest + stride), d0);
// store input2
_mm_storel_epi64((__m128i *)(dest + stride * 2), d2);
// store input3
d2 = _mm_srli_si128(d2, 8);
_mm_storel_epi64((__m128i *)(dest + stride * 3), d2);
}
} else {
// Run the un-optimised column transform
tran_low_t temp_in[4], temp_out[4];
// Columns
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j)
temp_in[j] = out[j * 4 + i];
vp9_highbd_idct4(temp_in, temp_out, bd);
for (j = 0; j < 4; ++j)
dest[j * stride + i] = highbd_clip_pixel_add(dest[j * stride + i],
ROUND_POWER_OF_TWO(temp_out[j], 4),
bd);
}
}
}
void vp9_highbd_idct8x8_64_add_sse2(const tran_low_t *input, uint8_t *dest8,
int stride, int bd) {
tran_low_t out[8 * 8];
tran_low_t *outptr = out;
int i, j, test;
__m128i inptr[8];
__m128i min_input, max_input, temp1, temp2, sign_bits;
uint16_t * dest = CONVERT_TO_SHORTPTR(dest8);
const __m128i zero = _mm_set1_epi16(0);
const __m128i sixteen = _mm_set1_epi16(16);
const __m128i max = _mm_set1_epi16(6201);
const __m128i min = _mm_set1_epi16(-6201);
int optimised_cols = 0;
// Load input into __m128i & pack to 16 bits
for (i = 0; i < 8; i++) {
temp1 = _mm_loadu_si128((const __m128i *)(input + 8*i));
temp2 = _mm_loadu_si128((const __m128i *)(input + 8*i + 4));
inptr[i] = _mm_packs_epi32(temp1, temp2);
}
// Find the min & max for the row transform
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
for (i = 2; i < 8; i++) {
max_input = _mm_max_epi16(max_input, inptr[i]);
min_input = _mm_min_epi16(min_input, inptr[i]);
}
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp1 = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp1);
if (!test) {
// Do the row transform
idct8_sse2(inptr);
// Find the min & max for the column transform
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
for (i = 2; i < 8; i++) {
max_input = _mm_max_epi16(max_input, inptr[i]);
min_input = _mm_min_epi16(min_input, inptr[i]);
}
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp1 = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp1);
if (test) {
array_transpose_8x8(inptr, inptr);
for (i = 0; i < 8; i++) {
sign_bits = _mm_cmplt_epi16(inptr[i], zero);
temp1 = _mm_unpackhi_epi16(inptr[i], sign_bits);
temp2 = _mm_unpacklo_epi16(inptr[i], sign_bits);
_mm_storeu_si128((__m128i*)(outptr + 4*(2*i+1)), temp1);
_mm_storeu_si128((__m128i*)(outptr + 4*(2*i)), temp2);
}
} else {
// Set to use the optimised transform for the column
optimised_cols = 1;
}
} else {
// Run the un-optimised row transform
for (i = 0; i < 8; ++i) {
vp9_highbd_idct8(input, outptr, bd);
input += 8;
outptr += 8;
}
}
if (optimised_cols) {
idct8_sse2(inptr);
// Final round & shift and Reconstruction and Store
{
__m128i d[8];
for (i = 0; i < 8; i++) {
inptr[i] = _mm_add_epi16(inptr[i], sixteen);
d[i] = _mm_loadu_si128((const __m128i *)(dest + stride*i));
inptr[i] = _mm_srai_epi16(inptr[i], 5);
d[i] = clamp_high_sse2(_mm_adds_epi16(d[i], inptr[i]), bd);
// Store
_mm_storeu_si128((__m128i *)(dest + stride*i), d[i]);
}
}
} else {
// Run the un-optimised column transform
tran_low_t temp_in[8], temp_out[8];
for (i = 0; i < 8; ++i) {
for (j = 0; j < 8; ++j)
temp_in[j] = out[j * 8 + i];
vp9_highbd_idct8(temp_in, temp_out, bd);
for (j = 0; j < 8; ++j)
dest[j * stride + i] = highbd_clip_pixel_add(dest[j * stride + i],
ROUND_POWER_OF_TWO(temp_out[j], 5),
bd);
}
}
}
void vp9_highbd_idct8x8_10_add_sse2(const tran_low_t *input, uint8_t *dest8,
int stride, int bd) {
tran_low_t out[8 * 8] = { 0 };
tran_low_t *outptr = out;
int i, j, test;
__m128i inptr[8];
__m128i min_input, max_input, temp1, temp2, sign_bits;
uint16_t * dest = CONVERT_TO_SHORTPTR(dest8);
const __m128i zero = _mm_set1_epi16(0);
const __m128i sixteen = _mm_set1_epi16(16);
const __m128i max = _mm_set1_epi16(6201);
const __m128i min = _mm_set1_epi16(-6201);
int optimised_cols = 0;
// Load input into __m128i & pack to 16 bits
for (i = 0; i < 8; i++) {
temp1 = _mm_loadu_si128((const __m128i *)(input + 8*i));
temp2 = _mm_loadu_si128((const __m128i *)(input + 8*i + 4));
inptr[i] = _mm_packs_epi32(temp1, temp2);
}
// Find the min & max for the row transform
// only first 4 row has non-zero coefs
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
for (i = 2; i < 4; i++) {
max_input = _mm_max_epi16(max_input, inptr[i]);
min_input = _mm_min_epi16(min_input, inptr[i]);
}
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp1 = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp1);
if (!test) {
// Do the row transform
idct8_sse2(inptr);
// Find the min & max for the column transform
// N.B. Only first 4 cols contain non-zero coeffs
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
for (i = 2; i < 8; i++) {
max_input = _mm_max_epi16(max_input, inptr[i]);
min_input = _mm_min_epi16(min_input, inptr[i]);
}
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp1 = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp1);
if (test) {
// Use fact only first 4 rows contain non-zero coeffs
array_transpose_4X8(inptr, inptr);
for (i = 0; i < 4; i++) {
sign_bits = _mm_cmplt_epi16(inptr[i], zero);
temp1 = _mm_unpackhi_epi16(inptr[i], sign_bits);
temp2 = _mm_unpacklo_epi16(inptr[i], sign_bits);
_mm_storeu_si128((__m128i*)(outptr + 4*(2*i+1)), temp1);
_mm_storeu_si128((__m128i*)(outptr + 4*(2*i)), temp2);
}
} else {
// Set to use the optimised transform for the column
optimised_cols = 1;
}
} else {
// Run the un-optimised row transform
for (i = 0; i < 4; ++i) {
vp9_highbd_idct8(input, outptr, bd);
input += 8;
outptr += 8;
}
}
if (optimised_cols) {
idct8_sse2(inptr);
// Final round & shift and Reconstruction and Store
{
__m128i d[8];
for (i = 0; i < 8; i++) {
inptr[i] = _mm_add_epi16(inptr[i], sixteen);
d[i] = _mm_loadu_si128((const __m128i *)(dest + stride*i));
inptr[i] = _mm_srai_epi16(inptr[i], 5);
d[i] = clamp_high_sse2(_mm_adds_epi16(d[i], inptr[i]), bd);
// Store
_mm_storeu_si128((__m128i *)(dest + stride*i), d[i]);
}
}
} else {
// Run the un-optimised column transform
tran_low_t temp_in[8], temp_out[8];
for (i = 0; i < 8; ++i) {
for (j = 0; j < 8; ++j)
temp_in[j] = out[j * 8 + i];
vp9_highbd_idct8(temp_in, temp_out, bd);
for (j = 0; j < 8; ++j)
dest[j * stride + i] = highbd_clip_pixel_add(dest[j * stride + i],
ROUND_POWER_OF_TWO(temp_out[j], 5),
bd);
}
}
}
void vp9_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest8,
int stride, int bd) {
tran_low_t out[16 * 16];
tran_low_t *outptr = out;
int i, j, test;
__m128i inptr[32];
__m128i min_input, max_input, temp1, temp2, sign_bits;
uint16_t * dest = CONVERT_TO_SHORTPTR(dest8);
const __m128i zero = _mm_set1_epi16(0);
const __m128i rounding = _mm_set1_epi16(32);
const __m128i max = _mm_set1_epi16(3155);
const __m128i min = _mm_set1_epi16(-3155);
int optimised_cols = 0;
// Load input into __m128i & pack to 16 bits
for (i = 0; i < 16; i++) {
temp1 = _mm_loadu_si128((const __m128i *)(input + 16*i));
temp2 = _mm_loadu_si128((const __m128i *)(input + 16*i + 4));
inptr[i] = _mm_packs_epi32(temp1, temp2);
temp1 = _mm_loadu_si128((const __m128i *)(input + 16*i + 8));
temp2 = _mm_loadu_si128((const __m128i *)(input + 16*i + 12));
inptr[i + 16] = _mm_packs_epi32(temp1, temp2);
}
// Find the min & max for the row transform
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
for (i = 2; i < 32; i++) {
max_input = _mm_max_epi16(max_input, inptr[i]);
min_input = _mm_min_epi16(min_input, inptr[i]);
}
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp1 = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp1);
if (!test) {
// Do the row transform
idct16_sse2(inptr, inptr + 16);
// Find the min & max for the column transform
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
for (i = 2; i < 32; i++) {
max_input = _mm_max_epi16(max_input, inptr[i]);
min_input = _mm_min_epi16(min_input, inptr[i]);
}
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp1 = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp1);
if (test) {
array_transpose_16x16(inptr, inptr + 16);
for (i = 0; i < 16; i++) {
sign_bits = _mm_cmplt_epi16(inptr[i], zero);
temp1 = _mm_unpacklo_epi16(inptr[i ], sign_bits);
temp2 = _mm_unpackhi_epi16(inptr[i ], sign_bits);
_mm_storeu_si128((__m128i*)(outptr + 4*(i*4)), temp1);
_mm_storeu_si128((__m128i*)(outptr + 4*(i*4+1)), temp2);
sign_bits = _mm_cmplt_epi16(inptr[i+16], zero);
temp1 = _mm_unpacklo_epi16(inptr[i+16], sign_bits);
temp2 = _mm_unpackhi_epi16(inptr[i+16], sign_bits);
_mm_storeu_si128((__m128i*)(outptr + 4*(i*4+2)), temp1);
_mm_storeu_si128((__m128i*)(outptr + 4*(i*4+3)), temp2);
}
} else {
// Set to use the optimised transform for the column
optimised_cols = 1;
}
} else {
// Run the un-optimised row transform
for (i = 0; i < 16; ++i) {
vp9_highbd_idct16(input, outptr, bd);
input += 16;
outptr += 16;
}
}
if (optimised_cols) {
idct16_sse2(inptr, inptr + 16);
// Final round & shift and Reconstruction and Store
{
__m128i d[2];
for (i = 0; i < 16; i++) {
inptr[i ] = _mm_add_epi16(inptr[i ], rounding);
inptr[i+16] = _mm_add_epi16(inptr[i+16], rounding);
d[0] = _mm_loadu_si128((const __m128i *)(dest + stride*i));
d[1] = _mm_loadu_si128((const __m128i *)(dest + stride*i + 8));
inptr[i ] = _mm_srai_epi16(inptr[i ], 6);
inptr[i+16] = _mm_srai_epi16(inptr[i+16], 6);
d[0] = clamp_high_sse2(_mm_add_epi16(d[0], inptr[i ]), bd);
d[1] = clamp_high_sse2(_mm_add_epi16(d[1], inptr[i+16]), bd);
// Store
_mm_storeu_si128((__m128i *)(dest + stride*i), d[0]);
_mm_storeu_si128((__m128i *)(dest + stride*i + 8), d[1]);
}
}
} else {
// Run the un-optimised column transform
tran_low_t temp_in[16], temp_out[16];
for (i = 0; i < 16; ++i) {
for (j = 0; j < 16; ++j)
temp_in[j] = out[j * 16 + i];
vp9_highbd_idct16(temp_in, temp_out, bd);
for (j = 0; j < 16; ++j)
dest[j * stride + i] = highbd_clip_pixel_add(dest[j * stride + i],
ROUND_POWER_OF_TWO(temp_out[j], 6),
bd);
}
}
}
void vp9_highbd_idct16x16_10_add_sse2(const tran_low_t *input, uint8_t *dest8,
int stride, int bd) {
tran_low_t out[16 * 16] = { 0 };
tran_low_t *outptr = out;
int i, j, test;
__m128i inptr[32];
__m128i min_input, max_input, temp1, temp2, sign_bits;
uint16_t * dest = CONVERT_TO_SHORTPTR(dest8);
const __m128i zero = _mm_set1_epi16(0);
const __m128i rounding = _mm_set1_epi16(32);
const __m128i max = _mm_set1_epi16(3155);
const __m128i min = _mm_set1_epi16(-3155);
int optimised_cols = 0;
// Load input into __m128i & pack to 16 bits
for (i = 0; i < 16; i++) {
temp1 = _mm_loadu_si128((const __m128i *)(input + 16*i));
temp2 = _mm_loadu_si128((const __m128i *)(input + 16*i + 4));
inptr[i] = _mm_packs_epi32(temp1, temp2);
temp1 = _mm_loadu_si128((const __m128i *)(input + 16*i + 8));
temp2 = _mm_loadu_si128((const __m128i *)(input + 16*i + 12));
inptr[i + 16] = _mm_packs_epi32(temp1, temp2);
}
// Find the min & max for the row transform
// Since all non-zero dct coefficients are in upper-left 4x4 area,
// we only need to consider first 4 rows here.
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
for (i = 2; i < 4; i++) {
max_input = _mm_max_epi16(max_input, inptr[i]);
min_input = _mm_min_epi16(min_input, inptr[i]);
}
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp1 = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp1);
if (!test) {
// Do the row transform (N.B. This transposes inptr)
idct16_sse2(inptr, inptr + 16);
// Find the min & max for the column transform
// N.B. Only first 4 cols contain non-zero coeffs
max_input = _mm_max_epi16(inptr[0], inptr[1]);
min_input = _mm_min_epi16(inptr[0], inptr[1]);
for (i = 2; i < 16; i++) {
max_input = _mm_max_epi16(max_input, inptr[i]);
min_input = _mm_min_epi16(min_input, inptr[i]);
}
max_input = _mm_cmpgt_epi16(max_input, max);
min_input = _mm_cmplt_epi16(min_input, min);
temp1 = _mm_or_si128(max_input, min_input);
test = _mm_movemask_epi8(temp1);
if (test) {
// Use fact only first 4 rows contain non-zero coeffs
array_transpose_8x8(inptr, inptr);
array_transpose_8x8(inptr + 8, inptr + 16);
for (i = 0; i < 4; i++) {
sign_bits = _mm_cmplt_epi16(inptr[i], zero);
temp1 = _mm_unpacklo_epi16(inptr[i ], sign_bits);
temp2 = _mm_unpackhi_epi16(inptr[i ], sign_bits);
_mm_storeu_si128((__m128i*)(outptr + 4*(i*4)), temp1);
_mm_storeu_si128((__m128i*)(outptr + 4*(i*4+1)), temp2);
sign_bits = _mm_cmplt_epi16(inptr[i+16], zero);
temp1 = _mm_unpacklo_epi16(inptr[i+16], sign_bits);
temp2 = _mm_unpackhi_epi16(inptr[i+16], sign_bits);
_mm_storeu_si128((__m128i*)(outptr + 4*(i*4+2)), temp1);
_mm_storeu_si128((__m128i*)(outptr + 4*(i*4+3)), temp2);
}
} else {
// Set to use the optimised transform for the column
optimised_cols = 1;
}
} else {
// Run the un-optimised row transform
for (i = 0; i < 4; ++i) {
vp9_highbd_idct16(input, outptr, bd);
input += 16;
outptr += 16;
}
}
if (optimised_cols) {
idct16_sse2(inptr, inptr + 16);
// Final round & shift and Reconstruction and Store
{
__m128i d[2];
for (i = 0; i < 16; i++) {
inptr[i ] = _mm_add_epi16(inptr[i ], rounding);
inptr[i+16] = _mm_add_epi16(inptr[i+16], rounding);
d[0] = _mm_loadu_si128((const __m128i *)(dest + stride*i));
d[1] = _mm_loadu_si128((const __m128i *)(dest + stride*i + 8));
inptr[i ] = _mm_srai_epi16(inptr[i ], 6);
inptr[i+16] = _mm_srai_epi16(inptr[i+16], 6);
d[0] = clamp_high_sse2(_mm_add_epi16(d[0], inptr[i ]), bd);
d[1] = clamp_high_sse2(_mm_add_epi16(d[1], inptr[i+16]), bd);
// Store
_mm_storeu_si128((__m128i *)(dest + stride*i), d[0]);
_mm_storeu_si128((__m128i *)(dest + stride*i + 8), d[1]);
}
}
} else {
// Run the un-optimised column transform
tran_low_t temp_in[16], temp_out[16];
for (i = 0; i < 16; ++i) {
for (j = 0; j < 16; ++j)
temp_in[j] = out[j * 16 + i];
vp9_highbd_idct16(temp_in, temp_out, bd);
for (j = 0; j < 16; ++j)
dest[j * stride + i] = highbd_clip_pixel_add(dest[j * stride + i],
ROUND_POWER_OF_TWO(temp_out[j], 6),
bd);
}
}
}
#endif // CONFIG_VP9_HIGHBITDEPTH

File diff suppressed because it is too large Load Diff

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