From 376d4b3c0d9d779baef3e2a72ac1ffe77e8508b8 Mon Sep 17 00:00:00 2001 From: James Almer Date: Thu, 4 Aug 2016 16:21:25 -0300 Subject: [PATCH] avformat: add a TTA Muxer Reviewed-by: Michael Niedermayer Signed-off-by: James Almer --- Changelog | 1 + doc/general.texi | 2 +- libavformat/Makefile | 1 + libavformat/allformats.c | 2 +- libavformat/ttaenc.c | 149 +++++++++++++++++++++++++++++++++++++++ libavformat/version.h | 2 +- tests/fate/acodec.mak | 4 +- tests/fate/avformat.mak | 2 + tests/lavf-regression.sh | 8 +++ tests/ref/acodec/tta | 4 +- tests/ref/lavf/mka | 3 + tests/ref/lavf/tta | 3 + 12 files changed, 174 insertions(+), 7 deletions(-) create mode 100644 libavformat/ttaenc.c create mode 100644 tests/ref/lavf/mka create mode 100644 tests/ref/lavf/tta diff --git a/Changelog b/Changelog index 0f9b4cf6b0..a0bf4d6271 100644 --- a/Changelog +++ b/Changelog @@ -12,6 +12,7 @@ version : - 16-bit support in selectivecolor filter - OpenH264 decoder wrapper - MediaCodec hwaccel +- True Audio (TTA) muxer version 3.1: diff --git a/doc/general.texi b/doc/general.texi index 6b5975c6d4..74fc539e17 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -509,7 +509,7 @@ library: @tab Used on the Nintendo GameCube. @item Tiertex Limited SEQ @tab @tab X @tab Tiertex .seq files used in the DOS CD-ROM version of the game Flashback. -@item True Audio @tab @tab X +@item True Audio @tab X @tab X @item VAG @tab @tab X @tab Audio format used in many Sony PS2 games. @item VC-1 test bitstream @tab X @tab X diff --git a/libavformat/Makefile b/libavformat/Makefile index e2cb474396..fda1e17c83 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -471,6 +471,7 @@ OBJS-$(CONFIG_TMV_DEMUXER) += tmv.o OBJS-$(CONFIG_TRUEHD_DEMUXER) += rawdec.o mlpdec.o OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o +OBJS-$(CONFIG_TTA_MUXER) += ttaenc.o apetag.o img2.o OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o OBJS-$(CONFIG_TXD_DEMUXER) += txd.o OBJS-$(CONFIG_UNCODEDFRAMECRC_MUXER) += uncodedframecrcenc.o framehash.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 10c9bcce7f..a69195e6fe 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -311,7 +311,7 @@ void av_register_all(void) REGISTER_MUXER (MKVTIMESTAMP_V2, mkvtimestamp_v2); REGISTER_DEMUXER (TMV, tmv); REGISTER_MUXDEMUX(TRUEHD, truehd); - REGISTER_DEMUXER (TTA, tta); + REGISTER_MUXDEMUX(TTA, tta); REGISTER_DEMUXER (TXD, txd); REGISTER_DEMUXER (TTY, tty); REGISTER_MUXER (UNCODEDFRAMECRC, uncodedframecrc); diff --git a/libavformat/ttaenc.c b/libavformat/ttaenc.c new file mode 100644 index 0000000000..fdce1e3dc1 --- /dev/null +++ b/libavformat/ttaenc.c @@ -0,0 +1,149 @@ +/* + * True Audio (TTA) muxer + * Copyright (c) 2016 James Almer + * + * 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 "libavutil/crc.h" +#include "libavutil/intreadwrite.h" + +#include "apetag.h" +#include "avformat.h" +#include "avio_internal.h" +#include "internal.h" + +typedef struct TTAMuxContext { + AVIOContext *seek_table; + AVIOContext *data; + uint32_t nb_samples; + int frame_size; + int last_frame; +} TTAMuxContext; + +static int tta_write_header(AVFormatContext *s) +{ + TTAMuxContext *tta = s->priv_data; + AVCodecParameters *par = s->streams[0]->codecpar; + int ret; + + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "Only one stream is supported\n"); + return AVERROR(EINVAL); + } + if (par->codec_id != AV_CODEC_ID_TTA) { + av_log(s, AV_LOG_ERROR, "Unsupported codec\n"); + return AVERROR(EINVAL); + } + if (par->extradata && par->extradata_size < 22) { + av_log(s, AV_LOG_ERROR, "Invalid TTA extradata\n"); + return AVERROR_INVALIDDATA; + } + + if ((ret = avio_open_dyn_buf(&tta->seek_table)) < 0) + return ret; + if ((ret = avio_open_dyn_buf(&tta->data)) < 0) { + ffio_free_dyn_buf(&tta->seek_table); + return ret; + } + + /* Ignore most extradata information if present. It can be innacurate + if for example remuxing from Matroska */ + ffio_init_checksum(s->pb, ff_crcEDB88320_update, UINT32_MAX); + ffio_init_checksum(tta->seek_table, ff_crcEDB88320_update, UINT32_MAX); + avio_write(s->pb, "TTA1", 4); + avio_wl16(s->pb, par->extradata ? AV_RL16(par->extradata + 4) : 1); + avio_wl16(s->pb, par->channels); + avio_wl16(s->pb, par->bits_per_raw_sample); + avio_wl32(s->pb, par->sample_rate); + /* Prevent overflow */ + if (par->sample_rate > 0x7FFFFFu) { + av_log(s, AV_LOG_ERROR, "Sample rate too large\n"); + return AVERROR(EINVAL); + } + tta->frame_size = par->sample_rate * 256 / 245; + avpriv_set_pts_info(s->streams[0], 64, 1, par->sample_rate); + + return 0; +} + +static int tta_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + TTAMuxContext *tta = s->priv_data; + + avio_write(tta->data, pkt->data, pkt->size); + avio_wl32(tta->seek_table, pkt->size); + tta->nb_samples += pkt->duration; + + if (tta->frame_size != pkt->duration) { + if (tta->last_frame) { + /* Two frames with a different duration than the default frame + size means the TTA stream comes from a faulty container, and + there's no way the last frame duration will be correct. */ + av_log(s, AV_LOG_ERROR, "Invalid frame durations\n"); + + return AVERROR_INVALIDDATA; + } + /* First frame with a different duration than the default frame size. + Assume it's the last frame in the stream and continue. */ + tta->last_frame++; + } + + return 0; +} + +static int tta_write_trailer(AVFormatContext *s) +{ + TTAMuxContext *tta = s->priv_data; + uint8_t *ptr; + unsigned int crc; + int size; + + avio_wl32(s->pb, tta->nb_samples); + crc = ffio_get_checksum(s->pb) ^ UINT32_MAX; + avio_wl32(s->pb, crc); + + /* Write Seek table */ + crc = ffio_get_checksum(tta->seek_table) ^ UINT32_MAX; + avio_wl32(tta->seek_table, crc); + size = avio_close_dyn_buf(tta->seek_table, &ptr); + avio_write(s->pb, ptr, size); + av_free(ptr); + + /* Write audio data */ + size = avio_close_dyn_buf(tta->data, &ptr); + avio_write(s->pb, ptr, size); + av_free(ptr); + + ff_ape_write_tag(s); + avio_flush(s->pb); + + return 0; +} + +AVOutputFormat ff_tta_muxer = { + .name = "tta", + .long_name = NULL_IF_CONFIG_SMALL("TTA (True Audio)"), + .mime_type = "audio/x-tta", + .extensions = "tta", + .priv_data_size = sizeof(TTAMuxContext), + .audio_codec = AV_CODEC_ID_TTA, + .video_codec = AV_CODEC_ID_NONE, + .write_header = tta_write_header, + .write_packet = tta_write_packet, + .write_trailer = tta_write_trailer, +}; diff --git a/libavformat/version.h b/libavformat/version.h index 56308088b0..8899bfde0c 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,7 +32,7 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you belive might be affected here #define LIBAVFORMAT_VERSION_MAJOR 57 -#define LIBAVFORMAT_VERSION_MINOR 44 +#define LIBAVFORMAT_VERSION_MINOR 45 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ diff --git a/tests/fate/acodec.mak b/tests/fate/acodec.mak index e0f23208e2..c7d4d269cb 100644 --- a/tests/fate/acodec.mak +++ b/tests/fate/acodec.mak @@ -154,8 +154,8 @@ FATE_ACODEC-$(call ENCDEC, WAVPACK, WV) += fate-acodec-wavpack fate-acodec-wavpack: FMT = wv fate-acodec-wavpack: CODEC = wavpack -compression_level 1 -FATE_ACODEC-$(call ENCDEC, TTA, MATROSKA) += fate-acodec-tta -fate-acodec-tta: FMT = matroska +FATE_ACODEC-$(call ENCDEC, TTA, TTA) += fate-acodec-tta +fate-acodec-tta: FMT = tta FATE_ACODEC += $(FATE_ACODEC-yes) diff --git a/tests/fate/avformat.mak b/tests/fate/avformat.mak index c7f3124bb9..3760e41457 100644 --- a/tests/fate/avformat.mak +++ b/tests/fate/avformat.mak @@ -15,6 +15,7 @@ FATE_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif FATE_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf FATE_LAVF-$(call ENCDEC, PCM_S16LE, IRCAM) += ircam FATE_LAVF-$(call ENCDEC, MJPEG, IMAGE2) += jpg +FATE_LAVF-$(call ENCMUX, TTA, MATROSKA_AUDIO) += mka FATE_LAVF-$(call ENCDEC2, MPEG4, MP2, MATROSKA) += mkv FATE_LAVF-$(call ENCDEC, ADPCM_YAMAHA, MMF) += mmf FATE_LAVF-$(call ENCDEC2, MPEG4, PCM_ALAW, MOV) += mov ismv @@ -44,6 +45,7 @@ FATE_LAVF-$(call ENCDEC, FLV, SWF) += swf FATE_LAVF-$(call ENCDEC, TARGA, IMAGE2) += tga FATE_LAVF-$(call ENCDEC, TIFF, IMAGE2) += tiff FATE_LAVF-$(call ENCDEC2, MPEG2VIDEO, MP2, MPEGTS) += ts +FATE_LAVF-$(call ENCDEC, TTA, TTA) += tta FATE_LAVF-$(call ENCDEC, PCM_U8, VOC) += voc FATE_LAVF-$(call ENCDEC, PCM_S16LE, VOC) += voc_s16 FATE_LAVF-$(call ENCDEC, PCM_S16LE, WAV) += wav diff --git a/tests/lavf-regression.sh b/tests/lavf-regression.sh index 0e20513563..8d961781d9 100755 --- a/tests/lavf-regression.sh +++ b/tests/lavf-regression.sh @@ -145,6 +145,10 @@ if [ -n "$do_nut" ] ; then do_lavf nut "" "-acodec mp2 -ab 64k -ar 44100 -threads 1" fi +if [ -n "$do_mka" ] ; then +do_audio_only mka "" "-c:a tta" +fi + if [ -n "$do_mkv" ] ; then do_lavf mkv "" "-acodec mp2 -ab 64k -vcodec mpeg4 \ -attach ${raw_src%/*}/00.pgm -metadata:s:t mimetype=image/x-portable-greymap -threads 1" @@ -350,6 +354,10 @@ if [ -n "$do_sox" ] ; then do_audio_only sox fi +if [ -n "$do_tta" ] ; then +do_audio_only tta +fi + if [ -n "$do_caf" ] ; then do_audio_only caf fi diff --git a/tests/ref/acodec/tta b/tests/ref/acodec/tta index 0f60345679..8e183f9922 100644 --- a/tests/ref/acodec/tta +++ b/tests/ref/acodec/tta @@ -1,4 +1,4 @@ -6c260836d7a32e4bd714453a3546c0d5 *tests/data/fate/acodec-tta.matroska -331148 tests/data/fate/acodec-tta.matroska +847d065f082ac94825728b5f1af853eb *tests/data/fate/acodec-tta.tta +330583 tests/data/fate/acodec-tta.tta 95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-tta.out.wav stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 diff --git a/tests/ref/lavf/mka b/tests/ref/lavf/mka new file mode 100644 index 0000000000..962b2542f9 --- /dev/null +++ b/tests/ref/lavf/mka @@ -0,0 +1,3 @@ +b2e3746787b885d0191a1a26f3faa58f *./tests/data/lavf/lavf.mka +43654 ./tests/data/lavf/lavf.mka +./tests/data/lavf/lavf.mka CRC=0x3a1da17e diff --git a/tests/ref/lavf/tta b/tests/ref/lavf/tta new file mode 100644 index 0000000000..745e8d21bd --- /dev/null +++ b/tests/ref/lavf/tta @@ -0,0 +1,3 @@ +f2721d06704ac43d89fdd25835b43598 *./tests/data/lavf/lavf.tta +43200 ./tests/data/lavf/lavf.tta +./tests/data/lavf/lavf.tta CRC=0x3a1da17e