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
4ab56667
Commit
4ab56667
authored
Jul 20, 2015
by
Rodger Combs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lavf/mov: add support for sidx fragment indexes
Fixes trac #3842
parent
cd847839
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
208 additions
and
39 deletions
+208
-39
isom.h
libavformat/isom.h
+2
-0
mov.c
libavformat/mov.c
+206
-39
No files found.
libavformat/isom.h
View file @
4ab56667
...
@@ -103,6 +103,7 @@ typedef struct MOVSbgp {
...
@@ -103,6 +103,7 @@ typedef struct MOVSbgp {
typedef
struct
MOVFragmentIndexItem
{
typedef
struct
MOVFragmentIndexItem
{
int64_t
moof_offset
;
int64_t
moof_offset
;
int64_t
time
;
int64_t
time
;
int
headers_read
;
}
MOVFragmentIndexItem
;
}
MOVFragmentIndexItem
;
typedef
struct
MOVFragmentIndex
{
typedef
struct
MOVFragmentIndex
{
...
@@ -197,6 +198,7 @@ typedef struct MOVContext {
...
@@ -197,6 +198,7 @@ typedef struct MOVContext {
int
has_looked_for_mfra
;
int
has_looked_for_mfra
;
MOVFragmentIndex
**
fragment_index_data
;
MOVFragmentIndex
**
fragment_index_data
;
unsigned
fragment_index_count
;
unsigned
fragment_index_count
;
int
fragment_index_complete
;
int
atom_depth
;
int
atom_depth
;
unsigned
int
aax_mode
;
///< 'aax' file has been detected
unsigned
int
aax_mode
;
///< 'aax' file has been detected
uint8_t
file_key
[
20
];
uint8_t
file_key
[
20
];
...
...
libavformat/mov.c
View file @
4ab56667
...
@@ -3349,7 +3349,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
...
@@ -3349,7 +3349,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
MOVFragment
*
frag
=
&
c
->
fragment
;
MOVFragment
*
frag
=
&
c
->
fragment
;
MOVTrackExt
*
trex
=
NULL
;
MOVTrackExt
*
trex
=
NULL
;
MOVFragmentIndex
*
index
=
NULL
;
MOVFragmentIndex
*
index
=
NULL
;
int
flags
,
track_id
,
i
;
int
flags
,
track_id
,
i
,
found
=
0
;
avio_r8
(
pb
);
/* version */
avio_r8
(
pb
);
/* version */
flags
=
avio_rb24
(
pb
);
flags
=
avio_rb24
(
pb
);
...
@@ -3367,15 +3367,6 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
...
@@ -3367,15 +3367,6 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_log
(
c
->
fc
,
AV_LOG_ERROR
,
"could not find corresponding trex
\n
"
);
av_log
(
c
->
fc
,
AV_LOG_ERROR
,
"could not find corresponding trex
\n
"
);
return
AVERROR_INVALIDDATA
;
return
AVERROR_INVALIDDATA
;
}
}
for
(
i
=
0
;
i
<
c
->
fragment_index_count
;
i
++
)
{
MOVFragmentIndex
*
candidate
=
c
->
fragment_index_data
[
i
];
if
(
candidate
->
track_id
==
frag
->
track_id
)
{
av_log
(
c
->
fc
,
AV_LOG_DEBUG
,
"found fragment index for track %u
\n
"
,
frag
->
track_id
);
index
=
candidate
;
break
;
}
}
frag
->
base_data_offset
=
flags
&
MOV_TFHD_BASE_DATA_OFFSET
?
frag
->
base_data_offset
=
flags
&
MOV_TFHD_BASE_DATA_OFFSET
?
avio_rb64
(
pb
)
:
flags
&
MOV_TFHD_DEFAULT_BASE_IS_MOOF
?
avio_rb64
(
pb
)
:
flags
&
MOV_TFHD_DEFAULT_BASE_IS_MOOF
?
...
@@ -3389,24 +3380,33 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
...
@@ -3389,24 +3380,33 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
frag
->
flags
=
flags
&
MOV_TFHD_DEFAULT_FLAGS
?
frag
->
flags
=
flags
&
MOV_TFHD_DEFAULT_FLAGS
?
avio_rb32
(
pb
)
:
trex
->
flags
;
avio_rb32
(
pb
)
:
trex
->
flags
;
frag
->
time
=
AV_NOPTS_VALUE
;
frag
->
time
=
AV_NOPTS_VALUE
;
if
(
index
)
{
for
(
i
=
0
;
i
<
c
->
fragment_index_count
;
i
++
)
{
int
i
,
found
=
0
;
int
j
;
for
(
i
=
index
->
current_item
;
i
<
index
->
item_count
;
i
++
)
{
MOVFragmentIndex
*
candidate
=
c
->
fragment_index_data
[
i
];
if
(
frag
->
implicit_offset
==
index
->
items
[
i
].
moof_offset
)
{
if
(
candidate
->
track_id
==
frag
->
track_id
)
{
av_log
(
c
->
fc
,
AV_LOG_DEBUG
,
"found fragment index entry "
av_log
(
c
->
fc
,
AV_LOG_DEBUG
,
"for track %u and moof_offset %"
PRId64
"
\n
"
,
"found fragment index for track %u
\n
"
,
frag
->
track_id
);
frag
->
track_id
,
index
->
items
[
i
].
moof_offset
);
index
=
candidate
;
frag
->
time
=
index
->
items
[
i
].
time
;
for
(
j
=
index
->
current_item
;
j
<
index
->
item_count
;
j
++
)
{
index
->
current_item
=
i
+
1
;
if
(
frag
->
implicit_offset
==
index
->
items
[
j
].
moof_offset
)
{
found
=
1
;
av_log
(
c
->
fc
,
AV_LOG_DEBUG
,
"found fragment index entry "
"for track %u and moof_offset %"
PRId64
"
\n
"
,
frag
->
track_id
,
index
->
items
[
j
].
moof_offset
);
frag
->
time
=
index
->
items
[
j
].
time
;
index
->
current_item
=
j
+
1
;
found
=
1
;
break
;
}
}
}
}
if
(
found
)
if
(
!
found
)
{
break
;
av_log
(
c
->
fc
,
AV_LOG_WARNING
,
"track %u has a fragment index "
"but it doesn't have an (in-order) entry for moof_offset "
"%"
PRId64
"
\n
"
,
frag
->
track_id
,
frag
->
implicit_offset
);
}
}
}
}
if
(
index
&&
!
found
)
{
av_log
(
c
->
fc
,
AV_LOG_DEBUG
,
"track %u has a fragment index but "
"it doesn't have an (in-order) entry for moof_offset "
"%"
PRId64
"
\n
"
,
frag
->
track_id
,
frag
->
implicit_offset
);
}
av_log
(
c
->
fc
,
AV_LOG_TRACE
,
"frag flags 0x%x
\n
"
,
frag
->
flags
);
av_log
(
c
->
fc
,
AV_LOG_TRACE
,
"frag flags 0x%x
\n
"
,
frag
->
flags
);
return
0
;
return
0
;
}
}
...
@@ -3596,7 +3596,106 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
...
@@ -3596,7 +3596,106 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return
AVERROR_EOF
;
return
AVERROR_EOF
;
frag
->
implicit_offset
=
offset
;
frag
->
implicit_offset
=
offset
;
st
->
duration
=
sc
->
track_end
=
dts
+
sc
->
time_offset
;
sc
->
track_end
=
dts
+
sc
->
time_offset
;
if
(
st
->
duration
<
sc
->
track_end
)
st
->
duration
=
sc
->
track_end
;
return
0
;
}
static
int
mov_read_sidx
(
MOVContext
*
c
,
AVIOContext
*
pb
,
MOVAtom
atom
)
{
int64_t
offset
=
avio_tell
(
pb
)
+
atom
.
size
,
pts
;
uint8_t
version
;
unsigned
i
,
track_id
;
AVStream
*
st
=
NULL
;
MOVStreamContext
*
sc
;
MOVFragmentIndex
*
index
=
NULL
;
MOVFragmentIndex
**
tmp
;
AVRational
timescale
;
version
=
avio_r8
(
pb
);
if
(
version
>
1
)
{
avpriv_request_sample
(
c
->
fc
,
"sidx version %u"
,
version
);
return
AVERROR_PATCHWELCOME
;
}
avio_rb24
(
pb
);
// flags
track_id
=
avio_rb32
(
pb
);
// Reference ID
for
(
i
=
0
;
i
<
c
->
fc
->
nb_streams
;
i
++
)
{
if
(
c
->
fc
->
streams
[
i
]
->
id
==
track_id
)
{
st
=
c
->
fc
->
streams
[
i
];
break
;
}
}
if
(
!
st
)
{
av_log
(
c
->
fc
,
AV_LOG_ERROR
,
"could not find corresponding track id %d
\n
"
,
track_id
);
return
AVERROR_INVALIDDATA
;
}
sc
=
st
->
priv_data
;
timescale
=
av_make_q
(
1
,
avio_rb32
(
pb
));
if
(
version
==
0
)
{
pts
=
avio_rb32
(
pb
);
offset
+=
avio_rb32
(
pb
);
}
else
{
pts
=
avio_rb64
(
pb
);
offset
+=
avio_rb64
(
pb
);
}
avio_rb16
(
pb
);
// reserved
index
=
av_mallocz
(
sizeof
(
MOVFragmentIndex
));
if
(
!
index
)
return
AVERROR
(
ENOMEM
);
index
->
track_id
=
track_id
;
index
->
item_count
=
avio_rb16
(
pb
);
index
->
items
=
av_mallocz_array
(
index
->
item_count
,
sizeof
(
MOVFragmentIndexItem
));
if
(
!
index
->
items
)
{
av_freep
(
&
index
);
return
AVERROR
(
ENOMEM
);
}
for
(
i
=
0
;
i
<
index
->
item_count
;
i
++
)
{
uint32_t
size
=
avio_rb32
(
pb
);
uint32_t
duration
=
avio_rb32
(
pb
);
if
(
size
&
0x80000000
)
{
avpriv_request_sample
(
c
->
fc
,
"sidx reference_type 1"
);
av_freep
(
&
index
->
items
);
av_freep
(
&
index
);
return
AVERROR_PATCHWELCOME
;
}
avio_rb32
(
pb
);
// sap_flags
index
->
items
[
i
].
moof_offset
=
offset
;
index
->
items
[
i
].
time
=
av_rescale_q
(
pts
,
st
->
time_base
,
timescale
);
offset
+=
size
;
pts
+=
duration
;
}
st
->
duration
=
sc
->
track_end
=
pts
;
tmp
=
av_realloc_array
(
c
->
fragment_index_data
,
c
->
fragment_index_count
+
1
,
sizeof
(
MOVFragmentIndex
*
));
if
(
!
tmp
)
{
av_freep
(
&
index
->
items
);
av_freep
(
&
index
);
return
AVERROR
(
ENOMEM
);
}
c
->
fragment_index_data
=
tmp
;
c
->
fragment_index_data
[
c
->
fragment_index_count
++
]
=
index
;
if
(
offset
==
avio_size
(
pb
))
c
->
fragment_index_complete
=
1
;
return
0
;
return
0
;
}
}
...
@@ -3854,6 +3953,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
...
@@ -3854,6 +3953,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{
MKTAG
(
'a'
,
'l'
,
'a'
,
'c'
),
mov_read_alac
},
/* alac specific atom */
{
MKTAG
(
'a'
,
'l'
,
'a'
,
'c'
),
mov_read_alac
},
/* alac specific atom */
{
MKTAG
(
'a'
,
'v'
,
'c'
,
'C'
),
mov_read_glbl
},
{
MKTAG
(
'a'
,
'v'
,
'c'
,
'C'
),
mov_read_glbl
},
{
MKTAG
(
'p'
,
'a'
,
's'
,
'p'
),
mov_read_pasp
},
{
MKTAG
(
'p'
,
'a'
,
's'
,
'p'
),
mov_read_pasp
},
{
MKTAG
(
's'
,
'i'
,
'd'
,
'x'
),
mov_read_sidx
},
{
MKTAG
(
's'
,
't'
,
'b'
,
'l'
),
mov_read_default
},
{
MKTAG
(
's'
,
't'
,
'b'
,
'l'
),
mov_read_default
},
{
MKTAG
(
's'
,
't'
,
'c'
,
'o'
),
mov_read_stco
},
{
MKTAG
(
's'
,
't'
,
'c'
,
'o'
),
mov_read_stco
},
{
MKTAG
(
's'
,
't'
,
'p'
,
's'
),
mov_read_stps
},
{
MKTAG
(
's'
,
't'
,
'p'
,
's'
),
mov_read_stps
},
...
@@ -3978,9 +4078,9 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
...
@@ -3978,9 +4078,9 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return
err
;
return
err
;
}
}
if
(
c
->
found_moov
&&
c
->
found_mdat
&&
if
(
c
->
found_moov
&&
c
->
found_mdat
&&
((
!
pb
->
seekable
||
c
->
fc
->
flags
&
AVFMT_FLAG_IGNIDX
)
||
((
!
pb
->
seekable
||
c
->
fc
->
flags
&
AVFMT_FLAG_IGNIDX
||
c
->
fragment_index_complete
)
||
start_pos
+
a
.
size
==
avio_size
(
pb
)))
{
start_pos
+
a
.
size
==
avio_size
(
pb
)))
{
if
(
!
pb
->
seekable
||
c
->
fc
->
flags
&
AVFMT_FLAG_IGNIDX
)
if
(
!
pb
->
seekable
||
c
->
fc
->
flags
&
AVFMT_FLAG_IGNIDX
||
c
->
fragment_index_complete
)
c
->
next_root_atom
=
start_pos
+
a
.
size
;
c
->
next_root_atom
=
start_pos
+
a
.
size
;
c
->
atom_depth
--
;
c
->
atom_depth
--
;
return
0
;
return
0
;
...
@@ -4585,6 +4685,52 @@ static int should_retry(AVIOContext *pb, int error_code) {
...
@@ -4585,6 +4685,52 @@ static int should_retry(AVIOContext *pb, int error_code) {
return
1
;
return
1
;
}
}
static
int
mov_switch_root
(
AVFormatContext
*
s
,
int64_t
target
)
{
MOVContext
*
mov
=
s
->
priv_data
;
int
i
,
j
;
int
already_read
=
0
;
if
(
avio_seek
(
s
->
pb
,
target
,
SEEK_SET
)
!=
target
)
{
av_log
(
mov
->
fc
,
AV_LOG_ERROR
,
"root atom offset 0x%"
PRIx64
": partial file
\n
"
,
target
);
return
AVERROR_INVALIDDATA
;
}
mov
->
next_root_atom
=
0
;
for
(
i
=
0
;
i
<
mov
->
fragment_index_count
;
i
++
)
{
MOVFragmentIndex
*
index
=
mov
->
fragment_index_data
[
i
];
int
found
=
0
;
for
(
j
=
0
;
j
<
index
->
item_count
;
j
++
)
{
MOVFragmentIndexItem
*
item
=
&
index
->
items
[
j
];
if
(
found
)
{
mov
->
next_root_atom
=
item
->
moof_offset
;
break
;
// Advance to next index in outer loop
}
else
if
(
item
->
moof_offset
==
target
)
{
index
->
current_item
=
FFMIN
(
j
,
index
->
current_item
);
if
(
item
->
headers_read
)
already_read
=
1
;
item
->
headers_read
=
1
;
found
=
1
;
}
}
if
(
!
found
)
index
->
current_item
=
0
;
}
if
(
already_read
)
return
0
;
mov
->
found_mdat
=
0
;
if
(
mov_read_default
(
mov
,
s
->
pb
,
(
MOVAtom
){
AV_RL32
(
"root"
),
INT64_MAX
})
<
0
||
avio_feof
(
s
->
pb
))
return
AVERROR_EOF
;
av_log
(
s
,
AV_LOG_TRACE
,
"read fragments, offset 0x%"
PRIx64
"
\n
"
,
avio_tell
(
s
->
pb
));
return
1
;
}
static
int
mov_read_packet
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
static
int
mov_read_packet
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
{
{
MOVContext
*
mov
=
s
->
priv_data
;
MOVContext
*
mov
=
s
->
priv_data
;
...
@@ -4595,19 +4741,11 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
...
@@ -4595,19 +4741,11 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
mov
->
fc
=
s
;
mov
->
fc
=
s
;
retry:
retry:
sample
=
mov_find_next_sample
(
s
,
&
st
);
sample
=
mov_find_next_sample
(
s
,
&
st
);
if
(
!
sample
)
{
if
(
!
sample
||
(
mov
->
next_root_atom
&&
sample
->
pos
>
mov
->
next_root_atom
))
{
mov
->
found_mdat
=
0
;
if
(
!
mov
->
next_root_atom
)
if
(
!
mov
->
next_root_atom
)
return
AVERROR_EOF
;
return
AVERROR_EOF
;
if
(
avio_seek
(
s
->
pb
,
mov
->
next_root_atom
,
SEEK_SET
)
!=
mov
->
next_root_atom
)
{
if
((
ret
=
mov_switch_root
(
s
,
mov
->
next_root_atom
))
<
0
)
av_log
(
mov
->
fc
,
AV_LOG_ERROR
,
"next root atom offset 0x%"
PRIx64
": partial file
\n
"
,
mov
->
next_root_atom
);
return
ret
;
return
AVERROR_INVALIDDATA
;
}
mov
->
next_root_atom
=
0
;
if
(
mov_read_default
(
mov
,
s
->
pb
,
(
MOVAtom
){
AV_RL32
(
"root"
),
INT64_MAX
})
<
0
||
avio_feof
(
s
->
pb
))
return
AVERROR_EOF
;
av_log
(
s
,
AV_LOG_TRACE
,
"read fragments, offset 0x%"
PRIx64
"
\n
"
,
avio_tell
(
s
->
pb
));
goto
retry
;
goto
retry
;
}
}
sc
=
st
->
priv_data
;
sc
=
st
->
priv_data
;
...
@@ -4685,12 +4823,41 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
...
@@ -4685,12 +4823,41 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
return
0
;
return
0
;
}
}
static
int
mov_seek_fragment
(
AVFormatContext
*
s
,
AVStream
*
st
,
int64_t
timestamp
)
{
MOVContext
*
mov
=
s
->
priv_data
;
int
i
,
j
;
if
(
!
mov
->
fragment_index_complete
)
return
0
;
for
(
i
=
0
;
i
<
mov
->
fragment_index_count
;
i
++
)
{
if
(
mov
->
fragment_index_data
[
i
]
->
track_id
==
st
->
id
)
{
MOVFragmentIndex
*
index
=
index
=
mov
->
fragment_index_data
[
i
];
for
(
j
=
index
->
item_count
-
1
;
j
>=
0
;
j
--
)
{
if
(
index
->
items
[
j
].
time
<=
timestamp
)
{
if
(
index
->
items
[
j
].
headers_read
)
return
0
;
return
mov_switch_root
(
s
,
index
->
items
[
j
].
moof_offset
);
}
}
}
}
return
0
;
}
static
int
mov_seek_stream
(
AVFormatContext
*
s
,
AVStream
*
st
,
int64_t
timestamp
,
int
flags
)
static
int
mov_seek_stream
(
AVFormatContext
*
s
,
AVStream
*
st
,
int64_t
timestamp
,
int
flags
)
{
{
MOVStreamContext
*
sc
=
st
->
priv_data
;
MOVStreamContext
*
sc
=
st
->
priv_data
;
int
sample
,
time_sample
;
int
sample
,
time_sample
;
int
i
;
int
i
;
int
ret
=
mov_seek_fragment
(
s
,
st
,
timestamp
);
if
(
ret
<
0
)
return
ret
;
sample
=
av_index_search_timestamp
(
st
,
timestamp
,
flags
);
sample
=
av_index_search_timestamp
(
st
,
timestamp
,
flags
);
av_log
(
s
,
AV_LOG_TRACE
,
"stream %d, timestamp %"
PRId64
", sample %d
\n
"
,
st
->
index
,
timestamp
,
sample
);
av_log
(
s
,
AV_LOG_TRACE
,
"stream %d, timestamp %"
PRId64
", sample %d
\n
"
,
st
->
index
,
timestamp
,
sample
);
if
(
sample
<
0
&&
st
->
nb_index_entries
&&
timestamp
<
st
->
index_entries
[
0
].
timestamp
)
if
(
sample
<
0
&&
st
->
nb_index_entries
&&
timestamp
<
st
->
index_entries
[
0
].
timestamp
)
...
...
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