1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * VQF demuxer
3cabdff1aSopenharmony_ci * Copyright (c) 2009 Vitor Sessak
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci#include "avformat.h"
23cabdff1aSopenharmony_ci#include "internal.h"
24cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
25cabdff1aSopenharmony_ci#include "libavutil/dict.h"
26cabdff1aSopenharmony_ci#include "libavutil/mathematics.h"
27cabdff1aSopenharmony_ci#include "riff.h"
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_citypedef struct VqfContext {
30cabdff1aSopenharmony_ci    int frame_bit_len;
31cabdff1aSopenharmony_ci    uint8_t last_frame_bits;
32cabdff1aSopenharmony_ci    int remaining_bits;
33cabdff1aSopenharmony_ci} VqfContext;
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_cistatic int vqf_probe(const AVProbeData *probe_packet)
36cabdff1aSopenharmony_ci{
37cabdff1aSopenharmony_ci    if (AV_RL32(probe_packet->buf) != MKTAG('T','W','I','N'))
38cabdff1aSopenharmony_ci        return 0;
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_ci    if (!memcmp(probe_packet->buf + 4, "97012000", 8))
41cabdff1aSopenharmony_ci        return AVPROBE_SCORE_MAX;
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_ci    if (!memcmp(probe_packet->buf + 4, "00052200", 8))
44cabdff1aSopenharmony_ci        return AVPROBE_SCORE_MAX;
45cabdff1aSopenharmony_ci
46cabdff1aSopenharmony_ci    if (AV_RL32(probe_packet->buf + 12) > (1<<27))
47cabdff1aSopenharmony_ci        return AVPROBE_SCORE_EXTENSION/2;
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_ci    return AVPROBE_SCORE_EXTENSION;
50cabdff1aSopenharmony_ci}
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_cistatic void add_metadata(AVFormatContext *s, uint32_t tag,
53cabdff1aSopenharmony_ci                         unsigned int tag_len, unsigned int remaining)
54cabdff1aSopenharmony_ci{
55cabdff1aSopenharmony_ci    int len = FFMIN(tag_len, remaining);
56cabdff1aSopenharmony_ci    char *buf, key[5] = {0};
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci    if (len == UINT_MAX)
59cabdff1aSopenharmony_ci        return;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci    buf = av_malloc(len+1);
62cabdff1aSopenharmony_ci    if (!buf)
63cabdff1aSopenharmony_ci        return;
64cabdff1aSopenharmony_ci    avio_read(s->pb, buf, len);
65cabdff1aSopenharmony_ci    buf[len] = 0;
66cabdff1aSopenharmony_ci    AV_WL32(key, tag);
67cabdff1aSopenharmony_ci    av_dict_set(&s->metadata, key, buf, AV_DICT_DONT_STRDUP_VAL);
68cabdff1aSopenharmony_ci}
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_cistatic const AVMetadataConv vqf_metadata_conv[] = {
71cabdff1aSopenharmony_ci    { "(c) ", "copyright" },
72cabdff1aSopenharmony_ci    { "ARNG", "arranger"  },
73cabdff1aSopenharmony_ci    { "AUTH", "author"    },
74cabdff1aSopenharmony_ci    { "BAND", "band"      },
75cabdff1aSopenharmony_ci    { "CDCT", "conductor" },
76cabdff1aSopenharmony_ci    { "COMT", "comment"   },
77cabdff1aSopenharmony_ci    { "FILE", "filename"  },
78cabdff1aSopenharmony_ci    { "GENR", "genre"     },
79cabdff1aSopenharmony_ci    { "LABL", "publisher" },
80cabdff1aSopenharmony_ci    { "MUSC", "composer"  },
81cabdff1aSopenharmony_ci    { "NAME", "title"     },
82cabdff1aSopenharmony_ci    { "NOTE", "note"      },
83cabdff1aSopenharmony_ci    { "PROD", "producer"  },
84cabdff1aSopenharmony_ci    { "PRSN", "personnel" },
85cabdff1aSopenharmony_ci    { "REMX", "remixer"   },
86cabdff1aSopenharmony_ci    { "SING", "singer"    },
87cabdff1aSopenharmony_ci    { "TRCK", "track"     },
88cabdff1aSopenharmony_ci    { "WORD", "words"     },
89cabdff1aSopenharmony_ci    { 0 },
90cabdff1aSopenharmony_ci};
91cabdff1aSopenharmony_ci
92cabdff1aSopenharmony_cistatic int vqf_read_header(AVFormatContext *s)
93cabdff1aSopenharmony_ci{
94cabdff1aSopenharmony_ci    VqfContext *c = s->priv_data;
95cabdff1aSopenharmony_ci    AVStream *st  = avformat_new_stream(s, NULL);
96cabdff1aSopenharmony_ci    int chunk_tag;
97cabdff1aSopenharmony_ci    int rate_flag = -1;
98cabdff1aSopenharmony_ci    int header_size;
99cabdff1aSopenharmony_ci    int read_bitrate = 0;
100cabdff1aSopenharmony_ci    int size, ret;
101cabdff1aSopenharmony_ci    uint8_t comm_chunk[12];
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_ci    if (!st)
104cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
105cabdff1aSopenharmony_ci
106cabdff1aSopenharmony_ci    avio_skip(s->pb, 12);
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_ci    header_size = avio_rb32(s->pb);
109cabdff1aSopenharmony_ci
110cabdff1aSopenharmony_ci    if (header_size < 0)
111cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
112cabdff1aSopenharmony_ci
113cabdff1aSopenharmony_ci    st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
114cabdff1aSopenharmony_ci    st->codecpar->codec_id   = AV_CODEC_ID_TWINVQ;
115cabdff1aSopenharmony_ci    st->start_time = 0;
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ci    do {
118cabdff1aSopenharmony_ci        int len;
119cabdff1aSopenharmony_ci        chunk_tag = avio_rl32(s->pb);
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_ci        if (chunk_tag == MKTAG('D','A','T','A'))
122cabdff1aSopenharmony_ci            break;
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_ci        len = avio_rb32(s->pb);
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_ci        if ((unsigned) len > INT_MAX/2 || header_size < 8) {
127cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "Malformed header\n");
128cabdff1aSopenharmony_ci            return -1;
129cabdff1aSopenharmony_ci        }
130cabdff1aSopenharmony_ci
131cabdff1aSopenharmony_ci        header_size -= 8;
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_ci        switch(chunk_tag){
134cabdff1aSopenharmony_ci        case MKTAG('C','O','M','M'):
135cabdff1aSopenharmony_ci            if (len < 12)
136cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci            avio_read(s->pb, comm_chunk, 12);
139cabdff1aSopenharmony_ci            st->codecpar->ch_layout.nb_channels = AV_RB32(comm_chunk) + 1;
140cabdff1aSopenharmony_ci            read_bitrate        = AV_RB32(comm_chunk + 4);
141cabdff1aSopenharmony_ci            rate_flag           = AV_RB32(comm_chunk + 8);
142cabdff1aSopenharmony_ci            avio_skip(s->pb, len-12);
143cabdff1aSopenharmony_ci
144cabdff1aSopenharmony_ci            if (st->codecpar->ch_layout.nb_channels <= 0) {
145cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "Invalid number of channels\n");
146cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
147cabdff1aSopenharmony_ci            }
148cabdff1aSopenharmony_ci
149cabdff1aSopenharmony_ci            st->codecpar->bit_rate = (int64_t)read_bitrate * 1000;
150cabdff1aSopenharmony_ci            break;
151cabdff1aSopenharmony_ci        case MKTAG('D','S','I','Z'): // size of compressed data
152cabdff1aSopenharmony_ci        {
153cabdff1aSopenharmony_ci            av_dict_set_int(&s->metadata, "size", avio_rb32(s->pb), 0);
154cabdff1aSopenharmony_ci        }
155cabdff1aSopenharmony_ci            break;
156cabdff1aSopenharmony_ci        case MKTAG('Y','E','A','R'): // recording date
157cabdff1aSopenharmony_ci        case MKTAG('E','N','C','D'): // compression date
158cabdff1aSopenharmony_ci        case MKTAG('E','X','T','R'): // reserved
159cabdff1aSopenharmony_ci        case MKTAG('_','Y','M','H'): // reserved
160cabdff1aSopenharmony_ci        case MKTAG('_','N','T','T'): // reserved
161cabdff1aSopenharmony_ci        case MKTAG('_','I','D','3'): // reserved for ID3 tags
162cabdff1aSopenharmony_ci            avio_skip(s->pb, FFMIN(len, header_size));
163cabdff1aSopenharmony_ci            break;
164cabdff1aSopenharmony_ci        default:
165cabdff1aSopenharmony_ci            add_metadata(s, chunk_tag, len, header_size);
166cabdff1aSopenharmony_ci            break;
167cabdff1aSopenharmony_ci        }
168cabdff1aSopenharmony_ci
169cabdff1aSopenharmony_ci        header_size -= len;
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_ci    } while (header_size >= 0 && !avio_feof(s->pb));
172cabdff1aSopenharmony_ci
173cabdff1aSopenharmony_ci    switch (rate_flag) {
174cabdff1aSopenharmony_ci    case -1:
175cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "COMM tag not found!\n");
176cabdff1aSopenharmony_ci        return -1;
177cabdff1aSopenharmony_ci    case 44:
178cabdff1aSopenharmony_ci        st->codecpar->sample_rate = 44100;
179cabdff1aSopenharmony_ci        break;
180cabdff1aSopenharmony_ci    case 22:
181cabdff1aSopenharmony_ci        st->codecpar->sample_rate = 22050;
182cabdff1aSopenharmony_ci        break;
183cabdff1aSopenharmony_ci    case 11:
184cabdff1aSopenharmony_ci        st->codecpar->sample_rate = 11025;
185cabdff1aSopenharmony_ci        break;
186cabdff1aSopenharmony_ci    default:
187cabdff1aSopenharmony_ci        if (rate_flag < 8 || rate_flag > 44) {
188cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "Invalid rate flag %d\n", rate_flag);
189cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
190cabdff1aSopenharmony_ci        }
191cabdff1aSopenharmony_ci        st->codecpar->sample_rate = rate_flag*1000;
192cabdff1aSopenharmony_ci        break;
193cabdff1aSopenharmony_ci    }
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    if (read_bitrate / st->codecpar->ch_layout.nb_channels <  8 ||
196cabdff1aSopenharmony_ci        read_bitrate / st->codecpar->ch_layout.nb_channels > 48) {
197cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Invalid bitrate per channel %d\n",
198cabdff1aSopenharmony_ci               read_bitrate / st->codecpar->ch_layout.nb_channels);
199cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
200cabdff1aSopenharmony_ci    }
201cabdff1aSopenharmony_ci
202cabdff1aSopenharmony_ci    switch (((st->codecpar->sample_rate/1000) << 8) +
203cabdff1aSopenharmony_ci            read_bitrate/st->codecpar->ch_layout.nb_channels) {
204cabdff1aSopenharmony_ci    case (11<<8) + 8 :
205cabdff1aSopenharmony_ci    case (8 <<8) + 8 :
206cabdff1aSopenharmony_ci    case (11<<8) + 10:
207cabdff1aSopenharmony_ci    case (22<<8) + 32:
208cabdff1aSopenharmony_ci        size = 512;
209cabdff1aSopenharmony_ci        break;
210cabdff1aSopenharmony_ci    case (16<<8) + 16:
211cabdff1aSopenharmony_ci    case (22<<8) + 20:
212cabdff1aSopenharmony_ci    case (22<<8) + 24:
213cabdff1aSopenharmony_ci        size = 1024;
214cabdff1aSopenharmony_ci        break;
215cabdff1aSopenharmony_ci    case (44<<8) + 40:
216cabdff1aSopenharmony_ci    case (44<<8) + 48:
217cabdff1aSopenharmony_ci        size = 2048;
218cabdff1aSopenharmony_ci        break;
219cabdff1aSopenharmony_ci    default:
220cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Mode not supported: %d Hz, %"PRId64" kb/s.\n",
221cabdff1aSopenharmony_ci               st->codecpar->sample_rate, st->codecpar->bit_rate);
222cabdff1aSopenharmony_ci        return -1;
223cabdff1aSopenharmony_ci    }
224cabdff1aSopenharmony_ci    c->frame_bit_len = st->codecpar->bit_rate*size/st->codecpar->sample_rate;
225cabdff1aSopenharmony_ci    avpriv_set_pts_info(st, 64, size, st->codecpar->sample_rate);
226cabdff1aSopenharmony_ci
227cabdff1aSopenharmony_ci    /* put first 12 bytes of COMM chunk in extradata */
228cabdff1aSopenharmony_ci    if ((ret = ff_alloc_extradata(st->codecpar, 12)) < 0)
229cabdff1aSopenharmony_ci        return ret;
230cabdff1aSopenharmony_ci    memcpy(st->codecpar->extradata, comm_chunk, 12);
231cabdff1aSopenharmony_ci
232cabdff1aSopenharmony_ci    ff_metadata_conv_ctx(s, NULL, vqf_metadata_conv);
233cabdff1aSopenharmony_ci
234cabdff1aSopenharmony_ci    return 0;
235cabdff1aSopenharmony_ci}
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_cistatic int vqf_read_packet(AVFormatContext *s, AVPacket *pkt)
238cabdff1aSopenharmony_ci{
239cabdff1aSopenharmony_ci    VqfContext *c = s->priv_data;
240cabdff1aSopenharmony_ci    int ret;
241cabdff1aSopenharmony_ci    int size = (c->frame_bit_len - c->remaining_bits + 7)>>3;
242cabdff1aSopenharmony_ci
243cabdff1aSopenharmony_ci    if ((ret = av_new_packet(pkt, size + 2)) < 0)
244cabdff1aSopenharmony_ci        return ret;
245cabdff1aSopenharmony_ci
246cabdff1aSopenharmony_ci    pkt->pos          = avio_tell(s->pb);
247cabdff1aSopenharmony_ci    pkt->stream_index = 0;
248cabdff1aSopenharmony_ci    pkt->duration     = 1;
249cabdff1aSopenharmony_ci
250cabdff1aSopenharmony_ci    pkt->data[0] = 8 - c->remaining_bits; // Number of bits to skip
251cabdff1aSopenharmony_ci    pkt->data[1] = c->last_frame_bits;
252cabdff1aSopenharmony_ci    ret = avio_read(s->pb, pkt->data+2, size);
253cabdff1aSopenharmony_ci
254cabdff1aSopenharmony_ci    if (ret != size) {
255cabdff1aSopenharmony_ci        return AVERROR(EIO);
256cabdff1aSopenharmony_ci    }
257cabdff1aSopenharmony_ci
258cabdff1aSopenharmony_ci    c->last_frame_bits = pkt->data[size+1];
259cabdff1aSopenharmony_ci    c->remaining_bits  = (size << 3) - c->frame_bit_len + c->remaining_bits;
260cabdff1aSopenharmony_ci
261cabdff1aSopenharmony_ci    return size+2;
262cabdff1aSopenharmony_ci}
263cabdff1aSopenharmony_ci
264cabdff1aSopenharmony_cistatic int vqf_read_seek(AVFormatContext *s,
265cabdff1aSopenharmony_ci                         int stream_index, int64_t timestamp, int flags)
266cabdff1aSopenharmony_ci{
267cabdff1aSopenharmony_ci    VqfContext *c = s->priv_data;
268cabdff1aSopenharmony_ci    AVStream *st;
269cabdff1aSopenharmony_ci    int64_t ret;
270cabdff1aSopenharmony_ci    int64_t pos;
271cabdff1aSopenharmony_ci
272cabdff1aSopenharmony_ci    st = s->streams[stream_index];
273cabdff1aSopenharmony_ci    pos = av_rescale_rnd(timestamp * st->codecpar->bit_rate,
274cabdff1aSopenharmony_ci                         st->time_base.num,
275cabdff1aSopenharmony_ci                         st->time_base.den * (int64_t)c->frame_bit_len,
276cabdff1aSopenharmony_ci                         (flags & AVSEEK_FLAG_BACKWARD) ?
277cabdff1aSopenharmony_ci                                                   AV_ROUND_DOWN : AV_ROUND_UP);
278cabdff1aSopenharmony_ci    pos *= c->frame_bit_len;
279cabdff1aSopenharmony_ci
280cabdff1aSopenharmony_ci    ffstream(st)->cur_dts = av_rescale(pos, st->time_base.den,
281cabdff1aSopenharmony_ci                             st->codecpar->bit_rate * (int64_t)st->time_base.num);
282cabdff1aSopenharmony_ci
283cabdff1aSopenharmony_ci    if ((ret = avio_seek(s->pb, ((pos-7) >> 3) + ffformatcontext(s)->data_offset, SEEK_SET)) < 0)
284cabdff1aSopenharmony_ci        return ret;
285cabdff1aSopenharmony_ci
286cabdff1aSopenharmony_ci    c->remaining_bits = -7 - ((pos-7)&7);
287cabdff1aSopenharmony_ci    return 0;
288cabdff1aSopenharmony_ci}
289cabdff1aSopenharmony_ci
290cabdff1aSopenharmony_ciconst AVInputFormat ff_vqf_demuxer = {
291cabdff1aSopenharmony_ci    .name           = "vqf",
292cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("Nippon Telegraph and Telephone Corporation (NTT) TwinVQ"),
293cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VqfContext),
294cabdff1aSopenharmony_ci    .read_probe     = vqf_probe,
295cabdff1aSopenharmony_ci    .read_header    = vqf_read_header,
296cabdff1aSopenharmony_ci    .read_packet    = vqf_read_packet,
297cabdff1aSopenharmony_ci    .read_seek      = vqf_read_seek,
298cabdff1aSopenharmony_ci    .extensions     = "vqf,vql,vqe",
299cabdff1aSopenharmony_ci};
300