Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
FFmpeg
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
libremedia
Tethys
FFmpeg
Commits
155e9ee9
Commit
155e9ee9
authored
21 years ago
by
Fabrice Bellard
Browse files
Options
Downloads
Patches
Plain Diff
initial seek support
Originally committed as revision 2502 to
svn://svn.ffmpeg.org/ffmpeg/trunk
parent
27f388aa
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
libavformat/avi.h
+3
-0
3 additions, 0 deletions
libavformat/avi.h
libavformat/avidec.c
+291
-26
291 additions, 26 deletions
libavformat/avidec.c
with
294 additions
and
26 deletions
libavformat/avi.h
+
3
−
0
View file @
155e9ee9
...
@@ -13,6 +13,9 @@
...
@@ -13,6 +13,9 @@
#define AVI_MAX_RIFF_SIZE 0x40000000LL
#define AVI_MAX_RIFF_SIZE 0x40000000LL
#define AVI_MASTER_INDEX_SIZE 256
#define AVI_MASTER_INDEX_SIZE 256
/* index flags */
#define AVIIF_INDEX 0x10
offset_t
start_tag
(
ByteIOContext
*
pb
,
const
char
*
tag
);
offset_t
start_tag
(
ByteIOContext
*
pb
,
const
char
*
tag
);
void
end_tag
(
ByteIOContext
*
pb
,
offset_t
start
);
void
end_tag
(
ByteIOContext
*
pb
,
offset_t
start
);
...
...
This diff is collapsed.
Click to expand it.
libavformat/avidec.c
+
291
−
26
View file @
155e9ee9
...
@@ -21,18 +21,33 @@
...
@@ -21,18 +21,33 @@
#include
"dv.h"
#include
"dv.h"
//#define DEBUG
//#define DEBUG
//#define DEBUG_SEEK
typedef
struct
AVIIndex
{
unsigned
char
tag
[
4
];
typedef
struct
AVIIndexEntry
{
unsigned
int
flags
,
pos
,
len
;
unsigned
int
flags
;
struct
AVIIndex
*
next
;
unsigned
int
pos
;
}
AVIIndex
;
unsigned
int
cum_len
;
/* sum of all lengths before this packet */
}
AVIIndexEntry
;
typedef
struct
AVIStream
{
AVIIndexEntry
*
index_entries
;
int
nb_index_entries
;
int
index_entries_allocated_size
;
int
frame_offset
;
/* current frame (video) or byte (audio) counter
(used to compute the pts) */
int
scale
;
int
rate
;
int
sample_size
;
/* audio only data */
int
new_frame_offset
;
/* temporary storage (used during seek) */
int
cum_len
;
/* temporary storage (used during seek) */
}
AVIStream
;
typedef
struct
{
typedef
struct
{
int64_t
riff_end
;
int64_t
riff_end
;
int64_t
movi_end
;
int64_t
movi_end
;
offset_t
movi_list
;
offset_t
movi_list
;
AVIIndex
*
first
,
*
last
;
int
index_loaded
;
DVDemuxContext
*
dv_demux
;
DVDemuxContext
*
dv_demux
;
}
AVIContext
;
}
AVIContext
;
...
@@ -74,8 +89,11 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
...
@@ -74,8 +89,11 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
unsigned
int
size
,
nb_frames
;
unsigned
int
size
,
nb_frames
;
int
i
,
n
;
int
i
,
n
;
AVStream
*
st
;
AVStream
*
st
;
AVIStream
*
ast
;
int
xan_video
=
0
;
/* hack to support Xan A/V */
int
xan_video
=
0
;
/* hack to support Xan A/V */
av_set_pts_info
(
s
,
64
,
1
,
AV_TIME_BASE
);
if
(
get_riff
(
avi
,
pb
)
<
0
)
if
(
get_riff
(
avi
,
pb
)
<
0
)
return
-
1
;
return
-
1
;
...
@@ -100,7 +118,8 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
...
@@ -100,7 +118,8 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
print_tag
(
"list"
,
tag1
,
0
);
print_tag
(
"list"
,
tag1
,
0
);
#endif
#endif
if
(
tag1
==
MKTAG
(
'm'
,
'o'
,
'v'
,
'i'
))
{
if
(
tag1
==
MKTAG
(
'm'
,
'o'
,
'v'
,
'i'
))
{
avi
->
movi_end
=
url_ftell
(
pb
)
+
size
-
4
;
avi
->
movi_list
=
url_ftell
(
pb
)
-
4
;
avi
->
movi_end
=
avi
->
movi_list
+
size
;
#ifdef DEBUG
#ifdef DEBUG
printf
(
"movi end=%Lx
\n
"
,
avi
->
movi_end
);
printf
(
"movi end=%Lx
\n
"
,
avi
->
movi_end
);
#endif
#endif
...
@@ -115,9 +134,14 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
...
@@ -115,9 +134,14 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
url_fskip
(
pb
,
4
*
4
);
url_fskip
(
pb
,
4
*
4
);
n
=
get_le32
(
pb
);
n
=
get_le32
(
pb
);
for
(
i
=
0
;
i
<
n
;
i
++
)
{
for
(
i
=
0
;
i
<
n
;
i
++
)
{
AVIStream
*
ast
;
st
=
av_new_stream
(
s
,
i
);
st
=
av_new_stream
(
s
,
i
);
if
(
!
st
)
if
(
!
st
)
goto
fail
;
goto
fail
;
ast
=
av_mallocz
(
sizeof
(
AVIStream
));
if
(
!
ast
)
goto
fail
;
st
->
priv_data
=
ast
;
}
}
url_fskip
(
pb
,
size
-
7
*
4
);
url_fskip
(
pb
,
size
-
7
*
4
);
break
;
break
;
...
@@ -159,7 +183,8 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
...
@@ -159,7 +183,8 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
}
}
st
=
s
->
streams
[
stream_index
];
st
=
s
->
streams
[
stream_index
];
ast
=
st
->
priv_data
;
get_le32
(
pb
);
/* flags */
get_le32
(
pb
);
/* flags */
get_le16
(
pb
);
/* priority */
get_le16
(
pb
);
/* priority */
get_le16
(
pb
);
/* language */
get_le16
(
pb
);
/* language */
...
@@ -168,27 +193,28 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
...
@@ -168,27 +193,28 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
rate
=
get_le32
(
pb
);
/* rate */
rate
=
get_le32
(
pb
);
/* rate */
if
(
scale
&&
rate
){
if
(
scale
&&
rate
){
st
->
codec
.
frame_rate
=
rate
;
st
->
codec
.
frame_rate_base
=
scale
;
}
else
if
(
frame_period
){
}
else
if
(
frame_period
){
st
->
codec
.
frame_
rate
=
1000000
;
rate
=
1000000
;
s
t
->
codec
.
frame_rate_bas
e
=
frame_period
;
s
cal
e
=
frame_period
;
}
else
{
}
else
{
st
->
codec
.
frame_
rate
=
25
;
rate
=
25
;
s
t
->
codec
.
frame_rate_bas
e
=
1
;
s
cal
e
=
1
;
}
}
ast
->
rate
=
rate
;
ast
->
scale
=
scale
;
st
->
codec
.
frame_rate
=
rate
;
st
->
codec
.
frame_rate_base
=
scale
;
get_le32
(
pb
);
/* start */
get_le32
(
pb
);
/* start */
nb_frames
=
get_le32
(
pb
);
nb_frames
=
get_le32
(
pb
);
st
->
start_time
=
0
;
st
->
start_time
=
0
;
st
->
duration
=
(
double
)
nb_frames
*
st
->
duration
=
(
double
)
nb_frames
*
st
->
codec
.
frame_rate_base
*
AV_TIME_BASE
/
st
->
codec
.
frame_rate_base
*
AV_TIME_BASE
/
st
->
codec
.
frame_rate
;
st
->
codec
.
frame_rate
;
url_fskip
(
pb
,
size
-
9
*
4
);
url_fskip
(
pb
,
size
-
9
*
4
);
break
;
break
;
case
MKTAG
(
'a'
,
'u'
,
'd'
,
's'
):
case
MKTAG
(
'a'
,
'u'
,
'd'
,
's'
):
{
{
unsigned
int
length
,
rate
;
unsigned
int
length
;
codec_type
=
CODEC_TYPE_AUDIO
;
codec_type
=
CODEC_TYPE_AUDIO
;
...
@@ -197,19 +223,23 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
...
@@ -197,19 +223,23 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
break
;
break
;
}
}
st
=
s
->
streams
[
stream_index
];
st
=
s
->
streams
[
stream_index
];
ast
=
st
->
priv_data
;
get_le32
(
pb
);
/* flags */
get_le32
(
pb
);
/* flags */
get_le16
(
pb
);
/* priority */
get_le16
(
pb
);
/* priority */
get_le16
(
pb
);
/* language */
get_le16
(
pb
);
/* language */
get_le32
(
pb
);
/* initial frame */
get_le32
(
pb
);
/* initial frame */
get_le32
(
pb
);
/* scale */
ast
->
scale
=
get_le32
(
pb
);
/* scale */
rate
=
get_le32
(
pb
);
ast
->
rate
=
get_le32
(
pb
);
get_le32
(
pb
);
/* start */
get_le32
(
pb
);
/* start */
length
=
get_le32
(
pb
);
/* length, in samples or bytes */
length
=
get_le32
(
pb
);
/* length, in samples or bytes */
get_le32
(
pb
);
/* buffer size */
get_le32
(
pb
);
/* quality */
ast
->
sample_size
=
get_le32
(
pb
);
/* sample ssize */
st
->
start_time
=
0
;
st
->
start_time
=
0
;
if
(
rate
!=
0
)
if
(
ast
->
rate
!=
0
)
st
->
duration
=
(
int64_t
)
length
*
AV_TIME_BASE
/
rate
;
st
->
duration
=
(
int64_t
)
length
*
AV_TIME_BASE
/
ast
->
rate
;
url_fskip
(
pb
,
size
-
9
*
4
);
url_fskip
(
pb
,
size
-
12
*
4
);
}
}
break
;
break
;
default:
default:
...
@@ -274,6 +304,9 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
...
@@ -274,6 +304,9 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
url_fskip
(
pb
,
1
);
url_fskip
(
pb
,
1
);
/* special case time: To support Xan DPCM, hardcode
/* special case time: To support Xan DPCM, hardcode
* the format if Xxan is the video codec */
* the format if Xxan is the video codec */
st
->
need_parsing
=
1
;
/* force parsing as several audio frames can be in
one packet */
if
(
xan_video
)
if
(
xan_video
)
st
->
codec
.
codec_id
=
CODEC_ID_XAN_DPCM
;
st
->
codec
.
codec_id
=
CODEC_ID_XAN_DPCM
;
break
;
break
;
...
@@ -377,10 +410,31 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
...
@@ -377,10 +410,31 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
size
=
dv_produce_packet
(
avi
->
dv_demux
,
pkt
,
size
=
dv_produce_packet
(
avi
->
dv_demux
,
pkt
,
pkt
->
data
,
pkt
->
size
);
pkt
->
data
,
pkt
->
size
);
pkt
->
destruct
=
dstr
;
pkt
->
destruct
=
dstr
;
pkt
->
flags
|=
PKT_FLAG_KEY
;
}
else
{
}
else
{
AVStream
*
st
;
AVIStream
*
ast
;
st
=
s
->
streams
[
n
];
ast
=
st
->
priv_data
;
/* XXX: how to handle B frames in avi ? */
pkt
->
pts
=
((
int64_t
)
ast
->
frame_offset
*
ast
->
scale
*
AV_TIME_BASE
)
/
ast
->
rate
;
pkt
->
stream_index
=
n
;
pkt
->
stream_index
=
n
;
pkt
->
flags
|=
PKT_FLAG_KEY
;
// FIXME: We really should read
/* FIXME: We really should read index for that */
// index for that
if
(
st
->
codec
.
codec_type
==
CODEC_TYPE_VIDEO
)
{
if
(
ast
->
frame_offset
<
ast
->
nb_index_entries
)
{
if
(
ast
->
index_entries
[
ast
->
frame_offset
].
flags
&
AVIIF_INDEX
)
pkt
->
flags
|=
PKT_FLAG_KEY
;
}
else
{
/* if no index, better to say that all frames
are key frames */
pkt
->
flags
|=
PKT_FLAG_KEY
;
}
ast
->
frame_offset
++
;
}
else
{
ast
->
frame_offset
+=
pkt
->
size
;
pkt
->
flags
|=
PKT_FLAG_KEY
;
}
}
}
return
size
;
return
size
;
}
}
...
@@ -388,6 +442,214 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
...
@@ -388,6 +442,214 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
return
-
1
;
return
-
1
;
}
}
/* XXX: we make the implicit supposition that the position are sorted
for each stream */
static
int
avi_read_idx1
(
AVFormatContext
*
s
,
int
size
)
{
ByteIOContext
*
pb
=
&
s
->
pb
;
int
nb_index_entries
,
i
;
AVStream
*
st
;
AVIStream
*
ast
;
AVIIndexEntry
*
ie
,
*
entries
;
unsigned
int
index
,
tag
,
flags
,
pos
,
len
;
nb_index_entries
=
size
/
16
;
if
(
nb_index_entries
<=
0
)
return
-
1
;
/* read the entries and sort them in each stream component */
for
(
i
=
0
;
i
<
nb_index_entries
;
i
++
)
{
tag
=
get_le32
(
pb
);
flags
=
get_le32
(
pb
);
pos
=
get_le32
(
pb
);
len
=
get_le32
(
pb
);
#if defined(DEBUG_SEEK) && 0
printf
(
"%d: tag=0x%x flags=0x%x pos=0x%x len=%d
\n
"
,
i
,
tag
,
flags
,
pos
,
len
);
#endif
index
=
((
tag
&
0xff
)
-
'0'
)
*
10
;
index
+=
((
tag
>>
8
)
&
0xff
)
-
'0'
;
if
(
index
>=
s
->
nb_streams
)
continue
;
st
=
s
->
streams
[
index
];
ast
=
st
->
priv_data
;
entries
=
av_fast_realloc
(
ast
->
index_entries
,
&
ast
->
index_entries_allocated_size
,
(
ast
->
nb_index_entries
+
1
)
*
sizeof
(
AVIIndexEntry
));
if
(
entries
)
{
ast
->
index_entries
=
entries
;
ie
=
&
entries
[
ast
->
nb_index_entries
++
];
ie
->
flags
=
flags
;
ie
->
pos
=
pos
;
ie
->
cum_len
=
ast
->
cum_len
;
ast
->
cum_len
+=
len
;
}
}
return
0
;
}
static
int
avi_load_index
(
AVFormatContext
*
s
)
{
AVIContext
*
avi
=
s
->
priv_data
;
ByteIOContext
*
pb
=
&
s
->
pb
;
uint32_t
tag
,
size
;
url_fseek
(
pb
,
avi
->
movi_end
,
SEEK_SET
);
#ifdef DEBUG_SEEK
printf
(
"movi_end=0x%llx
\n
"
,
avi
->
movi_end
);
#endif
for
(;;)
{
if
(
url_feof
(
pb
))
break
;
tag
=
get_le32
(
pb
);
size
=
get_le32
(
pb
);
#ifdef DEBUG_SEEK
printf
(
"tag=%c%c%c%c size=0x%x
\n
"
,
tag
&
0xff
,
(
tag
>>
8
)
&
0xff
,
(
tag
>>
16
)
&
0xff
,
(
tag
>>
24
)
&
0xff
,
size
);
#endif
switch
(
tag
)
{
case
MKTAG
(
'i'
,
'd'
,
'x'
,
'1'
):
if
(
avi_read_idx1
(
s
,
size
)
<
0
)
goto
skip
;
else
goto
the_end
;
break
;
default:
skip:
size
+=
(
size
&
1
);
url_fskip
(
pb
,
size
);
break
;
}
}
the_end:
return
0
;
}
/* return the index entry whose position is immediately >= 'wanted_pos' */
static
int
locate_frame_in_index
(
AVIIndexEntry
*
entries
,
int
nb_entries
,
int
wanted_pos
)
{
int
a
,
b
,
m
,
pos
;
a
=
0
;
b
=
nb_entries
-
1
;
while
(
a
<=
b
)
{
m
=
(
a
+
b
)
>>
1
;
pos
=
entries
[
m
].
pos
;
if
(
pos
==
wanted_pos
)
goto
found
;
else
if
(
pos
>
wanted_pos
)
{
b
=
m
-
1
;
}
else
{
a
=
m
+
1
;
}
}
m
=
a
;
if
(
m
>
0
)
m
--
;
found:
return
m
;
}
static
int
avi_read_seek
(
AVFormatContext
*
s
,
int
stream_index
,
int64_t
timestamp
)
{
AVIContext
*
avi
=
s
->
priv_data
;
AVStream
*
st
;
AVIStream
*
ast
;
int
frame_number
,
i
;
int64_t
pos
;
if
(
!
avi
->
index_loaded
)
{
/* we only load the index on demand */
avi_load_index
(
s
);
avi
->
index_loaded
=
1
;
}
if
(
stream_index
<
0
)
{
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
st
=
s
->
streams
[
i
];
if
(
st
->
codec
.
codec_type
==
CODEC_TYPE_VIDEO
)
goto
found
;
}
return
-
1
;
found:
stream_index
=
i
;
}
st
=
s
->
streams
[
stream_index
];
if
(
st
->
codec
.
codec_type
!=
CODEC_TYPE_VIDEO
)
return
-
1
;
ast
=
st
->
priv_data
;
/* compute the frame number */
frame_number
=
(
timestamp
*
ast
->
rate
)
/
(
ast
->
scale
*
(
int64_t
)
AV_TIME_BASE
);
#ifdef DEBUG_SEEK
printf
(
"timestamp=%0.3f nb_indexes=%d frame_number=%d
\n
"
,
(
double
)
timestamp
/
AV_TIME_BASE
,
ast
->
nb_index_entries
,
frame_number
);
#endif
/* find a closest key frame before */
if
(
frame_number
>=
ast
->
nb_index_entries
)
return
-
1
;
while
(
frame_number
>=
0
&&
!
(
ast
->
index_entries
[
frame_number
].
flags
&
AVIIF_INDEX
))
frame_number
--
;
if
(
frame_number
<
0
)
return
-
1
;
ast
->
new_frame_offset
=
frame_number
;
/* find the position */
pos
=
ast
->
index_entries
[
frame_number
].
pos
;
#ifdef DEBUG_SEEK
printf
(
"key_frame_number=%d pos=0x%llx
\n
"
,
frame_number
,
pos
);
#endif
/* update the frame counters for all the other stream by looking
at the positions just after the one found */
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
int
j
;
if
(
i
!=
stream_index
)
{
st
=
s
->
streams
[
i
];
ast
=
st
->
priv_data
;
if
(
ast
->
nb_index_entries
<=
0
)
return
-
1
;
j
=
locate_frame_in_index
(
ast
->
index_entries
,
ast
->
nb_index_entries
,
pos
);
/* get next frame */
if
((
j
+
1
)
<
ast
->
nb_index_entries
)
j
++
;
/* extract the current frame number */
if
(
st
->
codec
.
codec_type
==
CODEC_TYPE_VIDEO
)
ast
->
new_frame_offset
=
j
;
else
ast
->
new_frame_offset
=
ast
->
index_entries
[
j
].
cum_len
;
}
}
/* everything is OK now. We can update the frame offsets */
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
st
=
s
->
streams
[
i
];
ast
=
st
->
priv_data
;
ast
->
frame_offset
=
ast
->
new_frame_offset
;
#ifdef DEBUG_SEEK
printf
(
"%d: frame_offset=%d
\n
"
,
i
,
ast
->
frame_offset
);
#endif
}
/* do the seek */
pos
+=
avi
->
movi_list
;
url_fseek
(
&
s
->
pb
,
pos
,
SEEK_SET
);
return
0
;
}
static
int
avi_read_close
(
AVFormatContext
*
s
)
static
int
avi_read_close
(
AVFormatContext
*
s
)
{
{
int
i
;
int
i
;
...
@@ -395,7 +657,9 @@ static int avi_read_close(AVFormatContext *s)
...
@@ -395,7 +657,9 @@ static int avi_read_close(AVFormatContext *s)
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
for
(
i
=
0
;
i
<
s
->
nb_streams
;
i
++
)
{
AVStream
*
st
=
s
->
streams
[
i
];
AVStream
*
st
=
s
->
streams
[
i
];
// av_free(st->priv_data);
AVIStream
*
ast
=
st
->
priv_data
;
av_free
(
ast
->
index_entries
);
av_free
(
ast
);
av_free
(
st
->
codec
.
extradata
);
av_free
(
st
->
codec
.
extradata
);
av_free
(
st
->
codec
.
palctrl
);
av_free
(
st
->
codec
.
palctrl
);
}
}
...
@@ -428,6 +692,7 @@ static AVInputFormat avi_iformat = {
...
@@ -428,6 +692,7 @@ static AVInputFormat avi_iformat = {
avi_read_header
,
avi_read_header
,
avi_read_packet
,
avi_read_packet
,
avi_read_close
,
avi_read_close
,
avi_read_seek
,
};
};
int
avidec_init
(
void
)
int
avidec_init
(
void
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment