yading@11: /* yading@11: * Electronic Arts .cdata file Demuxer yading@11: * Copyright (c) 2007 Peter Ross 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: * Electronic Arts cdata Format Demuxer yading@11: * by Peter Ross (pross@xvid.org) yading@11: * yading@11: * Technical details here: yading@11: * http://wiki.multimedia.cx/index.php?title=EA_Command_And_Conquer_3_Audio_Codec yading@11: */ yading@11: yading@11: #include "avformat.h" yading@11: #include "internal.h" yading@11: yading@11: typedef struct { yading@11: unsigned int channels; yading@11: unsigned int audio_pts; yading@11: } CdataDemuxContext; yading@11: yading@11: static int cdata_probe(AVProbeData *p) yading@11: { yading@11: const uint8_t *b = p->buf; yading@11: yading@11: if (b[0] == 0x04 && (b[1] == 0x00 || b[1] == 0x04 || b[1] == 0x0C || b[1] == 0x14)) yading@11: return AVPROBE_SCORE_MAX/8; yading@11: return 0; yading@11: } yading@11: yading@11: static int cdata_read_header(AVFormatContext *s) yading@11: { yading@11: CdataDemuxContext *cdata = s->priv_data; yading@11: AVIOContext *pb = s->pb; yading@11: unsigned int sample_rate, header; yading@11: AVStream *st; yading@11: int64_t channel_layout = 0; yading@11: yading@11: header = avio_rb16(pb); yading@11: switch (header) { yading@11: case 0x0400: cdata->channels = 1; break; yading@11: case 0x0404: cdata->channels = 2; break; yading@11: case 0x040C: cdata->channels = 4; channel_layout = AV_CH_LAYOUT_QUAD; break; yading@11: case 0x0414: cdata->channels = 6; channel_layout = AV_CH_LAYOUT_5POINT1_BACK; break; yading@11: default: yading@11: av_log(s, AV_LOG_INFO, "unknown header 0x%04x\n", header); yading@11: return -1; yading@11: }; yading@11: yading@11: sample_rate = avio_rb16(pb); yading@11: avio_skip(pb, (avio_r8(pb) & 0x20) ? 15 : 11); yading@11: yading@11: st = avformat_new_stream(s, NULL); yading@11: if (!st) yading@11: return AVERROR(ENOMEM); yading@11: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; yading@11: st->codec->codec_tag = 0; /* no fourcc */ yading@11: st->codec->codec_id = AV_CODEC_ID_ADPCM_EA_XAS; yading@11: st->codec->channels = cdata->channels; yading@11: st->codec->channel_layout = channel_layout; yading@11: st->codec->sample_rate = sample_rate; yading@11: avpriv_set_pts_info(st, 64, 1, sample_rate); yading@11: yading@11: cdata->audio_pts = 0; yading@11: return 0; yading@11: } yading@11: yading@11: static int cdata_read_packet(AVFormatContext *s, AVPacket *pkt) yading@11: { yading@11: CdataDemuxContext *cdata = s->priv_data; yading@11: int packet_size = 76*cdata->channels; yading@11: yading@11: int ret = av_get_packet(s->pb, pkt, packet_size); yading@11: if (ret < 0) yading@11: return ret; yading@11: pkt->pts = cdata->audio_pts++; yading@11: return 0; yading@11: } yading@11: yading@11: AVInputFormat ff_ea_cdata_demuxer = { yading@11: .name = "ea_cdata", yading@11: .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts cdata"), yading@11: .priv_data_size = sizeof(CdataDemuxContext), yading@11: .read_probe = cdata_probe, yading@11: .read_header = cdata_read_header, yading@11: .read_packet = cdata_read_packet, yading@11: .extensions = "cdata", yading@11: };