/* * aacscan: FFmpeg's AAC decoder, asked one frame at a time how many bytes * each raw AAC frame takes. For johnmcm.com's Video Repair: a recording cut * off before its index holds its sound as raw AAC frames with no lengths * written down, so the page finds them by decoding, here, and copies them * into the repaired file untouched. * * The decoder's own decode callback returns the bytes it consumed; the * public API keeps that to itself, so it is called directly (the internal * header is part of the FFmpeg 5.1.6 tree this is built in). * * LGPL-2.1-or-later, as FFmpeg is. */ #include #include #include #include "libavcodec/avcodec.h" #include "libavcodec/codec_internal.h" #include "libavutil/frame.h" #include "libavutil/mem.h" static AVCodecContext *ctx; static AVFrame *frame; static AVPacket *pkt; static const FFCodec *codec; /* The last frame's sample count and channels, for the page to check. */ static int last_samples; static int last_channels; void *aacs_alloc(int n) { return malloc(n); } void aacs_free(void *p) { free(p); } void aacs_close(void) { if (ctx) avcodec_free_context(&ctx); if (frame) av_frame_free(&frame); if (pkt) av_packet_free(&pkt); } /* Opens the decoder with an AudioSpecificConfig; 0 when it took it. */ int aacs_open(const uint8_t *asc, int len) { aacs_close(); const AVCodec *c = avcodec_find_decoder(AV_CODEC_ID_AAC); if (!c) return -1; codec = ffcodec(c); ctx = avcodec_alloc_context3(c); frame = av_frame_alloc(); pkt = av_packet_alloc(); if (!ctx || !frame || !pkt) return -2; ctx->extradata = av_mallocz(len + AV_INPUT_BUFFER_PADDING_SIZE); if (!ctx->extradata) return -2; memcpy(ctx->extradata, asc, len); ctx->extradata_size = len; if (avcodec_open2(ctx, c, NULL) < 0) return -3; return 0; } /* * Decodes one frame from the start of buf: the bytes it took (> 0), or * a negative number when the bytes there are not an AAC frame under this * configuration. buf must have AV_INPUT_BUFFER_PADDING_SIZE (64) spare * bytes after size, zeroed. */ int aacs_frame(uint8_t *buf, int size) { if (!ctx) return -100; int got = 0; pkt->data = buf; pkt->size = size; av_frame_unref(frame); int ret = codec->cb.decode(ctx, frame, &got, pkt); last_samples = got ? frame->nb_samples : 0; last_channels = got ? frame->ch_layout.nb_channels : 0; av_frame_unref(frame); if (ret < 0) return ret; if (!got) return -101; return ret; } int aacs_samples(void) { return last_samples; } int aacs_channels(void) { return last_channels; }