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