]> git.sesse.net Git - ffmpeg/blob - libavformat/apm.c
avcodec/dvbsubdec: prefer to use variable instead of type for sizeof
[ffmpeg] / libavformat / apm.c
1 /*
2  * Rayman 2 APM 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 "riff.h"
25 #include "libavutil/internal.h"
26 #include "libavutil/intreadwrite.h"
27
28 #define APM_FILE_HEADER_SIZE    20
29 #define APM_VS12_CHUNK_SIZE     76
30 #define APM_MAX_READ_SIZE       4096
31
32 #define APM_TAG_CODEC           0x2000
33 #define APM_TAG_VS12            MKTAG('v', 's', '1', '2')
34 #define APM_TAG_DATA            MKTAG('D', 'A', 'T', 'A')
35
36 typedef struct APMState {
37     int32_t     has_saved;
38     int32_t     predictor_r;
39     int32_t     step_index_r;
40     int32_t     saved_r;
41     int32_t     predictor_l;
42     int32_t     step_index_l;
43     int32_t     saved_l;
44 } APMState;
45
46 typedef struct APMVS12Chunk {
47     uint32_t    magic;
48     uint32_t    file_size;
49     uint32_t    data_size;
50     uint32_t    unk1;
51     uint32_t    unk2;
52     APMState    state;
53     uint32_t    pad[7];
54 } APMVS12Chunk;
55
56 static void apm_parse_vs12(APMVS12Chunk *vs12, const uint8_t *buf)
57 {
58     vs12->magic                 = AV_RL32(buf + 0);
59     vs12->file_size             = AV_RL32(buf + 4);
60     vs12->data_size             = AV_RL32(buf + 8);
61     vs12->unk1                  = AV_RL32(buf + 12);
62     vs12->unk2                  = AV_RL32(buf + 16);
63
64     vs12->state.has_saved       = AV_RL32(buf + 20);
65     vs12->state.predictor_r     = AV_RL32(buf + 24);
66     vs12->state.step_index_r    = AV_RL32(buf + 28);
67     vs12->state.saved_r         = AV_RL32(buf + 32);
68     vs12->state.predictor_l     = AV_RL32(buf + 36);
69     vs12->state.step_index_l    = AV_RL32(buf + 40);
70     vs12->state.saved_l         = AV_RL32(buf + 44);
71
72     for (int i = 0; i < FF_ARRAY_ELEMS(vs12->pad); i++)
73         vs12->pad[i]            = AV_RL32(buf + 48 + (i * 4));
74 }
75
76 static int apm_probe(const AVProbeData *p)
77 {
78     if (AV_RL16(p->buf) != APM_TAG_CODEC)
79         return 0;
80
81     if (p->buf_size < 100)
82         return 0;
83
84     if (AV_RL32(p->buf + 20) != APM_TAG_VS12)
85         return 0;
86
87     if (AV_RL32(p->buf + 96) != APM_TAG_DATA)
88         return 0;
89
90     return AVPROBE_SCORE_MAX - 1;
91 }
92
93 static int apm_read_header(AVFormatContext *s)
94 {
95     int64_t ret;
96     AVStream *st;
97     APMVS12Chunk vs12;
98     uint8_t buf[APM_VS12_CHUNK_SIZE];
99
100     if (!(st = avformat_new_stream(s, NULL)))
101         return AVERROR(ENOMEM);
102
103     /* The header starts with a WAVEFORMATEX */
104     if ((ret = ff_get_wav_header(s, s->pb, st->codecpar, APM_FILE_HEADER_SIZE, 0)) < 0)
105         return ret;
106
107     if (st->codecpar->bits_per_coded_sample != 4)
108         return AVERROR_INVALIDDATA;
109
110     if (st->codecpar->codec_tag != APM_TAG_CODEC)
111         return AVERROR_INVALIDDATA;
112
113     /* ff_get_wav_header() does most of the work, but we need to fix a few things. */
114     st->codecpar->codec_id              = AV_CODEC_ID_ADPCM_IMA_APM;
115     st->codecpar->codec_tag             = 0;
116
117     if (st->codecpar->channels == 2)
118         st->codecpar->channel_layout    = AV_CH_LAYOUT_STEREO;
119     else if (st->codecpar->channels == 1)
120         st->codecpar->channel_layout    = AV_CH_LAYOUT_MONO;
121     else
122         return AVERROR_INVALIDDATA;
123
124     st->codecpar->format                = AV_SAMPLE_FMT_S16;
125     st->codecpar->bits_per_raw_sample   = 16;
126     st->codecpar->bit_rate              = st->codecpar->channels *
127                                           st->codecpar->sample_rate *
128                                           st->codecpar->bits_per_coded_sample;
129
130     if ((ret = avio_read(s->pb, buf, APM_VS12_CHUNK_SIZE)) < 0)
131         return ret;
132     else if (ret != APM_VS12_CHUNK_SIZE)
133         return AVERROR(EIO);
134
135     apm_parse_vs12(&vs12, buf);
136
137     if (vs12.magic != APM_TAG_VS12) {
138         return AVERROR_INVALIDDATA;
139     }
140
141     if (vs12.state.has_saved) {
142         avpriv_request_sample(s, "Saved Samples");
143         return AVERROR_PATCHWELCOME;
144     }
145
146     if (avio_rl32(s->pb) != APM_TAG_DATA)
147         return AVERROR_INVALIDDATA;
148
149     if ((ret = ff_alloc_extradata(st->codecpar, 16)) < 0)
150         return ret;
151
152     AV_WL32(st->codecpar->extradata +  0, vs12.state.predictor_l);
153     AV_WL32(st->codecpar->extradata +  4, vs12.state.step_index_l);
154     AV_WL32(st->codecpar->extradata +  8, vs12.state.predictor_r);
155     AV_WL32(st->codecpar->extradata + 12, vs12.state.step_index_r);
156
157     avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
158     st->start_time  = 0;
159     st->duration    = vs12.data_size *
160                       (8 / st->codecpar->bits_per_coded_sample) /
161                       st->codecpar->channels;
162     return 0;
163 }
164
165 static int apm_read_packet(AVFormatContext *s, AVPacket *pkt)
166 {
167     int ret;
168     AVCodecParameters *par = s->streams[0]->codecpar;
169
170     /*
171      * For future reference: if files with the `has_saved` field set ever
172      * surface, `saved_l`, and `saved_r` will each contain 8 "saved" samples
173      * that should be sent to the decoder before the actual data.
174      */
175
176     if ((ret = av_get_packet(s->pb, pkt, APM_MAX_READ_SIZE)) < 0)
177         return ret;
178
179     pkt->flags          &= ~AV_PKT_FLAG_CORRUPT;
180     pkt->stream_index   = 0;
181     pkt->duration       = ret * (8 / par->bits_per_coded_sample) / par->channels;
182
183     return 0;
184 }
185
186 AVInputFormat ff_apm_demuxer = {
187     .name           = "apm",
188     .long_name      = NULL_IF_CONFIG_SMALL("Ubisoft Rayman 2 APM"),
189     .read_probe     = apm_probe,
190     .read_header    = apm_read_header,
191     .read_packet    = apm_read_packet
192 };