chromium/third_party/ffmpeg/libavformat/wavdec.c

/*
 * WAV demuxer
 * Copyright (c) 2001, 2002 Fabrice Bellard
 *
 * Sony Wave64 demuxer
 * RF64 demuxer
 * Copyright (c) 2009 Daniel Verkamp
 *
 * BW64 demuxer
 *
 * 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 <stdint.h>

#include "config_components.h"
#include "libavutil/avassert.h"
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/mathematics.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavcodec/internal.h"
#include "avformat.h"
#include "avio.h"
#include "avio_internal.h"
#include "demux.h"
#include "id3v2.h"
#include "internal.h"
#include "metadata.h"
#include "pcm.h"
#include "riff.h"
#include "w64.h"
#include "spdif.h"

WAVDemuxContext;

#define OFFSET(x)
#define DEC
static const AVOption demux_options[] =;

static void set_max_size(AVStream *st, WAVDemuxContext *wav)
{}

static void set_spdif(AVFormatContext *s, WAVDemuxContext *wav)
{}

#if CONFIG_WAV_DEMUXER

static int64_t next_tag(AVIOContext *pb, uint32_t *tag, int big_endian)
{}

/* RIFF chunks are always at even offsets relative to where they start. */
static int64_t wav_seek_tag(WAVDemuxContext * wav, AVIOContext *s, int64_t offset, int whence)
{}

/* return the size of the found tag */
static int64_t find_tag(WAVDemuxContext * wav, AVIOContext *pb, uint32_t tag1)
{}

static int wav_probe(const AVProbeData *p)
{}

static void handle_stream_probing(AVStream *st)
{}

static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream *st)
{}

static int wav_parse_xma2_tag(AVFormatContext *s, int64_t size, AVStream *st)
{}

static inline int wav_parse_bext_string(AVFormatContext *s, const char *key,
                                        int length)
{}

static int wav_parse_bext_tag(AVFormatContext *s, int64_t size)
{}

static const AVMetadataConv wav_metadata_conv[] =;

/* wav input */
static int wav_read_header(AVFormatContext *s)
{}

/**
 * Find chunk with w64 GUID by skipping over other chunks.
 * @return the size of the found chunk
 */
static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16])
{}

static int wav_read_packet(AVFormatContext *s, AVPacket *pkt)
{}

static int wav_read_seek(AVFormatContext *s,
                         int stream_index, int64_t timestamp, int flags)
{}

static const AVClass wav_demuxer_class =;
const FFInputFormat ff_wav_demuxer =;
#endif /* CONFIG_WAV_DEMUXER */

#if CONFIG_W64_DEMUXER
static int w64_probe(const AVProbeData *p)
{
    if (p->buf_size <= 40)
        return 0;
    if (!memcmp(p->buf,      ff_w64_guid_riff, 16) &&
        !memcmp(p->buf + 24, ff_w64_guid_wave, 16))
        return AVPROBE_SCORE_MAX;
    else
        return 0;
}

