/* * DRA parser * Copyright (c) 2026 Amlogic, Inc. * * 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 "parser.h" #include "get_bits.h" #include "libavcodec/internal.h" #include "libavutil/log.h" typedef struct DRAParseContext { int sample_rate; int channels; /* Lightweight state only (no heap buffer management) */ int last_sync_pos; } DRAParseContext; /* DRA sample rate table */ static const int dra_sample_rates[13] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000 }; /* Find sync word 0x7FFF */ static int dra_find_sync(const uint8_t *buf, int buf_size) { int i; for (i = 0; i < buf_size - 1; i++) { if (buf[i] == 0x7F && buf[i + 1] == 0xFF) return i; } return -1; } /* Parse DRA frame header safely */ static int dra_parse_header(const uint8_t *buf, int buf_size, int *frame_size, int *sample_rate, int *channels) { GetBitContext gb; int frm_header_type; int num_word; int sr_idx; int num_normal_ch; int num_lfe_ch; if (buf_size < 8) return AVERROR_INVALIDDATA; init_get_bits8(&gb, buf, buf_size); /* Sync word */ if (get_bits(&gb, 16) != 0x7FFF) return AVERROR_INVALIDDATA; frm_header_type = get_bits1(&gb); /* Frame size in 32-bit words */ if (frm_header_type == 0) num_word = get_bits(&gb, 10); else num_word = get_bits(&gb, 13); *frame_size = num_word * 4; /* Basic sanity check */ if (*frame_size < 32 || *frame_size > 8192) return AVERROR_INVALIDDATA; /* Blocks per frame (ignored but must consume bits) */ get_bits(&gb, 2); /* Sample rate index */ sr_idx = get_bits(&gb, 4); if (sr_idx > 12) return AVERROR_INVALIDDATA; *sample_rate = dra_sample_rates[sr_idx]; /* Channel parsing */ if (frm_header_type == 0) { num_normal_ch = get_bits(&gb, 3) + 1; num_lfe_ch = get_bits1(&gb); } else { num_normal_ch = get_bits(&gb, 6) + 1; num_lfe_ch = get_bits(&gb, 2); } *channels = num_normal_ch + num_lfe_ch; return 0; } /* Find frame boundary */ static int dra_find_frame_end(AVCodecParserContext *s, const uint8_t *buf, int buf_size) { int frame_size; int sr, ch; if (buf_size < 8) return END_NOT_FOUND; /* Try to parse header */ if (dra_parse_header(buf, buf_size, &frame_size, &sr, &ch) < 0) return END_NOT_FOUND; /* Not enough data */ if (buf_size < frame_size) return END_NOT_FOUND; return frame_size; } /* * Split function (used for resync) * Must be conservative and safe. */ static int dra_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size) { int pos = dra_find_sync(buf, buf_size); if (pos < 0) return buf_size; /* drop all if no sync found */ return pos; } /* * Main parser function */ static int dra_parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **outbuf, int *outbuf_size, const uint8_t *buf, int buf_size) { DRAParseContext *ctx = s->priv_data; int offset = 0; /* Step 1: find sync */ offset = dra_find_sync(buf, buf_size); if (offset < 0) { *outbuf = NULL; *outbuf_size = 0; return buf_size; } buf += offset; buf_size -= offset; /* Step 2: find frame size */ int frame_size = dra_find_frame_end(s, buf, buf_size); if (frame_size == END_NOT_FOUND) { *outbuf = NULL; *outbuf_size = 0; return offset ? offset : buf_size; } /* Step 3: parse header (for codec config only) */ int sr = 0, ch = 0; if (dra_parse_header(buf, buf_size, &frame_size, &sr, &ch) == 0) { avctx->sample_rate = sr; avctx->channels = ch; ctx->sample_rate = sr; ctx->channels = ch; } /* Fixed DRA frame duration (typical) */ s->duration = 1024; /* Output frame */ *outbuf = buf; *outbuf_size = frame_size; /* Consumed bytes */ return offset + frame_size; } /* * Safe close */ static void dra_close(AVCodecParserContext *s) { DRAParseContext *ctx = s->priv_data; av_log(NULL, AV_LOG_INFO, "[DRA] parser close ctx=%p\n", ctx); if (ctx) { memset(ctx, 0, sizeof(*ctx)); } } /* * Parser definition */ AVCodecParser ff_dra_parser = { .codec_ids = { AV_CODEC_ID_DRA }, .priv_data_size = sizeof(DRAParseContext), .parser_parse = dra_parse, .parser_close = dra_close, .split = dra_split, };