[Ffmpeg-devel] [PATCH] apple caff demuxer
Justin Ruggles
justinruggles
Wed Apr 4 17:18:02 CEST 2007
Baptiste Coudurier wrote:
> 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.
I think we're having a terminology mixup here. The CAFF specification
uses the term "frame" to refer to 1 sample over all channels. WAVE
calls this a block. The frame you're referring to is at the codec
level, and is called a "packet" by CAFF. Multiple CAFF packets can be
put in one AVPacket.
>
>>[...]
>>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.
I keep forgetting that one...
>
>>[...]
>>- }
>>- 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.
Does this look ok?
ff_mov_read_esds(ByteIOContext *pb, int size, MOV_esds_t *esds)
Then esds->decoder_cfg and esds->decoder_cfg_len would be used instead
of codec extradata and extradata_size.
>
>>+ 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;
Will do.
>
>>[...]
>>+ 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.
I actually did try this several ways, including the one Michael
suggested. I might go back to doing it that way.
>
>>[...]
>>+
>>+ default:
>>+ av_log(s, AV_LOG_WARNING, "skipping CAFF chunk: %08X\n", tag);
>
>
> DEBUG no ?
Well, for invalid chunks it should be a warning, but for unimplemented
chunks it could go either way. I figured that since skipping a valid
chunk may very well leave out an intended functionality (channel layout
for example), it wouldn't hurt to give a warning here as well. But I
have no strong feelings on this. If you want DEBUG I'll switch it.
>
>>[...]
>>+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 ?
See above discussion regarding timebase and frames vs. samples. I did
lots of seeking tests using ffplay.
>
>>+ 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 ?
Yes. Try adding a print statement and do some seeking in ffplay. :)
>
>>+ } 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 ?
I did consider that. But it's not necessarily simpler. I'll give it a
try though and let you decide which is better.
> libavformat version bump is missing also.
ok. Just so I'm clear about this, what are the criteria for a
libavformat version bump?
Thanks,
Justin
More information about the ffmpeg-devel
mailing list