00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00036 #include "libavutil/intreadwrite.h"
00037 #include "avformat.h"
00038 #include "internal.h"
00039
00040 #define AUD_HEADER_SIZE 12
00041 #define AUD_CHUNK_PREAMBLE_SIZE 8
00042 #define AUD_CHUNK_SIGNATURE 0x0000DEAF
00043
00044 static int wsaud_probe(AVProbeData *p)
00045 {
00046 int field;
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 if (p->buf_size < AUD_HEADER_SIZE + AUD_CHUNK_PREAMBLE_SIZE)
00059 return 0;
00060
00061
00062 field = AV_RL16(&p->buf[0]);
00063 if ((field < 8000) || (field > 48000))
00064 return 0;
00065
00066
00067
00068 if (p->buf[10] & 0xFC)
00069 return 0;
00070
00071
00072
00073 if (p->buf[11] != 99 && p->buf[11] != 1)
00074 return 0;
00075
00076
00077 if (AV_RL32(&p->buf[16]) != AUD_CHUNK_SIGNATURE)
00078 return 0;
00079
00080
00081 return AVPROBE_SCORE_MAX / 2;
00082 }
00083
00084 static int wsaud_read_header(AVFormatContext *s)
00085 {
00086 AVIOContext *pb = s->pb;
00087 AVStream *st;
00088 unsigned char header[AUD_HEADER_SIZE];
00089 int sample_rate, channels, codec;
00090
00091 if (avio_read(pb, header, AUD_HEADER_SIZE) != AUD_HEADER_SIZE)
00092 return AVERROR(EIO);
00093
00094 sample_rate = AV_RL16(&header[0]);
00095 channels = (header[10] & 0x1) + 1;
00096 codec = header[11];
00097
00098
00099 st = avformat_new_stream(s, NULL);
00100 if (!st)
00101 return AVERROR(ENOMEM);
00102
00103 switch (codec) {
00104 case 1:
00105 if (channels != 1) {
00106 av_log_ask_for_sample(s, "Stereo WS-SND1 is not supported.\n");
00107 return AVERROR_PATCHWELCOME;
00108 }
00109 st->codec->codec_id = AV_CODEC_ID_WESTWOOD_SND1;
00110 break;
00111 case 99:
00112 st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_WS;
00113 st->codec->bits_per_coded_sample = 4;
00114 st->codec->bit_rate = channels * sample_rate * 4;
00115 break;
00116 default:
00117 av_log_ask_for_sample(s, "Unknown codec: %d\n", codec);
00118 return AVERROR_PATCHWELCOME;
00119 }
00120 avpriv_set_pts_info(st, 64, 1, sample_rate);
00121 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00122 st->codec->channels = channels;
00123 st->codec->sample_rate = sample_rate;
00124
00125 return 0;
00126 }
00127
00128 static int wsaud_read_packet(AVFormatContext *s,
00129 AVPacket *pkt)
00130 {
00131 AVIOContext *pb = s->pb;
00132 unsigned char preamble[AUD_CHUNK_PREAMBLE_SIZE];
00133 unsigned int chunk_size;
00134 int ret = 0;
00135 AVStream *st = s->streams[0];
00136
00137 if (avio_read(pb, preamble, AUD_CHUNK_PREAMBLE_SIZE) !=
00138 AUD_CHUNK_PREAMBLE_SIZE)
00139 return AVERROR(EIO);
00140
00141
00142 if (AV_RL32(&preamble[4]) != AUD_CHUNK_SIGNATURE)
00143 return AVERROR_INVALIDDATA;
00144
00145 chunk_size = AV_RL16(&preamble[0]);
00146
00147 if (st->codec->codec_id == AV_CODEC_ID_WESTWOOD_SND1) {
00148
00149
00150
00151
00152 int out_size = AV_RL16(&preamble[2]);
00153 if ((ret = av_new_packet(pkt, chunk_size + 4)))
00154 return ret;
00155 if ((ret = avio_read(pb, &pkt->data[4], chunk_size)) != chunk_size)
00156 return ret < 0 ? ret : AVERROR(EIO);
00157 AV_WL16(&pkt->data[0], out_size);
00158 AV_WL16(&pkt->data[2], chunk_size);
00159
00160 pkt->duration = out_size;
00161 } else {
00162 ret = av_get_packet(pb, pkt, chunk_size);
00163 if (ret != chunk_size)
00164 return AVERROR(EIO);
00165
00166
00167 pkt->duration = (chunk_size * 2) / st->codec->channels;
00168 }
00169 pkt->stream_index = st->index;
00170
00171 return ret;
00172 }
00173
00174 AVInputFormat ff_wsaud_demuxer = {
00175 .name = "wsaud",
00176 .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios audio"),
00177 .read_probe = wsaud_probe,
00178 .read_header = wsaud_read_header,
00179 .read_packet = wsaud_read_packet,
00180 };