* commit 'a3a0af4fb1237bed0af75868073f9a63db8b1864': avutil: make aes and sha api public handle malloc failures in ff_get_wav_header add xWMA demuxer mpegts: force the default timebase libavcodec: Bump micro after adding the dtx AVOptions Merged-by: Michael Niedermayer <michaelni@gmx.at>tags/n0.8
| @@ -93,6 +93,7 @@ version <next>: | |||||
| - fieldorder video filter added | - fieldorder video filter added | ||||
| - AAC encoding via libvo-aacenc | - AAC encoding via libvo-aacenc | ||||
| - AMR-WB encoding via libvo-amrwbenc | - AMR-WB encoding via libvo-amrwbenc | ||||
| - xWMA demuxer | |||||
| version 0.6: | version 0.6: | ||||
| @@ -259,6 +259,8 @@ library: | |||||
| @tab Multimedia format used in Westwood Studios games. | @tab Multimedia format used in Westwood Studios games. | ||||
| @item Westwood Studios VQA @tab @tab X | @item Westwood Studios VQA @tab @tab X | ||||
| @tab Multimedia format used in Westwood Studios games. | @tab Multimedia format used in Westwood Studios games. | ||||
| @item xWMA @tab @tab X | |||||
| @tab Microsoft audio container used by XAudio 2. | |||||
| @item YUV4MPEG pipe @tab X @tab X | @item YUV4MPEG pipe @tab X @tab X | ||||
| @item Psygnosis YOP @tab @tab X | @item Psygnosis YOP @tab @tab X | ||||
| @end multitable | @end multitable | ||||
| @@ -2,20 +2,20 @@ | |||||
| * AAC encoder wrapper | * AAC encoder wrapper | ||||
| * Copyright (c) 2010 Martin Storsjo | * Copyright (c) 2010 Martin Storsjo | ||||
| * | * | ||||
| * This file is part of Libav. | |||||
| * This file is part of FFmpeg. | |||||
| * | * | ||||
| * Libav is free software; you can redistribute it and/or | |||||
| * FFmpeg is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public | * modify it under the terms of the GNU Lesser General Public | ||||
| * License as published by the Free Software Foundation; either | * License as published by the Free Software Foundation; either | ||||
| * version 2.1 of the License, or (at your option) any later version. | * version 2.1 of the License, or (at your option) any later version. | ||||
| * | * | ||||
| * Libav is distributed in the hope that it will be useful, | |||||
| * FFmpeg is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
| * Lesser General Public License for more details. | * Lesser General Public License for more details. | ||||
| * | * | ||||
| * You should have received a copy of the GNU Lesser General Public | * You should have received a copy of the GNU Lesser General Public | ||||
| * License along with Libav; if not, write to the Free Software | |||||
| * License along with FFmpeg; if not, write to the Free Software | |||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| */ | */ | ||||
| @@ -2,20 +2,20 @@ | |||||
| * AMR Audio encoder stub | * AMR Audio encoder stub | ||||
| * Copyright (c) 2003 the ffmpeg project | * Copyright (c) 2003 the ffmpeg project | ||||
| * | * | ||||
| * This file is part of Libav. | |||||
| * This file is part of FFmpeg. | |||||
| * | * | ||||
| * Libav is free software; you can redistribute it and/or | |||||
| * FFmpeg is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public | * modify it under the terms of the GNU Lesser General Public | ||||
| * License as published by the Free Software Foundation; either | * License as published by the Free Software Foundation; either | ||||
| * version 2.1 of the License, or (at your option) any later version. | * version 2.1 of the License, or (at your option) any later version. | ||||
| * | * | ||||
| * Libav is distributed in the hope that it will be useful, | |||||
| * FFmpeg is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
| * Lesser General Public License for more details. | * Lesser General Public License for more details. | ||||
| * | * | ||||
| * You should have received a copy of the GNU Lesser General Public | * You should have received a copy of the GNU Lesser General Public | ||||
| * License along with Libav; if not, write to the Free Software | |||||
| * License along with FFmpeg; if not, write to the Free Software | |||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| */ | */ | ||||
| @@ -22,7 +22,7 @@ | |||||
| #define LIBAVCODEC_VERSION_MAJOR 52 | #define LIBAVCODEC_VERSION_MAJOR 52 | ||||
| #define LIBAVCODEC_VERSION_MINOR 119 | #define LIBAVCODEC_VERSION_MINOR 119 | ||||
| #define LIBAVCODEC_VERSION_MICRO 0 | |||||
| #define LIBAVCODEC_VERSION_MICRO 1 | |||||
| #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | ||||
| LIBAVCODEC_VERSION_MINOR, \ | LIBAVCODEC_VERSION_MINOR, \ | ||||
| @@ -302,6 +302,7 @@ OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood.o | |||||
| OBJS-$(CONFIG_WTV_DEMUXER) += wtv.o asf.o asfdec.o mpegts.o riff.o | OBJS-$(CONFIG_WTV_DEMUXER) += wtv.o asf.o asfdec.o mpegts.o riff.o | ||||
| OBJS-$(CONFIG_WV_DEMUXER) += wv.o apetag.o | OBJS-$(CONFIG_WV_DEMUXER) += wv.o apetag.o | ||||
| OBJS-$(CONFIG_XA_DEMUXER) += xa.o | OBJS-$(CONFIG_XA_DEMUXER) += xa.o | ||||
| OBJS-$(CONFIG_XWMA_DEMUXER) += xwma.o riff.o | |||||
| OBJS-$(CONFIG_YOP_DEMUXER) += yop.o | OBJS-$(CONFIG_YOP_DEMUXER) += yop.o | ||||
| OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o | OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o | ||||
| OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o | OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o | ||||
| @@ -227,6 +227,7 @@ void av_register_all(void) | |||||
| REGISTER_DEMUXER (WTV, wtv); | REGISTER_DEMUXER (WTV, wtv); | ||||
| REGISTER_DEMUXER (WV, wv); | REGISTER_DEMUXER (WV, wv); | ||||
| REGISTER_DEMUXER (XA, xa); | REGISTER_DEMUXER (XA, xa); | ||||
| REGISTER_DEMUXER (XWMA, xwma); | |||||
| REGISTER_DEMUXER (YOP, yop); | REGISTER_DEMUXER (YOP, yop); | ||||
| REGISTER_MUXDEMUX (YUV4MPEGPIPE, yuv4mpegpipe); | REGISTER_MUXDEMUX (YUV4MPEGPIPE, yuv4mpegpipe); | ||||
| @@ -280,7 +280,9 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size) | |||||
| st->codec->codec_type = type; | st->codec->codec_type = type; | ||||
| if (type == AVMEDIA_TYPE_AUDIO) { | if (type == AVMEDIA_TYPE_AUDIO) { | ||||
| ff_get_wav_header(pb, st->codec, type_specific_size); | |||||
| int ret = ff_get_wav_header(pb, st->codec, type_specific_size); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| if (is_dvr_ms_audio) { | if (is_dvr_ms_audio) { | ||||
| // codec_id and codec_tag are unreliable in dvr_ms | // codec_id and codec_tag are unreliable in dvr_ms | ||||
| // files. Set them later by probing stream. | // files. Set them later by probing stream. | ||||
| @@ -345,6 +345,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| int avih_width=0, avih_height=0; | int avih_width=0, avih_height=0; | ||||
| int amv_file_format=0; | int amv_file_format=0; | ||||
| uint64_t list_end = 0; | uint64_t list_end = 0; | ||||
| int ret; | |||||
| avi->stream_index= -1; | avi->stream_index= -1; | ||||
| @@ -623,7 +624,9 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| // avio_skip(pb, size - 5 * 4); | // avio_skip(pb, size - 5 * 4); | ||||
| break; | break; | ||||
| case AVMEDIA_TYPE_AUDIO: | case AVMEDIA_TYPE_AUDIO: | ||||
| ff_get_wav_header(pb, st->codec, size); | |||||
| ret = ff_get_wav_header(pb, st->codec, size); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| ast->dshow_block_align= st->codec->block_align; | ast->dshow_block_align= st->codec->block_align; | ||||
| if(ast->sample_size && st->codec->block_align && ast->sample_size != st->codec->block_align){ | if(ast->sample_size && st->codec->block_align && ast->sample_size != st->codec->block_align){ | ||||
| av_log(s, AV_LOG_WARNING, "sample size (%d) != block align (%d)\n", ast->sample_size, st->codec->block_align); | av_log(s, AV_LOG_WARNING, "sample size (%d) != block align (%d)\n", ast->sample_size, st->codec->block_align); | ||||
| @@ -60,6 +60,7 @@ static int dxa_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| int w, h; | int w, h; | ||||
| int num, den; | int num, den; | ||||
| int flags; | int flags; | ||||
| int ret; | |||||
| tag = avio_rl32(pb); | tag = avio_rl32(pb); | ||||
| if (tag != MKTAG('D', 'E', 'X', 'A')) | if (tag != MKTAG('D', 'E', 'X', 'A')) | ||||
| @@ -102,7 +103,9 @@ static int dxa_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| ast = av_new_stream(s, 0); | ast = av_new_stream(s, 0); | ||||
| if (!ast) | if (!ast) | ||||
| return -1; | return -1; | ||||
| ff_get_wav_header(pb, ast->codec, fsize); | |||||
| ret = ff_get_wav_header(pb, ast->codec, fsize); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| // find 'data' chunk | // find 'data' chunk | ||||
| while(avio_tell(pb) < c->vidpos && !url_feof(pb)){ | while(avio_tell(pb) < c->vidpos && !url_feof(pb)){ | ||||
| tag = avio_rl32(pb); | tag = avio_rl32(pb); | ||||
| @@ -1332,9 +1332,12 @@ static int matroska_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| } else if (!strcmp(track->codec_id, "A_MS/ACM") | } else if (!strcmp(track->codec_id, "A_MS/ACM") | ||||
| && track->codec_priv.size >= 14 | && track->codec_priv.size >= 14 | ||||
| && track->codec_priv.data != NULL) { | && track->codec_priv.data != NULL) { | ||||
| int ret; | |||||
| ffio_init_context(&b, track->codec_priv.data, track->codec_priv.size, | ffio_init_context(&b, track->codec_priv.data, track->codec_priv.size, | ||||
| AVIO_RDONLY, NULL, NULL, NULL, NULL); | AVIO_RDONLY, NULL, NULL, NULL, NULL); | ||||
| ff_get_wav_header(&b, st->codec, track->codec_priv.size); | |||||
| ret = ff_get_wav_header(&b, st->codec, track->codec_priv.size); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| codec_id = st->codec->codec_id; | codec_id = st->codec->codec_id; | ||||
| extradata_offset = FFMIN(track->codec_priv.size, 18); | extradata_offset = FFMIN(track->codec_priv.size, 18); | ||||
| } else if (!strcmp(track->codec_id, "V_QUICKTIME") | } else if (!strcmp(track->codec_id, "V_QUICKTIME") | ||||
| @@ -479,6 +479,7 @@ static int mpegts_write_header(AVFormatContext *s) | |||||
| /* assign pids to each stream */ | /* assign pids to each stream */ | ||||
| for(i = 0;i < s->nb_streams; i++) { | for(i = 0;i < s->nb_streams; i++) { | ||||
| st = s->streams[i]; | st = s->streams[i]; | ||||
| av_set_pts_info(st, 33, 1, 90000); | |||||
| ts_st = av_mallocz(sizeof(MpegTSWriteStream)); | ts_st = av_mallocz(sizeof(MpegTSWriteStream)); | ||||
| if (!ts_st) | if (!ts_st) | ||||
| goto fail; | goto fail; | ||||
| @@ -488,7 +488,7 @@ void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *t | |||||
| * WAVEFORMATEX adds 'WORD cbSize' and basically makes itself | * WAVEFORMATEX adds 'WORD cbSize' and basically makes itself | ||||
| * an openended structure. | * an openended structure. | ||||
| */ | */ | ||||
| void ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) | |||||
| int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) | |||||
| { | { | ||||
| int id; | int id; | ||||
| @@ -531,6 +531,8 @@ void ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) | |||||
| codec->extradata_size = cbSize; | codec->extradata_size = cbSize; | ||||
| if (cbSize > 0) { | if (cbSize > 0) { | ||||
| codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | ||||
| if (!codec->extradata) | |||||
| return AVERROR(ENOMEM); | |||||
| avio_read(pb, codec->extradata, codec->extradata_size); | avio_read(pb, codec->extradata, codec->extradata_size); | ||||
| size -= cbSize; | size -= cbSize; | ||||
| } | } | ||||
| @@ -544,6 +546,8 @@ void ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) | |||||
| codec->channels = 0; | codec->channels = 0; | ||||
| codec->sample_rate = 0; | codec->sample_rate = 0; | ||||
| } | } | ||||
| return 0; | |||||
| } | } | ||||
| @@ -45,7 +45,7 @@ int ff_get_bmp_header(AVIOContext *pb, AVStream *st); | |||||
| void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf); | void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf); | ||||
| int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc); | int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc); | ||||
| enum CodecID ff_wav_codec_get_id(unsigned int tag, int bps); | enum CodecID ff_wav_codec_get_id(unsigned int tag, int bps); | ||||
| void ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size); | |||||
| int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size); | |||||
| extern const AVCodecTag ff_codec_bmp_tags[]; | extern const AVCodecTag ff_codec_bmp_tags[]; | ||||
| extern const AVCodecTag ff_codec_wav_tags[]; | extern const AVCodecTag ff_codec_wav_tags[]; | ||||
| @@ -24,7 +24,7 @@ | |||||
| #include "libavutil/avutil.h" | #include "libavutil/avutil.h" | ||||
| #define LIBAVFORMAT_VERSION_MAJOR 52 | #define LIBAVFORMAT_VERSION_MAJOR 52 | ||||
| #define LIBAVFORMAT_VERSION_MINOR 107 | |||||
| #define LIBAVFORMAT_VERSION_MINOR 108 | |||||
| #define LIBAVFORMAT_VERSION_MICRO 0 | #define LIBAVFORMAT_VERSION_MICRO 0 | ||||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | ||||
| @@ -195,6 +195,7 @@ static int wav_read_header(AVFormatContext *s, | |||||
| AVIOContext *pb = s->pb; | AVIOContext *pb = s->pb; | ||||
| AVStream *st; | AVStream *st; | ||||
| WAVContext *wav = s->priv_data; | WAVContext *wav = s->priv_data; | ||||
| int ret; | |||||
| /* check RIFF header */ | /* check RIFF header */ | ||||
| tag = avio_rl32(pb); | tag = avio_rl32(pb); | ||||
| @@ -227,7 +228,9 @@ static int wav_read_header(AVFormatContext *s, | |||||
| if (!st) | if (!st) | ||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| ff_get_wav_header(pb, st->codec, size); | |||||
| ret = ff_get_wav_header(pb, st->codec, size); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| st->need_parsing = AVSTREAM_PARSE_FULL; | st->need_parsing = AVSTREAM_PARSE_FULL; | ||||
| av_set_pts_info(st, 64, 1, st->codec->sample_rate); | av_set_pts_info(st, 64, 1, st->codec->sample_rate); | ||||
| @@ -383,6 +386,7 @@ static int w64_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| WAVContext *wav = s->priv_data; | WAVContext *wav = s->priv_data; | ||||
| AVStream *st; | AVStream *st; | ||||
| uint8_t guid[16]; | uint8_t guid[16]; | ||||
| int ret; | |||||
| avio_read(pb, guid, 16); | avio_read(pb, guid, 16); | ||||
| if (memcmp(guid, guid_riff, 16)) | if (memcmp(guid, guid_riff, 16)) | ||||
| @@ -408,7 +412,9 @@ static int w64_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| /* subtract chunk header size - normal wav file doesn't count it */ | /* subtract chunk header size - normal wav file doesn't count it */ | ||||
| ff_get_wav_header(pb, st->codec, size - 24); | |||||
| ret = ff_get_wav_header(pb, st->codec, size - 24); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| avio_skip(pb, FFALIGN(size, INT64_C(8)) - size); | avio_skip(pb, FFALIGN(size, INT64_C(8)) - size); | ||||
| st->need_parsing = AVSTREAM_PARSE_FULL; | st->need_parsing = AVSTREAM_PARSE_FULL; | ||||
| @@ -645,7 +645,9 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid, | |||||
| if (!st) | if (!st) | ||||
| return NULL; | return NULL; | ||||
| if (!ff_guidcmp(formattype, format_waveformatex)) { | if (!ff_guidcmp(formattype, format_waveformatex)) { | ||||
| ff_get_wav_header(pb, st->codec, size); | |||||
| int ret = ff_get_wav_header(pb, st->codec, size); | |||||
| if (ret < 0) | |||||
| return NULL; | |||||
| } else { | } else { | ||||
| if (ff_guidcmp(formattype, format_none)) | if (ff_guidcmp(formattype, format_none)) | ||||
| av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype)); | av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype)); | ||||
| @@ -0,0 +1,257 @@ | |||||
| /* | |||||
| * xWMA demuxer | |||||
| * Copyright (c) 2011 Max Horn | |||||
| * | |||||
| * This file is part of FFmpeg. | |||||
| * | |||||
| * FFmpeg is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * FFmpeg is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details. | |||||
| * | |||||
| * You should have received a copy of the GNU Lesser General Public | |||||
| * License along with FFmpeg; if not, write to the Free Software | |||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
| */ | |||||
| #include "avformat.h" | |||||
| #include "riff.h" | |||||
| /* | |||||
| * Demuxer for xWMA, a Microsoft audio container used by XAudio 2. | |||||
| */ | |||||
| typedef struct { | |||||
| int64_t data_end; | |||||
| } XWMAContext; | |||||
| static int xwma_probe(AVProbeData *p) | |||||
| { | |||||
| if (!memcmp(p->buf, "RIFF", 4) && !memcmp(p->buf + 8, "XWMA", 4)) | |||||
| return AVPROBE_SCORE_MAX; | |||||
| return 0; | |||||
| } | |||||
| static int xwma_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| { | |||||
| int64_t size, av_uninit(data_size); | |||||
| int ret; | |||||
| uint32_t dpds_table_size = 0; | |||||
| uint32_t *dpds_table = 0; | |||||
| unsigned int tag; | |||||
| AVIOContext *pb = s->pb; | |||||
| AVStream *st; | |||||
| XWMAContext *xwma = s->priv_data; | |||||
| int i; | |||||
| /* The following code is mostly copied from wav.c, with some | |||||
| * minor alterations. | |||||
| */ | |||||
| /* check RIFF header */ | |||||
| tag = avio_rl32(pb); | |||||
| if (tag != MKTAG('R', 'I', 'F', 'F')) | |||||
| return -1; | |||||
| avio_rl32(pb); /* file size */ | |||||
| tag = avio_rl32(pb); | |||||
| if (tag != MKTAG('X', 'W', 'M', 'A')) | |||||
| return -1; | |||||
| /* parse fmt header */ | |||||
| tag = avio_rl32(pb); | |||||
| if (tag != MKTAG('f', 'm', 't', ' ')) | |||||
| return -1; | |||||
| size = avio_rl32(pb); | |||||
| st = av_new_stream(s, 0); | |||||
| if (!st) | |||||
| return AVERROR(ENOMEM); | |||||
| ret = ff_get_wav_header(pb, st->codec, size); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| st->need_parsing = AVSTREAM_PARSE_NONE; | |||||
| /* All xWMA files I have seen contained WMAv2 data. If there are files | |||||
| * using WMA Pro or some other codec, then we need to figure out the right | |||||
| * extradata for that. Thus, ask the user for feedback, but try to go on | |||||
| * anyway. | |||||
| */ | |||||
| if (st->codec->codec_id != CODEC_ID_WMAV2) { | |||||
| av_log(s, AV_LOG_WARNING, "unexpected codec (tag 0x04%x; id %d)\n", | |||||
| st->codec->codec_tag, st->codec->codec_id); | |||||
| av_log_ask_for_sample(s, NULL); | |||||
| } else { | |||||
| /* In all xWMA files I have seen, there is no extradata. But the WMA | |||||
| * codecs require extradata, so we provide our own fake extradata. | |||||
| * | |||||
| * First, check that there really was no extradata in the header. If | |||||
| * there was, then try to use, after asking the the user to provide a | |||||
| * sample of this unusual file. | |||||
| */ | |||||
| if (st->codec->extradata_size != 0) { | |||||
| /* Surprise, surprise: We *did* get some extradata. No idea | |||||
| * if it will work, but just go on and try it, after asking | |||||
| * the user for a sample. | |||||
| */ | |||||
| av_log(s, AV_LOG_WARNING, "unexpected extradata (%d bytes)\n", | |||||
| st->codec->extradata_size); | |||||
| av_log_ask_for_sample(s, NULL); | |||||
| } else { | |||||
| st->codec->extradata_size = 6; | |||||
| st->codec->extradata = av_mallocz(6 + FF_INPUT_BUFFER_PADDING_SIZE); | |||||
| if (!st->codec->extradata) | |||||
| return AVERROR(ENOMEM); | |||||
| /* setup extradata with our experimentally obtained value */ | |||||
| st->codec->extradata[4] = 31; | |||||
| } | |||||
| } | |||||
| /* set the sample rate */ | |||||
| av_set_pts_info(st, 64, 1, st->codec->sample_rate); | |||||
| /* parse the remaining RIFF chunks */ | |||||
| for (;;) { | |||||
| if (pb->eof_reached) | |||||
| return -1; | |||||
| /* read next chunk tag */ | |||||
| tag = avio_rl32(pb); | |||||
| size = avio_rl32(pb); | |||||
| if (tag == MKTAG('d', 'a', 't', 'a')) { | |||||
| /* We assume that the data chunk comes last. */ | |||||
| break; | |||||
| } else if (tag == MKTAG('d','p','d','s')) { | |||||
| /* Quoting the MSDN xWMA docs on the dpds chunk: "Contains the | |||||
| * decoded packet cumulative data size array, each element is the | |||||
| * number of bytes accumulated after the corresponding xWMA packet | |||||
| * is decoded in order" | |||||
| * | |||||
| * Each packet has size equal to st->codec->block_align, which in | |||||
| * all cases I saw so far was always 2230. Thus, we can use the | |||||
| * dpds data to compute a seeking index. | |||||
| */ | |||||
| /* Error out if there is more than one dpds chunk. */ | |||||
| if (dpds_table) { | |||||
| av_log(s, AV_LOG_ERROR, "two dpds chunks present\n"); | |||||
| return -1; | |||||
| } | |||||
| /* Compute the number of entries in the dpds chunk. */ | |||||
| if (size & 3) { /* Size should be divisible by four */ | |||||
| av_log(s, AV_LOG_WARNING, "dpds chunk size "PRId64" not divisible by 4\n", size); | |||||
| } | |||||
| dpds_table_size = size / 4; | |||||
| if (dpds_table_size == 0 || dpds_table_size >= INT_MAX / 4) { | |||||
| av_log(s, AV_LOG_ERROR, "dpds chunk size "PRId64" invalid\n", size); | |||||
| return -1; | |||||
| } | |||||
| /* Allocate some temporary storage to keep the dpds data around. | |||||
| * for processing later on. | |||||
| */ | |||||
| dpds_table = av_malloc(dpds_table_size * sizeof(uint32_t)); | |||||
| if (!dpds_table) { | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| for (i = 0; i < dpds_table_size; ++i) { | |||||
| dpds_table[i] = avio_rl32(pb); | |||||
| size -= 4; | |||||
| } | |||||
| } | |||||
| avio_skip(pb, size); | |||||
| } | |||||
| /* Determine overall data length */ | |||||
| if (size < 0) | |||||
| return -1; | |||||
| if (!size) { | |||||
| xwma->data_end = INT64_MAX; | |||||
| } else | |||||
| xwma->data_end = avio_tell(pb) + size; | |||||
| if (dpds_table && dpds_table_size) { | |||||
| int64_t cur_pos; | |||||
| const uint32_t bytes_per_sample | |||||
| = (st->codec->channels * st->codec->bits_per_coded_sample) >> 3; | |||||
| /* Estimate the duration from the total number of output bytes. */ | |||||
| const uint64_t total_decoded_bytes = dpds_table[dpds_table_size - 1]; | |||||
| st->duration = total_decoded_bytes / bytes_per_sample; | |||||
| /* Use the dpds data to build a seek table. We can only do this after | |||||
| * we know the offset to the data chunk, as we need that to determine | |||||
| * the actual offset to each input block. | |||||
| * Note: If we allowed ourselves to assume that the data chunk always | |||||
| * follows immediately after the dpds block, we could of course guess | |||||
| * the data block's start offset already while reading the dpds chunk. | |||||
| * I decided against that, just in case other chunks ever are | |||||
| * discovered. | |||||
| */ | |||||
| cur_pos = avio_tell(pb); | |||||
| for (i = 0; i < dpds_table_size; ++i) { | |||||
| /* From the number of output bytes that would accumulate in the | |||||
| * output buffer after decoding the first (i+1) packets, we compute | |||||
| * an offset / timestamp pair. | |||||
| */ | |||||
| av_add_index_entry(st, | |||||
| cur_pos + (i+1) * st->codec->block_align, /* pos */ | |||||
| dpds_table[i] / bytes_per_sample, /* timestamp */ | |||||
| st->codec->block_align, /* size */ | |||||
| 0, /* duration */ | |||||
| AVINDEX_KEYFRAME); | |||||
| } | |||||
| } else if (st->codec->bit_rate) { | |||||
| /* No dpds chunk was present (or only an empty one), so estimate | |||||
| * the total duration using the average bits per sample and the | |||||
| * total data length. | |||||
| */ | |||||
| st->duration = (size<<3) * st->codec->sample_rate / st->codec->bit_rate; | |||||
| } | |||||
| av_free(dpds_table); | |||||
| return 0; | |||||
| } | |||||
| static int xwma_read_packet(AVFormatContext *s, AVPacket *pkt) | |||||
| { | |||||
| int ret, size; | |||||
| int64_t left; | |||||
| AVStream *st; | |||||
| XWMAContext *xwma = s->priv_data; | |||||
| st = s->streams[0]; | |||||
| left = xwma->data_end - avio_tell(s->pb); | |||||
| if (left <= 0) { | |||||
| return AVERROR_EOF; | |||||
| } | |||||
| /* read a single block; the default block size is 2230. */ | |||||
| size = (st->codec->block_align > 1) ? st->codec->block_align : 2230; | |||||
| size = FFMIN(size, left); | |||||
| ret = av_get_packet(s->pb, pkt, size); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| pkt->stream_index = 0; | |||||
| return ret; | |||||
| } | |||||
| AVInputFormat ff_xwma_demuxer = { | |||||
| "xwma", | |||||
| NULL_IF_CONFIG_SMALL("Microsoft xWMA"), | |||||
| sizeof(XWMAContext), | |||||
| xwma_probe, | |||||
| xwma_read_header, | |||||
| xwma_read_packet, | |||||
| }; | |||||