Message ID | AM9PR09MB5170DBB90D3CDDC0E271E112C5459@AM9PR09MB5170.eurprd09.prod.outlook.com |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel,1/2] avcodec/adpcmenc Adds encoder for Westwood ADPCM. | expand |
Context | Check | Description |
---|---|---|
andriy/x86_make | success | Make finished |
andriy/x86_make_fate | success | Make fate finished |
andriy/PPC64_make | success | Make finished |
andriy/PPC64_make_fate | success | Make fate finished |
On 23/4/21 6:51 pm, Aidan Richmond wrote: > + /* This flags that the file contains 16 bit samples rather than 8 bit > + since the encoder only encodes 16 bit samples this should be set. */ > + flags |= 2; > + > + avio_wl16(pb, s->codecpar->sample_rate); > + /* We don't know the file size yet, so just skip forward 8 bytes */ > + avio_seek(pb, 8, SEEK_CUR); Might be better to ffio_fill() with zeros here instead. > + avio_w8(pb, flags); > + /* 99 indicates the ADPCM format. Other formats not supported. */ > + avio_w8(pb, 99); > + > + return 0; > +} > +AVOutputFormat ff_wsaud_muxer = { > + .name = "wsaud", > + .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios audio"), > + .extensions = "aud", > + .priv_data_size = sizeof(AUDMuxContext), > + .audio_codec = AV_CODEC_ID_ADPCM_IMA_WS, > + .video_codec = AV_CODEC_ID_NONE, > + .flags = AVFMT_TS_NONSTRICT, Why nonstrict? Does this format explicitly support it? > + .write_header = wsaud_write_header, > + .write_packet = wsaud_write_packet, > + .write_trailer = wsaud_write_trailer, > +}; > Zane
Aidan Richmond: > Format is still used by modders of these old games. > --- > libavformat/Makefile | 1 + > libavformat/allformats.c | 1 + > libavformat/westwood_audenc.c | 120 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 122 insertions(+) > create mode 100644 libavformat/westwood_audenc.c > > diff --git a/libavformat/Makefile b/libavformat/Makefile > index bc1ddfa81c..85b5d8e7eb 100644 > --- a/libavformat/Makefile > +++ b/libavformat/Makefile > @@ -581,6 +581,7 @@ OBJS-$(CONFIG_WEBP_MUXER) += webpenc.o > OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.o > OBJS-$(CONFIG_WEBVTT_MUXER) += webvttenc.o > OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o > +OBJS-$(CONFIG_WSAUD_MUXER) += westwood_audenc.o > OBJS-$(CONFIG_WSD_DEMUXER) += wsddec.o rawdec.o > OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o > OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv_common.o \ > diff --git a/libavformat/allformats.c b/libavformat/allformats.c > index fa093c7ac2..fe70a1e9a2 100644 > --- a/libavformat/allformats.c > +++ b/libavformat/allformats.c > @@ -478,6 +478,7 @@ extern AVOutputFormat ff_webp_muxer; > extern AVInputFormat ff_webvtt_demuxer; > extern AVOutputFormat ff_webvtt_muxer; > extern AVInputFormat ff_wsaud_demuxer; > +extern AVOutputFormat ff_wsaud_muxer; > extern AVInputFormat ff_wsd_demuxer; > extern AVInputFormat ff_wsvqa_demuxer; > extern AVInputFormat ff_wtv_demuxer; > diff --git a/libavformat/westwood_audenc.c b/libavformat/westwood_audenc.c > new file mode 100644 > index 0000000000..49310a47c8 > --- /dev/null > +++ b/libavformat/westwood_audenc.c > @@ -0,0 +1,120 @@ > +/* > + * Copyright (c) 2021 Aidan Richmond > + * > + * 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 > + */ > + > +/** > + * @file > + * Westwood Studios AUD file muxer > + * by Aidan Richmond (aidan.is@hotmail.co.uk) > + * > + * This muxer supports IMA ADPCM packed in westwoods format. > + * > + * @see http://xhp.xwis.net/documents/aud3.txt > + */ > + > +#include "avformat.h" > +#include "internal.h" > + > +#define AUD_CHUNK_SIGNATURE 0x0000DEAF > + > +typedef struct AUDMuxContext { > + int uncomp_size; > + int size; > +} AUDMuxContext; > + > +static int wsaud_write_header(AVFormatContext *ctx) > +{ > + AVStream *s = ctx->streams[0]; We typically use st for AVStream (and s is (for some reason used for AVFormatContext). > + AVIOContext *pb = ctx->pb; > + AUDMuxContext *a = ctx->priv_data; > + unsigned char flags = 0; > + > + if (s->codecpar->codec_id != AV_CODEC_ID_ADPCM_IMA_WS) { > + AVCodec *codec = avcodec_find_decoder(ctx->streams[0]->codecpar->codec_id); Use avcodec_get_name() directly. Furthermore use > + av_log(s, AV_LOG_ERROR, "%s codec not supported for Westwood AUD.\n", > + codec ? codec->name : "NONE"); > + return -1; > + } > + > + if (ctx->nb_streams != 1) { > + av_log(s, AV_LOG_ERROR, "AUD files have exactly one stream\n"); > + return AVERROR(EINVAL); > + } > + > + a->uncomp_size = 0; > + a->size = 0; > + > + /* Flag if we have stereo data. */ > + if (s->codecpar->channels == 2) > + flags |= 1; > + > + /* This flags that the file contains 16 bit samples rather than 8 bit > + since the encoder only encodes 16 bit samples this should be set. */ > + flags |= 2; You presume that libavformat is only used in conjunction with the current libavcodec version. But the packets might come from another encoder or a future version of libavcodec. I presume the information about the bitness is contained in codecpar->bits_per_raw_sample or so. > + > + avio_wl16(pb, s->codecpar->sample_rate); > + /* We don't know the file size yet, so just skip forward 8 bytes */ > + avio_seek(pb, 8, SEEK_CUR); Then just zero this field. > + avio_w8(pb, flags); > + /* 99 indicates the ADPCM format. Other formats not supported. */ > + avio_w8(pb, 99); > + > + return 0; > +} > + > +static int wsaud_write_packet(AVFormatContext *ctx, AVPacket *pkt) > +{ > + AVIOContext *pb = ctx->pb; > + AUDMuxContext *a = ctx->priv_data; > + > + /* Assumes ADPCM since this muxer doesn't support SND1 or PCM format. */ > + avio_wl16(pb, pkt->size); > + avio_wl16(pb, pkt->size * 4); You need to check that this indeed fits into an uint16_t. > + avio_wl32(pb, AUD_CHUNK_SIGNATURE); > + avio_write(pb, pkt->data, pkt->size); > + a->size += pkt->size + 8; > + a->uncomp_size += pkt->size * 4; > + > + return 0; > +} > + > +static int wsaud_write_trailer(AVFormatContext *ctx) > +{ > + AVIOContext *pb = ctx->pb; > + AUDMuxContext *a = ctx->priv_data; > + > + avio_seek(pb, 2, SEEK_SET); Don't just seek, check whether the file is seekable first. Otherwise you will write junk at the end of the output. > + avio_wl32(pb, a->size); > + avio_wl32(pb, a->uncomp_size); > + > + return 0; > +} > + > +AVOutputFormat ff_wsaud_muxer = { > + .name = "wsaud", > + .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios audio"), > + .extensions = "aud", > + .priv_data_size = sizeof(AUDMuxContext), > + .audio_codec = AV_CODEC_ID_ADPCM_IMA_WS, > + .video_codec = AV_CODEC_ID_NONE, > + .flags = AVFMT_TS_NONSTRICT, > + .write_header = wsaud_write_header, > + .write_packet = wsaud_write_packet, > + .write_trailer = wsaud_write_trailer, > +}; >
diff --git a/libavformat/Makefile b/libavformat/Makefile index bc1ddfa81c..85b5d8e7eb 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -581,6 +581,7 @@ OBJS-$(CONFIG_WEBP_MUXER) += webpenc.o OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.o OBJS-$(CONFIG_WEBVTT_MUXER) += webvttenc.o OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o +OBJS-$(CONFIG_WSAUD_MUXER) += westwood_audenc.o OBJS-$(CONFIG_WSD_DEMUXER) += wsddec.o rawdec.o OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv_common.o \ diff --git a/libavformat/allformats.c b/libavformat/allformats.c index fa093c7ac2..fe70a1e9a2 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -478,6 +478,7 @@ extern AVOutputFormat ff_webp_muxer; extern AVInputFormat ff_webvtt_demuxer; extern AVOutputFormat ff_webvtt_muxer; extern AVInputFormat ff_wsaud_demuxer; +extern AVOutputFormat ff_wsaud_muxer; extern AVInputFormat ff_wsd_demuxer; extern AVInputFormat ff_wsvqa_demuxer; extern AVInputFormat ff_wtv_demuxer; diff --git a/libavformat/westwood_audenc.c b/libavformat/westwood_audenc.c new file mode 100644 index 0000000000..49310a47c8 --- /dev/null +++ b/libavformat/westwood_audenc.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2021 Aidan Richmond + * + * 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 + */ + +/** + * @file + * Westwood Studios AUD file muxer + * by Aidan Richmond (aidan.is@hotmail.co.uk) + * + * This muxer supports IMA ADPCM packed in westwoods format. + * + * @see http://xhp.xwis.net/documents/aud3.txt + */ + +#include "avformat.h" +#include "internal.h" + +#define AUD_CHUNK_SIGNATURE 0x0000DEAF + +typedef struct AUDMuxContext { + int uncomp_size; + int size; +} AUDMuxContext; + +static int wsaud_write_header(AVFormatContext *ctx) +{ + AVStream *s = ctx->streams[0]; + AVIOContext *pb = ctx->pb; + AUDMuxContext *a = ctx->priv_data; + unsigned char flags = 0; + + if (s->codecpar->codec_id != AV_CODEC_ID_ADPCM_IMA_WS) { + AVCodec *codec = avcodec_find_decoder(ctx->streams[0]->codecpar->codec_id); + av_log(s, AV_LOG_ERROR, "%s codec not supported for Westwood AUD.\n", + codec ? codec->name : "NONE"); + return -1; + } + + if (ctx->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "AUD files have exactly one stream\n"); + return AVERROR(EINVAL); + } + + a->uncomp_size = 0; + a->size = 0; + + /* Flag if we have stereo data. */ + if (s->codecpar->channels == 2) + flags |= 1; + + /* This flags that the file contains 16 bit samples rather than 8 bit + since the encoder only encodes 16 bit samples this should be set. */ + flags |= 2; + + avio_wl16(pb, s->codecpar->sample_rate); + /* We don't know the file size yet, so just skip forward 8 bytes */ + avio_seek(pb, 8, SEEK_CUR); + avio_w8(pb, flags); + /* 99 indicates the ADPCM format. Other formats not supported. */ + avio_w8(pb, 99); + + return 0; +} + +static int wsaud_write_packet(AVFormatContext *ctx, AVPacket *pkt) +{ + AVIOContext *pb = ctx->pb; + AUDMuxContext *a = ctx->priv_data; + + /* Assumes ADPCM since this muxer doesn't support SND1 or PCM format. */ + avio_wl16(pb, pkt->size); + avio_wl16(pb, pkt->size * 4); + avio_wl32(pb, AUD_CHUNK_SIGNATURE); + avio_write(pb, pkt->data, pkt->size); + a->size += pkt->size + 8; + a->uncomp_size += pkt->size * 4; + + return 0; +} + +static int wsaud_write_trailer(AVFormatContext *ctx) +{ + AVIOContext *pb = ctx->pb; + AUDMuxContext *a = ctx->priv_data; + + avio_seek(pb, 2, SEEK_SET); + avio_wl32(pb, a->size); + avio_wl32(pb, a->uncomp_size); + + return 0; +} + +AVOutputFormat ff_wsaud_muxer = { + .name = "wsaud", + .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios audio"), + .extensions = "aud", + .priv_data_size = sizeof(AUDMuxContext), + .audio_codec = AV_CODEC_ID_ADPCM_IMA_WS, + .video_codec = AV_CODEC_ID_NONE, + .flags = AVFMT_TS_NONSTRICT, + .write_header = wsaud_write_header, + .write_packet = wsaud_write_packet, + .write_trailer = wsaud_write_trailer, +};