Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
ffmpeg
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
ffmpeg
Commits
c8c81ac5
Commit
c8c81ac5
authored
Sep 09, 2018
by
Mark Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lavc: Add coded bitstream read/write support for AV1
parent
5ee41447
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
3541 additions
and
0 deletions
+3541
-0
configure
configure
+2
-0
Makefile
libavcodec/Makefile
+1
-0
av1.h
libavcodec/av1.h
+88
-0
cbs.c
libavcodec/cbs.c
+6
-0
cbs_av1.c
libavcodec/cbs_av1.c
+1320
-0
cbs_av1.h
libavcodec/cbs_av1.h
+429
-0
cbs_av1_syntax_template.c
libavcodec/cbs_av1_syntax_template.c
+1694
-0
cbs_internal.h
libavcodec/cbs_internal.h
+1
-0
No files found.
configure
View file @
c8c81ac5
...
...
@@ -2271,6 +2271,7 @@ CONFIG_EXTRA="
bswapdsp
cabac
cbs
cbs_av1
cbs_h264
cbs_h265
cbs_jpeg
...
...
@@ -2535,6 +2536,7 @@ w32threads_deps="atomics_native"
threads_if_any
=
"
$THREADS_LIST
"
# subsystems
cbs_av1_select
=
"cbs"
cbs_h264_select
=
"cbs golomb"
cbs_h265_select
=
"cbs golomb"
cbs_jpeg_select
=
"cbs"
...
...
libavcodec/Makefile
View file @
c8c81ac5
...
...
@@ -63,6 +63,7 @@ OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o
OBJS-$(CONFIG_BSWAPDSP)
+=
bswapdsp.o
OBJS-$(CONFIG_CABAC)
+=
cabac.o
OBJS-$(CONFIG_CBS)
+=
cbs.o
OBJS-$(CONFIG_CBS_AV1)
+=
cbs_av1.o
OBJS-$(CONFIG_CBS_H264)
+=
cbs_h2645.o
h2645_parse.o
OBJS-$(CONFIG_CBS_H265)
+=
cbs_h2645.o
h2645_parse.o
OBJS-$(CONFIG_CBS_JPEG)
+=
cbs_jpeg.o
...
...
libavcodec/av1.h
View file @
c8c81ac5
...
...
@@ -39,4 +39,92 @@ typedef enum {
AV1_OBU_PADDING
=
15
,
}
AV1_OBU_Type
;
// Metadata types (section 6.7.1).
enum
{
AV1_METADATA_TYPE_HDR_CLL
=
1
,
AV1_METADATA_TYPE_HDR_MDCV
=
2
,
AV1_METADATA_TYPE_SCALABILITY
=
3
,
AV1_METADATA_TYPE_ITUT_T35
=
4
,
AV1_METADATA_TYPE_TIMECODE
=
5
,
};
// Frame types (section 6.8.2).
enum
{
AV1_FRAME_KEY
=
0
,
AV1_FRAME_INTER
=
1
,
AV1_FRAME_INTRA_ONLY
=
2
,
AV1_FRAME_SWITCH
=
3
,
};
// Reference frames (section 6.10.24).
enum
{
AV1_REF_FRAME_INTRA
=
0
,
AV1_REF_FRAME_LAST
=
1
,
AV1_REF_FRAME_LAST2
=
2
,
AV1_REF_FRAME_LAST3
=
3
,
AV1_REF_FRAME_GOLDEN
=
4
,
AV1_REF_FRAME_BWDREF
=
5
,
AV1_REF_FRAME_ALTREF2
=
6
,
AV1_REF_FRAME_ALTREF
=
7
,
};
// Constants (section 3).
enum
{
AV1_MAX_OPERATING_POINTS
=
32
,
AV1_MAX_SB_SIZE
=
128
,
AV1_MI_SIZE
=
4
,
AV1_MAX_TILE_WIDTH
=
4096
,
AV1_MAX_TILE_AREA
=
4096
*
2304
,
AV1_MAX_TILE_ROWS
=
64
,
AV1_MAX_TILE_COLS
=
64
,
AV1_NUM_REF_FRAMES
=
8
,
AV1_REFS_PER_FRAME
=
7
,
AV1_TOTAL_REFS_PER_FRAME
=
8
,
AV1_PRIMARY_REF_NONE
=
7
,
AV1_MAX_SEGMENTS
=
8
,
AV1_SEG_LVL_MAX
=
8
,
AV1_SEG_LVL_ALT_Q
=
0
,
AV1_SEG_LVL_ALT_LF_Y_V
=
1
,
AV1_SEG_LVL_REF_FRAME
=
5
,
AV1_SEG_LVL_SKIP
=
6
,
AV1_SEG_LVL_GLOBAL_MV
=
7
,
AV1_SELECT_SCREEN_CONTENT_TOOLS
=
2
,
AV1_SELECT_INTEGER_MV
=
2
,
AV1_SUPERRES_NUM
=
8
,
AV1_SUPERRES_DENOM_MIN
=
9
,
AV1_INTERPOLATION_FILTER_SWITCHABLE
=
4
,
AV1_GM_ABS_ALPHA_BITS
=
12
,
AV1_GM_ALPHA_PREC_BITS
=
15
,
AV1_GM_ABS_TRANS_ONLY_BITS
=
9
,
AV1_GM_TRANS_ONLY_PREC_BITS
=
3
,
AV1_GM_ABS_TRANS_BITS
=
12
,
AV1_GM_TRANS_PREC_BITS
=
6
,
AV1_WARPEDMODEL_PREC_BITS
=
16
,
AV1_WARP_MODEL_IDENTITY
=
0
,
AV1_WARP_MODEL_TRANSLATION
=
1
,
AV1_WARP_MODEL_ROTZOOM
=
2
,
AV1_WARP_MODEL_AFFINE
=
3
,
};
// The main colour configuration information uses the same ISO/IEC 23001-8
// (H.273) enums as FFmpeg does, so separate definitions are not required.
// Chroma sample position.
enum
{
AV1_CSP_UNKNOWN
=
0
,
AV1_CSP_VERTICAL
=
1
,
// -> AVCHROMA_LOC_LEFT.
AV1_CSP_COLOCATED
=
2
,
// -> AVCHROMA_LOC_TOPLEFT.
};
#endif
/* AVCODEC_AV1_H */
libavcodec/cbs.c
View file @
c8c81ac5
...
...
@@ -29,6 +29,9 @@
static
const
CodedBitstreamType
*
cbs_type_table
[]
=
{
#if CONFIG_CBS_AV1
&
ff_cbs_type_av1
,
#endif
#if CONFIG_CBS_H264
&
ff_cbs_type_h264
,
#endif
...
...
@@ -47,6 +50,9 @@ static const CodedBitstreamType *cbs_type_table[] = {
};
const
enum
AVCodecID
ff_cbs_all_codec_ids
[]
=
{
#if CONFIG_CBS_AV1
AV_CODEC_ID_AV1
,
#endif
#if CONFIG_CBS_H264
AV_CODEC_ID_H264
,
#endif
...
...
libavcodec/cbs_av1.c
0 → 100644
View file @
c8c81ac5
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/avassert.h"
#include "libavutil/pixfmt.h"
#include "cbs.h"
#include "cbs_internal.h"
#include "cbs_av1.h"
#include "internal.h"
static
int
cbs_av1_read_uvlc
(
CodedBitstreamContext
*
ctx
,
GetBitContext
*
gbc
,
const
char
*
name
,
uint32_t
*
write_to
,
uint32_t
range_min
,
uint32_t
range_max
)
{
uint32_t
value
;
int
position
,
zeroes
,
i
,
j
;
char
bits
[
65
];
if
(
ctx
->
trace_enable
)
position
=
get_bits_count
(
gbc
);
zeroes
=
i
=
0
;
while
(
1
)
{
if
(
get_bits_left
(
gbc
)
<
zeroes
+
1
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Invalid uvlc code at "
"%s: bitstream ended.
\n
"
,
name
);
return
AVERROR_INVALIDDATA
;
}
if
(
get_bits1
(
gbc
))
{
bits
[
i
++
]
=
'1'
;
break
;
}
else
{
bits
[
i
++
]
=
'0'
;
++
zeroes
;
}
}
if
(
zeroes
>=
32
)
{
value
=
MAX_UINT_BITS
(
32
);
}
else
{
value
=
get_bits_long
(
gbc
,
zeroes
);
for
(
j
=
0
;
j
<
zeroes
;
j
++
)
bits
[
i
++
]
=
(
value
>>
(
zeroes
-
j
-
1
)
&
1
)
?
'1'
:
'0'
;
value
+=
(
1
<<
zeroes
)
-
1
;
}
if
(
ctx
->
trace_enable
)
{
bits
[
i
]
=
0
;
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
NULL
,
bits
,
value
);
}
if
(
value
<
range_min
||
value
>
range_max
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"%s out of range: "
"%"
PRIu32
", but must be in [%"
PRIu32
",%"
PRIu32
"].
\n
"
,
name
,
value
,
range_min
,
range_max
);
return
AVERROR_INVALIDDATA
;
}
*
write_to
=
value
;
return
0
;
}
static
int
cbs_av1_write_uvlc
(
CodedBitstreamContext
*
ctx
,
PutBitContext
*
pbc
,
const
char
*
name
,
uint32_t
value
,
uint32_t
range_min
,
uint32_t
range_max
)
{
uint32_t
v
;
int
position
,
zeroes
;
if
(
value
<
range_min
||
value
>
range_max
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"%s out of range: "
"%"
PRIu32
", but must be in [%"
PRIu32
",%"
PRIu32
"].
\n
"
,
name
,
value
,
range_min
,
range_max
);
return
AVERROR_INVALIDDATA
;
}
if
(
ctx
->
trace_enable
)
position
=
put_bits_count
(
pbc
);
if
(
value
==
0
)
{
zeroes
=
0
;
put_bits
(
pbc
,
1
,
1
);
}
else
{
zeroes
=
av_log2
(
value
+
1
);
v
=
value
-
(
1
<<
zeroes
)
+
1
;
put_bits
(
pbc
,
zeroes
+
1
,
1
);
put_bits
(
pbc
,
zeroes
,
v
);
}
if
(
ctx
->
trace_enable
)
{
char
bits
[
65
];
int
i
,
j
;
i
=
0
;
for
(
j
=
0
;
j
<
zeroes
;
j
++
)
bits
[
i
++
]
=
'0'
;
bits
[
i
++
]
=
'1'
;
for
(
j
=
0
;
j
<
zeroes
;
j
++
)
bits
[
i
++
]
=
(
v
>>
(
zeroes
-
j
-
1
)
&
1
)
?
'1'
:
'0'
;
bits
[
i
++
]
=
0
;
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
NULL
,
bits
,
value
);
}
return
0
;
}
static
int
cbs_av1_read_leb128
(
CodedBitstreamContext
*
ctx
,
GetBitContext
*
gbc
,
const
char
*
name
,
uint64_t
*
write_to
)
{
uint64_t
value
;
int
position
,
err
,
i
;
if
(
ctx
->
trace_enable
)
position
=
get_bits_count
(
gbc
);
value
=
0
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
int
subscript
[
2
]
=
{
1
,
i
};
uint32_t
byte
;
err
=
ff_cbs_read_unsigned
(
ctx
,
gbc
,
8
,
"leb128_byte[i]"
,
subscript
,
&
byte
,
0x00
,
0xff
);
if
(
err
<
0
)
return
err
;
value
|=
(
uint64_t
)(
byte
&
0x7f
)
<<
(
i
*
7
);
if
(
!
(
byte
&
0x80
))
break
;
}
if
(
ctx
->
trace_enable
)
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
NULL
,
""
,
value
);
*
write_to
=
value
;
return
0
;
}
static
int
cbs_av1_write_leb128
(
CodedBitstreamContext
*
ctx
,
PutBitContext
*
pbc
,
const
char
*
name
,
uint64_t
value
)
{
int
position
,
err
,
len
,
i
;
uint8_t
byte
;
len
=
(
av_log2
(
value
)
+
7
)
/
7
;
if
(
ctx
->
trace_enable
)
position
=
put_bits_count
(
pbc
);
for
(
i
=
0
;
i
<
len
;
i
++
)
{
int
subscript
[
2
]
=
{
1
,
i
};
byte
=
value
>>
(
7
*
i
)
&
0x7f
;
if
(
i
<
len
-
1
)
byte
|=
0x80
;
err
=
ff_cbs_write_unsigned
(
ctx
,
pbc
,
8
,
"leb128_byte[i]"
,
subscript
,
byte
,
0x00
,
0xff
);
if
(
err
<
0
)
return
err
;
}
if
(
ctx
->
trace_enable
)
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
NULL
,
""
,
value
);
return
0
;
}
static
int
cbs_av1_read_su
(
CodedBitstreamContext
*
ctx
,
GetBitContext
*
gbc
,
int
width
,
const
char
*
name
,
const
int
*
subscripts
,
int32_t
*
write_to
)
{
uint32_t
magnitude
;
int
position
,
sign
;
int32_t
value
;
if
(
ctx
->
trace_enable
)
position
=
get_bits_count
(
gbc
);
if
(
get_bits_left
(
gbc
)
<
width
+
1
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Invalid signed value at "
"%s: bitstream ended.
\n
"
,
name
);
return
AVERROR_INVALIDDATA
;
}
magnitude
=
get_bits
(
gbc
,
width
);
sign
=
get_bits1
(
gbc
);
value
=
sign
?
-
(
int32_t
)
magnitude
:
magnitude
;
if
(
ctx
->
trace_enable
)
{
char
bits
[
33
];
int
i
;
for
(
i
=
0
;
i
<
width
;
i
++
)
bits
[
i
]
=
magnitude
>>
(
width
-
i
-
1
)
&
1
?
'1'
:
'0'
;
bits
[
i
]
=
sign
?
'1'
:
'0'
;
bits
[
i
+
1
]
=
0
;
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
subscripts
,
bits
,
value
);
}
*
write_to
=
value
;
return
0
;
}
static
int
cbs_av1_write_su
(
CodedBitstreamContext
*
ctx
,
PutBitContext
*
pbc
,
int
width
,
const
char
*
name
,
const
int
*
subscripts
,
int32_t
value
)
{
uint32_t
magnitude
;
int
sign
;
if
(
put_bits_left
(
pbc
)
<
width
+
1
)
return
AVERROR
(
ENOSPC
);
sign
=
value
<
0
;
magnitude
=
sign
?
-
value
:
value
;
if
(
ctx
->
trace_enable
)
{
char
bits
[
33
];
int
i
;
for
(
i
=
0
;
i
<
width
;
i
++
)
bits
[
i
]
=
magnitude
>>
(
width
-
i
-
1
)
&
1
?
'1'
:
'0'
;
bits
[
i
]
=
sign
?
'1'
:
'0'
;
bits
[
i
+
1
]
=
0
;
ff_cbs_trace_syntax_element
(
ctx
,
put_bits_count
(
pbc
),
name
,
subscripts
,
bits
,
value
);
}
put_bits
(
pbc
,
width
,
magnitude
);
put_bits
(
pbc
,
1
,
sign
);
return
0
;
}
static
int
cbs_av1_read_ns
(
CodedBitstreamContext
*
ctx
,
GetBitContext
*
gbc
,
uint32_t
n
,
const
char
*
name
,
const
int
*
subscripts
,
uint32_t
*
write_to
)
{
uint32_t
w
,
m
,
v
,
extra_bit
,
value
;
int
position
;
av_assert0
(
n
>
0
);
if
(
ctx
->
trace_enable
)
position
=
get_bits_count
(
gbc
);
w
=
av_log2
(
n
)
+
1
;
m
=
(
1
<<
w
)
-
n
;
if
(
get_bits_left
(
gbc
)
<
w
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Invalid non-symmetric value at "
"%s: bitstream ended.
\n
"
,
name
);
return
AVERROR_INVALIDDATA
;
}
if
(
w
-
1
>
0
)
v
=
get_bits
(
gbc
,
w
-
1
);
else
v
=
0
;
if
(
v
<
m
)
{
value
=
v
;
}
else
{
extra_bit
=
get_bits1
(
gbc
);
value
=
(
v
<<
1
)
-
m
+
extra_bit
;
}
if
(
ctx
->
trace_enable
)
{
char
bits
[
33
];
int
i
;
for
(
i
=
0
;
i
<
w
-
1
;
i
++
)
bits
[
i
]
=
(
v
>>
i
&
1
)
?
'1'
:
'0'
;
if
(
v
>=
m
)
bits
[
i
++
]
=
extra_bit
?
'1'
:
'0'
;
bits
[
i
]
=
0
;
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
subscripts
,
bits
,
value
);
}
*
write_to
=
value
;
return
0
;
}
static
int
cbs_av1_write_ns
(
CodedBitstreamContext
*
ctx
,
PutBitContext
*
pbc
,
uint32_t
n
,
const
char
*
name
,
const
int
*
subscripts
,
uint32_t
value
)
{
uint32_t
w
,
m
,
v
,
extra_bit
;
int
position
;
if
(
value
>
n
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"%s out of range: "
"%"
PRIu32
", but must be in [0,%"
PRIu32
"].
\n
"
,
name
,
value
,
n
);
return
AVERROR_INVALIDDATA
;
}
if
(
ctx
->
trace_enable
)
position
=
put_bits_count
(
pbc
);
w
=
av_log2
(
n
)
+
1
;
m
=
(
1
<<
w
)
-
n
;
if
(
put_bits_left
(
pbc
)
<
w
)
return
AVERROR
(
ENOSPC
);
if
(
value
<
m
)
{
v
=
value
;
put_bits
(
pbc
,
w
-
1
,
v
);
}
else
{
v
=
m
+
((
value
-
m
)
>>
1
);
extra_bit
=
(
value
-
m
)
&
1
;
put_bits
(
pbc
,
w
-
1
,
v
);
put_bits
(
pbc
,
1
,
extra_bit
);
}
if
(
ctx
->
trace_enable
)
{
char
bits
[
33
];
int
i
;
for
(
i
=
0
;
i
<
w
-
1
;
i
++
)
bits
[
i
]
=
(
v
>>
i
&
1
)
?
'1'
:
'0'
;
if
(
value
>=
m
)
bits
[
i
++
]
=
extra_bit
?
'1'
:
'0'
;
bits
[
i
]
=
0
;
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
subscripts
,
bits
,
value
);
}
return
0
;
}
static
int
cbs_av1_read_increment
(
CodedBitstreamContext
*
ctx
,
GetBitContext
*
gbc
,
uint32_t
range_min
,
uint32_t
range_max
,
const
char
*
name
,
uint32_t
*
write_to
)
{
uint32_t
value
;
int
position
,
i
;
char
bits
[
33
];
av_assert0
(
range_min
<=
range_max
&&
range_max
-
range_min
<
sizeof
(
bits
)
-
1
);
if
(
ctx
->
trace_enable
)
position
=
get_bits_count
(
gbc
);
for
(
i
=
0
,
value
=
range_min
;
value
<
range_max
;)
{
if
(
get_bits_left
(
gbc
)
<
1
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Invalid increment value at "
"%s: bitstream ended.
\n
"
,
name
);
return
AVERROR_INVALIDDATA
;
}
if
(
get_bits1
(
gbc
))
{
bits
[
i
++
]
=
'1'
;
++
value
;
}
else
{
bits
[
i
++
]
=
'0'
;
break
;
}
}
if
(
ctx
->
trace_enable
)
{
bits
[
i
]
=
0
;
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
NULL
,
bits
,
value
);
}
*
write_to
=
value
;
return
0
;
}
static
int
cbs_av1_write_increment
(
CodedBitstreamContext
*
ctx
,
PutBitContext
*
pbc
,
uint32_t
range_min
,
uint32_t
range_max
,
const
char
*
name
,
uint32_t
value
)
{
int
len
;
av_assert0
(
range_min
<=
range_max
&&
range_max
-
range_min
<
32
);
if
(
value
<
range_min
||
value
>
range_max
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"%s out of range: "
"%"
PRIu32
", but must be in [%"
PRIu32
",%"
PRIu32
"].
\n
"
,
name
,
value
,
range_min
,
range_max
);
return
AVERROR_INVALIDDATA
;
}
if
(
value
==
range_max
)
len
=
range_max
-
range_min
;
else
len
=
value
-
range_min
+
1
;
if
(
put_bits_left
(
pbc
)
<
len
)
return
AVERROR
(
ENOSPC
);
if
(
ctx
->
trace_enable
)
{
char
bits
[
33
];
int
i
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
if
(
range_min
+
i
==
value
)
bits
[
i
]
=
'0'
;
else
bits
[
i
]
=
'1'
;
}
bits
[
i
]
=
0
;
ff_cbs_trace_syntax_element
(
ctx
,
put_bits_count
(
pbc
),
name
,
NULL
,
bits
,
value
);
}
if
(
len
>
0
)
put_bits
(
pbc
,
len
,
(
1
<<
len
)
-
1
-
(
value
!=
range_max
));
return
0
;
}
static
int
cbs_av1_read_subexp
(
CodedBitstreamContext
*
ctx
,
GetBitContext
*
gbc
,
uint32_t
range_max
,
const
char
*
name
,
const
int
*
subscripts
,
uint32_t
*
write_to
)
{
uint32_t
value
;
int
position
,
err
;
uint32_t
max_len
,
len
,
range_offset
,
range_bits
;
if
(
ctx
->
trace_enable
)
position
=
get_bits_count
(
gbc
);
av_assert0
(
range_max
>
0
);
max_len
=
av_log2
(
range_max
-
1
)
-
3
;
err
=
cbs_av1_read_increment
(
ctx
,
gbc
,
0
,
max_len
,
"subexp_more_bits"
,
&
len
);
if
(
err
<
0
)
return
err
;
if
(
len
)
{
range_bits
=
2
+
len
;
range_offset
=
1
<<
range_bits
;
}
else
{
range_bits
=
3
;
range_offset
=
0
;
}
if
(
len
<
max_len
)
{
err
=
ff_cbs_read_unsigned
(
ctx
,
gbc
,
range_bits
,
"subexp_bits"
,
NULL
,
&
value
,
0
,
MAX_UINT_BITS
(
range_bits
));
if
(
err
<
0
)
return
err
;
}
else
{
err
=
cbs_av1_read_ns
(
ctx
,
gbc
,
range_max
-
range_offset
,
"subexp_final_bits"
,
NULL
,
&
value
);
if
(
err
<
0
)
return
err
;
}
value
+=
range_offset
;
if
(
ctx
->
trace_enable
)
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
subscripts
,
""
,
value
);
*
write_to
=
value
;
return
err
;
}
static
int
cbs_av1_write_subexp
(
CodedBitstreamContext
*
ctx
,
PutBitContext
*
pbc
,
uint32_t
range_max
,
const
char
*
name
,
const
int
*
subscripts
,
uint32_t
value
)
{
int
position
,
err
;
uint32_t
max_len
,
len
,
range_offset
,
range_bits
;
if
(
value
>
range_max
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"%s out of range: "
"%"
PRIu32
", but must be in [0,%"
PRIu32
"].
\n
"
,
name
,
value
,
range_max
);
return
AVERROR_INVALIDDATA
;
}
if
(
ctx
->
trace_enable
)
position
=
put_bits_count
(
pbc
);
av_assert0
(
range_max
>
0
);
max_len
=
av_log2
(
range_max
-
1
)
-
3
;
if
(
value
<
8
)
{
range_bits
=
3
;
range_offset
=
0
;
len
=
0
;
}
else
{
range_bits
=
av_log2
(
value
);
len
=
range_bits
-
2
;
if
(
len
>
max_len
)
{
// The top bin is combined with the one below it.
av_assert0
(
len
==
max_len
+
1
);
--
range_bits
;
len
=
max_len
;
}
range_offset
=
1
<<
range_bits
;
}
err
=
cbs_av1_write_increment
(
ctx
,
pbc
,
0
,
max_len
,
"subexp_more_bits"
,
len
);
if
(
err
<
0
)
return
err
;
if
(
len
<
max_len
)
{
err
=
ff_cbs_write_unsigned
(
ctx
,
pbc
,
range_bits
,
"subexp_bits"
,
NULL
,
value
-
range_offset
,
0
,
MAX_UINT_BITS
(
range_bits
));
if
(
err
<
0
)
return
err
;
}
else
{
err
=
cbs_av1_write_ns
(
ctx
,
pbc
,
range_max
-
range_offset
,
"subexp_final_bits"
,
NULL
,
value
-
range_offset
);
if
(
err
<
0
)
return
err
;
}
if
(
ctx
->
trace_enable
)
ff_cbs_trace_syntax_element
(
ctx
,
position
,
name
,
subscripts
,
""
,
value
);
return
err
;
}
static
int
cbs_av1_tile_log2
(
int
blksize
,
int
target
)
{
int
k
;
for
(
k
=
0
;
(
blksize
<<
k
)
<
target
;
k
++
);
return
k
;
}
static
int
cbs_av1_get_relative_dist
(
const
AV1RawSequenceHeader
*
seq
,
unsigned
int
a
,
unsigned
int
b
)
{
unsigned
int
diff
,
m
;
if
(
!
seq
->
enable_order_hint
)
return
0
;
diff
=
a
-
b
;
m
=
1
<<
seq
->
order_hint_bits_minus_1
;
diff
=
(
diff
&
(
m
-
1
))
-
(
diff
&
m
);
return
diff
;
}
#define HEADER(name) do { \
ff_cbs_trace_header(ctx, name); \
} while (0)
#define CHECK(call) do { \
err = (call); \
if (err < 0) \
return err; \
} while (0)
#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name
#define FUNC_AV1(rw, name) FUNC_NAME(rw, av1, name)
#define FUNC(name) FUNC_AV1(READWRITE, name)
#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
#define fb(width, name) \
xf(width, name, current->name, 0, MAX_UINT_BITS(width), 0)
#define fc(width, name, range_min, range_max) \
xf(width, name, current->name, range_min, range_max, 0)
#define flag(name) fb(1, name)
#define su(width, name) \
xsu(width, name, current->name, 0)
#define fbs(width, name, subs, ...) \
xf(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__)
#define fcs(width, name, range_min, range_max, subs, ...) \
xf(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
#define flags(name, subs, ...) \
xf(1, name, current->name, 0, 1, subs, __VA_ARGS__)
#define sus(width, name, subs, ...) \
xsu(width, name, current->name, subs, __VA_ARGS__)
#define fixed(width, name, value) do { \
av_unused uint32_t fixed_value = value; \
xf(width, name, fixed_value, value, value, 0); \
} while (0)
#define READ
#define READWRITE read
#define RWContext GetBitContext
#define xf(width, name, var, range_min, range_max, subs, ...) do { \
uint32_t value = range_min; \
CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
SUBSCRIPTS(subs, __VA_ARGS__), \
&value, range_min, range_max)); \
var = value; \
} while (0)
#define xsu(width, name, var, subs, ...) do { \
int32_t value = 0; \
CHECK(cbs_av1_read_su(ctx, rw, width, #name, \
SUBSCRIPTS(subs, __VA_ARGS__), &value)); \
var = value; \
} while (0)
#define uvlc(name, range_min, range_max) do { \
uint32_t value = range_min; \
CHECK(cbs_av1_read_uvlc(ctx, rw, #name, \
&value, range_min, range_max)); \
current->name = value; \
} while (0)
#define ns(max_value, name, subs, ...) do { \
uint32_t value = 0; \
CHECK(cbs_av1_read_ns(ctx, rw, max_value, #name, \
SUBSCRIPTS(subs, __VA_ARGS__), &value)); \
current->name = value; \
} while (0)
#define increment(name, min, max) do { \
uint32_t value = 0; \
CHECK(cbs_av1_read_increment(ctx, rw, min, max, #name, &value)); \
current->name = value; \
} while (0)
#define subexp(name, max, subs, ...) do { \
uint32_t value = 0; \
CHECK(cbs_av1_read_subexp(ctx, rw, max, #name, \
SUBSCRIPTS(subs, __VA_ARGS__), &value)); \
current->name = value; \
} while (0)
#define delta_q(name) do { \
uint8_t delta_coded; \
int8_t delta_q; \
xf(1, name.delta_coded, delta_coded, 0, 1, 0); \
if (delta_coded) \
xsu(1 + 6, name.delta_q, delta_q, 0); \
else \
delta_q = 0; \
current->name = delta_q; \
} while (0)
#define leb128(name) do { \
uint64_t value = 0; \
CHECK(cbs_av1_read_leb128(ctx, rw, #name, &value)); \
current->name = value; \
} while (0)
#define infer(name, value) do { \
current->name = value; \
} while (0)
#define byte_alignment(rw) (get_bits_count(rw) % 8)
#include "cbs_av1_syntax_template.c"
#undef READ
#undef READWRITE
#undef RWContext
#undef xf
#undef xsu
#undef uvlc
#undef leb128
#undef ns
#undef increment
#undef subexp
#undef delta_q
#undef leb128
#undef infer
#undef byte_alignment
#define WRITE
#define READWRITE write
#define RWContext PutBitContext
#define xf(width, name, var, range_min, range_max, subs, ...) do { \
CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
SUBSCRIPTS(subs, __VA_ARGS__), \
var, range_min, range_max)); \
} while (0)
#define xsu(width, name, var, subs, ...) do { \
CHECK(cbs_av1_write_su(ctx, rw, width, #name, \
SUBSCRIPTS(subs, __VA_ARGS__), var)); \
} while (0)
#define uvlc(name, range_min, range_max) do { \
CHECK(cbs_av1_write_uvlc(ctx, rw, #name, current->name, \
range_min, range_max)); \
} while (0)
#define ns(max_value, name, subs, ...) do { \
CHECK(cbs_av1_write_ns(ctx, rw, max_value, #name, \
SUBSCRIPTS(subs, __VA_ARGS__), \
current->name)); \
} while (0)
#define increment(name, min, max) do { \
CHECK(cbs_av1_write_increment(ctx, rw, min, max, #name, \
current->name)); \
} while (0)
#define subexp(name, max, subs, ...) do { \
CHECK(cbs_av1_write_subexp(ctx, rw, max, #name, \
SUBSCRIPTS(subs, __VA_ARGS__), \
current->name)); \
} while (0)
#define delta_q(name) do { \
xf(1, name.delta_coded, current->name != 0, 0, 1, 0); \
if (current->name) \
xsu(1 + 6, name.delta_q, current->name, 0); \
} while (0)
#define leb128(name) do { \
CHECK(cbs_av1_write_leb128(ctx, rw, #name, current->name)); \
} while (0)
#define infer(name, value) do { \
if (current->name != (value)) { \
av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \
"%s does not match inferred value: " \
"%"PRId64", but should be %"PRId64".\n", \
#name, (int64_t)current->name, (int64_t)(value)); \
} \
} while (0)
#define byte_alignment(rw) (put_bits_count(rw) % 8)
#include "cbs_av1_syntax_template.c"
#undef READ
#undef READWRITE
#undef RWContext
#undef xf
#undef xsu
#undef uvlc
#undef leb128
#undef ns
#undef increment
#undef subexp
#undef delta_q
#undef infer
#undef byte_alignment
static
int
cbs_av1_split_fragment
(
CodedBitstreamContext
*
ctx
,
CodedBitstreamFragment
*
frag
,
int
header
)
{
GetBitContext
gbc
;
uint8_t
*
data
;
size_t
size
;
uint64_t
obu_length
;
int
pos
,
err
,
trace
;
// Don't include this parsing in trace output.
trace
=
ctx
->
trace_enable
;
ctx
->
trace_enable
=
0
;
data
=
frag
->
data
;
size
=
frag
->
data_size
;
if
(
INT_MAX
/
8
<
size
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Invalid fragment: "
"too large (%zu bytes).
\n
"
,
size
);
err
=
AVERROR_INVALIDDATA
;
goto
fail
;
}
while
(
size
>
0
)
{
AV1RawOBUHeader
header
;
uint64_t
obu_size
;
init_get_bits
(
&
gbc
,
data
,
8
*
size
);
err
=
cbs_av1_read_obu_header
(
ctx
,
&
gbc
,
&
header
);
if
(
err
<
0
)
goto
fail
;
if
(
!
header
.
obu_has_size_field
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Invalid OBU for raw "
"stream: size field must be present.
\n
"
);
err
=
AVERROR_INVALIDDATA
;
goto
fail
;
}
if
(
get_bits_left
(
&
gbc
)
<
8
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Invalid OBU: fragment "
"too short (%zu bytes).
\n
"
,
size
);
err
=
AVERROR_INVALIDDATA
;
goto
fail
;
}
err
=
cbs_av1_read_leb128
(
ctx
,
&
gbc
,
"obu_size"
,
&
obu_size
);
if
(
err
<
0
)
goto
fail
;
pos
=
get_bits_count
(
&
gbc
);
av_assert0
(
pos
%
8
==
0
&&
pos
/
8
<=
size
);
obu_length
=
pos
/
8
+
obu_size
;
if
(
size
<
obu_length
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Invalid OBU length: "
"%"
PRIu64
", but only %zu bytes remaining in fragment.
\n
"
,
obu_length
,
size
);
err
=
AVERROR_INVALIDDATA
;
goto
fail
;
}
err
=
ff_cbs_insert_unit_data
(
ctx
,
frag
,
-
1
,
header
.
obu_type
,
data
,
obu_length
,
frag
->
data_ref
);
if
(
err
<
0
)
goto
fail
;
data
+=
obu_length
;
size
-=
obu_length
;
}
err
=
0
;
fail:
ctx
->
trace_enable
=
trace
;
return
err
;
}
static
void
cbs_av1_free_tile_data
(
AV1RawTileData
*
td
)
{
av_buffer_unref
(
&
td
->
data_ref
);
}
static
void
cbs_av1_free_metadata
(
AV1RawMetadata
*
md
)
{
switch
(
md
->
metadata_type
)
{
case
AV1_METADATA_TYPE_ITUT_T35
:
av_buffer_unref
(
&
md
->
metadata
.
itut_t35
.
payload_ref
);
break
;
}
}
static
void
cbs_av1_free_obu
(
void
*
unit
,
uint8_t
*
content
)
{
AV1RawOBU
*
obu
=
(
AV1RawOBU
*
)
content
;
switch
(
obu
->
header
.
obu_type
)
{
case
AV1_OBU_TILE_GROUP
:
cbs_av1_free_tile_data
(
&
obu
->
obu
.
tile_group
.
tile_data
);
break
;
case
AV1_OBU_FRAME
:
cbs_av1_free_tile_data
(
&
obu
->
obu
.
frame
.
tile_group
.
tile_data
);
break
;
case
AV1_OBU_TILE_LIST
:
cbs_av1_free_tile_data
(
&
obu
->
obu
.
tile_list
.
tile_data
);
break
;
case
AV1_OBU_METADATA
:
cbs_av1_free_metadata
(
&
obu
->
obu
.
metadata
);
break
;
}
av_freep
(
&
obu
);
}
static
int
cbs_av1_ref_tile_data
(
CodedBitstreamContext
*
ctx
,
CodedBitstreamUnit
*
unit
,
GetBitContext
*
gbc
,
AV1RawTileData
*
td
)
{
int
pos
;
pos
=
get_bits_count
(
gbc
);
if
(
pos
>=
8
*
unit
->
data_size
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Bitstream ended before "
"any data in tile group (%d bits read).
\n
"
,
pos
);
return
AVERROR_INVALIDDATA
;
}
// Must be byte-aligned at this point.
av_assert0
(
pos
%
8
==
0
);
td
->
data_ref
=
av_buffer_ref
(
unit
->
data_ref
);
if
(
!
td
->
data_ref
)
return
AVERROR
(
ENOMEM
);
td
->
data
=
unit
->
data
+
pos
/
8
;
td
->
data_size
=
unit
->
data_size
-
pos
/
8
;
return
0
;
}
static
int
cbs_av1_read_unit
(
CodedBitstreamContext
*
ctx
,
CodedBitstreamUnit
*
unit
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
AV1RawOBU
*
obu
;
GetBitContext
gbc
;
int
err
,
start_pos
,
end_pos
;
err
=
ff_cbs_alloc_unit_content
(
ctx
,
unit
,
sizeof
(
*
obu
),
&
cbs_av1_free_obu
);
if
(
err
<
0
)
return
err
;
obu
=
unit
->
content
;
err
=
init_get_bits
(
&
gbc
,
unit
->
data
,
8
*
unit
->
data_size
);
if
(
err
<
0
)
return
err
;
err
=
cbs_av1_read_obu_header
(
ctx
,
&
gbc
,
&
obu
->
header
);
if
(
err
<
0
)
return
err
;
av_assert0
(
obu
->
header
.
obu_type
==
unit
->
type
);
if
(
obu
->
header
.
obu_has_size_field
)
{
uint64_t
obu_size
;
err
=
cbs_av1_read_leb128
(
ctx
,
&
gbc
,
"obu_size"
,
&
obu_size
);
if
(
err
<
0
)
return
err
;
obu
->
obu_size
=
obu_size
;
}
else
{
if
(
unit
->
data_size
<
1
+
obu
->
header
.
obu_extension_flag
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Invalid OBU length: "
"unit too short (%zu).
\n
"
,
unit
->
data_size
);
return
AVERROR_INVALIDDATA
;
}
obu
->
obu_size
=
unit
->
data_size
-
1
-
obu
->
header
.
obu_extension_flag
;
}
start_pos
=
get_bits_count
(
&
gbc
);
if
(
obu
->
header
.
obu_extension_flag
)
{
priv
->
temporal_id
=
obu
->
header
.
temporal_id
;
priv
->
spatial_id
=
obu
->
header
.
temporal_id
;
if
(
obu
->
header
.
obu_type
!=
AV1_OBU_SEQUENCE_HEADER
&&
obu
->
header
.
obu_type
!=
AV1_OBU_TEMPORAL_DELIMITER
&&
priv
->
operating_point_idc
)
{
int
in_temporal_layer
=
(
priv
->
operating_point_idc
>>
priv
->
temporal_id
)
&
1
;
int
in_spatial_layer
=
(
priv
->
operating_point_idc
>>
(
priv
->
spatial_id
+
8
))
&
1
;
if
(
!
in_temporal_layer
||
!
in_spatial_layer
)
{
// Decoding will drop this OBU at this operating point.
}
}
}
else
{
priv
->
temporal_id
=
0
;
priv
->
spatial_id
=
0
;
}
switch
(
obu
->
header
.
obu_type
)
{
case
AV1_OBU_SEQUENCE_HEADER
:
{
err
=
cbs_av1_read_sequence_header_obu
(
ctx
,
&
gbc
,
&
obu
->
obu
.
sequence_header
);
if
(
err
<
0
)
return
err
;
av_buffer_unref
(
&
priv
->
sequence_header_ref
);
priv
->
sequence_header
=
NULL
;
priv
->
sequence_header_ref
=
av_buffer_ref
(
unit
->
content_ref
);
if
(
!
priv
->
sequence_header_ref
)
return
AVERROR
(
ENOMEM
);
priv
->
sequence_header
=
&
obu
->
obu
.
sequence_header
;
}
break
;
case
AV1_OBU_TEMPORAL_DELIMITER
:
{
err
=
cbs_av1_read_temporal_delimiter_obu
(
ctx
,
&
gbc
);
if
(
err
<
0
)
return
err
;
}
break
;
case
AV1_OBU_FRAME_HEADER
:
case
AV1_OBU_REDUNDANT_FRAME_HEADER
:
{
err
=
cbs_av1_read_frame_header_obu
(
ctx
,
&
gbc
,
&
obu
->
obu
.
frame_header
);
if
(
err
<
0
)
return
err
;
}
break
;
case
AV1_OBU_TILE_GROUP
:
{
err
=
cbs_av1_read_tile_group_obu
(
ctx
,
&
gbc
,
&
obu
->
obu
.
tile_group
);
if
(
err
<
0
)
return
err
;
err
=
cbs_av1_ref_tile_data
(
ctx
,
unit
,
&
gbc
,
&
obu
->
obu
.
tile_group
.
tile_data
);
if
(
err
<
0
)
return
err
;
}
break
;
case
AV1_OBU_FRAME
:
{
err
=
cbs_av1_read_frame_obu
(
ctx
,
&
gbc
,
&
obu
->
obu
.
frame
);
if
(
err
<
0
)
return
err
;
err
=
cbs_av1_ref_tile_data
(
ctx
,
unit
,
&
gbc
,
&
obu
->
obu
.
frame
.
tile_group
.
tile_data
);
if
(
err
<
0
)
return
err
;
}
break
;
case
AV1_OBU_TILE_LIST
:
{
err
=
cbs_av1_read_tile_list_obu
(
ctx
,
&
gbc
,
&
obu
->
obu
.
tile_list
);
if
(
err
<
0
)
return
err
;
err
=
cbs_av1_ref_tile_data
(
ctx
,
unit
,
&
gbc
,
&
obu
->
obu
.
tile_list
.
tile_data
);
if
(
err
<
0
)
return
err
;
}
break
;
case
AV1_OBU_METADATA
:
{
err
=
cbs_av1_read_metadata_obu
(
ctx
,
&
gbc
,
&
obu
->
obu
.
metadata
);
if
(
err
<
0
)
return
err
;
}
break
;
case
AV1_OBU_PADDING
:
default:
return
AVERROR
(
ENOSYS
);
}
end_pos
=
get_bits_count
(
&
gbc
);
av_assert0
(
end_pos
<=
unit
->
data_size
*
8
);
if
(
obu
->
obu_size
>
0
&&
obu
->
header
.
obu_type
!=
AV1_OBU_TILE_GROUP
&&
obu
->
header
.
obu_type
!=
AV1_OBU_FRAME
)
{
err
=
cbs_av1_read_trailing_bits
(
ctx
,
&
gbc
,
obu
->
obu_size
*
8
+
start_pos
-
end_pos
);
if
(
err
<
0
)
return
err
;
}
return
0
;
}
static
int
cbs_av1_write_obu
(
CodedBitstreamContext
*
ctx
,
CodedBitstreamUnit
*
unit
,
PutBitContext
*
pbc
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
AV1RawOBU
*
obu
=
unit
->
content
;
PutBitContext
pbc_tmp
;
AV1RawTileData
*
td
;
size_t
header_size
;
int
err
,
start_pos
,
end_pos
,
data_pos
;
// OBUs in the normal bitstream format must contain a size field
// in every OBU (in annex B it is optional, but we don't support
// writing that).
obu
->
header
.
obu_has_size_field
=
1
;
err
=
cbs_av1_write_obu_header
(
ctx
,
pbc
,
&
obu
->
header
);
if
(
err
<
0
)
return
err
;
if
(
obu
->
header
.
obu_has_size_field
)
{
pbc_tmp
=
*
pbc
;
// Add space for the size field to fill later.
put_bits32
(
pbc
,
0
);
put_bits32
(
pbc
,
0
);
}
td
=
NULL
;
start_pos
=
put_bits_count
(
pbc
);
switch
(
obu
->
header
.
obu_type
)
{
case
AV1_OBU_SEQUENCE_HEADER
:
{
err
=
cbs_av1_write_sequence_header_obu
(
ctx
,
pbc
,
&
obu
->
obu
.
sequence_header
);
if
(
err
<
0
)
return
err
;
av_buffer_unref
(
&
priv
->
sequence_header_ref
);
priv
->
sequence_header
=
NULL
;
priv
->
sequence_header_ref
=
av_buffer_ref
(
unit
->
content_ref
);
if
(
!
priv
->
sequence_header_ref
)
return
AVERROR
(
ENOMEM
);
priv
->
sequence_header
=
&
obu
->
obu
.
sequence_header
;
}
break
;
case
AV1_OBU_TEMPORAL_DELIMITER
:
{
err
=
cbs_av1_write_temporal_delimiter_obu
(
ctx
,
pbc
);
if
(
err
<
0
)
return
err
;
}
break
;
case
AV1_OBU_FRAME_HEADER
:
case
AV1_OBU_REDUNDANT_FRAME_HEADER
:
{
err
=
cbs_av1_write_frame_header_obu
(
ctx
,
pbc
,
&
obu
->
obu
.
frame_header
);
if
(
err
<
0
)
return
err
;
}
break
;
case
AV1_OBU_TILE_GROUP
:
{
err
=
cbs_av1_write_tile_group_obu
(
ctx
,
pbc
,
&
obu
->
obu
.
tile_group
);
if
(
err
<
0
)
return
err
;
td
=
&
obu
->
obu
.
tile_group
.
tile_data
;
}
break
;
case
AV1_OBU_FRAME
:
{
err
=
cbs_av1_write_frame_obu
(
ctx
,
pbc
,
&
obu
->
obu
.
frame
);
if
(
err
<
0
)
return
err
;
td
=
&
obu
->
obu
.
frame
.
tile_group
.
tile_data
;
}
break
;
case
AV1_OBU_TILE_LIST
:
{
err
=
cbs_av1_write_tile_list_obu
(
ctx
,
pbc
,
&
obu
->
obu
.
tile_list
);
if
(
err
<
0
)
return
err
;
td
=
&
obu
->
obu
.
tile_list
.
tile_data
;
}
break
;
case
AV1_OBU_METADATA
:
{
err
=
cbs_av1_write_metadata_obu
(
ctx
,
pbc
,
&
obu
->
obu
.
metadata
);
if
(
err
<
0
)
return
err
;
}
break
;
case
AV1_OBU_PADDING
:
default:
return
AVERROR
(
ENOSYS
);
}
end_pos
=
put_bits_count
(
pbc
);
header_size
=
(
end_pos
-
start_pos
+
7
)
/
8
;
if
(
td
)
{
obu
->
obu_size
=
header_size
+
td
->
data_size
;
}
else
if
(
header_size
>
0
)
{
// Add trailing bits and recalculate.
err
=
cbs_av1_write_trailing_bits
(
ctx
,
pbc
,
8
-
end_pos
%
8
);
if
(
err
<
0
)
return
err
;
end_pos
=
put_bits_count
(
pbc
);
obu
->
obu_size
=
(
end_pos
-
start_pos
+
7
)
/
8
;
}
else
{
// Empty OBU.
obu
->
obu_size
=
0
;
}
end_pos
=
put_bits_count
(
pbc
);
// Must now be byte-aligned.
av_assert0
(
end_pos
%
8
==
0
);
flush_put_bits
(
pbc
);
start_pos
/=
8
;
end_pos
/=
8
;
*
pbc
=
pbc_tmp
;
err
=
cbs_av1_write_leb128
(
ctx
,
pbc
,
"obu_size"
,
obu
->
obu_size
);
if
(
err
<
0
)
return
err
;
data_pos
=
put_bits_count
(
pbc
)
/
8
;
flush_put_bits
(
pbc
);
av_assert0
(
data_pos
<=
start_pos
);
if
(
8
*
obu
->
obu_size
>
put_bits_left
(
pbc
))
return
AVERROR
(
ENOSPC
);
if
(
obu
->
obu_size
>
0
)
{
memmove
(
priv
->
write_buffer
+
data_pos
,
priv
->
write_buffer
+
start_pos
,
header_size
);
skip_put_bytes
(
pbc
,
header_size
);
if
(
td
)
{
memcpy
(
priv
->
write_buffer
+
data_pos
+
header_size
,
td
->
data
,
td
->
data_size
);
skip_put_bytes
(
pbc
,
td
->
data_size
);
}
}
return
0
;
}
static
int
cbs_av1_write_unit
(
CodedBitstreamContext
*
ctx
,
CodedBitstreamUnit
*
unit
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
PutBitContext
pbc
;
int
err
;
if
(
!
priv
->
write_buffer
)
{
// Initial write buffer size is 1MB.
priv
->
write_buffer_size
=
1024
*
1024
;
reallocate_and_try_again:
err
=
av_reallocp
(
&
priv
->
write_buffer
,
priv
->
write_buffer_size
);
if
(
err
<
0
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Unable to allocate a "
"sufficiently large write buffer (last attempt "
"%zu bytes).
\n
"
,
priv
->
write_buffer_size
);
return
err
;
}
}
init_put_bits
(
&
pbc
,
priv
->
write_buffer
,
priv
->
write_buffer_size
);
err
=
cbs_av1_write_obu
(
ctx
,
unit
,
&
pbc
);
if
(
err
==
AVERROR
(
ENOSPC
))
{
// Overflow.
priv
->
write_buffer_size
*=
2
;
goto
reallocate_and_try_again
;
}
if
(
err
<
0
)
return
err
;
// Overflow but we didn't notice.
av_assert0
(
put_bits_count
(
&
pbc
)
<=
8
*
priv
->
write_buffer_size
);
// OBU data must be byte-aligned.
av_assert0
(
put_bits_count
(
&
pbc
)
%
8
==
0
);
unit
->
data_size
=
put_bits_count
(
&
pbc
)
/
8
;
flush_put_bits
(
&
pbc
);
err
=
ff_cbs_alloc_unit_data
(
ctx
,
unit
,
unit
->
data_size
);
if
(
err
<
0
)
return
err
;
memcpy
(
unit
->
data
,
priv
->
write_buffer
,
unit
->
data_size
);
return
0
;
}
static
int
cbs_av1_assemble_fragment
(
CodedBitstreamContext
*
ctx
,
CodedBitstreamFragment
*
frag
)
{
size_t
size
,
pos
;
int
i
;
size
=
0
;
for
(
i
=
0
;
i
<
frag
->
nb_units
;
i
++
)
size
+=
frag
->
units
[
i
].
data_size
;
frag
->
data_ref
=
av_buffer_alloc
(
size
+
AV_INPUT_BUFFER_PADDING_SIZE
);
if
(
!
frag
->
data_ref
)
return
AVERROR
(
ENOMEM
);
frag
->
data
=
frag
->
data_ref
->
data
;
memset
(
frag
->
data
+
size
,
0
,
AV_INPUT_BUFFER_PADDING_SIZE
);
pos
=
0
;
for
(
i
=
0
;
i
<
frag
->
nb_units
;
i
++
)
{
memcpy
(
frag
->
data
+
pos
,
frag
->
units
[
i
].
data
,
frag
->
units
[
i
].
data_size
);
pos
+=
frag
->
units
[
i
].
data_size
;
}
av_assert0
(
pos
==
size
);
frag
->
data_size
=
size
;
return
0
;
}
static
void
cbs_av1_close
(
CodedBitstreamContext
*
ctx
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
av_buffer_unref
(
&
priv
->
sequence_header_ref
);
av_freep
(
&
priv
->
write_buffer
);
}
const
CodedBitstreamType
ff_cbs_type_av1
=
{
.
codec_id
=
AV_CODEC_ID_AV1
,
.
priv_data_size
=
sizeof
(
CodedBitstreamAV1Context
),
.
split_fragment
=
&
cbs_av1_split_fragment
,
.
read_unit
=
&
cbs_av1_read_unit
,
.
write_unit
=
&
cbs_av1_write_unit
,
.
assemble_fragment
=
&
cbs_av1_assemble_fragment
,
.
close
=
&
cbs_av1_close
,
};
libavcodec/cbs_av1.h
0 → 100644
View file @
c8c81ac5
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_CBS_AV1_H
#define AVCODEC_CBS_AV1_H
#include <stddef.h>
#include <stdint.h>
#include "av1.h"
#include "cbs.h"
typedef
struct
AV1RawOBUHeader
{
uint8_t
obu_forbidden_bit
;
uint8_t
obu_type
;
uint8_t
obu_extension_flag
;
uint8_t
obu_has_size_field
;
uint8_t
obu_reserved_1bit
;
uint8_t
temporal_id
;
uint8_t
spatial_id
;
uint8_t
extension_header_reserved_3bits
;
}
AV1RawOBUHeader
;
typedef
struct
AV1RawColorConfig
{
uint8_t
high_bitdepth
;
uint8_t
twelve_bit
;
uint8_t
mono_chrome
;
uint8_t
color_description_present_flag
;
uint8_t
color_primaries
;
uint8_t
transfer_characteristics
;
uint8_t
matrix_coefficients
;
uint8_t
color_range
;
uint8_t
subsampling_x
;
uint8_t
subsampling_y
;
uint8_t
chroma_sample_position
;
uint8_t
separate_uv_delta_q
;
}
AV1RawColorConfig
;
typedef
struct
AV1RawTimingInfo
{
uint32_t
num_units_in_display_tick
;
uint32_t
time_scale
;
uint8_t
equal_picture_interval
;
uint32_t
num_ticks_per_picture_minus_1
;
}
AV1RawTimingInfo
;
typedef
struct
AV1RawDecoderModelInfo
{
uint8_t
buffer_delay_length_minus_1
;
uint32_t
num_units_in_decoding_tick
;
uint8_t
buffer_removal_time_length_minus_1
;
uint8_t
frame_presentation_time_length_minus_1
;
}
AV1RawDecoderModelInfo
;
typedef
struct
AV1RawSequenceHeader
{
uint8_t
seq_profile
;
uint8_t
still_picture
;
uint8_t
reduced_still_picture_header
;
uint8_t
timing_info_present_flag
;
uint8_t
decoder_model_info_present_flag
;
uint8_t
initial_display_delay_present_flag
;
uint8_t
operating_points_cnt_minus_1
;
AV1RawTimingInfo
timing_info
;
AV1RawDecoderModelInfo
decoder_model_info
;
uint16_t
operating_point_idc
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
seq_level_idx
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
seq_tier
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
decoder_model_present_for_this_op
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
decoder_buffer_delay
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
encoder_buffer_delay
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
low_delay_mode_flag
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
initial_display_delay_present_for_this_op
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
initial_display_delay_minus_1
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
frame_width_bits_minus_1
;
uint8_t
frame_height_bits_minus_1
;
uint16_t
max_frame_width_minus_1
;
uint16_t
max_frame_height_minus_1
;
uint8_t
frame_id_numbers_present_flag
;
uint8_t
delta_frame_id_length_minus_2
;
uint8_t
additional_frame_id_length_minus_1
;
uint8_t
use_128x128_superblock
;
uint8_t
enable_filter_intra
;
uint8_t
enable_intra_edge_filter
;
uint8_t
enable_intraintra_compound
;
uint8_t
enable_masked_compound
;
uint8_t
enable_warped_motion
;
uint8_t
enable_dual_filter
;
uint8_t
enable_order_hint
;
uint8_t
enable_jnt_comp
;
uint8_t
enable_ref_frame_mvs
;
uint8_t
seq_choose_screen_content_tools
;
uint8_t
seq_force_screen_content_tools
;
uint8_t
seq_choose_integer_mv
;
uint8_t
seq_force_integer_mv
;
uint8_t
order_hint_bits_minus_1
;
uint8_t
enable_superres
;
uint8_t
enable_cdef
;
uint8_t
enable_restoration
;
AV1RawColorConfig
color_config
;
uint8_t
film_grain_params_present
;
}
AV1RawSequenceHeader
;
typedef
struct
AV1RawFrameHeader
{
uint8_t
show_existing_frame
;
uint8_t
frame_to_show_map_idx
;
uint32_t
frame_presentation_time
;
uint32_t
display_frame_id
;
uint8_t
frame_type
;
uint8_t
show_frame
;
uint8_t
showable_frame
;
uint8_t
error_resilient_mode
;
uint8_t
disable_cdf_update
;
uint8_t
allow_screen_content_tools
;
uint8_t
force_integer_mv
;
uint32_t
current_frame_id
;
uint8_t
frame_size_override_flag
;
uint8_t
order_hint
;
uint8_t
buffer_removal_time_present_flag
;
uint32_t
buffer_removal_time
[
AV1_MAX_OPERATING_POINTS
];
uint8_t
primary_ref_frame
;
uint16_t
frame_width_minus_1
;
uint16_t
frame_height_minus_1
;
uint8_t
use_superres
;
uint8_t
coded_denom
;
uint8_t
render_and_frame_size_different
;
uint8_t
render_width_minus_1
;
uint8_t
render_height_minus_1
;
uint8_t
found_ref
;
uint8_t
refresh_frame_flags
;
uint8_t
allow_intrabc
;
uint8_t
ref_order_hint
[
AV1_NUM_REF_FRAMES
];
uint8_t
frame_refs_short_signaling
;
uint8_t
last_frame_idx
;
uint8_t
golden_frame_idx
;
int8_t
ref_frame_idx
[
AV1_REFS_PER_FRAME
];
uint8_t
delta_frame_id_minus1
;
uint8_t
allow_high_precision_mv
;
uint8_t
is_filter_switchable
;
uint8_t
interpolation_filter
;
uint8_t
is_motion_mode_switchable
;
uint8_t
use_ref_frame_mvs
;
uint8_t
disable_frame_end_update_cdf
;
uint8_t
uniform_tile_spacing_flag
;
uint8_t
tile_cols_log2
;
uint8_t
tile_rows_log2
;
uint8_t
width_in_sbs_minus_1
[
AV1_MAX_TILE_COLS
];
uint8_t
height_in_sbs_minus_1
[
AV1_MAX_TILE_ROWS
];
uint16_t
context_update_tile_id
;
uint8_t
tile_size_bytes_minus1
;
// These are derived values, but it's very unhelpful to have to
// recalculate them all the time so we store them here.
uint16_t
tile_cols
;
uint16_t
tile_rows
;
uint8_t
base_q_idx
;
int8_t
delta_q_y_dc
;
uint8_t
diff_uv_delta
;
int8_t
delta_q_u_dc
;
int8_t
delta_q_u_ac
;
int8_t
delta_q_v_dc
;
int8_t
delta_q_v_ac
;
uint8_t
using_qmatrix
;
uint8_t
qm_y
;
uint8_t
qm_u
;
uint8_t
qm_v
;
uint8_t
segmentation_enabled
;
uint8_t
segmentation_update_map
;
uint8_t
segmentation_temporal_update
;
uint8_t
segmentation_update_data
;
uint8_t
feature_enabled
[
AV1_MAX_SEGMENTS
][
AV1_SEG_LVL_MAX
];
uint8_t
feature_value
[
AV1_MAX_SEGMENTS
][
AV1_SEG_LVL_MAX
];
uint8_t
delta_q_present
;
uint8_t
delta_q_res
;
uint8_t
delta_lf_present
;
uint8_t
delta_lf_res
;
uint8_t
delta_lf_multi
;
uint8_t
loop_filter_level
[
4
];
uint8_t
loop_filter_sharpness
;
uint8_t
loop_filter_delta_enabled
;
uint8_t
loop_filter_delta_update
;
uint8_t
update_ref_delta
[
AV1_TOTAL_REFS_PER_FRAME
];
int8_t
loop_filter_ref_deltas
[
AV1_TOTAL_REFS_PER_FRAME
];
uint8_t
update_mode_delta
[
2
];
int8_t
loop_filter_mode_deltas
[
2
];
uint8_t
cdef_damping_minus_3
;
uint8_t
cdef_bits
;
uint8_t
cdef_y_pri_strength
[
8
];
uint8_t
cdef_y_sec_strength
[
8
];
uint8_t
cdef_uv_pri_strength
[
8
];
uint8_t
cdef_uv_sec_strength
[
8
];
uint8_t
lr_type
[
3
];
uint8_t
lr_unit_shift
;
uint8_t
lr_uv_shift
;
uint8_t
tx_mode
;
uint8_t
reference_select
;
uint8_t
skip_mode_present
;
uint8_t
allow_warped_motion
;
uint8_t
reduced_tx_set
;
uint8_t
is_global
[
AV1_TOTAL_REFS_PER_FRAME
];
uint8_t
is_rot_zoom
[
AV1_TOTAL_REFS_PER_FRAME
];
uint8_t
is_translation
[
AV1_TOTAL_REFS_PER_FRAME
];
//AV1RawSubexp gm_params[AV1_TOTAL_REFS_PER_FRAME][6];
uint32_t
gm_params
[
AV1_TOTAL_REFS_PER_FRAME
][
6
];
uint8_t
apply_grain
;
uint16_t
grain_seed
;
uint8_t
update_grain
;
uint8_t
film_grain_params_ref_idx
;
uint8_t
num_y_points
;
uint8_t
point_y_value
[
16
];
uint8_t
point_y_scaling
[
16
];
uint8_t
chroma_scaling_from_luma
;
uint8_t
num_cb_points
;
uint8_t
point_cb_value
[
16
];
uint8_t
point_cb_scaling
[
16
];
uint8_t
num_cr_points
;
uint8_t
point_cr_value
[
16
];
uint8_t
point_cr_scaling
[
16
];
uint8_t
grain_scaling_minus_8
;
uint8_t
ar_coeff_lag
;
uint8_t
ar_coeffs_y_plus_128
[
24
];
uint8_t
ar_coeffs_cb_plus_128
[
24
];
uint8_t
ar_coeffs_cr_plus_128
[
24
];
uint8_t
ar_coeff_shift_minus_6
;
uint8_t
grain_scale_shift
;
uint8_t
cb_mult
;
uint8_t
cb_luma_mult
;
uint16_t
cb_offset
;
uint8_t
cr_mult
;
uint8_t
cr_luma_mult
;
uint16_t
cr_offset
;
uint8_t
overlap_flag
;
uint8_t
clip_to_restricted_range
;
}
AV1RawFrameHeader
;
typedef
struct
AV1RawTileData
{
uint8_t
*
data
;
size_t
data_size
;
AVBufferRef
*
data_ref
;
}
AV1RawTileData
;
typedef
struct
AV1RawTileGroup
{
uint8_t
tile_start_and_end_present_flag
;
uint16_t
tg_start
;
uint16_t
tg_end
;
AV1RawTileData
tile_data
;
}
AV1RawTileGroup
;
typedef
struct
AV1RawFrame
{
AV1RawFrameHeader
header
;
AV1RawTileGroup
tile_group
;
}
AV1RawFrame
;
typedef
struct
AV1RawTileList
{
uint8_t
output_frame_width_in_tiles_minus_1
;
uint8_t
output_frame_height_in_tiles_minus_1
;
uint16_t
tile_count_minus_1
;
AV1RawTileData
tile_data
;
}
AV1RawTileList
;
typedef
struct
AV1RawMetadataHDRCLL
{
uint16_t
max_cll
;
uint16_t
max_fall
;
}
AV1RawMetadataHDRCLL
;
typedef
struct
AV1RawMetadataHDRMDCV
{
uint16_t
primary_chromaticity_x
[
3
];
uint16_t
primary_chromaticity_y
[
3
];
uint16_t
white_point_chromaticity_x
;
uint16_t
white_point_chromaticity_y
;
uint32_t
luminance_max
;
uint32_t
luminance_min
;
}
AV1RawMetadataHDRMDCV
;
typedef
struct
AV1RawMetadataScalability
{
uint8_t
scalability_mode_idc
;
// TODO: more stuff.
}
AV1RawMetadataScalability
;
typedef
struct
AV1RawMetadataITUTT35
{
uint8_t
itu_t_t35_country_code
;
uint8_t
itu_t_t35_country_code_extension_byte
;
uint8_t
*
payload
;
size_t
payload_size
;
AVBufferRef
*
payload_ref
;
}
AV1RawMetadataITUTT35
;
typedef
struct
AV1RawMetadataTimecode
{
uint8_t
counting_type
;
uint8_t
full_timestamp_flag
;
uint8_t
discontinuity_flag
;
uint8_t
cnt_dropped_flag
;
uint16_t
n_frames
;
uint8_t
seconds_value
;
uint8_t
minutes_value
;
uint8_t
hours_value
;
uint8_t
seconds_flag
;
uint8_t
minutes_flag
;
uint8_t
hours_flag
;
uint8_t
time_offset_length
;
uint32_t
time_offset_value
;
}
AV1RawMetadataTimecode
;
typedef
struct
AV1RawMetadata
{
uint64_t
metadata_type
;
union
{
AV1RawMetadataHDRCLL
hdr_cll
;
AV1RawMetadataHDRMDCV
hdr_mdcv
;
AV1RawMetadataScalability
scalability
;
AV1RawMetadataITUTT35
itut_t35
;
AV1RawMetadataTimecode
timecode
;
}
metadata
;
}
AV1RawMetadata
;
typedef
struct
AV1RawOBU
{
AV1RawOBUHeader
header
;
size_t
obu_size
;
union
{
AV1RawSequenceHeader
sequence_header
;
AV1RawFrameHeader
frame_header
;
AV1RawFrame
frame
;
AV1RawTileGroup
tile_group
;
AV1RawTileList
tile_list
;
AV1RawMetadata
metadata
;
}
obu
;
}
AV1RawOBU
;
typedef
struct
AV1ReferenceFrameState
{
int
valid
;
// RefValid
int
frame_id
;
// RefFrameId
int
upscaled_width
;
// RefUpscaledWidth
int
frame_width
;
// RefFrameWidth
int
frame_height
;
// RefFrameHeight
int
render_width
;
// RefRenderWidth
int
render_height
;
// RefRenderHeight
int
frame_type
;
// RefFrameType
int
subsampling_x
;
// RefSubsamplingX
int
subsampling_y
;
// RefSubsamplingY
int
bit_depth
;
// RefBitDepth
int
order_hint
;
// RefOrderHint
}
AV1ReferenceFrameState
;
typedef
struct
CodedBitstreamAV1Context
{
AV1RawSequenceHeader
*
sequence_header
;
AVBufferRef
*
sequence_header_ref
;
int
seen_frame_header
;
int
temporal_id
;
int
spatial_id
;
int
operating_point_idc
;
int
bit_depth
;
int
frame_width
;
int
frame_height
;
int
upscaled_width
;
int
render_width
;
int
render_height
;
int
num_planes
;
int
coded_lossless
;
int
all_lossless
;
int
tile_cols
;
int
tile_rows
;
AV1ReferenceFrameState
ref
[
AV1_NUM_REF_FRAMES
];
// Write buffer.
uint8_t
*
write_buffer
;
size_t
write_buffer_size
;
}
CodedBitstreamAV1Context
;
#endif
/* AVCODEC_CBS_AV1_H */
libavcodec/cbs_av1_syntax_template.c
0 → 100644
View file @
c8c81ac5
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
static
int
FUNC
(
obu_header
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawOBUHeader
*
current
)
{
int
err
;
av_unused
int
zero
=
0
;
HEADER
(
"OBU header"
);
fc
(
1
,
obu_forbidden_bit
,
0
,
0
);
fc
(
4
,
obu_type
,
0
,
AV1_OBU_PADDING
);
flag
(
obu_extension_flag
);
flag
(
obu_has_size_field
);
fc
(
1
,
obu_reserved_1bit
,
0
,
0
);
if
(
current
->
obu_extension_flag
)
{
fb
(
3
,
temporal_id
);
fb
(
2
,
spatial_id
);
fc
(
3
,
extension_header_reserved_3bits
,
0
,
0
);
}
return
0
;
}
static
int
FUNC
(
trailing_bits
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
int
nb_bits
)
{
int
err
;
av_assert0
(
nb_bits
>
0
);
fixed
(
1
,
trailing_one_bit
,
1
);
--
nb_bits
;
while
(
nb_bits
>
0
)
{
fixed
(
1
,
trailing_zero_bit
,
0
);
--
nb_bits
;
}
return
0
;
}
static
int
FUNC
(
byte_alignment
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
)
{
int
err
;
while
(
byte_alignment
(
rw
)
!=
0
)
fixed
(
1
,
zero_bit
,
0
);
return
0
;
}
static
int
FUNC
(
color_config
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawColorConfig
*
current
,
int
seq_profile
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
int
err
;
flag
(
high_bitdepth
);
if
(
seq_profile
==
FF_PROFILE_AV1_PROFESSIONAL
&&
current
->
high_bitdepth
)
{
flag
(
twelve_bit
);
priv
->
bit_depth
=
current
->
twelve_bit
?
12
:
10
;
}
else
{
priv
->
bit_depth
=
current
->
high_bitdepth
?
10
:
8
;
}
if
(
seq_profile
==
FF_PROFILE_AV1_HIGH
)
infer
(
mono_chrome
,
0
);
else
flag
(
mono_chrome
);
priv
->
num_planes
=
current
->
mono_chrome
?
1
:
3
;
flag
(
color_description_present_flag
);
if
(
current
->
color_description_present_flag
)
{
fb
(
8
,
color_primaries
);
fb
(
8
,
transfer_characteristics
);
fb
(
8
,
matrix_coefficients
);
}
else
{
infer
(
color_primaries
,
AVCOL_PRI_UNSPECIFIED
);
infer
(
transfer_characteristics
,
AVCOL_TRC_UNSPECIFIED
);
infer
(
matrix_coefficients
,
AVCOL_SPC_UNSPECIFIED
);
}
if
(
current
->
mono_chrome
)
{
flag
(
color_range
);
infer
(
subsampling_x
,
1
);
infer
(
subsampling_y
,
1
);
infer
(
chroma_sample_position
,
AV1_CSP_UNKNOWN
);
infer
(
separate_uv_delta_q
,
0
);
}
else
if
(
current
->
color_primaries
==
AVCOL_PRI_BT709
&&
current
->
transfer_characteristics
==
AVCOL_TRC_IEC61966_2_1
&&
current
->
matrix_coefficients
==
AVCOL_SPC_RGB
)
{
infer
(
color_range
,
1
);
infer
(
subsampling_x
,
0
);
infer
(
subsampling_y
,
0
);
flag
(
separate_uv_delta_q
);
}
else
{
flag
(
color_range
);
if
(
seq_profile
==
FF_PROFILE_AV1_MAIN
)
{
infer
(
subsampling_x
,
1
);
infer
(
subsampling_y
,
1
);
}
else
if
(
seq_profile
==
FF_PROFILE_AV1_HIGH
)
{
infer
(
subsampling_x
,
0
);
infer
(
subsampling_y
,
0
);
}
else
{
if
(
priv
->
bit_depth
==
12
)
{
fb
(
1
,
subsampling_x
);
if
(
current
->
subsampling_x
)
fb
(
1
,
subsampling_y
);
else
infer
(
subsampling_y
,
0
);
}
else
{
infer
(
subsampling_x
,
1
);
infer
(
subsampling_y
,
0
);
}
}
if
(
current
->
subsampling_x
&&
current
->
subsampling_y
)
{
fc
(
2
,
chroma_sample_position
,
AV1_CSP_UNKNOWN
,
AV1_CSP_COLOCATED
);
}
flag
(
separate_uv_delta_q
);
}
return
0
;
}
static
int
FUNC
(
timing_info
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawTimingInfo
*
current
)
{
int
err
;
fc
(
32
,
num_units_in_display_tick
,
1
,
MAX_UINT_BITS
(
32
));
fc
(
32
,
time_scale
,
1
,
MAX_UINT_BITS
(
32
));
flag
(
equal_picture_interval
);
if
(
current
->
equal_picture_interval
)
uvlc
(
num_ticks_per_picture_minus_1
,
0
,
MAX_UINT_BITS
(
32
)
-
1
);
return
0
;
}
static
int
FUNC
(
decoder_model_info
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawDecoderModelInfo
*
current
)
{
int
err
;
fb
(
5
,
buffer_delay_length_minus_1
);
fb
(
32
,
num_units_in_decoding_tick
);
fb
(
5
,
buffer_removal_time_length_minus_1
);
fb
(
5
,
frame_presentation_time_length_minus_1
);
return
0
;
}
static
int
FUNC
(
sequence_header_obu
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawSequenceHeader
*
current
)
{
int
i
,
err
;
HEADER
(
"Sequence Header"
);
fc
(
3
,
seq_profile
,
FF_PROFILE_AV1_MAIN
,
FF_PROFILE_AV1_PROFESSIONAL
);
flag
(
still_picture
);
flag
(
reduced_still_picture_header
);
if
(
current
->
reduced_still_picture_header
)
{
infer
(
timing_info_present_flag
,
0
);
infer
(
decoder_model_info_present_flag
,
0
);
infer
(
initial_display_delay_present_flag
,
0
);
infer
(
operating_points_cnt_minus_1
,
0
);
infer
(
operating_point_idc
[
0
],
0
);
fb
(
5
,
seq_level_idx
[
0
]);
infer
(
seq_tier
[
0
],
0
);
infer
(
decoder_model_present_for_this_op
[
0
],
0
);
infer
(
initial_display_delay_present_for_this_op
[
0
],
0
);
}
else
{
flag
(
timing_info_present_flag
);
if
(
current
->
timing_info_present_flag
)
{
CHECK
(
FUNC
(
timing_info
)(
ctx
,
rw
,
&
current
->
timing_info
));
flag
(
decoder_model_info_present_flag
);
if
(
current
->
decoder_model_info_present_flag
)
{
CHECK
(
FUNC
(
decoder_model_info
)
(
ctx
,
rw
,
&
current
->
decoder_model_info
));
}
}
else
{
infer
(
decoder_model_info_present_flag
,
0
);
}
flag
(
initial_display_delay_present_flag
);
fb
(
5
,
operating_points_cnt_minus_1
);
for
(
i
=
0
;
i
<=
current
->
operating_points_cnt_minus_1
;
i
++
)
{
fbs
(
12
,
operating_point_idc
[
i
],
1
,
i
);
fbs
(
5
,
seq_level_idx
[
i
],
1
,
i
);
if
(
current
->
seq_level_idx
[
i
]
>
7
)
flags
(
seq_tier
[
i
],
1
,
i
);
else
infer
(
seq_tier
[
i
],
0
);
if
(
current
->
decoder_model_info_present_flag
)
{
flags
(
decoder_model_present_for_this_op
[
i
],
1
,
i
);
if
(
current
->
decoder_model_present_for_this_op
[
i
])
{
int
n
=
current
->
decoder_model_info
.
buffer_delay_length_minus_1
+
1
;
fbs
(
n
,
decoder_buffer_delay
[
i
],
1
,
i
);
fbs
(
n
,
encoder_buffer_delay
[
i
],
1
,
i
);
flags
(
low_delay_mode_flag
[
i
],
1
,
i
);
}
}
else
{
infer
(
decoder_model_present_for_this_op
[
i
],
0
);
}
if
(
current
->
initial_display_delay_present_flag
)
{
flags
(
initial_display_delay_present_for_this_op
[
i
],
1
,
i
);
if
(
current
->
initial_display_delay_present_for_this_op
[
i
])
fbs
(
4
,
initial_display_delay_minus_1
[
i
],
1
,
i
);
}
}
}
fb
(
4
,
frame_width_bits_minus_1
);
fb
(
4
,
frame_height_bits_minus_1
);
fb
(
current
->
frame_width_bits_minus_1
+
1
,
max_frame_width_minus_1
);
fb
(
current
->
frame_height_bits_minus_1
+
1
,
max_frame_height_minus_1
);
if
(
current
->
reduced_still_picture_header
)
infer
(
frame_id_numbers_present_flag
,
0
);
else
flag
(
frame_id_numbers_present_flag
);
if
(
current
->
frame_id_numbers_present_flag
)
{
fb
(
4
,
delta_frame_id_length_minus_2
);
fb
(
3
,
additional_frame_id_length_minus_1
);
}
flag
(
use_128x128_superblock
);
flag
(
enable_filter_intra
);
flag
(
enable_intra_edge_filter
);
if
(
current
->
reduced_still_picture_header
)
{
infer
(
enable_intraintra_compound
,
0
);
infer
(
enable_masked_compound
,
0
);
infer
(
enable_warped_motion
,
0
);
infer
(
enable_dual_filter
,
0
);
infer
(
enable_order_hint
,
0
);
infer
(
enable_jnt_comp
,
0
);
infer
(
enable_ref_frame_mvs
,
0
);
infer
(
seq_force_screen_content_tools
,
AV1_SELECT_SCREEN_CONTENT_TOOLS
);
infer
(
seq_force_integer_mv
,
AV1_SELECT_INTEGER_MV
);
}
else
{
flag
(
enable_intraintra_compound
);
flag
(
enable_masked_compound
);
flag
(
enable_warped_motion
);
flag
(
enable_dual_filter
);
flag
(
enable_order_hint
);
if
(
current
->
enable_order_hint
)
{
flag
(
enable_jnt_comp
);
flag
(
enable_ref_frame_mvs
);
}
else
{
infer
(
enable_jnt_comp
,
0
);
infer
(
enable_ref_frame_mvs
,
0
);
}
flag
(
seq_choose_screen_content_tools
);
if
(
current
->
seq_choose_screen_content_tools
)
infer
(
seq_force_screen_content_tools
,
AV1_SELECT_SCREEN_CONTENT_TOOLS
);
else
fb
(
1
,
seq_force_screen_content_tools
);
if
(
current
->
seq_force_screen_content_tools
>
0
)
{
flag
(
seq_choose_integer_mv
);
if
(
current
->
seq_choose_integer_mv
)
infer
(
seq_force_integer_mv
,
AV1_SELECT_INTEGER_MV
);
else
fb
(
1
,
seq_force_integer_mv
);
}
else
{
infer
(
seq_force_integer_mv
,
AV1_SELECT_INTEGER_MV
);
}
if
(
current
->
enable_order_hint
)
fb
(
3
,
order_hint_bits_minus_1
);
}
flag
(
enable_superres
);
flag
(
enable_cdef
);
flag
(
enable_restoration
);
CHECK
(
FUNC
(
color_config
)(
ctx
,
rw
,
&
current
->
color_config
,
current
->
seq_profile
));
flag
(
film_grain_params_present
);
return
0
;
}
static
int
FUNC
(
temporal_delimiter_obu
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
HEADER
(
"Temporal Delimiter"
);
priv
->
seen_frame_header
=
0
;
return
0
;
}
static
int
FUNC
(
superres_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
const
AV1RawSequenceHeader
*
seq
=
priv
->
sequence_header
;
int
denom
,
err
;
if
(
seq
->
enable_superres
)
flag
(
use_superres
);
else
infer
(
use_superres
,
0
);
if
(
current
->
use_superres
)
{
fb
(
3
,
coded_denom
);
denom
=
current
->
coded_denom
+
AV1_SUPERRES_DENOM_MIN
;
}
else
{
denom
=
AV1_SUPERRES_NUM
;
}
priv
->
upscaled_width
=
priv
->
frame_width
;
priv
->
frame_width
=
(
priv
->
upscaled_width
*
AV1_SUPERRES_NUM
+
denom
/
2
)
/
denom
;
return
0
;
}
static
int
FUNC
(
frame_size
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
const
AV1RawSequenceHeader
*
seq
=
priv
->
sequence_header
;
int
err
;
if
(
current
->
frame_size_override_flag
)
{
fb
(
seq
->
frame_width_bits_minus_1
+
1
,
frame_width_minus_1
);
fb
(
seq
->
frame_height_bits_minus_1
+
1
,
frame_height_minus_1
);
priv
->
frame_width
=
current
->
frame_width_minus_1
+
1
;
priv
->
frame_height
=
current
->
frame_height_minus_1
+
1
;
}
else
{
priv
->
frame_width
=
seq
->
max_frame_width_minus_1
+
1
;
priv
->
frame_height
=
seq
->
max_frame_height_minus_1
+
1
;
}
CHECK
(
FUNC
(
superres_params
)(
ctx
,
rw
,
current
));
return
0
;
}
static
int
FUNC
(
render_size
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
int
err
;
flag
(
render_and_frame_size_different
);
if
(
current
->
render_and_frame_size_different
)
{
fb
(
16
,
render_width_minus_1
);
fb
(
16
,
render_height_minus_1
);
priv
->
render_width
=
current
->
render_width_minus_1
+
1
;
priv
->
render_height
=
current
->
render_height_minus_1
+
1
;
}
else
{
priv
->
render_width
=
priv
->
upscaled_width
;
priv
->
render_height
=
priv
->
frame_height
;
}
return
0
;
}
static
int
FUNC
(
frame_size_with_refs
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
int
i
,
err
;
for
(
i
=
0
;
i
<
AV1_REFS_PER_FRAME
;
i
++
)
{
flag
(
found_ref
);
if
(
current
->
found_ref
)
{
AV1ReferenceFrameState
*
ref
=
&
priv
->
ref
[
current
->
ref_frame_idx
[
i
]];
if
(
!
ref
->
valid
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"Missing reference frame needed for frame size "
"(ref = %d, ref_frame_idx = %d).
\n
"
,
i
,
current
->
ref_frame_idx
[
i
]);
return
AVERROR_INVALIDDATA
;
}
priv
->
upscaled_width
=
ref
->
upscaled_width
;
priv
->
frame_width
=
ref
->
frame_width
;
priv
->
frame_height
=
ref
->
frame_height
;
priv
->
render_width
=
ref
->
render_width
;
priv
->
render_height
=
ref
->
render_height
;
break
;
}
}
if
(
current
->
found_ref
==
0
)
{
CHECK
(
FUNC
(
frame_size
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
render_size
)(
ctx
,
rw
,
current
));
}
else
{
CHECK
(
FUNC
(
superres_params
)(
ctx
,
rw
,
current
));
}
return
0
;
}
static
int
FUNC
(
interpolation_filter
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
int
err
;
flag
(
is_filter_switchable
);
if
(
current
->
is_filter_switchable
)
infer
(
interpolation_filter
,
AV1_INTERPOLATION_FILTER_SWITCHABLE
);
else
fb
(
2
,
interpolation_filter
);
return
0
;
}
static
int
FUNC
(
tile_info
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
const
AV1RawSequenceHeader
*
seq
=
priv
->
sequence_header
;
int
mi_cols
,
mi_rows
,
sb_cols
,
sb_rows
,
sb_shift
,
sb_size
;
int
max_tile_width_sb
,
max_tile_height_sb
,
max_tile_area_sb
;
int
min_log2_tile_cols
,
max_log2_tile_cols
,
max_log2_tile_rows
;
int
min_log2_tiles
,
min_log2_tile_rows
;
int
i
,
err
;
mi_cols
=
2
*
((
priv
->
frame_width
+
7
)
>>
3
);
mi_rows
=
2
*
((
priv
->
frame_height
+
7
)
>>
3
);
sb_cols
=
seq
->
use_128x128_superblock
?
((
mi_cols
+
31
)
>>
5
)
:
((
mi_cols
+
15
)
>>
4
);
sb_rows
=
seq
->
use_128x128_superblock
?
((
mi_rows
+
31
)
>>
5
)
:
((
mi_rows
+
15
)
>>
4
);
sb_shift
=
seq
->
use_128x128_superblock
?
5
:
4
;
sb_size
=
sb_shift
+
2
;
max_tile_width_sb
=
AV1_MAX_TILE_WIDTH
>>
sb_size
;
max_tile_area_sb
=
AV1_MAX_TILE_AREA
>>
(
2
*
sb_size
);
min_log2_tile_cols
=
cbs_av1_tile_log2
(
max_tile_width_sb
,
sb_cols
);
max_log2_tile_cols
=
cbs_av1_tile_log2
(
1
,
FFMIN
(
sb_cols
,
AV1_MAX_TILE_COLS
));
max_log2_tile_rows
=
cbs_av1_tile_log2
(
1
,
FFMIN
(
sb_rows
,
AV1_MAX_TILE_ROWS
));
min_log2_tiles
=
FFMAX
(
min_log2_tile_cols
,
cbs_av1_tile_log2
(
max_tile_area_sb
,
sb_rows
*
sb_cols
));
flag
(
uniform_tile_spacing_flag
);
if
(
current
->
uniform_tile_spacing_flag
)
{
int
tile_width_sb
,
tile_height_sb
;
increment
(
tile_cols_log2
,
min_log2_tile_cols
,
max_log2_tile_cols
);
tile_width_sb
=
(
sb_cols
+
(
1
<<
current
->
tile_cols_log2
)
-
1
)
>>
current
->
tile_cols_log2
;
current
->
tile_cols
=
(
sb_cols
+
tile_width_sb
-
1
)
/
tile_width_sb
;
min_log2_tile_rows
=
FFMAX
(
min_log2_tiles
-
current
->
tile_cols_log2
,
0
);
increment
(
tile_rows_log2
,
min_log2_tile_rows
,
max_log2_tile_rows
);
tile_height_sb
=
(
sb_rows
+
(
1
<<
current
->
tile_rows_log2
)
-
1
)
>>
current
->
tile_rows_log2
;
current
->
tile_rows
=
(
sb_rows
+
tile_height_sb
-
1
)
/
tile_height_sb
;
}
else
{
int
widest_tile_sb
,
start_sb
,
size_sb
,
max_width
,
max_height
;
widest_tile_sb
=
0
;
start_sb
=
0
;
for
(
i
=
0
;
start_sb
<
sb_cols
&&
i
<
AV1_MAX_TILE_COLS
;
i
++
)
{
max_width
=
FFMIN
(
sb_cols
-
start_sb
,
max_tile_width_sb
);
ns
(
max_width
,
width_in_sbs_minus_1
[
i
],
1
,
i
);
size_sb
=
current
->
width_in_sbs_minus_1
[
i
]
+
1
;
widest_tile_sb
=
FFMAX
(
size_sb
,
widest_tile_sb
);
start_sb
+=
size_sb
;
}
current
->
tile_cols_log2
=
cbs_av1_tile_log2
(
1
,
i
);
current
->
tile_cols
=
i
;
if
(
min_log2_tiles
>
0
)
max_tile_area_sb
=
(
sb_rows
*
sb_cols
)
>>
(
min_log2_tiles
+
1
);
else
max_tile_area_sb
=
sb_rows
*
sb_cols
;
max_tile_height_sb
=
FFMAX
(
max_tile_area_sb
/
widest_tile_sb
,
1
);
start_sb
=
0
;
for
(
i
=
0
;
start_sb
<
sb_rows
&&
i
<
AV1_MAX_TILE_ROWS
;
i
++
)
{
max_height
=
FFMIN
(
sb_rows
-
start_sb
,
max_tile_height_sb
);
ns
(
max_height
,
height_in_sbs_minus_1
[
i
],
1
,
i
);
size_sb
=
current
->
height_in_sbs_minus_1
[
i
]
+
1
;
start_sb
+=
size_sb
;
}
current
->
tile_rows_log2
=
cbs_av1_tile_log2
(
1
,
i
);
current
->
tile_rows
=
i
;
}
if
(
current
->
tile_cols_log2
>
0
||
current
->
tile_rows_log2
>
0
)
{
fb
(
current
->
tile_cols_log2
+
current
->
tile_rows_log2
,
context_update_tile_id
);
fb
(
2
,
tile_size_bytes_minus1
);
}
else
{
infer
(
context_update_tile_id
,
0
);
}
priv
->
tile_cols
=
current
->
tile_cols
;
priv
->
tile_rows
=
current
->
tile_rows
;
return
0
;
}
static
int
FUNC
(
quantization_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
const
AV1RawSequenceHeader
*
seq
=
priv
->
sequence_header
;
int
err
;
fb
(
8
,
base_q_idx
);
delta_q
(
delta_q_y_dc
);
if
(
priv
->
num_planes
>
1
)
{
if
(
seq
->
color_config
.
separate_uv_delta_q
)
flag
(
diff_uv_delta
);
else
infer
(
diff_uv_delta
,
0
);
delta_q
(
delta_q_u_dc
);
delta_q
(
delta_q_u_ac
);
if
(
current
->
diff_uv_delta
)
{
delta_q
(
delta_q_v_dc
);
delta_q
(
delta_q_v_ac
);
}
else
{
infer
(
delta_q_v_dc
,
current
->
delta_q_u_dc
);
infer
(
delta_q_v_ac
,
current
->
delta_q_u_ac
);
}
}
else
{
infer
(
delta_q_u_dc
,
0
);
infer
(
delta_q_u_ac
,
0
);
infer
(
delta_q_v_dc
,
0
);
infer
(
delta_q_v_ac
,
0
);
}
flag
(
using_qmatrix
);
if
(
current
->
using_qmatrix
)
{
fb
(
4
,
qm_y
);
fb
(
4
,
qm_u
);
if
(
seq
->
color_config
.
separate_uv_delta_q
)
fb
(
4
,
qm_v
);
else
infer
(
qm_v
,
current
->
qm_u
);
}
return
0
;
}
static
int
FUNC
(
segmentation_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
static
const
uint8_t
bits
[
AV1_SEG_LVL_MAX
]
=
{
8
,
6
,
6
,
6
,
6
,
3
,
0
,
0
};
static
const
uint8_t
sign
[
AV1_SEG_LVL_MAX
]
=
{
1
,
1
,
1
,
1
,
1
,
0
,
0
,
0
};
int
i
,
j
,
err
;
flag
(
segmentation_enabled
);
if
(
current
->
segmentation_enabled
)
{
if
(
current
->
primary_ref_frame
==
AV1_PRIMARY_REF_NONE
)
{
infer
(
segmentation_update_map
,
1
);
infer
(
segmentation_temporal_update
,
0
);
infer
(
segmentation_update_data
,
1
);
}
else
{
flag
(
segmentation_update_map
);
if
(
current
->
segmentation_update_map
)
flag
(
segmentation_temporal_update
);
else
infer
(
segmentation_temporal_update
,
0
);
flag
(
segmentation_update_data
);
}
if
(
current
->
segmentation_update_data
)
{
for
(
i
=
0
;
i
<
AV1_MAX_SEGMENTS
;
i
++
)
{
for
(
j
=
0
;
j
<
AV1_SEG_LVL_MAX
;
j
++
)
{
flags
(
feature_enabled
[
i
][
j
],
2
,
i
,
j
);
if
(
current
->
feature_enabled
[
i
][
j
]
&&
bits
[
j
]
>
0
)
{
if
(
sign
[
j
])
sus
(
1
+
bits
[
j
],
feature_value
[
i
][
j
],
2
,
i
,
j
);
else
fbs
(
bits
[
j
],
feature_value
[
i
][
j
],
2
,
i
,
j
);
}
else
{
infer
(
feature_value
[
i
][
j
],
0
);
}
}
}
}
}
else
{
for
(
i
=
0
;
i
<
AV1_MAX_SEGMENTS
;
i
++
)
{
for
(
j
=
0
;
j
<
AV1_SEG_LVL_MAX
;
j
++
)
{
infer
(
feature_enabled
[
i
][
j
],
0
);
infer
(
feature_value
[
i
][
j
],
0
);
}
}
}
return
0
;
}
static
int
FUNC
(
delta_q_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
int
err
;
if
(
current
->
base_q_idx
>
0
)
flag
(
delta_q_present
);
else
infer
(
delta_q_present
,
0
);
if
(
current
->
delta_q_present
)
fb
(
2
,
delta_q_res
);
return
0
;
}
static
int
FUNC
(
delta_lf_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
int
err
;
if
(
current
->
delta_q_present
)
{
if
(
!
current
->
allow_intrabc
)
flag
(
delta_lf_present
);
else
infer
(
delta_lf_present
,
0
);
if
(
current
->
delta_lf_present
)
{
fb
(
2
,
delta_lf_res
);
flag
(
delta_lf_multi
);
}
else
{
infer
(
delta_lf_res
,
0
);
infer
(
delta_lf_multi
,
0
);
}
}
else
{
infer
(
delta_lf_present
,
0
);
infer
(
delta_lf_res
,
0
);
infer
(
delta_lf_multi
,
0
);
}
return
0
;
}
static
int
FUNC
(
loop_filter_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
int
i
,
err
;
if
(
priv
->
coded_lossless
||
current
->
allow_intrabc
)
{
infer
(
loop_filter_level
[
0
],
0
);
infer
(
loop_filter_level
[
1
],
0
);
infer
(
loop_filter_ref_deltas
[
AV1_REF_FRAME_INTRA
],
1
);
infer
(
loop_filter_ref_deltas
[
AV1_REF_FRAME_LAST
],
0
);
infer
(
loop_filter_ref_deltas
[
AV1_REF_FRAME_LAST2
],
0
);
infer
(
loop_filter_ref_deltas
[
AV1_REF_FRAME_LAST3
],
0
);
infer
(
loop_filter_ref_deltas
[
AV1_REF_FRAME_BWDREF
],
0
);
infer
(
loop_filter_ref_deltas
[
AV1_REF_FRAME_GOLDEN
],
-
1
);
infer
(
loop_filter_ref_deltas
[
AV1_REF_FRAME_ALTREF
],
-
1
);
infer
(
loop_filter_ref_deltas
[
AV1_REF_FRAME_ALTREF2
],
-
1
);
for
(
i
=
0
;
i
<
2
;
i
++
)
infer
(
loop_filter_mode_deltas
[
i
],
0
);
return
0
;
}
fb
(
6
,
loop_filter_level
[
0
]);
fb
(
6
,
loop_filter_level
[
1
]);
if
(
priv
->
num_planes
>
1
)
{
if
(
current
->
loop_filter_level
[
0
]
||
current
->
loop_filter_level
[
1
])
{
fb
(
6
,
loop_filter_level
[
2
]);
fb
(
6
,
loop_filter_level
[
3
]);
}
}
fb
(
3
,
loop_filter_sharpness
);
flag
(
loop_filter_delta_enabled
);
if
(
current
->
loop_filter_delta_enabled
)
{
flag
(
loop_filter_delta_update
);
if
(
current
->
loop_filter_delta_update
)
{
for
(
i
=
0
;
i
<
AV1_TOTAL_REFS_PER_FRAME
;
i
++
)
{
flags
(
update_ref_delta
[
i
],
1
,
i
);
if
(
current
->
update_ref_delta
[
i
])
sus
(
1
+
6
,
loop_filter_ref_deltas
[
i
],
1
,
i
);
}
for
(
i
=
0
;
i
<
2
;
i
++
)
{
flags
(
update_mode_delta
[
i
],
1
,
i
);
if
(
current
->
update_mode_delta
[
i
])
sus
(
1
+
6
,
loop_filter_mode_deltas
[
i
],
1
,
i
);
}
}
}
return
0
;
}
static
int
FUNC
(
cdef_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
const
AV1RawSequenceHeader
*
seq
=
priv
->
sequence_header
;
int
i
,
err
;
if
(
priv
->
coded_lossless
||
current
->
allow_intrabc
||
!
seq
->
enable_cdef
)
{
infer
(
cdef_damping_minus_3
,
0
);
infer
(
cdef_bits
,
0
);
infer
(
cdef_y_pri_strength
[
0
],
0
);
infer
(
cdef_y_sec_strength
[
0
],
0
);
infer
(
cdef_uv_pri_strength
[
0
],
0
);
infer
(
cdef_uv_sec_strength
[
0
],
0
);
return
0
;
}
fb
(
2
,
cdef_damping_minus_3
);
fb
(
2
,
cdef_bits
);
for
(
i
=
0
;
i
<
(
1
<<
current
->
cdef_bits
);
i
++
)
{
fbs
(
4
,
cdef_y_pri_strength
[
i
],
1
,
i
);
fbs
(
2
,
cdef_y_sec_strength
[
i
],
1
,
i
);
if
(
priv
->
num_planes
>
1
)
{
fbs
(
4
,
cdef_uv_pri_strength
[
i
],
1
,
i
);
fbs
(
2
,
cdef_uv_sec_strength
[
i
],
1
,
i
);
}
}
return
0
;
}
static
int
FUNC
(
lr_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
const
AV1RawSequenceHeader
*
seq
=
priv
->
sequence_header
;
int
uses_lr
,
uses_chroma_lr
;
int
i
,
err
;
if
(
priv
->
all_lossless
||
current
->
allow_intrabc
||
!
seq
->
enable_restoration
)
{
return
0
;
}
uses_lr
=
uses_chroma_lr
=
0
;
for
(
i
=
0
;
i
<
priv
->
num_planes
;
i
++
)
{
fbs
(
2
,
lr_type
[
i
],
1
,
i
);
if
(
current
->
lr_type
[
i
]
!=
0
)
{
uses_lr
=
1
;
if
(
i
>
0
)
uses_chroma_lr
=
1
;
}
}
if
(
uses_lr
)
{
if
(
seq
->
use_128x128_superblock
)
increment
(
lr_unit_shift
,
1
,
2
);
else
increment
(
lr_unit_shift
,
0
,
2
);
if
(
seq
->
color_config
.
subsampling_x
&&
seq
->
color_config
.
subsampling_y
&&
uses_chroma_lr
)
{
fb
(
1
,
lr_uv_shift
);
}
else
{
infer
(
lr_uv_shift
,
0
);
}
}
return
0
;
}
static
int
FUNC
(
read_tx_mode
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
int
err
;
if
(
priv
->
coded_lossless
)
infer
(
tx_mode
,
0
);
else
increment
(
tx_mode
,
1
,
2
);
return
0
;
}
static
int
FUNC
(
frame_reference_mode
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
int
err
;
if
(
current
->
frame_type
==
AV1_FRAME_INTRA_ONLY
||
current
->
frame_type
==
AV1_FRAME_KEY
)
infer
(
reference_select
,
0
);
else
flag
(
reference_select
);
return
0
;
}
static
int
FUNC
(
skip_mode_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
const
AV1RawSequenceHeader
*
seq
=
priv
->
sequence_header
;
int
skip_mode_allowed
;
int
err
;
if
(
current
->
frame_type
==
AV1_FRAME_KEY
||
current
->
frame_type
==
AV1_FRAME_INTRA_ONLY
||
!
current
->
reference_select
||
!
seq
->
enable_order_hint
)
{
skip_mode_allowed
=
0
;
}
else
{
int
forward_idx
,
backward_idx
;
int
forward_hint
,
backward_hint
;
int
ref_hint
,
dist
,
i
;
forward_idx
=
-
1
;
backward_idx
=
-
1
;
for
(
i
=
0
;
i
<
AV1_REFS_PER_FRAME
;
i
++
)
{
ref_hint
=
priv
->
ref
[
i
].
order_hint
;
dist
=
cbs_av1_get_relative_dist
(
seq
,
ref_hint
,
current
->
order_hint
);
if
(
dist
<
0
)
{
if
(
forward_idx
<
0
||
cbs_av1_get_relative_dist
(
seq
,
ref_hint
,
forward_hint
)
>
0
)
{
forward_idx
=
i
;
forward_hint
=
ref_hint
;
}
}
else
if
(
dist
>
0
)
{
if
(
backward_idx
<
0
||
cbs_av1_get_relative_dist
(
seq
,
ref_hint
,
backward_hint
)
<
0
)
{
backward_idx
=
i
;
backward_hint
=
ref_hint
;
}
}
}
if
(
forward_idx
<
0
)
{
skip_mode_allowed
=
0
;
}
else
if
(
backward_idx
>=
0
)
{
skip_mode_allowed
=
1
;
// Frames for skip mode are forward_idx and backward_idx.
}
else
{
int
second_forward_idx
;
int
second_forward_hint
;
second_forward_idx
=
-
1
;
for
(
i
=
0
;
i
<
AV1_REFS_PER_FRAME
;
i
++
)
{
ref_hint
=
priv
->
ref
[
i
].
order_hint
;
if
(
cbs_av1_get_relative_dist
(
seq
,
ref_hint
,
forward_hint
)
<
0
)
{
if
(
second_forward_idx
<
0
||
cbs_av1_get_relative_dist
(
seq
,
ref_hint
,
second_forward_hint
)
>
0
)
{
second_forward_idx
=
i
;
second_forward_hint
=
ref_hint
;
}
}
}
if
(
second_forward_idx
<
0
)
{
skip_mode_allowed
=
0
;
}
else
{
skip_mode_allowed
=
1
;
// Frames for skip mode are forward_idx and second_forward_idx.
}
}
}
if
(
skip_mode_allowed
)
flag
(
skip_mode_present
);
else
infer
(
skip_mode_present
,
0
);
return
0
;
}
static
int
FUNC
(
global_motion_param
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
,
int
type
,
int
ref
,
int
idx
)
{
uint32_t
abs_bits
,
prec_bits
,
num_syms
;
int
err
;
if
(
idx
<
2
)
{
if
(
type
==
AV1_WARP_MODEL_TRANSLATION
)
{
abs_bits
=
AV1_GM_ABS_TRANS_ONLY_BITS
-
!
current
->
allow_high_precision_mv
;
prec_bits
=
AV1_GM_TRANS_ONLY_PREC_BITS
-
!
current
->
allow_high_precision_mv
;
}
else
{
abs_bits
=
AV1_GM_ABS_TRANS_BITS
;
prec_bits
=
AV1_GM_TRANS_PREC_BITS
;
}
}
else
{
abs_bits
=
AV1_GM_ABS_ALPHA_BITS
;
prec_bits
=
AV1_GM_ALPHA_PREC_BITS
;
}
num_syms
=
2
*
(
1
<<
abs_bits
)
+
1
;
subexp
(
gm_params
[
ref
][
idx
],
num_syms
,
2
,
ref
,
idx
);
// Actual gm_params value is not reconstructed here.
(
void
)
prec_bits
;
return
0
;
}
static
int
FUNC
(
global_motion_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
int
ref
,
type
;
int
err
;
if
(
current
->
frame_type
==
AV1_FRAME_KEY
||
current
->
frame_type
==
AV1_FRAME_INTRA_ONLY
)
return
0
;
for
(
ref
=
AV1_REF_FRAME_LAST
;
ref
<=
AV1_REF_FRAME_ALTREF
;
ref
++
)
{
flags
(
is_global
[
ref
],
1
,
ref
);
if
(
current
->
is_global
[
ref
])
{
flags
(
is_rot_zoom
[
ref
],
1
,
ref
);
if
(
current
->
is_rot_zoom
[
ref
])
{
type
=
AV1_WARP_MODEL_ROTZOOM
;
}
else
{
flags
(
is_translation
[
ref
],
1
,
ref
);
type
=
current
->
is_translation
[
ref
]
?
AV1_WARP_MODEL_TRANSLATION
:
AV1_WARP_MODEL_AFFINE
;
}
}
else
{
type
=
AV1_WARP_MODEL_IDENTITY
;
}
if
(
type
>=
AV1_WARP_MODEL_ROTZOOM
)
{
CHECK
(
FUNC
(
global_motion_param
)(
ctx
,
rw
,
current
,
type
,
ref
,
2
));
CHECK
(
FUNC
(
global_motion_param
)(
ctx
,
rw
,
current
,
type
,
ref
,
3
));
if
(
type
==
AV1_WARP_MODEL_AFFINE
)
{
CHECK
(
FUNC
(
global_motion_param
)(
ctx
,
rw
,
current
,
type
,
ref
,
4
));
CHECK
(
FUNC
(
global_motion_param
)(
ctx
,
rw
,
current
,
type
,
ref
,
5
));
}
else
{
// gm_params[ref][4] = -gm_params[ref][3]
// gm_params[ref][5] = gm_params[ref][2]
}
}
if
(
type
>=
AV1_WARP_MODEL_TRANSLATION
)
{
CHECK
(
FUNC
(
global_motion_param
)(
ctx
,
rw
,
current
,
type
,
ref
,
0
));
CHECK
(
FUNC
(
global_motion_param
)(
ctx
,
rw
,
current
,
type
,
ref
,
1
));
}
}
return
0
;
}
static
int
FUNC
(
film_grain_params
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
const
AV1RawSequenceHeader
*
seq
=
priv
->
sequence_header
;
int
num_pos_luma
,
num_pos_chroma
;
int
i
,
err
;
if
(
!
seq
->
film_grain_params_present
||
(
!
current
->
show_frame
&&
!
current
->
showable_frame
))
return
0
;
flag
(
apply_grain
);
if
(
!
current
->
apply_grain
)
return
0
;
fb
(
16
,
grain_seed
);
if
(
current
->
frame_type
==
AV1_FRAME_INTER
)
flag
(
update_grain
);
else
infer
(
update_grain
,
1
);
if
(
!
current
->
update_grain
)
{
fb
(
3
,
film_grain_params_ref_idx
);
return
0
;
}
fb
(
4
,
num_y_points
);
for
(
i
=
0
;
i
<
current
->
num_y_points
;
i
++
)
{
fbs
(
8
,
point_y_value
[
i
],
1
,
i
);
fbs
(
8
,
point_y_scaling
[
i
],
1
,
i
);
}
if
(
seq
->
color_config
.
mono_chrome
)
infer
(
chroma_scaling_from_luma
,
0
);
else
flag
(
chroma_scaling_from_luma
);
if
(
seq
->
color_config
.
mono_chrome
||
current
->
chroma_scaling_from_luma
||
(
seq
->
color_config
.
subsampling_x
==
1
&&
seq
->
color_config
.
subsampling_y
==
1
&&
current
->
num_y_points
==
0
))
{
infer
(
num_cb_points
,
0
);
infer
(
num_cr_points
,
0
);
}
else
{
fb
(
4
,
num_cb_points
);
for
(
i
=
0
;
i
<
current
->
num_cb_points
;
i
++
)
{
fbs
(
8
,
point_cb_value
[
i
],
1
,
i
);
fbs
(
8
,
point_cb_scaling
[
i
],
1
,
i
);
}
fb
(
4
,
num_cr_points
);
for
(
i
=
0
;
i
<
current
->
num_cr_points
;
i
++
)
{
fbs
(
8
,
point_cr_value
[
i
],
1
,
i
);
fbs
(
8
,
point_cr_scaling
[
i
],
1
,
i
);
}
}
fb
(
2
,
grain_scaling_minus_8
);
fb
(
2
,
ar_coeff_lag
);
num_pos_luma
=
2
*
current
->
ar_coeff_lag
*
(
current
->
ar_coeff_lag
+
1
);
if
(
current
->
num_y_points
)
{
num_pos_chroma
=
num_pos_luma
+
1
;
for
(
i
=
0
;
i
<
num_pos_luma
;
i
++
)
fbs
(
8
,
ar_coeffs_y_plus_128
[
i
],
1
,
i
);
}
else
{
num_pos_chroma
=
num_pos_luma
;
}
if
(
current
->
chroma_scaling_from_luma
||
current
->
num_cb_points
)
{
for
(
i
=
0
;
i
<
num_pos_chroma
;
i
++
)
fbs
(
8
,
ar_coeffs_cb_plus_128
[
i
],
1
,
i
);
}
if
(
current
->
chroma_scaling_from_luma
||
current
->
num_cr_points
)
{
for
(
i
=
0
;
i
<
num_pos_chroma
;
i
++
)
fbs
(
8
,
ar_coeffs_cr_plus_128
[
i
],
1
,
i
);
}
fb
(
2
,
ar_coeff_shift_minus_6
);
fb
(
2
,
grain_scale_shift
);
if
(
current
->
num_cb_points
)
{
fb
(
8
,
cb_mult
);
fb
(
8
,
cb_luma_mult
);
fb
(
9
,
cb_offset
);
}
if
(
current
->
num_cr_points
)
{
fb
(
8
,
cr_mult
);
fb
(
8
,
cr_luma_mult
);
fb
(
9
,
cr_offset
);
}
flag
(
overlap_flag
);
flag
(
clip_to_restricted_range
);
return
0
;
}
static
int
FUNC
(
uncompressed_header
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
const
AV1RawSequenceHeader
*
seq
;
int
id_len
,
diff_len
,
all_frames
,
frame_is_intra
,
order_hint_bits
;
int
i
,
err
;
if
(
!
priv
->
sequence_header
)
{
av_log
(
ctx
->
log_ctx
,
AV_LOG_ERROR
,
"No sequence header available: "
"unable to decode frame header.
\n
"
);
return
AVERROR_INVALIDDATA
;
}
seq
=
priv
->
sequence_header
;
id_len
=
seq
->
additional_frame_id_length_minus_1
+
seq
->
delta_frame_id_length_minus_2
+
3
;
all_frames
=
(
1
<<
AV1_NUM_REF_FRAMES
)
-
1
;
if
(
seq
->
reduced_still_picture_header
)
{
infer
(
show_existing_frame
,
0
);
infer
(
frame_type
,
AV1_FRAME_KEY
);
infer
(
show_frame
,
1
);
infer
(
showable_frame
,
0
);
frame_is_intra
=
1
;
}
else
{
flag
(
show_existing_frame
);
if
(
current
->
show_existing_frame
)
{
AV1ReferenceFrameState
*
frame
;
fb
(
3
,
frame_to_show_map_idx
);
frame
=
&
priv
->
ref
[
current
->
frame_to_show_map_idx
];
if
(
seq
->
decoder_model_info_present_flag
&&
!
seq
->
timing_info
.
equal_picture_interval
)
{
fb
(
seq
->
decoder_model_info
.
frame_presentation_time_length_minus_1
+
1
,
frame_presentation_time
);
}
if
(
seq
->
frame_id_numbers_present_flag
)
fb
(
id_len
,
display_frame_id
);
if
(
frame
->
frame_type
==
AV1_FRAME_KEY
)
infer
(
refresh_frame_flags
,
all_frames
);
else
infer
(
refresh_frame_flags
,
0
);
return
0
;
}
fb
(
2
,
frame_type
);
frame_is_intra
=
(
current
->
frame_type
==
AV1_FRAME_INTRA_ONLY
||
current
->
frame_type
==
AV1_FRAME_KEY
);
flag
(
show_frame
);
if
(
current
->
show_frame
&&
seq
->
decoder_model_info_present_flag
&&
!
seq
->
timing_info
.
equal_picture_interval
)
{
fb
(
seq
->
decoder_model_info
.
frame_presentation_time_length_minus_1
+
1
,
frame_presentation_time
);
}
if
(
current
->
show_frame
)
infer
(
showable_frame
,
current
->
frame_type
!=
AV1_FRAME_KEY
);
else
flag
(
showable_frame
);
if
(
current
->
frame_type
==
AV1_FRAME_SWITCH
||
(
current
->
frame_type
==
AV1_FRAME_KEY
&&
current
->
show_frame
))
infer
(
error_resilient_mode
,
1
);
else
flag
(
error_resilient_mode
);
}
if
(
current
->
frame_type
==
AV1_FRAME_KEY
&&
current
->
show_frame
)
{
for
(
i
=
0
;
i
<
AV1_NUM_REF_FRAMES
;
i
++
)
{
priv
->
ref
[
i
].
valid
=
0
;
priv
->
ref
[
i
].
order_hint
=
0
;
}
}
flag
(
disable_cdf_update
);
if
(
seq
->
seq_force_screen_content_tools
==
AV1_SELECT_SCREEN_CONTENT_TOOLS
)
{
flag
(
allow_screen_content_tools
);
}
else
{
infer
(
allow_screen_content_tools
,
seq
->
seq_force_screen_content_tools
);
}
if
(
current
->
allow_screen_content_tools
)
{
if
(
seq
->
seq_force_integer_mv
==
AV1_SELECT_INTEGER_MV
)
flag
(
force_integer_mv
);
else
infer
(
force_integer_mv
,
seq
->
seq_force_integer_mv
);
}
else
{
infer
(
force_integer_mv
,
0
);
}
if
(
seq
->
frame_id_numbers_present_flag
)
{
fb
(
id_len
,
current_frame_id
);
diff_len
=
seq
->
delta_frame_id_length_minus_2
+
2
;
for
(
i
=
0
;
i
<
AV1_NUM_REF_FRAMES
;
i
++
)
{
if
(
current
->
current_frame_id
>
(
1
<<
diff_len
))
{
if
(
priv
->
ref
[
i
].
frame_id
>
current
->
current_frame_id
||
priv
->
ref
[
i
].
frame_id
<
(
current
->
current_frame_id
-
(
1
<<
diff_len
)))
priv
->
ref
[
i
].
valid
=
0
;
}
else
{
if
(
priv
->
ref
[
i
].
frame_id
>
current
->
current_frame_id
&&
priv
->
ref
[
i
].
frame_id
<
((
1
<<
id_len
)
+
current
->
current_frame_id
-
(
1
<<
diff_len
)))
priv
->
ref
[
i
].
valid
=
0
;
}
}
}
else
{
infer
(
current_frame_id
,
0
);
}
if
(
current
->
frame_type
==
AV1_FRAME_SWITCH
)
infer
(
frame_size_override_flag
,
1
);
else
if
(
seq
->
reduced_still_picture_header
)
infer
(
frame_size_override_flag
,
0
);
else
flag
(
frame_size_override_flag
);
order_hint_bits
=
seq
->
enable_order_hint
?
seq
->
order_hint_bits_minus_1
+
1
:
0
;
if
(
order_hint_bits
>
0
)
fb
(
order_hint_bits
,
order_hint
);
else
infer
(
order_hint
,
0
);
if
(
frame_is_intra
||
current
->
error_resilient_mode
)
infer
(
primary_ref_frame
,
AV1_PRIMARY_REF_NONE
);
else
fb
(
3
,
primary_ref_frame
);
if
(
seq
->
decoder_model_info_present_flag
)
{
flag
(
buffer_removal_time_present_flag
);
if
(
current
->
buffer_removal_time_present_flag
)
{
for
(
i
=
0
;
i
<=
seq
->
operating_points_cnt_minus_1
;
i
++
)
{
if
(
seq
->
decoder_model_present_for_this_op
[
i
])
{
int
op_pt_idc
=
seq
->
operating_point_idc
[
i
];
int
in_temporal_layer
=
(
op_pt_idc
>>
priv
->
temporal_id
)
&
1
;
int
in_spatial_layer
=
(
op_pt_idc
>>
(
priv
->
spatial_id
+
8
))
&
1
;
if
(
seq
->
operating_point_idc
[
i
]
==
0
||
in_temporal_layer
||
in_spatial_layer
)
{
fbs
(
seq
->
decoder_model_info
.
buffer_removal_time_length_minus_1
+
1
,
buffer_removal_time
[
i
],
1
,
i
);
}
}
}
}
}
if
(
current
->
frame_type
==
AV1_FRAME_SWITCH
||
(
current
->
frame_type
==
AV1_FRAME_KEY
&&
current
->
show_frame
))
infer
(
refresh_frame_flags
,
all_frames
);
else
fb
(
8
,
refresh_frame_flags
);
if
(
!
frame_is_intra
||
current
->
refresh_frame_flags
!=
all_frames
)
{
if
(
current
->
error_resilient_mode
&&
seq
->
enable_order_hint
)
{
for
(
i
=
0
;
i
<
AV1_NUM_REF_FRAMES
;
i
++
)
{
fbs
(
order_hint_bits
,
ref_order_hint
[
i
],
1
,
i
);
if
(
current
->
ref_order_hint
[
i
]
!=
priv
->
ref
[
i
].
order_hint
)
priv
->
ref
[
i
].
valid
=
0
;
}
}
}
if
(
current
->
frame_type
==
AV1_FRAME_KEY
||
current
->
frame_type
==
AV1_FRAME_INTRA_ONLY
)
{
CHECK
(
FUNC
(
frame_size
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
render_size
)(
ctx
,
rw
,
current
));
if
(
current
->
allow_screen_content_tools
&&
priv
->
upscaled_width
==
priv
->
frame_width
)
flag
(
allow_intrabc
);
else
infer
(
allow_intrabc
,
0
);
}
else
{
if
(
!
seq
->
enable_order_hint
)
{
infer
(
frame_refs_short_signaling
,
0
);
}
else
{
flag
(
frame_refs_short_signaling
);
if
(
current
->
frame_refs_short_signaling
)
{
fb
(
3
,
last_frame_idx
);
fb
(
3
,
golden_frame_idx
);
for
(
i
=
0
;
i
<
AV1_REFS_PER_FRAME
;
i
++
)
{
if
(
i
==
0
)
infer
(
ref_frame_idx
[
i
],
current
->
last_frame_idx
);
else
if
(
i
==
AV1_REF_FRAME_GOLDEN
-
AV1_REF_FRAME_LAST
)
infer
(
ref_frame_idx
[
i
],
current
->
golden_frame_idx
);
else
infer
(
ref_frame_idx
[
i
],
-
1
);
}
}
}
for
(
i
=
0
;
i
<
AV1_REFS_PER_FRAME
;
i
++
)
{
if
(
!
current
->
frame_refs_short_signaling
)
fbs
(
3
,
ref_frame_idx
[
i
],
1
,
i
);
if
(
seq
->
frame_id_numbers_present_flag
)
{
fb
(
seq
->
delta_frame_id_length_minus_2
+
2
,
delta_frame_id_minus1
);
}
}
if
(
current
->
frame_size_override_flag
&&
!
current
->
error_resilient_mode
)
{
CHECK
(
FUNC
(
frame_size_with_refs
)(
ctx
,
rw
,
current
));
}
else
{
CHECK
(
FUNC
(
frame_size
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
render_size
)(
ctx
,
rw
,
current
));
}
if
(
current
->
force_integer_mv
)
infer
(
allow_high_precision_mv
,
0
);
else
flag
(
allow_high_precision_mv
);
CHECK
(
FUNC
(
interpolation_filter
)(
ctx
,
rw
,
current
));
flag
(
is_motion_mode_switchable
);
if
(
current
->
error_resilient_mode
||
!
seq
->
enable_ref_frame_mvs
)
infer
(
use_ref_frame_mvs
,
0
);
else
flag
(
use_ref_frame_mvs
);
infer
(
allow_intrabc
,
0
);
}
if
(
!
frame_is_intra
)
{
// Derive reference frame sign biases.
}
if
(
seq
->
reduced_still_picture_header
||
current
->
disable_cdf_update
)
infer
(
disable_frame_end_update_cdf
,
1
);
else
flag
(
disable_frame_end_update_cdf
);
if
(
current
->
primary_ref_frame
==
AV1_PRIMARY_REF_NONE
)
{
// Init non-coeff CDFs.
// Setup past independence.
}
else
{
// Load CDF tables from previous frame.
// Load params from previous frame.
}
if
(
current
->
use_ref_frame_mvs
)
{
// Perform motion field estimation process.
}
CHECK
(
FUNC
(
tile_info
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
quantization_params
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
segmentation_params
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
delta_q_params
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
delta_lf_params
)(
ctx
,
rw
,
current
));
// Init coeff CDFs / load previous segments.
priv
->
coded_lossless
=
1
;
for
(
i
=
0
;
i
<
AV1_MAX_SEGMENTS
;
i
++
)
{
int
qindex
;
if
(
current
->
feature_enabled
[
i
][
AV1_SEG_LVL_ALT_Q
])
{
qindex
=
(
current
->
base_q_idx
+
current
->
feature_value
[
i
][
AV1_SEG_LVL_ALT_Q
]);
}
else
{
qindex
=
current
->
base_q_idx
;
}
qindex
=
av_clip_uintp2
(
qindex
,
8
);
if
(
qindex
||
current
->
delta_q_y_dc
||
current
->
delta_q_u_ac
||
current
->
delta_q_u_dc
||
current
->
delta_q_v_ac
||
current
->
delta_q_v_dc
)
{
priv
->
coded_lossless
=
0
;
}
}
priv
->
all_lossless
=
priv
->
coded_lossless
&&
priv
->
frame_width
==
priv
->
upscaled_width
;
CHECK
(
FUNC
(
loop_filter_params
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
cdef_params
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
lr_params
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
read_tx_mode
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
frame_reference_mode
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
skip_mode_params
)(
ctx
,
rw
,
current
));
if
(
frame_is_intra
||
current
->
error_resilient_mode
||
!
seq
->
enable_warped_motion
)
infer
(
allow_warped_motion
,
0
);
else
flag
(
allow_warped_motion
);
flag
(
reduced_tx_set
);
CHECK
(
FUNC
(
global_motion_params
)(
ctx
,
rw
,
current
));
CHECK
(
FUNC
(
film_grain_params
)(
ctx
,
rw
,
current
));
for
(
i
=
0
;
i
<
AV1_NUM_REF_FRAMES
;
i
++
)
{
if
(
current
->
refresh_frame_flags
&
(
1
<<
i
))
{
priv
->
ref
[
i
]
=
(
AV1ReferenceFrameState
)
{
.
valid
=
1
,
.
frame_id
=
current
->
current_frame_id
,
.
upscaled_width
=
priv
->
upscaled_width
,
.
frame_width
=
priv
->
frame_width
,
.
frame_height
=
priv
->
frame_height
,
.
render_width
=
priv
->
render_width
,
.
render_height
=
priv
->
render_height
,
.
frame_type
=
current
->
frame_type
,
.
subsampling_x
=
seq
->
color_config
.
subsampling_x
,
.
subsampling_y
=
seq
->
color_config
.
subsampling_y
,
.
bit_depth
=
priv
->
bit_depth
,
.
order_hint
=
current
->
order_hint
,
};
}
}
av_log
(
ctx
->
log_ctx
,
AV_LOG_DEBUG
,
"Frame %d: size %dx%d "
"upscaled %d render %dx%d subsample %dx%d "
"bitdepth %d tiles %dx%d.
\n
"
,
current
->
order_hint
,
priv
->
frame_width
,
priv
->
frame_height
,
priv
->
upscaled_width
,
priv
->
render_width
,
priv
->
render_height
,
seq
->
color_config
.
subsampling_x
+
1
,
seq
->
color_config
.
subsampling_y
+
1
,
priv
->
bit_depth
,
priv
->
tile_rows
,
priv
->
tile_cols
);
return
0
;
}
static
int
FUNC
(
frame_header_obu
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrameHeader
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
int
err
;
HEADER
(
"Frame Header"
);
if
(
priv
->
seen_frame_header
)
{
// Nothing to do.
}
else
{
priv
->
seen_frame_header
=
1
;
CHECK
(
FUNC
(
uncompressed_header
)(
ctx
,
rw
,
current
));
if
(
current
->
show_existing_frame
)
{
priv
->
seen_frame_header
=
0
;
}
else
{
priv
->
seen_frame_header
=
1
;
}
}
return
0
;
}
static
int
FUNC
(
tile_group_obu
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawTileGroup
*
current
)
{
CodedBitstreamAV1Context
*
priv
=
ctx
->
priv_data
;
int
num_tiles
,
tile_bits
;
int
err
;
HEADER
(
"Tile Group"
);
num_tiles
=
priv
->
tile_cols
*
priv
->
tile_rows
;
if
(
num_tiles
>
1
)
flag
(
tile_start_and_end_present_flag
);
else
infer
(
tile_start_and_end_present_flag
,
0
);
if
(
num_tiles
==
1
||
!
current
->
tile_start_and_end_present_flag
)
{
infer
(
tg_start
,
0
);
infer
(
tg_end
,
num_tiles
-
1
);
}
else
{
tile_bits
=
cbs_av1_tile_log2
(
1
,
priv
->
tile_cols
)
+
cbs_av1_tile_log2
(
1
,
priv
->
tile_rows
);
fb
(
tile_bits
,
tg_start
);
fb
(
tile_bits
,
tg_end
);
}
CHECK
(
FUNC
(
byte_alignment
)(
ctx
,
rw
));
// Reset header for next frame.
if
(
current
->
tg_end
==
num_tiles
-
1
)
priv
->
seen_frame_header
=
0
;
// Tile data follows.
return
0
;
}
static
int
FUNC
(
frame_obu
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawFrame
*
current
)
{
int
err
;
CHECK
(
FUNC
(
frame_header_obu
)(
ctx
,
rw
,
&
current
->
header
));
CHECK
(
FUNC
(
byte_alignment
)(
ctx
,
rw
));
CHECK
(
FUNC
(
tile_group_obu
)(
ctx
,
rw
,
&
current
->
tile_group
));
return
0
;
}
static
int
FUNC
(
tile_list_obu
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawTileList
*
current
)
{
int
err
;
fb
(
8
,
output_frame_width_in_tiles_minus_1
);
fb
(
8
,
output_frame_height_in_tiles_minus_1
);
fb
(
16
,
tile_count_minus_1
);
// Tile data follows.
return
0
;
}
static
int
FUNC
(
metadata_hdr_cll
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawMetadataHDRCLL
*
current
)
{
int
err
;
fb
(
16
,
max_cll
);
fb
(
16
,
max_fall
);
return
0
;
}
static
int
FUNC
(
metadata_hdr_mdcv
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawMetadataHDRMDCV
*
current
)
{
int
err
,
i
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
fcs
(
16
,
primary_chromaticity_x
[
i
],
0
,
50000
,
1
,
i
);
fcs
(
16
,
primary_chromaticity_y
[
i
],
0
,
50000
,
1
,
i
);
}
fc
(
16
,
white_point_chromaticity_x
,
0
,
50000
);
fc
(
16
,
white_point_chromaticity_y
,
0
,
50000
);
fc
(
32
,
luminance_max
,
1
,
MAX_UINT_BITS
(
32
));
fc
(
32
,
luminance_min
,
0
,
current
->
luminance_max
>>
6
);
return
0
;
}
static
int
FUNC
(
metadata_scalability
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawMetadataScalability
*
current
)
{
// TODO: scalability metadata.
return
AVERROR_PATCHWELCOME
;
}
static
int
FUNC
(
metadata_itut_t35
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawMetadataITUTT35
*
current
)
{
int
err
;
size_t
i
;
fb
(
8
,
itu_t_t35_country_code
);
if
(
current
->
itu_t_t35_country_code
==
0xff
)
fb
(
8
,
itu_t_t35_country_code_extension_byte
);
#ifdef READ
// The payload runs up to the start of the trailing bits, but there might
// be arbitrarily many trailing zeroes so we need to read through twice.
{
GetBitContext
tmp
=
*
rw
;
current
->
payload_size
=
0
;
for
(
i
=
0
;
get_bits_left
(
rw
)
>=
8
;
i
++
)
{
if
(
get_bits
(
rw
,
8
))
current
->
payload_size
=
i
;
}
*
rw
=
tmp
;
}
current
->
payload_ref
=
av_buffer_alloc
(
current
->
payload_size
);
if
(
!
current
->
payload_ref
)
return
AVERROR
(
ENOMEM
);
current
->
payload
=
current
->
payload_ref
->
data
;
#endif
for
(
i
=
0
;
i
<
current
->
payload_size
;
i
++
)
xf
(
8
,
itu_t_t35_payload_bytes
[
i
],
current
->
payload
[
i
],
0x00
,
0xff
,
1
,
i
);
return
0
;
}
static
int
FUNC
(
metadata_timecode
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawMetadataTimecode
*
current
)
{
int
err
;
fb
(
5
,
counting_type
);
flag
(
full_timestamp_flag
);
flag
(
discontinuity_flag
);
flag
(
cnt_dropped_flag
);
fb
(
9
,
n_frames
);
if
(
current
->
full_timestamp_flag
)
{
fb
(
6
,
seconds_value
);
fb
(
6
,
minutes_value
);
fb
(
5
,
hours_value
);
}
else
{
flag
(
seconds_flag
);
if
(
current
->
seconds_flag
)
{
fb
(
6
,
seconds_value
);
flag
(
minutes_flag
);
if
(
current
->
minutes_flag
)
{
fb
(
6
,
minutes_value
);
flag
(
hours_flag
);
if
(
current
->
hours_flag
)
fb
(
5
,
hours_value
);
}
}
}
fb
(
5
,
time_offset_length
);
if
(
current
->
time_offset_length
>
0
)
fb
(
current
->
time_offset_length
,
time_offset_value
);
return
0
;
}
static
int
FUNC
(
metadata_obu
)(
CodedBitstreamContext
*
ctx
,
RWContext
*
rw
,
AV1RawMetadata
*
current
)
{
int
err
;
leb128
(
metadata_type
);
switch
(
current
->
metadata_type
)
{
case
AV1_METADATA_TYPE_HDR_CLL
:
CHECK
(
FUNC
(
metadata_hdr_cll
)(
ctx
,
rw
,
&
current
->
metadata
.
hdr_cll
));
break
;
case
AV1_METADATA_TYPE_HDR_MDCV
:
CHECK
(
FUNC
(
metadata_hdr_mdcv
)(
ctx
,
rw
,
&
current
->
metadata
.
hdr_mdcv
));
break
;
case
AV1_METADATA_TYPE_SCALABILITY
:
CHECK
(
FUNC
(
metadata_scalability
)(
ctx
,
rw
,
&
current
->
metadata
.
scalability
));
break
;
case
AV1_METADATA_TYPE_ITUT_T35
:
CHECK
(
FUNC
(
metadata_itut_t35
)(
ctx
,
rw
,
&
current
->
metadata
.
itut_t35
));
break
;
case
AV1_METADATA_TYPE_TIMECODE
:
CHECK
(
FUNC
(
metadata_timecode
)(
ctx
,
rw
,
&
current
->
metadata
.
timecode
));
break
;
default:
// Unknown metadata type.
return
AVERROR_PATCHWELCOME
;
}
return
0
;
}
libavcodec/cbs_internal.h
View file @
c8c81ac5
...
...
@@ -86,6 +86,7 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
#define MAX_UINT_BITS(length) ((UINT64_C(1) << (length)) - 1)
extern
const
CodedBitstreamType
ff_cbs_type_av1
;
extern
const
CodedBitstreamType
ff_cbs_type_h264
;
extern
const
CodedBitstreamType
ff_cbs_type_h265
;
extern
const
CodedBitstreamType
ff_cbs_type_jpeg
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment