From: asivery via ffmpeg-devel <ffmpeg-devel@ffmpeg.org> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org> Cc: asivery <asivery@protonmail.com> Subject: Re: [FFmpeg-devel] [PATCH] avformat/aea: Add aea muxer Date: Sat, 09 Mar 2024 17:20:49 +0000 Message-ID: <Udn4nQXIGrYLw_55GiJyTdoD62pxsS1fCC3P4_9zRbRHqK_-xSQkhL4TuqDPWJkkChyoMWeQJM32_JflR8bS2SJeyz6YXxzxS2avvIw78PA=@protonmail.com> (raw) In-Reply-To: <AS8P250MB0744508AE1AE97392C1AB6978F262@AS8P250MB0744.EURP250.PROD.OUTLOOK.COM> [-- Attachment #1: Type: text/plain, Size: 4128 bytes --] Thank you both for the suggestions. I've updated the code as requested, and I apologize for the AV_LOG_WARNING instead of AV_LOG_ERROR - it was an oversight on my part. I have also added the stream codec check, and it did get triggered when I tried to feed it audio that was not ATRAC1, so it seems it is required. Regarding titles being truncated - that was my intention. However I've now added a warning if it was going to happen. As for the block count in the header - none of the modern software which uses AEA reads that field, but for the older software, it will now be truncated to UINT32_MAX if needed. Is there anything else that needs changes? - asivery On Saturday, March 9th, 2024 at 1:06 PM, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote: > asivery via ffmpeg-devel: > > > +#include "libavutil/intreadwrite.h" > > +#include "libavutil/avstring.h" > > > These two headers seem unused. > > > +#include "avformat.h" > > +#include "avio_internal.h" > > +#include "rawenc.h" > > +#include "mux.h" > > + > > +static int aea_write_header(AVFormatContext *s) > > +{ > > + const AVDictionaryEntry title_entry; > > + int title_length = 0; > > + char title_contents; > > > const please. Also we put the * to the variable (because "char* foo, > bar" still only declares one pointer to char). Furthermore, the scope > for this should be the block below. > > > + AVStream st; > > + > > + if (s->nb_streams > 1) { > > + av_log(s, AV_LOG_WARNING, "Got more than one stream to encode. This is not supported.\n"); > > + return AVERROR(EINVAL); > > + } > > + > > + st = s->streams[0]; > > + if (st->codecpar->ch_layout.nb_channels != 1 && st->codecpar->ch_layout.nb_channels != 2) { > > + av_log(s, AV_LOG_ERROR, "Invalid amount of channels to mux (%d).\n", st->codecpar->ch_layout.nb_channels); > > + return AVERROR(EINVAL); > > + } > > + > > + if (st->codecpar->sample_rate != 44100) { > > + av_log(s, AV_LOG_ERROR, "Invalid sample rate (%d) AEA only supports 44.1kHz.\n", st->codecpar->sample_rate); > > + return AVERROR(EINVAL); > > + } > > + > > + / Write magic / > > + avio_wl32(s->pb, 2048); > > + > > + / Write AEA title */ > > + title_entry = av_dict_get(st->metadata, "title", NULL, 0); > > + if (title_entry) { > > + title_contents = title_entry->value; > > + title_length = strlen(title_contents); > > > Possible truncation here. > > > + title_length = FFMIN(256, title_length); > > + avio_write(s->pb, title_contents, title_length); > > + } > > + > > + ffio_fill(s->pb, 0, 256 - title_length); > > + > > + /* Write number of frames (zero at header-writing time, will seek later), number of channels / > > + avio_wl32(s->pb, 0); > > + avio_w8(s->pb, st->codecpar->ch_layout.nb_channels); > > + avio_w8(s->pb, 0); > > + > > + / Pad the header to 2048 bytes */ > > + ffio_fill(s->pb, 0, 1782); > > + > > + return 0; > > +} > > + > > +static int aea_write_trailer(struct AVFormatContext *s) > > +{ > > + AVIOContext *pb = s->pb; > > + AVStream st = s->streams[0]; > > + if (pb->seekable & AVIO_SEEKABLE_NORMAL) { > > + / Seek to rewrite the block count. */ > > + avio_seek(pb, 260, SEEK_SET); > > + avio_wl32(pb, st->nb_frames * st->codecpar->ch_layout.nb_channels); > > > I don't see anything guaranteeing that the result fits into 32 bits. > > > + } else { > > + av_log(s, AV_LOG_WARNING, "unable to rewrite AEA header.\n"); > > + } > > + > > + return 0; > > +} > > + > > +const FFOutputFormat ff_aea_muxer = { > > + .p.name = "aea", > > + .p.long_name = NULL_IF_CONFIG_SMALL("MD STUDIO audio"), > > + .p.extensions = "aea", > > + .p.audio_codec = AV_CODEC_ID_ATRAC1, > > + > > + .write_header = aea_write_header, > > + .write_packet = ff_raw_write_packet, > > + .write_trailer = aea_write_trailer, > > +}; > > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-avformat-aea-Add-aea-muxer.patch --] [-- Type: text/x-patch; name=0001-avformat-aea-Add-aea-muxer.patch, Size: 6904 bytes --] From ee1d4c93c66e729d9d0456b2e8e789f3f98389e3 Mon Sep 17 00:00:00 2001 From: asivery <asivery@protonmail.com> Date: Fri, 8 Mar 2024 14:45:02 +0100 Subject: [PATCH] avformat/aea: Add aea muxer Signed-off-by: asivery <asivery@protonmail.com> --- doc/muxers.texi | 10 +++ libavformat/Makefile | 3 +- libavformat/{aea.c => aeadec.c} | 0 libavformat/aeaenc.c | 115 ++++++++++++++++++++++++++++++++ libavformat/allformats.c | 1 + 5 files changed, 128 insertions(+), 1 deletion(-) rename libavformat/{aea.c => aeadec.c} (100%) create mode 100644 libavformat/aeaenc.c diff --git a/doc/muxers.texi b/doc/muxers.texi index 2104cc4a95..a4df8f736d 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -663,6 +663,16 @@ when enabled, write a CRC checksum for each packet to the output, default is @code{false} @end table +@anchor{aea} +@section aea +MD STUDIO audio muxer. + +This muxer accepts a single ATRAC1 audio stream with either one or two channels +and a sample rate of 44100Hz. + +As AEA supports storing the track title, this muxer will also write +the title from stream's metadata to the container. + @anchor{adts} @section adts Audio Data Transport Stream muxer. diff --git a/libavformat/Makefile b/libavformat/Makefile index 8811a0ffc9..70d56f391f 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -91,7 +91,8 @@ OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o apetag.o img2.o \ id3v2enc.o OBJS-$(CONFIG_ADX_DEMUXER) += adxdec.o OBJS-$(CONFIG_ADX_MUXER) += rawenc.o -OBJS-$(CONFIG_AEA_DEMUXER) += aea.o pcm.o +OBJS-$(CONFIG_AEA_DEMUXER) += aeadec.o pcm.o +OBJS-$(CONFIG_AEA_MUXER) += aeaenc.o rawenc.o OBJS-$(CONFIG_AFC_DEMUXER) += afc.o OBJS-$(CONFIG_AIFF_DEMUXER) += aiffdec.o aiff.o pcm.o \ mov_chan.o replaygain.o diff --git a/libavformat/aea.c b/libavformat/aeadec.c similarity index 100% rename from libavformat/aea.c rename to libavformat/aeadec.c diff --git a/libavformat/aeaenc.c b/libavformat/aeaenc.c new file mode 100644 index 0000000000..12aed72a13 --- /dev/null +++ b/libavformat/aeaenc.c @@ -0,0 +1,115 @@ +/* + * MD STUDIO audio muxer + * + * Copyright (c) 2024 asivery + * + * 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 "avio_internal.h" +#include "rawenc.h" +#include "mux.h" + +static int aea_write_header(AVFormatContext *s) +{ + const AVDictionaryEntry *title_entry; + int title_length = 0; + AVStream *st; + + if (s->nb_streams > 1) { + av_log(s, AV_LOG_ERROR, "Got more than one stream to encode. This is not supported.\n"); + return AVERROR(EINVAL); + } + + st = s->streams[0]; + if (st->codecpar->ch_layout.nb_channels != 1 && st->codecpar->ch_layout.nb_channels != 2) { + av_log(s, AV_LOG_ERROR, "Only maximum 2 channels are supported in the audio" + " stream, %d channels were found.\n", st->codecpar->ch_layout.nb_channels); + return AVERROR(EINVAL); + } + + if (st->codecpar->codec_id != AV_CODEC_ID_ATRAC1) { + av_log(s, AV_LOG_ERROR, "AEA can only store ATRAC1 streams, %s was found.\n", avcodec_get_name(st->codecpar->codec_id)); + return AVERROR(EINVAL); + } + + if (st->codecpar->sample_rate != 44100) { + av_log(s, AV_LOG_ERROR, "Invalid sample rate (%d) AEA only supports 44.1kHz.\n", st->codecpar->sample_rate); + return AVERROR(EINVAL); + } + + /* Write magic */ + avio_wl32(s->pb, 2048); + + /* Write AEA title */ + title_entry = av_dict_get(st->metadata, "title", NULL, 0); + if (title_entry) { + const char *title_contents = title_entry->value; + title_length = strlen(title_contents); + if (title_length > 256) { + av_log(s, AV_LOG_WARNING, "Title too long, truncated to 256 bytes.\n"); + title_length = 256; + } + avio_write(s->pb, title_contents, title_length); + } + + ffio_fill(s->pb, 0, 256 - title_length); + + /* Write number of frames (zero at header-writing time, will seek later), number of channels */ + avio_wl32(s->pb, 0); + avio_w8(s->pb, st->codecpar->ch_layout.nb_channels); + avio_w8(s->pb, 0); + + /* Pad the header to 2048 bytes */ + ffio_fill(s->pb, 0, 1782); + + return 0; +} + +static int aea_write_trailer(struct AVFormatContext *s) +{ + int64_t total_blocks; + AVIOContext *pb = s->pb; + AVStream *st = s->streams[0]; + if (pb->seekable & AVIO_SEEKABLE_NORMAL) { + /* Seek to rewrite the block count. */ + avio_seek(pb, 260, SEEK_SET); + total_blocks = st->nb_frames * st->codecpar->ch_layout.nb_channels; + if (total_blocks > UINT32_MAX) { + av_log(s, AV_LOG_WARNING, "Too many frames in the file to properly encode the header (%ld)." + " Block count in the header will be truncated.\n", total_blocks); + total_blocks = UINT32_MAX; + } + avio_wl32(pb, total_blocks); + } else { + av_log(s, AV_LOG_WARNING, "Unable to rewrite AEA header.\n"); + } + + return 0; +} + +const FFOutputFormat ff_aea_muxer = { + .p.name = "aea", + .p.long_name = NULL_IF_CONFIG_SMALL("MD STUDIO audio"), + .p.extensions = "aea", + .p.audio_codec = AV_CODEC_ID_ATRAC1, + + .write_header = aea_write_header, + .write_packet = ff_raw_write_packet, + .write_trailer = aea_write_trailer, +}; diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 0a0e76138f..5639715104 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -47,6 +47,7 @@ extern const FFOutputFormat ff_adts_muxer; extern const FFInputFormat ff_adx_demuxer; extern const FFOutputFormat ff_adx_muxer; extern const FFInputFormat ff_aea_demuxer; +extern const FFOutputFormat ff_aea_muxer; extern const FFInputFormat ff_afc_demuxer; extern const FFInputFormat ff_aiff_demuxer; extern const FFOutputFormat ff_aiff_muxer; -- 2.34.1 [-- Attachment #3: Type: text/plain, Size: 251 bytes --] _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2024-03-09 17:21 UTC|newest] Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top 2024-03-08 11:19 asivery via ffmpeg-devel 2024-03-08 11:22 ` Andreas Rheinhardt 2024-03-08 11:48 ` asivery via ffmpeg-devel 2024-03-08 12:06 ` Andreas Rheinhardt 2024-03-08 13:50 ` asivery via ffmpeg-devel 2024-03-09 10:17 ` Stefano Sabatini 2024-03-09 12:06 ` Andreas Rheinhardt 2024-03-09 17:20 ` asivery via ffmpeg-devel [this message] 2024-03-09 17:48 ` Andreas Rheinhardt 2024-03-09 17:57 ` asivery via ffmpeg-devel 2024-03-10 14:00 ` Stefano Sabatini 2024-03-10 14:20 ` asivery via ffmpeg-devel 2024-03-10 15:10 ` Stefano Sabatini 2024-03-12 10:27 ` Stefano Sabatini 2024-03-12 11:10 ` asivery via ffmpeg-devel
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to='Udn4nQXIGrYLw_55GiJyTdoD62pxsS1fCC3P4_9zRbRHqK_-xSQkhL4TuqDPWJkkChyoMWeQJM32_JflR8bS2SJeyz6YXxzxS2avvIw78PA=@protonmail.com' \ --to=ffmpeg-devel@ffmpeg.org \ --cc=asivery@protonmail.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git