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
d2a33f66
Commit
d2a33f66
authored
Jan 10, 2020
by
James Almer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avformat/dashenc: add Trick Mode support for AdaptationSets
Signed-off-by:
James Almer
<
jamrial@gmail.com
>
parent
4d27def5
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
64 additions
and
11 deletions
+64
-11
muxers.texi
doc/muxers.texi
+2
-0
dashenc.c
libavformat/dashenc.c
+61
-10
version.h
libavformat/version.h
+1
-1
No files found.
doc/muxers.texi
View file @
d2a33f66
...
@@ -286,6 +286,8 @@ For example, -adaptation_sets "id=0,descriptor=<SupplementalProperty schemeIdUri
...
@@ -286,6 +286,8 @@ For example, -adaptation_sets "id=0,descriptor=<SupplementalProperty schemeIdUri
Please note that descriptor string should be a self-closing xml tag.
Please note that descriptor string should be a self-closing xml tag.
seg_duration, frag_duration and frag_type override the global option values for each adaptation set.
seg_duration, frag_duration and frag_type override the global option values for each adaptation set.
For example, -adaptation_sets "id=0,seg_duration=2,frag_duration=1,frag_type=duration,streams=v id=1,seg_duration=2,frag_type=none,streams=a"
For example, -adaptation_sets "id=0,seg_duration=2,frag_duration=1,frag_type=duration,streams=v id=1,seg_duration=2,frag_type=none,streams=a"
type_id marks an adaptation set as containing streams meant to be used for Trick Mode for the referenced adaptation set.
For example, -adaptation_sets "id=0,seg_duration=2,frag_type=none,streams=0 id=1,seg_duration=10,frag_type=none,trick_id=0,streams=1"
@item timeout @var{timeout}
@item timeout @var{timeout}
Set timeout for socket I/O operations. Applicable only for HTTP output.
Set timeout for socket I/O operations. Applicable only for HTTP output.
@item index_correction @var{index_correction}
@item index_correction @var{index_correction}
...
...
libavformat/dashenc.c
View file @
d2a33f66
...
@@ -93,6 +93,7 @@ typedef struct AdaptationSet {
...
@@ -93,6 +93,7 @@ typedef struct AdaptationSet {
int
max_width
,
max_height
;
int
max_width
,
max_height
;
int
nb_streams
;
int
nb_streams
;
AVRational
par
;
AVRational
par
;
int
trick_idx
;
}
AdaptationSet
;
}
AdaptationSet
;
typedef
struct
OutputStream
{
typedef
struct
OutputStream
{
...
@@ -135,6 +136,7 @@ typedef struct OutputStream {
...
@@ -135,6 +136,7 @@ typedef struct OutputStream {
int
frag_type
;
int
frag_type
;
int64_t
gop_size
;
int64_t
gop_size
;
AVRational
sar
;
AVRational
sar
;
int
coding_dependency
;
}
OutputStream
;
}
OutputStream
;
typedef
struct
DASHContext
{
typedef
struct
DASHContext
{
...
@@ -819,6 +821,8 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
...
@@ -819,6 +821,8 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
if
(
!
final
&&
c
->
ldash
&&
as
->
max_frag_duration
)
if
(
!
final
&&
c
->
ldash
&&
as
->
max_frag_duration
)
avio_printf
(
out
,
"
\t\t\t
<Resync dT=
\"
%"
PRId64
"
\"
type=
\"
0
\"
/>
\n
"
,
as
->
max_frag_duration
);
avio_printf
(
out
,
"
\t\t\t
<Resync dT=
\"
%"
PRId64
"
\"
type=
\"
0
\"
/>
\n
"
,
as
->
max_frag_duration
);
if
(
as
->
trick_idx
>=
0
)
avio_printf
(
out
,
"
\t\t\t
<EssentialProperty id=
\"
%d
\"
schemeIdUri=
\"
http://dashif.org/guidelines/trickmode
\"
value=
\"
%d
\"
/>
\n
"
,
as
->
id
,
as
->
trick_idx
);
role
=
av_dict_get
(
as
->
metadata
,
"role"
,
NULL
,
0
);
role
=
av_dict_get
(
as
->
metadata
,
"role"
,
NULL
,
0
);
if
(
role
)
if
(
role
)
avio_printf
(
out
,
"
\t\t\t
<Role schemeIdUri=
\"
urn:mpeg:dash:role:2011
\"
value=
\"
%s
\"
/>
\n
"
,
role
->
value
);
avio_printf
(
out
,
"
\t\t\t
<Role schemeIdUri=
\"
urn:mpeg:dash:role:2011
\"
value=
\"
%s
\"
/>
\n
"
,
role
->
value
);
...
@@ -846,6 +850,13 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
...
@@ -846,6 +850,13 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
avio_printf
(
out
,
" sar=
\"
%d:%d
\"
"
,
os
->
sar
.
num
,
os
->
sar
.
den
);
avio_printf
(
out
,
" sar=
\"
%d:%d
\"
"
,
os
->
sar
.
num
,
os
->
sar
.
den
);
if
(
st
->
avg_frame_rate
.
num
&&
av_cmp_q
(
as
->
min_frame_rate
,
as
->
max_frame_rate
)
<
0
)
if
(
st
->
avg_frame_rate
.
num
&&
av_cmp_q
(
as
->
min_frame_rate
,
as
->
max_frame_rate
)
<
0
)
avio_printf
(
out
,
" frameRate=
\"
%d/%d
\"
"
,
st
->
avg_frame_rate
.
num
,
st
->
avg_frame_rate
.
den
);
avio_printf
(
out
,
" frameRate=
\"
%d/%d
\"
"
,
st
->
avg_frame_rate
.
num
,
st
->
avg_frame_rate
.
den
);
if
(
as
->
trick_idx
>=
0
)
{
AdaptationSet
*
tas
=
&
c
->
as
[
as
->
trick_idx
];
if
(
!
as
->
ambiguous_frame_rate
&&
!
tas
->
ambiguous_frame_rate
)
avio_printf
(
out
,
" maxPlayoutRate=
\"
%d
\"
"
,
FFMAX
((
int
)
av_q2d
(
av_div_q
(
tas
->
min_frame_rate
,
as
->
min_frame_rate
)),
1
));
}
if
(
!
os
->
coding_dependency
)
avio_printf
(
out
,
" codingDependency=
\"
false
\"
"
);
avio_printf
(
out
,
">
\n
"
);
avio_printf
(
out
,
">
\n
"
);
}
else
{
}
else
{
avio_printf
(
out
,
"
\t\t\t
<Representation id=
\"
%d
\"
mimeType=
\"
audio/%s
\"
codecs=
\"
%s
\"
%s audioSamplingRate=
\"
%d
\"
>
\n
"
,
avio_printf
(
out
,
"
\t\t\t
<Representation id=
\"
%d
\"
mimeType=
\"
audio/%s
\"
codecs=
\"
%s
\"
%s audioSamplingRate=
\"
%d
\"
>
\n
"
,
...
@@ -889,6 +900,7 @@ static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMed
...
@@ -889,6 +900,7 @@ static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMed
memset
(
*
as
,
0
,
sizeof
(
**
as
));
memset
(
*
as
,
0
,
sizeof
(
**
as
));
(
*
as
)
->
media_type
=
type
;
(
*
as
)
->
media_type
=
type
;
(
*
as
)
->
frag_type
=
-
1
;
(
*
as
)
->
frag_type
=
-
1
;
(
*
as
)
->
trick_idx
=
-
1
;
return
0
;
return
0
;
}
}
...
@@ -939,7 +951,8 @@ static int parse_adaptation_sets(AVFormatContext *s)
...
@@ -939,7 +951,8 @@ static int parse_adaptation_sets(AVFormatContext *s)
// syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
// syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
// option id=0,descriptor=descriptor_str,streams=0,1,2 and so on
// option id=0,descriptor=descriptor_str,streams=0,1,2 and so on
// option id=0,seg_duration=2.5,frag_duration=0.5,streams=0,1,2 and so on
// option id=0,seg_duration=2.5,frag_duration=0.5,streams=0,1,2
// id=1,trick_id=0,seg_duration=10,frag_type=none,streams=3 and so on
// descriptor is useful to the scheme defined by ISO/IEC 23009-1:2014/Amd.2:2015
// descriptor is useful to the scheme defined by ISO/IEC 23009-1:2014/Amd.2:2015
// descriptor_str should be a self-closing xml tag.
// descriptor_str should be a self-closing xml tag.
// seg_duration and frag_duration have the same syntax as the global options of
// seg_duration and frag_duration have the same syntax as the global options of
...
@@ -1025,6 +1038,20 @@ static int parse_adaptation_sets(AVFormatContext *s)
...
@@ -1025,6 +1038,20 @@ static int parse_adaptation_sets(AVFormatContext *s)
return
AVERROR
(
EINVAL
);
return
AVERROR
(
EINVAL
);
}
}
p
+=
n
;
p
+=
n
;
if
(
*
p
)
p
++
;
state
=
parse_default
;
}
else
if
((
state
!=
new_set
)
&&
av_strstart
(
p
,
"trick_id="
,
&
p
))
{
char
trick_id_str
[
10
],
*
end_str
;
n
=
strcspn
(
p
,
","
);
snprintf
(
trick_id_str
,
sizeof
(
trick_id_str
),
"%.*s"
,
n
,
p
);
p
+=
n
;
as
->
trick_idx
=
strtol
(
trick_id_str
,
&
end_str
,
10
);
if
(
trick_id_str
==
end_str
||
as
->
trick_idx
<
0
)
return
AVERROR
(
EINVAL
);
if
(
*
p
)
if
(
*
p
)
p
++
;
p
++
;
state
=
parse_default
;
state
=
parse_default
;
...
@@ -1086,6 +1113,22 @@ end:
...
@@ -1086,6 +1113,22 @@ end:
return
AVERROR
(
EINVAL
);
return
AVERROR
(
EINVAL
);
}
}
}
}
// check references for trick mode AdaptationSet
for
(
i
=
0
;
i
<
c
->
nb_as
;
i
++
)
{
as
=
&
c
->
as
[
i
];
if
(
as
->
trick_idx
<
0
)
continue
;
for
(
n
=
0
;
n
<
c
->
nb_as
;
n
++
)
{
if
(
c
->
as
[
n
].
id
==
as
->
trick_idx
)
break
;
}
if
(
n
>=
c
->
nb_as
)
{
av_log
(
s
,
AV_LOG_ERROR
,
"reference AdaptationSet id
\"
%d
\"
not found for trick mode AdaptationSet id
\"
%d
\"\n
"
,
as
->
trick_idx
,
as
->
id
);
return
AVERROR
(
EINVAL
);
}
}
return
0
;
return
0
;
}
}
...
@@ -1476,7 +1519,8 @@ static int dash_init(AVFormatContext *s)
...
@@ -1476,7 +1519,8 @@ static int dash_init(AVFormatContext *s)
return
ret
;
return
ret
;
// We only want to parse frame headers
// We only want to parse frame headers
os
->
parser
->
flags
|=
PARSER_FLAG_COMPLETE_FRAMES
;
os
->
parser
->
flags
|=
PARSER_FLAG_COMPLETE_FRAMES
;
}
}
else
os
->
coding_dependency
=
1
;
if
(
c
->
single_file
)
{
if
(
c
->
single_file
)
{
if
(
os
->
single_file_name
)
if
(
os
->
single_file_name
)
...
@@ -2014,6 +2058,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
...
@@ -2014,6 +2058,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
if
(
!
os
->
availability_time_offset
&&
if
(
!
os
->
availability_time_offset
&&
((
os
->
frag_type
==
FRAG_TYPE_DURATION
&&
os
->
seg_duration
!=
os
->
frag_duration
)
||
((
os
->
frag_type
==
FRAG_TYPE_DURATION
&&
os
->
seg_duration
!=
os
->
frag_duration
)
||
(
os
->
frag_type
==
FRAG_TYPE_EVERY_FRAME
&&
pkt
->
duration
)))
{
(
os
->
frag_type
==
FRAG_TYPE_EVERY_FRAME
&&
pkt
->
duration
)))
{
AdaptationSet
*
as
=
&
c
->
as
[
os
->
as_idx
-
1
];
int64_t
frame_duration
=
0
;
int64_t
frame_duration
=
0
;
switch
(
os
->
frag_type
)
{
switch
(
os
->
frag_type
)
{
...
@@ -2038,6 +2083,19 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
...
@@ -2038,6 +2083,19 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
seg_end_duration
=
os
->
seg_duration
;
seg_end_duration
=
os
->
seg_duration
;
}
}
if
(
os
->
parser
&&
(
os
->
frag_type
==
FRAG_TYPE_PFRAMES
||
as
->
trick_idx
>=
0
))
{
// Parse the packets only in scenarios where it's needed
uint8_t
*
data
;
int
size
;
av_parser_parse2
(
os
->
parser
,
os
->
parser_avctx
,
&
data
,
&
size
,
pkt
->
data
,
pkt
->
size
,
pkt
->
pts
,
pkt
->
dts
,
pkt
->
pos
);
os
->
coding_dependency
|=
os
->
parser
->
pict_type
!=
AV_PICTURE_TYPE_I
;
}
if
(
pkt
->
flags
&
AV_PKT_FLAG_KEY
&&
os
->
packets_written
&&
if
(
pkt
->
flags
&
AV_PKT_FLAG_KEY
&&
os
->
packets_written
&&
av_compare_ts
(
elapsed_duration
,
st
->
time_base
,
av_compare_ts
(
elapsed_duration
,
st
->
time_base
,
seg_end_duration
,
AV_TIME_BASE_Q
)
>=
0
)
{
seg_end_duration
,
AV_TIME_BASE_Q
)
>=
0
)
{
...
@@ -2085,14 +2143,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
...
@@ -2085,14 +2143,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
if
(
st
->
codecpar
->
codec_type
==
AVMEDIA_TYPE_VIDEO
&&
if
(
st
->
codecpar
->
codec_type
==
AVMEDIA_TYPE_VIDEO
&&
os
->
frag_type
==
FRAG_TYPE_PFRAMES
&&
os
->
frag_type
==
FRAG_TYPE_PFRAMES
&&
os
->
packets_written
)
{
os
->
packets_written
)
{
uint8_t
*
data
;
int
size
;
av_assert0
(
os
->
parser
);
av_assert0
(
os
->
parser
);
av_parser_parse2
(
os
->
parser
,
os
->
parser_avctx
,
&
data
,
&
size
,
pkt
->
data
,
pkt
->
size
,
pkt
->
pts
,
pkt
->
dts
,
pkt
->
pos
);
if
((
os
->
parser
->
pict_type
==
AV_PICTURE_TYPE_P
&&
if
((
os
->
parser
->
pict_type
==
AV_PICTURE_TYPE_P
&&
st
->
codecpar
->
video_delay
&&
st
->
codecpar
->
video_delay
&&
!
(
os
->
last_flags
&
AV_PKT_FLAG_KEY
))
||
!
(
os
->
last_flags
&
AV_PKT_FLAG_KEY
))
||
...
@@ -2111,7 +2162,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
...
@@ -2111,7 +2162,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
}
}
}
}
if
(
pkt
->
flags
&
AV_PKT_FLAG_KEY
&&
(
os
->
packets_written
||
os
->
nb_segments
)
&&
!
os
->
gop_size
)
{
if
(
pkt
->
flags
&
AV_PKT_FLAG_KEY
&&
(
os
->
packets_written
||
os
->
nb_segments
)
&&
!
os
->
gop_size
&&
as
->
trick_idx
<
0
)
{
os
->
gop_size
=
os
->
last_duration
+
av_rescale_q
(
os
->
total_pkt_duration
,
st
->
time_base
,
AV_TIME_BASE_Q
);
os
->
gop_size
=
os
->
last_duration
+
av_rescale_q
(
os
->
total_pkt_duration
,
st
->
time_base
,
AV_TIME_BASE_Q
);
c
->
max_gop_size
=
FFMAX
(
c
->
max_gop_size
,
os
->
gop_size
);
c
->
max_gop_size
=
FFMAX
(
c
->
max_gop_size
,
os
->
gop_size
);
}
}
...
...
libavformat/version.h
View file @
d2a33f66
...
@@ -33,7 +33,7 @@
...
@@ -33,7 +33,7 @@
// Also please add any ticket numbers that you believe might be affected here
// Also please add any ticket numbers that you believe might be affected here
#define LIBAVFORMAT_VERSION_MAJOR 58
#define LIBAVFORMAT_VERSION_MAJOR 58
#define LIBAVFORMAT_VERSION_MINOR 38
#define LIBAVFORMAT_VERSION_MINOR 38
#define LIBAVFORMAT_VERSION_MICRO 10
0
#define LIBAVFORMAT_VERSION_MICRO 10
1
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \
LIBAVFORMAT_VERSION_MINOR, \
...
...
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