[FFmpeg-devel] [PATCH 2/2] aeaenc: add an aea muxer
Andreas Rheinhardt
andreas.rheinhardt at gmail.com
Fri Feb 26 07:48:51 EET 2021
Lynne:
> This allows to (re)mux Sony ATRAC1 files.
>
> Patch attached
>
> +#include "libavutil/intreadwrite.h"
> +#include "avformat.h"
> +#include "rawenc.h"
> +
> +#define AT1_SU_SIZE 212
> +
> +typedef struct AEAEncContext {
> + uint32_t frame_cnt;
> +} AEAEncContext;
> +
> +static int aea_write_header(AVFormatContext *s)
> +{
> + AVDictionaryEntry *dtmp;
> + AVCodecParameters *par = s->streams[0]->codecpar;
> + AVIOContext *pb = s->pb;
> +
> + if (par->channels != 1 && par->channels != 2) {
> + av_log(s, AV_LOG_ERROR, "Unsupported number of channels %i!\n", par->channels);
> + return AVERROR(EINVAL);
> + }
> +
> + if (par->sample_rate != 44100) {
> + av_log(s, AV_LOG_ERROR, "Unsupported samplerate %i!\n", par->sample_rate);
> + return AVERROR(EINVAL);
> + }
> +
> + if (par->block_align != (AT1_SU_SIZE * par->channels)) {
> + av_log(s, AV_LOG_ERROR, "Unsupported block align %i!\n", par->block_align);
> + return AVERROR(EINVAL);
> + }
> +
> + avio_wl32(pb, 0x800); // magic
> +
> + dtmp = av_dict_get(s->metadata, "title", NULL, 0);
> + if (dtmp) {
> + int len = FFMIN(strlen(dtmp->value), 15);
> + avio_write(pb, dtmp->value, len);
> + for (int i = 0; i < (16 - len); i++)
> + avio_w8(pb, 0);
> + } else {
> + avio_wl64(pb, 0);
> + avio_wl64(pb, 0);
> + }
How about
int len = 0;
...
if (dtmp) {
len = FFMIN
avio_write(pb, drmp->value, len);
}
ffio_fill(pb, 0, 16 - len);
> +
> + avio_skip(pb, 240); // not needed
> +
skip? For a muxer? There is a danger of producing nondeterministic
output here. Better add these 240 bytes to the ffio_fill I just suggested.
> + avio_wl32(pb, 0); // #frames field overwritten when closing
This could also be done by ffio_fill.
> + avio_w8 (pb, par->channels); // Number of channels
> +
> + /* Skip to 2048 */
> + avio_skip(pb, 2048 - avio_tell(pb));
Same problem as above. Best to just use ffio_fill(pb, 0, 2048 - 265).
> +
> + return 0;
> +}
> +
> +static int aea_write_packet(AVFormatContext *s, AVPacket *pkt)
> +{
> + AEAEncContext *ctx = s->priv_data;
> + ctx->frame_cnt++;
Unnecessary: The muxing code generically sets AVStream.nb_frames. You
can just use ff_raw_write_packet as your write_packet function and can
remove the whole context.
> + return ff_raw_write_packet(s, pkt);
> +}
> +
> +static int aea_write_trailer(AVFormatContext *s)
> +{
> + AVIOContext *pb = s->pb;
> + AEAEncContext *ctx = s->priv_data;
> +
> + if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && ctx->frame_cnt > 1) {
> + int64_t end = avio_tell(pb);
> +
> + avio_seek(pb, 260, SEEK_SET);
> + avio_wl32(pb, ctx->frame_cnt);
> + avio_seek(pb, end, SEEK_SET);
> + }
> +
> + return 0;
> +}
> +
> +AVOutputFormat ff_aea_muxer = {
> + .name = "aea",
> + .long_name = NULL_IF_CONFIG_SMALL("MD STUDIO audio"),
> + .priv_data_size = sizeof(AEAEncContext),
> + .extensions = "aea",
> + .audio_codec = AV_CODEC_ID_ATRAC1,
> + .write_header = aea_write_header,
> + .write_packet = aea_write_packet,
> + .write_trailer = aea_write_trailer,
> + .flags = AVFMT_NOTIMESTAMPS,
> +};
More information about the ffmpeg-devel
mailing list