summaryrefslogtreecommitdiffstats
path: root/libmpdemux/aviheader.c
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 /libmpdemux/aviheader.c
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
Diffstat (limited to 'libmpdemux/aviheader.c')
-rw-r--r--libmpdemux/aviheader.c268
1 files changed, 264 insertions, 4 deletions
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
}
}