static int w64_read_header(AVFormatContext *s)
{
    int64_t size, data_ofs = 0;
    AVIOContext *pb      = s->pb;
    WAVDemuxContext *wav = s->priv_data;
    AVStream *st;
    uint8_t guid[16];
    int ret;

    avio_read(pb, guid, 16);
    if (memcmp(guid, ff_w64_guid_riff, 16))
        return AVERROR_INVALIDDATA;

    /* riff + wave + fmt + sizes */
    if (avio_rl64(pb) < 16 + 8 + 16 + 8 + 16 + 8)
        return AVERROR_INVALIDDATA;

    avio_read(pb, guid, 16);
    if (memcmp(guid, ff_w64_guid_wave, 16)) {
        av_log(s, AV_LOG_ERROR, "could not find wave guid\n");
        return AVERROR_INVALIDDATA;
    }

    wav->w64 = 1;

    st = avformat_new_stream(s, NULL);
    if (!st)
        return AVERROR(ENOMEM);

    while (!avio_feof(pb)) {
        if (avio_read(pb, guid, 16) != 16)
            break;
        size = avio_rl64(pb);
        if (size <= 24 || INT64_MAX - size < avio_tell(pb)) {
            if (data_ofs)
                break;
            return AVERROR_INVALIDDATA;
        }

        if (!memcmp(guid, ff_w64_guid_fmt, 16)) {
            /* subtract chunk header size - normal wav file doesn't count it */
            ret = ff_get_wav_header(s, pb, st->codecpar, size - 24, 0);
            if (ret < 0)
                return ret;
            avio_skip(pb, FFALIGN(size, INT64_C(8)) - size);
            if (st->codecpar->block_align &&
                st->codecpar->ch_layout.nb_channels < FF_SANE_NB_CHANNELS &&
                st->codecpar->bits_per_coded_sample < 128) {
                int block_align = st->codecpar->block_align;

                block_align = FFMAX(block_align,
                                    ((st->codecpar->bits_per_coded_sample + 7) / 8) *
                                    st->codecpar->ch_layout.nb_channels);
                if (block_align > st->codecpar->block_align) {
                    av_log(s, AV_LOG_WARNING, "invalid block_align: %d, broken file.\n",
                           st->codecpar->block_align);
                    st->codecpar->block_align = block_align;
                }
            }
            avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
        } else if (!memcmp(guid, ff_w64_guid_fact, 16)) {
            int64_t samples;

            samples = avio_rl64(pb);
            if (samples > 0)
                st->duration = samples;
            avio_skip(pb, FFALIGN(size, INT64_C(8)) - 32);
        } else if (!memcmp(guid, ff_w64_guid_data, 16)) {
            wav->data_end = avio_tell(pb) + size - 24;

            data_ofs = avio_tell(pb);
            if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
                break;

            avio_skip(pb, size - 24);
        } else if (!memcmp(guid, ff_w64_guid_summarylist, 16)) {
            int64_t start, end, cur;
            uint32_t count, chunk_size, i;
            int64_t filesize  = avio_size(s->pb);

            start = avio_tell(pb);
            end = start + FFALIGN(size, INT64_C(8)) - 24;
            count = avio_rl32(pb);

            for (i = 0; i < count; i++) {
                char chunk_key[5], *value;

                if (avio_feof(pb) || (cur = avio_tell(pb)) < 0 || cur > end - 8 /* = tag + size */)
                    break;

                chunk_key[4] = 0;
                avio_read(pb, chunk_key, 4);
                chunk_size = avio_rl32(pb);
                if (chunk_size == UINT32_MAX || (filesize >= 0 && chunk_size > filesize))
                    return AVERROR_INVALIDDATA;

                value = av_malloc(chunk_size + 1);
                if (!value)
                    return AVERROR(ENOMEM);

                ret = avio_get_str16le(pb, chunk_size, value, chunk_size);
                if (ret < 0) {
                    av_free(value);
                    return ret;
                }
                avio_skip(pb, chunk_size - ret);

                av_dict_set(&s->metadata, chunk_key, value, AV_DICT_DONT_STRDUP_VAL);
            }

            avio_skip(pb, end - avio_tell(pb));
        } else {
            av_log(s, AV_LOG_DEBUG, "unknown guid: "FF_PRI_GUID"\n", FF_ARG_GUID(guid));
            avio_skip(pb, FFALIGN(size, INT64_C(8)) - 24);
        }
    }

    if (!data_ofs)
        return AVERROR_EOF;

    ff_metadata_conv_ctx(s, NULL, wav_metadata_conv);
    ff_metadata_conv_ctx(s, NULL, ff_riff_info_conv);

    handle_stream_probing(st);
    ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;

    avio_seek(pb, data_ofs, SEEK_SET);

    set_spdif(s, wav);
    set_max_size(st, wav);

    return 0;
}

static const AVClass w64_demuxer_class = {
    .class_name = "W64 demuxer",
    .item_name  = av_default_item_name,
    .option     = &demux_options[W64_DEMUXER_OPTIONS_OFFSET],
    .version    = LIBAVUTIL_VERSION_INT,
};

const FFInputFormat ff_w64_demuxer = {
    .p.name         = "w64",
    .p.long_name    = NULL_IF_CONFIG_SMALL("Sony Wave64"),
    .p.flags        = AVFMT_GENERIC_INDEX,
    .p.codec_tag    = ff_wav_codec_tags_list,
    .p.priv_class   = &w64_demuxer_class,
    .priv_data_size = sizeof(WAVDemuxContext),
    .read_probe     = w64_probe,
    .read_header    = w64_read_header,
    .read_packet    = wav_read_packet,
    .read_seek      = wav_read_seek,
};
#endif /* CONFIG_W64_DEMUXER */