[Ffmpeg-devel] [PATCH] apple caff demuxer

Baptiste Coudurier baptiste.coudurier
Wed Apr 4 11:44:34 CEST 2007


Hi

Justin Ruggles wrote:
>>> [...]
>>> +        if(ctx->bits_per_channel == 8) {
>>> +            ctx->codec_id = CODEC_ID_PCM_S8;
>>> +        } else if(ctx->bits_per_channel == 16) {
>>> +            if(ctx->format_flags & CAFF_LPCM_FLAGS_IS_LITTLEENDIAN) {
>>> +                ctx->codec_id = CODEC_ID_PCM_S16LE;
>>> +            } else {
>>> +                ctx->codec_id = CODEC_ID_PCM_S16BE;
>>> +            }
>>> +        } else if(ctx->bits_per_channel == 24) {
>>> +            if(ctx->format_flags & CAFF_LPCM_FLAGS_IS_LITTLEENDIAN) {
>>> +                ctx->codec_id = CODEC_ID_PCM_S24LE;
>>> +            } else {
>>> +                ctx->codec_id = CODEC_ID_PCM_S24BE;
>>> +            }
>>> +        } else if(ctx->bits_per_channel == 32) {
>>> +            if(ctx->format_flags & CAFF_LPCM_FLAGS_IS_LITTLEENDIAN) {
>>> +                ctx->codec_id = CODEC_ID_PCM_S32LE;
>>> +            } else {
>>> +                ctx->codec_id = CODEC_ID_PCM_S32BE;
>>> +            }
>>
>> that mess begins to be duplicated in every demuxer, maybe
>> CODEC_ID_RAWAUDIO should be added, how to handle the BE/LE case ?
> 
> maybe CODEC_ID_PCM_BE / CODEC_ID_PCM_LE.  and actually use the
> SampleFormat in AVCodecContext, which would make it easy to implement
> floating-point PCM decoding.

CODEC_ID_LPCM_BE/LE, ok with that, any other opinion ?

>>> [...]
>>> +
>>> +    av_set_pts_info(st, 64, 1, st->codec->sample_rate);
>>> +    st->start_time = 0;
>>> +    st->duration = st->nb_frames;
>>
>> wrong, duration is in stream timebase according to demuxers and utils.c,
>> btw doxy is also wrong in avformat.h.
> 
> But 1/sample_rate is the stream timebase in this case, so 1 frame is
> equivalent to 1 timebase unit.

no, 1 frame is long as how many samples are in your frame, being said,
one ac3 frame contains 1536 samples at 48khz, duration of one frame is
1536/48000, and assuming you have 50 frames, you have 76800 samples, and
duration is 76800 / 48000, not 50 / 48000.

> [...]
> Index: libavformat/Makefile
> ===================================================================
> --- libavformat/Makefile	(revision 8622)
> +++ libavformat/Makefile	(working copy)
> @@ -28,6 +28,7 @@
>  OBJS-$(CONFIG_AVI_MUXER)                 += avienc.o riff.o
>  OBJS-$(CONFIG_AVISYNTH)                  += avisynth.o
>  OBJS-$(CONFIG_AVS_DEMUXER)               += avs.o vocdec.o voc.o riff.o
> +OBJS-$(CONFIG_CAFF_DEMUXER)              += caffdec.o caff.o riff.o

need isom.o also.

> [...]
> -    }
> -    return 0;
> +    return ff_mov_read_esds(c->fc, &sc->esds);
>  }

ff_mov_read_esds(c->fc, &sc->esds);
return 0;

maybe ff_mov_read_esds should only take ByteIOContext.

