2 * ISS (.iss) file demuxer
3 * Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net>
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
24 * Funcom ISS file demuxer
25 * @author Jaikrishnan Menon
26 * @see http://wiki.multimedia.cx/index.php?title=FunCom_ISS
29 #include "libavutil/channel_layout.h"
33 #include "libavutil/avstring.h"
35 #define ISS_SIG "IMA_ADPCM_Sound"
36 #define ISS_SIG_LEN 15
37 #define MAX_TOKEN_SIZE 20
39 typedef struct IssDemuxContext
{
44 static void get_token(AVIOContext
*s
, char *buf
, int maxlen
)
49 while ((c
= avio_r8(s
))) {
59 buf
[i
] = 0; /* Ensure null terminated, but may be truncated */
62 static int iss_probe(const AVProbeData
*p
)
64 if (strncmp(p
->buf
, ISS_SIG
, ISS_SIG_LEN
))
67 return AVPROBE_SCORE_MAX
;
70 static av_cold
int iss_read_header(AVFormatContext
*s
)
72 IssDemuxContext
*iss
= s
->priv_data
;
73 AVIOContext
*pb
= s
->pb
;
75 char token
[MAX_TOKEN_SIZE
];
76 int stereo
, rate_divisor
;
78 get_token(pb
, token
, sizeof(token
)); //"IMA_ADPCM_Sound"
79 get_token(pb
, token
, sizeof(token
)); //packet size
80 if (sscanf(token
, "%d", &iss
->packet_size
) != 1) {
81 av_log(s
, AV_LOG_ERROR
, "Failed parsing packet size\n");
82 return AVERROR_INVALIDDATA
;
84 get_token(pb
, token
, sizeof(token
)); //File ID
85 get_token(pb
, token
, sizeof(token
)); //out size
86 get_token(pb
, token
, sizeof(token
)); //stereo
87 if (sscanf(token
, "%d", &stereo
) != 1) {
88 av_log(s
, AV_LOG_ERROR
, "Failed parsing stereo flag\n");
89 return AVERROR_INVALIDDATA
;
91 get_token(pb
, token
, sizeof(token
)); //Unknown1
92 get_token(pb
, token
, sizeof(token
)); //RateDivisor
93 if (sscanf(token
, "%d", &rate_divisor
) != 1) {
94 av_log(s
, AV_LOG_ERROR
, "Failed parsing rate_divisor\n");
95 return AVERROR_INVALIDDATA
;
97 get_token(pb
, token
, sizeof(token
)); //Unknown2
98 get_token(pb
, token
, sizeof(token
)); //Version ID
99 get_token(pb
, token
, sizeof(token
)); //Size
101 if (iss
->packet_size
<= 0) {
102 av_log(s
, AV_LOG_ERROR
, "packet_size %d is invalid\n", iss
->packet_size
);
103 return AVERROR_INVALIDDATA
;
106 iss
->sample_start_pos
= avio_tell(pb
);
108 st
= avformat_new_stream(s
, NULL
);
110 return AVERROR(ENOMEM
);
111 st
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
112 st
->codecpar
->codec_id
= AV_CODEC_ID_ADPCM_IMA_ISS
;
115 st
->codecpar
->ch_layout
= (AVChannelLayout
)AV_CHANNEL_LAYOUT_STEREO
;
117 st
->codecpar
->ch_layout
= (AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
;
120 st
->codecpar
->sample_rate
= 44100;
122 st
->codecpar
->sample_rate
/= rate_divisor
;
123 st
->codecpar
->bits_per_coded_sample
= 4;
124 st
->codecpar
->bit_rate
= st
->codecpar
->ch_layout
.nb_channels
*
125 st
->codecpar
->sample_rate
*
126 st
->codecpar
->bits_per_coded_sample
;
127 st
->codecpar
->block_align
= iss
->packet_size
;
128 avpriv_set_pts_info(st
, 32, 1, st
->codecpar
->sample_rate
);
133 static int iss_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
135 IssDemuxContext
*iss
= s
->priv_data
;
136 int ret
= av_get_packet(s
->pb
, pkt
, iss
->packet_size
);
138 if(ret
!= iss
->packet_size
)
139 return AVERROR_INVALIDDATA
;
141 pkt
->stream_index
= 0;
142 pkt
->pts
= avio_tell(s
->pb
) - iss
->sample_start_pos
;
143 if (s
->streams
[0]->codecpar
->ch_layout
.nb_channels
> 0)
144 pkt
->pts
/= s
->streams
[0]->codecpar
->ch_layout
.nb_channels
* 2;
148 const FFInputFormat ff_iss_demuxer
= {
150 .p
.long_name
= NULL_IF_CONFIG_SMALL("Funcom ISS"),
151 .priv_data_size
= sizeof(IssDemuxContext
),
152 .read_probe
= iss_probe
,
153 .read_header
= iss_read_header
,
154 .read_packet
= iss_read_packet
,