Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavformat
tmv.c
Go to the documentation of this file.
1
/*
2
* 8088flex TMV file demuxer
3
* Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
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
29
#include "
libavutil/intreadwrite.h
"
30
#include "
avformat.h
"
31
#include "
internal.h
"
32
33
enum
{
34
TMV_PADDING
= 0x01,
35
TMV_STEREO
= 0x02,
36
};
37
38
#define TMV_TAG MKTAG('T', 'M', 'A', 'V')
39
40
typedef
struct
TMVContext
{
41
unsigned
audio_chunk_size
;
42
unsigned
video_chunk_size
;
43
unsigned
padding
;
44
unsigned
stream_index
;
45
}
TMVContext
;
46
47
#define TMV_HEADER_SIZE 12
48
49
#define PROBE_MIN_SAMPLE_RATE 5000
50
#define PROBE_MAX_FPS 120
51
#define PROBE_MIN_AUDIO_SIZE (PROBE_MIN_SAMPLE_RATE / PROBE_MAX_FPS)
52
53
static
int
tmv_probe
(
AVProbeData
*p)
54
{
55
if
(
AV_RL32
(p->
buf
) ==
TMV_TAG
&&
56
AV_RL16
(p->
buf
+4) >=
PROBE_MIN_SAMPLE_RATE
&&
57
AV_RL16
(p->
buf
+6) >=
PROBE_MIN_AUDIO_SIZE
&&
58
!p->
buf
[8] &&
// compression method
59
p->
buf
[9] &&
// char cols
60
p->
buf
[10])
// char rows
61
return
AVPROBE_SCORE_MAX
/
62
((p->
buf
[9] == 40 && p->
buf
[10] == 25) ? 1 : 4);
63
return
0;
64
}
65
66
static
int
tmv_read_header
(
AVFormatContext
*s,
AVFormatParameters
*ap)
67
{
68
TMVContext
*tmv = s->
priv_data
;
69
AVIOContext
*pb = s->
pb
;
70
AVStream
*vst, *ast;
71
AVRational
fps;
72
unsigned
comp_method, char_cols, char_rows, features;
73
74
if
(
avio_rl32
(pb) !=
TMV_TAG
)
75
return
-1;
76
77
if
(!(vst =
avformat_new_stream
(s,
NULL
)))
78
return
AVERROR
(ENOMEM);
79
80
if
(!(ast =
avformat_new_stream
(s,
NULL
)))
81
return
AVERROR
(ENOMEM);
82
83
ast->
codec
->
sample_rate
=
avio_rl16
(pb);
84
if
(!ast->
codec
->
sample_rate
) {
85
av_log
(s,
AV_LOG_ERROR
,
"invalid sample rate\n"
);
86
return
-1;
87
}
88
89
tmv->
audio_chunk_size
=
avio_rl16
(pb);
90
if
(!tmv->
audio_chunk_size
) {
91
av_log
(s,
AV_LOG_ERROR
,
"invalid audio chunk size\n"
);
92
return
-1;
93
}
94
95
comp_method =
avio_r8
(pb);
96
if
(comp_method) {
97
av_log
(s,
AV_LOG_ERROR
,
"unsupported compression method %d\n"
,
98
comp_method);
99
return
-1;
100
}
101
102
char_cols =
avio_r8
(pb);
103
char_rows =
avio_r8
(pb);
104
tmv->
video_chunk_size
= char_cols * char_rows * 2;
105
106
features =
avio_r8
(pb);
107
if
(features & ~(
TMV_PADDING
|
TMV_STEREO
)) {
108
av_log
(s,
AV_LOG_ERROR
,
"unsupported features 0x%02x\n"
,
109
features & ~(
TMV_PADDING
|
TMV_STEREO
));
110
return
-1;
111
}
112
113
ast->
codec
->
codec_type
=
AVMEDIA_TYPE_AUDIO
;
114
ast->
codec
->
codec_id
=
CODEC_ID_PCM_U8
;
115
ast->
codec
->
channels
= features &
TMV_STEREO
? 2 : 1;
116
ast->
codec
->
bits_per_coded_sample
= 8;
117
ast->
codec
->
bit_rate
= ast->
codec
->
sample_rate
*
118
ast->
codec
->
bits_per_coded_sample
;
119
avpriv_set_pts_info
(ast, 32, 1, ast->
codec
->
sample_rate
);
120
121
fps.
num
= ast->
codec
->
sample_rate
* ast->
codec
->
channels
;
122
fps.
den
= tmv->
audio_chunk_size
;
123
av_reduce
(&fps.
num
, &fps.
den
, fps.
num
, fps.
den
, 0xFFFFFFFFLL);
124
125
vst->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
126
vst->
codec
->
codec_id
=
CODEC_ID_TMV
;
127
vst->
codec
->
pix_fmt
=
PIX_FMT_PAL8
;
128
vst->
codec
->
width
= char_cols * 8;
129
vst->
codec
->
height
= char_rows * 8;
130
avpriv_set_pts_info
(vst, 32, fps.
den
, fps.
num
);
131
132
if
(features &
TMV_PADDING
)
133
tmv->
padding
=
134
((tmv->
video_chunk_size
+ tmv->
audio_chunk_size
+ 511) & ~511) -
135
(tmv->
video_chunk_size
+ tmv->
audio_chunk_size
);
136
137
vst->
codec
->
bit_rate
= ((tmv->
video_chunk_size
+ tmv->
padding
) *
138
fps.
num
* 8) / fps.
den
;
139
140
return
0;
141
}
142
143
static
int
tmv_read_packet
(
AVFormatContext
*s,
AVPacket
*pkt)
144
{
145
TMVContext
*tmv = s->
priv_data
;
146
AVIOContext
*pb = s->
pb
;
147
int
ret, pkt_size = tmv->
stream_index
?
148
tmv->
audio_chunk_size
: tmv->
video_chunk_size
;
149
150
if
(pb->
eof_reached
)
151
return
AVERROR_EOF
;
152
153
ret =
av_get_packet
(pb, pkt, pkt_size);
154
155
if
(tmv->
stream_index
)
156
avio_skip
(pb, tmv->
padding
);
157
158
pkt->
stream_index
= tmv->
stream_index
;
159
tmv->
stream_index
^= 1;
160
pkt->
flags
|=
AV_PKT_FLAG_KEY
;
161
162
return
ret;
163
}
164
165
static
int
tmv_read_seek
(
AVFormatContext
*s,
int
stream_index,
166
int64_t timestamp,
int
flags
)
167
{
168
TMVContext
*tmv = s->
priv_data
;
169
int64_t pos;
170
171
if
(stream_index)
172
return
-1;
173
174
pos = timestamp *
175
(tmv->
audio_chunk_size
+ tmv->
video_chunk_size
+ tmv->
padding
);
176
177
avio_seek
(s->
pb
, pos +
TMV_HEADER_SIZE
, SEEK_SET);
178
tmv->
stream_index
= 0;
179
return
0;
180
}
181
182
AVInputFormat
ff_tmv_demuxer
= {
183
.
name
=
"tmv"
,
184
.long_name =
NULL_IF_CONFIG_SMALL
(
"8088flex TMV"
),
185
.priv_data_size =
sizeof
(
TMVContext
),
186
.
read_probe
=
tmv_probe
,
187
.
read_header
=
tmv_read_header
,
188
.
read_packet
=
tmv_read_packet
,
189
.
read_seek
=
tmv_read_seek
,
190
.
flags
=
AVFMT_GENERIC_INDEX
,
191
};