X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fwvenc.c;h=b0d74caaec94a207a99ee01c1f4cf4a711c89a74;hb=e4bf3a97de9c39bbf0a37074e8cba756f3c1a87b;hp=c33d4309acfc19d547bcfcd14c832972040c2b0d;hpb=d61681f9e99e7caf6b39e0e596d198d3b96f3792;p=ffmpeg diff --git a/libavformat/wvenc.c b/libavformat/wvenc.c index c33d4309acf..b0d74caaec9 100644 --- a/libavformat/wvenc.c +++ b/libavformat/wvenc.c @@ -1,5 +1,6 @@ /* * WavPack muxer + * Copyright (c) 2013 Konstantin Shishkov * Copyright (c) 2012 Paul B Mahol * * This file is part of FFmpeg. @@ -19,125 +20,72 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/intreadwrite.h" -#include "avformat.h" -#include "internal.h" -#include "avio_internal.h" -#include "apetag.h" +#include "libavutil/attributes.h" -#define WV_EXTRA_SIZE 12 -#define WV_END_BLOCK 0x1000 +#include "apetag.h" +#include "avformat.h" +#include "wv.h" -typedef struct{ - uint32_t duration; -} WVMuxContext; +typedef struct WvMuxContext { + int64_t samples; +} WvMuxContext; -static int write_header(AVFormatContext *s) +static av_cold int wv_write_header(AVFormatContext *ctx) { - AVCodecContext *codec = s->streams[0]->codec; - - if (s->nb_streams > 1) { - av_log(s, AV_LOG_ERROR, "only one stream is supported\n"); - return AVERROR(EINVAL); - } - if (codec->codec_id != AV_CODEC_ID_WAVPACK) { - av_log(s, AV_LOG_ERROR, "unsupported codec\n"); + if (ctx->nb_streams > 1 || + ctx->streams[0]->codec->codec_id != AV_CODEC_ID_WAVPACK) { + av_log(ctx, AV_LOG_ERROR, "This muxer only supports a single WavPack stream.\n"); return AVERROR(EINVAL); } - if (codec->extradata_size > 0) { - avpriv_report_missing_feature(s, "remuxing from matroska container"); - return AVERROR_PATCHWELCOME; - } - avpriv_set_pts_info(s->streams[0], 64, 1, codec->sample_rate); return 0; } -static int write_packet(AVFormatContext *s, AVPacket *pkt) +static int wv_write_packet(AVFormatContext *ctx, AVPacket *pkt) { - WVMuxContext *wc = s->priv_data; - AVCodecContext *codec = s->streams[0]->codec; - AVIOContext *pb = s->pb; - uint64_t size; - uint32_t flags; - uint32_t left = pkt->size; - uint8_t *ptr = pkt->data; - int off = codec->channels > 2 ? 4 : 0; + WvMuxContext *s = ctx->priv_data; + WvHeader header; + int ret; - /* FIXME: Simplify decoder/demuxer so bellow code can support midstream - * change of stream parameters */ - wc->duration += pkt->duration; - ffio_wfourcc(pb, "wvpk"); - if (off) { - size = AV_RL32(pkt->data); - if (size <= 12) - return AVERROR_INVALIDDATA; - size -= 12; - } else { - size = pkt->size; + if (pkt->size < WV_HEADER_SIZE || + (ret = ff_wv_parse_header(&header, pkt->data)) < 0) { + av_log(ctx, AV_LOG_ERROR, "Invalid WavPack packet.\n"); + return AVERROR(EINVAL); } + s->samples += header.samples; - if (size + off > left) - return AVERROR_INVALIDDATA; - - avio_wl32(pb, size + 12); - avio_wl16(pb, 0x410); - avio_w8(pb, 0); - avio_w8(pb, 0); - avio_wl32(pb, -1); - avio_wl32(pb, pkt->pts); - ptr += off; left -= off; - flags = AV_RL32(ptr + 4); - avio_write(pb, ptr, size); - ptr += size; left -= size; - - while (!(flags & WV_END_BLOCK) && - (left >= 4 + WV_EXTRA_SIZE)) { - ffio_wfourcc(pb, "wvpk"); - size = AV_RL32(ptr); - ptr += 4; left -= 4; - if (size < 24 || size - 24 > left) - return AVERROR_INVALIDDATA; - avio_wl32(pb, size); - avio_wl16(pb, 0x410); - avio_w8(pb, 0); - avio_w8(pb, 0); - avio_wl32(pb, -1); - avio_wl32(pb, pkt->pts); - flags = AV_RL32(ptr + 4); - avio_write(pb, ptr, WV_EXTRA_SIZE); - ptr += WV_EXTRA_SIZE; left -= WV_EXTRA_SIZE; - avio_write(pb, ptr, size - 24); - ptr += size - 24; left -= size - 24; - } + avio_write(ctx->pb, pkt->data, pkt->size); return 0; } -static int write_trailer(AVFormatContext *s) +static av_cold int wv_write_trailer(AVFormatContext *ctx) { - WVMuxContext *wc = s->priv_data; - AVIOContext *pb = s->pb; - - ff_ape_write(s); - - if (pb->seekable) { - avio_seek(pb, 12, SEEK_SET); - avio_wl32(pb, wc->duration); - avio_flush(pb); + WvMuxContext *s = ctx->priv_data; + + /* update total number of samples in the first block */ + if (ctx->pb->seekable && s->samples && + s->samples < UINT32_MAX) { + int64_t pos = avio_tell(ctx->pb); + avio_seek(ctx->pb, 12, SEEK_SET); + avio_wl32(ctx->pb, s->samples); + avio_seek(ctx->pb, pos, SEEK_SET); } + ff_ape_write_tag(ctx); return 0; } AVOutputFormat ff_wv_muxer = { .name = "wv", - .long_name = NULL_IF_CONFIG_SMALL("WavPack"), - .priv_data_size = sizeof(WVMuxContext), + .long_name = NULL_IF_CONFIG_SMALL("raw WavPack"), + .mime_type = "audio/x-wavpack", .extensions = "wv", + .priv_data_size = sizeof(WvMuxContext), .audio_codec = AV_CODEC_ID_WAVPACK, .video_codec = AV_CODEC_ID_NONE, - .write_header = write_header, - .write_packet = write_packet, - .write_trailer = write_trailer, + .write_header = wv_write_header, + .write_packet = wv_write_packet, + .write_trailer = wv_write_trailer, + .flags = AVFMT_NOTIMESTAMPS, };