Files
BPI-CM9-Linux/aml-comp/multimedia/ffmpeg-aml/libavcodec/dra_parser.c
T

234 lines
5.5 KiB
C
Raw Normal View History

2026-08-25 10:02:36 +08:00
/*
* 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,
};