summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorranma <ranma@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-03-17 14:50:37 +0000
committerranma <ranma@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-03-17 14:50:37 +0000
commit873b579c1afbe832b108bf4254adc9bb27130db6 (patch)
tree052e21d9fefff721cbe8d91329e92c325597a242
parent6080f085606ffe918a0260dc94a0e9c59f02cce7 (diff)
downloadmpv-873b579c1afbe832b108bf4254adc9bb27130db6.tar.bz2
mpv-873b579c1afbe832b108bf4254adc9bb27130db6.tar.xz
OpenDML read/write support
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@12037 b3059339-0415-0410-9bf9-f77b7e298cf2
-rw-r--r--AUTHORS4
-rw-r--r--DOCS/man/en/mplayer.115
-rw-r--r--libmpdemux/aviheader.c268
-rw-r--r--libmpdemux/aviheader.h136
-rw-r--r--libmpdemux/aviprint.c50
-rw-r--r--libmpdemux/demux_avi.c16
-rw-r--r--libmpdemux/muxer.h6
-rw-r--r--libmpdemux/muxer_avi.c411
-rw-r--r--mencoder.c6
9 files changed, 828 insertions, 84 deletions
diff --git a/AUTHORS b/AUTHORS
index 47d6f5439a..a502b161bc 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -260,6 +260,7 @@ Tobias Diedrich <ranma@gmx.at>
* DXR2 driver
* softpulldown video filter
* ported Donald Graft's kerndeint video filter
+ * AVI OpenDML write support
Kilian A. Foth <foth@informatik.uni-hamburg.de>
* -slave mode
@@ -623,6 +624,9 @@ Jake Janovetz
Vivien Chappelier, Damien Vincent
* libFAME authors [fast mpeg-1 encoder, used by -vo mpegpes/-vo dxr3]
+Tilmann Bitterberg
+ * AVI OpenDML read support
+
_____________________________________________________
Their code is not used in the current player version,
but I've got some ideas or other technical help from:
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index a65d16852a..9809923d49 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -817,7 +817,7 @@ Further, MPlayer won't prevent you from loading an index file generated
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, because MPlayer has OpenDML support.
.TP
.B \-mc <seconds/frame>
Maximum A-V sync correction per frame (in seconds).
@@ -926,20 +926,9 @@ not pass incoming UDP packets (see http://www.live.com/mplayer/).
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.
diff --git a/libmpdemux/aviheader.c b/libmpdemux/aviheader.c
index 332b9d9b16..7727d5285c 100644
--- a/libmpdemux/aviheader.c
+++ b/libmpdemux/aviheader.c
@@ -25,6 +25,48 @@ extern void print_strh(AVIStreamHeader *h);
extern void print_wave_header(WAVEFORMATEX *h);
extern void print_video_header(BITMAPINFOHEADER *h);
extern void print_index(AVIINDEXENTRY *idx,int idx_size);
+extern void print_avistdindex_chunk(avistdindex_chunk *h);
+extern void print_avisuperindex_chunk(avisuperindex_chunk *h);
+
+static int odml_get_vstream_id(int id, unsigned char res[])
+{
+ unsigned char *p = (unsigned char *)&id;
+ id = le2me_32(id);
+
+ if (p[2] == 'd') {
+ if (res) {
+ res[0] = p[0];
+ res[1] = p[1];
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Simple quicksort for AVIINDEXENTRYs
+ */
+static void avi_idx_quicksort(AVIINDEXENTRY *idx, int from, int to)
+{
+ AVIINDEXENTRY temp;
+ int lo = to;
+ int hi = from;
+ off_t pivot_ofs = AVI_IDX_OFFSET(&idx[(from + to) / 2]);
+ do {
+ while(pivot_ofs < AVI_IDX_OFFSET(&idx[lo])) lo--;
+ while(pivot_ofs > AVI_IDX_OFFSET(&idx[hi])) hi++;
+ if(hi <= lo) {
+ if (hi != lo) {
+ memcpy(&temp, &idx[lo], sizeof(temp));
+ memcpy(&idx[lo], &idx[hi], sizeof(temp));
+ memcpy(&idx[hi], &temp, sizeof(temp));
+ }
+ lo--; hi++;
+ }
+ } while (lo >= hi);
+ if (from < lo) avi_idx_quicksort(idx, from, lo);
+ if (to > hi) avi_idx_quicksort(idx, hi, to);
+}
void read_avi_header(demuxer_t *demuxer,int index_mode){
sh_audio_t *sh_audio=NULL;
@@ -179,6 +221,47 @@ while(1){
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,11 +329,41 @@ while(1){
}
break;
}
+ case mmioFOURCC('v', 'p', 'r', 'p'): {
+ VideoPropHeader *vprp = malloc(chunksize);
+ int i;
+ stream_read(demuxer->stream, (void*)vprp, chunksize);
+ le2me_VideoPropHeader(vprp);
+ chunksize -= sizeof(*vprp)-sizeof(vprp->FieldInfo);
+ chunksize /= sizeof(VIDEO_FIELD_DESC);
+ if (vprp->nbFieldPerFrame > chunksize) {
+ vprp->nbFieldPerFrame = chunksize;
+ }
+ chunksize = 0;
+ for (i=0; i<vprp->nbFieldPerFrame; i++) {
+ le2me_VIDEO_FIELD_DESC(&vprp->FieldInfo[i]);
+ }
+ if (sh_video) {
+ sh_video->aspect = GET_AVI_ASPECT(vprp->dwFrameAspectRatio);
+ }
+ if(verbose>=1) print_vprp(vprp);
+ 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;
+ off_t base = 0;
+ uint32_t last_off = 0;
priv->idx_size=size2>>4;
mp_msg(MSGT_HEADER,MSGL_V,"Reading INDEX block, %d chunks for %ld frames (fpos=%p)\n",
priv->idx_size,avih.dwTotalFrames, stream_tell(demuxer->stream));
@@ -261,8 +374,21 @@ while(1){
le2me_AVIINDEXENTRY((AVIINDEXENTRY*)priv->idx + i);
chunksize-=priv->idx_size<<4;
if(verbose>=2) print_index(priv->idx,priv->idx_size);
- break;
+ /*
+ * Fixup index for files >4GB
+ */
+ for (i = 0; i < priv->idx_size; i++) {
+ AVIINDEXENTRY *idx = (AVIINDEXENTRY*)priv->idx + i;
+ idx->dwFlags &= 0xffff;
+ if (idx->dwChunkOffset < last_off) {
+ mp_msg(MSGT_HEADER,MSGL_WARN,"Index offset going backwards (last=%08X, now=%08X), compensating...\n", last_off, idx->dwChunkOffset);
+ base += 0x100000000LL;
+ }
+ idx->dwFlags |= base >> 16;
+ last_off = idx->dwChunkOffset;
+ }
}
+ break;
/* added May 2002 */
case mmioFOURCC('R','I','F','F'): {
char riff_type[4];
@@ -275,6 +401,10 @@ while(1){
chunksize = 0;
list_end = 0; /* a new list will follow */
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 +423,8 @@ while(1){
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 +435,133 @@ while(1){
}
+if (priv->isodml && (index_mode==-1 || index_mode==0)) {
+ int i, j, k;
+ int safety=1000;
+
+ avisuperindex_chunk *cx;
+ AVIINDEXENTRY *idx;
+
+
+ if (priv->idx_size) free(priv->idx);
+ 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);
+
+ // 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;
+ 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;
+ 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;
+
+ }
+ }
+
+ /*
+ * We convert the index by translating all entries into AVIINDEXENTRYs
+ * and sorting them by offset. The result should be the same index
+ * we would get with -forceidx.
+ */
+
+ idx = priv->idx = malloc(priv->idx_size * sizeof (AVIINDEXENTRY));
+
+ for (cx = priv->suidx; cx != &priv->suidx[priv->suidx_size]; cx++) {
+ avistdindex_chunk *sic;
+ for (sic = cx->stdidx; sic != &cx->stdidx[cx->nEntriesInUse]; sic++) {
+ avistdindex_entry *sie;
+ for (sie = sic->aIndex; sie != &sic->aIndex[sic->nEntriesInUse]; sie++) {
+ uint64_t off = sic->qwBaseOffset + sie->dwOffset - 8;
+ memcpy(&idx->ckid, sic->dwChunkId, 4);
+ idx->dwChunkOffset = off;
+ idx->dwFlags = (off >> 32) << 16;
+ idx->dwChunkLength = sie->dwSize & 0x7fffffff;
+ idx->dwFlags |= (sie->dwSize&0x80000000)?0x0:AVIIF_KEYFRAME; // bit 31 denotes !keyframe
+ idx++;
+ }
+ }
+ }
+ avi_idx_quicksort(priv->idx, 0, priv->idx_size-1);
+
+ /*
+ 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, AVI_IDX_OFFSET(idx));
+ 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) print_index(priv->idx, priv->idx_size);
+
+ 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;
@@ -376,6 +635,7 @@ if(index_mode>=2 || (priv->idx_size==0 && index_mode==1)){
idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++];
idx->ckid=id;
idx->dwFlags=AVIIF_KEYFRAME; // FIXME
+ idx->dwFlags|=(demuxer->filepos>>16)&0xffff0000U;
idx->dwChunkOffset=(unsigned long)demuxer->filepos;
idx->dwChunkLength=len;
@@ -386,8 +646,8 @@ if(index_mode>=2 || (priv->idx_size==0 && index_mode==1)){
if(avi_stream_id(id)==idxfix_videostream){
switch(idxfix_divx){
case 3: c=stream_read_dword(demuxer->stream)<<5; //skip 32+5 bits for m$mpeg4v1
- case 1: if(c&0x40000000) idx->dwFlags=0;break; // divx 3
- case 2: if(c==0x1B6) idx->dwFlags=0;break; // divx 4
+ case 1: if(c&0x40000000) idx->dwFlags&=~AVIIF_KEYFRAME;break; // divx 3
+ case 2: if(c==0x1B6) idx->dwFlags&=~AVIIF_KEYFRAME;break; // divx 4
}
}
diff --git a/libmpdemux/aviheader.h b/libmpdemux/aviheader.h
index 4ca63fc9c0..80449a548b 100644
--- a/libmpdemux/aviheader.h
+++ b/libmpdemux/aviheader.h
@@ -4,6 +4,89 @@
//#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;
+
+typedef struct {
+ uint32_t CompressedBMHeight;
+ uint32_t CompressedBMWidth;
+ uint32_t ValidBMHeight;
+ uint32_t ValidBMWidth;
+ uint32_t ValidBMXOffset;
+ uint32_t ValidBMYOffset;
+ uint32_t VideoXOffsetInT;
+ uint32_t VideoYValidStartLine;
+} VIDEO_FIELD_DESC;
+
+typedef struct {
+ uint32_t VideoFormatToken;
+ uint32_t VideoStandard;
+ uint32_t dwVerticalRefreshRate;
+ uint32_t dwHTotalInT;
+ uint32_t dwVTotalInLines;
+ uint32_t dwFrameAspectRatio;
+ uint32_t dwFrameWidthInPixels;
+ uint32_t dwFrameHeightInLines;
+ uint32_t nbFieldPerFrame;
+ VIDEO_FIELD_DESC FieldInfo[2];
+} VideoPropHeader;
+
+enum {
+ FORMAT_UNKNOWN,
+ FORMAT_PAL_SQUARE,
+ FORMAT_PAL_CCIR_601,
+ FORMAT_NTSC_SQUARE,
+ FORMAT_NTSC_CCIR_601,
+} VIDEO_FORMAT;
+
+enum {
+ STANDARD_UNKNOWN,
+ STANDARD_PAL,
+ STANDARD_NTSC,
+ STANDARD_SECAM
+} VIDEO_STANDARD;
+
+#define MAKE_AVI_ASPECT(a, b) (((a)<<16)|(b))
+#define GET_AVI_ASPECT(a) ((float)((a)>>16)/(float)((a)&0xffff))
+
/*
* Some macros to swap little endian structures read from an AVI file
* into machine endian format
@@ -72,6 +155,44 @@
(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); \
+}
+#define le2me_VideoPropHeader(h) { \
+ (h)->VideoFormatToken = le2me_32((h)->VideoFormatToke) \
+ (h)->VideoStandrad = le2me_32((h)->VideoStandard) \
+ (h)->dwVerticalRefreshRate = le2me_32((h)->dwVerticalRefreshRate) \
+ (h)->dwHTotalInT = le2me_32((h)->dwHTotalInT) \
+ (h)->dwVTotalInLines = le2me_32((h)->dwVTotalInLines) \
+ (h)->dwFrameAspectRatio = le2me_32((h)->dwFrameAspectRatio) \
+ (h)->dwFrameWidthInPixels = le2me_32((h)->dwFrameWidthInPixels) \
+ (h)->dwFrameHeightInLines = le2me_32((h)->dwFrameHeightInLines) \
+ (h)->nbFieldPerFrame = le2me_32((h)->nbFieldPerFrame) \
+}
+#define le2me_VIDEO_FIELD_DESC(h) { \
+ (h)->CompressedBMHeight = le2me_32((h)->CompressedBMHeight) \
+ (h)->CompressedBMWidth = le2me_32((h)->CompressedBMWidth) \
+ (h)->ValidBMHeight = le2me_32((h)->ValidBMHeight) \
+ (h)->ValidBMWidth = le2me_32((h)->ValidBMWidth) \
+ (h)->ValidBMXOffset = le2me_32((h)->ValidXOffset) \
+ (h)->ValidBMYOffset = le2me_32((h)->ValidYOffset) \
+ (h)->VideoXOffsetInT = le2me_32((h)->VideoXOffsetInT) \
+ (h)->VideoYValidStartLine = le2me_32((h)->VideoYValidStartLine) \
+}
+
#else
#define le2me_MainAVIHeader(h) /**/
#define le2me_AVIStreamHeader(h) /**/
@@ -79,12 +200,12 @@
#define le2me_BITMAPINFOHEADER(h) /**/
#define le2me_WAVEFORMATEX(h) /**/
#define le2me_AVIINDEXENTRY(h) /**/
+#define le2me_AVISTDIDXCHUNK(h) /**/
+#define le2me_AVISTDIDXENTRY(h) /**/
+#define le2me_VideoPropHeader(h) /**/
+#define le2me_VIDEO_FIELD_DESC(h) /**/
#endif
-
-#endif
-
-
typedef struct {
// index stuff:
void* idx;
@@ -107,6 +228,13 @@ typedef struct {
unsigned char pts_corrected;
unsigned char pts_has_video;
unsigned int numberofframes;
+ avisuperindex_chunk *suidx;
+ int suidx_size;
+ int isodml;
} avi_priv_t;
#define AVI_PRIV ((avi_priv_t*)(demuxer->priv))
+
+#define AVI_IDX_OFFSET(x) ((((uint64_t)(x)->dwFlags&0xffff0000)<<16)+(x)->dwChunkOffset)
+
+#endif /* _aviheader_h */
diff --git a/libmpdemux/aviprint.c b/libmpdemux/aviprint.c
index 0f582da5a9..da271eae15 100644
--- a/libmpdemux/aviprint.c
+++ b/libmpdemux/aviprint.c
@@ -13,6 +13,8 @@
#include "wine/avifmt.h"
#include "wine/vfw.h"
+#include "aviheader.h"
+
//#include "codec-cfg.h"
//#include "stheader.h"
@@ -105,6 +107,31 @@ void print_video_header(BITMAPINFOHEADER *h){
printf("===========================\n");
}
+void print_vprp(VideoPropHeader *vprp){
+ int i;
+ printf("======= Video Properties Header =======\n");
+ printf("Format: %d VideoStandard: %d\n",
+ vprp->VideoFormatToken,vprp->VideoStandard);
+ printf("VRefresh: %d HTotal: %d VTotal: %d\n",
+ vprp->dwVerticalRefreshRate, vprp->dwHTotalInT, vprp->dwVTotalInLines);
+ printf("FrameAspect: %d:%d Framewidth: %d Frameheight: %d\n",
+ vprp->dwFrameAspectRatio >> 16, vprp->dwFrameAspectRatio & 0xffff,
+ vprp->dwFrameWidthInPixels, vprp->dwFrameHeightInLines);
+ printf("Fields: %d\n", vprp->nbFieldPerFrame);
+ for (i=0; i<vprp->nbFieldPerFrame; i++) {
+ VIDEO_FIELD_DESC *vfd = &vprp->FieldInfo[i];
+ printf(" == Field %d description ==\n", i);
+ printf(" CompressedBMHeight: %d CompressedBMWidth: %d\n",
+ vfd->CompressedBMHeight, vfd->CompressedBMWidth);
+ printf(" ValidBMHeight: %d ValidBMWidth: %d\n",
+ vfd->ValidBMHeight, vfd->ValidBMWidth);
+ printf(" ValidBMXOffset: %d ValidBMYOffset: %d\n",
+ vfd->ValidBMXOffset, vfd->ValidBMYOffset);
+ printf(" VideoXOffsetInT: %d VideoYValidStartLine: %d\n",
+ vfd->VideoXOffsetInT, vfd->VideoYValidStartLine);
+ }
+ printf("=======================================\n");
+}
void print_index(AVIINDEXENTRY *idx,int idx_size){
int i;
@@ -114,10 +141,10 @@ void print_index(AVIINDEXENTRY *idx,int idx_size){
for(i=0;i<idx_size;i++){
int id=avi_stream_id(idx[i].ckid);
if(id<0 || id>255) id=255;
- printf("%5d: %.4s %4X %08X len:%6ld pos:%7d->%7.3f %7d->%7.3f\n",i,
+ printf("%5d: %.4s %4X %016llX len:%6ld pos:%7d->%7.3f %7d->%7.3f\n",i,
(char *)&idx[i].ckid,
- (unsigned int)idx[i].dwFlags,
- (unsigned int)idx[i].dwChunkOffset,
+ (unsigned int)idx[i].dwFlags&0xffff,
+ (uint64_t)AVI_IDX_OFFSET(&idx[i]),
// idx[i].dwChunkOffset+demuxer->movi_start,
idx[i].dwChunkLength,
pos[id],(float)pos[id]/18747.0f,
@@ -128,4 +155,21 @@ 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");
+}
diff --git a/libmpdemux/demux_avi.c b/libmpdemux/demux_avi.c
index 9d2fa17f1d..bef49b1e45 100644
--- a/libmpdemux/demux_avi.c
+++ b/libmpdemux/demux_avi.c
@@ -213,7 +213,7 @@ do{
continue; // skip this chunk
}
- pos = priv->idx_offset + (unsigned long)idx->dwChunkOffset;
+ pos = (off_t)priv->idx_offset+AVI_IDX_OFFSET(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;
@@ -325,7 +325,7 @@ do{
continue; // skip this chunk
}
- pos = priv->idx_offset+(unsigned long)idx->dwChunkOffset;
+ pos = priv->idx_offset+AVI_IDX_OFFSET(idx);
if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start)){
mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! current=0x%X idx=0x%X \n",demux->filepos,pos);
continue;
@@ -446,6 +446,10 @@ demuxer_t* demux_open_avi(demuxer_t* demuxer){
priv->video_pack_no=0;
priv->audio_block_no=0;
priv->audio_block_size=0;
+ priv->isodml = 0;
+ priv->suidx_size = 0;
+ priv->suidx = NULL;
+
demuxer->priv=(void*)priv;
//---- AVI header:
@@ -468,13 +472,13 @@ demuxer_t* demux_open_avi(demuxer_t* demuxer){
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((AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[0])<demuxer->movi_start ||
+ AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[1])<demuxer->movi_start )&& !priv->isodml)
priv->idx_offset=demuxer->movi_start-4;
else
priv->idx_offset=0;
#else
- if((unsigned long)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start)
+ if(AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[0])<demuxer->movi_start)
priv->idx_offset=demuxer->movi_start-4;
else
priv->idx_offset=0;
@@ -494,7 +498,7 @@ demuxer_t* demux_open_avi(demuxer_t* demuxer){
for(i=0;i<priv->idx_size;i++){
AVIINDEXENTRY* idx=&((AVIINDEXENTRY *)priv->idx)[i];
demux_stream_t* ds=demux_avi_select_stream(demuxer,idx->ckid);
- off_t pos = priv->idx_offset + (unsigned long)idx->dwChunkOffset;
+ off_t pos = priv->idx_offset + AVI_IDX_OFFSET(idx);
if(a_pos==-1 && ds==demuxer->audio){
a_pos=pos;
if(v_pos!=-1) break;
diff --git a/libmpdemux/muxer.h b/libmpdemux/muxer.h
index 696d25bc32..bf546fca1f 100644
--- a/libmpdemux/muxer.h
+++ b/libmpdemux/muxer.h
@@ -48,9 +48,9 @@ typedef struct {
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;
diff --git a/libmpdemux/muxer_avi.c b/libmpdemux/muxer_avi.c
index f98f4b0002..f6be330f69 100644
--- a/libmpdemux/muxer_avi.c
+++ b/libmpdemux/muxer_avi.c
@@ -1,16 +1,16 @@
-
#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 "stream.h"
+#include "demuxer.h"
+#include "stheader.h"
#include "wine/mmreg.h"
#include "wine/avifmt.h"
@@ -19,6 +19,7 @@
#include "muxer.h"
#include "aviheader.h"
+#include "mp_msg.h"
extern char *info_name;
extern char *info_artist;
@@ -28,11 +29,38 @@ extern char *info_copyright;
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 +72,11 @@ static muxer_stream_t* avifile_new_stream(muxer_t *muxer,int type){
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 +88,7 @@ static muxer_stream_t* avifile_new_stream(muxer_t *muxer,int type){
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,28 +123,80 @@ if(len>0){
}
}
+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;
+ int isodml = muxer->file_end > ODML_CHUNKLEN ? 1 : 0;
+
+ if (!isodml) {
+ // 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=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 = muxer->file_end;
+ if (pos < ODML_CHUNKLEN &&
+ pos + 16*muxer->idx_pos + len + 8 > ODML_CHUNKLEN) {
- // add to the index:
- if(muxer->idx_pos>=muxer->idx_size){
- muxer->idx_size+=256; // 4kB
- muxer->idx=realloc(muxer->idx,16*muxer->idx_size);
+ avifile_write_index(muxer);
+ avifile_odml_new_riff(muxer)