3 * Copyright (c) 2015 Paul B Mahol
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
25 static int threedostr_probe(const AVProbeData
*p
)
27 if (memcmp(p
->buf
, "CTRL", 4) &&
28 memcmp(p
->buf
, "SHDR", 4) &&
29 memcmp(p
->buf
, "SNDS", 4))
32 return AVPROBE_SCORE_MAX
/ 3 * 2;
35 static int threedostr_read_header(AVFormatContext
*s
)
37 unsigned chunk
, codec
= 0, size
, ctrl_size
= -1, found_shdr
= 0;
40 while (!avio_feof(s
->pb
) && !found_shdr
) {
41 chunk
= avio_rl32(s
->pb
);
42 size
= avio_rb32(s
->pb
);
45 return AVERROR_INVALIDDATA
;
49 case MKTAG('C','T','R','L'):
52 case MKTAG('S','N','D','S'):
54 return AVERROR_INVALIDDATA
;
56 if (avio_rl32(s
->pb
) != MKTAG('S','H','D','R'))
57 return AVERROR_INVALIDDATA
;
60 st
= avformat_new_stream(s
, NULL
);
62 return AVERROR(ENOMEM
);
64 st
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
65 st
->codecpar
->sample_rate
= avio_rb32(s
->pb
);
66 st
->codecpar
->channels
= avio_rb32(s
->pb
);
67 if (st
->codecpar
->channels
<= 0 || st
->codecpar
->sample_rate
<= 0)
68 return AVERROR_INVALIDDATA
;
69 codec
= avio_rl32(s
->pb
);
71 if (ctrl_size
== 20 || ctrl_size
== 3 || ctrl_size
== -1)
72 st
->duration
= (avio_rb32(s
->pb
) - 1) / st
->codecpar
->channels
;
74 st
->duration
= avio_rb32(s
->pb
) * 16 / st
->codecpar
->channels
;
78 case MKTAG('S','H','D','R'):
80 avio_skip(s
->pb
, 0x74);
82 if (avio_rl32(s
->pb
) == MKTAG('C','T','R','L') && size
> 4) {
83 ctrl_size
= avio_rb32(s
->pb
);
89 av_log(s
, AV_LOG_DEBUG
, "skipping unknown chunk: %X\n", chunk
);
93 avio_skip(s
->pb
, size
);
97 case MKTAG('S','D','X','2'):
98 st
->codecpar
->codec_id
= AV_CODEC_ID_SDX2_DPCM
;
99 st
->codecpar
->block_align
= 1 * st
->codecpar
->channels
;
102 avpriv_request_sample(s
, "codec %X", codec
);
103 return AVERROR_PATCHWELCOME
;
106 avpriv_set_pts_info(st
, 64, 1, st
->codecpar
->sample_rate
);
111 static int threedostr_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
113 unsigned chunk
, size
, found_ssmp
= 0;
114 AVStream
*st
= s
->streams
[0];
118 while (!found_ssmp
) {
119 if (avio_feof(s
->pb
))
122 pos
= avio_tell(s
->pb
);
123 chunk
= avio_rl32(s
->pb
);
124 size
= avio_rb32(s
->pb
);
130 return AVERROR_INVALIDDATA
;
134 case MKTAG('S','N','D','S'):
136 return AVERROR_INVALIDDATA
;
138 if (avio_rl32(s
->pb
) != MKTAG('S','S','M','P'))
139 return AVERROR_INVALIDDATA
;
142 ret
= av_get_packet(s
->pb
, pkt
, size
);
144 pkt
->stream_index
= 0;
145 pkt
->duration
= size
/ st
->codecpar
->channels
;
150 av_log(s
, AV_LOG_DEBUG
, "skipping unknown chunk: %X\n", chunk
);
154 avio_skip(s
->pb
, size
);
160 AVInputFormat ff_threedostr_demuxer
= {
162 .long_name
= NULL_IF_CONFIG_SMALL("3DO STR"),
163 .read_probe
= threedostr_probe
,
164 .read_header
= threedostr_read_header
,
165 .read_packet
= threedostr_read_packet
,
167 .flags
= AVFMT_GENERIC_INDEX
,