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
0b0953ba
Commit
0b0953ba
authored
May 18, 2013
by
Kostya Shishkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
proresenc: alpha coding support
parent
86113667
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
226 additions
and
21 deletions
+226
-21
encoders.texi
doc/encoders.texi
+6
-0
proresenc.c
libavcodec/proresenc.c
+220
-21
No files found.
doc/encoders.texi
View file @
0b0953ba
...
...
@@ -608,6 +608,7 @@ Select the ProRes profile to encode
@item lt
@item standard
@item hq
@item 4444
@end table
@item quant_mat @var{integer}
...
...
@@ -637,6 +638,11 @@ Override the 4-byte vendor ID.
A custom vendor ID like @var{apl0} would claim the stream was produced by
the Apple encoder.
@item alpha_bits @var{integer}
Specify number of bits for alpha component.
Possible values are @var{0}, @var{8} and @var{16}.
Use @var{0} to disable alpha plane coding.
@end table
@subsection Speed considerations
...
...
libavcodec/proresenc.c
View file @
0b0953ba
...
...
@@ -21,6 +21,7 @@
*/
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "dsputil.h"
#include "put_bits.h"
...
...
@@ -34,13 +35,14 @@
#define MAX_MBS_PER_SLICE 8
#define MAX_PLANES
3 // should be increased to 4 when there's AV_PIX_FMT_YUV444AP10
#define MAX_PLANES
4
enum
{
PRORES_PROFILE_PROXY
=
0
,
PRORES_PROFILE_LT
,
PRORES_PROFILE_STANDARD
,
PRORES_PROFILE_HQ
,
PRORES_PROFILE_4444
,
};
enum
{
...
...
@@ -119,7 +121,7 @@ static const struct prores_profile {
int
max_quant
;
int
br_tab
[
NUM_MB_LIMITS
];
int
quant
;
}
prores_profile_info
[
4
]
=
{
}
prores_profile_info
[
5
]
=
{
{
.
full_name
=
"proxy"
,
.
tag
=
MKTAG
(
'a'
,
'p'
,
'c'
,
'o'
),
...
...
@@ -151,8 +153,15 @@ static const struct prores_profile {
.
max_quant
=
6
,
.
br_tab
=
{
1566
,
1216
,
1070
,
950
},
.
quant
=
QUANT_MAT_HQ
,
},
{
.
full_name
=
"4444"
,
.
tag
=
MKTAG
(
'a'
,
'p'
,
'4'
,
'h'
),
.
min_quant
=
1
,
.
max_quant
=
6
,
.
br_tab
=
{
2350
,
1828
,
1600
,
1425
},
.
quant
=
QUANT_MAT_HQ
,
}
// for 4444 profile bitrate numbers are { 2350, 1828, 1600, 1425 }
};
#define TRELLIS_WIDTH 16
...
...
@@ -195,6 +204,7 @@ typedef struct ProresContext {
int
num_planes
;
int
bits_per_mb
;
int
force_quant
;
int
alpha_bits
;
char
*
vendor
;
int
quant_sel
;
...
...
@@ -280,6 +290,34 @@ static void get_slice_data(ProresContext *ctx, const uint16_t *src,
}
}
static
void
get_alpha_data
(
ProresContext
*
ctx
,
const
uint16_t
*
src
,
int
linesize
,
int
x
,
int
y
,
int
w
,
int
h
,
int16_t
*
blocks
,
int
mbs_per_slice
,
int
abits
)
{
const
int
slice_width
=
16
*
mbs_per_slice
;
int
i
,
j
,
copy_w
,
copy_h
;
copy_w
=
FFMIN
(
w
-
x
,
slice_width
);
copy_h
=
FFMIN
(
h
-
y
,
16
);
for
(
i
=
0
;
i
<
copy_h
;
i
++
)
{
memcpy
(
blocks
,
src
,
copy_w
*
sizeof
(
*
src
));
if
(
abits
==
8
)
for
(
j
=
0
;
j
<
copy_w
;
j
++
)
blocks
[
j
]
>>=
2
;
else
for
(
j
=
0
;
j
<
copy_w
;
j
++
)
blocks
[
j
]
=
(
blocks
[
j
]
<<
6
)
|
(
blocks
[
j
]
>>
4
);
for
(
j
=
copy_w
;
j
<
slice_width
;
j
++
)
blocks
[
j
]
=
blocks
[
copy_w
-
1
];
blocks
+=
slice_width
;
src
+=
linesize
>>
1
;
}
for
(;
i
<
16
;
i
++
)
{
memcpy
(
blocks
,
blocks
-
slice_width
,
slice_width
*
sizeof
(
*
blocks
));
blocks
+=
slice_width
;
}
}
/**
* Write an unsigned rice/exp golomb codeword.
*/
...
...
@@ -394,6 +432,73 @@ static int encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
return
(
put_bits_count
(
pb
)
-
saved_pos
)
>>
3
;
}
static
void
put_alpha_diff
(
PutBitContext
*
pb
,
int
cur
,
int
prev
,
int
abits
)
{
const
int
mask
=
(
1
<<
abits
)
-
1
;
const
int
dbits
=
(
abits
==
8
)
?
4
:
7
;
const
int
dsize
=
1
<<
dbits
-
1
;
int
diff
=
cur
-
prev
;
diff
&=
mask
;
if
(
diff
>=
(
1
<<
abits
)
-
dsize
)
diff
-=
1
<<
abits
;
if
(
diff
<
-
dsize
||
diff
>
dsize
||
!
diff
)
{
put_bits
(
pb
,
1
,
1
);
put_bits
(
pb
,
abits
,
diff
);
}
else
{
put_bits
(
pb
,
1
,
0
);
put_bits
(
pb
,
dbits
-
1
,
FFABS
(
diff
)
-
1
);
put_bits
(
pb
,
1
,
diff
<
0
);
}
}
static
void
put_alpha_run
(
PutBitContext
*
pb
,
int
run
)
{
if
(
run
)
{
put_bits
(
pb
,
1
,
0
);
if
(
run
<
0x10
)
put_bits
(
pb
,
4
,
run
);
else
put_bits
(
pb
,
15
,
run
);
}
else
{
put_bits
(
pb
,
1
,
1
);
}
}
// todo alpha quantisation for high quants
static
int
encode_alpha_plane
(
ProresContext
*
ctx
,
PutBitContext
*
pb
,
const
uint16_t
*
src
,
int
linesize
,
int
mbs_per_slice
,
uint16_t
*
blocks
,
int
quant
)
{
const
int
abits
=
ctx
->
alpha_bits
;
const
int
mask
=
(
1
<<
abits
)
-
1
;
const
int
num_coeffs
=
mbs_per_slice
*
256
;
int
saved_pos
=
put_bits_count
(
pb
);
int
prev
=
mask
,
cur
;
int
idx
=
0
;
int
run
=
0
;
cur
=
blocks
[
idx
++
];
put_alpha_diff
(
pb
,
cur
,
prev
,
abits
);
prev
=
cur
;
do
{
cur
=
blocks
[
idx
++
];
if
(
cur
!=
prev
)
{
put_alpha_run
(
pb
,
run
);
put_alpha_diff
(
pb
,
cur
,
prev
,
abits
);
prev
=
cur
;
run
=
0
;
}
else
{
run
++
;
}
}
while
(
idx
<
num_coeffs
);
if
(
run
)
put_alpha_run
(
pb
,
run
);
flush_put_bits
(
pb
);
return
(
put_bits_count
(
pb
)
-
saved_pos
)
>>
3
;
}
static
int
encode_slice
(
AVCodecContext
*
avctx
,
const
AVFrame
*
pic
,
PutBitContext
*
pb
,
int
sizes
[
4
],
int
x
,
int
y
,
int
quant
,
...
...
@@ -444,14 +549,23 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
src
=
(
const
uint16_t
*
)(
pic
->
data
[
i
]
+
yp
*
linesize
+
line_add
*
pic
->
linesize
[
i
])
+
xp
;
get_slice_data
(
ctx
,
src
,
linesize
,
xp
,
yp
,
pwidth
,
avctx
->
height
/
ctx
->
pictures_per_frame
,
ctx
->
blocks
[
0
],
ctx
->
emu_buf
,
mbs_per_slice
,
num_cblocks
,
is_chroma
);
sizes
[
i
]
=
encode_slice_plane
(
ctx
,
pb
,
src
,
linesize
,
mbs_per_slice
,
ctx
->
blocks
[
0
],
num_cblocks
,
plane_factor
,
qmat
);
if
(
i
<
3
)
{
get_slice_data
(
ctx
,
src
,
linesize
,
xp
,
yp
,
pwidth
,
avctx
->
height
/
ctx
->
pictures_per_frame
,
ctx
->
blocks
[
0
],
ctx
->
emu_buf
,
mbs_per_slice
,
num_cblocks
,
is_chroma
);
sizes
[
i
]
=
encode_slice_plane
(
ctx
,
pb
,
src
,
linesize
,
mbs_per_slice
,
ctx
->
blocks
[
0
],
num_cblocks
,
plane_factor
,
qmat
);
}
else
{
get_alpha_data
(
ctx
,
src
,
linesize
,
xp
,
yp
,
pwidth
,
avctx
->
height
/
ctx
->
pictures_per_frame
,
ctx
->
blocks
[
0
],
mbs_per_slice
,
ctx
->
alpha_bits
);
sizes
[
i
]
=
encode_alpha_plane
(
ctx
,
pb
,
src
,
linesize
,
mbs_per_slice
,
ctx
->
blocks
[
0
],
quant
);
}
total_size
+=
sizes
[
i
];
}
return
total_size
;
...
...
@@ -564,6 +678,66 @@ static int estimate_slice_plane(ProresContext *ctx, int *error, int plane,
return
FFALIGN
(
bits
,
8
);
}
static
int
est_alpha_diff
(
int
cur
,
int
prev
,
int
abits
)
{
const
int
mask
=
(
1
<<
abits
)
-
1
;
const
int
dbits
=
(
abits
==
8
)
?
4
:
7
;
const
int
dsize
=
1
<<
dbits
-
1
;
int
diff
=
cur
-
prev
;
diff
&=
mask
;
if
(
diff
>=
(
1
<<
abits
)
-
dsize
)
diff
-=
1
<<
abits
;
if
(
diff
<
-
dsize
||
diff
>
dsize
||
!
diff
)
return
abits
+
1
;
else
return
dbits
+
1
;
}
static
int
estimate_alpha_plane
(
ProresContext
*
ctx
,
int
*
error
,
const
uint16_t
*
src
,
int
linesize
,
int
mbs_per_slice
,
int
quant
,
int16_t
*
blocks
)
{
const
int
abits
=
ctx
->
alpha_bits
;
const
int
mask
=
(
1
<<
abits
)
-
1
;
const
int
num_coeffs
=
mbs_per_slice
*
256
;
int
prev
=
mask
,
cur
;
int
idx
=
0
;
int
run
=
0
;
int
bits
;
*
error
=
0
;
cur
=
blocks
[
idx
++
];
bits
=
est_alpha_diff
(
cur
,
prev
,
abits
);
prev
=
cur
;
do
{
cur
=
blocks
[
idx
++
];
if
(
cur
!=
prev
)
{
if
(
!
run
)
bits
++
;
else
if
(
run
<
0x10
)
bits
+=
4
;
else
bits
+=
15
;
bits
+=
est_alpha_diff
(
cur
,
prev
,
abits
);
prev
=
cur
;
run
=
0
;
}
else
{
run
++
;
}
}
while
(
idx
<
num_coeffs
);
if
(
run
)
{
if
(
run
<
0x10
)
bits
+=
4
;
else
bits
+=
15
;
}
return
bits
;
}
static
int
find_slice_quant
(
AVCodecContext
*
avctx
,
const
AVFrame
*
pic
,
int
trellis_node
,
int
x
,
int
y
,
int
mbs_per_slice
,
ProresThreadData
*
td
)
...
...
@@ -610,10 +784,16 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
src
=
(
const
uint16_t
*
)(
pic
->
data
[
i
]
+
yp
*
linesize
[
i
]
+
line_add
*
pic
->
linesize
[
i
])
+
xp
;
get_slice_data
(
ctx
,
src
,
linesize
[
i
],
xp
,
yp
,
pwidth
,
avctx
->
height
/
ctx
->
pictures_per_frame
,
td
->
blocks
[
i
],
td
->
emu_buf
,
mbs_per_slice
,
num_cblocks
[
i
],
is_chroma
[
i
]);
if
(
i
<
3
)
{
get_slice_data
(
ctx
,
src
,
linesize
[
i
],
xp
,
yp
,
pwidth
,
avctx
->
height
/
ctx
->
pictures_per_frame
,
td
->
blocks
[
i
],
td
->
emu_buf
,
mbs_per_slice
,
num_cblocks
[
i
],
is_chroma
[
i
]);
}
else
{
get_alpha_data
(
ctx
,
src
,
linesize
[
i
],
xp
,
yp
,
pwidth
,
avctx
->
height
/
ctx
->
pictures_per_frame
,
td
->
blocks
[
i
],
mbs_per_slice
,
ctx
->
alpha_bits
);
}
}
for
(
q
=
min_quant
;
q
<
max_quant
+
2
;
q
++
)
{
...
...
@@ -625,13 +805,16 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
for
(
q
=
min_quant
;
q
<=
max_quant
;
q
++
)
{
bits
=
0
;
error
=
0
;
for
(
i
=
0
;
i
<
ctx
->
num_planes
;
i
++
)
{
for
(
i
=
0
;
i
<
ctx
->
num_planes
-
!!
ctx
->
alpha_bits
;
i
++
)
{
bits
+=
estimate_slice_plane
(
ctx
,
&
error
,
i
,
src
,
linesize
[
i
],
mbs_per_slice
,
num_cblocks
[
i
],
plane_factor
[
i
],
ctx
->
quants
[
q
],
td
);
}
if
(
ctx
->
alpha_bits
)
bits
+=
estimate_alpha_plane
(
ctx
,
&
error
,
src
,
linesize
[
3
],
mbs_per_slice
,
q
,
td
->
blocks
[
3
]);
if
(
bits
>
65000
*
8
)
{
error
=
SCORE_LIMIT
;
break
;
...
...
@@ -654,13 +837,16 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
for
(
i
=
0
;
i
<
64
;
i
++
)
qmat
[
i
]
=
ctx
->
quant_mat
[
i
]
*
q
;
}
for
(
i
=
0
;
i
<
ctx
->
num_planes
;
i
++
)
{
for
(
i
=
0
;
i
<
ctx
->
num_planes
-
!!
ctx
->
alpha_bits
;
i
++
)
{
bits
+=
estimate_slice_plane
(
ctx
,
&
error
,
i
,
src
,
linesize
[
i
],
mbs_per_slice
,
num_cblocks
[
i
],
plane_factor
[
i
],
qmat
,
td
);
}
if
(
ctx
->
alpha_bits
)
bits
+=
estimate_alpha_plane
(
ctx
,
&
error
,
src
,
linesize
[
3
],
mbs_per_slice
,
q
,
td
->
blocks
[
3
]);
if
(
bits
<=
ctx
->
bits_per_mb
*
mbs_per_slice
)
break
;
}
...
...
@@ -782,7 +968,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
bytestream_put_byte
(
&
buf
,
avctx
->
color_primaries
);
bytestream_put_byte
(
&
buf
,
avctx
->
color_trc
);
bytestream_put_byte
(
&
buf
,
avctx
->
colorspace
);
bytestream_put_byte
(
&
buf
,
0x40
);
// source format and alpha information
bytestream_put_byte
(
&
buf
,
0x40
|
(
ctx
->
alpha_bits
>>
3
));
bytestream_put_byte
(
&
buf
,
0
);
// reserved
if
(
ctx
->
quant_sel
!=
QUANT_MAT_DEFAULT
)
{
bytestream_put_byte
(
&
buf
,
0x03
);
// matrix flags - both matrices are present
...
...
@@ -904,12 +1090,20 @@ static av_cold int encode_init(AVCodecContext *avctx)
"there should be an integer power of two MBs per slice
\n
"
);
return
AVERROR
(
EINVAL
);
}
if
(
av_pix_fmt_desc_get
(
avctx
->
pix_fmt
)
->
flags
&
AV_PIX_FMT_FLAG_ALPHA
)
{
if
(
ctx
->
alpha_bits
&
7
)
{
av_log
(
avctx
,
AV_LOG_ERROR
,
"alpha bits should be 0, 8 or 16
\n
"
);
return
AVERROR
(
EINVAL
);
}
}
else
{
ctx
->
alpha_bits
=
0
;
}
ctx
->
chroma_factor
=
avctx
->
pix_fmt
==
AV_PIX_FMT_YUV422P10
?
CFACTOR_Y422
:
CFACTOR_Y444
;
ctx
->
profile_info
=
prores_profile_info
+
ctx
->
profile
;
ctx
->
num_planes
=
3
;
ctx
->
num_planes
=
3
+
!!
ctx
->
alpha_bits
;
ctx
->
mb_width
=
FFALIGN
(
avctx
->
width
,
16
)
>>
4
;
...
...
@@ -1025,7 +1219,7 @@ static const AVOption options[] = {
AV_OPT_TYPE_INT
,
{
.
i64
=
8
},
1
,
MAX_MBS_PER_SLICE
,
VE
},
{
"profile"
,
NULL
,
OFFSET
(
profile
),
AV_OPT_TYPE_INT
,
{
.
i64
=
PRORES_PROFILE_STANDARD
},
PRORES_PROFILE_PROXY
,
PRORES_PROFILE_
HQ
,
VE
,
"profile"
},
PRORES_PROFILE_PROXY
,
PRORES_PROFILE_
4444
,
VE
,
"profile"
},
{
"proxy"
,
NULL
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
PRORES_PROFILE_PROXY
},
0
,
0
,
VE
,
"profile"
},
{
"lt"
,
NULL
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
PRORES_PROFILE_LT
},
...
...
@@ -1034,6 +1228,8 @@ static const AVOption options[] = {
0
,
0
,
VE
,
"profile"
},
{
"hq"
,
NULL
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
PRORES_PROFILE_HQ
},
0
,
0
,
VE
,
"profile"
},
{
"4444"
,
NULL
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
PRORES_PROFILE_4444
},
0
,
0
,
VE
,
"profile"
},
{
"vendor"
,
"vendor ID"
,
OFFSET
(
vendor
),
AV_OPT_TYPE_STRING
,
{
.
str
=
"Lavc"
},
CHAR_MIN
,
CHAR_MAX
,
VE
},
{
"bits_per_mb"
,
"desired bits per macroblock"
,
OFFSET
(
bits_per_mb
),
...
...
@@ -1052,6 +1248,8 @@ static const AVOption options[] = {
0
,
0
,
VE
,
"quant_mat"
},
{
"default"
,
NULL
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
QUANT_MAT_DEFAULT
},
0
,
0
,
VE
,
"quant_mat"
},
{
"alpha_bits"
,
"bits for alpha plane"
,
OFFSET
(
alpha_bits
),
AV_OPT_TYPE_INT
,
{
.
i64
=
16
},
0
,
16
,
VE
},
{
NULL
}
};
...
...
@@ -1073,7 +1271,8 @@ AVCodec ff_prores_encoder = {
.
capabilities
=
CODEC_CAP_SLICE_THREADS
,
.
long_name
=
NULL_IF_CONFIG_SMALL
(
"Apple ProRes (iCodec Pro)"
),
.
pix_fmts
=
(
const
enum
AVPixelFormat
[])
{
AV_PIX_FMT_YUV422P10
,
AV_PIX_FMT_YUV444P10
,
AV_PIX_FMT_NONE
AV_PIX_FMT_YUV422P10
,
AV_PIX_FMT_YUV444P10
,
AV_PIX_FMT_YUVA444P10
,
AV_PIX_FMT_NONE
},
.
priv_class
=
&
proresenc_class
,
};
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