[FFmpeg-devel] [RFC] LOAS (aka LATM) demuxer

Alex Converse alex.converse
Mon Aug 2 17:38:18 CEST 2010


On Sun, Aug 1, 2010 at 4:50 PM, Janne Grunau <janne-ffmpeg at jannau.net> wrote:
> Hi,
>
> attached is a first working version of a LOAS/LATM demuxer. Only tested
> with single audio stream files. No seek support yet since it would
> require to read all frames. LOAS has no index and no timestamps.
>
> It is on its own not very useful since I doubt loas files/streams exists
> besides the ones I've extracted out of mpeg-ts samples. It needs to be
> integrated into the mpeg-ts demuxer. I'm not convinced that demuxer
> chaining is the best way to do it.
>

Could MPEG-TS spin it manually the way we handle dv-in-mov?

> Janne
>
> From f5cb3aa15d7ce995a2aca776a4fd668897bbc88a Mon Sep 17 00:00:00 2001
> From: Janne Grunau <janne at grunau.be>
> Date: Sun, 1 Aug 2010 22:25:43 +0200
> Subject: [PATCH] Add MPEG4 Low Overhead Audio Stream demuxer
>
> LOAS is just a thin synchronization layer around LATM and is the actual
> format used in MPEG-TS with stream_type=0x11.
>
> The demuxer code contains already all code necessary for a real LATM
> demuxer but it is pointless since it would require another format to
> signal if the AudioMuxElement includes an audio configuration.
>
> The demuxer should support multiple programs (streams) but is only
> tested with single stream samples. It misses support for MPEG4 Audio
> features without decoding support in libavcodec.
> ---
> ?Changelog ? ? ? ? ? ? ? ?| ? ?1 +
> ?libavformat/Makefile ? ? | ? ?1 +
> ?libavformat/allformats.c | ? ?1 +
> ?libavformat/avformat.h ? | ? ?2 +-
> ?libavformat/latmdec.c ? ?| ?574 ++++++++++++++++++++++++++++++++++++++++++++++
> ?5 files changed, 578 insertions(+), 1 deletions(-)
> ?create mode 100644 libavformat/latmdec.c
>
> diff --git a/Changelog b/Changelog
> index eded417..c44a25a 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -27,6 +27,7 @@ version <next>:
> ?- SubRip subtitle file muxer and demuxer
> ?- Chinese AVS encoding via libxavs
> ?- ffprobe -show_packets option added
> +- LOAS/LATM demuxer added
>
>
>
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index f73bc54..e41d62f 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -101,6 +101,7 @@ OBJS-$(CONFIG_ISS_DEMUXER) ? ? ? ? ? ? ? += iss.o
> ?OBJS-$(CONFIG_IV8_DEMUXER) ? ? ? ? ? ? ? += iv8.o
> ?OBJS-$(CONFIG_IVF_DEMUXER) ? ? ? ? ? ? ? += ivfdec.o riff.o
> ?OBJS-$(CONFIG_LMLM4_DEMUXER) ? ? ? ? ? ? += lmlm4.o
> +OBJS-$(CONFIG_LOAS_DEMUXER) ? ? ? ? ? ? ?+= latmdec.o
> ?OBJS-$(CONFIG_M4V_DEMUXER) ? ? ? ? ? ? ? += raw.o
> ?OBJS-$(CONFIG_M4V_MUXER) ? ? ? ? ? ? ? ? += raw.o
> ?OBJS-$(CONFIG_MATROSKA_DEMUXER) ? ? ? ? ?+= matroskadec.o matroska.o \
> diff --git a/libavformat/allformats.c b/libavformat/allformats.c
> index 80475b9..2d28335 100644
> --- a/libavformat/allformats.c
> +++ b/libavformat/allformats.c
> @@ -107,6 +107,7 @@ void av_register_all(void)
> ? ? REGISTER_DEMUXER ?(IV8, iv8);
> ? ? REGISTER_DEMUXER ?(IVF, ivf);
> ? ? REGISTER_DEMUXER ?(LMLM4, lmlm4);
> + ? ?REGISTER_DEMUXER ?(LOAS, loas);
> ? ? REGISTER_MUXDEMUX (M4V, m4v);
> ? ? REGISTER_MUXER ? ?(MD5, md5);
> ? ? REGISTER_MUXDEMUX (MATROSKA, matroska);
> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
> index 452aea6..d85d83c 100644
> --- a/libavformat/avformat.h
> +++ b/libavformat/avformat.h
> @@ -22,7 +22,7 @@
> ?#define AVFORMAT_AVFORMAT_H
>
> ?#define LIBAVFORMAT_VERSION_MAJOR 52
> -#define LIBAVFORMAT_VERSION_MINOR 78
> +#define LIBAVFORMAT_VERSION_MINOR 79
> ?#define LIBAVFORMAT_VERSION_MICRO ?0
>
> ?#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
> diff --git a/libavformat/latmdec.c b/libavformat/latmdec.c
> new file mode 100644
> index 0000000..57d762d
> --- /dev/null
> +++ b/libavformat/latmdec.c
> @@ -0,0 +1,574 @@
> +/*
> + * copyright (c) 2009 Paul Kendall <paul at kcbbs.gen.nz>
> + * copyright (c) 2010 Janne Grunau <janne-ffmpeg at jannau.net>
> + *
> + * 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
> + */
> +
> +/**
> + * @file
> + * LATM/LOAS demuxer
> + */
> +
> +#include "avformat.h"
> +#include "libavcodec/avcodec.h"
> +#include "libavcodec/get_bits.h"
> +#include "libavcodec/put_bits.h"
> +#include "libavcodec/mpeg4audio.h"
> +
> +
> +#define LOAS_SYNC_WORD 0x2B7 ? ? ? /// LOAS sync word, 11 bits
> +
> +#define LATM_MAX_FRAME_SIZE ?(8*1024)
> +
> +struct latm_stream_config {
> + ? ?uint32_t ? ? ? ? ?frame_length;
> + ? ?uint32_t ? ? ? ? ?mux_slot_length;
> + ? ?uint8_t ? ? ? ? ? frame_length_type;
> + ? ?uint8_t ? ? ? ? ? extra[64];
> + ? ?int ? ? ? ? ? ? ? extrasize;
> + ? ?MPEG4AudioConfig ?config;
> +};
> +
> +struct latm_demux_context {
> + ? ?uint8_t ? ? ? ? ? ? ? ? ? ?audio_mux_version_A;
> + ? ?uint8_t ? ? ? ? ? ? ? ? ? ?same_time_framing;
> + ? ?uint8_t ? ? ? ? ? ? ? ? ? ?num_sub_frames;
> + ? ?uint8_t ? ? ? ? ? ? ? ? ? ?num_programs;
> + ? ?uint8_t ? ? ? ? ? ? ? ? ? ?num_layers[16];
> + ? ?struct latm_stream_config ?streams[16];
> + ? ?int ? ? ? ? ? ? ? ? ? ? ? ?stream_cnt;
> + ? ?int ? ? ? ? ? ? ? ? ? ? ? ?cur_stream;
> + ? ?int ? ? ? ? ? ? ? ? ? ? ? ?has_config;
> + ? ?int ? ? ? ? ? ? ? ? ? ? ? ?read_data;
> + ? ?AVFormatContext ? ? ? ? ? *s;
> + ? ?GetBitContext ? ? ? ? ? ? *gb;
> + ? ?uint8_t ? ? ? ? ? ? ? ? ? *buf;
> + ? ?int ? ? ? ? ? ? ? ? ? ? ? ?pos;
> + ? ?int ? ? ? ? ? ? ? ? ? ? ? ?len;
> + ? ?uint64_t ? ? ? ? ? ? ? ? ? pkt_cnt;
> +};
> +
> +
> +static inline uint32_t latm_get_value(GetBitContext *gb)
> +{
> + ? ?uint8_t num_bytes = get_bits(gb, 2);
> + ? ?return get_bits_long(gb, num_bytes * 8);
> +}
> +
> +static inline void copy_bits(PutBitContext *pb, GetBitContext *gb, int bits)
> +{
> + ? ?put_bits(pb, bits, get_bits(gb, bits));

unsigned el = get_bits(gb, bits);
put_bits(pb, eb);
return el;

should avoid a bunch of temporaries alter on.

> +}
> +



