2 * 8088flex TMV file demuxer
3 * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
5 * This file is part of FFmpeg.
7 * FFmpeg 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.
12 * FFmpeg 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * 8088flex TMV file demuxer
24 * @file libavformat/tmv.c
25 * @author Daniel Verkamp
26 * @sa http://www.oldskool.org/pc/8088_Corruption
29 #include "libavutil/intreadwrite.h"
37 #define TMV_TAG MKTAG('T', 'M', 'A', 'V')
39 typedef struct TMVContext
{
40 unsigned audio_chunk_size
;
41 unsigned video_chunk_size
;
43 unsigned stream_index
;
46 static int tmv_probe(AVProbeData
*p
)
48 if (AV_RL32(p
->buf
) == TMV_TAG
)
49 return AVPROBE_SCORE_MAX
;
53 static int tmv_read_header(AVFormatContext
*s
, AVFormatParameters
*ap
)
55 TMVContext
*tmv
= s
->priv_data
;
56 ByteIOContext
*pb
= s
->pb
;
59 unsigned comp_method
, char_cols
, char_rows
, features
;
61 if (get_le32(pb
) != TMV_TAG
)
64 if (!(vst
= av_new_stream(s
, 0)))
65 return AVERROR(ENOMEM
);
67 if (!(ast
= av_new_stream(s
, 0)))
68 return AVERROR(ENOMEM
);
70 ast
->codec
->sample_rate
= get_le16(pb
);
71 tmv
->audio_chunk_size
= get_le16(pb
);
72 if (!tmv
->audio_chunk_size
) {
73 av_log(s
, AV_LOG_ERROR
, "invalid audio chunk size\n");
77 comp_method
= get_byte(pb
);
79 av_log(s
, AV_LOG_ERROR
, "unsupported compression method %d\n",
84 char_cols
= get_byte(pb
);
85 char_rows
= get_byte(pb
);
86 tmv
->video_chunk_size
= char_cols
* char_rows
* 2;
88 features
= get_byte(pb
);
89 if (features
& ~(TMV_PADDING
| TMV_STEREO
)) {
90 av_log(s
, AV_LOG_ERROR
, "unsupported features 0x%02x\n",
91 features
& ~(TMV_PADDING
| TMV_STEREO
));
95 ast
->codec
->codec_type
= CODEC_TYPE_AUDIO
;
96 ast
->codec
->codec_id
= CODEC_ID_PCM_U8
;
97 ast
->codec
->sample_fmt
= SAMPLE_FMT_U8
;
98 ast
->codec
->channels
= features
& TMV_STEREO
? 2 : 1;
99 ast
->codec
->bits_per_coded_sample
= 8;
100 ast
->codec
->bit_rate
= ast
->codec
->sample_rate
*
101 ast
->codec
->bits_per_coded_sample
;
102 av_set_pts_info(ast
, 32, 1, ast
->codec
->sample_rate
);
104 fps
.num
= ast
->codec
->sample_rate
* ast
->codec
->channels
;
105 fps
.den
= tmv
->audio_chunk_size
;
106 av_reduce(&fps
.num
, &fps
.den
, fps
.num
, fps
.den
, 0xFFFFFFFFLL
);
108 vst
->codec
->codec_type
= CODEC_TYPE_VIDEO
;
109 vst
->codec
->codec_id
= CODEC_ID_TMV
;
110 vst
->codec
->pix_fmt
= PIX_FMT_PAL8
;
111 vst
->codec
->width
= char_cols
* 8;
112 vst
->codec
->height
= char_rows
* 8;
113 av_set_pts_info(vst
, 32, fps
.den
, fps
.num
);
115 if (features
& TMV_PADDING
)
117 ((tmv
->video_chunk_size
+ tmv
->audio_chunk_size
+ 511) & ~511) -
118 (tmv
->video_chunk_size
+ tmv
->audio_chunk_size
);
120 vst
->codec
->bit_rate
= ((tmv
->video_chunk_size
+ tmv
->padding
) *
121 fps
.num
* 8) / fps
.den
;
126 static int tmv_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
128 TMVContext
*tmv
= s
->priv_data
;
129 ByteIOContext
*pb
= s
->pb
;
130 int ret
, pkt_size
= tmv
->stream_index
?
131 tmv
->audio_chunk_size
: tmv
->video_chunk_size
;
136 ret
= av_get_packet(pb
, pkt
, pkt_size
);
138 if (tmv
->stream_index
)
139 url_fskip(pb
, tmv
->padding
);
141 pkt
->stream_index
= tmv
->stream_index
;
142 tmv
->stream_index
^= 1;
143 pkt
->flags
|= PKT_FLAG_KEY
;
148 AVInputFormat tmv_demuxer
= {
150 NULL_IF_CONFIG_SMALL("8088flex TMV"),
155 .flags
= AVFMT_GENERIC_INDEX
,