> [...]
>
> +static int caff_read_kuki(AVFormatContext *s, int64_t size)
> +{
> +    ByteIOContext *pb = &s->pb;
> +    CaffContext *ctx = s->priv_data;
> +
> +    if(size < 0)
> +        return -1;
> +
> +    if(ctx->avctx->codec_id == CODEC_ID_AAC) {
> +        /* The magic cookie format for AAC is an mp4 esds atom.
> +           The lavc aac decoder requires the data from the codec specific
> +           description as extradata input. */
> +        MOV_esds_t esds;
> +        int strt, skip;
> +
> +        strt = url_ftell(pb);
> +        ff_mov_read_esds(s, &esds);

IMHO size should be passed to read_esds and it will skip data.

> +        skip = size - (url_ftell(pb) - strt);
> +        if(skip < 0 || !ctx->avctx->extradata ||
> +                ctx->avctx->codec_id != CODEC_ID_AAC) {
> +            av_log(s, AV_LOG_ERROR, "invalid AAC magic cookie\n");
> +            return AVERROR_INVALIDDATA;
> +        }
> +        url_fskip(pb, skip);
> +    } else {
> +        /* read all kuki chunk data into extradata */
> +        ctx->avctx->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
> +        if(ctx->avctx->extradata) {
> +            get_buffer(pb, ctx->avctx->extradata, size);
> +            ctx->avctx->extradata_size = size;

add a check like in mov_read_extradata to avoid overflow.

if((uint64_t)size > (1<<30))
   return -1;

> [...]
> +        if(ctx->bytes_per_packet == 0) {
> +            ctx->packet_table[i].bytes = ff_mov_mp4_read_descr_len(pb);
> +        } else {
> +            ctx->packet_table[i].bytes = ctx->bytes_per_packet;
> +        }
> +        if(ctx->frames_per_packet == 0) {
> +            ctx->packet_table[i].frames = ff_mov_mp4_read_descr_len(pb);
> +        } else {
> +            ctx->packet_table[i].frames = ctx->frames_per_packet;
> +        }

maybe ternary or without { would be easier to read but that's up to you.

> [...]
> +
> +            default:
> +                av_log(s, AV_LOG_WARNING, "skipping CAFF chunk: %08X\n", tag);

DEBUG no ?

> [...]
> +static int caff_read_seek(AVFormatContext *s, int stream_index,
> +                          int64_t timestamp, int flags)
> +{
> +    CaffContext *ctx = s->priv_data;
> +    int64_t fpos=0, bpos=0;
> +
> +    fpos = FFMAX(0, ctx->frame_cnt + timestamp);

timestamp will be in stream timebase. Are you sure that this works ?

> +    if(ctx->frames_per_packet > 0 && ctx->bytes_per_packet > 0) {
> +        /* calculate new byte position based on target frame position */
> +        bpos = ctx->bytes_per_packet * fpos / ctx->frames_per_packet;
> +        bpos = FFMIN(bpos, ctx->data_size);
> +        ctx->packet_cnt = bpos / ctx->bytes_per_packet;
> +        ctx->frame_cnt = ctx->frames_per_packet * ctx->packet_cnt;
> +    } else if(ctx->has_packet_table) {
> +        /* scan through packet table for target frame position */
> +        int64_t p = ctx->packet_cnt;
> +        if(timestamp < 0) {
> +            while(ctx->packet_table[p].fpos > fpos && p > 0)
> +                p--;

Negative timestamp ?

> +        } else {
> +            while(ctx->packet_table[p].fpos < fpos && p < ctx->num_packets)
> +                p++;
> +            p = FFMAX(p-1, 0);
> +        }
> +        ctx->packet_cnt = p;
> +        ctx->frame_cnt = ctx->packet_table[p].fpos;
> +        bpos = ctx->packet_table[p].bpos;

maybe it is simpler to use AVIndex when parsing header ?

libavformat version bump is missing also.

[...]

-- 
Baptiste COUDURIER                              GnuPG Key Id: 0x5C1ABAAA
SMARTJOG S.A.                                    http://www.smartjog.com
Key fingerprint                 8D77134D20CC9220201FC5DB0AC9325C5C1ABAAA
Phone: +33 1 49966312




More information about the ffmpeg-devel mailing list