> +static void read_ga_specific_config(int audio_object_type, GetBitContext *gb,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?PutBitContext *pb)
> +{
> + ? ?int depends_on_coder;
> + ? ?int ext_flag;
> +
> + ? ?copy_bits(pb, gb, 1); ? ? ? ? ? ? ? ? ? ? ? ?// framelen_flag
> + ? ?depends_on_coder = get_bits(gb, 1);
> + ? ?put_bits(pb, 1, depends_on_coder);
> + ? ?if (depends_on_coder)
> + ? ? ? ?copy_bits(pb, gb, 14); ? ? ? ? ? ? ? ? ? // delay
> + ? ?ext_flag = get_bits(gb, 1);
> + ? ?put_bits(pb, 1, ext_flag);
> +
> + ? ?if (audio_object_type == AOT_AAC_SCALABLE ||
> + ? ? ? ?audio_object_type == AOT_ER_AAC_SCALABLE)
> + ? ? ? ?copy_bits(pb, gb, 3); ? ? ? ? ? ? ? ? ? ?// layer number
> +
> + ? ?if (!ext_flag)
> + ? ? ? ?return;
> +
> + ? ?if (audio_object_type == AOT_ER_BSAC) {
> + ? ? ? ?copy_bits(pb, gb, 5); ? ? ? ? ? ? ? ? ? ?// numOfSubFrame
> + ? ? ? ?copy_bits(pb, gb, 11); ? ? ? ? ? ? ? ? ? // layer_length
> + ? ?} else if (audio_object_type == AOT_ER_AAC_LC ||
> + ? ? ? ? ? ? ? audio_object_type == AOT_ER_AAC_LTP ||
> + ? ? ? ? ? ? ? audio_object_type == AOT_ER_AAC_SCALABLE ||
> + ? ? ? ? ? ? ? audio_object_type == AOT_ER_AAC_LD)
> + ? ? ? ?copy_bits(pb, gb, 3); ? ? ? ? ? ? ? ? ? ?// stuff
> + ? ?copy_bits(pb, gb, 1); ? ? ? ? ? ? ? ? ? ? ? ?// extflag3
> +}
> +
> +static int read_audio_specific_config(struct latm_stream_config *stream,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?GetBitContext *gb)
> +{
> + ? ?PutBitContext pb;
> + ? ?int ret = 0;
> + ? ?int audio_object_type;
> + ? ?int sampling_frequency_index;
> +
> + ? ?MPEG4AudioConfig *c = &stream->config;
> +
> + ? ?init_put_bits(&pb, stream->extra, sizeof(stream->extra));
> +
> + ? ?c->sbr = -1;
> +
> + ? ?audio_object_type = get_bits(gb, 5);
> + ? ?put_bits(&pb, 5, audio_object_type);
> + ? ?if (audio_object_type == AOT_ESCAPE) {
> + ? ? ? ?uint8_t extended = get_bits(gb, 6);
> + ? ? ? ?put_bits(&pb, 6, extended);
> + ? ? ? ?audio_object_type = AOT_ESCAPE + extended + 1;
> + ? ?}
> + ? ?c->object_type = audio_object_type;
> +
> + ? ?sampling_frequency_index = get_bits(gb, 4);
> + ? ?put_bits(&pb, 4, sampling_frequency_index);
> + ? ?c->sampling_index = sampling_frequency_index;
> + ? ?c->sample_rate =
> + ? ? ? ? ? ?ff_mpeg4audio_sample_rates[sampling_frequency_index];
> + ? ?if (sampling_frequency_index == 0x0f) {
> + ? ? ? ?c->sample_rate = get_bits_long(gb, 24);
> + ? ? ? ?put_bits(&pb, 24, c->sample_rate);
> + ? ?}
> + ? ?c->chan_config = get_bits(gb, 4);

Is this allowed to be zero? if so does that trigger a PCE?

> + ? ?put_bits(&pb, 4, c->chan_config);
> +
> + ? ?if (c->chan_config < FF_ARRAY_ELEMS(ff_mpeg4audio_channels))
> + ? ? ? ?c->channels = ff_mpeg4audio_channels[c->chan_config];
> +
> + ? ?if (audio_object_type == AOT_AAC_MAIN ||
> + ? ? ? ?audio_object_type == AOT_AAC_LC ||
> + ? ? ? ?audio_object_type == AOT_AAC_SSR ||
> + ? ? ? ?audio_object_type == AOT_AAC_LTP ||
> + ? ? ? ?audio_object_type == AOT_AAC_SCALABLE ||
> + ? ? ? ?audio_object_type == AOT_TWINVQ) {
> + ? ? ? ?read_ga_specific_config(audio_object_type, gb, &pb);
> + ? ?} else if (audio_object_type == AOT_SBR) {
> + ? ? ? ?c->sbr = 1;
> + ? ? ? ?sampling_frequency_index = get_bits(gb, 4);
> + ? ? ? ?c->ext_sampling_index = sampling_frequency_index;
> + ? ? ? ?c->ext_sample_rate =
> + ? ? ? ? ? ? ? ?ff_mpeg4audio_sample_rates[sampling_frequency_index];
> + ? ? ? ?if (sampling_frequency_index == 0x0f) {
> + ? ? ? ? ? ?c->ext_sample_rate = get_bits_long(gb, 24);
> + ? ? ? ? ? ?put_bits(&pb, 24, c->ext_sample_rate);
> + ? ? ? ?}
> + ? ? ? ?c->object_type = get_bits(gb, 5);
> + ? ? ? ?put_bits(&pb, 5, c->object_type);
> + ? ?} else if (audio_object_type >= AOT_ER_AAC_LC) {
> + ? ? ? ?read_ga_specific_config(audio_object_type, gb, &pb);
> + ? ? ? ?copy_bits(&pb, gb, 2); ? ? ? ? ? ? ? ? ? // epConfig
> + ? ?}
> +
> + ? ?if (c->sbr == -1 && c->sample_rate <= 24000)
> + ? ? ? ?c->sample_rate *= 2;
> +
> + ? ?// count the extradata
> + ? ?ret = put_bits_count(&pb);
> + ? ?stream->extrasize = (ret + 7) / 8;
> +
> + ? ?flush_put_bits(&pb);
> + ? ?return ret;
> +}
> +
> +static void copy_audio_specific_config(struct latm_stream_config *dst,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct latm_stream_config *src)
> +{
> + ? ?dst->frame_length_type = src->frame_length_type;
> + ? ?dst->frame_length ? ? ?= src->frame_length;
> + ? ?dst->mux_slot_length ? = src->mux_slot_length;
> + ? ?dst->extrasize ? ? ? ? = src->extrasize;
> +
> + ? ?memcpy(dst->extra, ? src->extra, ? sizeof(*dst->extra));
> + ? ?memcpy(&dst->config, &src->config, sizeof(dst->config));
> +}
> +
> +static void read_stream_mux_config(struct AVFormatContext *s, GetBitContext *gb)
> +{
> + ? ?struct latm_demux_context *ctx = s->priv_data;
> + ? ?struct latm_stream_config *stream_cfg, *prev_stream_cfg = NULL;
> + ? ?AVStream *st = NULL;
> + ? ?uint8_t program, layer;
> + ? ?int use_same_config=0;
> +
> + ? ?int audio_mux_version = get_bits(gb, 1);
> +
> + ? ?ctx->audio_mux_version_A = 0;
> + ? ?if (audio_mux_version)
> + ? ? ? ?ctx->audio_mux_version_A = get_bits(gb, 1);
> +
> + ? ?if (!ctx->audio_mux_version_A) {
> +
> + ? ? ? ?if (audio_mux_version)
> + ? ? ? ? ? ?latm_get_value(gb); ? ? ? ? ? ? ? ? // taraFullness
> +
> + ? ? ? ?// reset stream count
> + ? ? ? ?ctx->stream_cnt ? ? ? ?= 0;
> +
> + ? ? ? ?ctx->same_time_framing = get_bits(gb, 1) + 1;
> + ? ? ? ?ctx->num_sub_frames ? ?= get_bits(gb, 6) + 1;
> + ? ? ? ?ctx->num_programs ? ? ?= get_bits(gb, 4) + 1;
> +
> + ? ? ? ?// for each program
> + ? ? ? ?for (program = 0; program < ctx->num_programs; program++) {
> + ? ? ? ? ? ?ctx->num_layers[program] = get_bits(gb, 3) + 1;
> +
> + ? ? ? ? ? ?// for each layer
> + ? ? ? ? ? ?for (layer = 0; layer < ctx->num_layers[program]; layer++) {
> +
> + ? ? ? ? ? ? ? ?if (layer)
> + ? ? ? ? ? ? ? ? ? ?av_log_missing_feature(s, "multiple layers are not "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "supported", 1);
> +
> + ? ? ? ? ? ? ? ?use_same_config = !ctx->stream_cnt ? 0 : get_bits(gb, 1);
> + ? ? ? ? ? ? ? ?stream_cfg = &ctx->streams[ctx->stream_cnt];
> + ? ? ? ? ? ? ? ?if (s->nb_streams <= ctx->stream_cnt) {
> + ? ? ? ? ? ? ? ? ? ?st = av_new_stream(s, ctx->stream_cnt);
> + ? ? ? ? ? ? ? ? ? ?av_log(s, AV_LOG_DEBUG, "added stream %d for program %d, "
> + ? ? ? ? ? ? ? ? ? ? ? ? ? "layer %d\n", ctx->stream_cnt, program, layer);
> + ? ? ? ? ? ? ? ?} else
> + ? ? ? ? ? ? ? ? ? ?st = s->streams[ctx->stream_cnt];
> +
> + ? ? ? ? ? ? ? ?if (!use_same_config) {
> + ? ? ? ? ? ? ? ? ? ?if (!audio_mux_version) {
> + ? ? ? ? ? ? ? ? ? ? ? ?read_audio_specific_config(stream_cfg, gb);
> + ? ? ? ? ? ? ? ? ? ?} else {
> + ? ? ? ? ? ? ? ? ? ? ? ?uint32_t ascLen = latm_get_value(gb);
> + ? ? ? ? ? ? ? ? ? ? ? ?ascLen -= read_audio_specific_config(stream_cfg, gb);
> + ? ? ? ? ? ? ? ? ? ? ? ?skip_bits_long(gb, ascLen);
> + ? ? ? ? ? ? ? ? ? ?}
> + ? ? ? ? ? ? ? ?} else {
> + ? ? ? ? ? ? ? ? ? ?copy_audio_specific_config(stream_cfg, prev_stream_cfg);
> + ? ? ? ? ? ? ? ?}
> +
> + ? ? ? ? ? ? ? ?st->codec->extradata = av_malloc(stream_cfg->extrasize +
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FF_INPUT_BUFFER_PADDING_SIZE);
> + ? ? ? ? ? ? ? ?if (st->codec->extradata) {
> + ? ? ? ? ? ? ? ? ? ?st->codec->extradata_size = stream_cfg->extrasize;
> + ? ? ? ? ? ? ? ? ? ?memcpy(st->codec->extradata, stream_cfg->extra,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? stream_cfg->extrasize);
> + ? ? ? ? ? ? ? ?}
> +
> + ? ? ? ? ? ? ? ?av_set_pts_info(st, 33, 1, stream_cfg->config.sample_rate);
> + ? ? ? ? ? ? ? ?st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
> + ? ? ? ? ? ? ? ?st->codec->codec_id ? = CODEC_ID_AAC;
> + ? ? ? ? ? ? ? ?st->codec->sample_rate = stream_cfg->config.sample_rate;
> + ? ? ? ? ? ? ? ?st->codec->channels ? ?= stream_cfg->config.channels;
> +
> + ? ? ? ? ? ? ? ?stream_cfg->frame_length_type = get_bits(gb, 3);
> + ? ? ? ? ? ? ? ?switch (stream_cfg->frame_length_type) {
> + ? ? ? ? ? ? ? ? ? ?case 0:
> + ? ? ? ? ? ? ? ? ? ? ? ?skip_bits(gb, 8); ? ? ? // latmBufferFullness
> + ? ? ? ? ? ? ? ? ? ? ? ?if (!ctx->same_time_framing && layer > 0) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?int cur_aot ?= stream_cfg->config.object_type;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?int prev_aot = prev_stream_cfg->config.object_type;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?if ((cur_aot ?== AOT_AAC_SCALABLE ||
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cur_aot ?== AOT_ER_AAC_SCALABLE) &&
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(prev_aot == AOT_CELP ? ? ? ? ||
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? prev_aot == AOT_ER_CELP))
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?skip_bits(gb, 6);// core_frame_offset
> + ? ? ? ? ? ? ? ? ? ? ? ?}
> + ? ? ? ? ? ? ? ? ? ? ? ?break;
> + ? ? ? ? ? ? ? ? ? ?case 1:
> + ? ? ? ? ? ? ? ? ? ? ? ?stream_cfg->frame_length = get_bits(gb, 9);
> + ? ? ? ? ? ? ? ? ? ? ? ?break;
> + ? ? ? ? ? ? ? ? ? ?case 3:
> + ? ? ? ? ? ? ? ? ? ?case 4:
> + ? ? ? ? ? ? ? ? ? ?case 5:
> + ? ? ? ? ? ? ? ? ? ? ? ?skip_bits(gb, 6); ? ? ? // CELP frame length table index
> + ? ? ? ? ? ? ? ? ? ? ? ?break;
> + ? ? ? ? ? ? ? ? ? ?case 6:
> + ? ? ? ? ? ? ? ? ? ?case 7:
> + ? ? ? ? ? ? ? ? ? ? ? ?skip_bits(gb, 1); ? ? ? // HVXC frame length table index
> + ? ? ? ? ? ? ? ? ? ? ? ?break;
> + ? ? ? ? ? ? ? ?}
> +
> + ? ? ? ? ? ? ? ?ctx->stream_cnt++;
> + ? ? ? ? ? ? ? ?prev_stream_cfg = stream_cfg;
> + ? ? ? ? ? ?}
> + ? ? ? ?}
> +
> + ? ? ? ?if (get_bits(gb, 1)) { ? ? ? ? ? ? ? ? ?// other data
> + ? ? ? ? ? ?if (audio_mux_version) {
> + ? ? ? ? ? ? ? ?latm_get_value(gb); ? ? ? ? ? ? // other_data_bits
> + ? ? ? ? ? ?} else {
> + ? ? ? ? ? ? ? ?int esc;
> + ? ? ? ? ? ? ? ?do {
> + ? ? ? ? ? ? ? ? ? ?esc = get_bits(gb, 1);
> + ? ? ? ? ? ? ? ? ? ?skip_bits(gb, 8);
> + ? ? ? ? ? ? ? ?} while (esc);
> + ? ? ? ? ? ?}
> + ? ? ? ?}
> +
> + ? ? ? ?if (get_bits(gb, 1)) ? ? ? ? ? ? ? ? ? ? // crc present
> + ? ? ? ? ? ?skip_bits(gb, 8); ? ? ? ? ? ? ? ? ? ?// config_crc
> + ? ?}
> +}
> +
> +static int read_payload_length_info(struct latm_demux_context *ctx)
> +{
> + ? ?uint8_t stream, tmp;
> + ? ?if (ctx->same_time_framing) {
> + ? ? ? ?for (stream = 0; stream < ctx->stream_cnt; stream++) {
> + ? ? ? ? ? ?struct latm_stream_config *st = &ctx->streams[stream];
> + ? ? ? ? ? ?if (st->frame_length_type == 0) {
> + ? ? ? ? ? ? ? ?int mux_slot_length = 0;
> + ? ? ? ? ? ? ? ?do {
> + ? ? ? ? ? ? ? ? ? ?tmp = get_bits(ctx->gb, 8);
> + ? ? ? ? ? ? ? ? ? ?mux_slot_length += tmp;
> + ? ? ? ? ? ? ? ?} while (tmp == 255);
> + ? ? ? ? ? ? ? ?st->mux_slot_length = mux_slot_length;
> + ? ? ? ? ? ?} else if (st->frame_length_type == 3 ||
> + ? ? ? ? ? ? ? ? ? ? ? st->frame_length_type == 5 ||
> + ? ? ? ? ? ? ? ? ? ? ? st->frame_length_type == 7) {
> + ? ? ? ? ? ? ? ?skip_bits(ctx->gb, 2); ? ? ? ? ?// mux_slot_length_coded
> + ? ? ? ? ? ?}
> + ? ? ? ?}
> + ? ?} else {
> + ? ? ? ?uint8_t num_chunk= get_bits(ctx->gb, 4);
> + ? ? ? ?av_log(ctx->s, AV_LOG_ERROR, "!allStreamsSameTimeFraming not handled "
> + ? ? ? ? ? ? ? "%d\n", num_chunk);
> + ? ?}
> + ? ?return 0;
> +}
> +
> +static int latm_read_audio_mux_element_config(AVFormatContext *s,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int mux_config_present)
> +{
> + ? ?struct latm_demux_context *ctx = s->priv_data;
> + ? ?uint8_t use_same_mux;
> +
> + ? ?if (mux_config_present) {
> + ? ? ? ?use_same_mux = get_bits(ctx->gb, 1);
> + ? ? ? ?if (!use_same_mux) {
> + ? ? ? ? ? ?read_stream_mux_config(s, ctx->gb);
> + ? ? ? ? ? ?ctx->has_config = 1;
> + ? ? ? ?}
> + ? ?}
> +
> + ? ?return ctx->has_config;
> +}
> +
> +static int latm_read_audio_mux_element_data(AVFormatContext *s,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?AVPacket *pkt)
> +{
> + ? ?struct latm_demux_context *ctx = s->priv_data;
> + ? ?struct latm_stream_config *cfg = &ctx->streams[ctx->cur_stream];
> + ? ?int j;
> +
> + ? ?if (!ctx->audio_mux_version_A) {
> +
> + ? ? ? ?pkt->pts ?= pkt->dts = 2048 * ctx->pkt_cnt;
> + ? ? ? ?pkt->data = av_malloc(cfg->mux_slot_length);

if malloc fails?

> + ? ? ? ?pkt->size = cfg->mux_slot_length;
> + ? ? ? ?pkt->stream_index = ctx->cur_stream++;
> + ? ? ? ?//TODO: try to use byte copying
> + ? ? ? ?for (j = 0; j < cfg->mux_slot_length; j++)
> + ? ? ? ? ? ?pkt->data[j] = get_bits(ctx->gb, 8);
> + ? ? ? ?//av_hex_dump_log(s, AV_LOG_INFO, pkt->data, pkt->size);
> + ? ?} else {
> + ? ? ? ?av_log(s, AV_LOG_ERROR, "invalid latm syntax\n");
> + ? ? ? ?return -1;
> + ? ?}
> +
> + ? ?return 0;
> +}
> +
> +/** LOAS */
> +static int loas_read_audio_sync_stream(AVFormatContext *s,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct latm_demux_context *latmctx)
> +{
> + ? ?ByteIOContext *pb = s->pb;
> + ? ?int muxlength;
> + ? ?uint8_t *buf = latmctx->buf + latmctx->pos;
> + ? ?int size ? ? = latmctx->len - latmctx->pos;
> +
> + ? ?while (size >= 3) {
> +
> + ? ? ? ?if ((buf[0] << 3 | buf[1] >> 5) == LOAS_SYNC_WORD) {
> +
> + ? ? ? ? ? ?muxlength = ((buf[1] & 0x1f) << 8) | buf[2];
> + ? ? ? ? ? ?if (muxlength+3 > size) {
> + ? ? ? ? ? ? ? ?memmove(latmctx->buf, buf, size);
> + ? ? ? ? ? ? ? ?buf ? ? ? ? ?= latmctx->buf;
> + ? ? ? ? ? ? ? ?latmctx->pos = 0;
> + ? ? ? ? ? ? ? ?latmctx->len = size + get_buffer(pb, latmctx->buf+size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? LATM_MAX_FRAME_SIZE-size);
> + ? ? ? ? ? ?} else {
> + ? ? ? ? ? ? ? ?//av_log(s, AV_LOG_INFO, "LOAS frame of %d bytes\n", muxlength);
> + ? ? ? ? ? ? ? ?return muxlength+3;
> + ? ? ? ? ? ?}
> + ? ? ? ?} else
> + ? ? ? ? ? ?latmctx->pos++;
> +
> + ? ? ? ?size = latmctx->len - latmctx->pos;
> + ? ?}
> +
> + ? ?return -1;
> +}
> +
> +/**
> + * Read packets until a config or data is found
> + *
> + * @param pkt output packet, NULL for read_header
> + * @param nb_packets number of LOAS frames probing for audio config
> + * @return 0 on success, < 0 on error.
> + */
> +static int handle_packets(struct AVFormatContext *s, AVPacket *pkt,
> + ? ? ? ? ? ? ? ? ? ? ? ? ?int nb_packets)
> +{
> + ? ?struct latm_demux_context *latmctx = s->priv_data;
> +
> + ? ?int has_config, ret, packet_num=0;
> +
> + ? ?while (!latmctx->read_data) {
> +
> + ? ? ? ?ret = loas_read_audio_sync_stream(s, latmctx);
> + ? ? ? ?if (ret < 0)
> + ? ? ? ? ? ?return -1;
> +
> + ? ? ? ?init_get_bits(latmctx->gb, latmctx->buf+latmctx->pos+3, (ret-3)*8);
> + ? ? ? ?latmctx->pos += ret;
> +
> + ? ? ? ?has_config = latm_read_audio_mux_element_config(s, 1);
> +
> + ? ? ? ?if (nb_packets) {
> + ? ? ? ? ? ?if (has_config) {
> + ? ? ? ? ? ? ? ?latmctx->has_config = has_config;
> + ? ? ? ? ? ? ? ?return 0;
> + ? ? ? ? ? ?}
> + ? ? ? ? ? ?if (packet_num > nb_packets)
> + ? ? ? ? ? ? ? ?return -1;
> + ? ? ? ?}
> +
> + ? ? ? ?if (latmctx->has_config)
> + ? ? ? ? ? ?latmctx->read_data = 1;
> + ? ?}
> +
> + ? ?read_payload_length_info(latmctx);
> +
> + ? ?ret = latm_read_audio_mux_element_data(s, pkt);
> + ? ?if (latmctx->cur_stream >= latmctx->stream_cnt || ret < 0) {
> + ? ? ? ?latmctx->read_data ?= 0;
> + ? ? ? ?latmctx->cur_stream = 0;
> + ? ? ? ?latmctx->pkt_cnt++;
> + ? ?}
> +
> + ? ?return ret;
> +}
> +
> +
> +static int loas_probe(AVProbeData *pd)
> +{
> + ? ?int i=0, len=0, score=0;
> + ? ?uint8_t *buf = pd->buf;
> +
> + ? ?while (i+3 < pd->buf_size && score < AVPROBE_SCORE_MAX) {
> + ? ? ? ?if ((buf[i] << 3 | (buf[i+1] & 0xe0) >> 5) == LOAS_SYNC_WORD) {
> + ? ? ? ? ? ?if (len || !i) {
> + ? ? ? ? ? ? ? ?score += AVPROBE_SCORE_MAX/4;
> + ? ? ? ? ? ?} else
> + ? ? ? ? ? ? ? ?score++;
> + ? ? ? ? ? ?len = (buf[i+1] & 0x1f) << 8 | buf[i+2];
> + ? ? ? ? ? ?dprintf(NULL, "found LOAS_SYNC_WORD at 0x%x. "
> + ? ? ? ? ? ? ? ? ? ?"len = %d, score = %d\n", i, len, score);
> + ? ? ? ? ? ?i += len+3;
> + ? ? ? ?} else {
> + ? ? ? ? ? ?if (len && score > 0)
> + ? ? ? ? ? ? ? ?score -= AVPROBE_SCORE_MAX/4;
> + ? ? ? ? ? ?len = 0;
> + ? ? ? ? ? ?i++;
> + ? ? ? ?}
> + ? ?}
> +
> + ? ?return FFMAX(0, FFMIN(score, AVPROBE_SCORE_MAX));
> +}
> +
> +
> +static int loas_read_header(AVFormatContext *s,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?AVFormatParameters *ap)
> +{
> + ? ?ByteIOContext *pb = s->pb;
> + ? ?struct latm_demux_context *latmctx = s->priv_data;
> +
> + ? ?latmctx->s = s;
> +
> + ? ?s->ctx_flags |= AVFMTCTX_NOHEADER;
> +
> + ? ?if (!latmctx->buf) {
> + ? ? ? ?latmctx->pos = 0;
> + ? ? ? ?latmctx->buf = av_malloc(LATM_MAX_FRAME_SIZE);

If malloc fails?

> + ? ? ? ?latmctx->len = get_buffer(pb, latmctx->buf, LATM_MAX_FRAME_SIZE);
> + ? ?}
> +
> + ? ?if (!latmctx->gb)
> + ? ? ? ?latmctx->gb = av_malloc(sizeof(*latmctx->gb));

If malloc fails?

> +
> + ? ?handle_packets(s, NULL, 100);
> +
> + ? ?url_fseek(pb, 0, SEEK_SET);
> + ? ?latmctx->len = get_buffer(pb, latmctx->buf, LATM_MAX_FRAME_SIZE);
> + ? ?latmctx->pos = 0;
> +
> + ? ?return latmctx->has_config ? 0 : -1;
> +}
> +
> +
> +static int loas_read_packet(struct AVFormatContext *s, AVPacket *pkt)
> +{
> + ? ?struct latm_demux_context *latmctx = s->priv_data;
> + ? ?ByteIOContext *pb = s->pb;
> +
> + ? ?latmctx->s = s;
> +
> + ? ?if (!latmctx->buf) {
> + ? ? ? ?latmctx->buf = av_malloc(LATM_MAX_FRAME_SIZE);

if malloc fails?

> + ? ? ? ?latmctx->pos = 0;
> + ? ? ? ?latmctx->len = get_buffer(pb, latmctx->buf, LATM_MAX_FRAME_SIZE);
> + ? ?}
> +
> + ? ?if (!latmctx->gb)
> + ? ? ? ?latmctx->gb = av_malloc(sizeof(*latmctx->gb));
> +

if malloc fails?

> + ? ?return handle_packets(s, pkt, 0);
> +}
> +
> +static int latm_close(struct AVFormatContext *avctx)
> +{
> + ? ?struct latm_demux_context *latmctx = avctx->priv_data;
> +
> + ? ?av_freep(&latmctx->buf);
> + ? ?av_freep(&latmctx->gb);
> + ? ?return 0;
> +}
> +
> +/*
> +AVInputFormat latm_demuxer = {
> + ? ?"latm",
> + ? ?NULL_IF_CONFIG_SMALL("Low-overhead MPEG-4 Audio Transport Multiplex"),
> + ? ?sizeof(struct latm_demux_context),
> + ? ?latm_probe,
> + ? ?latm_read_header,
> + ? ?latm_read_packet,
> + ? ?latm_close,
> +};
> +*/
> +
> +AVInputFormat loas_demuxer = {
> + ? ?"loas",
> + ? ?NULL_IF_CONFIG_SMALL("MPEG4 Low-overhead Audio Stream"),
> + ? ?sizeof(struct latm_demux_context),
> + ? ?loas_probe,
> + ? ?loas_read_header,
> + ? ?loas_read_packet,
> + ? ?latm_close,
> +};
> --
> 1.7.2
>
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at mplayerhq.hu
> https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-devel
>



More information about the ffmpeg-devel mailing list