# HG changeset patch # User nenolod # Date 1173737125 25200 # Node ID c294c470093721b0c0b2ede3cb72204041b19af1 # Parent 81749781b75fa8b8248a21115c9fbedb4db3149e [svn] - more stuff to kill diff -r 81749781b75f -r c294c4700937 ChangeLog --- a/ChangeLog Mon Mar 12 14:49:42 2007 -0700 +++ b/ChangeLog Mon Mar 12 15:05:25 2007 -0700 @@ -1,3 +1,21 @@ +2007-03-12 21:49:42 +0000 William Pitcock + revision [1754] + - remove some more stuff + + trunk/src/ffmpeg/Makefile | 8 + trunk/src/ffmpeg/libavformat/gxf.c | 516 ---------------- + trunk/src/ffmpeg/libavformat/gxf.h | 34 - + trunk/src/ffmpeg/libavformat/gxfenc.c | 819 -------------------------- + trunk/src/ffmpeg/libavformat/ogg.c | 283 -------- + trunk/src/ffmpeg/libavformat/ogg2.c | 697 ---------------------- + trunk/src/ffmpeg/libavformat/ogg2.h | 85 -- + trunk/src/ffmpeg/libavformat/oggparseflac.c | 82 -- + trunk/src/ffmpeg/libavformat/oggparseogm.c | 166 ----- + trunk/src/ffmpeg/libavformat/oggparsetheora.c | 129 ---- + trunk/src/ffmpeg/libavformat/oggparsevorbis.c | 205 ------ + 11 files changed, 3024 deletions(-) + + 2007-03-12 21:43:32 +0000 William Pitcock revision [1752] - start removing demuxers for video and images diff -r 81749781b75f -r c294c4700937 src/ffmpeg/Makefile --- a/src/ffmpeg/Makefile Mon Mar 12 14:49:42 2007 -0700 +++ b/src/ffmpeg/Makefile Mon Mar 12 15:05:25 2007 -0700 @@ -16,7 +16,6 @@ libavcodec/alac.c \ libavcodec/allcodecs.c \ libavcodec/audioconvert.c \ - libavcodec/avs.c \ libavcodec/bitstream.c \ libavcodec/bitstream_filter.c \ libavcodec/cabac.c \ @@ -76,11 +75,8 @@ libavformat/asf.c \ libavformat/au.c \ libavformat/audio.c \ - libavformat/avidec.c \ - libavformat/avienc.c \ libavformat/avio.c \ libavformat/aviobuf.c \ - libavformat/avs.c \ libavformat/barpainet.c \ libavformat/crc.c \ libavformat/cutils.c \ @@ -104,8 +100,6 @@ libavformat/matroska.c \ libavformat/mm.c \ libavformat/mmf.c \ - libavformat/mov.c \ - libavformat/movenc.c \ libavformat/mp3.c \ libavformat/mpeg.c \ libavformat/mpegts.c \ @@ -122,7 +116,6 @@ libavformat/raw.c \ libavformat/riff.c \ libavformat/rm.c \ - libavformat/rtpproto.c \ libavformat/segafilm.c \ libavformat/sgi.c \ libavformat/sierravmd.c \ @@ -133,7 +126,6 @@ libavformat/tta.c \ libavformat/utils.c \ libavformat/v4l2.c \ - libavformat/voc.c \ libavformat/wav.c \ libavformat/wc3movie.c \ libavformat/westwood.c \ diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/avidec.c --- a/src/ffmpeg/libavformat/avidec.c Mon Mar 12 14:49:42 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,984 +0,0 @@ -/* - * AVI decoder. - * Copyright (c) 2001 Fabrice Bellard. - * - * 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 "avformat.h" -#include "avi.h" -#include "dv.h" -#include "riff.h" - -#undef NDEBUG -#include - -//#define DEBUG -//#define DEBUG_SEEK - -typedef struct AVIStream { - int64_t frame_offset; /* current frame (video) or byte (audio) counter - (used to compute the pts) */ - int remaining; - int packet_size; - - int scale; - int rate; - int sample_size; /* size of one sample (or packet) (in the rate/scale sense) in bytes */ - - int64_t cum_len; /* temporary storage (used during seek) */ - - int prefix; ///< normally 'd'<<8 + 'c' or 'w'<<8 + 'b' - int prefix_count; -} AVIStream; - -typedef struct { - int64_t riff_end; - int64_t movi_end; - offset_t movi_list; - int index_loaded; - int is_odml; - int non_interleaved; - int stream_index; - DVDemuxContext* dv_demux; -} AVIContext; - -static int avi_load_index(AVFormatContext *s); -static int guess_ni_flag(AVFormatContext *s); - -#ifdef DEBUG -static void print_tag(const char *str, unsigned int tag, int size) -{ - printf("%s: tag=%c%c%c%c size=0x%x\n", - str, tag & 0xff, - (tag >> 8) & 0xff, - (tag >> 16) & 0xff, - (tag >> 24) & 0xff, - size); -} -#endif - -static int get_riff(AVIContext *avi, ByteIOContext *pb) -{ - uint32_t tag; - /* check RIFF header */ - tag = get_le32(pb); - - if (tag != MKTAG('R', 'I', 'F', 'F')) - return -1; - avi->riff_end = get_le32(pb); /* RIFF chunk size */ - avi->riff_end += url_ftell(pb); /* RIFF chunk end */ - tag = get_le32(pb); - if (tag != MKTAG('A', 'V', 'I', ' ') && tag != MKTAG('A', 'V', 'I', 'X')) - return -1; - - return 0; -} - -static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ - AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; - int longs_pre_entry= get_le16(pb); - int index_sub_type = get_byte(pb); - int index_type = get_byte(pb); - int entries_in_use = get_le32(pb); - int chunk_id = get_le32(pb); - int64_t base = get_le64(pb); - int stream_id= 10*((chunk_id&0xFF) - '0') + (((chunk_id>>8)&0xFF) - '0'); - AVStream *st; - AVIStream *ast; - int i; - int64_t last_pos= -1; - int64_t filesize= url_fsize(&s->pb); - -#ifdef DEBUG_SEEK - av_log(s, AV_LOG_ERROR, "longs_pre_entry:%d index_type:%d entries_in_use:%d chunk_id:%X base:%16LX\n", - longs_pre_entry,index_type, entries_in_use, chunk_id, base); -#endif - - if(stream_id > s->nb_streams || stream_id < 0) - return -1; - st= s->streams[stream_id]; - ast = st->priv_data; - - if(index_sub_type) - return -1; - - get_le32(pb); - - if(index_type && longs_pre_entry != 2) - return -1; - if(index_type>1) - return -1; - - if(filesize > 0 && base >= filesize){ - av_log(s, AV_LOG_ERROR, "ODML index invalid\n"); - if(base>>32 == (base & 0xFFFFFFFF) && (base & 0xFFFFFFFF) < filesize && filesize <= 0xFFFFFFFF) - base &= 0xFFFFFFFF; - else - return -1; - } - - for(i=0; i= 0; - len &= 0x7FFFFFFF; - -#ifdef DEBUG_SEEK - av_log(s, AV_LOG_ERROR, "pos:%Ld, len:%X\n", pos, len); -#endif - if(last_pos == pos || pos == base - 8) - avi->non_interleaved= 1; - else - av_add_index_entry(st, pos, ast->cum_len, len, 0, key ? AVINDEX_KEYFRAME : 0); - - if(ast->sample_size) - ast->cum_len += len / ast->sample_size; - else - ast->cum_len ++; - last_pos= pos; - }else{ - int64_t offset, pos; - int duration; - offset = get_le64(pb); - get_le32(pb); /* size */ - duration = get_le32(pb); - pos = url_ftell(pb); - - url_fseek(pb, offset+8, SEEK_SET); - read_braindead_odml_indx(s, frame_num); - frame_num += duration; - - url_fseek(pb, pos, SEEK_SET); - } - } - avi->index_loaded=1; - return 0; -} - -static void clean_index(AVFormatContext *s){ - int i; - int64_t j; - - for(i=0; inb_streams; i++){ - AVStream *st = s->streams[i]; - AVIStream *ast = st->priv_data; - int n= st->nb_index_entries; - int max= ast->sample_size; - int64_t pos, size, ts; - - if(n != 1 || ast->sample_size==0) - continue; - - while(max < 1024) max+=max; - - pos= st->index_entries[0].pos; - size= st->index_entries[0].size; - ts= st->index_entries[0].timestamp; - - for(j=0; jsample_size, FFMIN(max, size-j), 0, AVINDEX_KEYFRAME); - } - } -} - -static int avi_read_tag(ByteIOContext *pb, char *buf, int maxlen, unsigned int size) -{ - offset_t i = url_ftell(pb); - size += (size & 1); - get_strz(pb, buf, maxlen); - url_fseek(pb, i+size, SEEK_SET); - return 0; -} - -static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) -{ - AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; - uint32_t tag, tag1, handler; - int codec_type, stream_index, frame_period, bit_rate; - unsigned int size, nb_frames; - int i, n; - AVStream *st; - AVIStream *ast = NULL; - int xan_video = 0; /* hack to support Xan A/V */ - char str_track[4]; - - avi->stream_index= -1; - - if (get_riff(avi, pb) < 0) - return -1; - - /* first list tag */ - stream_index = -1; - codec_type = -1; - frame_period = 0; - for(;;) { - if (url_feof(pb)) - goto fail; - tag = get_le32(pb); - size = get_le32(pb); -#ifdef DEBUG - print_tag("tag", tag, size); -#endif - - switch(tag) { - case MKTAG('L', 'I', 'S', 'T'): - /* ignored, except when start of video packets */ - tag1 = get_le32(pb); -#ifdef DEBUG - print_tag("list", tag1, 0); -#endif - if (tag1 == MKTAG('m', 'o', 'v', 'i')) { - avi->movi_list = url_ftell(pb) - 4; - if(size) avi->movi_end = avi->movi_list + size + (size & 1); - else avi->movi_end = url_fsize(pb); -#ifdef DEBUG - printf("movi end=%Lx\n", avi->movi_end); -#endif - goto end_of_header; - } - break; - case MKTAG('d', 'm', 'l', 'h'): - avi->is_odml = 1; - url_fskip(pb, size + (size & 1)); - break; - case MKTAG('a', 'v', 'i', 'h'): - /* avi header */ - /* using frame_period is bad idea */ - frame_period = get_le32(pb); - bit_rate = get_le32(pb) * 8; - get_le32(pb); - avi->non_interleaved |= get_le32(pb) & AVIF_MUSTUSEINDEX; - - url_fskip(pb, 2 * 4); - n = get_le32(pb); - for(i=0;ipriv_data = ast; - } - url_fskip(pb, size - 7 * 4); - break; - case MKTAG('s', 't', 'r', 'h'): - /* stream header */ - stream_index++; - tag1 = get_le32(pb); - handler = get_le32(pb); /* codec tag */ -#ifdef DEBUG - print_tag("strh", tag1, -1); -#endif - if(tag1 == MKTAG('i', 'a', 'v', 's') || tag1 == MKTAG('i', 'v', 'a', 's')){ - /* - * After some consideration -- I don't think we - * have to support anything but DV in a type1 AVIs. - */ - if (s->nb_streams != 1) - goto fail; - - if (handler != MKTAG('d', 'v', 's', 'd') && - handler != MKTAG('d', 'v', 'h', 'd') && - handler != MKTAG('d', 'v', 's', 'l')) - goto fail; - - ast = s->streams[0]->priv_data; - av_freep(&s->streams[0]->codec->extradata); - av_freep(&s->streams[0]); - s->nb_streams = 0; - avi->dv_demux = dv_init_demux(s); - if (!avi->dv_demux) - goto fail; - s->streams[0]->priv_data = ast; - url_fskip(pb, 3 * 4); - ast->scale = get_le32(pb); - ast->rate = get_le32(pb); - stream_index = s->nb_streams - 1; - url_fskip(pb, size - 7*4); - break; - } - - if (stream_index >= s->nb_streams) { - url_fskip(pb, size - 8); - /* ignore padding stream */ - if (tag1 == MKTAG('p', 'a', 'd', 's')) - stream_index--; - break; - } - st = s->streams[stream_index]; - ast = st->priv_data; - st->codec->stream_codec_tag= handler; - - get_le32(pb); /* flags */ - get_le16(pb); /* priority */ - get_le16(pb); /* language */ - get_le32(pb); /* initial frame */ - ast->scale = get_le32(pb); - ast->rate = get_le32(pb); - if(ast->scale && ast->rate){ - }else if(frame_period){ - ast->rate = 1000000; - ast->scale = frame_period; - }else{ - ast->rate = 25; - ast->scale = 1; - } - av_set_pts_info(st, 64, ast->scale, ast->rate); - - ast->cum_len=get_le32(pb); /* start */ - nb_frames = get_le32(pb); - - st->start_time = 0; - st->duration = nb_frames; - get_le32(pb); /* buffer size */ - get_le32(pb); /* quality */ - ast->sample_size = get_le32(pb); /* sample ssize */ -// av_log(NULL, AV_LOG_DEBUG, "%d %d %d %d\n", ast->rate, ast->scale, ast->start, ast->sample_size); - - switch(tag1) { - case MKTAG('v', 'i', 'd', 's'): - codec_type = CODEC_TYPE_VIDEO; - - ast->sample_size = 0; - break; - case MKTAG('a', 'u', 'd', 's'): - codec_type = CODEC_TYPE_AUDIO; - break; - case MKTAG('t', 'x', 't', 's'): - //FIXME - codec_type = CODEC_TYPE_DATA; //CODEC_TYPE_SUB ? FIXME - break; - case MKTAG('p', 'a', 'd', 's'): - codec_type = CODEC_TYPE_UNKNOWN; - stream_index--; - break; - default: - av_log(s, AV_LOG_ERROR, "unknown stream type %X\n", tag1); - goto fail; - } - ast->frame_offset= ast->cum_len * FFMAX(ast->sample_size, 1); - url_fskip(pb, size - 12 * 4); - break; - case MKTAG('s', 't', 'r', 'f'): - /* stream header */ - if (stream_index >= s->nb_streams || avi->dv_demux) { - url_fskip(pb, size); - } else { - st = s->streams[stream_index]; - switch(codec_type) { - case CODEC_TYPE_VIDEO: - get_le32(pb); /* size */ - st->codec->width = get_le32(pb); - st->codec->height = get_le32(pb); - get_le16(pb); /* panes */ - st->codec->bits_per_sample= get_le16(pb); /* depth */ - tag1 = get_le32(pb); - get_le32(pb); /* ImageSize */ - get_le32(pb); /* XPelsPerMeter */ - get_le32(pb); /* YPelsPerMeter */ - get_le32(pb); /* ClrUsed */ - get_le32(pb); /* ClrImportant */ - - if(size > 10*4 && size<(1<<30)){ - st->codec->extradata_size= size - 10*4; - st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - get_buffer(pb, st->codec->extradata, st->codec->extradata_size); - } - - if(st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly - get_byte(pb); - - /* Extract palette from extradata if bpp <= 8 */ - /* This code assumes that extradata contains only palette */ - /* This is true for all paletted codecs implemented in ffmpeg */ - if (st->codec->extradata_size && (st->codec->bits_per_sample <= 8)) { - st->codec->palctrl = av_mallocz(sizeof(AVPaletteControl)); -#ifdef WORDS_BIGENDIAN - for (i = 0; i < FFMIN(st->codec->extradata_size, AVPALETTE_SIZE)/4; i++) - st->codec->palctrl->palette[i] = bswap_32(((uint32_t*)st->codec->extradata)[i]); -#else - memcpy(st->codec->palctrl->palette, st->codec->extradata, - FFMIN(st->codec->extradata_size, AVPALETTE_SIZE)); -#endif - st->codec->palctrl->palette_changed = 1; - } - -#ifdef DEBUG - print_tag("video", tag1, 0); -#endif - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_tag = tag1; - st->codec->codec_id = codec_get_id(codec_bmp_tags, tag1); - if (st->codec->codec_id == CODEC_ID_XAN_WC4) - xan_video = 1; - st->need_parsing = 2; //only parse headers dont do slower repacketization, this is needed to get the pict type which is needed for generating correct pts -// url_fskip(pb, size - 5 * 4); - break; - case CODEC_TYPE_AUDIO: - get_wav_header(pb, st->codec, size); - if(ast->sample_size && st->codec->block_align && ast->sample_size % st->codec->block_align) - av_log(s, AV_LOG_DEBUG, "invalid sample size or block align detected\n"); - if (size%2) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */ - url_fskip(pb, 1); - /* special case time: To support Xan DPCM, hardcode - * the format if Xxan is the video codec */ - st->need_parsing = 1; - /* force parsing as several audio frames can be in - one packet */ - if (xan_video) - st->codec->codec_id = CODEC_ID_XAN_DPCM; - break; - default: - st->codec->codec_type = CODEC_TYPE_DATA; - st->codec->codec_id= CODEC_ID_NONE; - st->codec->codec_tag= 0; - url_fskip(pb, size); - break; - } - } - break; - case MKTAG('i', 'n', 'd', 'x'): - i= url_ftell(pb); - if(!url_is_streamed(pb) && !(s->flags & AVFMT_FLAG_IGNIDX)){ - read_braindead_odml_indx(s, 0); - } - url_fseek(pb, i+size, SEEK_SET); - break; - case MKTAG('I', 'N', 'A', 'M'): - avi_read_tag(pb, s->title, sizeof(s->title), size); - break; - case MKTAG('I', 'A', 'R', 'T'): - avi_read_tag(pb, s->author, sizeof(s->author), size); - break; - case MKTAG('I', 'C', 'O', 'P'): - avi_read_tag(pb, s->copyright, sizeof(s->copyright), size); - break; - case MKTAG('I', 'C', 'M', 'T'): - avi_read_tag(pb, s->comment, sizeof(s->comment), size); - break; - case MKTAG('I', 'G', 'N', 'R'): - avi_read_tag(pb, s->genre, sizeof(s->genre), size); - break; - case MKTAG('I', 'P', 'R', 'D'): - avi_read_tag(pb, s->album, sizeof(s->album), size); - break; - case MKTAG('I', 'P', 'R', 'T'): - avi_read_tag(pb, str_track, sizeof(str_track), size); - sscanf(str_track, "%d", &s->track); - break; - default: - /* skip tag */ - size += (size & 1); - url_fskip(pb, size); - break; - } - } - end_of_header: - /* check stream number */ - if (stream_index != s->nb_streams - 1) { - fail: - for(i=0;inb_streams;i++) { - av_freep(&s->streams[i]->codec->extradata); - av_freep(&s->streams[i]); - } - return -1; - } - - if(!avi->index_loaded && !url_is_streamed(pb)) - avi_load_index(s); - avi->index_loaded = 1; - avi->non_interleaved |= guess_ni_flag(s); - if(avi->non_interleaved) - clean_index(s); - - return 0; -} - -static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; - int n, d[8], size; - offset_t i, sync; - void* dstr; - - if (avi->dv_demux) { - size = dv_get_packet(avi->dv_demux, pkt); - if (size >= 0) - return size; - } - - if(avi->non_interleaved){ - int best_stream_index = 0; - AVStream *best_st= NULL; - AVIStream *best_ast; - int64_t best_ts= INT64_MAX; - int i; - - for(i=0; inb_streams; i++){ - AVStream *st = s->streams[i]; - AVIStream *ast = st->priv_data; - int64_t ts= ast->frame_offset; - - if(ast->sample_size) - ts /= ast->sample_size; - ts= av_rescale(ts, AV_TIME_BASE * (int64_t)st->time_base.num, st->time_base.den); - -// av_log(NULL, AV_LOG_DEBUG, "%Ld %d/%d %Ld\n", ts, st->time_base.num, st->time_base.den, ast->frame_offset); - if(ts < best_ts){ - best_ts= ts; - best_st= st; - best_stream_index= i; - } - } - best_ast = best_st->priv_data; - best_ts= av_rescale(best_ts, best_st->time_base.den, AV_TIME_BASE * (int64_t)best_st->time_base.num); //FIXME a little ugly - if(best_ast->remaining) - i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD); - else - i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY); - -// av_log(NULL, AV_LOG_DEBUG, "%d\n", i); - if(i>=0){ - int64_t pos= best_st->index_entries[i].pos; - pos += best_ast->packet_size - best_ast->remaining; - url_fseek(&s->pb, pos + 8, SEEK_SET); -// av_log(NULL, AV_LOG_DEBUG, "pos=%Ld\n", pos); - - assert(best_ast->remaining <= best_ast->packet_size); - - avi->stream_index= best_stream_index; - if(!best_ast->remaining) - best_ast->packet_size= - best_ast->remaining= best_st->index_entries[i].size; - } - } - -resync: - if(avi->stream_index >= 0){ - AVStream *st= s->streams[ avi->stream_index ]; - AVIStream *ast= st->priv_data; - int size; - - if(ast->sample_size <= 1) // minorityreport.AVI block_align=1024 sample_size=1 IMA-ADPCM - size= INT_MAX; - else if(ast->sample_size < 32) - size= 64*ast->sample_size; - else - size= ast->sample_size; - - if(size > ast->remaining) - size= ast->remaining; - av_get_packet(pb, pkt, size); - - if (avi->dv_demux) { - dstr = pkt->destruct; - size = dv_produce_packet(avi->dv_demux, pkt, - pkt->data, pkt->size); - pkt->destruct = dstr; - pkt->flags |= PKT_FLAG_KEY; - } else { - /* XXX: how to handle B frames in avi ? */ - pkt->dts = ast->frame_offset; -// pkt->dts += ast->start; - if(ast->sample_size) - pkt->dts /= ast->sample_size; -//av_log(NULL, AV_LOG_DEBUG, "dts:%Ld offset:%Ld %d/%d smpl_siz:%d base:%d st:%d size:%d\n", pkt->dts, ast->frame_offset, ast->scale, ast->rate, ast->sample_size, AV_TIME_BASE, avi->stream_index, size); - pkt->stream_index = avi->stream_index; - - if (st->codec->codec_type == CODEC_TYPE_VIDEO) { - if(st->index_entries){ - AVIndexEntry *e; - int index; - - index= av_index_search_timestamp(st, pkt->dts, 0); - e= &st->index_entries[index]; - - if(index >= 0 && e->timestamp == ast->frame_offset){ - if (e->flags & AVINDEX_KEYFRAME) - pkt->flags |= PKT_FLAG_KEY; - } - } else { - /* if no index, better to say that all frames - are key frames */ - pkt->flags |= PKT_FLAG_KEY; - } - } else { - pkt->flags |= PKT_FLAG_KEY; - } - if(ast->sample_size) - ast->frame_offset += pkt->size; - else - ast->frame_offset++; - } - ast->remaining -= size; - if(!ast->remaining){ - avi->stream_index= -1; - ast->packet_size= 0; - if (size & 1) { - get_byte(pb); - size++; - } - } - - return size; - } - - memset(d, -1, sizeof(int)*8); - for(i=sync=url_ftell(pb); !url_feof(pb); i++) { - int j; - - if (i >= avi->movi_end) { - if (avi->is_odml) { - url_fskip(pb, avi->riff_end - i); - avi->riff_end = avi->movi_end = url_fsize(pb); - } else - break; - } - - for(j=0; j<7; j++) - d[j]= d[j+1]; - d[7]= get_byte(pb); - - size= d[4] + (d[5]<<8) + (d[6]<<16) + (d[7]<<24); - - if( d[2] >= '0' && d[2] <= '9' - && d[3] >= '0' && d[3] <= '9'){ - n= (d[2] - '0') * 10 + (d[3] - '0'); - }else{ - n= 100; //invalid stream id - } -//av_log(NULL, AV_LOG_DEBUG, "%X %X %X %X %X %X %X %X %lld %d %d\n", d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], i, size, n); - if(i + size > avi->movi_end || d[0]<0) - continue; - - //parse ix## - if( (d[0] == 'i' && d[1] == 'x' && n < s->nb_streams) - //parse JUNK - ||(d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K')){ - url_fskip(pb, size); -//av_log(NULL, AV_LOG_DEBUG, "SKIP\n"); - goto resync; - } - - if( d[0] >= '0' && d[0] <= '9' - && d[1] >= '0' && d[1] <= '9'){ - n= (d[0] - '0') * 10 + (d[1] - '0'); - }else{ - n= 100; //invalid stream id - } - - //parse ##dc/##wb - if(n < s->nb_streams){ - AVStream *st; - AVIStream *ast; - st = s->streams[n]; - ast = st->priv_data; - - if( (st->discard >= AVDISCARD_DEFAULT && size==0) - /*|| (st->discard >= AVDISCARD_NONKEY && !(pkt->flags & PKT_FLAG_KEY))*/ //FIXME needs a little reordering - || st->discard >= AVDISCARD_ALL){ - if(ast->sample_size) ast->frame_offset += pkt->size; - else ast->frame_offset++; - url_fskip(pb, size); - goto resync; - } - - if( ((ast->prefix_count<5 || sync+9 > i) && d[2]<128 && d[3]<128) || - d[2]*256+d[3] == ast->prefix /*|| - (d[2] == 'd' && d[3] == 'c') || - (d[2] == 'w' && d[3] == 'b')*/) { - -//av_log(NULL, AV_LOG_DEBUG, "OK\n"); - if(d[2]*256+d[3] == ast->prefix) - ast->prefix_count++; - else{ - ast->prefix= d[2]*256+d[3]; - ast->prefix_count= 0; - } - - avi->stream_index= n; - ast->packet_size= size + 8; - ast->remaining= size; - goto resync; - } - } - /* palette changed chunk */ - if ( d[0] >= '0' && d[0] <= '9' - && d[1] >= '0' && d[1] <= '9' - && ((d[2] == 'p' && d[3] == 'c')) - && n < s->nb_streams && i + size <= avi->movi_end) { - - AVStream *st; - int first, clr, flags, k, p; - - st = s->streams[n]; - - first = get_byte(pb); - clr = get_byte(pb); - if(!clr) /* all 256 colors used */ - clr = 256; - flags = get_le16(pb); - p = 4; - for (k = first; k < clr + first; k++) { - int r, g, b; - r = get_byte(pb); - g = get_byte(pb); - b = get_byte(pb); - get_byte(pb); - st->codec->palctrl->palette[k] = b + (g << 8) + (r << 16); - } - st->codec->palctrl->palette_changed = 1; - goto resync; - } - - } - - return -1; -} - -/* XXX: we make the implicit supposition that the position are sorted - for each stream */ -static int avi_read_idx1(AVFormatContext *s, int size) -{ - AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; - int nb_index_entries, i; - AVStream *st; - AVIStream *ast; - unsigned int index, tag, flags, pos, len; - unsigned last_pos= -1; - - nb_index_entries = size / 16; - if (nb_index_entries <= 0) - return -1; - - /* read the entries and sort them in each stream component */ - for(i = 0; i < nb_index_entries; i++) { - tag = get_le32(pb); - flags = get_le32(pb); - pos = get_le32(pb); - len = get_le32(pb); -#if defined(DEBUG_SEEK) - av_log(NULL, AV_LOG_DEBUG, "%d: tag=0x%x flags=0x%x pos=0x%x len=%d/", - i, tag, flags, pos, len); -#endif - if(i==0 && pos > avi->movi_list) - avi->movi_list= 0; //FIXME better check - pos += avi->movi_list; - - index = ((tag & 0xff) - '0') * 10; - index += ((tag >> 8) & 0xff) - '0'; - if (index >= s->nb_streams) - continue; - st = s->streams[index]; - ast = st->priv_data; - -#if defined(DEBUG_SEEK) - av_log(NULL, AV_LOG_DEBUG, "%d cum_len=%Ld\n", len, ast->cum_len); -#endif - if(last_pos == pos) - avi->non_interleaved= 1; - else - av_add_index_entry(st, pos, ast->cum_len, len, 0, (flags&AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0); - if(ast->sample_size) - ast->cum_len += len / ast->sample_size; - else - ast->cum_len ++; - last_pos= pos; - } - return 0; -} - -static int guess_ni_flag(AVFormatContext *s){ - int i; - int64_t last_start=0; - int64_t first_end= INT64_MAX; - - for(i=0; inb_streams; i++){ - AVStream *st = s->streams[i]; - int n= st->nb_index_entries; - - if(n <= 0) - continue; - - if(st->index_entries[0].pos > last_start) - last_start= st->index_entries[0].pos; - if(st->index_entries[n-1].pos < first_end) - first_end= st->index_entries[n-1].pos; - } - return last_start > first_end; -} - -static int avi_load_index(AVFormatContext *s) -{ - AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; - uint32_t tag, size; - offset_t pos= url_ftell(pb); - - url_fseek(pb, avi->movi_end, SEEK_SET); -#ifdef DEBUG_SEEK - printf("movi_end=0x%llx\n", avi->movi_end); -#endif - for(;;) { - if (url_feof(pb)) - break; - tag = get_le32(pb); - size = get_le32(pb); -#ifdef DEBUG_SEEK - printf("tag=%c%c%c%c size=0x%x\n", - tag & 0xff, - (tag >> 8) & 0xff, - (tag >> 16) & 0xff, - (tag >> 24) & 0xff, - size); -#endif - switch(tag) { - case MKTAG('i', 'd', 'x', '1'): - if (avi_read_idx1(s, size) < 0) - goto skip; - else - goto the_end; - break; - default: - skip: - size += (size & 1); - url_fskip(pb, size); - break; - } - } - the_end: - url_fseek(pb, pos, SEEK_SET); - return 0; -} - -static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) -{ - AVIContext *avi = s->priv_data; - AVStream *st; - int i, index; - int64_t pos; - - if (!avi->index_loaded) { - /* we only load the index on demand */ - avi_load_index(s); - avi->index_loaded = 1; - } - assert(stream_index>= 0); - - st = s->streams[stream_index]; - index= av_index_search_timestamp(st, timestamp, flags); - if(index<0) - return -1; - - /* find the position */ - pos = st->index_entries[index].pos; - timestamp = st->index_entries[index].timestamp; - -// av_log(NULL, AV_LOG_DEBUG, "XX %Ld %d %Ld\n", timestamp, index, st->index_entries[index].timestamp); - - for(i = 0; i < s->nb_streams; i++) { - AVStream *st2 = s->streams[i]; - AVIStream *ast2 = st2->priv_data; - - ast2->packet_size= - ast2->remaining= 0; - - if (st2->nb_index_entries <= 0) - continue; - -// assert(st2->codec->block_align); - assert(st2->time_base.den == ast2->rate); - assert(st2->time_base.num == ast2->scale); - index = av_index_search_timestamp( - st2, - av_rescale(timestamp, st2->time_base.den*(int64_t)st->time_base.num, st->time_base.den * (int64_t)st2->time_base.num), - flags | AVSEEK_FLAG_BACKWARD); - if(index<0) - index=0; - - if(!avi->non_interleaved){ - while(index>0 && st2->index_entries[index].pos > pos) - index--; - while(index+1 < st2->nb_index_entries && st2->index_entries[index].pos < pos) - index++; - } - -// av_log(NULL, AV_LOG_DEBUG, "%Ld %d %Ld\n", timestamp, index, st2->index_entries[index].timestamp); - /* extract the current frame number */ - ast2->frame_offset = st2->index_entries[index].timestamp; - if(ast2->sample_size) - ast2->frame_offset *=ast2->sample_size; - } - - if (avi->dv_demux) - dv_flush_audio_packets(avi->dv_demux); - /* do the seek */ - url_fseek(&s->pb, pos, SEEK_SET); - avi->stream_index= -1; - return 0; -} - -static int avi_read_close(AVFormatContext *s) -{ - int i; - AVIContext *avi = s->priv_data; - - for(i=0;inb_streams;i++) { - AVStream *st = s->streams[i]; - AVIStream *ast = st->priv_data; - av_free(ast); - av_free(st->codec->palctrl); - } - - if (avi->dv_demux) - av_free(avi->dv_demux); - - return 0; -} - -static int avi_probe(AVProbeData *p) -{ - /* check file header */ - if (p->buf_size <= 32) - return 0; - if (p->buf[0] == 'R' && p->buf[1] == 'I' && - p->buf[2] == 'F' && p->buf[3] == 'F' && - p->buf[8] == 'A' && p->buf[9] == 'V' && - p->buf[10] == 'I' && p->buf[11] == ' ') - return AVPROBE_SCORE_MAX; - else - return 0; -} - -AVInputFormat avi_demuxer = { - "avi", - "avi format", - sizeof(AVIContext), - avi_probe, - avi_read_header, - avi_read_packet, - avi_read_close, - avi_read_seek, -}; diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/avienc.c --- a/src/ffmpeg/libavformat/avienc.c Mon Mar 12 14:49:42 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,580 +0,0 @@ -/* - * AVI encoder. - * Copyright (c) 2000 Fabrice Bellard. - * - * 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 "avformat.h" -#include "avi.h" -#include "riff.h" - -/* - * TODO: - * - fill all fields if non streamed (nb_frames for example) - */ - -#ifdef CONFIG_AVI_MUXER -typedef struct AVIIentry { - unsigned int flags, pos, len; -} AVIIentry; - -#define AVI_INDEX_CLUSTER_SIZE 16384 - -typedef struct AVIIndex { - offset_t indx_start; - int entry; - int ents_allocated; - AVIIentry** cluster; -} AVIIndex; - -typedef struct { - offset_t riff_start, movi_list, odml_list; - offset_t frames_hdr_all, frames_hdr_strm[MAX_STREAMS]; - int audio_strm_length[MAX_STREAMS]; - int riff_id; - int packet_count[MAX_STREAMS]; - - AVIIndex indexes[MAX_STREAMS]; -} AVIContext; - -static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id) -{ - int cl = ent_id / AVI_INDEX_CLUSTER_SIZE; - int id = ent_id % AVI_INDEX_CLUSTER_SIZE; - return &idx->cluster[cl][id]; -} - -static offset_t avi_start_new_riff(AVIContext *avi, ByteIOContext *pb, - const char* riff_tag, const char* list_tag) -{ - offset_t loff; - int i; - - avi->riff_id++; - for (i=0; iindexes[i].entry = 0; - - avi->riff_start = start_tag(pb, "RIFF"); - put_tag(pb, riff_tag); - loff = start_tag(pb, "LIST"); - put_tag(pb, list_tag); - return loff; -} - -static char* avi_stream2fourcc(char* tag, int index, enum CodecType type) -{ - tag[0] = '0'; - tag[1] = '0' + index; - if (type == CODEC_TYPE_VIDEO) { - tag[2] = 'd'; - tag[3] = 'c'; - } else { - tag[2] = 'w'; - tag[3] = 'b'; - } - tag[4] = '\0'; - return tag; -} - -static void avi_write_info_tag(ByteIOContext *pb, const char *tag, const char *str) -{ - int len = strlen(str); - if (len > 0) { - len++; - put_tag(pb, tag); - put_le32(pb, len); - put_strz(pb, str); - if (len & 1) - put_byte(pb, 0); - } -} - -static int avi_write_counters(AVFormatContext* s, int riff_id) -{ - ByteIOContext *pb = &s->pb; - AVIContext *avi = s->priv_data; - int n, au_byterate, au_ssize, au_scale, nb_frames = 0; - offset_t file_size; - AVCodecContext* stream; - - file_size = url_ftell(pb); - for(n = 0; n < s->nb_streams; n++) { - assert(avi->frames_hdr_strm[n]); - stream = s->streams[n]->codec; - url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET); - ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); - if(au_ssize == 0) { - put_le32(pb, avi->packet_count[n]); - } else { - put_le32(pb, avi->audio_strm_length[n] / au_ssize); - } - if(stream->codec_type == CODEC_TYPE_VIDEO) - nb_frames = FFMAX(nb_frames, avi->packet_count[n]); - } - if(riff_id == 1) { - assert(avi->frames_hdr_all); - url_fseek(pb, avi->frames_hdr_all, SEEK_SET); - put_le32(pb, nb_frames); - } - url_fseek(pb, file_size, SEEK_SET); - - return 0; -} - -static int avi_write_header(AVFormatContext *s) -{ - AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; - int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; - AVCodecContext *stream, *video_enc; - offset_t list1, list2, strh, strf; - - /* header list */ - avi->riff_id = 0; - list1 = avi_start_new_riff(avi, pb, "AVI ", "hdrl"); - - /* avi header */ - put_tag(pb, "avih"); - put_le32(pb, 14 * 4); - bitrate = 0; - - video_enc = NULL; - for(n=0;nnb_streams;n++) { - stream = s->streams[n]->codec; - bitrate += stream->bit_rate; - if (stream->codec_type == CODEC_TYPE_VIDEO) - video_enc = stream; - } - - nb_frames = 0; - - if(video_enc){ - put_le32(pb, (uint32_t)(int64_t_C(1000000) * video_enc->time_base.num / video_enc->time_base.den)); - } else { - put_le32(pb, 0); - } - put_le32(pb, bitrate / 8); /* XXX: not quite exact */ - put_le32(pb, 0); /* padding */ - if (url_is_streamed(pb)) - put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ - else - put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ - avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */ - put_le32(pb, nb_frames); /* nb frames, filled later */ - put_le32(pb, 0); /* initial frame */ - put_le32(pb, s->nb_streams); /* nb streams */ - put_le32(pb, 1024 * 1024); /* suggested buffer size */ - if(video_enc){ - put_le32(pb, video_enc->width); - put_le32(pb, video_enc->height); - } else { - put_le32(pb, 0); - put_le32(pb, 0); - } - put_le32(pb, 0); /* reserved */ - put_le32(pb, 0); /* reserved */ - put_le32(pb, 0); /* reserved */ - put_le32(pb, 0); /* reserved */ - - /* stream list */ - for(i=0;istreams[i]->codec; - - /* FourCC should really be set by the codec itself */ - if (! stream->codec_tag) { - stream->codec_tag = codec_get_bmp_tag(stream->codec_id); - } - - /* stream generic header */ - strh = start_tag(pb, "strh"); - switch(stream->codec_type) { - case CODEC_TYPE_VIDEO: put_tag(pb, "vids"); break; - case CODEC_TYPE_AUDIO: put_tag(pb, "auds"); break; -// case CODEC_TYPE_TEXT : put_tag(pb, "txts"); break; - case CODEC_TYPE_DATA : put_tag(pb, "dats"); break; - } - if(stream->codec_type == CODEC_TYPE_VIDEO) - put_le32(pb, stream->codec_tag); - else - put_le32(pb, 1); - put_le32(pb, 0); /* flags */ - put_le16(pb, 0); /* priority */ - put_le16(pb, 0); /* language */ - put_le32(pb, 0); /* initial frame */ - - ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); - - put_le32(pb, au_scale); /* scale */ - put_le32(pb, au_byterate); /* rate */ - av_set_pts_info(s->streams[i], 64, au_scale, au_byterate); - - put_le32(pb, 0); /* start */ - avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ - if (url_is_streamed(pb)) - put_le32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ - else - put_le32(pb, 0); /* length, XXX: filled later */ - - /* suggested buffer size */ //FIXME set at the end to largest chunk - if(stream->codec_type == CODEC_TYPE_VIDEO) - put_le32(pb, 1024 * 1024); - else if(stream->codec_type == CODEC_TYPE_AUDIO) - put_le32(pb, 12 * 1024); - else - put_le32(pb, 0); - put_le32(pb, -1); /* quality */ - put_le32(pb, au_ssize); /* sample size */ - put_le32(pb, 0); - put_le16(pb, stream->width); - put_le16(pb, stream->height); - end_tag(pb, strh); - - if(stream->codec_type != CODEC_TYPE_DATA){ - strf = start_tag(pb, "strf"); - switch(stream->codec_type) { - case CODEC_TYPE_VIDEO: - put_bmp_header(pb, stream, codec_bmp_tags, 0); - break; - case CODEC_TYPE_AUDIO: - if (put_wav_header(pb, stream) < 0) { - av_free(avi); - return -1; - } - break; - default: - return -1; - } - end_tag(pb, strf); - } - - if (!url_is_streamed(pb)) { - unsigned char tag[5]; - int j; - - /* Starting to lay out AVI OpenDML master index. - * We want to make it JUNK entry for now, since we'd - * like to get away without making AVI an OpenDML one - * for compatibility reasons. - */ - avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0; - avi->indexes[i].indx_start = start_tag(pb, "JUNK"); - put_le16(pb, 4); /* wLongsPerEntry */ - put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ - put_byte(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ - put_le32(pb, 0); /* nEntriesInUse (will fill out later on) */ - put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type)); - /* dwChunkId */ - put_le64(pb, 0); /* dwReserved[3] - put_le32(pb, 0); Must be 0. */ - for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) - put_le64(pb, 0); - end_tag(pb, avi->indexes[i].indx_start); - } - - end_tag(pb, list2); - } - - if (!url_is_streamed(pb)) { - /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ - avi->odml_list = start_tag(pb, "JUNK"); - put_tag(pb, "odml"); - put_tag(pb, "dmlh"); - put_le32(pb, 248); - for (i = 0; i < 248; i+= 4) - put_le32(pb, 0); - end_tag(pb, avi->odml_list); - } - - end_tag(pb, list1); - - list2 = start_tag(pb, "LIST"); - put_tag(pb, "INFO"); - avi_write_info_tag(pb, "INAM", s->title); - avi_write_info_tag(pb, "IART", s->author); - avi_write_info_tag(pb, "ICOP", s->copyright); - avi_write_info_tag(pb, "ICMT", s->comment); - avi_write_info_tag(pb, "IPRD", s->album); - avi_write_info_tag(pb, "IGNR", s->genre); - if (s->track) { - char str_track[4]; - snprintf(str_track, 4, "%d", s->track); - avi_write_info_tag(pb, "IPRT", str_track); - } - if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) - avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); - end_tag(pb, list2); - - /* some padding for easier tag editing */ - list2 = start_tag(pb, "JUNK"); - for (i = 0; i < 1016; i += 4) - put_le32(pb, 0); - end_tag(pb, list2); - - avi->movi_list = start_tag(pb, "LIST"); - put_tag(pb, "movi"); - - put_flush_packet(pb); - - return 0; -} - -static int avi_write_ix(AVFormatContext *s) -{ - ByteIOContext *pb = &s->pb; - AVIContext *avi = s->priv_data; - char tag[5]; - char ix_tag[] = "ix00"; - int i, j; - - assert(!url_is_streamed(pb)); - - if (avi->riff_id > AVI_MASTER_INDEX_SIZE) - return -1; - - for (i=0;inb_streams;i++) { - offset_t ix, pos; - - avi_stream2fourcc(&tag[0], i, s->streams[i]->codec->codec_type); - ix_tag[3] = '0' + i; - - /* Writing AVI OpenDML leaf index chunk */ - ix = url_ftell(pb); - put_tag(pb, &ix_tag[0]); /* ix?? */ - put_le32(pb, avi->indexes[i].entry * 8 + 24); - /* chunk size */ - put_le16(pb, 2); /* wLongsPerEntry */ - put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ - put_byte(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ - put_le32(pb, avi->indexes[i].entry); - /* nEntriesInUse */ - put_tag(pb, &tag[0]); /* dwChunkId */ - put_le64(pb, avi->movi_list);/* qwBaseOffset */ - put_le32(pb, 0); /* dwReserved_3 (must be 0) */ - - for (j=0; jindexes[i].entry; j++) { - AVIIentry* ie = avi_get_ientry(&avi->indexes[i], j); - put_le32(pb, ie->pos + 8); - put_le32(pb, ((uint32_t)ie->len & ~0x80000000) | - (ie->flags & 0x10 ? 0 : 0x80000000)); - } - put_flush_packet(pb); - pos = url_ftell(pb); - - /* Updating one entry in the AVI OpenDML master index */ - url_fseek(pb, avi->indexes[i].indx_start - 8, SEEK_SET); - put_tag(pb, "indx"); /* enabling this entry */ - url_fskip(pb, 8); - put_le32(pb, avi->riff_id); /* nEntriesInUse */ - url_fskip(pb, 16*avi->riff_id); - put_le64(pb, ix); /* qwOffset */ - put_le32(pb, pos - ix); /* dwSize */ - put_le32(pb, avi->indexes[i].entry); /* dwDuration */ - - url_fseek(pb, pos, SEEK_SET); - } - return 0; -} - -static int avi_write_idx1(AVFormatContext *s) -{ - ByteIOContext *pb = &s->pb; - AVIContext *avi = s->priv_data; - offset_t idx_chunk; - int i; - char tag[5]; - - if (!url_is_streamed(pb)) { - AVIIentry* ie = 0, *tie; - int entry[MAX_STREAMS]; - int empty, stream_id = -1; - - idx_chunk = start_tag(pb, "idx1"); - memset(&entry[0], 0, sizeof(entry)); - do { - empty = 1; - for (i=0; inb_streams; i++) { - if (avi->indexes[i].entry <= entry[i]) - continue; - - tie = avi_get_ientry(&avi->indexes[i], entry[i]); - if (empty || tie->pos < ie->pos) { - ie = tie; - stream_id = i; - } - empty = 0; - } - if (!empty) { - avi_stream2fourcc(&tag[0], stream_id, - s->streams[stream_id]->codec->codec_type); - put_tag(pb, &tag[0]); - put_le32(pb, ie->flags); - put_le32(pb, ie->pos); - put_le32(pb, ie->len); - entry[stream_id]++; - } - } while (!empty); - end_tag(pb, idx_chunk); - - avi_write_counters(s, avi->riff_id); - } - return 0; -} - -static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; - unsigned char tag[5]; - unsigned int flags=0; - const int stream_index= pkt->stream_index; - AVCodecContext *enc= s->streams[stream_index]->codec; - int size= pkt->size; - -// av_log(s, AV_LOG_DEBUG, "%lld %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index); - while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avi->packet_count[stream_index]){ - AVPacket empty_packet; - - av_init_packet(&empty_packet); - empty_packet.size= 0; - empty_packet.data= NULL; - empty_packet.stream_index= stream_index; - avi_write_packet(s, &empty_packet); -// av_log(s, AV_LOG_DEBUG, "dup %lld %d\n", pkt->dts, avi->packet_count[stream_index]); - } - avi->packet_count[stream_index]++; - - // Make sure to put an OpenDML chunk when the file size exceeds the limits - if (!url_is_streamed(pb) && - (url_ftell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { - - avi_write_ix(s); - end_tag(pb, avi->movi_list); - - if (avi->riff_id == 1) - avi_write_idx1(s); - - end_tag(pb, avi->riff_start); - avi->movi_list = avi_start_new_riff(avi, pb, "AVIX", "movi"); - } - - avi_stream2fourcc(&tag[0], stream_index, enc->codec_type); - if(pkt->flags&PKT_FLAG_KEY) - flags = 0x10; - if (enc->codec_type == CODEC_TYPE_AUDIO) { - avi->audio_strm_length[stream_index] += size; - } - - if (!url_is_streamed(&s->pb)) { - AVIIndex* idx = &avi->indexes[stream_index]; - int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; - int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; - if (idx->ents_allocated <= idx->entry) { - idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); - if (!idx->cluster) - return -1; - idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); - if (!idx->cluster[cl]) - return -1; - idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; - } - - idx->cluster[cl][id].flags = flags; - idx->cluster[cl][id].pos = url_ftell(pb) - avi->movi_list; - idx->cluster[cl][id].len = size; - idx->entry++; - } - - put_buffer(pb, tag, 4); - put_le32(pb, size); - put_buffer(pb, pkt->data, size); - if (size & 1) - put_byte(pb, 0); - - put_flush_packet(pb); - return 0; -} - -static int avi_write_trailer(AVFormatContext *s) -{ - AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; - int res = 0; - int i, j, n, nb_frames; - offset_t file_size; - - if (!url_is_streamed(pb)) - { - if (avi->riff_id == 1) { - end_tag(pb, avi->movi_list); - res = avi_write_idx1(s); - end_tag(pb, avi->riff_start); - } else { - avi_write_ix(s); - end_tag(pb, avi->movi_list); - end_tag(pb, avi->riff_start); - - file_size = url_ftell(pb); - url_fseek(pb, avi->odml_list - 8, SEEK_SET); - put_tag(pb, "LIST"); /* Making this AVI OpenDML one */ - url_fskip(pb, 16); - - for (n=nb_frames=0;nnb_streams;n++) { - AVCodecContext *stream = s->streams[n]->codec; - if (stream->codec_type == CODEC_TYPE_VIDEO) { - if (nb_frames < avi->packet_count[n]) - nb_frames = avi->packet_count[n]; - } else { - if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3) { - nb_frames += avi->packet_count[n]; - } - } - } - put_le32(pb, nb_frames); - url_fseek(pb, file_size, SEEK_SET); - - avi_write_counters(s, avi->riff_id); - } - } - put_flush_packet(pb); - - for (i=0; iindexes[i].ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) - av_free(avi->indexes[i].cluster[j]); - av_free(avi->indexes[i].cluster); - avi->indexes[i].cluster = NULL; - avi->indexes[i].ents_allocated = avi->indexes[i].entry = 0; - } - - return res; -} - -AVOutputFormat avi_muxer = { - "avi", - "avi format", - "video/x-msvideo", - "avi", - sizeof(AVIContext), - CODEC_ID_MP2, - CODEC_ID_MPEG4, - avi_write_header, - avi_write_packet, - avi_write_trailer, -}; -#endif //CONFIG_AVI_MUXER diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/aviobuf.c --- a/src/ffmpeg/libavformat/aviobuf.c Mon Mar 12 14:49:42 2007 -0700 +++ b/src/ffmpeg/libavformat/aviobuf.c Mon Mar 12 15:05:25 2007 -0700 @@ -172,6 +172,25 @@ return size1 - size; } +int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size) +{ + int len; + + if(size<0) + return -1; + + len = s->buf_end - s->buf_ptr; + if (len == 0) { + fill_buffer(s); + len = s->buf_end - s->buf_ptr; + } + if (len > size) + len = size; + memcpy(buf, s->buf_ptr, len); + s->buf_ptr += len; + return len; +} + unsigned int get_le16(ByteIOContext *s) { unsigned int val; @@ -180,6 +199,14 @@ return val; } +unsigned int get_le24(ByteIOContext *s) +{ + unsigned int val; + val = get_le16(s); + val |= get_byte(s) << 16; + return val; +} + unsigned int get_le32(ByteIOContext *s) { unsigned int val; @@ -206,6 +233,14 @@ return val; } +unsigned int get_be24(ByteIOContext *s) +{ + unsigned int val; + val = get_be16(s) << 8; + val |= get_byte(s); + return val; +} + unsigned int get_be32(ByteIOContext *s) { unsigned int val; @@ -406,3 +441,99 @@ return size; } +static void flush_buffer(ByteIOContext *s) +{ + if (s->buf_ptr > s->buffer) { + if (s->write_packet){ + s->write_packet(s->opaque, s->buffer, s->buf_ptr - s->buffer); + } + s->pos += s->buf_ptr - s->buffer; + } + s->buf_ptr = s->buffer; +} + +void put_byte(ByteIOContext *s, int b) +{ + *(s->buf_ptr)++ = b; + if (s->buf_ptr >= s->buf_end) + flush_buffer(s); +} + +void put_buffer(ByteIOContext *s, const unsigned char *buf, int size) +{ + int len; + + while (size > 0) { + len = (s->buf_end - s->buf_ptr); + if (len > size) + len = size; + memcpy(s->buf_ptr, buf, len); + s->buf_ptr += len; + + if (s->buf_ptr >= s->buf_end) + flush_buffer(s); + + buf += len; + size -= len; + } +} + +void put_be32(ByteIOContext *s, unsigned int val) +{ + put_byte(s, val >> 24); + put_byte(s, val >> 16); + put_byte(s, val >> 8); + put_byte(s, val); +} + +void put_strz(ByteIOContext *s, const char *str) +{ + if (str) + put_buffer(s, (const unsigned char *) str, strlen(str) + 1); + else + put_byte(s, 0); +} + +void put_le64(ByteIOContext *s, uint64_t val) +{ + put_le32(s, (uint32_t)(val & 0xffffffff)); + put_le32(s, (uint32_t)(val >> 32)); +} + +void put_be64(ByteIOContext *s, uint64_t val) +{ + put_be32(s, (uint32_t)(val >> 32)); + put_be32(s, (uint32_t)(val & 0xffffffff)); +} + +void put_le16(ByteIOContext *s, unsigned int val) +{ + put_byte(s, val); + put_byte(s, val >> 8); +} + +void put_be16(ByteIOContext *s, unsigned int val) +{ + put_byte(s, val >> 8); + put_byte(s, val); +} + +void put_le24(ByteIOContext *s, unsigned int val) +{ + put_le16(s, val & 0xffff); + put_byte(s, val >> 16); +} + +void put_be24(ByteIOContext *s, unsigned int val) +{ + put_be16(s, val >> 8); + put_byte(s, val); +} + +void put_tag(ByteIOContext *s, const char *tag) +{ + while (*tag) { + put_byte(s, *tag++); + } +} + diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/avs.c --- a/src/ffmpeg/libavformat/avs.c Mon Mar 12 14:49:42 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -/* - * AVS demuxer. - * Copyright (c) 2006 Aurelien Jacobs - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "avformat.h" -#include "voc.h" - - -typedef struct avs_format { - voc_dec_context_t voc; - AVStream *st_video; - AVStream *st_audio; - int width; - int height; - int bits_per_sample; - int fps; - int nb_frames; - int remaining_frame_size; - int remaining_audio_size; -} avs_format_t; - -typedef enum avs_block_type { - AVS_VIDEO = 0x01, - AVS_AUDIO = 0x02, - AVS_PALETTE = 0x03, - AVS_GAME_DATA = 0x04, -} avs_block_type_t; - -static int avs_probe(AVProbeData * p) -{ - const uint8_t *d; - - if (p->buf_size < 2) - return 0; - d = p->buf; - if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0) - return 50; - - return 0; -} - -static int avs_read_header(AVFormatContext * s, AVFormatParameters * ap) -{ - avs_format_t *avs = s->priv_data; - - s->ctx_flags |= AVFMTCTX_NOHEADER; - - url_fskip(&s->pb, 4); - avs->width = get_le16(&s->pb); - avs->height = get_le16(&s->pb); - avs->bits_per_sample = get_le16(&s->pb); - avs->fps = get_le16(&s->pb); - avs->nb_frames = get_le32(&s->pb); - avs->remaining_frame_size = 0; - avs->remaining_audio_size = 0; - - avs->st_video = avs->st_audio = NULL; - - if (avs->width != 318 || avs->height != 198) - av_log(s, AV_LOG_ERROR, "This avs pretend to be %dx%d " - "when the avs format is supposed to be 318x198 only.\n", - avs->width, avs->height); - - return 0; -} - -static int -avs_read_video_packet(AVFormatContext * s, AVPacket * pkt, - avs_block_type_t type, int sub_type, int size, - uint8_t * palette, int palette_size) -{ - avs_format_t *avs = s->priv_data; - int ret; - - ret = av_new_packet(pkt, size + palette_size); - if (ret < 0) - return ret; - - if (palette_size) { - pkt->data[0] = 0x00; - pkt->data[1] = 0x03; - pkt->data[2] = palette_size & 0xFF; - pkt->data[3] = (palette_size >> 8) & 0xFF; - memcpy(pkt->data + 4, palette, palette_size - 4); - } - - pkt->data[palette_size + 0] = sub_type; - pkt->data[palette_size + 1] = type; - pkt->data[palette_size + 2] = size & 0xFF; - pkt->data[palette_size + 3] = (size >> 8) & 0xFF; - ret = get_buffer(&s->pb, pkt->data + palette_size + 4, size - 4) + 4; - if (ret < size) { - av_free_packet(pkt); - return AVERROR_IO; - } - - pkt->size = ret + palette_size; - pkt->stream_index = avs->st_video->index; - if (sub_type == 0) - pkt->flags |= PKT_FLAG_KEY; - - return 0; -} - -static int avs_read_audio_packet(AVFormatContext * s, AVPacket * pkt) -{ - avs_format_t *avs = s->priv_data; - int ret, size; - - size = url_ftell(&s->pb); - ret = voc_get_packet(s, pkt, avs->st_audio, avs->remaining_audio_size); - size = url_ftell(&s->pb) - size; - avs->remaining_audio_size -= size; - - if (ret == AVERROR_IO) - return 0; /* this indicate EOS */ - if (ret < 0) - return ret; - - pkt->stream_index = avs->st_audio->index; - pkt->flags |= PKT_FLAG_KEY; - - return size; -} - -static int avs_read_packet(AVFormatContext * s, AVPacket * pkt) -{ - avs_format_t *avs = s->priv_data; - int sub_type = 0, size = 0; - avs_block_type_t type = 0; - int palette_size = 0; - uint8_t palette[4 + 3 * 256]; - int ret; - - if (avs->remaining_audio_size > 0) - if (avs_read_audio_packet(s, pkt) > 0) - return 0; - - while (1) { - if (avs->remaining_frame_size <= 0) { - if (!get_le16(&s->pb)) /* found EOF */ - return AVERROR_IO; - avs->remaining_frame_size = get_le16(&s->pb) - 4; - } - - while (avs->remaining_frame_size > 0) { - sub_type = get_byte(&s->pb); - type = get_byte(&s->pb); - size = get_le16(&s->pb); - avs->remaining_frame_size -= size; - - switch (type) { - case AVS_PALETTE: - ret = get_buffer(&s->pb, palette, size - 4); - if (ret < size - 4) - return AVERROR_IO; - palette_size = size; - break; - - case AVS_VIDEO: - if (!avs->st_video) { - avs->st_video = av_new_stream(s, AVS_VIDEO); - if (avs->st_video == NULL) - return AVERROR_NOMEM; - avs->st_video->codec->codec_type = CODEC_TYPE_VIDEO; - avs->st_video->codec->codec_id = CODEC_ID_AVS; - avs->st_video->codec->width = avs->width; - avs->st_video->codec->height = avs->height; - avs->st_video->codec->bits_per_sample=avs->bits_per_sample; - avs->st_video->nb_frames = avs->nb_frames; - avs->st_video->codec->time_base = (AVRational) { - 1, avs->fps}; - } - return avs_read_video_packet(s, pkt, type, sub_type, size, - palette, palette_size); - - case AVS_AUDIO: - if (!avs->st_audio) { - avs->st_audio = av_new_stream(s, AVS_AUDIO); - if (avs->st_audio == NULL) - return AVERROR_NOMEM; - avs->st_audio->codec->codec_type = CODEC_TYPE_AUDIO; - } - avs->remaining_audio_size = size - 4; - size = avs_read_audio_packet(s, pkt); - if (size != 0) - return size; - break; - - default: - url_fskip(&s->pb, size - 4); - } - } - } -} - -static int avs_read_close(AVFormatContext * s) -{ - return 0; -} - -AVInputFormat avs_demuxer = { - "avs", - "avs format", - sizeof(avs_format_t), - avs_probe, - avs_read_header, - avs_read_packet, - avs_read_close, -}; diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/dv.c --- a/src/ffmpeg/libavformat/dv.c Mon Mar 12 14:49:42 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,451 +0,0 @@ -/* - * General DV muxer/demuxer - * Copyright (c) 2003 Roman Shaposhnik - * - * Many thanks to Dan Dennedy for providing wealth - * of DV technical info. - * - * Raw DV format - * Copyright (c) 2002 Fabrice Bellard. - * - * 50 Mbps (DVCPRO50) support - * Copyright (c) 2006 Daniel Maas - * - * 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 -#include "avformat.h" -#include "dvdata.h" -#include "dv.h" - -struct DVDemuxContext { - const DVprofile* sys; /* Current DV profile. E.g.: 525/60, 625/50 */ - AVFormatContext* fctx; - AVStream* vst; - AVStream* ast[2]; - AVPacket audio_pkt[2]; - uint8_t audio_buf[2][8192]; - int ach; - int frames; - uint64_t abytes; -}; - -static inline uint16_t dv_audio_12to16(uint16_t sample) -{ - uint16_t shift, result; - - sample = (sample < 0x800) ? sample : sample | 0xf000; - shift = (sample & 0xf00) >> 8; - - if (shift < 0x2 || shift > 0xd) { - result = sample; - } else if (shift < 0x8) { - shift--; - result = (sample - (256 * shift)) << shift; - } else { - shift = 0xe - shift; - result = ((sample + ((256 * shift) + 1)) << shift) - 1; - } - - return result; -} - -/* - * This is the dumbest implementation of all -- it simply looks at - * a fixed offset and if pack isn't there -- fails. We might want - * to have a fallback mechanism for complete search of missing packs. - */ -static const uint8_t* dv_extract_pack(uint8_t* frame, enum dv_pack_type t) -{ - int offs; - - switch (t) { - case dv_audio_source: - offs = (80*6 + 80*16*3 + 3); - break; - case dv_audio_control: - offs = (80*6 + 80*16*4 + 3); - break; - case dv_video_control: - offs = (80*5 + 48 + 5); - break; - default: - return NULL; - } - - return (frame[offs] == t ? &frame[offs] : NULL); -} - -/* - * There's a couple of assumptions being made here: - * 1. By default we silence erroneous (0x8000/16bit 0x800/12bit) audio samples. - * We can pass them upwards when ffmpeg will be ready to deal with them. - * 2. We don't do software emphasis. - * 3. Audio is always returned as 16bit linear samples: 12bit nonlinear samples - * are converted into 16bit linear ones. - */ -static int dv_extract_audio(uint8_t* frame, uint8_t* pcm, uint8_t* pcm2, - const DVprofile *sys) -{ - int size, chan, i, j, d, of, smpls, freq, quant, half_ch; - uint16_t lc, rc; - const uint8_t* as_pack; - - as_pack = dv_extract_pack(frame, dv_audio_source); - if (!as_pack) /* No audio ? */ - return 0; - - smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */ - freq = (as_pack[4] >> 3) & 0x07; /* 0 - 48KHz, 1 - 44,1kHz, 2 - 32 kHz */ - quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */ - - if (quant > 1) - return -1; /* Unsupported quantization */ - - size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */ - half_ch = sys->difseg_size/2; - - /* for each DIF channel */ - for (chan = 0; chan < sys->n_difchan; chan++) { - /* for each DIF segment */ - for (i = 0; i < sys->difseg_size; i++) { - frame += 6 * 80; /* skip DIF segment header */ - if (quant == 1 && i == half_ch) { - /* next stereo channel (12bit mode only) */ - if (!pcm2) - break; - else - pcm = pcm2; - } - - /* for each AV sequence */ - for (j = 0; j < 9; j++) { - for (d = 8; d < 80; d += 2) { - if (quant == 0) { /* 16bit quantization */ - of = sys->audio_shuffle[i][j] + (d - 8)/2 * sys->audio_stride; - if (of*2 >= size) - continue; - - pcm[of*2] = frame[d+1]; // FIXME: may be we have to admit - pcm[of*2+1] = frame[d]; // that DV is a big endian PCM - if (pcm[of*2+1] == 0x80 && pcm[of*2] == 0x00) - pcm[of*2+1] = 0; - } else { /* 12bit quantization */ - lc = ((uint16_t)frame[d] << 4) | - ((uint16_t)frame[d+2] >> 4); - rc = ((uint16_t)frame[d+1] << 4) | - ((uint16_t)frame[d+2] & 0x0f); - lc = (lc == 0x800 ? 0 : dv_audio_12to16(lc)); - rc = (rc == 0x800 ? 0 : dv_audio_12to16(rc)); - - of = sys->audio_shuffle[i%half_ch][j] + (d - 8)/3 * sys->audio_stride; - if (of*2 >= size) - continue; - - pcm[of*2] = lc & 0xff; // FIXME: may be we have to admit - pcm[of*2+1] = lc >> 8; // that DV is a big endian PCM - of = sys->audio_shuffle[i%half_ch+half_ch][j] + - (d - 8)/3 * sys->audio_stride; - pcm[of*2] = rc & 0xff; // FIXME: may be we have to admit - pcm[of*2+1] = rc >> 8; // that DV is a big endian PCM - ++d; - } - } - - frame += 16 * 80; /* 15 Video DIFs + 1 Audio DIF */ - } - } - - /* next stereo channel (50Mbps only) */ - if(!pcm2) - break; - pcm = pcm2; - } - - return size; -} - -static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame) -{ - const uint8_t* as_pack; - int freq, stype, smpls, quant, i, ach; - - as_pack = dv_extract_pack(frame, dv_audio_source); - if (!as_pack || !c->sys) { /* No audio ? */ - c->ach = 0; - return 0; - } - - smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */ - freq = (as_pack[4] >> 3) & 0x07; /* 0 - 48KHz, 1 - 44,1kHz, 2 - 32 kHz */ - stype = (as_pack[3] & 0x1f); /* 0 - 2CH, 2 - 4CH */ - quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */ - - /* note: ach counts PAIRS of channels (i.e. stereo channels) */ - ach = (stype == 2 || (quant && (freq == 2))) ? 2 : 1; - - /* Dynamic handling of the audio streams in DV */ - for (i=0; iast[i]) { - c->ast[i] = av_new_stream(c->fctx, 0); - if (!c->ast[i]) - break; - av_set_pts_info(c->ast[i], 64, 1, 30000); - c->ast[i]->codec->codec_type = CODEC_TYPE_AUDIO; - c->ast[i]->codec->codec_id = CODEC_ID_PCM_S16LE; - - av_init_packet(&c->audio_pkt[i]); - c->audio_pkt[i].size = 0; - c->audio_pkt[i].data = c->audio_buf[i]; - c->audio_pkt[i].stream_index = c->ast[i]->index; - c->audio_pkt[i].flags |= PKT_FLAG_KEY; - } - c->ast[i]->codec->sample_rate = dv_audio_frequency[freq]; - c->ast[i]->codec->channels = 2; - c->ast[i]->codec->bit_rate = 2 * dv_audio_frequency[freq] * 16; - c->ast[i]->start_time = 0; - } - c->ach = i; - - return (c->sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */; -} - -static int dv_extract_video_info(DVDemuxContext *c, uint8_t* frame) -{ - const uint8_t* vsc_pack; - AVCodecContext* avctx; - int apt, is16_9; - int size = 0; - - if (c->sys) { - avctx = c->vst->codec; - - av_set_pts_info(c->vst, 64, c->sys->frame_rate_base, c->sys->frame_rate); - avctx->time_base= (AVRational){c->sys->frame_rate_base, c->sys->frame_rate}; - if(!avctx->width){ - avctx->width = c->sys->width; - avctx->height = c->sys->height; - } - avctx->pix_fmt = c->sys->pix_fmt; - - /* finding out SAR is a little bit messy */ - vsc_pack = dv_extract_pack(frame, dv_video_control); - apt = frame[4] & 0x07; - is16_9 = (vsc_pack && ((vsc_pack[2] & 0x07) == 0x02 || - (!apt && (vsc_pack[2] & 0x07) == 0x07))); - avctx->sample_aspect_ratio = c->sys->sar[is16_9]; - avctx->bit_rate = av_rescale(c->sys->frame_size * 8, - c->sys->frame_rate, - c->sys->frame_rate_base); - size = c->sys->frame_size; - } - return size; -} - -/* - * The following 3 functions constitute our interface to the world - */ - -DVDemuxContext* dv_init_demux(AVFormatContext *s) -{ - DVDemuxContext *c; - - c = av_mallocz(sizeof(DVDemuxContext)); - if (!c) - return NULL; - - c->vst = av_new_stream(s, 0); - if (!c->vst) { - av_free(c); - return NULL; - } - - c->sys = NULL; - c->fctx = s; - c->ast[0] = c->ast[1] = NULL; - c->ach = 0; - c->frames = 0; - c->abytes = 0; - - c->vst->codec->codec_type = CODEC_TYPE_VIDEO; - c->vst->codec->codec_id = CODEC_ID_DVVIDEO; - c->vst->codec->bit_rate = 25000000; - c->vst->start_time = 0; - - return c; -} - -int dv_get_packet(DVDemuxContext *c, AVPacket *pkt) -{ - int size = -1; - int i; - - for (i=0; iach; i++) { - if (c->ast[i] && c->audio_pkt[i].size) { - *pkt = c->audio_pkt[i]; - c->audio_pkt[i].size = 0; - size = pkt->size; - break; - } - } - - return size; -} - -int dv_produce_packet(DVDemuxContext *c, AVPacket *pkt, - uint8_t* buf, int buf_size) -{ - int size, i; - - if (buf_size < DV_PROFILE_BYTES || - !(c->sys = dv_frame_profile(buf)) || - buf_size < c->sys->frame_size) { - return -1; /* Broken frame, or not enough data */ - } - - /* Queueing audio packet */ - /* FIXME: in case of no audio/bad audio we have to do something */ - size = dv_extract_audio_info(c, buf); - for (i=0; iach; i++) { - c->audio_pkt[i].size = size; - c->audio_pkt[i].pts = c->abytes * 30000*8 / c->ast[i]->codec->bit_rate; - } - dv_extract_audio(buf, c->audio_buf[0], c->audio_buf[1], c->sys); - c->abytes += size; - - /* Now it's time to return video packet */ - size = dv_extract_video_info(c, buf); - av_init_packet(pkt); - pkt->data = buf; - pkt->size = size; - pkt->flags |= PKT_FLAG_KEY; - pkt->stream_index = c->vst->id; - pkt->pts = c->frames; - - c->frames++; - - return size; -} - -static int64_t dv_frame_offset(AVFormatContext *s, DVDemuxContext *c, - int64_t timestamp, int flags) -{ - // FIXME: sys may be wrong if last dv_read_packet() failed (buffer is junk) - const DVprofile* sys = dv_codec_profile(c->vst->codec); - int64_t offset; - int64_t size = url_fsize(&s->pb); - int64_t max_offset = ((size-1) / sys->frame_size) * sys->frame_size; - - offset = sys->frame_size * timestamp; - - if (offset > max_offset) offset = max_offset; - else if (offset < 0) offset = 0; - - return offset; -} - -void dv_flush_audio_packets(DVDemuxContext *c) -{ - c->audio_pkt[0].size = c->audio_pkt[1].size = 0; -} - -/************************************************************ - * Implementation of the easiest DV storage of all -- raw DV. - ************************************************************/ - -typedef struct RawDVContext { - DVDemuxContext* dv_demux; - uint8_t buf[DV_MAX_FRAME_SIZE]; -} RawDVContext; - -static int dv_read_header(AVFormatContext *s, - AVFormatParameters *ap) -{ - RawDVContext *c = s->priv_data; - - c->dv_demux = dv_init_demux(s); - if (!c->dv_demux) - return -1; - - if (get_buffer(&s->pb, c->buf, DV_PROFILE_BYTES) <= 0 || - url_fseek(&s->pb, -DV_PROFILE_BYTES, SEEK_CUR) < 0) - return AVERROR_IO; - - c->dv_demux->sys = dv_frame_profile(c->buf); - s->bit_rate = av_rescale(c->dv_demux->sys->frame_size * 8, - c->dv_demux->sys->frame_rate, - c->dv_demux->sys->frame_rate_base); - - return 0; -} - - -static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - int size; - RawDVContext *c = s->priv_data; - - size = dv_get_packet(c->dv_demux, pkt); - - if (size < 0) { - size = c->dv_demux->sys->frame_size; - if (get_buffer(&s->pb, c->buf, size) <= 0) - return AVERROR_IO; - - size = dv_produce_packet(c->dv_demux, pkt, c->buf, size); - } - - return size; -} - -static int dv_read_seek(AVFormatContext *s, int stream_index, - int64_t timestamp, int flags) -{ - RawDVContext *r = s->priv_data; - DVDemuxContext *c = r->dv_demux; - int64_t offset= dv_frame_offset(s, c, timestamp, flags); - - c->frames= offset / c->sys->frame_size; - if (c->ach) - c->abytes= av_rescale(c->frames, - c->ast[0]->codec->bit_rate * (int64_t)c->sys->frame_rate_base, - 8*c->sys->frame_rate); - - dv_flush_audio_packets(c); - return url_fseek(&s->pb, offset, SEEK_SET); -} - -static int dv_read_close(AVFormatContext *s) -{ - RawDVContext *c = s->priv_data; - av_free(c->dv_demux); - return 0; -} - -#ifdef CONFIG_DV_DEMUXER -AVInputFormat dv_demuxer = { - "dv", - "DV video format", - sizeof(RawDVContext), - NULL, - dv_read_header, - dv_read_packet, - dv_read_close, - dv_read_seek, - .extensions = "dv,dif", -}; -#endif diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/dv.h --- a/src/ffmpeg/libavformat/dv.h Mon Mar 12 14:49:42 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * General DV muxer/demuxer - * Copyright (c) 2003 Roman Shaposhnik - * - * Many thanks to Dan Dennedy for providing wealth - * of DV technical info. - * - * Raw DV format - * Copyright (c) 2002 Fabrice Bellard. - * - * 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 - */ - -typedef struct DVDemuxContext DVDemuxContext; -DVDemuxContext* dv_init_demux(AVFormatContext* s); -int dv_get_packet(DVDemuxContext*, AVPacket *); -int dv_produce_packet(DVDemuxContext*, AVPacket*, uint8_t*, int); -void dv_flush_audio_packets(DVDemuxContext*); - -typedef struct DVMuxContext DVMuxContext; -DVMuxContext* dv_init_mux(AVFormatContext* s); -int dv_assemble_frame(DVMuxContext *c, AVStream*, const uint8_t*, int, uint8_t**); -void dv_delete_mux(DVMuxContext*); diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/mov.c --- a/src/ffmpeg/libavformat/mov.c Mon Mar 12 14:49:42 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1870 +0,0 @@ -/* - * MOV decoder. - * Copyright (c) 2001 Fabrice Bellard. - * - * 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 - -//#define DEBUG - -#include "avformat.h" -#include "riff.h" -#include "isom.h" -#include "dv.h" - -#ifdef CONFIG_ZLIB -#include -#endif - -/* - * First version by Francois Revol revol@free.fr - * Seek function by Gael Chardon gael.dev@4now.net - * - * Features and limitations: - * - reads most of the QT files I have (at least the structure), - * the exceptions are .mov with zlib compressed headers ('cmov' section). It shouldn't be hard to implement. - * FIXED, Francois Revol, 07/17/2002 - * - ffmpeg has nearly none of the usual QuickTime codecs, - * although I succesfully dumped raw and mp3 audio tracks off .mov files. - * Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html - * - .mp4 parsing is still hazardous, although the format really is QuickTime with some minor changes - * (to make .mov parser crash maybe ?), despite what they say in the MPEG FAQ at - * http://mpeg.telecomitalialab.com/faq.htm - * - the code is quite ugly... maybe I won't do it recursive next time :-) - * - seek is not supported with files that contain edit list - * - * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/ - * when coding this :) (it's a writer anyway) - * - * Reference documents: - * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt - * Apple: - * http://developer.apple.com/documentation/QuickTime/QTFF/ - * http://developer.apple.com/documentation/QuickTime/QTFF/qtff.pdf - * QuickTime is a trademark of Apple (AFAIK :)) - */ - -#include "qtpalette.h" - - -#undef NDEBUG -#include - -static const CodecTag mov_video_tags[] = { -/* { CODEC_ID_, MKTAG('c', 'v', 'i', 'd') }, *//* Cinepak */ -/* { CODEC_ID_H263, MKTAG('r', 'a', 'w', ' ') }, *//* Uncompressed RGB */ -/* { CODEC_ID_H263, MKTAG('Y', 'u', 'v', '2') }, *//* Uncompressed YUV422 */ -/* { CODEC_ID_RAWVIDEO, MKTAG('A', 'V', 'U', 'I') }, *//* YUV with alpha-channel (AVID Uncompressed) */ -/* Graphics */ -/* Animation */ -/* Apple video */ -/* Kodak Photo CD */ - { CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, /* PhotoJPEG */ - { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */ - { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') }, /* Motion-JPEG (format A) */ - { CODEC_ID_MJPEGB, MKTAG('m', 'j', 'p', 'b') }, /* Motion-JPEG (format B) */ - { CODEC_ID_MJPEG, MKTAG('A', 'V', 'D', 'J') }, /* MJPEG with alpha-channel (AVID JFIF meridien compressed) */ -/* { CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') }, *//* MJPEG with alpha-channel (AVID ABVB/Truevision NuVista) */ - { CODEC_ID_GIF, MKTAG('g', 'i', 'f', ' ') }, /* embedded gif files as frames (usually one "click to play movie" frame) */ -/* Sorenson video */ - { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') }, /* Sorenson Video v1 */ - { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') }, /* Sorenson Video v1 */ - { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', 'i') }, /* Sorenson Video v1 (from QT specs)*/ - { CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') }, /* Sorenson Video v3 */ - { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') }, - { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') }, /* OpenDiVX *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */ - { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') }, - { CODEC_ID_MPEG4, MKTAG('3', 'I', 'V', '2') }, /* experimental: 3IVX files before ivx D4 4.5.1 */ -/* { CODEC_ID_, MKTAG('I', 'V', '5', '0') }, *//* Indeo 5.0 */ - { CODEC_ID_H263, MKTAG('h', '2', '6', '3') }, /* H263 */ - { CODEC_ID_H263, MKTAG('s', '2', '6', '3') }, /* H263 ?? works */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */ - { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, /* On2 VP3 */ - { CODEC_ID_RPZA, MKTAG('r', 'p', 'z', 'a') }, /* Apple Video (RPZA) */ - { CODEC_ID_CINEPAK, MKTAG('c', 'v', 'i', 'd') }, /* Cinepak */ - { CODEC_ID_8BPS, MKTAG('8', 'B', 'P', 'S') }, /* Planar RGB (8BPS) */ - { CODEC_ID_SMC, MKTAG('s', 'm', 'c', ' ') }, /* Apple Graphics (SMC) */ - { CODEC_ID_QTRLE, MKTAG('r', 'l', 'e', ' ') }, /* Apple Animation (RLE) */ - { CODEC_ID_QDRAW, MKTAG('q', 'd', 'r', 'w') }, /* QuickDraw */ - { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, /* AVC-1/H.264 */ - { CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '2') }, /* MPEG2 produced by Sony HD camera */ - { CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '3') }, /* HDV produced by FCP */ - { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '5', 'n') }, /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */ - { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '5', 'p') }, /* MPEG2 IMX PAL 625/50 50mb/s produced by FCP */ - { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'n') }, /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */ - { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'p') }, /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'p', 'p') }, /* DVCPRO PAL produced by FCP */ - //{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '5') }, /* DVCPRO HD 50i produced by FCP */ - //{ CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '6') }, /* DVCPRO HD 60i produced by FCP */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'p') }, /* DVCPRO50 PAL produced by FCP */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'n') }, /* DVCPRO50 NTSC produced by FCP */ - { CODEC_ID_DVVIDEO, MKTAG('A', 'V', 'd', 'v') }, /* AVID DV */ - //{ CODEC_ID_JPEG2000, MKTAG('m', 'j', 'p', '2') }, /* JPEG 2000 produced by FCP */ - { CODEC_ID_TARGA, MKTAG('t', 'g', 'a', ' ') }, /* Truevision Targa */ - { CODEC_ID_TIFF, MKTAG('t', 'i', 'f', 'f') }, /* TIFF embedded in MOV */ - { CODEC_ID_RAWVIDEO, MKTAG('2', 'v', 'u', 'y') }, /* UNCOMPRESSED 8BIT 4:2:2 */ - { CODEC_ID_NONE, 0 }, -}; - -static const CodecTag mov_audio_tags[] = { - { CODEC_ID_PCM_S32BE, MKTAG('i', 'n', '3', '2') }, - { CODEC_ID_PCM_S24BE, MKTAG('i', 'n', '2', '4') }, - { CODEC_ID_PCM_S16BE, MKTAG('N', 'O', 'N', 'E') }, /* uncompressed */ - { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, /* 16 bits */ - { CODEC_ID_PCM_U8, MKTAG('r', 'a', 'w', ' ') }, /* 8 bits unsigned */ - { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, /* */ - { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, /* */ - { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, /* */ - { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') }, /* IMA-4 ADPCM */ - { CODEC_ID_ADPCM_MS, MKTAG('m', 's', 0x00, 0x02) }, /* MS ADPCM */ - { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') }, /* Macintosh Audio Compression and Expansion 3:1 */ - { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') }, /* Macintosh Audio Compression and Expansion 6:1 */ - - { CODEC_ID_MP3, MKTAG('.', 'm', 'p', '3') }, /* MPEG layer 3 */ /* sample files at http://www.3ivx.com/showcase.html use this tag */ - { CODEC_ID_MP2, 0x6D730055 }, /* MPEG layer 3 */ - { CODEC_ID_MP2, 0x5500736D }, /* MPEG layer 3 *//* XXX: check endianness */ -/* { CODEC_ID_OGG_VORBIS, MKTAG('O', 'g', 'g', 'S') }, *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */ -/* MP4 tags */ - { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') }, /* MPEG-4 AAC */ - /* The standard for mpeg4 audio is still not normalised AFAIK anyway */ - { CODEC_ID_AMR_NB, MKTAG('s', 'a', 'm', 'r') }, /* AMR-NB 3gp */ - { CODEC_ID_AMR_WB, MKTAG('s', 'a', 'w', 'b') }, /* AMR-WB 3gp */ - { CODEC_ID_AC3, MKTAG('m', 's', 0x20, 0x00) }, /* Dolby AC-3 */ - { CODEC_ID_ALAC,MKTAG('a', 'l', 'a', 'c') }, /* Apple Lossless */ - { CODEC_ID_QDM2,MKTAG('Q', 'D', 'M', '2') }, /* QDM2 */ - { CODEC_ID_DVAUDIO, MKTAG('v', 'd', 'v', 'a') }, - { CODEC_ID_DVAUDIO, MKTAG('d', 'v', 'c', 'a') }, - { CODEC_ID_PCM_S16LE, MKTAG('l', 'p', 'c', 'm') }, - { CODEC_ID_NONE, 0 }, -}; - -/* the QuickTime file format is quite convoluted... - * it has lots of index tables, each indexing something in another one... - * Here we just use what is needed to read the chunks - */ - -typedef struct MOV_sample_to_chunk_tbl { - long first; - long count; - long id; -} MOV_sample_to_chunk_tbl; - -typedef struct { - uint32_t type; - int64_t offset; - int64_t size; /* total size (excluding the size and type fields) */ -} MOV_atom_t; - -typedef struct { - int seed; - int flags; - int size; - void* clrs; -} MOV_ctab_t; - -typedef struct MOV_mdat_atom_s { - offset_t offset; - int64_t size; -} MOV_mdat_atom_t; - -typedef struct { - uint8_t version; - uint32_t flags; // 24bit - - /* 0x03 ESDescrTag */ - uint16_t es_id; -#define MP4ODescrTag 0x01 -#define MP4IODescrTag 0x02 -#define MP4ESDescrTag 0x03 -#define MP4DecConfigDescrTag 0x04 -#define MP4DecSpecificDescrTag 0x05 -#define MP4SLConfigDescrTag 0x06 -#define MP4ContentIdDescrTag 0x07 -#define MP4SupplContentIdDescrTag 0x08 -#define MP4IPIPtrDescrTag 0x09 -#define MP4IPMPPtrDescrTag 0x0A -#define MP4IPMPDescrTag 0x0B -#define MP4RegistrationDescrTag 0x0D -#define MP4ESIDIncDescrTag 0x0E -#define MP4ESIDRefDescrTag 0x0F -#define MP4FileIODescrTag 0x10 -#define MP4FileODescrTag 0x11 -#define MP4ExtProfileLevelDescrTag 0x13 -#define MP4ExtDescrTagsStart 0x80 -#define MP4ExtDescrTagsEnd 0xFE - uint8_t stream_priority; - - /* 0x04 DecConfigDescrTag */ - uint8_t object_type_id; - uint8_t stream_type; - /* XXX: really streamType is - * only 6bit, followed by: - * 1bit upStream - * 1bit reserved - */ - uint32_t buffer_size_db; // 24 - uint32_t max_bitrate; - uint32_t avg_bitrate; - - /* 0x05 DecSpecificDescrTag */ - uint8_t decoder_cfg_len; - uint8_t *decoder_cfg; - - /* 0x06 SLConfigDescrTag */ - uint8_t sl_config_len; - uint8_t *sl_config; -} MOV_esds_t; - -struct MOVParseTableEntry; - -typedef struct MOVStreamContext { - int ffindex; /* the ffmpeg stream id */ - long next_chunk; - long chunk_count; - int64_t *chunk_offsets; - int stts_count; - Time2Sample *stts_data; - int ctts_count; - Time2Sample *ctts_data; - int edit_count; /* number of 'edit' (elst atom) */ - long sample_to_chunk_sz; - MOV_sample_to_chunk_tbl *sample_to_chunk; - int sample_to_ctime_index; - int sample_to_ctime_sample; - long sample_size; - long sample_count; - long *sample_sizes; - long keyframe_count; - long *keyframes; - int time_scale; - int time_rate; - long current_sample; - MOV_esds_t esds; - AVRational sample_size_v1; - int dv_audio_container; -} MOVStreamContext; - -typedef struct MOVContext { - int mp4; /* set to 1 as soon as we are sure that the file is an .mp4 file (even some header parsing depends on this) */ - AVFormatContext *fc; - int time_scale; - int64_t duration; /* duration of the longest track */ - int found_moov; /* when both 'moov' and 'mdat' sections has been found */ - int found_mdat; /* we suppose we have enough data to read the file */ - int64_t mdat_size; - int64_t mdat_offset; - int total_streams; - /* some streams listed here aren't presented to the ffmpeg API, since they aren't either video nor audio - * but we need the info to be able to skip data from those streams in the 'mdat' section - */ - MOVStreamContext *streams[MAX_STREAMS]; - - int ctab_size; - MOV_ctab_t **ctab; /* color tables */ - const struct MOVParseTableEntry *parse_table; /* could be eventually used to change the table */ - /* NOTE: for recursion save to/ restore from local variable! */ - - AVPaletteControl palette_control; - MOV_mdat_atom_t *mdat_list; - int mdat_count; - DVDemuxContext *dv_demux; - AVFormatContext *dv_fctx; -} MOVContext; - - -/* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */ - -/* those functions parse an atom */ -/* return code: - 1: found what I wanted, exit - 0: continue to parse next atom - -1: error occured, exit - */ -typedef int (*mov_parse_function)(MOVContext *ctx, ByteIOContext *pb, MOV_atom_t atom); - -/* links atom IDs to parse functions */ -typedef struct MOVParseTableEntry { - uint32_t type; - mov_parse_function func; -} MOVParseTableEntry; - -static int mov_read_leaf(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - if (atom.size>1) - url_fskip(pb, atom.size); -/* url_seek(pb, atom_offset+atom.size, SEEK_SET); */ - return 0; -} - -static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - int64_t total_size = 0; - MOV_atom_t a; - int i; - int err = 0; - - a.offset = atom.offset; - - if (atom.size < 0) - atom.size = 0x7fffffffffffffffLL; - while(((total_size + 8) < atom.size) && !url_feof(pb) && !err) { - a.size = atom.size; - a.type=0L; - if(atom.size >= 8) { - a.size = get_be32(pb); - a.type = get_le32(pb); - } - total_size += 8; - a.offset += 8; - dprintf("type: %08x %.4s sz: %"PRIx64" %"PRIx64" %"PRIx64"\n", a.type, (char*)&a.type, a.size, atom.size, total_size); - if (a.size == 1) { /* 64 bit extended size */ - a.size = get_be64(pb) - 8; - a.offset += 8; - total_size += 8; - } - if (a.size == 0) { - a.size = atom.size - total_size; - if (a.size <= 8) - break; - } - for (i = 0; c->parse_table[i].type != 0L - && c->parse_table[i].type != a.type; i++) - /* empty */; - - a.size -= 8; - - if(a.size < 0) - break; - - if (c->parse_table[i].type == 0) { /* skip leaf atoms data */ - url_fskip(pb, a.size); - } else { - offset_t start_pos = url_ftell(pb); - int64_t left; - err = (c->parse_table[i].func)(c, pb, a); - left = a.size - url_ftell(pb) + start_pos; - if (left > 0) /* skip garbage at atom end */ - url_fskip(pb, left); - } - - a.offset += a.size; - total_size += a.size; - } - - if (!err && total_size < atom.size && atom.size < 0x7ffff) { - url_fskip(pb, atom.size - total_size); - } - - return err; -} - -static int mov_read_ctab(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ -#if 1 - url_fskip(pb, atom.size); // for now -#else - VERY VERY BROKEN, NEVER execute this, needs rewrite - unsigned int len; - MOV_ctab_t *t; - c->ctab = av_realloc(c->ctab, ++c->ctab_size); - t = c->ctab[c->ctab_size]; - t->seed = get_be32(pb); - t->flags = get_be16(pb); - t->size = get_be16(pb) + 1; - len = 2 * t->size * 4; - if (len > 0) { - t->clrs = av_malloc(len); // 16bit A R G B - if (t->clrs) - get_buffer(pb, t->clrs, len); - } -#endif - - return 0; -} - -static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - int len = 0; - uint32_t type; - uint32_t ctype; - - get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - - /* component type */ - ctype = get_le32(pb); - type = get_le32(pb); /* component subtype */ - - dprintf("ctype= %c%c%c%c (0x%08lx)\n", *((char *)&ctype), ((char *)&ctype)[1], ((char *)&ctype)[2], ((char *)&ctype)[3], (long) ctype); - dprintf("stype= %c%c%c%c\n", *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]); - if(ctype == MKTAG('m', 'h', 'l', 'r')) /* MOV */ - c->mp4 = 0; - else if(ctype == 0) - c->mp4 = 1; - if(type == MKTAG('v', 'i', 'd', 'e')) - st->codec->codec_type = CODEC_TYPE_VIDEO; - else if(type == MKTAG('s', 'o', 'u', 'n')) - st->codec->codec_type = CODEC_TYPE_AUDIO; - get_be32(pb); /* component manufacture */ - get_be32(pb); /* component flags */ - get_be32(pb); /* component flags mask */ - - if(atom.size <= 24) - return 0; /* nothing left to read */ - /* XXX: MP4 uses a C string, not a pascal one */ - /* component name */ - - if(c->mp4) { - /* .mp4: C string */ - while(get_byte(pb) && (++len < (atom.size - 24))); - } else { - /* .mov: PASCAL string */ - len = get_byte(pb); - url_fskip(pb, len); - } - - url_fskip(pb, atom.size - (url_ftell(pb) - atom.offset)); - return 0; -} - -static int mov_mp4_read_descr_len(ByteIOContext *pb) -{ - int len = 0; - int count = 4; - while (count--) { - int c = get_byte(pb); - len = (len << 7) | (c & 0x7f); - if (!(c & 0x80)) - break; - } - return len; -} - -static int mov_mp4_read_descr(ByteIOContext *pb, int *tag) -{ - int len; - *tag = get_byte(pb); - len = mov_mp4_read_descr_len(pb); - dprintf("MPEG4 description: tag=0x%02x len=%d\n", *tag, len); - return len; -} - -static int mov_read_esds(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - int tag, len; - - /* Well, broken but suffisant for some MP4 streams */ - get_be32(pb); /* version + flags */ - len = mov_mp4_read_descr(pb, &tag); - if (tag == MP4ESDescrTag) { - get_be16(pb); /* ID */ - get_byte(pb); /* priority */ - } else - get_be16(pb); /* ID */ - - len = mov_mp4_read_descr(pb, &tag); - if (tag == MP4DecConfigDescrTag) { - sc->esds.object_type_id = get_byte(pb); - sc->esds.stream_type = get_byte(pb); - sc->esds.buffer_size_db = get_be24(pb); - sc->esds.max_bitrate = get_be32(pb); - sc->esds.avg_bitrate = get_be32(pb); - - st->codec->codec_id= codec_get_id(ff_mov_obj_type, sc->esds.object_type_id); - dprintf("esds object type id %d\n", sc->esds.object_type_id); - len = mov_mp4_read_descr(pb, &tag); - if (tag == MP4DecSpecificDescrTag) { - dprintf("Specific MPEG4 header len=%d\n", len); - st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); - if (st->codec->extradata) { - get_buffer(pb, st->codec->extradata, len); - st->codec->extradata_size = len; - /* from mplayer */ - if ((*st->codec->extradata >> 3) == 29) { - st->codec->codec_id = CODEC_ID_MP3ON4; - } - } - } - } - return 0; -} - -/* this atom contains actual media data */ -static int mov_read_mdat(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - if(atom.size == 0) /* wrong one (MP4) */ - return 0; - c->mdat_list = av_realloc(c->mdat_list, (c->mdat_count + 1) * sizeof(*c->mdat_list)); - c->mdat_list[c->mdat_count].offset = atom.offset; - c->mdat_list[c->mdat_count].size = atom.size; - c->mdat_count++; - c->found_mdat=1; - c->mdat_offset = atom.offset; - c->mdat_size = atom.size; - if(c->found_moov) - return 1; /* found both, just go */ - url_fskip(pb, atom.size); - return 0; /* now go for moov */ -} - -static int mov_read_ftyp(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - uint32_t type = get_le32(pb); - - /* from mplayer */ - switch (type) { - case MKTAG('i', 's', 'o', 'm'): - case MKTAG('m', 'p', '4', '1'): - case MKTAG('m', 'p', '4', '2'): - case MKTAG('3', 'g', 'p', '1'): - case MKTAG('3', 'g', 'p', '2'): - case MKTAG('3', 'g', '2', 'a'): - case MKTAG('3', 'g', 'p', '3'): - case MKTAG('3', 'g', 'p', '4'): - case MKTAG('3', 'g', 'p', '5'): - case MKTAG('m', 'm', 'p', '4'): /* Mobile MP4 */ - case MKTAG('M', '4', 'A', ' '): /* Apple iTunes AAC-LC Audio */ - case MKTAG('M', '4', 'P', ' '): /* Apple iTunes AAC-LC Protected Audio */ - case MKTAG('m', 'j', 'p', '2'): /* Motion Jpeg 2000 */ - c->mp4 = 1; - case MKTAG('q', 't', ' ', ' '): - default: - av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand: %.4s\n",(char *)&type); - } - get_be32(pb); /* minor version */ - url_fskip(pb, atom.size - 8); - return 0; -} - -/* this atom should contain all header atoms */ -static int mov_read_moov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - int err; - - err = mov_read_default(c, pb, atom); - /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */ - /* so we don't parse the whole file if over a network */ - c->found_moov=1; - if(c->found_mdat) - return 1; /* found both, just go */ - return 0; /* now go for mdat */ -} - - -static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - int version = get_byte(pb); - int lang; - - if (version > 1) - return 1; /* unsupported */ - - get_byte(pb); get_byte(pb); - get_byte(pb); /* flags */ - - if (version == 1) { - get_be64(pb); - get_be64(pb); - } else { - get_be32(pb); /* creation time */ - get_be32(pb); /* modification time */ - } - - sc->time_scale = get_be32(pb); - st->duration = (version == 1) ? get_be64(pb) : get_be32(pb); /* duration */ - - lang = get_be16(pb); /* language */ - ff_mov_lang_to_iso639(lang, st->language); - get_be16(pb); /* quality */ - - return 0; -} - -static int mov_read_mvhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - int version = get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - - if (version == 1) { - get_be64(pb); - get_be64(pb); - } else { - get_be32(pb); /* creation time */ - get_be32(pb); /* modification time */ - } - c->time_scale = get_be32(pb); /* time scale */ -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "time scale = %i\n", c->time_scale); -#endif - c->duration = (version == 1) ? get_be64(pb) : get_be32(pb); /* duration */ - get_be32(pb); /* preferred scale */ - - get_be16(pb); /* preferred volume */ - - url_fskip(pb, 10); /* reserved */ - - url_fskip(pb, 36); /* display matrix */ - - get_be32(pb); /* preview time */ - get_be32(pb); /* preview duration */ - get_be32(pb); /* poster time */ - get_be32(pb); /* selection time */ - get_be32(pb); /* selection duration */ - get_be32(pb); /* current time */ - get_be32(pb); /* next track ID */ - - return 0; -} - -static int mov_read_smi(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - - if((uint64_t)atom.size > (1<<30)) - return -1; - - // currently SVQ3 decoder expect full STSD header - so let's fake it - // this should be fixed and just SMI header should be passed - av_free(st->codec->extradata); - st->codec->extradata_size = 0x5a + atom.size; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - - if (st->codec->extradata) { - strcpy(st->codec->extradata, "SVQ3"); // fake - get_buffer(pb, st->codec->extradata + 0x5a, atom.size); - dprintf("Reading SMI %"PRId64" %s\n", atom.size, st->codec->extradata + 0x5a); - } else - url_fskip(pb, atom.size); - - return 0; -} - -static int mov_read_enda(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - int little_endian = get_be16(pb); - - if (little_endian) { - switch (st->codec->codec_id) { - case CODEC_ID_PCM_S24BE: - st->codec->codec_id = CODEC_ID_PCM_S24LE; - break; - case CODEC_ID_PCM_S32BE: - st->codec->codec_id = CODEC_ID_PCM_S32LE; - break; - default: - break; - } - } - return 0; -} - -static int mov_read_alac(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - - // currently ALAC decoder expect full atom header - so let's fake it - // this should be fixed and just ALAC header should be passed - - av_free(st->codec->extradata); - st->codec->extradata_size = 36; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - - if (st->codec->extradata) { - strcpy(st->codec->extradata + 4, "alac"); // fake - get_buffer(pb, st->codec->extradata + 8, 36 - 8); - dprintf("Reading alac %d %s\n", st->codec->extradata_size, st->codec->extradata); - } else - url_fskip(pb, atom.size); - return 0; -} - -static int mov_read_wave(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - - if((uint64_t)atom.size > (1<<30)) - return -1; - - if (st->codec->codec_id == CODEC_ID_QDM2) { - // pass all frma atom to codec, needed at least for QDM2 - av_free(st->codec->extradata); - st->codec->extradata_size = atom.size; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - - if (st->codec->extradata) { - get_buffer(pb, st->codec->extradata, atom.size); - } else - url_fskip(pb, atom.size); - } else if (atom.size > 8) { /* to read frma, esds atoms */ - mov_read_default(c, pb, atom); - } else - url_fskip(pb, atom.size); - return 0; -} - -static int mov_read_jp2h(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - - if((uint64_t)atom.size > (1<<30)) - return -1; - - av_free(st->codec->extradata); - - st->codec->extradata_size = atom.size + 8; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - - /* pass all jp2h atom to codec */ - if (st->codec->extradata) { - strcpy(st->codec->extradata + 4, "jp2h"); - get_buffer(pb, st->codec->extradata + 8, atom.size); - } else - url_fskip(pb, atom.size); - return 0; -} - -static int mov_read_avcC(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - - if((uint64_t)atom.size > (1<<30)) - return -1; - - av_free(st->codec->extradata); - - st->codec->extradata_size = atom.size; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - - if (st->codec->extradata) { - get_buffer(pb, st->codec->extradata, atom.size); - } else - url_fskip(pb, atom.size); - - return 0; -} - -static int mov_read_stco(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - unsigned int i, entries; - - get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - - entries = get_be32(pb); - - if(entries >= UINT_MAX/sizeof(int64_t)) - return -1; - - sc->chunk_count = entries; - sc->chunk_offsets = av_malloc(entries * sizeof(int64_t)); - if (!sc->chunk_offsets) - return -1; - if (atom.type == MKTAG('s', 't', 'c', 'o')) { - for(i=0; ichunk_offsets[i] = get_be32(pb); - } - } else if (atom.type == MKTAG('c', 'o', '6', '4')) { - for(i=0; ichunk_offsets[i] = get_be64(pb); - } - } else - return -1; - - return 0; -} - -static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - int entries, frames_per_sample; - uint32_t format; - uint8_t codec_name[32]; - - /* for palette traversal */ - int color_depth; - int color_start; - int color_count; - int color_end; - int color_index; - int color_dec; - int color_greyscale; - unsigned char *color_table; - int j; - unsigned char r, g, b; - - get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - - entries = get_be32(pb); - - while(entries--) { //Parsing Sample description table - enum CodecID id; - MOV_atom_t a = { 0, 0, 0 }; - offset_t start_pos = url_ftell(pb); - int size = get_be32(pb); /* size */ - format = get_le32(pb); /* data format */ - - get_be32(pb); /* reserved */ - get_be16(pb); /* reserved */ - get_be16(pb); /* index */ - - if (st->codec->codec_tag) { - /* multiple fourcc, just skip for now */ - url_fskip(pb, size - (url_ftell(pb) - start_pos)); - continue; - } - - st->codec->codec_tag = format; - id = codec_get_id(mov_audio_tags, format); - if (id > 0) { - st->codec->codec_type = CODEC_TYPE_AUDIO; - } else if (format && format != MKTAG('m', 'p', '4', 's')) { /* skip old asf mpeg4 tag */ - id = codec_get_id(mov_video_tags, format); - if (id <= 0) - id = codec_get_id(codec_bmp_tags, format); - if (id > 0) - st->codec->codec_type = CODEC_TYPE_VIDEO; - } - - dprintf("size=%d 4CC= %c%c%c%c codec_type=%d\n", - size, - (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff, (format >> 24) & 0xff, - st->codec->codec_type); - - if(st->codec->codec_type==CODEC_TYPE_VIDEO) { - st->codec->codec_id = id; - get_be16(pb); /* version */ - get_be16(pb); /* revision level */ - get_be32(pb); /* vendor */ - get_be32(pb); /* temporal quality */ - get_be32(pb); /* spacial quality */ - - st->codec->width = get_be16(pb); /* width */ - st->codec->height = get_be16(pb); /* height */ - - get_be32(pb); /* horiz resolution */ - get_be32(pb); /* vert resolution */ - get_be32(pb); /* data size, always 0 */ - frames_per_sample = get_be16(pb); /* frames per samples */ -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "frames/samples = %d\n", frames_per_sample); -#endif - get_buffer(pb, codec_name, 32); /* codec name, pascal string (FIXME: true for mp4?) */ - if (codec_name[0] <= 31) { - memcpy(st->codec->codec_name, &codec_name[1],codec_name[0]); - st->codec->codec_name[codec_name[0]] = 0; - } - - st->codec->bits_per_sample = get_be16(pb); /* depth */ - st->codec->color_table_id = get_be16(pb); /* colortable id */ - - /* figure out the palette situation */ - color_depth = st->codec->bits_per_sample & 0x1F; - color_greyscale = st->codec->bits_per_sample & 0x20; - - /* if the depth is 2, 4, or 8 bpp, file is palettized */ - if ((color_depth == 2) || (color_depth == 4) || - (color_depth == 8)) { - - if (color_greyscale) { - - /* compute the greyscale palette */ - color_count = 1 << color_depth; - color_index = 255; - color_dec = 256 / (color_count - 1); - for (j = 0; j < color_count; j++) { - r = g = b = color_index; - c->palette_control.palette[j] = - (r << 16) | (g << 8) | (b); - color_index -= color_dec; - if (color_index < 0) - color_index = 0; - } - - } else if (st->codec->color_table_id & 0x08) { - - /* if flag bit 3 is set, use the default palette */ - color_count = 1 << color_depth; - if (color_depth == 2) - color_table = ff_qt_default_palette_4; - else if (color_depth == 4) - color_table = ff_qt_default_palette_16; - else - color_table = ff_qt_default_palette_256; - - for (j = 0; j < color_count; j++) { - r = color_table[j * 4 + 0]; - g = color_table[j * 4 + 1]; - b = color_table[j * 4 + 2]; - c->palette_control.palette[j] = - (r << 16) | (g << 8) | (b); - } - - } else { - - /* load the palette from the file */ - color_start = get_be32(pb); - color_count = get_be16(pb); - color_end = get_be16(pb); - for (j = color_start; j <= color_end; j++) { - /* each R, G, or B component is 16 bits; - * only use the top 8 bits; skip alpha bytes - * up front */ - get_byte(pb); - get_byte(pb); - r = get_byte(pb); - get_byte(pb); - g = get_byte(pb); - get_byte(pb); - b = get_byte(pb); - get_byte(pb); - c->palette_control.palette[j] = - (r << 16) | (g << 8) | (b); - } - } - - st->codec->palctrl = &c->palette_control; - st->codec->palctrl->palette_changed = 1; - } else - st->codec->palctrl = NULL; - } else if(st->codec->codec_type==CODEC_TYPE_AUDIO) { - int bits_per_sample; - uint16_t version = get_be16(pb); - - st->codec->codec_id = id; - get_be16(pb); /* revision level */ - get_be32(pb); /* vendor */ - - st->codec->channels = get_be16(pb); /* channel count */ - dprintf("audio channels %d\n", st->codec->channels); - st->codec->bits_per_sample = get_be16(pb); /* sample size */ - /* do we need to force to 16 for AMR ? */ - - /* handle specific s8 codec */ - get_be16(pb); /* compression id = 0*/ - get_be16(pb); /* packet size = 0 */ - - st->codec->sample_rate = ((get_be32(pb) >> 16)); - - switch (st->codec->codec_id) { - case CODEC_ID_PCM_S8: - case CODEC_ID_PCM_U8: - if (st->codec->bits_per_sample == 16) - st->codec->codec_id = CODEC_ID_PCM_S16BE; - break; - case CODEC_ID_PCM_S16LE: - case CODEC_ID_PCM_S16BE: - if (st->codec->bits_per_sample == 8) - st->codec->codec_id = CODEC_ID_PCM_S8; - else if (st->codec->bits_per_sample == 24) - st->codec->codec_id = CODEC_ID_PCM_S24BE; - break; - default: - break; - } - - //Read QT version 1 fields. In version 0 theese dont exist - dprintf("version =%d mp4=%d\n",version,c->mp4); - if(version==1) { - sc->sample_size_v1.den = get_be32(pb); /* samples per packet */ - get_be32(pb); /* bytes per packet */ - sc->sample_size_v1.num = get_be32(pb); /* bytes per frame */ - get_be32(pb); /* bytes per sample */ - } else if(version==2) { - get_be32(pb); /* sizeof struct only */ - st->codec->sample_rate = av_int2dbl(get_be64(pb)); /* float 64 */ - st->codec->channels = get_be32(pb); - get_be32(pb); /* always 0x7F000000 */ - get_be32(pb); /* bits per channel if sound is uncompressed */ - get_be32(pb); /* lcpm format specific flag */ - get_be32(pb); /* bytes per audio packet if constant */ - get_be32(pb); /* lpcm frames per audio packet if constant */ - } - - bits_per_sample = av_get_bits_per_sample(st->codec->codec_id); - if (bits_per_sample) { - st->codec->bits_per_sample = bits_per_sample; - sc->sample_size = (bits_per_sample >> 3) * st->codec->channels; - } - } else { - /* other codec type, just skip (rtp, mp4s, tmcd ...) */ - url_fskip(pb, size - (url_ftell(pb) - start_pos)); - } - /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */ - a.size = size - (url_ftell(pb) - start_pos); - if (a.size > 8) - mov_read_default(c, pb, a); - else if (a.size > 0) - url_fskip(pb, a.size); - } - - if(st->codec->codec_type==CODEC_TYPE_AUDIO && st->codec->sample_rate==0 && sc->time_scale>1) { - st->codec->sample_rate= sc->time_scale; - } - - /* special codec parameters handling */ - switch (st->codec->codec_id) { -#ifdef CONFIG_H261_DECODER - case CODEC_ID_H261: -#endif -#ifdef CONFIG_H263_DECODER - case CODEC_ID_H263: -#endif -#ifdef CONFIG_MPEG4_DECODER - case CODEC_ID_MPEG4: -#endif - st->codec->width= 0; /* let decoder init width/height */ - st->codec->height= 0; - break; -#ifdef CONFIG_FAAD - case CODEC_ID_AAC: -#endif -#ifdef CONFIG_VORBIS_DECODER - case CODEC_ID_VORBIS: -#endif - case CODEC_ID_MP3ON4: - st->codec->sample_rate= 0; /* let decoder init parameters properly */ - break; -#ifdef CONFIG_DV_DEMUXER - case CODEC_ID_DVAUDIO: - c->dv_fctx = av_alloc_format_context(); - c->dv_demux = dv_init_demux(c->dv_fctx); - if (!c->dv_demux) { - av_log(c->fc, AV_LOG_ERROR, "dv demux context init error\n"); - return -1; - } - sc->dv_audio_container = 1; - st->codec->codec_id = CODEC_ID_PCM_S16LE; - break; -#endif - /* no ifdef since parameters are always those */ - case CODEC_ID_AMR_WB: - st->codec->sample_rate= 16000; - st->codec->channels= 1; /* really needed */ - break; - case CODEC_ID_AMR_NB: - st->codec->sample_rate= 8000; - st->codec->channels= 1; /* really needed */ - break; - case CODEC_ID_MP2: - st->need_parsing = 1; - break; - default: - break; - } - - return 0; -} - -static int mov_read_stsc(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - unsigned int i, entries; - - get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - - entries = get_be32(pb); - - if(entries >= UINT_MAX / sizeof(MOV_sample_to_chunk_tbl)) - return -1; - -#ifdef DEBUG -av_log(NULL, AV_LOG_DEBUG, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); -#endif - sc->sample_to_chunk_sz = entries; - sc->sample_to_chunk = av_malloc(entries * sizeof(MOV_sample_to_chunk_tbl)); - if (!sc->sample_to_chunk) - return -1; - for(i=0; isample_to_chunk[i].first = get_be32(pb); - sc->sample_to_chunk[i].count = get_be32(pb); - sc->sample_to_chunk[i].id = get_be32(pb); - } - return 0; -} - -static int mov_read_stss(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - unsigned int i, entries; - - get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - - entries = get_be32(pb); - - if(entries >= UINT_MAX / sizeof(long)) - return -1; - - sc->keyframe_count = entries; -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "keyframe_count = %ld\n", sc->keyframe_count); -#endif - sc->keyframes = av_malloc(entries * sizeof(long)); - if (!sc->keyframes) - return -1; - for(i=0; ikeyframes[i] = get_be32(pb); -#ifdef DEBUG -/* av_log(NULL, AV_LOG_DEBUG, "keyframes[]=%ld\n", sc->keyframes[i]); */ -#endif - } - return 0; -} - -static int mov_read_stsz(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - unsigned int i, entries, sample_size; - - get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - - sample_size = get_be32(pb); - if (!sc->sample_size) /* do not overwrite value computed in stsd */ - sc->sample_size = sample_size; - entries = get_be32(pb); - if(entries >= UINT_MAX / sizeof(long)) - return -1; - - sc->sample_count = entries; - if (sample_size) - return 0; - -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count); -#endif - sc->sample_sizes = av_malloc(entries * sizeof(long)); - if (!sc->sample_sizes) - return -1; - for(i=0; isample_sizes[i] = get_be32(pb); -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "sample_sizes[]=%ld\n", sc->sample_sizes[i]); -#endif - } - return 0; -} - -static int mov_read_stts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - unsigned int i, entries; - int64_t duration=0; - int64_t total_sample_count=0; - - get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - entries = get_be32(pb); - if(entries >= UINT_MAX / sizeof(Time2Sample)) - return -1; - - sc->stts_count = entries; - sc->stts_data = av_malloc(entries * sizeof(Time2Sample)); - -#ifdef DEBUG -av_log(NULL, AV_LOG_DEBUG, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); -#endif - - sc->time_rate=0; - - for(i=0; istts_data[i].count= sample_count; - sc->stts_data[i].duration= sample_duration; - - sc->time_rate= ff_gcd(sc->time_rate, sample_duration); - - dprintf("sample_count=%d, sample_duration=%d\n",sample_count,sample_duration); - - duration+=(int64_t)sample_duration*sample_count; - total_sample_count+=sample_count; - } - - st->nb_frames= total_sample_count; - if(duration) - st->duration= duration; - return 0; -} - -static int mov_read_ctts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - unsigned int i, entries; - - get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - entries = get_be32(pb); - if(entries >= UINT_MAX / sizeof(Time2Sample)) - return -1; - - sc->ctts_count = entries; - sc->ctts_data = av_malloc(entries * sizeof(Time2Sample)); - - dprintf("track[%i].ctts.entries = %i\n", c->fc->nb_streams-1, entries); - - for(i=0; ifc, AV_LOG_ERROR, "negative ctts, ignoring\n"); - sc->ctts_count = 0; - url_fskip(pb, 8 * (entries - i - 1)); - break; - } - sc->ctts_data[i].count = count; - sc->ctts_data[i].duration= duration; - - sc->time_rate= ff_gcd(sc->time_rate, duration); - } - return 0; -} - -static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st; - MOVStreamContext *sc; - - st = av_new_stream(c->fc, c->fc->nb_streams); - if (!st) return -2; - sc = av_mallocz(sizeof(MOVStreamContext)); - if (!sc) { - av_free(st); - return -1; - } - - st->priv_data = sc; - st->codec->codec_type = CODEC_TYPE_DATA; - st->start_time = 0; /* XXX: check */ - c->streams[c->fc->nb_streams-1] = sc; - - return mov_read_default(c, pb, atom); -} - -static int mov_read_tkhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - int version = get_byte(pb); - - get_byte(pb); get_byte(pb); - get_byte(pb); /* flags */ - /* - MOV_TRACK_ENABLED 0x0001 - MOV_TRACK_IN_MOVIE 0x0002 - MOV_TRACK_IN_PREVIEW 0x0004 - MOV_TRACK_IN_POSTER 0x0008 - */ - - if (version == 1) { - get_be64(pb); - get_be64(pb); - } else { - get_be32(pb); /* creation time */ - get_be32(pb); /* modification time */ - } - st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/ - get_be32(pb); /* reserved */ - st->start_time = 0; /* check */ - (version == 1) ? get_be64(pb) : get_be32(pb); /* highlevel (considering edits) duration in movie timebase */ - get_be32(pb); /* reserved */ - get_be32(pb); /* reserved */ - - get_be16(pb); /* layer */ - get_be16(pb); /* alternate group */ - get_be16(pb); /* volume */ - get_be16(pb); /* reserved */ - - url_fskip(pb, 36); /* display matrix */ - - /* those are fixed-point */ - get_be32(pb); /* track width */ - get_be32(pb); /* track height */ - - return 0; -} - -/* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */ -/* like the files created with Adobe Premiere 5.0, for samples see */ -/* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */ -static int mov_read_wide(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - int err; - - if (atom.size < 8) - return 0; /* continue */ - if (get_be32(pb) != 0) { /* 0 sized mdat atom... use the 'wide' atom size */ - url_fskip(pb, atom.size - 4); - return 0; - } - atom.type = get_le32(pb); - atom.offset += 8; - atom.size -= 8; - if (atom.type != MKTAG('m', 'd', 'a', 't')) { - url_fskip(pb, atom.size); - return 0; - } - err = mov_read_mdat(c, pb, atom); - return err; -} - -static int mov_read_cmov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ -#ifdef CONFIG_ZLIB - ByteIOContext ctx; - uint8_t *cmov_data; - uint8_t *moov_data; /* uncompressed data */ - long cmov_len, moov_len; - int ret; - - get_be32(pb); /* dcom atom */ - if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' )) - return -1; - if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) { - av_log(NULL, AV_LOG_ERROR, "unknown compression for cmov atom !"); - return -1; - } - get_be32(pb); /* cmvd atom */ - if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' )) - return -1; - moov_len = get_be32(pb); /* uncompressed size */ - cmov_len = atom.size - 6 * 4; - - cmov_data = av_malloc(cmov_len); - if (!cmov_data) - return -1; - moov_data = av_malloc(moov_len); - if (!moov_data) { - av_free(cmov_data); - return -1; - } - get_buffer(pb, cmov_data, cmov_len); - if(uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK) - return -1; - if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, NULL, NULL, NULL) != 0) - return -1; - atom.type = MKTAG( 'm', 'o', 'o', 'v' ); - atom.offset = 0; - atom.size = moov_len; -#ifdef DEBUG -// { int fd = open("/tmp/uncompheader.mov", O_WRONLY | O_CREAT); write(fd, moov_data, moov_len); close(fd); } -#endif - ret = mov_read_default(c, &ctx, atom); - av_free(moov_data); - av_free(cmov_data); - return ret; -#else - av_log(c->fc, AV_LOG_ERROR, "this file requires zlib support compiled in\n"); - return -1; -#endif -} - -/* edit list atom */ -static int mov_read_elst(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) -{ - int i, edit_count; - - get_byte(pb); /* version */ - get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - edit_count= c->streams[c->fc->nb_streams-1]->edit_count = get_be32(pb); /* entries */ - - for(i=0; ifc->nb_streams-1, c->streams[c->fc->nb_streams-1]->edit_count); - return 0; -} - -static const MOVParseTableEntry mov_default_parse_table[] = { -/* mp4 atoms */ -{ MKTAG( 'c', 'o', '6', '4' ), mov_read_stco }, -{ MKTAG( 'c', 'p', 'r', 't' ), mov_read_default }, -{ MKTAG( 'c', 'r', 'h', 'd' ), mov_read_default }, -{ MKTAG( 'c', 't', 't', 's' ), mov_read_ctts }, /* composition time to sample */ -{ MKTAG( 'd', 'i', 'n', 'f' ), mov_read_default }, /* data information */ -{ MKTAG( 'd', 'p', 'n', 'd' ), mov_read_leaf }, -{ MKTAG( 'd', 'r', 'e', 'f' ), mov_read_leaf }, -{ MKTAG( 'e', 'd', 't', 's' ), mov_read_default }, -{ MKTAG( 'e', 'l', 's', 't' ), mov_read_elst }, -{ MKTAG( 'e', 'n', 'd', 'a' ), mov_read_enda }, -{ MKTAG( 'f', 'r', 'e', 'e' ), mov_read_leaf }, -{ MKTAG( 'f', 't', 'y', 'p' ), mov_read_ftyp }, -{ MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr }, -{ MKTAG( 'h', 'i', 'n', 't' ), mov_read_leaf }, -{ MKTAG( 'h', 'm', 'h', 'd' ), mov_read_leaf }, -{ MKTAG( 'i', 'o', 'd', 's' ), mov_read_leaf }, -{ MKTAG( 'j', 'p', '2', 'h' ), mov_read_jp2h }, -{ MKTAG( 'm', 'd', 'a', 't' ), mov_read_mdat }, -{ MKTAG( 'm', 'd', 'h', 'd' ), mov_read_mdhd }, -{ MKTAG( 'm', 'd', 'i', 'a' ), mov_read_default }, -{ MKTAG( 'm', 'i', 'n', 'f' ), mov_read_default }, -{ MKTAG( 'm', 'o', 'o', 'v' ), mov_read_moov }, -{ MKTAG( 'm', 'p', '4', 'a' ), mov_read_default }, -{ MKTAG( 'm', 'p', '4', 's' ), mov_read_default }, -{ MKTAG( 'm', 'p', '4', 'v' ), mov_read_default }, -{ MKTAG( 'm', 'p', 'o', 'd' ), mov_read_leaf }, -{ MKTAG( 'm', 'v', 'h', 'd' ), mov_read_mvhd }, -{ MKTAG( 'n', 'm', 'h', 'd' ), mov_read_leaf }, -{ MKTAG( 'o', 'd', 'h', 'd' ), mov_read_default }, -{ MKTAG( 's', 'd', 'h', 'd' ), mov_read_default }, -{ MKTAG( 's', 'k', 'i', 'p' ), mov_read_leaf }, -{ MKTAG( 's', 'm', 'h', 'd' ), mov_read_leaf }, /* sound media info header */ -{ MKTAG( 'S', 'M', 'I', ' ' ), mov_read_smi }, /* Sorenson extension ??? */ -{ MKTAG( 'a', 'l', 'a', 'c' ), mov_read_alac }, /* alac specific atom */ -{ MKTAG( 'a', 'v', 'c', 'C' ), mov_read_avcC }, -{ MKTAG( 's', 't', 'b', 'l' ), mov_read_default }, -{ MKTAG( 's', 't', 'c', 'o' ), mov_read_stco }, -{ MKTAG( 's', 't', 'd', 'p' ), mov_read_default }, -{ MKTAG( 's', 't', 's', 'c' ), mov_read_stsc }, -{ MKTAG( 's', 't', 's', 'd' ), mov_read_stsd }, /* sample description */ -{ MKTAG( 's', 't', 's', 'h' ), mov_read_default }, -{ MKTAG( 's', 't', 's', 's' ), mov_read_stss }, /* sync sample */ -{ MKTAG( 's', 't', 's', 'z' ), mov_read_stsz }, /* sample size */ -{ MKTAG( 's', 't', 't', 's' ), mov_read_stts }, -{ MKTAG( 't', 'k', 'h', 'd' ), mov_read_tkhd }, /* track header */ -{ MKTAG( 't', 'r', 'a', 'k' ), mov_read_trak }, -{ MKTAG( 't', 'r', 'e', 'f' ), mov_read_default }, /* not really */ -{ MKTAG( 'u', 'd', 't', 'a' ), mov_read_leaf }, -{ MKTAG( 'u', 'r', 'l', ' ' ), mov_read_leaf }, -{ MKTAG( 'u', 'r', 'n', ' ' ), mov_read_leaf }, -{ MKTAG( 'u', 'u', 'i', 'd' ), mov_read_leaf }, -{ MKTAG( 'v', 'm', 'h', 'd' ), mov_read_leaf }, /* video media info header */ -{ MKTAG( 'w', 'a', 'v', 'e' ), mov_read_wave }, -/* extra mp4 */ -{ MKTAG( 'M', 'D', 'E', 'S' ), mov_read_leaf }, -/* QT atoms */ -{ MKTAG( 'c', 'h', 'a', 'p' ), mov_read_leaf }, -{ MKTAG( 'c', 'l', 'i', 'p' ), mov_read_default }, -{ MKTAG( 'c', 'r', 'g', 'n' ), mov_read_leaf }, -{ MKTAG( 'c', 't', 'a', 'b' ), mov_read_ctab }, -{ MKTAG( 'e', 's', 'd', 's' ), mov_read_esds }, -{ MKTAG( 'k', 'm', 'a', 't' ), mov_read_leaf }, -{ MKTAG( 'm', 'a', 't', 't' ), mov_read_default }, -{ MKTAG( 'r', 'd', 'r', 'f' ), mov_read_leaf }, -{ MKTAG( 'r', 'm', 'd', 'a' ), mov_read_default }, -{ MKTAG( 'r', 'm', 'd', 'r' ), mov_read_leaf }, -{ MKTAG( 'r', 'm', 'r', 'a' ), mov_read_default }, -{ MKTAG( 's', 'c', 'p', 't' ), mov_read_leaf }, -{ MKTAG( 's', 's', 'r', 'c' ), mov_read_leaf }, -{ MKTAG( 's', 'y', 'n', 'c' ), mov_read_leaf }, -{ MKTAG( 't', 'c', 'm', 'd' ), mov_read_leaf }, -{ MKTAG( 'w', 'i', 'd', 'e' ), mov_read_wide }, /* place holder */ -//{ MKTAG( 'r', 'm', 'q', 'u' ), mov_read_leaf }, -{ MKTAG( 'c', 'm', 'o', 'v' ), mov_read_cmov }, -{ 0L, mov_read_leaf } -}; - -static void mov_free_stream_context(MOVStreamContext *sc) -{ - if(sc) { - av_freep(&sc->ctts_data); - av_freep(&sc); - } -} - -/* XXX: is it sufficient ? */ -static int mov_probe(AVProbeData *p) -{ - unsigned int offset; - uint32_t tag; - int score = 0; - - /* check file header */ - if (p->buf_size <= 12) - return 0; - offset = 0; - for(;;) { - /* ignore invalid offset */ - if ((offset + 8) > (unsigned int)p->buf_size) - return score; - tag = LE_32(p->buf + offset + 4); - switch(tag) { - /* check for obvious tags */ - case MKTAG( 'j', 'P', ' ', ' ' ): /* jpeg 2000 signature */ - case MKTAG( 'm', 'o', 'o', 'v' ): - case MKTAG( 'm', 'd', 'a', 't' ): - case MKTAG( 'p', 'n', 'o', 't' ): /* detect movs with preview pics like ew.mov and april.mov */ - case MKTAG( 'u', 'd', 't', 'a' ): /* Packet Video PVAuthor adds this and a lot of more junk */ - return AVPROBE_SCORE_MAX; - /* those are more common words, so rate then a bit less */ - case MKTAG( 'w', 'i', 'd', 'e' ): - case MKTAG( 'f', 'r', 'e', 'e' ): - case MKTAG( 'j', 'u', 'n', 'k' ): - case MKTAG( 'p', 'i', 'c', 't' ): - return AVPROBE_SCORE_MAX - 5; - case MKTAG( 'f', 't', 'y', 'p' ): - case MKTAG( 's', 'k', 'i', 'p' ): - case MKTAG( 'u', 'u', 'i', 'd' ): - offset = BE_32(p->buf+offset) + offset; - /* if we only find those cause probedata is too small at least rate them */ - score = AVPROBE_SCORE_MAX - 50; - break; - default: - /* unrecognized tag */ - return score; - } - } - return score; -} - -static void mov_build_index(MOVContext *mov, AVStream *st) -{ - MOVStreamContext *sc = st->priv_data; - offset_t current_offset; - int64_t current_dts = 0; - int stts_index = 0; - int stsc_index = 0; - int stss_index = 0; - int i, j, k; - - if (sc->sample_sizes || st->codec->codec_type == CODEC_TYPE_VIDEO || sc->dv_audio_container) { - int keyframe, sample_size; - int current_sample = 0; - int stts_sample = 0; - int distance = 0; - - st->nb_frames = sc->sample_count; - for (i = 0; i < sc->chunk_count; i++) { - current_offset = sc->chunk_offsets[i]; - if (stsc_index + 1 < sc->sample_to_chunk_sz && i + 1 == sc->sample_to_chunk[stsc_index + 1].first) - stsc_index++; - for (j = 0; j < sc->sample_to_chunk[stsc_index].count; j++) { - keyframe = !sc->keyframe_count || current_sample + 1 == sc->keyframes[stss_index]; - if (keyframe) { - distance = 0; - if (stss_index + 1 < sc->keyframe_count) - stss_index++; - } - sample_size = sc->sample_size > 0 ? sc->sample_size : sc->sample_sizes[current_sample]; - dprintf("AVIndex stream %d, sample %d, offset %llx, dts %lld, size %d, distance %d, keyframe %d\n", - st->index, current_sample, current_offset, current_dts, sample_size, distance, keyframe); - av_add_index_entry(st, current_offset, current_dts, sample_size, distance, keyframe ? AVINDEX_KEYFRAME : 0); - current_offset += sample_size; - assert(sc->stts_data[stts_index].duration % sc->time_rate == 0); - current_dts += sc->stts_data[stts_index].duration / sc->time_rate; - distance++; - stts_sample++; - if (current_sample + 1 < sc->sample_count) - current_sample++; - if (stts_index + 1 < sc->stts_count && stts_sample == sc->stts_data[stts_index].count) { - stts_sample = 0; - stts_index++; - } - } - } - } else { /* read whole chunk */ - int chunk_samples, chunk_size, chunk_duration; - - for (i = 0; i < sc->chunk_count; i++) { - current_offset = sc->chunk_offsets[i]; - if (stsc_index + 1 < sc->sample_to_chunk_sz && i + 1 == sc->sample_to_chunk[stsc_index + 1].first) - stsc_index++; - chunk_samples = sc->sample_to_chunk[stsc_index].count; - /* get chunk size */ - if (sc->sample_size > 1 || st->codec->codec_id == CODEC_ID_PCM_U8 || st->codec->codec_id == CODEC_ID_PCM_S8) - chunk_size = chunk_samples * sc->sample_size; - else if (sc->sample_size_v1.den > 0 && (chunk_samples * sc->sample_size_v1.num % sc->sample_size_v1.den == 0)) - chunk_size = chunk_samples * sc->sample_size_v1.num / sc->sample_size_v1.den; - else { /* workaround to find nearest next chunk offset */ - chunk_size = INT_MAX; - for (j = 0; j < mov->total_streams; j++) { - MOVStreamContext *msc = mov->streams[j]; - - for (k = msc->next_chunk; k < msc->chunk_count; k++) { - if (msc->chunk_offsets[k] > current_offset && msc->chunk_offsets[k] - current_offset < chunk_size) { - chunk_size = msc->chunk_offsets[k] - current_offset; - msc->next_chunk = k; - break; - } - } - } - /* check for last chunk */ - if (chunk_size == INT_MAX) - for (j = 0; j < mov->mdat_count; j++) { - dprintf("mdat %d, offset %llx, size %lld, current offset %llx\n", - j, mov->mdat_list[j].offset, mov->mdat_list[j].size, current_offset); - if (mov->mdat_list[j].offset <= current_offset && mov->mdat_list[j].offset + mov->mdat_list[j].size > current_offset) - chunk_size = mov->mdat_list[j].offset + mov->mdat_list[j].size - current_offset; - } - assert(chunk_size != INT_MAX); - for (j = 0; j < mov->total_streams; j++) { - mov->streams[j]->next_chunk = 0; - } - } - av_add_index_entry(st, current_offset, current_dts, chunk_size, 0, AVINDEX_KEYFRAME); - /* get chunk duration */ - chunk_duration = 0; - while (chunk_samples > 0) { - if (chunk_samples < sc->stts_data[stts_index].count) { - chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; - sc->stts_data[stts_index].count -= chunk_samples; - break; - } else { - chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; - chunk_samples -= sc->stts_data[stts_index].count; - if (stts_index + 1 < sc->stts_count) { - stts_index++; - } - } - } - dprintf("AVIndex stream %d, chunk %d, offset %llx, dts %lld, size %d, duration %d\n", - st->index, i, current_offset, current_dts, chunk_size, chunk_duration); - assert(chunk_duration % sc->time_rate == 0); - current_dts += chunk_duration / sc->time_rate; - } - } - /* adjust sample count to avindex entries */ - sc->sample_count = st->nb_index_entries; -} - -static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) -{ - MOVContext *mov = (MOVContext *) s->priv_data; - ByteIOContext *pb = &s->pb; - int i, err; - MOV_atom_t atom = { 0, 0, 0 }; - - mov->fc = s; - mov->parse_table = mov_default_parse_table; - - if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ - atom.size = url_fsize(pb); - else - atom.size = 0x7FFFFFFFFFFFFFFFLL; - - /* check MOV header */ - err = mov_read_default(mov, pb, atom); - if (err<0 || (!mov->found_moov && !mov->found_mdat)) { - av_log(s, AV_LOG_ERROR, "mov: header not found !!! (err:%d, moov:%d, mdat:%d) pos:%"PRId64"\n", - err, mov->found_moov, mov->found_mdat, url_ftell(pb)); - return -1; - } - dprintf("on_parse_exit_offset=%d\n", (int) url_ftell(pb)); - - /* some cleanup : make sure we are on the mdat atom */ - if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset)) - url_fseek(pb, mov->mdat_offset, SEEK_SET); - - mov->total_streams = s->nb_streams; - - for(i=0; itotal_streams; i++) { - MOVStreamContext *sc = mov->streams[i]; - - if(!sc->time_rate) - sc->time_rate=1; - if(!sc->time_scale) - sc->time_scale= mov->time_scale; - av_set_pts_info(s->streams[i], 64, sc->time_rate, sc->time_scale); - - if(s->streams[i]->duration != AV_NOPTS_VALUE){ - assert(s->streams[i]->duration % sc->time_rate == 0); - s->streams[i]->duration /= sc->time_rate; - } - sc->ffindex = i; - mov_build_index(mov, s->streams[i]); - } - - for(i=0; itotal_streams; i++) { - /* dont need those anymore */ - av_freep(&mov->streams[i]->chunk_offsets); - av_freep(&mov->streams[i]->sample_to_chunk); - av_freep(&mov->streams[i]->sample_sizes); - av_freep(&mov->streams[i]->keyframes); - av_freep(&mov->streams[i]->stts_data); - } - av_freep(&mov->mdat_list); - return 0; -} - -static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - MOVContext *mov = s->priv_data; - MOVStreamContext *sc = 0; - AVIndexEntry *sample = 0; - int64_t best_dts = INT64_MAX; - int i; - - for (i = 0; i < mov->total_streams; i++) { - MOVStreamContext *msc = mov->streams[i]; - - if (s->streams[i]->discard != AVDISCARD_ALL && msc->current_sample < msc->sample_count) { - AVIndexEntry *current_sample = &s->streams[i]->index_entries[msc->current_sample]; - int64_t dts = av_rescale(current_sample->timestamp * (int64_t)msc->time_rate, AV_TIME_BASE, msc->time_scale); - - dprintf("stream %d, sample %ld, dts %lld\n", i, msc->current_sample, dts); - if (dts < best_dts) { - sample = current_sample; - best_dts = dts; - sc = msc; - } - } - } - if (!sample) - return -1; - /* must be done just before reading, to avoid infinite loop on sample */ - sc->current_sample++; - if (sample->pos >= url_fsize(&s->pb)) { - av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n", sc->ffindex, sample->pos); - return -1; - } -#ifdef CONFIG_DV_DEMUXER - if (sc->dv_audio_container) { - dv_get_packet(mov->dv_demux, pkt); - dprintf("dv audio pkt size %d\n", pkt->size); - } else { -#endif - url_fseek(&s->pb, sample->pos, SEEK_SET); - av_get_packet(&s->pb, pkt, sample->size); -#ifdef CONFIG_DV_DEMUXER - if (mov->dv_demux) { - void *pkt_destruct_func = pkt->destruct; - dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size); - pkt->destruct = pkt_destruct_func; - } - } -#endif - pkt->stream_index = sc->ffindex; - pkt->dts = sample->timestamp; - if (sc->ctts_data) { - assert(sc->ctts_data[sc->sample_to_ctime_index].duration % sc->time_rate == 0); - pkt->pts = pkt->dts + sc->ctts_data[sc->sample_to_ctime_index].duration / sc->time_rate; - /* update ctts context */ - sc->sample_to_ctime_sample++; - if (sc->sample_to_ctime_index < sc->ctts_count && sc->ctts_data[sc->sample_to_ctime_index].count == sc->sample_to_ctime_sample) { - sc->sample_to_ctime_index++; - sc->sample_to_ctime_sample = 0; - } - } else { - pkt->pts = pkt->dts; - } - pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? PKT_FLAG_KEY : 0; - pkt->pos = sample->pos; - dprintf("stream %d, pts %lld, dts %lld, pos 0x%llx, duration %d\n", pkt->stream_index, pkt->pts, pkt->dts, pkt->pos, pkt->duration); - return 0; -} - -static int mov_seek_stream(AVStream *st, int64_t timestamp, int flags) -{ - MOVStreamContext *sc = st->priv_data; - int sample, time_sample; - int i; - - sample = av_index_search_timestamp(st, timestamp, flags); - dprintf("stream %d, timestamp %lld, sample %d\n", st->index, timestamp, sample); - if (sample < 0) /* not sure what to do */ - return -1; - sc->current_sample = sample; - dprintf("stream %d, found sample %ld\n", st->index, sc->current_sample); - /* adjust ctts index */ - if (sc->ctts_data) { - time_sample = 0; - for (i = 0; i < sc->ctts_count; i++) { - time_sample += sc->ctts_data[i].count; - if (time_sample >= sc->current_sample) { - sc->sample_to_ctime_index = i; - sc->sample_to_ctime_sample = time_sample - sc->current_sample; - break; - } - } - } - return sample; -} - -static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags) -{ - AVStream *st; - int64_t seek_timestamp, timestamp; - int sample; - int i; - - if (stream_index >= s->nb_streams) - return -1; - - st = s->streams[stream_index]; - sample = mov_seek_stream(st, sample_time, flags); - if (sample < 0) - return -1; - - /* adjust seek timestamp to found sample timestamp */ - seek_timestamp = st->index_entries[sample].timestamp; - - for (i = 0; i < s->nb_streams; i++) { - st = s->streams[i]; - if (stream_index == i || st->discard == AVDISCARD_ALL) - continue; - - timestamp = av_rescale_q(seek_timestamp, s->streams[stream_index]->time_base, st->time_base); - mov_seek_stream(st, timestamp, flags); - } - return 0; -} - -static int mov_read_close(AVFormatContext *s) -{ - int i; - MOVContext *mov = (MOVContext *) s->priv_data; - for(i=0; itotal_streams; i++) - mov_free_stream_context(mov->streams[i]); - /* free color tabs */ - for(i=0; ictab_size; i++) - av_freep(&mov->ctab[i]); - if(mov->dv_demux){ - for(i=0; idv_fctx->nb_streams; i++){ - av_freep(&mov->dv_fctx->streams[i]->codec); - av_freep(&mov->dv_fctx->streams[i]); - } - av_freep(&mov->dv_fctx); - av_freep(&mov->dv_demux); - } - av_freep(&mov->ctab); - return 0; -} - -AVInputFormat mov_demuxer = { - "mov,mp4,m4a,3gp,3g2,mj2", - "QuickTime/MPEG4/Motion JPEG 2000 format", - sizeof(MOVContext), - mov_probe, - mov_read_header, - mov_read_packet, - mov_read_close, - mov_read_seek, -}; diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/movenc.c --- a/src/ffmpeg/libavformat/movenc.c Mon Mar 12 14:49:42 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1674 +0,0 @@ -/* - * MOV, 3GP, MP4 encoder. - * Copyright (c) 2003 Thomas Raivio. - * Copyright (c) 2004 Gildas Bazin . - * - * 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 "avformat.h" -#include "riff.h" -#include "avio.h" -#include "isom.h" - -#undef NDEBUG -#include - -#define MOV_INDEX_CLUSTER_SIZE 16384 -#define globalTimescale 1000 - -#define MODE_MP4 0 -#define MODE_MOV 1 -#define MODE_3GP 2 -#define MODE_PSP 3 // example working PSP command line: -// ffmpeg -i testinput.avi -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4 -#define MODE_3G2 4 - -typedef struct MOVIentry { - unsigned int flags, size; - uint64_t pos; - unsigned int samplesInChunk; - char key_frame; - unsigned int entries; - int64_t cts; -} MOVIentry; - -typedef struct MOVIndex { - int mode; - int entry; - long timescale; - long time; - int64_t trackDuration; - long sampleCount; - long sampleDuration; - long sampleSize; - int hasKeyframes; - int hasBframes; - int language; - int trackID; - int tag; - AVCodecContext *enc; - - int vosLen; - uint8_t *vosData; - MOVIentry *cluster; -} MOVTrack; - -typedef struct MOVContext { - int mode; - int64_t time; - int nb_streams; - offset_t mdat_pos; - uint64_t mdat_size; - long timescale; - MOVTrack tracks[MAX_STREAMS]; -} MOVContext; - -//FIXME supprt 64bit varaint with wide placeholders -static offset_t updateSize (ByteIOContext *pb, offset_t pos) -{ - offset_t curpos = url_ftell(pb); - url_fseek(pb, pos, SEEK_SET); - put_be32(pb, curpos - pos); /* rewrite size */ - url_fseek(pb, curpos, SEEK_SET); - - return curpos - pos; -} - -/* Chunk offset atom */ -static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track) -{ - int i; - int mode64 = 0; // use 32 bit size variant if possible - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - if (pos > UINT32_MAX) { - mode64 = 1; - put_tag(pb, "co64"); - } else - put_tag(pb, "stco"); - put_be32(pb, 0); /* version & flags */ - put_be32(pb, track->entry); /* entry count */ - for (i=0; ientry; i++) { - if(mode64 == 1) - put_be64(pb, track->cluster[i].pos); - else - put_be32(pb, track->cluster[i].pos); - } - return updateSize (pb, pos); -} - -/* Sample size atom */ -static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track) -{ - int equalChunks = 1; - int i, j, entries = 0, tst = -1, oldtst = -1; - - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "stsz"); - put_be32(pb, 0); /* version & flags */ - - for (i=0; ientry; i++) { - tst = track->cluster[i].size/track->cluster[i].entries; - if(oldtst != -1 && tst != oldtst) { - equalChunks = 0; - } - oldtst = tst; - entries += track->cluster[i].entries; - } - if (equalChunks) { - int sSize = track->cluster[0].size/track->cluster[0].entries; - put_be32(pb, sSize); // sample size - put_be32(pb, entries); // sample count - } - else { - put_be32(pb, 0); // sample size - put_be32(pb, entries); // sample count - for (i=0; ientry; i++) { - for ( j=0; jcluster[i].entries; j++) { - put_be32(pb, track->cluster[i].size / - track->cluster[i].entries); - } - } - } - return updateSize (pb, pos); -} - -/* Sample to chunk atom */ -static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track) -{ - int index = 0, oldval = -1, i; - offset_t entryPos, curpos; - - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "stsc"); - put_be32(pb, 0); // version & flags - entryPos = url_ftell(pb); - put_be32(pb, track->entry); // entry count - for (i=0; ientry; i++) { - if(oldval != track->cluster[i].samplesInChunk) - { - put_be32(pb, i+1); // first chunk - put_be32(pb, track->cluster[i].samplesInChunk); // samples per chunk - put_be32(pb, 0x1); // sample description index - oldval = track->cluster[i].samplesInChunk; - index++; - } - } - curpos = url_ftell(pb); - url_fseek(pb, entryPos, SEEK_SET); - put_be32(pb, index); // rewrite size - url_fseek(pb, curpos, SEEK_SET); - - return updateSize (pb, pos); -} - -/* Sync sample atom */ -static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track) -{ - offset_t curpos, entryPos; - int i, index = 0; - offset_t pos = url_ftell(pb); - put_be32(pb, 0); // size - put_tag(pb, "stss"); - put_be32(pb, 0); // version & flags - entryPos = url_ftell(pb); - put_be32(pb, track->entry); // entry count - for (i=0; ientry; i++) { - if(track->cluster[i].key_frame == 1) { - put_be32(pb, i+1); - index++; - } - } - curpos = url_ftell(pb); - url_fseek(pb, entryPos, SEEK_SET); - put_be32(pb, index); // rewrite size - url_fseek(pb, curpos, SEEK_SET); - return updateSize (pb, pos); -} - -static int mov_write_amr_tag(ByteIOContext *pb, MOVTrack *track) -{ - put_be32(pb, 0x11); /* size */ - if (track->mode == MODE_MOV) put_tag(pb, "samr"); - else put_tag(pb, "damr"); - put_tag(pb, "FFMP"); - put_byte(pb, 0); /* decoder version */ - - put_be16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */ - put_byte(pb, 0x00); /* Mode change period (no restriction) */ - put_byte(pb, 0x01); /* Frames per sample */ - return 0x11; -} - -static int mov_write_enda_tag(ByteIOContext *pb) -{ - put_be32(pb, 10); - put_tag(pb, "enda"); - put_be16(pb, 1); /* little endian */ - return 10; -} - -static unsigned int descrLength(unsigned int len) -{ - int i; - for(i=1; len>>(7*i); i++); - return len + 1 + i; -} - -static void putDescr(ByteIOContext *pb, int tag, unsigned int size) -{ - int i= descrLength(size) - size - 2; - put_byte(pb, tag); - for(; i>0; i--) - put_byte(pb, (size>>(7*i)) | 0x80); - put_byte(pb, size & 0x7F); -} - -static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic -{ - offset_t pos = url_ftell(pb); - int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0; - - put_be32(pb, 0); // size - put_tag(pb, "esds"); - put_be32(pb, 0); // Version - - // ES descriptor - putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) + - descrLength(1)); - put_be16(pb, track->trackID); - put_byte(pb, 0x00); // flags (= no flags) - - // DecoderConfig descriptor - putDescr(pb, 0x04, 13 + decoderSpecificInfoLen); - - // Object type indication - put_byte(pb, codec_get_tag(ff_mov_obj_type, track->enc->codec_id)); - - // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio) - // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved) - if(track->enc->codec_type == CODEC_TYPE_AUDIO) - put_byte(pb, 0x15); // flags (= Audiostream) - else - put_byte(pb, 0x11); // flags (= Visualstream) - - put_byte(pb, track->enc->rc_buffer_size>>(3+16)); // Buffersize DB (24 bits) - put_be16(pb, (track->enc->rc_buffer_size>>3)&0xFFFF); // Buffersize DB - - put_be32(pb, FFMAX(track->enc->bit_rate, track->enc->rc_max_rate)); // maxbitrate (FIXME should be max rate in any 1 sec window) - if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0) - put_be32(pb, 0); // vbr - else - put_be32(pb, track->enc->rc_max_rate); // avg bitrate - - if (track->vosLen) - { - // DecoderSpecific info descriptor - putDescr(pb, 0x05, track->vosLen); - put_buffer(pb, track->vosData, track->vosLen); - } - - - // SL descriptor - putDescr(pb, 0x06, 1); - put_byte(pb, 0x02); - return updateSize (pb, pos); -} - -static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track) -{ - offset_t pos = url_ftell(pb); - - put_be32(pb, 0); /* size */ - put_tag(pb, "wave"); - - put_be32(pb, 12); /* size */ - put_tag(pb, "frma"); - put_le32(pb, track->tag); - - if (track->enc->codec_id == CODEC_ID_AAC) { - /* useless atom needed by mplayer, ipod, not needed by quicktime */ - put_be32(pb, 12); /* size */ - put_tag(pb, "mp4a"); - put_be32(pb, 0); - mov_write_esds_tag(pb, track); - } else if (track->enc->codec_id == CODEC_ID_PCM_S24LE || - track->enc->codec_id == CODEC_ID_PCM_S32LE) { - mov_write_enda_tag(pb); - } else if (track->enc->codec_id == CODEC_ID_AMR_NB) { - mov_write_amr_tag(pb, track); - } - - put_be32(pb, 8); /* size */ - put_be32(pb, 0); /* null tag */ - - return updateSize (pb, pos); -} - -static const CodecTag codec_movaudio_tags[] = { - { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, - { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, - { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') }, - { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') }, - { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') }, - { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') }, - { CODEC_ID_AMR_NB, MKTAG('s', 'a', 'm', 'r') }, - { CODEC_ID_AMR_WB, MKTAG('s', 'a', 'w', 'b') }, - { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, - { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, - { CODEC_ID_PCM_S24BE, MKTAG('i', 'n', '2', '4') }, - { CODEC_ID_PCM_S24LE, MKTAG('i', 'n', '2', '4') }, - { CODEC_ID_PCM_S32BE, MKTAG('i', 'n', '3', '2') }, - { CODEC_ID_PCM_S32LE, MKTAG('i', 'n', '3', '2') }, - { CODEC_ID_MP3, MKTAG('.', 'm', 'p', '3') }, - { CODEC_ID_NONE, 0 }, -}; - -static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track) -{ - offset_t pos = url_ftell(pb); - int vbr= track->mode == MODE_MOV && - (track->enc->codec_id == CODEC_ID_AAC || - track->enc->codec_id == CODEC_ID_MP3 || - track->enc->codec_id == CODEC_ID_AMR_NB); - int version = vbr || - track->enc->codec_id == CODEC_ID_PCM_S32LE || - track->enc->codec_id == CODEC_ID_PCM_S24LE; - - put_be32(pb, 0); /* size */ - put_le32(pb, track->tag); // store it byteswapped - put_be32(pb, 0); /* Reserved */ - put_be16(pb, 0); /* Reserved */ - put_be16(pb, 1); /* Data-reference index, XXX == 1 */ - - /* SoundDescription */ - put_be16(pb, version); /* Version */ - put_be16(pb, 0); /* Revision level */ - put_be32(pb, 0); /* Reserved */ - - put_be16(pb, track->mode == MODE_MOV ? track->enc->channels : 2); /* Number of channels */ - /* FIXME 8 bit for 'raw ' in mov */ - put_be16(pb, 16); /* Reserved */ - - put_be16(pb, vbr ? 0xfffe : 0); /* compression ID */ - put_be16(pb, 0); /* packet size (= 0) */ - put_be16(pb, track->timescale); /* Time scale */ - put_be16(pb, 0); /* Reserved */ - - if(version == 1) { /* SoundDescription V1 extended info */ - if (vbr) - track->sampleSize = 0; - put_be32(pb, track->enc->frame_size); /* Samples per packet */ - put_be32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */ - put_be32(pb, track->sampleSize); /* Bytes per frame */ - put_be32(pb, 2); /* Bytes per sample */ - } - - if(track->mode == MODE_MOV && - (track->enc->codec_id == CODEC_ID_AAC || - track->enc->codec_id == CODEC_ID_AMR_NB || - track->enc->codec_id == CODEC_ID_PCM_S24LE || - track->enc->codec_id == CODEC_ID_PCM_S32LE)) - mov_write_wave_tag(pb, track); - else if(track->enc->codec_id == CODEC_ID_AAC) - mov_write_esds_tag(pb, track); - else if(track->enc->codec_id == CODEC_ID_AMR_NB) - mov_write_amr_tag(pb, track); - - return updateSize (pb, pos); -} - -static int mov_write_d263_tag(ByteIOContext *pb) -{ - put_be32(pb, 0xf); /* size */ - put_tag(pb, "d263"); - put_tag(pb, "FFMP"); - put_byte(pb, 0); /* decoder version */ - /* FIXME use AVCodecContext level/profile, when encoder will set values */ - put_byte(pb, 0xa); /* level */ - put_byte(pb, 0); /* profile */ - return 0xf; -} - -/* TODO: No idea about these values */ -static int mov_write_svq3_tag(ByteIOContext *pb) -{ - put_be32(pb, 0x15); - put_tag(pb, "SMI "); - put_tag(pb, "SEQH"); - put_be32(pb, 0x5); - put_be32(pb, 0xe2c0211d); - put_be32(pb, 0xc0000000); - put_byte(pb, 0); - return 0x15; -} - -static uint8_t *avc_find_startcode( uint8_t *p, uint8_t *end ) -{ - uint8_t *a = p + 4 - ((int)p & 3); - - for( end -= 3; p < a && p < end; p++ ) { - if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) - return p; - } - - for( end -= 3; p < end; p += 4 ) { - uint32_t x = *(uint32_t*)p; -// if( (x - 0x01000100) & (~x) & 0x80008000 ) // little endian -// if( (x - 0x00010001) & (~x) & 0x00800080 ) // big endian - if( (x - 0x01010101) & (~x) & 0x80808080 ) { // generic - if( p[1] == 0 ) { - if( p[0] == 0 && p[2] == 1 ) - return p-1; - if( p[2] == 0 && p[3] == 1 ) - return p; - } - if( p[3] == 0 ) { - if( p[2] == 0 && p[4] == 1 ) - return p+1; - if( p[4] == 0 && p[5] == 1 ) - return p+2; - } - } - } - - for( end += 3; p < end; p++ ) { - if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) - return p; - } - - return end + 3; -} - -static void avc_parse_nal_units(uint8_t **buf, int *size) -{ - ByteIOContext pb; - uint8_t *p = *buf; - uint8_t *end = p + *size; - uint8_t *nal_start, *nal_end; - - url_open_dyn_buf(&pb); - nal_start = avc_find_startcode(p, end); - while (nal_start < end) { - while(!*(nal_start++)); - nal_end = avc_find_startcode(nal_start, end); - put_be32(&pb, nal_end - nal_start); - put_buffer(&pb, nal_start, nal_end - nal_start); - nal_start = nal_end; - } - av_freep(buf); - *size = url_close_dyn_buf(&pb, buf); -} - -static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track) -{ - offset_t pos = url_ftell(pb); - - put_be32(pb, 0); - put_tag(pb, "avcC"); - if (track->vosLen > 6) { - /* check for h264 start code */ - if (BE_32(track->vosData) == 0x00000001) { - uint8_t *buf, *end; - uint32_t sps_size=0, pps_size=0; - uint8_t *sps=0, *pps=0; - - avc_parse_nal_units(&track->vosData, &track->vosLen); - buf = track->vosData; - end = track->vosData + track->vosLen; - - /* look for sps and pps */ - while (buf < end) { - unsigned int size; - uint8_t nal_type; - size = BE_32(buf); - nal_type = buf[4] & 0x1f; - if (nal_type == 7) { /* SPS */ - sps = buf + 4; - sps_size = size; - } else if (nal_type == 8) { /* PPS */ - pps = buf + 4; - pps_size = size; - } - buf += size + 4; - } - assert(sps); - assert(pps); - - put_byte(pb, 1); /* version */ - put_byte(pb, sps[1]); /* profile */ - put_byte(pb, sps[2]); /* profile compat */ - put_byte(pb, sps[3]); /* level */ - put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ - put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ - - put_be16(pb, sps_size); - put_buffer(pb, sps, sps_size); - put_byte(pb, 1); /* number of pps */ - put_be16(pb, pps_size); - put_buffer(pb, pps, pps_size); - } else { - put_buffer(pb, track->vosData, track->vosLen); - } - } - return updateSize(pb, pos); -} - -static const CodecTag codec_movvideo_tags[] = { - { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') }, - { CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') }, - { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') }, - { CODEC_ID_H263, MKTAG('h', '2', '6', '3') }, - { CODEC_ID_H263, MKTAG('s', '2', '6', '3') }, - { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, - /* special handling in mov_find_video_codec_tag */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'p', 'p') }, /* DVCPRO PAL */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'n') }, /* DVCPRO50 NTSC */ - { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'p') }, /* DVCPRO50 PAL */ - { CODEC_ID_NONE, 0 }, -}; - -static int mov_find_video_codec_tag(AVFormatContext *s, MOVTrack *track) -{ - int tag = track->enc->codec_tag; - if (!tag) { - if (track->enc->codec_id == CODEC_ID_DVVIDEO) { - if (track->enc->height == 480) { /* NTSC */ - if (track->enc->pix_fmt == PIX_FMT_YUV422P) - tag = MKTAG('d', 'v', '5', 'n'); - else - tag = MKTAG('d', 'v', 'c', ' '); - } else { /* assume PAL */ - if (track->enc->pix_fmt == PIX_FMT_YUV422P) - tag = MKTAG('d', 'v', '5', 'p'); - else if (track->enc->pix_fmt == PIX_FMT_YUV420P) - tag = MKTAG('d', 'v', 'c', 'p'); - else - tag = MKTAG('d', 'v', 'p', 'p'); - } - } else if (track->enc->codec_id == CODEC_ID_H263) { - if (track->mode == MODE_MOV) - tag = MKTAG('h', '2', '6', '3'); - else - tag = MKTAG('s', '2', '6', '3'); - } else { - tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id); - } - } - // if no mac fcc found, try with Microsoft tags - if (!tag) { - tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id); - if (tag) { - av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, the file may be unplayable!\n"); - } - } - assert(tag); - return tag; -} - -static int mov_find_audio_codec_tag(AVFormatContext *s, MOVTrack *track) -{ - int tag = track->enc->codec_tag; - if (!tag) { - tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id); - } - // if no mac fcc found, try with Microsoft tags - if (!tag) { - int ms_tag = codec_get_tag(codec_wav_tags, track->enc->codec_id); - if (ms_tag) { - tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff)); - av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, the file may be unplayable!\n"); - } - } - assert(tag); - return tag; -} - -static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track) -{ - offset_t pos = url_ftell(pb); - char compressor_name[32]; - - put_be32(pb, 0); /* size */ - put_le32(pb, track->tag); // store it byteswapped - put_be32(pb, 0); /* Reserved */ - put_be16(pb, 0); /* Reserved */ - put_be16(pb, 1); /* Data-reference index */ - - put_be16(pb, 0); /* Codec stream version */ - put_be16(pb, 0); /* Codec stream revision (=0) */ - if (track->mode == MODE_MOV) { - put_tag(pb, "FFMP"); /* Vendor */ - if(track->enc->codec_id == CODEC_ID_RAWVIDEO) { - put_be32(pb, 0); /* Temporal Quality */ - put_be32(pb, 0x400); /* Spatial Quality = lossless*/ - } else { - put_be32(pb, 0x200); /* Temporal Quality = normal */ - put_be32(pb, 0x200); /* Spatial Quality = normal */ - } - } else { - put_be32(pb, 0); /* Reserved */ - put_be32(pb, 0); /* Reserved */ - put_be32(pb, 0); /* Reserved */ - } - put_be16(pb, track->enc->width); /* Video width */ - put_be16(pb, track->enc->height); /* Video height */ - put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */ - put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */ - put_be32(pb, 0); /* Data size (= 0) */ - put_be16(pb, 1); /* Frame count (= 1) */ - - memset(compressor_name,0,32); - /* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */ - if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name) - strncpy(compressor_name,track->enc->codec->name,31); - put_byte(pb, strlen(compressor_name)); - put_buffer(pb, compressor_name, 31); - - put_be16(pb, 0x18); /* Reserved */ - put_be16(pb, 0xffff); /* Reserved */ - if(track->enc->codec_id == CODEC_ID_MPEG4) - mov_write_esds_tag(pb, track); - else if(track->enc->codec_id == CODEC_ID_H263) - mov_write_d263_tag(pb); - else if(track->enc->codec_id == CODEC_ID_SVQ3) - mov_write_svq3_tag(pb); - else if(track->enc->codec_id == CODEC_ID_H264) - mov_write_avcc_tag(pb, track); - - return updateSize (pb, pos); -} - -static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track) -{ - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "stsd"); - put_be32(pb, 0); /* version & flags */ - put_be32(pb, 1); /* entry count */ - if (track->enc->codec_type == CODEC_TYPE_VIDEO) - mov_write_video_tag(pb, track); - else if (track->enc->codec_type == CODEC_TYPE_AUDIO) - mov_write_audio_tag(pb, track); - return updateSize(pb, pos); -} - -static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack* track) -{ - Time2Sample *ctts_entries; - uint32_t entries = 0; - uint32_t atom_size; - int i; - - ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */ - ctts_entries[0].count = 1; - ctts_entries[0].duration = track->cluster[0].cts; - for (i=1; ientry; i++) { - if (track->cluster[i].cts == ctts_entries[entries].duration) { - ctts_entries[entries].count++; /* compress */ - } else { - entries++; - ctts_entries[entries].duration = track->cluster[i].cts; - ctts_entries[entries].count = 1; - } - } - entries++; /* last one */ - atom_size = 16 + (entries * 8); - put_be32(pb, atom_size); /* size */ - put_tag(pb, "ctts"); - put_be32(pb, 0); /* version & flags */ - put_be32(pb, entries); /* entry count */ - for (i=0; isampleCount); /* sample count */ - put_be32(pb, track->sampleDuration); /* sample duration */ - return 0x18; -} - -static int mov_write_dref_tag(ByteIOContext *pb) -{ - put_be32(pb, 28); /* size */ - put_tag(pb, "dref"); - put_be32(pb, 0); /* version & flags */ - put_be32(pb, 1); /* entry count */ - - put_be32(pb, 0xc); /* size */ - put_tag(pb, "url "); - put_be32(pb, 1); /* version & flags */ - - return 28; -} - -static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track) -{ - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "stbl"); - mov_write_stsd_tag(pb, track); - mov_write_stts_tag(pb, track); - if (track->enc->codec_type == CODEC_TYPE_VIDEO && - track->hasKeyframes < track->entry) - mov_write_stss_tag(pb, track); - if (track->enc->codec_type == CODEC_TYPE_VIDEO && - track->hasBframes) - mov_write_ctts_tag(pb, track); - mov_write_stsc_tag(pb, track); - mov_write_stsz_tag(pb, track); - mov_write_stco_tag(pb, track); - return updateSize(pb, pos); -} - -static int mov_write_dinf_tag(ByteIOContext *pb) -{ - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "dinf"); - mov_write_dref_tag(pb); - return updateSize(pb, pos); -} - -static int mov_write_smhd_tag(ByteIOContext *pb) -{ - put_be32(pb, 16); /* size */ - put_tag(pb, "smhd"); - put_be32(pb, 0); /* version & flags */ - put_be16(pb, 0); /* reserved (balance, normally = 0) */ - put_be16(pb, 0); /* reserved */ - return 16; -} - -static int mov_write_vmhd_tag(ByteIOContext *pb) -{ - put_be32(pb, 0x14); /* size (always 0x14) */ - put_tag(pb, "vmhd"); - put_be32(pb, 0x01); /* version & flags */ - put_be64(pb, 0); /* reserved (graphics mode = copy) */ - return 0x14; -} - -static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track) -{ - const char *descr, *hdlr, *hdlr_type; - offset_t pos = url_ftell(pb); - - if (!track) { /* no media --> data handler */ - hdlr = "dhlr"; - hdlr_type = "url "; - descr = "DataHandler"; - } else { - hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0"; - if (track->enc->codec_type == CODEC_TYPE_VIDEO) { - hdlr_type = "vide"; - descr = "VideoHandler"; - } else { - hdlr_type = "soun"; - descr = "SoundHandler"; - } - } - - put_be32(pb, 0); /* size */ - put_tag(pb, "hdlr"); - put_be32(pb, 0); /* Version & flags */ - put_buffer(pb, hdlr, 4); /* handler */ - put_tag(pb, hdlr_type); /* handler type */ - put_be32(pb ,0); /* reserved */ - put_be32(pb ,0); /* reserved */ - put_be32(pb ,0); /* reserved */ - put_byte(pb, strlen(descr)); /* string counter */ - put_buffer(pb, descr, strlen(descr)); /* handler description */ - return updateSize(pb, pos); -} - -static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track) -{ - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "minf"); - if(track->enc->codec_type == CODEC_TYPE_VIDEO) - mov_write_vmhd_tag(pb); - else - mov_write_smhd_tag(pb); - if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */ - mov_write_hdlr_tag(pb, NULL); - mov_write_dinf_tag(pb); - mov_write_stbl_tag(pb, track); - return updateSize(pb, pos); -} - -static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track) -{ - int version = track->trackDuration < INT32_MAX ? 0 : 1; - - (version == 1) ? put_be32(pb, 44) : put_be32(pb, 32); /* size */ - put_tag(pb, "mdhd"); - put_byte(pb, version); - put_be24(pb, 0); /* flags */ - if (version == 1) { - put_be64(pb, track->time); - put_be64(pb, track->time); - } else { - put_be32(pb, track->time); /* creation time */ - put_be32(pb, track->time); /* modification time */ - } - put_be32(pb, track->timescale); /* time scale (sample rate for audio) */ - (version == 1) ? put_be64(pb, track->trackDuration) : put_be32(pb, track->trackDuration); /* duration */ - put_be16(pb, track->language); /* language */ - put_be16(pb, 0); /* reserved (quality) */ - return 32; -} - -static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track) -{ - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "mdia"); - mov_write_mdhd_tag(pb, track); - mov_write_hdlr_tag(pb, track); - mov_write_minf_tag(pb, track); - return updateSize(pb, pos); -} - -static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track) -{ - int64_t duration = av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP); - int version = duration < INT32_MAX ? 0 : 1; - - (version == 1) ? put_be32(pb, 104) : put_be32(pb, 92); /* size */ - put_tag(pb, "tkhd"); - put_byte(pb, version); - put_be24(pb, 0xf); /* flags (track enabled) */ - if (version == 1) { - put_be64(pb, track->time); - put_be64(pb, track->time); - } else { - put_be32(pb, track->time); /* creation time */ - put_be32(pb, track->time); /* modification time */ - } - put_be32(pb, track->trackID); /* track-id */ - put_be32(pb, 0); /* reserved */ - (version == 1) ? put_be64(pb, duration) : put_be32(pb, duration); - - put_be32(pb, 0); /* reserved */ - put_be32(pb, 0); /* reserved */ - put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */ - /* Volume, only for audio */ - if(track->enc->codec_type == CODEC_TYPE_AUDIO) - put_be16(pb, 0x0100); - else - put_be16(pb, 0); - put_be16(pb, 0); /* reserved */ - - /* Matrix structure */ - put_be32(pb, 0x00010000); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x00010000); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x40000000); /* reserved */ - - /* Track width and height, for visual only */ - if(track->enc->codec_type == CODEC_TYPE_VIDEO) { - double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio); - if( !sample_aspect_ratio ) sample_aspect_ratio = 1; - put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000); - put_be32(pb, track->enc->height*0x10000); - } - else { - put_be32(pb, 0); - put_be32(pb, 0); - } - return 0x5c; -} - -// This box seems important for the psp playback ... without it the movie seems to hang -static int mov_write_edts_tag(ByteIOContext *pb, MOVTrack *track) -{ - put_be32(pb, 0x24); /* size */ - put_tag(pb, "edts"); - put_be32(pb, 0x1c); /* size */ - put_tag(pb, "elst"); - put_be32(pb, 0x0); - put_be32(pb, 0x1); - - put_be32(pb, av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP)); /* duration ... doesn't seem to effect psp */ - - put_be32(pb, track->cluster[0].cts); /* first pts is cts since dts is 0 */ - put_be32(pb, 0x00010000); - return 0x24; -} - -// goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it) -static int mov_write_uuid_tag_psp(ByteIOContext *pb, MOVTrack *mov) -{ - put_be32(pb, 0x34); /* size ... reports as 28 in mp4box! */ - put_tag(pb, "uuid"); - put_tag(pb, "USMT"); - put_be32(pb, 0x21d24fce); - put_be32(pb, 0xbb88695c); - put_be32(pb, 0xfac9c740); - put_be32(pb, 0x1c); // another size here! - put_tag(pb, "MTDT"); - put_be32(pb, 0x00010012); - put_be32(pb, 0x0a); - put_be32(pb, 0x55c40000); - put_be32(pb, 0x1); - put_be32(pb, 0x0); - return 0x34; -} - -static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track) -{ - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "trak"); - mov_write_tkhd_tag(pb, track); - if (track->mode == MODE_PSP || track->hasBframes) - mov_write_edts_tag(pb, track); // PSP Movies require edts box - mov_write_mdia_tag(pb, track); - if (track->mode == MODE_PSP) - mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box - return updateSize(pb, pos); -} - -#if 0 -/* TODO: Not sorted out, but not necessary either */ -static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov) -{ - put_be32(pb, 0x15); /* size */ - put_tag(pb, "iods"); - put_be32(pb, 0); /* version & flags */ - put_be16(pb, 0x1007); - put_byte(pb, 0); - put_be16(pb, 0x4fff); - put_be16(pb, 0xfffe); - put_be16(pb, 0x01ff); - return 0x15; -} -#endif - -static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov) -{ - int maxTrackID = 1, i; - int64_t maxTrackLenTemp, maxTrackLen = 0; - int version; - - for (i=0; inb_streams; i++) { - if(mov->tracks[i].entry > 0) { - maxTrackLenTemp = av_rescale_rnd(mov->tracks[i].trackDuration, globalTimescale, mov->tracks[i].timescale, AV_ROUND_UP); - if(maxTrackLen < maxTrackLenTemp) - maxTrackLen = maxTrackLenTemp; - if(maxTrackID < mov->tracks[i].trackID) - maxTrackID = mov->tracks[i].trackID; - } - } - - version = maxTrackLen < UINT32_MAX ? 0 : 1; - (version == 1) ? put_be32(pb, 120) : put_be32(pb, 108); /* size */ - put_tag(pb, "mvhd"); - put_byte(pb, version); - put_be24(pb, 0); /* flags */ - if (version == 1) { - put_be64(pb, mov->time); - put_be64(pb, mov->time); - } else { - put_be32(pb, mov->time); /* creation time */ - put_be32(pb, mov->time); /* modification time */ - } - put_be32(pb, mov->timescale); /* timescale */ - (version == 1) ? put_be64(pb, maxTrackLen) : put_be32(pb, maxTrackLen); /* duration of longest track */ - - put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */ - put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */ - put_be16(pb, 0); /* reserved */ - put_be32(pb, 0); /* reserved */ - put_be32(pb, 0); /* reserved */ - - /* Matrix structure */ - put_be32(pb, 0x00010000); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x00010000); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x0); /* reserved */ - put_be32(pb, 0x40000000); /* reserved */ - - put_be32(pb, 0); /* reserved (preview time) */ - put_be32(pb, 0); /* reserved (preview duration) */ - put_be32(pb, 0); /* reserved (poster time) */ - put_be32(pb, 0); /* reserved (selection time) */ - put_be32(pb, 0); /* reserved (selection duration) */ - put_be32(pb, 0); /* reserved (current time) */ - put_be32(pb, maxTrackID+1); /* Next track id */ - return 0x6c; -} - -static int mov_write_itunes_hdlr_tag(ByteIOContext *pb, MOVContext* mov, - AVFormatContext *s) -{ - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "hdlr"); - put_be32(pb, 0); - put_be32(pb, 0); - put_tag(pb, "mdir"); - put_tag(pb, "appl"); - put_be32(pb, 0); - put_be32(pb, 0); - put_be16(pb, 0); - return updateSize(pb, pos); -} - -/* helper function to write a data tag with the specified string as data */ -static int mov_write_string_data_tag(ByteIOContext *pb, const char *data, int long_style) -{ - if(long_style){ - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "data"); - put_be32(pb, 1); - put_be32(pb, 0); - put_buffer(pb, data, strlen(data)); - return updateSize(pb, pos); - }else{ - put_be16(pb, strlen(data)); /* string length */ - put_be16(pb, 0); - put_buffer(pb, data, strlen(data)); - return strlen(data) + 4; - } -} - -static int mov_write_string_tag(ByteIOContext *pb, const char *name, const char *value, int long_style){ - int size = 0; - if ( value && value[0] ) { - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, name); - mov_write_string_data_tag(pb, value, long_style); - size= updateSize(pb, pos); - } - return size; -} - -/* iTunes year */ -static int mov_write_day_tag(ByteIOContext *pb, int year, int long_style) -{ - if(year){ - char year_str[5]; - snprintf(year_str, sizeof(year_str), "%04d", year); - return mov_write_string_tag(pb, "\251day", year_str, long_style); - }else - return 0; -} - -/* iTunes track number */ -static int mov_write_trkn_tag(ByteIOContext *pb, MOVContext* mov, - AVFormatContext *s) -{ - int size = 0; - if ( s->track ) { - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "trkn"); - { - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "data"); - put_be32(pb, 0); // 8 bytes empty - put_be32(pb, 0); - put_be16(pb, 0); // empty - put_be16(pb, s->track); // track number - put_be16(pb, 0); // total track number - put_be16(pb, 0); // empty - updateSize(pb, pos); - } - size = updateSize(pb, pos); - } - return size; -} - -/* iTunes meta data list */ -static int mov_write_ilst_tag(ByteIOContext *pb, MOVContext* mov, - AVFormatContext *s) -{ - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "ilst"); - mov_write_string_tag(pb, "\251nam", s->title , 1); - mov_write_string_tag(pb, "\251ART", s->author , 1); - mov_write_string_tag(pb, "\251wrt", s->author , 1); - mov_write_string_tag(pb, "\251alb", s->album , 1); - mov_write_day_tag(pb, s->year ,1); - if(mov->tracks[0].enc && !(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT)) - mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 1); - mov_write_string_tag(pb, "\251cmt", s->comment , 1); - mov_write_string_tag(pb, "\251gen", s->genre , 1); - mov_write_trkn_tag(pb, mov, s); - return updateSize(pb, pos); -} - -/* iTunes meta data tag */ -static int mov_write_meta_tag(ByteIOContext *pb, MOVContext* mov, - AVFormatContext *s) -{ - int size = 0; - - // only save meta tag if required - if ( s->title[0] || s->author[0] || s->album[0] || s->year || - s->comment[0] || s->genre[0] || s->track ) { - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size */ - put_tag(pb, "meta"); - put_be32(pb, 0); - mov_write_itunes_hdlr_tag(pb, mov, s); - mov_write_ilst_tag(pb, mov, s); - size = updateSize(pb, pos); - } - return size; -} - -static int mov_write_udta_tag(ByteIOContext *pb, MOVContext* mov, - AVFormatContext *s) -{ - offset_t pos = url_ftell(pb); - int i; - - put_be32(pb, 0); /* size */ - put_tag(pb, "udta"); - - /* iTunes meta data */ - mov_write_meta_tag(pb, mov, s); - - if(mov->mode == MODE_MOV){ // the title field breaks gtkpod with mp4 and my suspicion is that stuff isnt valid in mp4 - /* Requirements */ - for (i=0; inb_streams; i++) { - if(mov->tracks[i].entry <= 0) continue; - if (mov->tracks[i].enc->codec_id == CODEC_ID_AAC || - mov->tracks[i].enc->codec_id == CODEC_ID_MPEG4) { - mov_write_string_tag(pb, "\251req", "QuickTime 6.0 or greater", 0); - break; - } - } - - mov_write_string_tag(pb, "\251nam", s->title , 0); - mov_write_string_tag(pb, "\251aut", s->author , 0); - mov_write_string_tag(pb, "\251alb", s->album , 0); - mov_write_day_tag(pb, s->year, 0); - if(mov->tracks[0].enc && !(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT)) - mov_write_string_tag(pb, "\251enc", LIBAVFORMAT_IDENT, 0); - mov_write_string_tag(pb, "\251des", s->comment , 0); - mov_write_string_tag(pb, "\251gen", s->genre , 0); - } - - return updateSize(pb, pos); -} - - -static size_t ascii_to_wc (ByteIOContext *pb, char *b, size_t n) -{ - size_t i; - unsigned char c; - for (i = 0; i < n - 1; i++) { - c = b[i]; - if (! (0x20 <= c && c <= 0x7f )) - c = 0x3f; /* '?' */ - put_be16(pb, c); - } - put_be16(pb, 0x00); - return 2*n; -} - -static uint16_t language_code (const char *str) -{ - return ((((str[0]-0x60) & 0x1F)<<10) + (((str[1]-0x60) & 0x1F)<<5) + ((str[2]-0x60) & 0x1F)); -} - -static int mov_write_uuidusmt_tag (ByteIOContext *pb, AVFormatContext *s) -{ - size_t len, size; - offset_t pos, curpos; - - size = 0; - if (s->title[0]) { - pos = url_ftell(pb); - put_be32(pb, 0); /* size placeholder*/ - put_tag(pb, "uuid"); - put_tag(pb, "USMT"); - put_be32(pb, 0x21d24fce ); /* 96 bit UUID */ - put_be32(pb, 0xbb88695c ); - put_be32(pb, 0xfac9c740 ); - size += 24; - - put_be32(pb, 0); /* size placeholder*/ - put_tag(pb, "MTDT"); - put_be16(pb, 4); - size += 10; - - // ? - put_be16(pb, 0x0C); /* size */ - put_be32(pb, 0x0B); /* type */ - put_be16(pb, language_code("und")); /* language */ - put_be16(pb, 0x0); /* ? */ - put_be16(pb, 0x021C); /* data */ - size += 12; - - // Encoder - len = strlen(LIBAVCODEC_IDENT)+1; - put_be16(pb, len*2+10); /* size */ - put_be32(pb, 0x04); /* type */ - put_be16(pb, language_code("eng")); /* language */ - put_be16(pb, 0x01); /* ? */ - ascii_to_wc(pb, LIBAVCODEC_IDENT, len); - size += len*2+10; - - // Title - len = strlen(s->title)+1; - put_be16(pb, len*2+10); /* size */ - put_be32(pb, 0x01); /* type */ - put_be16(pb, language_code("eng")); /* language */ - put_be16(pb, 0x01); /* ? */ - ascii_to_wc (pb, s->title, len); - size += len*2+10; - - // Date -// snprintf(dt,32,"%04d/%02d/%02d %02d:%02d:%02d",t_st->tm_year+1900,t_st->tm_mon+1,t_st->tm_mday,t_st->tm_hour,t_st->tm_min,t_st->tm_sec); - len = strlen("2006/04/01 11:11:11")+1; - put_be16(pb, len*2+10); /* size */ - put_be32(pb, 0x03); /* type */ - put_be16(pb, language_code("und")); /* language */ - put_be16(pb, 0x01); /* ? */ - ascii_to_wc (pb, "2006/04/01 11:11:11", len); - size += len*2+10; - - // size - curpos = url_ftell(pb); - url_fseek(pb, pos, SEEK_SET); - put_be32(pb, size); - url_fseek(pb, pos+24, SEEK_SET); - put_be32(pb, size-24); - url_fseek(pb, curpos, SEEK_SET); - } - - return size; -} - -static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov, - AVFormatContext *s) -{ - int i; - offset_t pos = url_ftell(pb); - put_be32(pb, 0); /* size placeholder*/ - put_tag(pb, "moov"); - mov->timescale = globalTimescale; - - for (i=0; inb_streams; i++) { - if(mov->tracks[i].entry <= 0) continue; - - mov->tracks[i].trackDuration = - (int64_t)mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration; - mov->tracks[i].time = mov->time; - mov->tracks[i].trackID = i+1; - } - - mov_write_mvhd_tag(pb, mov); - //mov_write_iods_tag(pb, mov); - for (i=0; inb_streams; i++) { - if(mov->tracks[i].entry > 0) { - mov_write_trak_tag(pb, &(mov->tracks[i])); - } - } - - if (mov->mode == MODE_PSP) - mov_write_uuidusmt_tag(pb, s); - else - mov_write_udta_tag(pb, mov, s); - - return updateSize(pb, pos); -} - -static int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov) -{ - put_be32(pb, 8); // placeholder for extended size field (64 bit) - put_tag(pb, mov->mode == MODE_MOV ? "wide" : "free"); - - mov->mdat_pos = url_ftell(pb); - put_be32(pb, 0); /* size placeholder*/ - put_tag(pb, "mdat"); - return 0; -} - -/* TODO: This needs to be more general */ -static void mov_write_ftyp_tag (ByteIOContext *pb, AVFormatContext *s) -{ - MOVContext *mov = s->priv_data; - - put_be32(pb, 0x14 ); /* size */ - put_tag(pb, "ftyp"); - - if ( mov->mode == MODE_3GP ) - put_tag(pb, "3gp4"); - else if ( mov->mode == MODE_3G2 ) - put_tag(pb, "3g2a"); - else if ( mov->mode == MODE_PSP ) - put_tag(pb, "MSNV"); - else if ( mov->mode == MODE_MP4 ) - put_tag(pb, "isom"); - else - put_tag(pb, "qt "); - - put_be32(pb, 0x200 ); - - if ( mov->mode == MODE_3GP ) - put_tag(pb, "3gp4"); - else if ( mov->mode == MODE_3G2 ) - put_tag(pb, "3g2a"); - else if ( mov->mode == MODE_PSP ) - put_tag(pb, "MSNV"); - else if ( mov->mode == MODE_MP4 ) - put_tag(pb, "mp41"); - else - put_tag(pb, "qt "); -} - -static void mov_write_uuidprof_tag(ByteIOContext *pb, AVFormatContext *s) -{ - AVCodecContext *VideoCodec = s->streams[0]->codec; - AVCodecContext *AudioCodec = s->streams[1]->codec; - int AudioRate = AudioCodec->sample_rate; - int FrameRate = ((VideoCodec->time_base.den) * (0x10000))/ (VideoCodec->time_base.num); - int audio_kbitrate= AudioCodec->bit_rate / 1000; - int video_kbitrate= FFMIN(VideoCodec->bit_rate / 1000, 800 - audio_kbitrate); - - put_be32(pb, 0x94 ); /* size */ - put_tag(pb, "uuid"); - put_tag(pb, "PROF"); - - put_be32(pb, 0x21d24fce ); /* 96 bit UUID */ - put_be32(pb, 0xbb88695c ); - put_be32(pb, 0xfac9c740 ); - - put_be32(pb, 0x0 ); /* ? */ - put_be32(pb, 0x3 ); /* 3 sections ? */ - - put_be32(pb, 0x14 ); /* size */ - put_tag(pb, "FPRF"); - put_be32(pb, 0x0 ); /* ? */ - put_be32(pb, 0x0 ); /* ? */ - put_be32(pb, 0x0 ); /* ? */ - - put_be32(pb, 0x2c ); /* size */ - put_tag(pb, "APRF"); /* audio */ - put_be32(pb, 0x0 ); - put_be32(pb, 0x2 ); /* TrackID */ - put_tag(pb, "mp4a"); - put_be32(pb, 0x20f ); - put_be32(pb, 0x0 ); - put_be32(pb, audio_kbitrate); - put_be32(pb, audio_kbitrate); - put_be32(pb, AudioRate ); - put_be32(pb, AudioCodec->channels ); - - put_be32(pb, 0x34 ); /* size */ - put_tag(pb, "VPRF"); /* video */ - put_be32(pb, 0x0 ); - put_be32(pb, 0x1 ); /* TrackID */ - if (VideoCodec->codec_id == CODEC_ID_H264) { - put_tag(pb, "avc1"); - put_be16(pb, 0x014D ); - put_be16(pb, 0x0015 ); - } else { - put_tag(pb, "mp4v"); - put_be16(pb, 0x0000 ); - put_be16(pb, 0x0103 ); - } - put_be32(pb, 0x0 ); - put_be32(pb, video_kbitrate); - put_be32(pb, video_kbitrate); - put_be32(pb, FrameRate); - put_be32(pb, FrameRate); - put_be16(pb, VideoCodec->width); - put_be16(pb, VideoCodec->height); - put_be32(pb, 0x010001); /* ? */ -} - -static int mov_write_header(AVFormatContext *s) -{ - ByteIOContext *pb = &s->pb; - MOVContext *mov = s->priv_data; - int i; - - /* Default mode == MP4 */ - mov->mode = MODE_MP4; - - if (s->oformat != NULL) { - if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP; - else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3G2; - else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV; - else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP; - - mov_write_ftyp_tag(pb,s); - if ( mov->mode == MODE_PSP ) { - if ( s->nb_streams != 2 ) { - av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n"); - return -1; - } - mov_write_uuidprof_tag(pb,s); - } - } - - for(i=0; inb_streams; i++){ - AVStream *st= s->streams[i]; - MOVTrack *track= &mov->tracks[i]; - - track->enc = st->codec; - track->language = ff_mov_iso639_to_lang(st->language, mov->mode != MODE_MOV); - track->mode = mov->mode; - if(st->codec->codec_type == CODEC_TYPE_VIDEO){ - track->tag = mov_find_video_codec_tag(s, track); - track->timescale = st->codec->time_base.den; - track->sampleDuration = st->codec->time_base.num; - av_set_pts_info(st, 64, 1, st->codec->time_base.den); - }else if(st->codec->codec_type == CODEC_TYPE_AUDIO){ - track->tag = mov_find_audio_codec_tag(s, track); - track->timescale = st->codec->sample_rate; - track->sampleDuration = st->codec->frame_size; - av_set_pts_info(st, 64, 1, st->codec->sample_rate); - track->sampleSize = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels; - } - if (!track->sampleDuration) { - av_log(s, AV_LOG_ERROR, "track %d: sample duration is not set\n", i); - return -1; - } - } - - mov_write_mdat_tag(pb, mov); - mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based - mov->nb_streams = s->nb_streams; - - put_flush_packet(pb); - - return 0; -} - -static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - MOVContext *mov = s->priv_data; - ByteIOContext *pb = &s->pb; - MOVTrack *trk = &mov->tracks[pkt->stream_index]; - AVCodecContext *enc = trk->enc; - unsigned int samplesInChunk = 0; - int size= pkt->size; - - if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */ - if (!size) return 0; /* Discard 0 sized packets */ - - if (enc->codec_id == CODEC_ID_AMR_NB) { - /* We must find out how many AMR blocks there are in one packet */ - static uint16_t packed_size[16] = - {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0}; - int len = 0; - - while (len < size && samplesInChunk < 100) { - len += packed_size[(pkt->data[len] >> 3) & 0x0F]; - samplesInChunk++; - } - if(samplesInChunk > 1){ - av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, inplement a AVParser for it\n"); - return -1; - } - } else if (trk->sampleSize) - samplesInChunk = size/trk->sampleSize; - else - samplesInChunk = 1; - - /* copy extradata if it exists */ - if (trk->vosLen == 0 && enc->extradata_size > 0) { - trk->vosLen = enc->extradata_size; - trk->vosData = av_malloc(trk->vosLen); - memcpy(trk->vosData, enc->extradata, trk->vosLen); - } - - if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 && *(uint8_t *)trk->vosData != 1) { - /* from x264 or from bytestream h264 */ - /* nal reformating needed */ - avc_parse_nal_units(&pkt->data, &pkt->size); - assert(pkt->size); - size = pkt->size; - } - - if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) { - trk->cluster = av_realloc(trk->cluster, (trk->entry + MOV_INDEX_CLUSTER_SIZE) * sizeof(*trk->cluster)); - if (!trk->cluster) - return -1; - } - - trk->cluster[trk->entry].pos = url_ftell(pb); - trk->cluster[trk->entry].samplesInChunk = samplesInChunk; - trk->cluster[trk->entry].size = size; - trk->cluster[trk->entry].entries = samplesInChunk; - if(enc->codec_type == CODEC_TYPE_VIDEO) { - if (pkt->dts != pkt->pts) - trk->hasBframes = 1; - trk->cluster[trk->entry].cts = pkt->pts - pkt->dts; - trk->cluster[trk->entry].key_frame = !!(pkt->flags & PKT_FLAG_KEY); - if(trk->cluster[trk->entry].key_frame) - trk->hasKeyframes++; - } - trk->entry++; - trk->sampleCount += samplesInChunk; - mov->mdat_size += size; - - put_buffer(pb, pkt->data, size); - - put_flush_packet(pb); - return 0; -} - -static int mov_write_trailer(AVFormatContext *s) -{ - MOVContext *mov = s->priv_data; - ByteIOContext *pb = &s->pb; - int res = 0; - int i; - - offset_t moov_pos = url_ftell(pb); - - /* Write size of mdat tag */ - if (mov->mdat_size+8 <= UINT32_MAX) { - url_fseek(pb, mov->mdat_pos, SEEK_SET); - put_be32(pb, mov->mdat_size+8); - } else { - /* overwrite 'wide' placeholder atom */ - url_fseek(pb, mov->mdat_pos - 8, SEEK_SET); - put_be32(pb, 1); /* special value: real atom size will be 64 bit value after tag field */ - put_tag(pb, "mdat"); - put_be64(pb, mov->mdat_size+16); - } - url_fseek(pb, moov_pos, SEEK_SET); - - mov_write_moov_tag(pb, mov, s); - - for (i=0; inb_streams; i++) { - av_freep(&mov->tracks[i].cluster); - - if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData ); - - } - - put_flush_packet(pb); - - return res; -} - -#ifdef CONFIG_MOV_MUXER -AVOutputFormat mov_muxer = { - "mov", - "mov format", - NULL, - "mov", - sizeof(MOVContext), - CODEC_ID_AAC, - CODEC_ID_MPEG4, - mov_write_header, - mov_write_packet, - mov_write_trailer, - .flags = AVFMT_GLOBALHEADER, -}; -#endif -#ifdef CONFIG_TGP_MUXER -AVOutputFormat tgp_muxer = { - "3gp", - "3gp format", - NULL, - "3gp", - sizeof(MOVContext), - CODEC_ID_AMR_NB, - CODEC_ID_H263, - mov_write_header, - mov_write_packet, - mov_write_trailer, - .flags = AVFMT_GLOBALHEADER, -}; -#endif -#ifdef CONFIG_MP4_MUXER -AVOutputFormat mp4_muxer = { - "mp4", - "mp4 format", - "application/mp4", - "mp4,m4a", - sizeof(MOVContext), - CODEC_ID_AAC, - CODEC_ID_MPEG4, - mov_write_header, - mov_write_packet, - mov_write_trailer, - .flags = AVFMT_GLOBALHEADER, -}; -#endif -#ifdef CONFIG_PSP_MUXER -AVOutputFormat psp_muxer = { - "psp", - "psp mp4 format", - NULL, - "mp4,psp", - sizeof(MOVContext), - CODEC_ID_AAC, - CODEC_ID_MPEG4, - mov_write_header, - mov_write_packet, - mov_write_trailer, - .flags = AVFMT_GLOBALHEADER, -}; -#endif -#ifdef CONFIG_TG2_MUXER -AVOutputFormat tg2_muxer = { - "3g2", - "3gp2 format", - NULL, - "3g2", - sizeof(MOVContext), - CODEC_ID_AMR_NB, - CODEC_ID_H263, - mov_write_header, - mov_write_packet, - mov_write_trailer, - .flags = AVFMT_GLOBALHEADER, -}; -#endif diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/rtpproto.c --- a/src/ffmpeg/libavformat/rtpproto.c Mon Mar 12 14:49:42 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,303 +0,0 @@ -/* - * RTP network protocol - * Copyright (c) 2002 Fabrice Bellard. - * - * 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 "avformat.h" - -#include -#include -#include -#include -#include -#ifndef __BEOS__ -# include -#else -# include "barpainet.h" -#endif -#include -#include - -#define RTP_TX_BUF_SIZE (64 * 1024) -#define RTP_RX_BUF_SIZE (128 * 1024) - -typedef struct RTPContext { - URLContext *rtp_hd, *rtcp_hd; - int rtp_fd, rtcp_fd; -} RTPContext; - -/** - * If no filename is given to av_open_input_file because you want to - * get the local port first, then you must call this function to set - * the remote server address. - * - * @param s1 media file context - * @param uri of the remote server - * @return zero if no error. - */ -int rtp_set_remote_url(URLContext *h, const char *uri) -{ - RTPContext *s = h->priv_data; - char hostname[256]; - int port; - - char buf[1024]; - char path[1024]; - - url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, - path, sizeof(path), uri); - - snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path); - udp_set_remote_url(s->rtp_hd, buf); - - snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path); - udp_set_remote_url(s->rtcp_hd, buf); - return 0; -} - - -/* add option to url of the form: - "http://host:port/path?option1=val1&option2=val2... */ -static void url_add_option(char *buf, int buf_size, const char *fmt, ...) -{ - char buf1[1024]; - va_list ap; - - va_start(ap, fmt); - if (strchr(buf, '?')) - pstrcat(buf, buf_size, "&"); - else - pstrcat(buf, buf_size, "?"); - vsnprintf(buf1, sizeof(buf1), fmt, ap); - pstrcat(buf, buf_size, buf1); - va_end(ap); -} - -static void build_udp_url(char *buf, int buf_size, - const char *hostname, int port, - int local_port, int multicast, int ttl) -{ - snprintf(buf, buf_size, "udp://%s:%d", hostname, port); - if (local_port >= 0) - url_add_option(buf, buf_size, "localport=%d", local_port); - if (multicast) - url_add_option(buf, buf_size, "multicast=1", multicast); - if (ttl >= 0) - url_add_option(buf, buf_size, "ttl=%d", ttl); -} - -/* - * url syntax: rtp://host:port[?option=val...] - * option: 'multicast=1' : enable multicast - * 'ttl=n' : set the ttl value (for multicast only) - * 'localport=n' : set the local port to n - * - */ -static int rtp_open(URLContext *h, const char *uri, int flags) -{ - RTPContext *s; - int port, is_output, is_multicast, ttl, local_port; - char hostname[256]; - char buf[1024]; - char path[1024]; - const char *p; - - is_output = (flags & URL_WRONLY); - - s = av_mallocz(sizeof(RTPContext)); - if (!s) - return -ENOMEM; - h->priv_data = s; - - url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, - path, sizeof(path), uri); - /* extract parameters */ - is_multicast = 0; - ttl = -1; - local_port = -1; - p = strchr(uri, '?'); - if (p) { - is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p); - if (find_info_tag(buf, sizeof(buf), "ttl", p)) { - ttl = strtol(buf, NULL, 10); - } - if (find_info_tag(buf, sizeof(buf), "localport", p)) { - local_port = strtol(buf, NULL, 10); - } - } - - build_udp_url(buf, sizeof(buf), - hostname, port, local_port, is_multicast, ttl); - if (url_open(&s->rtp_hd, buf, flags) < 0) - goto fail; - local_port = udp_get_local_port(s->rtp_hd); - /* XXX: need to open another connexion if the port is not even */ - - /* well, should suppress localport in path */ - - build_udp_url(buf, sizeof(buf), - hostname, port + 1, local_port + 1, is_multicast, ttl); - if (url_open(&s->rtcp_hd, buf, flags) < 0) - goto fail; - - /* just to ease handle access. XXX: need to suppress direct handle - access */ - s->rtp_fd = udp_get_file_handle(s->rtp_hd); - s->rtcp_fd = udp_get_file_handle(s->rtcp_hd); - - h->max_packet_size = url_get_max_packet_size(s->rtp_hd); - h->is_streamed = 1; - return 0; - - fail: - if (s->rtp_hd) - url_close(s->rtp_hd); - if (s->rtcp_hd) - url_close(s->rtcp_hd); - av_free(s); - return AVERROR_IO; -} - -static int rtp_read(URLContext *h, uint8_t *buf, int size) -{ - RTPContext *s = h->priv_data; - struct sockaddr_in from; - socklen_t from_len; - int len, fd_max, n; - fd_set rfds; -#if 0 - for(;;) { - from_len = sizeof(from); - len = recvfrom (s->rtp_fd, buf, size, 0, - (struct sockaddr *)&from, &from_len); - if (len < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - return AVERROR_IO; - } - break; - } -#else - for(;;) { - /* build fdset to listen to RTP and RTCP packets */ - FD_ZERO(&rfds); - fd_max = s->rtp_fd; - FD_SET(s->rtp_fd, &rfds); - if (s->rtcp_fd > fd_max) - fd_max = s->rtcp_fd; - FD_SET(s->rtcp_fd, &rfds); - n = select(fd_max + 1, &rfds, NULL, NULL, NULL); - if (n > 0) { - /* first try RTCP */ - if (FD_ISSET(s->rtcp_fd, &rfds)) { - from_len = sizeof(from); - len = recvfrom (s->rtcp_fd, buf, size, 0, - (struct sockaddr *)&from, &from_len); - if (len < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - return AVERROR_IO; - } - break; - } - /* then RTP */ - if (FD_ISSET(s->rtp_fd, &rfds)) { - from_len = sizeof(from); - len = recvfrom (s->rtp_fd, buf, size, 0, - (struct sockaddr *)&from, &from_len); - if (len < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - return AVERROR_IO; - } - break; - } - } - } -#endif - return len; -} - -static int rtp_write(URLContext *h, uint8_t *buf, int size) -{ - RTPContext *s = h->priv_data; - int ret; - URLContext *hd; - - if (buf[1] >= 200 && buf[1] <= 204) { - /* RTCP payload type */ - hd = s->rtcp_hd; - } else { - /* RTP payload type */ - hd = s->rtp_hd; - } - - ret = url_write(hd, buf, size); -#if 0 - { - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = 10 * 1000000; - nanosleep(&ts, NULL); - } -#endif - return ret; -} - -static int rtp_close(URLContext *h) -{ - RTPContext *s = h->priv_data; - - url_close(s->rtp_hd); - url_close(s->rtcp_hd); - av_free(s); - return 0; -} - -/** - * Return the local port used by the RTP connexion - * @param s1 media file context - * @return the local port number - */ -int rtp_get_local_port(URLContext *h) -{ - RTPContext *s = h->priv_data; - return udp_get_local_port(s->rtp_hd); -} - -/** - * Return the rtp and rtcp file handles for select() usage to wait for several RTP - * streams at the same time. - * @param h media file context - */ -void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd) -{ - RTPContext *s = h->priv_data; - - *prtp_fd = s->rtp_fd; - *prtcp_fd = s->rtcp_fd; -} - -URLProtocol rtp_protocol = { - "rtp", - rtp_open, - rtp_read, - rtp_write, - NULL, /* seek */ - rtp_close, -}; diff -r 81749781b75f -r c294c4700937 src/ffmpeg/libavformat/voc.c --- a/src/ffmpeg/libavformat/voc.c Mon Mar 12 14:49:42 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/* - * Creative Voice File demuxer. - * Copyright (c) 2006 Aurelien Jacobs - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "avformat.h" -#include "riff.h" /* for CodecTag */ -#include "voc.h" - - -typedef enum voc_type { - VOC_TYPE_EOF = 0x00, - VOC_TYPE_VOICE_DATA = 0x01, - VOC_TYPE_VOICE_DATA_CONT = 0x02, - VOC_TYPE_SILENCE = 0x03, - VOC_TYPE_MARKER = 0x04, - VOC_TYPE_ASCII = 0x05, - VOC_TYPE_REPETITION_START = 0x06, - VOC_TYPE_REPETITION_END = 0x07, - VOC_TYPE_EXTENDED = 0x08, - VOC_TYPE_NEW_VOICE_DATA = 0x09, -} voc_type_t; - - -static const int voc_max_pkt_size = 2048; -static const unsigned char voc_magic[] = "Creative Voice File\x1A"; - -static const CodecTag voc_codec_tags[] = { - {CODEC_ID_PCM_U8, 0x00}, - {CODEC_ID_ADPCM_SBPRO_4, 0x01}, - {CODEC_ID_ADPCM_SBPRO_3, 0x02}, - {CODEC_ID_ADPCM_SBPRO_2, 0x03}, - {CODEC_ID_PCM_S16LE, 0x04}, - {CODEC_ID_PCM_ALAW, 0x06}, - {CODEC_ID_PCM_MULAW, 0x07}, - {CODEC_ID_ADPCM_CT, 0x0200}, - {0, 0}, -}; - - -#ifdef CONFIG_DEMUXERS - -static int voc_probe(AVProbeData *p) -{ - int version, check; - - if (p->buf_size < 26) - return 0; - if (memcmp(p->buf, voc_magic, sizeof(voc_magic) - 1)) - return 0; - version = p->buf[22] | (p->buf[23] << 8); - check = p->buf[24] | (p->buf[25] << 8); - if (~version + 0x1234 != check) - return 10; - - return AVPROBE_SCORE_MAX; -} - -static int voc_read_header(AVFormatContext *s, AVFormatParameters *ap) -{ - voc_dec_context_t *voc = s->priv_data; - ByteIOContext *pb = &s->pb; - int header_size; - AVStream *st; - - url_fskip(pb, 20); - header_size = get_le16(pb) - 22; - if (header_size != 4) { - av_log(s, AV_LOG_ERROR, "unkown header size: %d\n", header_size); - return AVERROR_NOTSUPP; - } - url_fskip(pb, header_size); - st = av_new_stream(s, 0); - if (!st) - return AVERROR_NOMEM; - st->codec->codec_type = CODEC_TYPE_AUDIO; - - voc->remaining_size = 0; - return 0; -} - -int -voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size) -{ - voc_dec_context_t *voc = s->priv_data; - AVCodecContext *dec = st->codec; - ByteIOContext *pb = &s->pb; - voc_type_t type; - int size; - int sample_rate = 0; - int channels = 1; - - while (!voc->remaining_size) { - type = get_byte(pb); - if (type == VOC_TYPE_EOF) - return AVERROR_IO; - voc->remaining_size = get_le24(pb); - max_size -= 4; - - switch (type) { - case VOC_TYPE_VOICE_DATA: - dec->sample_rate = 1000000 / (256 - get_byte(pb)); - if (sample_rate) - dec->sample_rate = sample_rate; - dec->channels = channels; - dec->codec_id = codec_get_id(voc_codec_tags, get_byte(pb)); - dec->bits_per_sample = av_get_bits_per_sample(dec->codec_id); - voc->remaining_size -= 2; - max_size -= 2; - channels = 1; - break; - - case VOC_TYPE_VOICE_DATA_CONT: - break; - - case VOC_TYPE_EXTENDED: - sample_rate = get_le16(pb); - get_byte(pb); - channels = get_byte(pb) + 1; - sample_rate = 256000000 / (channels * (65536 - sample_rate)); - voc->remaining_size = 0; - max_size -= 4; - break; - - case VOC_TYPE_NEW_VOICE_DATA: - dec->sample_rate = get_le32(pb); - dec->bits_per_sample = get_byte(pb); - dec->channels = get_byte(pb); - dec->codec_id = codec_get_id(voc_codec_tags, get_le16(pb)); - url_fskip(pb, 4); - voc->remaining_size -= 12; - max_size -= 12; - break; - - default: - url_fskip(pb, voc->remaining_size); - max_size -= voc->remaining_size; - voc->remaining_size = 0; - break; - } - } - - dec->bit_rate = dec->sample_rate * dec->bits_per_sample; - - if (max_size <= 0) - max_size = voc_max_pkt_size; - size = FFMIN(voc->remaining_size, max_size); - voc->remaining_size -= size; - return av_get_packet(pb, pkt, size); -} - -static int voc_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - return voc_get_packet(s, pkt, s->streams[0], 0); -} - -static int voc_read_close(AVFormatContext *s) -{ - return 0; -} - -AVInputFormat voc_demuxer = { - "voc", - "Creative Voice File format", - sizeof(voc_dec_context_t), - voc_probe, - voc_read_header, - voc_read_packet, - voc_read_close, -}; - -#endif /* CONFIG_DEMUXERS */ - - -#ifdef CONFIG_MUXERS - -typedef struct voc_enc_context { - int param_written; -} voc_enc_context_t; - -static int voc_write_header(AVFormatContext *s) -{ - ByteIOContext *pb = &s->pb; - const int header_size = 26; - const int version = 0x0114; - - if (s->nb_streams != 1 - || s->streams[0]->codec->codec_type != CODEC_TYPE_AUDIO) - return AVERROR_NOTSUPP; - - put_buffer(pb, voc_magic, sizeof(voc_magic) - 1); - put_le16(pb, header_size); - put_le16(pb, version); - put_le16(pb, ~version + 0x1234); - - return 0; -} - -static int voc_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - voc_enc_context_t *voc = s->priv_data; - AVCodecContext *enc = s->streams[0]->codec; - ByteIOContext *pb = &s->pb; - - if (!voc->param_written) { - int format = codec_get_tag(voc_codec_tags, enc->codec_id); - - if (format > 0xFF) { - put_byte(pb, VOC_TYPE_NEW_VOICE_DATA); - put_le24(pb, pkt->size + 12); - put_le32(pb, enc->sample_rate); - put_byte(pb, enc->bits_per_sample); - put_byte(pb, enc->channels); - put_le16(pb, format); - put_le32(pb, 0); - } else { - if (s->streams[0]->codec->channels > 1) { - put_byte(pb, VOC_TYPE_EXTENDED); - put_le24(pb, 4); - put_le16(pb, 65536-256000000/(enc->sample_rate*enc->channels)); - put_byte(pb, format); - put_byte(pb, enc->channels - 1); - } - put_byte(pb, VOC_TYPE_VOICE_DATA); - put_le24(pb, pkt->size + 2); - put_byte(pb, 256 - 1000000 / enc->sample_rate); - put_byte(pb, format); - } - voc->param_written = 1; - } else { - put_byte(pb, VOC_TYPE_VOICE_DATA_CONT); - put_le24(pb, pkt->size); - } - - put_buffer(pb, pkt->data, pkt->size); - return 0; -} - -static int voc_write_trailer(AVFormatContext *s) -{ - put_byte(&s->pb, 0); - return 0; -} - -AVOutputFormat voc_muxer = { - "voc", - "Creative Voice File format", - "audio/x-voc", - "voc", - sizeof(voc_enc_context_t), - CODEC_ID_PCM_U8, - CODEC_ID_NONE, - voc_write_header, - voc_write_packet, - voc_write_trailer, -}; - -#endif /* CONFIG_MUXERS */