yading@11: /* yading@11: * QCP format (.qcp) demuxer yading@11: * Copyright (c) 2009 Kenan Gillet yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: /** yading@11: * @file yading@11: * QCP format (.qcp) demuxer yading@11: * @author Kenan Gillet yading@11: * @see RFC 3625: "The QCP File Format and Media Types for Speech Data" yading@11: * http://tools.ietf.org/html/rfc3625 yading@11: */ yading@11: yading@11: #include "libavutil/channel_layout.h" yading@11: #include "libavutil/intreadwrite.h" yading@11: #include "avformat.h" yading@11: yading@11: typedef struct { yading@11: uint32_t data_size; ///< size of data chunk yading@11: yading@11: #define QCP_MAX_MODE 4 yading@11: int16_t rates_per_mode[QCP_MAX_MODE+1]; ///< contains the packet size corresponding yading@11: ///< to each mode, -1 if no size. yading@11: } QCPContext; yading@11: yading@11: /** yading@11: * Last 15 out of 16 bytes of QCELP-13K GUID, as stored in the file; yading@11: * the first byte of the GUID can be either 0x41 or 0x42. yading@11: */ yading@11: static const uint8_t guid_qcelp_13k_part[15] = { yading@11: 0x6d, 0x7f, 0x5e, 0x15, 0xb1, 0xd0, 0x11, 0xba, yading@11: 0x91, 0x00, 0x80, 0x5f, 0xb4, 0xb9, 0x7e yading@11: }; yading@11: yading@11: /** yading@11: * EVRC GUID as stored in the file yading@11: */ yading@11: static const uint8_t guid_evrc[16] = { yading@11: 0x8d, 0xd4, 0x89, 0xe6, 0x76, 0x90, 0xb5, 0x46, yading@11: 0x91, 0xef, 0x73, 0x6a, 0x51, 0x00, 0xce, 0xb4 yading@11: }; yading@11: yading@11: /** yading@11: * SMV GUID as stored in the file yading@11: */ yading@11: static const uint8_t guid_smv[16] = { yading@11: 0x75, 0x2b, 0x7c, 0x8d, 0x97, 0xa7, 0x49, 0xed, yading@11: 0x98, 0x5e, 0xd5, 0x3c, 0x8c, 0xc7, 0x5f, 0x84 yading@11: }; yading@11: yading@11: /** yading@11: * @param guid contains at least 16 bytes yading@11: * @return 1 if the guid is a qcelp_13k guid, 0 otherwise yading@11: */ yading@11: static int is_qcelp_13k_guid(const uint8_t *guid) { yading@11: return (guid[0] == 0x41 || guid[0] == 0x42) yading@11: && !memcmp(guid+1, guid_qcelp_13k_part, sizeof(guid_qcelp_13k_part)); yading@11: } yading@11: yading@11: static int qcp_probe(AVProbeData *pd) yading@11: { yading@11: if (AV_RL32(pd->buf ) == AV_RL32("RIFF") && yading@11: AV_RL64(pd->buf+8) == AV_RL64("QLCMfmt ")) yading@11: return AVPROBE_SCORE_MAX; yading@11: return 0; yading@11: } yading@11: yading@11: static int qcp_read_header(AVFormatContext *s) yading@11: { yading@11: AVIOContext *pb = s->pb; yading@11: QCPContext *c = s->priv_data; yading@11: AVStream *st = avformat_new_stream(s, NULL); yading@11: uint8_t buf[16]; yading@11: int i, nb_rates; yading@11: yading@11: if (!st) yading@11: return AVERROR(ENOMEM); yading@11: yading@11: avio_rb32(pb); // "RIFF" yading@11: avio_skip(pb, 4 + 8 + 4 + 1 + 1); // filesize + "QLCMfmt " + chunk-size + major-version + minor-version yading@11: yading@11: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; yading@11: st->codec->channels = 1; yading@11: st->codec->channel_layout = AV_CH_LAYOUT_MONO; yading@11: avio_read(pb, buf, 16); yading@11: if (is_qcelp_13k_guid(buf)) { yading@11: st->codec->codec_id = AV_CODEC_ID_QCELP; yading@11: } else if (!memcmp(buf, guid_evrc, 16)) { yading@11: st->codec->codec_id = AV_CODEC_ID_EVRC; yading@11: } else if (!memcmp(buf, guid_smv, 16)) { yading@11: st->codec->codec_id = AV_CODEC_ID_SMV; yading@11: } else { yading@11: av_log(s, AV_LOG_ERROR, "Unknown codec GUID.\n"); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: avio_skip(pb, 2 + 80); // codec-version + codec-name yading@11: st->codec->bit_rate = avio_rl16(pb); yading@11: yading@11: s->packet_size = avio_rl16(pb); yading@11: avio_skip(pb, 2); // block-size yading@11: st->codec->sample_rate = avio_rl16(pb); yading@11: avio_skip(pb, 2); // sample-size yading@11: yading@11: memset(c->rates_per_mode, -1, sizeof(c->rates_per_mode)); yading@11: nb_rates = avio_rl32(pb); yading@11: nb_rates = FFMIN(nb_rates, 8); yading@11: for (i=0; i QCP_MAX_MODE) { yading@11: av_log(s, AV_LOG_WARNING, "Unknown entry %d=>%d in rate-map-table.\n ", mode, size); yading@11: } else yading@11: c->rates_per_mode[mode] = size; yading@11: } yading@11: avio_skip(pb, 16 - 2*nb_rates + 20); // empty entries of rate-map-table + reserved yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: static int qcp_read_packet(AVFormatContext *s, AVPacket *pkt) yading@11: { yading@11: AVIOContext *pb = s->pb; yading@11: QCPContext *c = s->priv_data; yading@11: unsigned int chunk_size, tag; yading@11: yading@11: while(!url_feof(pb)) { yading@11: if (c->data_size) { yading@11: int pkt_size, ret, mode = avio_r8(pb); yading@11: yading@11: if (s->packet_size) { yading@11: pkt_size = s->packet_size - 1; yading@11: } else if (mode > QCP_MAX_MODE || (pkt_size = c->rates_per_mode[mode]) < 0) { yading@11: c->data_size--; yading@11: continue; yading@11: } yading@11: yading@11: if (c->data_size <= pkt_size) { yading@11: av_log(s, AV_LOG_WARNING, "Data chunk is too small.\n"); yading@11: pkt_size = c->data_size - 1; yading@11: } yading@11: yading@11: if ((ret = av_get_packet(pb, pkt, pkt_size)) >= 0) { yading@11: if (pkt_size != ret) yading@11: av_log(s, AV_LOG_ERROR, "Packet size is too small.\n"); yading@11: yading@11: c->data_size -= pkt_size + 1; yading@11: } yading@11: return ret; yading@11: } yading@11: yading@11: if (avio_tell(pb) & 1 && avio_r8(pb)) yading@11: av_log(s, AV_LOG_WARNING, "Padding should be 0.\n"); yading@11: yading@11: tag = avio_rl32(pb); yading@11: chunk_size = avio_rl32(pb); yading@11: switch (tag) { yading@11: case MKTAG('v', 'r', 'a', 't'): yading@11: if (avio_rl32(pb)) // var-rate-flag yading@11: s->packet_size = 0; yading@11: avio_skip(pb, 4); // size-in-packets yading@11: break; yading@11: case MKTAG('d', 'a', 't', 'a'): yading@11: c->data_size = chunk_size; yading@11: break; yading@11: yading@11: default: yading@11: avio_skip(pb, chunk_size); yading@11: } yading@11: } yading@11: return AVERROR_EOF; yading@11: } yading@11: yading@11: AVInputFormat ff_qcp_demuxer = { yading@11: .name = "qcp", yading@11: .long_name = NULL_IF_CONFIG_SMALL("QCP"), yading@11: .priv_data_size = sizeof(QCPContext), yading@11: .read_probe = qcp_probe, yading@11: .read_header = qcp_read_header, yading@11: .read_packet = qcp_read_packet, yading@11: };