Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavformat
mm.c
Go to the documentation of this file.
1
/*
2
* American Laser Games MM Format Demuxer
3
* Copyright (c) 2006 Peter Ross
4
*
5
* This file is part of Libav.
6
*
7
* Libav is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
11
*
12
* Libav is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with Libav; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
34
#include "
libavutil/intreadwrite.h
"
35
#include "
avformat.h
"
36
#include "
internal.h
"
37
38
#define MM_PREAMBLE_SIZE 6
39
40
#define MM_TYPE_HEADER 0x0
41
#define MM_TYPE_INTER 0x5
42
#define MM_TYPE_INTRA 0x8
43
#define MM_TYPE_INTRA_HH 0xc
44
#define MM_TYPE_INTER_HH 0xd
45
#define MM_TYPE_INTRA_HHV 0xe
46
#define MM_TYPE_INTER_HHV 0xf
47
#define MM_TYPE_AUDIO 0x15
48
#define MM_TYPE_PALETTE 0x31
49
50
#define MM_HEADER_LEN_V 0x16
/* video only */
51
#define MM_HEADER_LEN_AV 0x18
/* video + audio */
52
53
#define MM_PALETTE_COUNT 128
54
#define MM_PALETTE_SIZE (MM_PALETTE_COUNT*3)
55
56
typedef
struct
{
57
unsigned
int
audio_pts,
video_pts
;
58
}
MmDemuxContext
;
59
60
static
int
probe
(
AVProbeData
*p)
61
{
62
int
len
, type, fps, w, h;
63
if
(p->
buf_size
<
MM_HEADER_LEN_AV
+
MM_PREAMBLE_SIZE
)
64
return
0;
65
/* the first chunk is always the header */
66
if
(
AV_RL16
(&p->
buf
[0]) !=
MM_TYPE_HEADER
)
67
return
0;
68
len =
AV_RL32
(&p->
buf
[2]);
69
if
(len !=
MM_HEADER_LEN_V
&& len !=
MM_HEADER_LEN_AV
)
70
return
0;
71
fps =
AV_RL16
(&p->
buf
[8]);
72
w =
AV_RL16
(&p->
buf
[12]);
73
h =
AV_RL16
(&p->
buf
[14]);
74
if
(!fps || fps > 60 || !w || w > 2048 || !h || h > 2048)
75
return
0;
76
type =
AV_RL16
(&p->
buf
[len]);
77
if
(!type || type > 0x31)
78
return
0;
79
80
/* only return half certainty since this check is a bit sketchy */
81
return
AVPROBE_SCORE_MAX
/ 2;
82
}
83
84
static
int
read_header
(
AVFormatContext
*s,
85
AVFormatParameters
*ap)
86
{
87
MmDemuxContext
*mm = s->
priv_data
;
88
AVIOContext
*pb = s->
pb
;
89
AVStream
*st;
90
91
unsigned
int
type, length;
92
unsigned
int
frame_rate
,
width
,
height
;
93
94
type =
avio_rl16
(pb);
95
length =
avio_rl32
(pb);
96
97
if
(type !=
MM_TYPE_HEADER
)
98
return
AVERROR_INVALIDDATA
;
99
100
/* read header */
101
avio_rl16
(pb);
/* total number of chunks */
102
frame_rate =
avio_rl16
(pb);
103
avio_rl16
(pb);
/* ibm-pc video bios mode */
104
width =
avio_rl16
(pb);
105
height =
avio_rl16
(pb);
106
avio_skip
(pb, length - 10);
/* unknown data */
107
108
/* video stream */
109
st =
avformat_new_stream
(s,
NULL
);
110
if
(!st)
111
return
AVERROR
(ENOMEM);
112
st->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
113
st->
codec
->
codec_id
=
CODEC_ID_MMVIDEO
;
114
st->
codec
->
codec_tag
= 0;
/* no fourcc */
115
st->
codec
->
width
=
width
;
116
st->
codec
->
height
=
height
;
117
avpriv_set_pts_info
(st, 64, 1, frame_rate);
118
119
/* audio stream */
120
if
(length ==
MM_HEADER_LEN_AV
) {
121
st =
avformat_new_stream
(s,
NULL
);
122
if
(!st)
123
return
AVERROR
(ENOMEM);
124
st->
codec
->
codec_type
=
AVMEDIA_TYPE_AUDIO
;
125
st->
codec
->
codec_tag
= 0;
/* no fourcc */
126
st->
codec
->
codec_id
=
CODEC_ID_PCM_U8
;
127
st->
codec
->
channels
= 1;
128
st->
codec
->
sample_rate
= 8000;
129
avpriv_set_pts_info
(st, 64, 1, 8000);
/* 8000 hz */
130
}
131
132
mm->
audio_pts
= 0;
133
mm->
video_pts
= 0;
134
return
0;
135
}
136
137
static
int
read_packet
(
AVFormatContext
*s,
138
AVPacket
*pkt)
139
{
140
MmDemuxContext
*mm = s->
priv_data
;
141
AVIOContext
*pb = s->
pb
;
142
unsigned
char
preamble[
MM_PREAMBLE_SIZE
];
143
unsigned
int
type, length;
144
145
while
(1) {
146
147
if
(
avio_read
(pb, preamble,
MM_PREAMBLE_SIZE
) !=
MM_PREAMBLE_SIZE
) {
148
return
AVERROR
(EIO);
149
}
150
151
type =
AV_RL16
(&preamble[0]);
152
length =
AV_RL16
(&preamble[2]);
153
154
switch
(type) {
155
case
MM_TYPE_PALETTE
:
156
case
MM_TYPE_INTER
:
157
case
MM_TYPE_INTRA
:
158
case
MM_TYPE_INTRA_HH
:
159
case
MM_TYPE_INTER_HH
:
160
case
MM_TYPE_INTRA_HHV
:
161
case
MM_TYPE_INTER_HHV
:
162
/* output preamble + data */
163
if
(
av_new_packet
(pkt, length +
MM_PREAMBLE_SIZE
))
164
return
AVERROR
(ENOMEM);
165
memcpy(pkt->
data
, preamble,
MM_PREAMBLE_SIZE
);
166
if
(
avio_read
(pb, pkt->
data
+
MM_PREAMBLE_SIZE
, length) != length)
167
return
AVERROR
(EIO);
168
pkt->
size
= length +
MM_PREAMBLE_SIZE
;
169
pkt->
stream_index
= 0;
170
pkt->
pts
= mm->
video_pts
;
171
if
(type!=
MM_TYPE_PALETTE
)
172
mm->
video_pts
++;
173
return
0;
174
175
case
MM_TYPE_AUDIO
:
176
if
(
av_get_packet
(s->
pb
, pkt, length)<0)
177
return
AVERROR
(ENOMEM);
178
pkt->
size
= length;
179
pkt->
stream_index
= 1;
180
pkt->
pts
= mm->
audio_pts
++;
181
return
0;
182
183
default
:
184
av_log
(s,
AV_LOG_INFO
,
"unknown chunk type 0x%x\n"
, type);
185
avio_skip
(pb, length);
186
}
187
}
188
}
189
190
AVInputFormat
ff_mm_demuxer
= {
191
.
name
=
"mm"
,
192
.long_name =
NULL_IF_CONFIG_SMALL
(
"American Laser Games MM format"
),
193
.priv_data_size =
sizeof
(
MmDemuxContext
),
194
.
read_probe
=
probe
,
195
.
read_header
=
read_header
,
196
.
read_packet
=
read_packet
,
197
};