[MPlayer-dev-eng] OpenDML Read/Write support
Tobias Diedrich
ranma at gmx.at
Mon Mar 8 01:01:15 CET 2004
Intentionally starting a new thread here, the quoted text is from
<Pine.LNX.4.58-Ti8iT.0403011132050.32097 at bitterberg.de>.
Tilmann Bitterberg wrote:
> o deal with files where audio is 00wb and video 01db (I can
> provide a sample if wanted)
I think a better way of dealing with that would be to just look at the
stream number and ignore the wb/db/whatever. ATM -forceidx doesn't work
with processor_burning.avi for example. I think I'll have a look at
that.
> o better interleaving algorithm from the odml indices into
> mplayers index
That is kinda ugly too, but I don't think it is worth changing the
internal structs for that.
> + // completely empty chunk, whats the purpose of that? Just delete it.
> + if (idx->dwChunkOffset==0 && idx->dwChunkLength==0) {
> + mp_msg(MSGT_HEADER, MSGL_V,
> + "AVI: ODML: Skipping emtpy chunk nr %d fcc %.4s\n", i, (char *)&idx->ckid);
> + idx--;
> + priv->idx_size--;
> + i--;
> + }
Empty chunks mean "repeat last frame". They shouldn't be dropped, AFAICS
it would cause a/v desync.
The attached patch removes that part and also includes OpenDML write
support.
--
Tobias PGP: http://9ac7e0bc.2ya.com
Be vigilant!
-------------- next part --------------
? audiodump.wav
? test.wav
Index: DOCS/man/en/mplayer.1
===================================================================
RCS file: /cvsroot/mplayer/main/DOCS/man/en/mplayer.1,v
retrieving revision 1.553
diff -u -r1.553 mplayer.1
--- DOCS/man/en/mplayer.1 5 Mar 2004 04:49:36 -0000 1.553
+++ DOCS/man/en/mplayer.1 7 Mar 2004 23:48:15 -0000
@@ -817,7 +817,7 @@
from a different AVI, but this is sure to cause unfavorable results.
.br
.I NOTE:
-This option will be obsoleted once AVI gets ODML support!
+This option is obsolete.
.TP
.B \-mc <seconds/frame>
Maximum A-V sync correction per frame (in seconds).
@@ -926,20 +926,9 @@
Force rebuilding of INDEX and output to a separate file specified by the
argument filename.
Currently this only works with AVI files.
-Although you can use MEncoder to fix files without indexes, the AVI
-container format is limited to indexing files up to 2GB in size.
-It is however possible to store the index in a separate file and use it later
-with \-loadidx, which is faster than rebuilding the index (with \-idx or
-\-forceidx) each time the movie is opened.
-(This is a limitation of the AVI format, and although there exists an
-extension to index beyond 2GB, MPlayer doesn't yet support this extension.)
-After the index file is created, MPlayer will begin to play the video.
-If you want to automate index file generation (after encoding a large file
-off a TV capture card, for example), you can specify \-frames 0 to
-prevent MPlayer from playing the video after generating the index.
.br
.I NOTE:
-This option will be obsoleted once AVI gets ODML support!
+This option is obsolete, because mplayer has OpenDML support.
.TP
.B \-sb <byte\ position> (see \-ss option too)
Seek to byte position.
Index: libmpdemux/aviheader.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/aviheader.c,v
retrieving revision 1.51
diff -u -r1.51 aviheader.c
--- libmpdemux/aviheader.c 22 Oct 2003 19:01:37 -0000 1.51
+++ libmpdemux/aviheader.c 7 Mar 2004 23:53:36 -0000
@@ -26,6 +26,48 @@
extern void print_video_header(BITMAPINFOHEADER *h);
extern void print_index(AVIINDEXENTRY *idx,int idx_size);
+void print_avistdindex_chunk(avistdindex_chunk *h){
+ mp_msg (MSGT_HEADER, MSGL_V, "====== AVI Standard Index Header ========\n");
+ mp_msg (MSGT_HEADER, MSGL_V, " FCC (%.4s) dwSize (%d) wLongsPerEntry(%d)\n", h->fcc, h->dwSize, h->wLongsPerEntry);
+ mp_msg (MSGT_HEADER, MSGL_V, " bIndexSubType (%d) bIndexType (%d)\n", h->bIndexSubType, h->bIndexType);
+ mp_msg (MSGT_HEADER, MSGL_V, " nEntriesInUse (%d) dwChunkId (%.4s)\n", h->nEntriesInUse, h->dwChunkId);
+ mp_msg (MSGT_HEADER, MSGL_V, " qwBaseOffset (0x%llX) dwReserved3 (%d)\n", h->qwBaseOffset, h->dwReserved3);
+ mp_msg (MSGT_HEADER, MSGL_V, "===========================\n");
+}
+void print_avisuperindex_chunk(avisuperindex_chunk *h){
+ mp_msg (MSGT_HEADER, MSGL_V, "====== AVI Super Index Header ========\n");
+ mp_msg (MSGT_HEADER, MSGL_V, " FCC (%.4s) dwSize (%d) wLongsPerEntry(%d)\n", h->fcc, h->dwSize, h->wLongsPerEntry);
+ mp_msg (MSGT_HEADER, MSGL_V, " bIndexSubType (%d) bIndexType (%d)\n", h->bIndexSubType, h->bIndexType);
+ mp_msg (MSGT_HEADER, MSGL_V, " nEntriesInUse (%d) dwChunkId (%.4s)\n", h->nEntriesInUse, h->dwChunkId);
+ mp_msg (MSGT_HEADER, MSGL_V, " dwReserved[0] (%d) dwReserved[1] (%d) dwReserved[2] (%d)\n",
+ h->dwReserved[0], h->dwReserved[1], h->dwReserved[2]);
+ mp_msg (MSGT_HEADER, MSGL_V, "===========================\n");
+}
+
+int odml_get_vstream_id(int id, unsigned char res[])
+{
+ unsigned char *p = (unsigned char *)&id;
+
+#if WORDS_BIGENDIAN
+ if (p[1] == 'd') {
+ if (res) {
+ res[0] = p[3];
+ res[1] = p[2];
+ }
+ return 1;
+ }
+#else
+ if (p[2] == 'd') {
+ if (res) {
+ res[0] = p[0];
+ res[1] = p[1];
+ }
+ return 1;
+ }
+#endif
+ return 0;
+}
+
void read_avi_header(demuxer_t *demuxer,int index_mode){
sh_audio_t *sh_audio=NULL;
sh_video_t *sh_video=NULL;
@@ -179,6 +221,47 @@
last_fccType=h.fccType;
if(verbose>=1) print_strh(&h);
break; }
+ case mmioFOURCC('i', 'n', 'd', 'x'): {
+ DWORD i;
+ unsigned msize = 0;
+ avisuperindex_chunk *s;
+ priv->suidx_size++;
+ priv->suidx = realloc(priv->suidx, priv->suidx_size * sizeof (avisuperindex_chunk));
+ s = &priv->suidx[priv->suidx_size-1];
+
+ chunksize-=24;
+ memcpy(s->fcc, "indx", 4);
+ s->dwSize = size2;
+ s->wLongsPerEntry = stream_read_word_le(demuxer->stream);
+ s->bIndexSubType = stream_read_char(demuxer->stream);
+ s->bIndexType = stream_read_char(demuxer->stream);
+ s->nEntriesInUse = stream_read_dword_le(demuxer->stream);
+ *(uint32_t *)s->dwChunkId = stream_read_dword_le(demuxer->stream);
+ stream_read(demuxer->stream, (char *)s->dwReserved, 3*4);
+ memset(s->dwReserved, 0, 3*4);
+
+ print_avisuperindex_chunk(s);
+
+ msize = sizeof (uint32_t) * s->wLongsPerEntry * s->nEntriesInUse;
+ s->aIndex = malloc(msize);
+ memset (s->aIndex, 0, msize);
+ s->stdidx = malloc (s->nEntriesInUse * sizeof (avistdindex_chunk));
+ memset (s->stdidx, 0, s->nEntriesInUse * sizeof (avistdindex_chunk));
+
+ // now the real index of indices
+ for (i=0; i<s->nEntriesInUse; i++) {
+ chunksize-=16;
+ s->aIndex[i].qwOffset = stream_read_dword_le(demuxer->stream) & 0xffffffff;
+ s->aIndex[i].qwOffset |= ((uint64_t)stream_read_dword_le(demuxer->stream) & 0xffffffff)<<32;
+ s->aIndex[i].dwSize = stream_read_dword_le(demuxer->stream);
+ s->aIndex[i].dwDuration = stream_read_dword_le(demuxer->stream);
+ mp_msg (MSGT_HEADER, MSGL_V, "ODML (%.4s): [%d] 0x%016llx 0x%04lx %ld\n",
+ (s->dwChunkId), i,
+ (uint64_t)s->aIndex[i].qwOffset, s->aIndex[i].dwSize, s->aIndex[i].dwDuration);
+ }
+ priv->isodml++;
+
+ break; }
case ckidSTREAMFORMAT: { // read 'strf'
if(last_fccType==streamtypeVIDEO){
sh_video->bih=calloc((chunksize<sizeof(BITMAPINFOHEADER))?sizeof(BITMAPINFOHEADER):chunksize,1);
@@ -246,10 +329,18 @@
}
break;
}
+ case mmioFOURCC('d', 'm', 'l', 'h'): {
+ // dmlh 00 00 00 04 frms
+ unsigned int total_frames = stream_read_dword_le(demuxer->stream);
+ mp_msg(MSGT_HEADER,MSGL_V,"AVI: dmlh found (size=%d) (total_frames=%d)\n", chunksize, total_frames);
+ stream_skip(demuxer->stream, chunksize-4);
+ chunksize = 0;
+ }
+ break;
case ckidAVINEWINDEX:
if(demuxer->movi_end>stream_tell(demuxer->stream))
demuxer->movi_end=stream_tell(demuxer->stream); // fixup movi-end
- if(index_mode){
+ if(index_mode && !priv->isodml){
int i;
priv->idx_size=size2>>4;
mp_msg(MSGT_HEADER,MSGL_V,"Reading INDEX block, %d chunks for %ld frames (fpos=%p)\n",
@@ -261,8 +352,8 @@
le2me_AVIINDEXENTRY((AVIINDEXENTRY*)priv->idx + i);
chunksize-=priv->idx_size<<4;
if(verbose>=2) print_index(priv->idx,priv->idx_size);
- break;
}
+ break;
/* added May 2002 */
case mmioFOURCC('R','I','F','F'): {
char riff_type[4];
@@ -275,6 +366,29 @@
chunksize = 0;
list_end = 0; /* a new list will follow */
break; }
+ case mmioFOURCC('A', 'T', 'T', 'R'): {
+ unsigned int nrinfo;
+ char *data=malloc(chunksize), *c;
+ nrinfo = stream_read_dword_le(demuxer->stream);
+ mp_msg(MSGT_HEADER, MSGL_V, "[BTV] Beyond TV metainfo found with %d entries\n", nrinfo);
+ memset (data, '\0', chunksize);
+ stream_read (demuxer->stream, data, chunksize-4);
+ c = data;
+ while (nrinfo--) {
+ mp_msg(MSGT_HEADER, MSGL_V, "[BTV] %s: ", c);
+ c += strlen(c)+1;
+ if (strchr(c, '\n')) *strchr(c, '\n') = ' ';
+ if (!*c) mp_msg(MSGT_HEADER, MSGL_V, "not set\n");
+ else mp_msg(MSGT_HEADER, MSGL_V, "%s\n", c);
+ c += strlen(c)+1;
+ }
+ chunksize = 0;
+ }
+ break;
+ case ckidAVIPADDING:
+ stream_skip(demuxer->stream, chunksize);
+ chunksize = 0;
+ break;
}
if(hdr){
mp_msg(MSGT_HEADER,MSGL_V,"hdr=%s size=%u\n",hdr,size2);
@@ -293,6 +407,8 @@
mp_msg(MSGT_HEADER,MSGL_DBG2,"list_end=0x%X pos=0x%X chunksize=0x%X next=0x%X\n",
(int)list_end, (int)stream_tell(demuxer->stream),
chunksize, (int)chunksize+stream_tell(demuxer->stream));
+ if(list_end>0 &&
+ chunksize+stream_tell(demuxer->stream) == list_end) list_end=0;
if(list_end>0 && chunksize+stream_tell(demuxer->stream)>list_end){
mp_msg(MSGT_HEADER,MSGL_V,"Broken chunk? chunksize=%d (id=%.4s)\n",chunksize,(char *) &id);
stream_seek(demuxer->stream,list_end);
@@ -303,6 +419,234 @@
}
+if (priv->isodml && (index_mode==-1 || index_mode==0)) {
+ int i, j, k;
+ int safety=1000;
+ int nroffsets;
+
+ avisuperindex_chunk *cx;
+ AVIINDEXENTRY *idx;
+
+
+ if (priv->idx_size) free(priv->idx);
+ priv->offsets_size=0;
+ priv->idx_size = 0;
+ priv->idx_offset = 0;
+ priv->idx = NULL;
+
+ mp_msg(MSGT_HEADER, MSGL_INFO,
+ "AVI: ODML: Building odml index (%d superindexchunks)\n", priv->suidx_size);
+
+ // count number of stdindex entries in all superindices
+ nroffsets=0; cx = &priv->suidx[0];
+ do nroffsets+=cx->nEntriesInUse;
+ while (cx++ != &priv->suidx[priv->suidx_size-1]);
+
+ priv->offsets = malloc(sizeof(uint64_t) * (nroffsets+1));
+
+ // read the standard indices
+ for (cx = &priv->suidx[0], i=0; i<priv->suidx_size; cx++, i++) {
+ stream_reset(demuxer->stream);
+ for (j=0; j<cx->nEntriesInUse; j++) {
+ int ret1, ret2;
+ memset(&cx->stdidx[j], 0, 32);
+ ret1 = stream_seek(demuxer->stream, (off_t)cx->aIndex[j].qwOffset);
+ ret2 = stream_read(demuxer->stream, (char *)&cx->stdidx[j], 32);
+ if (ret1 != 1 || ret2 != 32 || cx->stdidx[j].nEntriesInUse==0) {
+ // this is a broken file (probably incomplete) let the standard
+ // gen_index routine handle this
+ priv->isodml = 0;
+ priv->idx_size = 0;
+ memset(priv->offsets, 0, (nroffsets+1)*sizeof(uint64_t));
+ priv->offsets_size = 0;
+ mp_msg(MSGT_HEADER, MSGL_WARN,
+ "AVI: ODML: Broken (incomplete?) file detected. Will use traditional index\n");
+ goto freeout;
+ }
+
+ le2me_AVISTDIDXCHUNK(&cx->stdidx[j]);
+ print_avistdindex_chunk(&cx->stdidx[j]);
+ priv->idx_size += cx->stdidx[j].nEntriesInUse;
+ priv->offsets[priv->offsets_size] = (off_t)(cx->stdidx[j].qwBaseOffset - 8);
+ priv->offsets_size++;
+ cx->stdidx[j].aIndex = malloc(cx->stdidx[j].nEntriesInUse*sizeof(avistdindex_entry));
+ stream_read(demuxer->stream, (char *)cx->stdidx[j].aIndex,
+ cx->stdidx[j].nEntriesInUse*sizeof(avistdindex_entry));
+ for (k=0;k<cx->stdidx[j].nEntriesInUse; k++)
+ le2me_AVISTDIDXENTRY(&cx->stdidx[j].aIndex[k]);
+
+ cx->stdidx[j].dwReserved3 = 0;
+
+ }
+ }
+
+ // put the number of frames per superindex into dwReserved[0]
+ cx = &priv->suidx[0];
+ do for (j=0;j<cx->nEntriesInUse;j++)
+ cx->dwReserved[0] += cx->stdidx[j].nEntriesInUse;
+ while (cx++ != &priv->suidx[priv->suidx_size-1]);
+
+ /*
+ priv->
+ suidx[0] ----- stdidx[0] ----- aIndex[0]
+ \ `---- aIndex[1]
+ `---- stdidx[1] --...
+ suidx[1] ---...
+
+ This code is not nice but has to done. It copies the stdindex entries
+ into the standard index structure mplayer wants. It has to interleave
+ them while doing this. The algorithm does so by looking at how many
+ packets from one stream already went into the index and choosing the
+ stream which has the least percent of packets in the idx1.
+ --tibit
+
+ We "recycle" the dwReserved variables as counters
+ cx->dwReserved[0] = number of total frames per superindex
+ cx->dwReserved[2] = number of used frames per superindex
+ cx->stdidx[n].dwReserved3 = number of used frames in this stdindex
+ */
+
+
+ priv->idx = malloc(priv->idx_size * sizeof (AVIINDEXENTRY));
+ idx = &((AVIINDEXENTRY *)priv->idx)[0];
+
+ cx = &priv->suidx[0];
+
+ safety = 1000;
+
+ // Interleave. Could be done smarter I guess
+ for (i=0; i<priv->idx_size; i++) {
+ avistdindex_entry *e;
+ int widx;
+ int id=0;
+
+ j = 1;
+ widx=cx->stdidx[0].nEntriesInUse;
+ while (cx->dwReserved[2] >= widx) {
+ if (j==cx->nEntriesInUse) { i--; safety--; goto tryagain; }
+ widx += cx->stdidx[j].nEntriesInUse;
+ j++;
+ }
+ j--;
+
+ e = &cx->stdidx[j].aIndex[cx->stdidx[j].dwReserved3];
+ memcpy(&idx->ckid, cx->stdidx[j].dwChunkId, 4);
+ id = idx->ckid;
+ idx->dwChunkOffset = e->dwOffset;
+ idx->dwFlags = idx->dwChunkLength = e->dwSize;
+ idx->dwChunkLength &= 0x7fffffff;
+ idx->dwFlags = (idx->dwFlags&0x80000000)?0x0:AVIIF_KEYFRAME; // first bit denotes !keyframe
+ k = 0;
+ while (priv->offsets[k]+8 != cx->stdidx[j].qwBaseOffset) {
+ k++;
+ if (k==priv->offsets_size)
+ mp_msg(MSGT_HEADER,MSGL_ERR,
+ "AVI: ODML: Internal error. Can't find offset in array\n");
+ }
+ // We now put the index chunk where this is in into the upper 16 bits
+ idx->dwFlags |= (k<<16)&0xffff0000;
+
+ cx->dwReserved[2]++;
+ cx->stdidx[j].dwReserved3++;
+
+ idx++;
+ safety = 1000;
+tryagain:
+ {
+ avisuperindex_chunk *mincx;
+ float percent, old_percent=1000.0;
+ float audio_bonus = 0.0;
+
+ // the audio_bonus ensures that audio chunks gets added
+ // into idx prior to video chunks. mplayer likes this better.
+ if (id && odml_get_vstream_id(id, NULL)==0)
+ audio_bonus = 5.0;
+
+ // find the cx with the least percentage written
+ cx = &priv->suidx[0];
+ do {
+ percent = (cx->dwReserved[2]+audio_bonus)*1000.0/cx->dwReserved[0];
+ if (percent < old_percent) {
+ old_percent = percent;
+ mincx = cx;
+ }
+
+ } while (cx++ != &priv->suidx[priv->suidx_size-1]);
+
+ cx = mincx;
+ if (safety <= 0) {
+ mp_msg(MSGT_HEADER, MSGL_ERR,
+ "AVI: ODML: Internal error. Endless loop. Please bugreport\n");
+ mp_msg(MSGT_HEADER, MSGL_ERR,
+ "cx->id = %.4s perc=%f %d / %d\n", cx->dwChunkId, percent,
+ cx->dwReserved[2], cx->dwReserved[0]);
+ sleep(10);
+ return;
+ }
+ }
+ }
+
+ /*
+ Hack to work around a "wrong" index in some divx odml files
+ (processor_burning.avi as an example)
+ They have ##dc on non keyframes but the ix00 tells us they are ##db.
+ Read the fcc of a non-keyframe vid frame and check it.
+ */
+
+ {
+ uint32_t id;
+ uint32_t db = 0;
+ stream_reset (demuxer->stream);
+
+ // find out the video stream id. I have seen files with 01db.
+ for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
+ unsigned char res[2];
+ if (odml_get_vstream_id(idx->ckid, res)) {
+ db = mmioFOURCC(res[0], res[1], 'd', 'b');
+ break;
+ }
+ }
+
+ // find first non keyframe
+ for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
+ if (!(idx->dwFlags & AVIIF_KEYFRAME) && idx->ckid == db) break;
+ }
+ if (i<priv->idx_size && db) {
+ stream_seek(demuxer->stream, idx->dwChunkOffset+priv->offsets[idx->dwFlags>>16&0xffff]);
+ id = stream_read_dword_le(demuxer->stream);
+ if (id && id != db) // index fcc and real fcc differ? fix it.
+ for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
+ if (!(idx->dwFlags & AVIIF_KEYFRAME) && idx->ckid == db)
+ idx->ckid = id;
+ }
+ }
+ }
+
+ if (verbose>=2) // dump the constructed index
+ for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++)
+ // chunknr fcc offset length flags base_offset
+ mp_msg(MSGT_HEADER, MSGL_DBG2,
+ "ODML %6d: %.4s %08x %08x %02x %016llx\n", i, (char *)&idx->ckid,
+ idx->dwChunkOffset, idx->dwChunkLength, idx->dwFlags&0xffff,
+ priv->offsets[(idx->dwFlags>>16)&0xffff]);
+
+
+ demuxer->movi_end=demuxer->stream->end_pos;
+
+freeout:
+
+ // free unneeded stuff
+ cx = &priv->suidx[0];
+ do {
+ for (j=0;j<cx->nEntriesInUse;j++)
+ if (cx->stdidx[j].nEntriesInUse) free(cx->stdidx[j].aIndex);
+ free(cx->stdidx);
+
+ } while (cx++ != &priv->suidx[priv->suidx_size-1]);
+ free(priv->suidx);
+
+}
+
/* Read a saved index file */
if (index_file_load) {
FILE *fp;
Index: libmpdemux/aviheader.h
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/aviheader.h,v
retrieving revision 1.6
diff -u -r1.6 aviheader.h
--- libmpdemux/aviheader.h 16 Nov 2002 03:42:14 -0000 1.6
+++ libmpdemux/aviheader.h 7 Mar 2004 23:53:36 -0000
@@ -4,6 +4,48 @@
//#include "config.h" /* get correct definition WORDS_BIGENDIAN */
#include "bswap.h"
+typedef struct _avisuperindex_entry {
+ uint64_t qwOffset; // absolute file offset
+ uint32_t dwSize; // size of index chunk at this offset
+ uint32_t dwDuration; // time span in stream ticks
+} avisuperindex_entry;
+
+typedef struct _avistdindex_entry {
+ uint32_t dwOffset; // qwBaseOffset + this is absolute file offset
+ uint32_t dwSize; // bit 31 is set if this is NOT a keyframe
+} avistdindex_entry;
+
+// Standard index
+typedef struct _avistdindex_chunk {
+ char fcc[4]; // ix##
+ uint32_t dwSize; // size of this chunk
+ uint16_t wLongsPerEntry; // must be sizeof(aIndex[0])/sizeof(DWORD)
+ uint8_t bIndexSubType; // must be 0
+ uint8_t bIndexType; // must be AVI_INDEX_OF_CHUNKS
+ uint32_t nEntriesInUse; // first unused entry
+ char dwChunkId[4]; // '##dc' or '##db' or '##wb' etc..
+ uint64_t qwBaseOffset; // all dwOffsets in aIndex array are relative to this
+ uint32_t dwReserved3; // must be 0
+ avistdindex_entry *aIndex; // the actual frames
+} avistdindex_chunk;
+
+
+// Base Index Form 'indx'
+typedef struct _avisuperindex_chunk {
+ char fcc[4];
+ uint32_t dwSize; // size of this chunk
+ uint16_t wLongsPerEntry; // size of each entry in aIndex array (must be 4*4 for us)
+ uint8_t bIndexSubType; // future use. must be 0
+ uint8_t bIndexType; // one of AVI_INDEX_* codes
+ uint32_t nEntriesInUse; // index of first unused member in aIndex array
+ char dwChunkId[4]; // fcc of what is indexed
+ uint32_t dwReserved[3]; // meaning differs for each index type/subtype.
+ // 0 if unused
+ avisuperindex_entry *aIndex; // position of ix## chunks
+ avistdindex_chunk *stdidx; // the actual std indices
+} avisuperindex_chunk;
+
+
/*
* Some macros to swap little endian structures read from an AVI file
* into machine endian format
@@ -72,6 +114,23 @@
(h)->dwChunkOffset = le2me_32((h)->dwChunkOffset); \
(h)->dwChunkLength = le2me_32((h)->dwChunkLength); \
}
+#define le2me_AVISTDIDXCHUNK(h) {\
+ char c; \
+ c = (h)->fcc[0]; (h)->fcc[0] = (h)->fcc[3]; (h)->fcc[3] = c; \
+ c = (h)->fcc[1]; (h)->fcc[1] = (h)->fcc[2]; (h)->fcc[2] = c; \
+ (h)->dwSize = le2me_32((h)->dwSize); \
+ (h)->wLongsPerEntry = le2me_16((h)->wLongsPerEntry); \
+ (h)->nEntriesInUse = le2me_32((h)->nEntriesInUse); \
+ c = (h)->dwChunkId[0]; (h)->dwChunkId[0] = (h)->dwChunkId[3]; (h)->dwChunkId[3] = c; \
+ c = (h)->dwChunkId[1]; (h)->dwChunkId[1] = (h)->dwChunkId[2]; (h)->dwChunkId[2] = c; \
+ (h)->qwBaseOffset = le2me_64((h)->qwBaseOffset); \
+ (h)->dwReserved3 = le2me_32((h)->dwReserved3); \
+}
+#define le2me_AVISTDIDXENTRY(h) {\
+ (h)->dwOffset = le2me_32((h)->dwOffset); \
+ (h)->dwSize = le2me_32((h)->dwSize); \
+}
+
#else
#define le2me_MainAVIHeader(h) /**/
#define le2me_AVIStreamHeader(h) /**/
@@ -79,12 +138,10 @@
#define le2me_BITMAPINFOHEADER(h) /**/
#define le2me_WAVEFORMATEX(h) /**/
#define le2me_AVIINDEXENTRY(h) /**/
+#define le2me_AVISTDIDXCHUNK(h) /**/
+#define le2me_AVISTDIDXENTRY(h) /**/
#endif
-
-#endif
-
-
typedef struct {
// index stuff:
void* idx;
@@ -107,6 +164,13 @@
unsigned char pts_corrected;
unsigned char pts_has_video;
unsigned int numberofframes;
+ avisuperindex_chunk *suidx;
+ int suidx_size;
+ uint64_t *offsets;
+ int offsets_size;
+ int isodml;
} avi_priv_t;
#define AVI_PRIV ((avi_priv_t*)(demuxer->priv))
+
+#endif /* _aviheader_h */
Index: libmpdemux/demux_avi.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/demux_avi.c,v
retrieving revision 1.59
diff -u -r1.59 demux_avi.c
--- libmpdemux/demux_avi.c 17 Feb 2004 12:30:44 -0000 1.59
+++ libmpdemux/demux_avi.c 7 Mar 2004 23:54:49 -0000
@@ -170,6 +170,13 @@
return ds?1:0;
}
+
+inline static off_t demux_avi_dml_offset(demuxer_t *demux, AVIINDEXENTRY *idx)
+{
+ avi_priv_t *priv = demux->priv;
+ return (off_t)(priv->offsets?priv->offsets[(idx->dwFlags>>16)&0xffff]:0);
+}
+
// return value:
// 0 = EOF or no stream found
// 1 = successfully read a packet
@@ -213,7 +220,7 @@
continue; // skip this chunk
}
- pos = priv->idx_offset + (unsigned long)idx->dwChunkOffset;
+ pos = (off_t)priv->idx_offset + (off_t)idx->dwChunkOffset + demux_avi_dml_offset(demux, idx);
if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start) && (demux->stream->flags & STREAM_SEEK)){
mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! idx=0x%X \n",pos);
continue;
@@ -446,6 +453,12 @@
priv->video_pack_no=0;
priv->audio_block_no=0;
priv->audio_block_size=0;
+ priv->isodml = 0;
+ priv->offsets_size = 0;
+ priv->offsets = NULL;
+ priv->suidx_size = 0;
+ priv->suidx = NULL;
+
demuxer->priv=(void*)priv;
//---- AVI header:
@@ -468,8 +481,8 @@
if(priv->idx_size>1){
// decide index format:
#if 1
- if((unsigned long)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start ||
- (unsigned long)((AVIINDEXENTRY *)priv->idx)[1].dwChunkOffset<demuxer->movi_start)
+ if(((unsigned long)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start ||
+ (unsigned long)((AVIINDEXENTRY *)priv->idx)[1].dwChunkOffset<demuxer->movi_start )&& !priv->isodml)
priv->idx_offset=demuxer->movi_start-4;
else
priv->idx_offset=0;
Index: libmpdemux/muxer.h
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/muxer.h,v
retrieving revision 1.8
diff -u -r1.8 muxer.h
--- libmpdemux/muxer.h 22 Oct 2003 17:04:39 -0000 1.8
+++ libmpdemux/muxer.h 7 Mar 2004 23:55:09 -0000
@@ -47,9 +47,9 @@
typedef struct muxer_t{
// encoding:
MainAVIHeader avih;
- unsigned int movi_start;
- unsigned int movi_end;
- unsigned int file_end; // for MPEG it's system timestamp in 1/90000 s
+ off_t movi_start;
+ off_t movi_end;
+ off_t file_end; // for MPEG it's system timestamp in 1/90000 s
// index:
AVIINDEXENTRY *idx;
int idx_pos;
Index: libmpdemux/muxer_avi.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/muxer_avi.c,v
retrieving revision 1.17
diff -u -r1.17 muxer_avi.c
--- libmpdemux/muxer_avi.c 28 Jan 2004 07:47:48 -0000 1.17
+++ libmpdemux/muxer_avi.c 7 Mar 2004 23:56:31 -0000
@@ -1,17 +1,13 @@
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
+#include <limits.h>
#include "config.h"
#include "../version.h"
-//#include "stream.h"
-//#include "demuxer.h"
-//#include "stheader.h"
-
#include "wine/mmreg.h"
#include "wine/avifmt.h"
#include "wine/vfw.h"
@@ -19,6 +15,7 @@
#include "muxer.h"
#include "aviheader.h"
+#include "mp_msg.h"
extern char *info_name;
extern char *info_artist;
@@ -28,11 +25,38 @@
extern char *info_sourceform;
extern char *info_comment;
+/* #define ODML_CHUNKLEN 0x02000000 */ /* for testing purposes */
+#define ODML_CHUNKLEN 0x40000000
+#define ODML_NOTKEYFRAME 0x80000000U
+#define MOVIALIGN 0x00001000
+
+struct avi_odmlidx_entry {
+ uint64_t ofs;
+ uint32_t len;
+ uint32_t flags;
+};
+
+struct avi_odmlsuperidx_entry {
+ uint64_t ofs;
+ uint32_t len;
+ uint32_t duration;
+};
+
+struct avi_stream_info {
+ int idxsize;
+ int idxpos;
+ int superidxpos;
+ int superidxsize;
+ struct avi_odmlidx_entry *idx;
+ struct avi_odmlsuperidx_entry *superidx;
+};
+
static muxer_stream_t* avifile_new_stream(muxer_t *muxer,int type){
+ struct avi_stream_info *si;
muxer_stream_t* s;
if (!muxer) return NULL;
if(muxer->avih.dwStreams>=MUXER_MAX_STREAMS){
- printf("Too many streams! increase MUXER_MAX_STREAMS !\n");
+ mp_msg(MSGT_MUXER, MSGL_ERR, "Too many streams! increase MUXER_MAX_STREAMS !\n");
return NULL;
}
s=malloc(sizeof(muxer_stream_t));
@@ -44,6 +68,11 @@
s->timer=0.0;
s->size=0;
s->muxer=muxer;
+ s->priv=si=malloc(sizeof(struct avi_stream_info));
+ memset(si,0,sizeof(struct avi_stream_info));
+ si->idxsize=256;
+ si->idx=malloc(sizeof(struct avi_odmlidx_entry)*si->idxsize);
+
switch(type){
case MUXER_TYPE_VIDEO:
s->ckid=mmioFOURCC(('0'+s->id/10),('0'+(s->id%10)),'d','c');
@@ -55,7 +84,7 @@
s->h.fccType=streamtypeAUDIO;
break;
default:
- printf("WarninG! unknown stream type: %d\n",type);
+ mp_msg(MSGT_MUXER, MSGL_WARN, "Warning! unknown stream type: %d\n",type);
return NULL;
}
muxer->avih.dwStreams++;
@@ -90,20 +119,65 @@
}
}
+static void write_avi_list(FILE *f,unsigned int id,int len);
+static void avifile_write_index(muxer_t *muxer);
+
+static void avifile_odml_new_riff(muxer_t *muxer)
+{
+ FILE *f = muxer->file;
+ uint32_t riff[3];
+
+ /* Pad to ODML_CHUNKLEN */
+ write_avi_chunk(f,ckidAVIPADDING,ODML_CHUNKLEN - (ftello(f)%ODML_CHUNKLEN) - 8,NULL);
+
+ /* RIFF/AVIX chunk */
+ riff[0]=le2me_32(mmioFOURCC('R','I','F','F'));
+ riff[1]=0;
+ riff[2]=le2me_32(mmioFOURCC('A','V','I','X'));
+ fwrite(riff,12,1,f);
+
+ write_avi_list(f,listtypeAVIMOVIE,0);
+}
+
static void avifile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags){
+ off_t pos;
+ struct avi_stream_info *si = s->priv;
muxer_t *muxer=s->muxer;
- // add to the index:
+ // add to the traditional index:
if(muxer->idx_pos>=muxer->idx_size){
muxer->idx_size+=256; // 4kB
muxer->idx=realloc(muxer->idx,16*muxer->idx_size);
}
muxer->idx[muxer->idx_pos].ckid=s->ckid;
muxer->idx[muxer->idx_pos].dwFlags=flags; // keyframe?
- muxer->idx[muxer->idx_pos].dwChunkOffset=ftell(muxer->file)-(muxer->movi_start-4);
+ muxer->idx[muxer->idx_pos].dwChunkOffset=ftello(muxer->file)-(muxer->movi_start-4);
muxer->idx[muxer->idx_pos].dwChunkLength=len;
++muxer->idx_pos;
+ // add to odml index
+ if(si->idxpos>=si->idxsize){
+ si->idxsize+=256;
+ si->idx=realloc(si->idx,sizeof(*si->idx)*si->idxsize);
+ }
+ si->idx[si->idxpos].flags=(flags&AVIIF_KEYFRAME)?0:ODML_NOTKEYFRAME;
+ si->idx[si->idxpos].ofs=ftello(muxer->file);
+ si->idx[si->idxpos].len=len;
+ ++si->idxpos;
+
+ pos = ftello(muxer->file);
+ if (pos < ODML_CHUNKLEN &&
+ pos + 16*muxer->idx_pos + len + 8 > ODML_CHUNKLEN) {
+
+ avifile_write_index(muxer);
+ avifile_odml_new_riff(muxer);
+ }
+ pos = ftello(muxer->file);
+ if (pos % ODML_CHUNKLEN + len + 8 > ODML_CHUNKLEN) {
+ muxer->movi_end = ftello(muxer->file);
+ avifile_odml_new_riff(muxer);
+ }
+
// write out the chunk:
write_avi_chunk(muxer->file,s->ckid,len,s->buffer); /* unsigned char */
@@ -111,7 +185,7 @@
if(s->h.dwSampleSize){
// CBR
s->h.dwLength+=len/s->h.dwSampleSize;
- if(len%s->h.dwSampleSize) printf("Warning! len isn't divisable by samplesize!\n");
+ if(len%s->h.dwSampleSize) mp_msg(MSGT_MUXER, MSGL_WARN, "Warning! len isn't divisable by samplesize!\n");
} else {
// VBR
s->h.dwLength++;
@@ -137,13 +211,217 @@
#define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(wf)->cbSize)
+static void avifile_odml_update_header(muxer_t *muxer){
+ FILE *f = muxer->file;
+ unsigned int i;
+ unsigned int hdrsize;
+ unsigned int dmlh[62];
+ muxer_info_t info[16];
+ off_t pos;
+
+ for (pos = 0; pos < muxer->file_end; pos += ODML_CHUNKLEN) {
+ unsigned int rifflen, movilen;
+
+ /* fixup RIFF length */
+ if (muxer->file_end - pos > ODML_CHUNKLEN) {
+ rifflen = le2me_32(ODML_CHUNKLEN - 8);
+ movilen = le2me_32(ODML_CHUNKLEN - 20);
+ } else {
+ rifflen = le2me_32(muxer->file_end - pos - 8);
+ movilen = le2me_32(muxer->movi_end - pos - 20);
+ }
+ fseeko(f, pos + 4, SEEK_SET);
+ fwrite(&rifflen,4,1,f);
+
+ /* fixup movi length */
+ if (pos > 0) {
+ fseeko(f, pos + 16, SEEK_SET);
+ fwrite(&movilen,4,1,f);
+ }
+ }
+
+ fseeko(f, 12, SEEK_SET);
+
+ // update AVI header:
+ if(muxer->def_v){
+ muxer->avih.dwMicroSecPerFrame=1000000.0*muxer->def_v->h.dwScale/muxer->def_v->h.dwRate;
+// muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME
+// muxer->avih.dwPaddingGranularity=2; // ???
+ muxer->avih.dwFlags|=AVIF_ISINTERLEAVED|AVIF_TRUSTCKTYPE;
+ muxer->avih.dwTotalFrames=muxer->def_v->h.dwLength;
+// muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize;
+ muxer->avih.dwWidth=muxer->def_v->bih->biWidth;
+ muxer->avih.dwHeight=muxer->def_v->bih->biHeight;
+ }
+
+ // AVI header:
+ hdrsize=sizeof(muxer->avih)+8;
+ hdrsize+=sizeof(dmlh)+20; // dmlh
+ // calc total header size:
+ for(i=0;i<muxer->avih.dwStreams;i++){
+ muxer_stream_t *s = muxer->streams[i];
+ struct avi_stream_info *si = s->priv;
+
+ if (si && si->superidx && si->superidxsize) {
+ hdrsize += 32 + 16*si->superidxsize; //indx
+ }
+ hdrsize+=12; // LIST
+ hdrsize+=sizeof(muxer->streams[i]->h)+8; // strh
+ switch(muxer->streams[i]->type){
+ case MUXER_TYPE_VIDEO:
+ hdrsize+=muxer->streams[i]->bih->biSize+8; // strf
+ break;
+ case MUXER_TYPE_AUDIO:
+ hdrsize+=WFSIZE(muxer->streams[i]->wf)+8; // strf
+ break;
+ }
+ }
+ write_avi_list(f,listtypeAVIHEADER,hdrsize);
+
+ le2me_MainAVIHeader(&muxer->avih);
+ write_avi_chunk(f,ckidAVIMAINHDR,sizeof(muxer->avih),&muxer->avih); /* MainAVIHeader */
+ le2me_MainAVIHeader(&muxer->avih);
+
+ // stream headers:
+ for(i=0;i<muxer->avih.dwStreams;i++){
+ muxer_stream_t *s = muxer->streams[i];
+ struct avi_stream_info *si = s->priv;
+ unsigned int idxhdr[8];
+ int j,n;
+
+ hdrsize=sizeof(s->h)+8; // strh
+ if (si && si->superidx && si->superidxsize) {
+ hdrsize += 32 + 16*si->superidxsize; //indx
+ }
+ switch(s->type){
+ case MUXER_TYPE_VIDEO:
+ hdrsize+=s->bih->biSize+8; // strf
+ s->h.fccHandler = s->bih->biCompression;
+ break;
+ case MUXER_TYPE_AUDIO:
+ hdrsize+=WFSIZE(s->wf)+8; // strf
+ s->h.fccHandler = s->wf->wFormatTag;
+ break;
+ }
+ write_avi_list(f,listtypeSTREAMHEADER,hdrsize);
+ le2me_AVIStreamHeader(&s->h);
+ write_avi_chunk(f,ckidSTREAMHEADER,sizeof(s->h),&s->h); /* AVISTreamHeader */ // strh
+ le2me_AVIStreamHeader(&s->h);
+
+ switch(s->type){
+ case MUXER_TYPE_VIDEO:
+{
+ int biSize=s->bih->biSize;
+ le2me_BITMAPINFOHEADER(s->bih);
+ write_avi_chunk(f,ckidSTREAMFORMAT,biSize,s->bih); /* BITMAPINFOHEADER */
+ le2me_BITMAPINFOHEADER(s->bih);
+}
+ break;
+ case MUXER_TYPE_AUDIO:
+{
+ int wfsize = WFSIZE(s->wf);
+ le2me_WAVEFORMATEX(s->wf);
+ write_avi_chunk(f,ckidSTREAMFORMAT,wfsize,s->wf); /* WAVEFORMATEX */
+ le2me_WAVEFORMATEX(s->wf);
+}
+ break;
+ }
+
+ if (si && si->superidx && si->superidxsize) {
+ n = si->superidxsize;
+
+ idxhdr[0] = le2me_32(mmioFOURCC('i', 'n', 'd', 'x'));
+ idxhdr[1] = le2me_32(24 + 16*n);
+ idxhdr[2] = le2me_32(0x00000004);
+ idxhdr[3] = le2me_32(si->superidxpos);
+ idxhdr[4] = le2me_32(s->ckid);
+ idxhdr[5] = 0;
+ idxhdr[6] = 0;
+ idxhdr[7] = 0;
+
+ fwrite(idxhdr,sizeof(idxhdr),1,f);
+ for (j=0; j<n; j++) {
+ struct avi_odmlsuperidx_entry *entry = &si->superidx[j];
+ unsigned int data[4];
+ data[0] = le2me_32(entry->ofs);
+ data[1] = le2me_32(entry->ofs >> 32);
+ data[2] = le2me_32(entry->len);
+ data[3] = le2me_32(entry->duration);
+ fwrite(data,sizeof(data),1,f);
+ }
+ }
+ }
+ // ODML
+ memset(dmlh, 0, sizeof(dmlh));
+ dmlh[0] = le2me_32(muxer->avih.dwTotalFrames);
+ write_avi_list(f,mmioFOURCC('o','d','m','l'),sizeof(dmlh)+8);
+ write_avi_chunk(f,mmioFOURCC('d','m','l','h'),sizeof(dmlh),dmlh);
+
+// ============= INFO ===============
+// always include software info
+info[0].id=mmioFOURCC('I','S','F','T'); // Software:
+info[0].text="MEncoder " VERSION;
+// include any optional strings
+i=1;
+if(info_name!=NULL){
+ info[i].id=mmioFOURCC('I','N','A','M'); // Name:
+ info[i++].text=info_name;
+}
+if(info_artist!=NULL){
+ info[i].id=mmioFOURCC('I','A','R','T'); // Artist:
+ info[i++].text=info_artist;
+}
+if(info_genre!=NULL){
+ info[i].id=mmioFOURCC('I','G','N','R'); // Genre:
+ info[i++].text=info_genre;
+}
+if(info_subject!=NULL){
+ info[i].id=mmioFOURCC('I','S','B','J'); // Subject:
+ info[i++].text=info_subject;
+}
+if(info_copyright!=NULL){
+ info[i].id=mmioFOURCC('I','C','O','P'); // Copyright:
+ info[i++].text=info_copyright;
+}
+if(info_sourceform!=NULL){
+ info[i].id=mmioFOURCC('I','S','R','F'); // Source Form:
+ info[i++].text=info_sourceform;
+}
+if(info_comment!=NULL){
+ info[i].id=mmioFOURCC('I','C','M','T'); // Comment:
+ info[i++].text=info_comment;
+}
+info[i].id=0;
+
+ hdrsize=0;
+ // calc info size:
+ for(i=0;info[i].id!=0;i++) if(info[i].text){
+ size_t sz=strlen(info[i].text)+1;
+ hdrsize+=sz+8+sz%2;
+ }
+ // write infos:
+ if (hdrsize!=0){
+ write_avi_list(f,mmioFOURCC('I','N','F','O'),hdrsize);
+ for(i=0;info[i].id!=0;i++) if(info[i].text){
+ write_avi_chunk(f,info[i].id,strlen(info[i].text)+1,info[i].text);
+ }
+ }
+
+ // JUNK:
+ write_avi_chunk(f,ckidAVIPADDING,MOVIALIGN-(ftello(f)%MOVIALIGN)-8,NULL); /* junk */
+}
+
static void avifile_write_header(muxer_t *muxer){
+ FILE *f = muxer->file;
uint32_t riff[3];
unsigned int i;
unsigned int hdrsize;
muxer_info_t info[16];
- FILE *f=muxer->file;
+ if(muxer->file_end > ODML_CHUNKLEN) {
+ avifile_odml_update_header(muxer);
+ return;
+ }
// RIFF header:
riff[0]=mmioFOURCC('R','I','F','F');
riff[1]=muxer->file_end-2*sizeof(unsigned int); // filesize
@@ -274,14 +552,123 @@
}
// JUNK:
- write_avi_chunk(f,ckidAVIPADDING,2048-(ftell(f)&2047)-8,NULL); /* junk */
+ write_avi_chunk(f,ckidAVIPADDING,MOVIALIGN-(ftello(f)%MOVIALIGN)-8,NULL); /* junk */
// 'movi' header:
- write_avi_list(f,listtypeAVIMOVIE,muxer->movi_end-ftell(f)-12);
- muxer->movi_start=ftell(f);
+ write_avi_list(f,listtypeAVIMOVIE,ODML_CHUNKLEN-ftello(f)-12);
+}
+
+static void avifile_odml_write_index(muxer_t *muxer){
+ muxer_stream_t* s;
+ struct avi_stream_info *si;
+ int entries_per_subidx = INT_MAX;
+ int entries_per_superidx = 0;
+ int i;
+
+ /*
+ * FIXME:
+ * The following code is supposed to keep MS Mediaplayer happy,
+ * but it still doesn't work.
+ * According to Avery Lee MSMP wants the subidx chunks to have the same size.
+ */
+ for (i=0; i<muxer->avih.dwStreams; i++) {
+ int j,n,len,last;
+ s = muxer->streams[i];
+ si = s->priv;
+
+ len = 0;
+ n = 0;
+ do {
+ off_t start = si->idx[0].ofs;
+ last = entries_per_subidx;
+ for (j=0; j<si->idxpos; j++) {
+ len = si->idx[j].ofs - start;
+ if(len >= ODML_CHUNKLEN || n >= entries_per_subidx) {
+ if (entries_per_subidx > n) {
+ entries_per_subidx = n;
+ }
+ start = si->idx[j].ofs;
+ len = 0;
+ n = 0;
+ }
+ n++;
+ }
+ } while (last != entries_per_subidx);
+ }
+
+ for (i=0; i<muxer->avih.dwStreams; i++) {
+ s = muxer->streams[i];
+ si = s->priv;
+ si->superidxpos = (si->idxpos+entries_per_subidx-1) / entries_per_subidx;
+ if (si->superidxpos > entries_per_superidx) {
+ entries_per_superidx = si->superidxpos;
+ }
+ }
+
+ /*
+ * end of MS compat calculations
+ */
+
+ for (i=0; i<muxer->avih.dwStreams; i++) {
+ int j,k,n,idxpos;
+ unsigned int idxhdr[8];
+ s = muxer->streams[i];
+ si = s->priv;
+
+ if (si->idxpos > entries_per_subidx) n = entries_per_subidx;
+ else n = si->idxpos;
+
+ mp_msg(MSGT_MUXER, MSGL_V, "ODML: Stream %d: Using %d entries per subidx, %d entries in superidx\n",
+ i, n, si->superidxpos);
+
+ si->superidxsize = entries_per_superidx;
+ si->superidx = malloc(sizeof(*si->superidx) * si->superidxsize);
+ memset(si->superidx, 0, sizeof(*si->superidx) * si->superidxsize);
+
+ idxpos = 0;
+ for (j=0; j<si->superidxpos; j++) {
+ off_t start = si->idx[idxpos].ofs;
+ int duration;
+
+ duration = 0;
+ for (k=0; k<n && idxpos+k<si->idxpos; k++) {
+ duration += s->h.dwSampleSize ? si->idx[idxpos+k].len/s->h.dwSampleSize : 1;
+ }
+
+ idxhdr[0] = le2me_32((s->ckid << 16) | mmioFOURCC('i', 'x', 0, 0));
+ idxhdr[1] = le2me_32(24 + 8*k);
+ idxhdr[2] = le2me_32(0x01000002);
+ idxhdr[3] = le2me_32(k);
+ idxhdr[4] = le2me_32(s->ckid);
+ idxhdr[5] = le2me_32(start + 8);
+ idxhdr[6] = le2me_32((start + 8)>> 32);
+ idxhdr[7] = 0; /* unused */
+
+ si->superidx[j].len = 24 + 8*k;
+ si->superidx[j].ofs = ftello(muxer->file);
+ si->superidx[j].duration = duration;
+
+ fwrite(idxhdr,sizeof(idxhdr),1,muxer->file);
+ for (k=0; k<n && idxpos<si->idxpos; k++) {
+ unsigned int entry[2];
+ entry[0] = le2me_32(si->idx[idxpos].ofs - start);
+ entry[1] = le2me_32(si->idx[idxpos].len | si->idx[idxpos].flags);
+ idxpos++;
+ fwrite(entry,sizeof(entry),1,muxer->file);
+ }
+ }
+ }
+ muxer->file_end=muxer->movi_end=ftello(muxer->file);
}
static void avifile_write_index(muxer_t *muxer){
- muxer->movi_end=ftell(muxer->file);
+ muxer->movi_end=ftello(muxer->file);
+
+ if(muxer->movi_end > ODML_CHUNKLEN &&
+ muxer->idx && muxer->idx_pos>0) {
+ avifile_odml_write_index(muxer);
+ return;
+ }
+
if(muxer->idx && muxer->idx_pos>0){
int i;
// fixup index entries:
@@ -292,7 +679,7 @@
for (i=0; i<muxer->idx_pos; i++) le2me_AVIINDEXENTRY((&muxer->idx[i]));
muxer->avih.dwFlags|=AVIF_HASINDEX;
}
- muxer->file_end=ftell(muxer->file);
+ muxer->file_end=ftello(muxer->file);
}
void muxer_init_muxer_avi(muxer_t *muxer){
More information about the MPlayer-dev-eng
mailing list