00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <inttypes.h>
00023
00024 #include "avformat.h"
00025 #include "riff.h"
00026
00027
00028
00029
00030
00031 typedef struct {
00032 int64_t data_end;
00033 } XWMAContext;
00034
00035 static int xwma_probe(AVProbeData *p)
00036 {
00037 if (!memcmp(p->buf, "RIFF", 4) && !memcmp(p->buf + 8, "XWMA", 4))
00038 return AVPROBE_SCORE_MAX;
00039 return 0;
00040 }
00041
00042 static int xwma_read_header(AVFormatContext *s, AVFormatParameters *ap)
00043 {
00044 int64_t size, av_uninit(data_size);
00045 int ret;
00046 uint32_t dpds_table_size = 0;
00047 uint32_t *dpds_table = 0;
00048 unsigned int tag;
00049 AVIOContext *pb = s->pb;
00050 AVStream *st;
00051 XWMAContext *xwma = s->priv_data;
00052 int i;
00053
00054
00055
00056
00057
00058
00059 tag = avio_rl32(pb);
00060 if (tag != MKTAG('R', 'I', 'F', 'F'))
00061 return -1;
00062 avio_rl32(pb);
00063 tag = avio_rl32(pb);
00064 if (tag != MKTAG('X', 'W', 'M', 'A'))
00065 return -1;
00066
00067
00068 tag = avio_rl32(pb);
00069 if (tag != MKTAG('f', 'm', 't', ' '))
00070 return -1;
00071 size = avio_rl32(pb);
00072 st = av_new_stream(s, 0);
00073 if (!st)
00074 return AVERROR(ENOMEM);
00075
00076 ret = ff_get_wav_header(pb, st->codec, size);
00077 if (ret < 0)
00078 return ret;
00079 st->need_parsing = AVSTREAM_PARSE_NONE;
00080
00081
00082
00083
00084
00085
00086 if (st->codec->codec_id != CODEC_ID_WMAV2) {
00087 av_log(s, AV_LOG_WARNING, "unexpected codec (tag 0x04%x; id %d)\n",
00088 st->codec->codec_tag, st->codec->codec_id);
00089 av_log_ask_for_sample(s, NULL);
00090 } else {
00091
00092
00093
00094
00095
00096
00097
00098 if (st->codec->extradata_size != 0) {
00099
00100
00101
00102
00103 av_log(s, AV_LOG_WARNING, "unexpected extradata (%d bytes)\n",
00104 st->codec->extradata_size);
00105 av_log_ask_for_sample(s, NULL);
00106 } else {
00107 st->codec->extradata_size = 6;
00108 st->codec->extradata = av_mallocz(6 + FF_INPUT_BUFFER_PADDING_SIZE);
00109 if (!st->codec->extradata)
00110 return AVERROR(ENOMEM);
00111
00112
00113 st->codec->extradata[4] = 31;
00114 }
00115 }
00116
00117
00118 av_set_pts_info(st, 64, 1, st->codec->sample_rate);
00119
00120
00121 for (;;) {
00122 if (pb->eof_reached)
00123 return -1;
00124
00125 tag = avio_rl32(pb);
00126 size = avio_rl32(pb);
00127 if (tag == MKTAG('d', 'a', 't', 'a')) {
00128
00129 break;
00130 } else if (tag == MKTAG('d','p','d','s')) {
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 if (dpds_table) {
00143 av_log(s, AV_LOG_ERROR, "two dpds chunks present\n");
00144 return -1;
00145 }
00146
00147
00148 if (size & 3) {
00149 av_log(s, AV_LOG_WARNING,
00150 "dpds chunk size %"PRId64" not divisible by 4\n", size);
00151 }
00152 dpds_table_size = size / 4;
00153 if (dpds_table_size == 0 || dpds_table_size >= INT_MAX / 4) {
00154 av_log(s, AV_LOG_ERROR,
00155 "dpds chunk size %"PRId64" invalid\n", size);
00156 return -1;
00157 }
00158
00159
00160
00161
00162 dpds_table = av_malloc(dpds_table_size * sizeof(uint32_t));
00163 if (!dpds_table) {
00164 return AVERROR(ENOMEM);
00165 }
00166
00167 for (i = 0; i < dpds_table_size; ++i) {
00168 dpds_table[i] = avio_rl32(pb);
00169 size -= 4;
00170 }
00171 }
00172 avio_skip(pb, size);
00173 }
00174
00175
00176 if (size < 0)
00177 return -1;
00178 if (!size) {
00179 xwma->data_end = INT64_MAX;
00180 } else
00181 xwma->data_end = avio_tell(pb) + size;
00182
00183
00184 if (dpds_table && dpds_table_size) {
00185 int64_t cur_pos;
00186 const uint32_t bytes_per_sample
00187 = (st->codec->channels * st->codec->bits_per_coded_sample) >> 3;
00188
00189
00190 const uint64_t total_decoded_bytes = dpds_table[dpds_table_size - 1];
00191 st->duration = total_decoded_bytes / bytes_per_sample;
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202 cur_pos = avio_tell(pb);
00203 for (i = 0; i < dpds_table_size; ++i) {
00204
00205
00206
00207
00208 av_add_index_entry(st,
00209 cur_pos + (i+1) * st->codec->block_align,
00210 dpds_table[i] / bytes_per_sample,
00211 st->codec->block_align,
00212 0,
00213 AVINDEX_KEYFRAME);
00214 }
00215 } else if (st->codec->bit_rate) {
00216
00217
00218
00219
00220 st->duration = (size<<3) * st->codec->sample_rate / st->codec->bit_rate;
00221 }
00222
00223 av_free(dpds_table);
00224
00225 return 0;
00226 }
00227
00228 static int xwma_read_packet(AVFormatContext *s, AVPacket *pkt)
00229 {
00230 int ret, size;
00231 int64_t left;
00232 AVStream *st;
00233 XWMAContext *xwma = s->priv_data;
00234
00235 st = s->streams[0];
00236
00237 left = xwma->data_end - avio_tell(s->pb);
00238 if (left <= 0) {
00239 return AVERROR_EOF;
00240 }
00241
00242
00243 size = (st->codec->block_align > 1) ? st->codec->block_align : 2230;
00244 size = FFMIN(size, left);
00245
00246 ret = av_get_packet(s->pb, pkt, size);
00247 if (ret < 0)
00248 return ret;
00249
00250 pkt->stream_index = 0;
00251 return ret;
00252 }
00253
00254 AVInputFormat ff_xwma_demuxer = {
00255 "xwma",
00256 NULL_IF_CONFIG_SMALL("Microsoft xWMA"),
00257 sizeof(XWMAContext),
00258 xwma_probe,
00259 xwma_read_header,
00260 xwma_read_packet,
00261 };