Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
6fb40779
Commit
6fb40779
authored
Dec 17, 2012
by
Peter Ross
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Silicon Graphics Movie (.mv) demuxer
Signed-off-by:
Peter Ross
<
pross@xvid.org
>
parent
746b1dcc
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
428 additions
and
0 deletions
+428
-0
Changelog
Changelog
+1
-0
general.texi
doc/general.texi
+1
-0
Makefile
libavformat/Makefile
+1
-0
allformats.c
libavformat/allformats.c
+1
-0
mvdec.c
libavformat/mvdec.c
+424
-0
No files found.
Changelog
View file @
6fb40779
...
...
@@ -44,6 +44,7 @@ version <next>:
- aselect filter
- SGI RLE 8-bit decoder
- Silicon Graphics Motion Video Compressor 1 & 2 decoder
- Silicon Graphics Movie demuxer
version 1.0:
...
...
doc/general.texi
View file @
6fb40779
...
...
@@ -359,6 +359,7 @@ library:
@item SDP @tab @tab X
@item Sega FILM/CPK @tab @tab X
@tab Used in many Sega Saturn console games.
@item Silicon Graphics Movie @tab @tab X
@item Sierra SOL @tab @tab X
@tab .sol files used in Sierra Online games.
@item Sierra VMD @tab @tab X
...
...
libavformat/Makefile
View file @
6fb40779
...
...
@@ -222,6 +222,7 @@ OBJS-$(CONFIG_MPJPEG_MUXER) += mpjpeg.o
OBJS-$(CONFIG_MSNWC_TCP_DEMUXER)
+=
msnwc_tcp.o
OBJS-$(CONFIG_MTV_DEMUXER)
+=
mtv.o
OBJS-$(CONFIG_MVI_DEMUXER)
+=
mvi.o
OBJS-$(CONFIG_MV_DEMUXER)
+=
mvdec.o
OBJS-$(CONFIG_MXF_DEMUXER)
+=
mxfdec.o
mxf.o
OBJS-$(CONFIG_MXF_MUXER)
+=
mxfenc.o
mxf.o
audiointerleave.o
OBJS-$(CONFIG_MXG_DEMUXER)
+=
mxg.o
...
...
libavformat/allformats.c
View file @
6fb40779
...
...
@@ -172,6 +172,7 @@ void av_register_all(void)
REGISTER_MUXER
(
MPJPEG
,
mpjpeg
);
REGISTER_DEMUXER
(
MSNWC_TCP
,
msnwc_tcp
);
REGISTER_DEMUXER
(
MTV
,
mtv
);
REGISTER_DEMUXER
(
MV
,
mv
);
REGISTER_DEMUXER
(
MVI
,
mvi
);
REGISTER_MUXDEMUX
(
MXF
,
mxf
);
REGISTER_MUXER
(
MXF_D10
,
mxf_d10
);
...
...
libavformat/mvdec.c
0 → 100644
View file @
6fb40779
/*
* Silicon Graphics Movie demuxer
* Copyright (c) 2012 Peter Ross
*
* 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
*/
/**
* @file
* Silicon Graphics Movie demuxer
*/
#include "libavutil/eval.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/rational.h"
#include "avformat.h"
#include "internal.h"
typedef
struct
{
int
nb_video_tracks
;
int
nb_audio_tracks
;
int
eof_count
;
/**< number of streams that have finished */
int
stream_index
;
/**< current stream index */
int
frame
[
2
];
/**< frame nb for current stream */
}
MvContext
;
#define AUDIO_FORMAT_SIGNED 401
static
int
mv_probe
(
AVProbeData
*
p
)
{
if
(
AV_RB32
(
p
->
buf
)
==
MKBETAG
(
'M'
,
'O'
,
'V'
,
'I'
)
&&
AV_RB16
(
p
->
buf
+
4
)
<
3
)
return
AVPROBE_SCORE_MAX
;
return
0
;
}
static
char
*
var_read_string
(
AVIOContext
*
pb
,
int
size
)
{
char
*
str
=
av_malloc
(
size
+
1
);
int
n
;
if
(
!
str
)
return
NULL
;
n
=
avio_get_str
(
pb
,
size
,
str
,
size
+
1
);
if
(
n
<
size
)
avio_skip
(
pb
,
size
-
n
);
return
str
;
}
static
int
var_read_int
(
AVIOContext
*
pb
,
int
size
)
{
int
v
;
char
*
s
=
var_read_string
(
pb
,
size
);
if
(
!
s
||
sscanf
(
s
,
"%d"
,
&
v
)
!=
1
)
v
=
0
;
av_free
(
s
);
return
v
;
}
static
AVRational
var_read_float
(
AVIOContext
*
pb
,
int
size
)
{
AVRational
v
;
char
*
s
=
var_read_string
(
pb
,
size
);
if
(
!
s
)
return
(
AVRational
){
0
,
0
};
v
=
av_d2q
(
av_strtod
(
s
,
NULL
),
INT_MAX
);
av_free
(
s
);
return
v
;
}
static
void
var_read_metadata
(
AVFormatContext
*
avctx
,
const
char
*
tag
,
int
size
)
{
char
*
value
=
var_read_string
(
avctx
->
pb
,
size
);
if
(
value
)
av_dict_set
(
&
avctx
->
metadata
,
tag
,
value
,
AV_DICT_DONT_STRDUP_VAL
);
}
/**
* Parse global variable
* @return < 0 if unknown
*/
static
int
parse_global_var
(
AVFormatContext
*
avctx
,
AVStream
*
st
,
const
char
*
name
,
int
size
)
{
MvContext
*
mv
=
avctx
->
priv_data
;
AVIOContext
*
pb
=
avctx
->
pb
;
if
(
!
strcmp
(
name
,
"__NUM_I_TRACKS"
))
{
mv
->
nb_video_tracks
=
var_read_int
(
pb
,
size
);
}
else
if
(
!
strcmp
(
name
,
"__NUM_A_TRACKS"
))
{
mv
->
nb_audio_tracks
=
var_read_int
(
pb
,
size
);
}
else
if
(
!
strcmp
(
name
,
"COMMENT"
)
||
!
strcmp
(
name
,
"TITLE"
))
{
var_read_metadata
(
avctx
,
name
,
size
);
}
else
if
(
!
strcmp
(
name
,
"LOOP_MODE"
)
||
!
strcmp
(
name
,
"NUM_LOOPS"
)
||
!
strcmp
(
name
,
"OPTIMIZED"
))
{
avio_skip
(
pb
,
size
);
// ignore
}
else
return
-
1
;
return
0
;
}
/**
* Parse audio variable
* @return < 0 if unknown
*/
static
int
parse_audio_var
(
AVFormatContext
*
avctx
,
AVStream
*
st
,
const
char
*
name
,
int
size
)
{
AVIOContext
*
pb
=
avctx
->
pb
;
if
(
!
strcmp
(
name
,
"__DIR_COUNT"
))
{
st
->
nb_frames
=
var_read_int
(
pb
,
size
);
}
else
if
(
!
strcmp
(
name
,
"AUDIO_FORMAT"
))
{
st
->
codec
->
codec_id
=
var_read_int
(
pb
,
size
);
}
else
if
(
!
strcmp
(
name
,
"COMPRESSION"
))
{
st
->
codec
->
codec_tag
=
var_read_int
(
pb
,
size
);
}
else
if
(
!
strcmp
(
name
,
"DEFAULT_VOL"
))
{
var_read_metadata
(
avctx
,
name
,
size
);
}
else
if
(
!
strcmp
(
name
,
"NUM_CHANNELS"
))
{
st
->
codec
->
channels
=
var_read_int
(
pb
,
size
);
st
->
codec
->
channel_layout
=
(
st
->
codec
->
channels
==
1
)
?
AV_CH_LAYOUT_MONO
:
AV_CH_LAYOUT_STEREO
;
}
else
if
(
!
strcmp
(
name
,
"SAMPLE_RATE"
))
{
st
->
codec
->
sample_rate
=
var_read_int
(
pb
,
size
);
avpriv_set_pts_info
(
st
,
33
,
1
,
st
->
codec
->
sample_rate
);
}
else
if
(
!
strcmp
(
name
,
"SAMPLE_WIDTH"
))
{
st
->
codec
->
bits_per_coded_sample
=
var_read_int
(
pb
,
size
)
*
8
;
}
else
return
-
1
;
return
0
;
}
/**
* Parse video variable
* @return < 0 if unknown
*/
static
int
parse_video_var
(
AVFormatContext
*
avctx
,
AVStream
*
st
,
const
char
*
name
,
int
size
)
{
AVIOContext
*
pb
=
avctx
->
pb
;
if
(
!
strcmp
(
name
,
"__DIR_COUNT"
))
{
st
->
nb_frames
=
st
->
duration
=
var_read_int
(
pb
,
size
);
}
else
if
(
!
strcmp
(
name
,
"COMPRESSION"
))
{
char
*
str
=
var_read_string
(
pb
,
size
);
if
(
!
strcmp
(
str
,
"1"
))
{
st
->
codec
->
codec_id
=
AV_CODEC_ID_MVC1
;
}
else
if
(
!
strcmp
(
str
,
"2"
))
{
st
->
codec
->
pix_fmt
=
AV_PIX_FMT_ABGR
;
st
->
codec
->
codec_id
=
AV_CODEC_ID_RAWVIDEO
;
}
else
if
(
!
strcmp
(
str
,
"3"
))
{
st
->
codec
->
codec_id
=
AV_CODEC_ID_SGIRLE
;
}
else
if
(
!
strcmp
(
str
,
"10"
))
{
st
->
codec
->
codec_id
=
AV_CODEC_ID_MJPEG
;
}
else
if
(
!
strcmp
(
str
,
"MVC2"
))
{
st
->
codec
->
codec_id
=
AV_CODEC_ID_MVC2
;
}
else
{
av_log_ask_for_sample
(
avctx
,
"unknown video compression %s
\n
"
,
str
);
}
av_free
(
str
);
}
else
if
(
!
strcmp
(
name
,
"FPS"
))
{
st
->
time_base
=
av_inv_q
(
var_read_float
(
pb
,
size
));
}
else
if
(
!
strcmp
(
name
,
"HEIGHT"
))
{
st
->
codec
->
height
=
var_read_int
(
pb
,
size
);
}
else
if
(
!
strcmp
(
name
,
"PIXEL_ASPECT"
))
{
st
->
sample_aspect_ratio
=
var_read_float
(
pb
,
size
);
av_reduce
(
&
st
->
sample_aspect_ratio
.
num
,
&
st
->
sample_aspect_ratio
.
den
,
st
->
sample_aspect_ratio
.
num
,
st
->
sample_aspect_ratio
.
den
,
INT_MAX
);
}
else
if
(
!
strcmp
(
name
,
"WIDTH"
))
{
st
->
codec
->
width
=
var_read_int
(
pb
,
size
);
}
else
if
(
!
strcmp
(
name
,
"ORIENTATION"
))
{
if
(
var_read_int
(
pb
,
size
)
==
1101
)
{
st
->
codec
->
extradata
=
av_strdup
(
"BottomUp"
);
st
->
codec
->
extradata_size
=
9
;
}
}
else
if
(
!
strcmp
(
name
,
"Q_SPATIAL"
)
||
!
strcmp
(
name
,
"Q_TEMPORAL"
))
{
var_read_metadata
(
avctx
,
name
,
size
);
}
else
if
(
!
strcmp
(
name
,
"INTERLACING"
)
||
!
strcmp
(
name
,
"PACKING"
))
{
avio_skip
(
pb
,
size
);
// ignore
}
else
return
-
1
;
return
0
;
}
static
void
read_table
(
AVFormatContext
*
avctx
,
AVStream
*
st
,
int
(
*
parse
)(
AVFormatContext
*
avctx
,
AVStream
*
st
,
const
char
*
name
,
int
size
))
{
int
count
,
i
;
AVIOContext
*
pb
=
avctx
->
pb
;
avio_skip
(
pb
,
4
);
count
=
avio_rb32
(
pb
);
avio_skip
(
pb
,
4
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
char
name
[
17
];
int
size
;
avio_read
(
pb
,
name
,
16
);
name
[
sizeof
(
name
)
-
1
]
=
0
;
size
=
avio_rb32
(
pb
);
if
(
parse
(
avctx
,
st
,
name
,
size
)
<
0
)
{
av_log_ask_for_sample
(
avctx
,
"unknown variable %s
\n
"
,
name
);
avio_skip
(
pb
,
size
);
}
}
}
static
void
read_index
(
AVIOContext
*
pb
,
AVStream
*
st
)
{
uint64_t
timestamp
=
0
;
int
i
;
for
(
i
=
0
;
i
<
st
->
nb_frames
;
i
++
)
{
uint32_t
pos
=
avio_rb32
(
pb
);
uint32_t
size
=
avio_rb32
(
pb
);
avio_skip
(
pb
,
8
);
av_add_index_entry
(
st
,
pos
,
timestamp
,
size
,
0
,
AVINDEX_KEYFRAME
);
if
(
st
->
codec
->
codec_type
==
AVMEDIA_TYPE_AUDIO
)
{
timestamp
+=
size
/
(
st
->
codec
->
channels
*
2
);
}
else
{
timestamp
++
;
}
}
}
static
int
mv_read_header
(
AVFormatContext
*
avctx
)
{
MvContext
*
mv
=
avctx
->
priv_data
;
AVIOContext
*
pb
=
avctx
->
pb
;
AVStream
*
ast
,
*
vst
;
int
version
,
i
;
avio_skip
(
pb
,
4
);
version
=
avio_rb16
(
pb
);
if
(
version
==
2
)
{
uint64_t
timestamp
;
int
v
;
avio_skip
(
pb
,
22
);
/* allocate audio track first to prevent unnecessary seeking
(audio packet always precede video packet for a given frame) */
ast
=
avformat_new_stream
(
avctx
,
NULL
);
if
(
!
ast
)
return
AVERROR
(
ENOMEM
);
vst
=
avformat_new_stream
(
avctx
,
NULL
);
if
(
!
vst
)
return
AVERROR
(
ENOMEM
);
vst
->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
vst
->
time_base
=
(
AVRational
){
1
,
15
};
vst
->
nb_frames
=
avio_rb32
(
pb
);
v
=
avio_rb32
(
pb
);
switch
(
v
)
{
case
1
:
vst
->
codec
->
codec_id
=
AV_CODEC_ID_MVC1
;
break
;
case
2
:
vst
->
codec
->
pix_fmt
=
AV_PIX_FMT_ARGB
;
vst
->
codec
->
codec_id
=
AV_CODEC_ID_RAWVIDEO
;
break
;
default:
av_log_ask_for_sample
(
avctx
,
"unknown video compression %i
\n
"
,
v
);
break
;
}
vst
->
codec
->
codec_tag
=
0
;
vst
->
codec
->
width
=
avio_rb32
(
pb
);
vst
->
codec
->
height
=
avio_rb32
(
pb
);
avio_skip
(
pb
,
12
);
ast
->
codec
->
codec_type
=
AVMEDIA_TYPE_AUDIO
;
ast
->
nb_frames
=
vst
->
nb_frames
;
ast
->
codec
->
sample_rate
=
avio_rb32
(
pb
);
avpriv_set_pts_info
(
ast
,
33
,
1
,
ast
->
codec
->
sample_rate
);
ast
->
codec
->
channels
=
avio_rb32
(
pb
);
ast
->
codec
->
channel_layout
=
(
ast
->
codec
->
channels
==
1
)
?
AV_CH_LAYOUT_MONO
:
AV_CH_LAYOUT_STEREO
;
v
=
avio_rb32
(
pb
);
if
(
v
==
AUDIO_FORMAT_SIGNED
)
{
ast
->
codec
->
codec_id
=
AV_CODEC_ID_PCM_S16BE
;
}
else
{
av_log_ask_for_sample
(
avctx
,
"unknown audio compression (format %i)
\n
"
,
v
);
}
avio_skip
(
pb
,
12
);
var_read_metadata
(
avctx
,
"title"
,
0x80
);
var_read_metadata
(
avctx
,
"comment"
,
0x100
);
avio_skip
(
pb
,
0x80
);
timestamp
=
0
;
for
(
i
=
0
;
i
<
vst
->
nb_frames
;
i
++
)
{
uint32_t
pos
=
avio_rb32
(
pb
);
uint32_t
asize
=
avio_rb32
(
pb
);
uint32_t
vsize
=
avio_rb32
(
pb
);
avio_skip
(
pb
,
8
);
av_add_index_entry
(
ast
,
pos
,
timestamp
,
asize
,
0
,
AVINDEX_KEYFRAME
);
av_add_index_entry
(
vst
,
pos
+
asize
,
i
,
vsize
,
0
,
AVINDEX_KEYFRAME
);
timestamp
+=
asize
/
(
ast
->
codec
->
channels
*
2
);
}
}
else
if
(
!
version
&&
avio_rb16
(
pb
)
==
3
)
{
avio_skip
(
pb
,
4
);
read_table
(
avctx
,
NULL
,
parse_global_var
);
if
(
mv
->
nb_audio_tracks
>
1
)
{
av_log_ask_for_sample
(
avctx
,
"multiple audio streams
\n
"
);
return
AVERROR_PATCHWELCOME
;
}
else
if
(
mv
->
nb_audio_tracks
)
{
ast
=
avformat_new_stream
(
avctx
,
NULL
);
if
(
!
ast
)
return
AVERROR
(
ENOMEM
);
ast
->
codec
->
codec_type
=
AVMEDIA_TYPE_AUDIO
;
/* temporarily store compression value in codec_tag; format value in codec_id */
read_table
(
avctx
,
ast
,
parse_audio_var
);
if
(
ast
->
codec
->
codec_tag
==
100
&&
ast
->
codec
->
codec_id
==
AUDIO_FORMAT_SIGNED
&&
ast
->
codec
->
bits_per_coded_sample
==
16
)
{
ast
->
codec
->
codec_id
=
AV_CODEC_ID_PCM_S16BE
;
}
else
{
av_log_ask_for_sample
(
avctx
,
"unknown audio compression %i (format %i, width %i)
\n
"
,
ast
->
codec
->
codec_tag
,
ast
->
codec
->
codec_id
,
ast
->
codec
->
bits_per_coded_sample
);
ast
->
codec
->
codec_id
=
AV_CODEC_ID_NONE
;
}
ast
->
codec
->
codec_tag
=
0
;
}
if
(
mv
->
nb_video_tracks
>
1
)
{
av_log_ask_for_sample
(
avctx
,
"multiple video streams
\n
"
);
return
AVERROR_PATCHWELCOME
;
}
else
if
(
mv
->
nb_video_tracks
)
{
vst
=
avformat_new_stream
(
avctx
,
NULL
);
if
(
!
vst
)
return
AVERROR
(
ENOMEM
);
vst
->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
read_table
(
avctx
,
vst
,
parse_video_var
);
}
if
(
mv
->
nb_audio_tracks
)
read_index
(
pb
,
ast
);
if
(
mv
->
nb_video_tracks
)
read_index
(
pb
,
vst
);
}
else
{
av_log_ask_for_sample
(
avctx
,
"unknown version %i
\n
"
,
version
);
return
AVERROR_PATCHWELCOME
;
}
return
0
;
}
static
int
mv_read_packet
(
AVFormatContext
*
avctx
,
AVPacket
*
pkt
)
{
MvContext
*
mv
=
avctx
->
priv_data
;
AVIOContext
*
pb
=
avctx
->
pb
;
AVStream
*
st
=
avctx
->
streams
[
mv
->
stream_index
];
const
AVIndexEntry
*
index
;
int
frame
=
mv
->
frame
[
mv
->
stream_index
];
int
ret
;
uint64_t
pos
;
if
(
frame
<
st
->
nb_frames
)
{
index
=
&
st
->
index_entries
[
frame
];
pos
=
avio_tell
(
pb
);
if
(
index
->
pos
>
pos
)
avio_skip
(
pb
,
index
->
pos
-
pos
);
else
if
(
index
->
pos
<
pos
)
{
if
(
!
pb
->
seekable
)
return
AVERROR
(
EIO
);
ret
=
avio_seek
(
pb
,
index
->
pos
,
SEEK_SET
);
if
(
ret
<
0
)
return
ret
;
}
ret
=
av_get_packet
(
pb
,
pkt
,
index
->
size
);
if
(
ret
<
0
)
return
ret
;
pkt
->
stream_index
=
mv
->
stream_index
;
pkt
->
pts
=
index
->
timestamp
;
pkt
->
flags
|=
AV_PKT_FLAG_KEY
;
mv
->
frame
[
mv
->
stream_index
]
++
;
mv
->
eof_count
=
0
;
}
else
{
mv
->
eof_count
++
;
if
(
mv
->
eof_count
>=
avctx
->
nb_streams
)
return
AVERROR_EOF
;
}
mv
->
stream_index
++
;
if
(
mv
->
stream_index
>=
avctx
->
nb_streams
)
mv
->
stream_index
=
0
;
return
0
;
}
static
int
mv_read_seek
(
AVFormatContext
*
avctx
,
int
stream_index
,
int64_t
timestamp
,
int
flags
)
{
MvContext
*
mv
=
avctx
->
priv_data
;
AVStream
*
st
=
avctx
->
streams
[
stream_index
];
int
frame
,
i
;
if
((
flags
&
AVSEEK_FLAG_FRAME
)
||
(
flags
&
AVSEEK_FLAG_BYTE
))
return
AVERROR
(
ENOSYS
);
if
(
!
avctx
->
pb
->
seekable
)
return
AVERROR
(
EIO
);
frame
=
av_index_search_timestamp
(
st
,
timestamp
,
flags
);
if
(
frame
<
0
)
return
-
1
;
for
(
i
=
0
;
i
<
avctx
->
nb_streams
;
i
++
)
mv
->
frame
[
i
]
=
frame
;
return
0
;
}
AVInputFormat
ff_mv_demuxer
=
{
.
name
=
"mv"
,
.
long_name
=
NULL_IF_CONFIG_SMALL
(
"Silicon Graphics Movie"
),
.
priv_data_size
=
sizeof
(
MvContext
),
.
read_probe
=
mv_probe
,
.
read_header
=
mv_read_header
,
.
read_packet
=
mv_read_packet
,
.
read_seek
=
mv_read_seek
,
};
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