2 * Simon & Schuster Interactive VAG (de)muxer
4 * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com)
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "config_components.h"
25 #include "libavutil/channel_layout.h"
27 #include "avio_internal.h"
32 #include "libavutil/intreadwrite.h"
34 #define KVAG_TAG MKTAG('K', 'V', 'A', 'G')
35 #define KVAG_HEADER_SIZE 14
36 #define KVAG_MAX_READ_SIZE 4096
38 typedef struct KVAGHeader
{
45 #if CONFIG_KVAG_DEMUXER
46 static int kvag_probe(const AVProbeData
*p
)
48 if (AV_RL32(p
->buf
) != KVAG_TAG
)
51 return AVPROBE_SCORE_EXTENSION
+ 1;
54 static int kvag_read_header(AVFormatContext
*s
)
59 AVCodecParameters
*par
;
60 uint8_t buf
[KVAG_HEADER_SIZE
];
62 if (!(st
= avformat_new_stream(s
, NULL
)))
63 return AVERROR(ENOMEM
);
65 if ((ret
= ffio_read_size(s
->pb
, buf
, KVAG_HEADER_SIZE
)) < 0)
68 hdr
.magic
= AV_RL32(buf
+ 0);
69 hdr
.data_size
= AV_RL32(buf
+ 4);
70 hdr
.sample_rate
= AV_RL32(buf
+ 8);
71 hdr
.stereo
= AV_RL16(buf
+ 12);
73 if (hdr
.sample_rate
<= 0)
74 return AVERROR_INVALIDDATA
;
77 par
->codec_type
= AVMEDIA_TYPE_AUDIO
;
78 par
->codec_id
= AV_CODEC_ID_ADPCM_IMA_SSI
;
79 par
->format
= AV_SAMPLE_FMT_S16
;
81 av_channel_layout_default(&par
->ch_layout
, !!hdr
.stereo
+ 1);
82 par
->sample_rate
= hdr
.sample_rate
;
83 par
->bits_per_coded_sample
= 4;
85 par
->bit_rate
= par
->ch_layout
.nb_channels
*
86 (uint64_t)par
->sample_rate
*
87 par
->bits_per_coded_sample
;
89 avpriv_set_pts_info(st
, 64, 1, par
->sample_rate
);
91 st
->duration
= hdr
.data_size
*
92 (8 / par
->bits_per_coded_sample
) /
93 par
->ch_layout
.nb_channels
;
98 static int kvag_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
101 AVCodecParameters
*par
= s
->streams
[0]->codecpar
;
103 if ((ret
= av_get_packet(s
->pb
, pkt
, KVAG_MAX_READ_SIZE
)) < 0)
106 pkt
->flags
&= ~AV_PKT_FLAG_CORRUPT
;
107 pkt
->stream_index
= 0;
108 pkt
->duration
= ret
* (8 / par
->bits_per_coded_sample
) / par
->ch_layout
.nb_channels
;
113 static int kvag_seek(AVFormatContext
*s
, int stream_index
,
114 int64_t pts
, int flags
)
117 return AVERROR(EINVAL
);
119 return avio_seek(s
->pb
, KVAG_HEADER_SIZE
, SEEK_SET
);
122 const FFInputFormat ff_kvag_demuxer
= {
124 .p
.long_name
= NULL_IF_CONFIG_SMALL("Simon & Schuster Interactive VAG"),
125 .read_probe
= kvag_probe
,
126 .read_header
= kvag_read_header
,
127 .read_packet
= kvag_read_packet
,
128 .read_seek
= kvag_seek
,
132 #if CONFIG_KVAG_MUXER
133 static int kvag_write_init(AVFormatContext
*s
)
135 AVCodecParameters
*par
= s
->streams
[0]->codecpar
;
137 if (par
->ch_layout
.nb_channels
> 2) {
138 av_log(s
, AV_LOG_ERROR
, "KVAG files only support up to 2 channels\n");
139 return AVERROR(EINVAL
);
142 if (!(s
->pb
->seekable
& AVIO_SEEKABLE_NORMAL
)) {
143 av_log(s
, AV_LOG_WARNING
, "Stream not seekable, unable to write output file\n");
144 return AVERROR(EINVAL
);
150 static int kvag_write_header(AVFormatContext
*s
)
152 uint8_t buf
[KVAG_HEADER_SIZE
];
153 AVCodecParameters
*par
= s
->streams
[0]->codecpar
;
155 AV_WL32(buf
+ 0, KVAG_TAG
);
156 AV_WL32(buf
+ 4, 0); /* Data size, we fix this up later. */
157 AV_WL32(buf
+ 8, par
->sample_rate
);
158 AV_WL16(buf
+ 12, par
->ch_layout
.nb_channels
== 2);
160 avio_write(s
->pb
, buf
, sizeof(buf
));
164 static int kvag_write_trailer(AVFormatContext
*s
)
166 int64_t file_size
, data_size
;
168 file_size
= avio_tell(s
->pb
);
169 data_size
= file_size
- KVAG_HEADER_SIZE
;
170 if (data_size
< UINT32_MAX
) {
171 avio_seek(s
->pb
, 4, SEEK_SET
);
172 avio_wl32(s
->pb
, (uint32_t)data_size
);
173 avio_seek(s
->pb
, file_size
, SEEK_SET
);
175 av_log(s
, AV_LOG_WARNING
,
176 "Filesize %"PRId64
" invalid for KVAG, output file will be broken\n",
183 const FFOutputFormat ff_kvag_muxer
= {
185 .p
.long_name
= NULL_IF_CONFIG_SMALL("Simon & Schuster Interactive VAG"),
186 .p
.extensions
= "vag",
187 .p
.audio_codec
= AV_CODEC_ID_ADPCM_IMA_SSI
,
188 .p
.video_codec
= AV_CODEC_ID_NONE
,
189 .p
.subtitle_codec
= AV_CODEC_ID_NONE
,
190 .flags_internal
= FF_OFMT_FLAG_MAX_ONE_OF_EACH
|
191 FF_OFMT_FLAG_ONLY_DEFAULT_CODECS
,
192 .init
= kvag_write_init
,
193 .write_header
= kvag_write_header
,
194 .write_packet
= ff_raw_write_packet
,
195 .write_trailer
= kvag_write_trailer