[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