]> git.sesse.net Git - ffmpeg/blob - libavformat/kvag.c
avformat: add demuxer for Simon & Schuster Interactive's VAG format
[ffmpeg] / libavformat / kvag.c
1 /*
2  * Simon & Schuster Interactive VAG demuxer
3  *
4  * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com)
5  *
6  * This file is part of FFmpeg.
7  *
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.
12  *
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.
17  *
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
21  */
22 #include "avformat.h"
23 #include "internal.h"
24 #include "libavutil/intreadwrite.h"
25
26 #define KVAG_TAG            MKTAG('K', 'V', 'A', 'G')
27 #define KVAG_HEADER_SIZE    14
28 #define KVAG_MAX_READ_SIZE  4096
29
30 typedef struct KVAGHeader {
31     uint32_t    magic;
32     uint32_t    data_size;
33     uint32_t    sample_rate;
34     uint16_t    stereo;
35 } KVAGHeader;
36
37 static int kvag_probe(const AVProbeData *p)
38 {
39     if (AV_RL32(p->buf) != KVAG_TAG)
40         return 0;
41
42     return AVPROBE_SCORE_EXTENSION + 1;
43 }
44
45 static int kvag_read_header(AVFormatContext *s)
46 {
47     int ret;
48     AVStream *st;
49     KVAGHeader hdr;
50     AVCodecParameters *par;
51     uint8_t buf[KVAG_HEADER_SIZE];
52
53     if (!(st = avformat_new_stream(s, NULL)))
54         return AVERROR(ENOMEM);
55
56     if ((ret = avio_read(s->pb, buf, KVAG_HEADER_SIZE)) < 0)
57         return ret;
58     else if (ret != KVAG_HEADER_SIZE)
59         return AVERROR(EIO);
60
61     hdr.magic                   = AV_RL32(buf +  0);
62     hdr.data_size               = AV_RL32(buf +  4);
63     hdr.sample_rate             = AV_RL32(buf +  8);
64     hdr.stereo                  = AV_RL16(buf + 12);
65
66     par                         = st->codecpar;
67     par->codec_type             = AVMEDIA_TYPE_AUDIO;
68     par->codec_id               = AV_CODEC_ID_ADPCM_IMA_SSI;
69     par->format                 = AV_SAMPLE_FMT_S16;
70
71     if (hdr.stereo) {
72         par->channel_layout     = AV_CH_LAYOUT_STEREO;
73         par->channels           = 2;
74     } else {
75         par->channel_layout     = AV_CH_LAYOUT_MONO;
76         par->channels           = 1;
77     }
78
79     par->sample_rate            = hdr.sample_rate;
80     par->bits_per_coded_sample  = 4;
81     par->bits_per_raw_sample    = 16;
82     par->block_align            = 1;
83     par->bit_rate               = par->channels *
84                                   par->sample_rate *
85                                   par->bits_per_coded_sample;
86
87     avpriv_set_pts_info(st, 64, 1, par->sample_rate);
88     st->start_time              = 0;
89     st->duration                = hdr.data_size *
90                                   (8 / par->bits_per_coded_sample) /
91                                   par->channels;
92
93     return 0;
94 }
95
96 static int kvag_read_packet(AVFormatContext *s, AVPacket *pkt)
97 {
98     int ret;
99     AVCodecParameters *par = s->streams[0]->codecpar;
100
101     if ((ret = av_get_packet(s->pb, pkt, KVAG_MAX_READ_SIZE)) < 0)
102         return ret;
103
104     pkt->flags          &= ~AV_PKT_FLAG_CORRUPT;
105     pkt->stream_index   = 0;
106     pkt->duration       = ret * (8 / par->bits_per_coded_sample) / par->channels;
107
108     return 0;
109 }
110
111 AVInputFormat ff_kvag_demuxer = {
112     .name           = "kvag",
113     .long_name      = NULL_IF_CONFIG_SMALL("Simon & Schuster Interactive VAG"),
114     .read_probe     = kvag_probe,
115     .read_header    = kvag_read_header,
116     .read_packet    = kvag_read_packet
117 };