Update Haali's MatroskaParser.c/.h in the main source tree (there's a copy in the FFMS2 folder as well, which will be updated later). Should fix a crash with x264-generated MKV's.

Originally committed to SVN as r2884.
This commit is contained in:
Karl Blomster 2009-04-29 21:00:08 +00:00
parent f0b442f4b4
commit 2f7b62d206
3 changed files with 151 additions and 209 deletions

View file

@ -1,32 +1,6 @@
/* /*
* Copyright (c) 2004-2006 Mike Matsnev. All Rights Reserved. * Copyright (c) 2004-2009 Mike Matsnev. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Absolutely no warranty of function or purpose is made by the author
* Mike Matsnev.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: MatroskaParser.c,v 1.59.2.4 2006/01/13 01:44:45 mike Exp $
*
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -35,10 +9,6 @@
#include <string.h> #include <string.h>
#include <setjmp.h> #include <setjmp.h>
#ifdef _MSC_VER
#pragma warning(disable: 4701)
#endif
#ifdef _WIN32 #ifdef _WIN32
// MS names some functions differently // MS names some functions differently
#define alloca _alloca #define alloca _alloca
@ -100,8 +70,7 @@ static char *mystrdup(struct InputStream *is,const char *src) {
return dst; return dst;
} }
#if !defined(__FreeBSD__) && !defined(__APPLE__) static void mystrlcpy(char *dst,const char *src,unsigned size) {
static void strlcpy(char *dst,const char *src,unsigned size) {
unsigned i; unsigned i;
for (i=0;i+1<size && src[i];++i) for (i=0;i+1<size && src[i];++i)
@ -109,7 +78,6 @@ static void strlcpy(char *dst,const char *src,unsigned size) {
if (i<size) if (i<size)
dst[i] = 0; dst[i] = 0;
} }
#endif
struct Cue { struct Cue {
ulonglong Time; ulonglong Time;
@ -244,7 +212,7 @@ static void myvsnprintf_uint_impl(char **pdest,char *de,int width,int zero,
int rem = (int)(val % base); int rem = (int)(val % base);
val = val / base; val = val / base;
*--np = (char) (rem < 10 ? rem + '0' : rem - 10 + letter); *--np = (char)(rem < 10 ? rem + '0' : rem - 10 + letter);
} }
rw = (int)(tmp - np + sizeof(tmp) - 1); rw = (int)(tmp - np + sizeof(tmp) - 1);
@ -294,7 +262,7 @@ static void myvsnprintf_int(char **pdest,char *de,int width,int zero,
static void myvsnprintf(char *dest,unsigned dsize,const char *fmt,va_list ap) { static void myvsnprintf(char *dest,unsigned dsize,const char *fmt,va_list ap) {
// s,d,x,u,ll // s,d,x,u,ll
char *de = dest + dsize - 1; char *de = dest + dsize - 1;
int state = 0, width=0, zero=0, neg=0, ll=0; int state = 0, width, zero, neg, ll;
if (dsize <= 1) { if (dsize <= 1) {
if (dsize > 0) if (dsize > 0)
@ -570,7 +538,7 @@ static void readbytes(MatroskaFile *mf,void *buffer,int len) {
static void skipbytes(MatroskaFile *mf,ulonglong len) { static void skipbytes(MatroskaFile *mf,ulonglong len) {
int nb = mf->buflen - mf->bufpos; int nb = mf->buflen - mf->bufpos;
if (nb > (int)len) if (nb > len)
nb = (int)len; nb = (int)len;
mf->bufpos += nb; mf->bufpos += nb;
@ -691,7 +659,7 @@ static ulonglong readVLUIntImp(MatroskaFile *mf,int *mask) {
c = readch(mf); c = readch(mf);
if (c == EOF) if (c == EOF)
return (ulonglong)EOF; return 0; // XXX should errorjmp()?
if (c == 0) if (c == 0)
errorjmp(mf,"Invalid first byte of EBML integer: 0"); errorjmp(mf,"Invalid first byte of EBML integer: 0");
@ -766,7 +734,6 @@ static MKFLOAT readFloat(MatroskaFile *mf,unsigned int len) {
#ifdef MATROSKA_INTEGER_ONLY #ifdef MATROSKA_INTEGER_ONLY
MKFLOAT f; MKFLOAT f;
int shift; int shift;
f.v = 0;
#else #else
union { union {
unsigned int ui; unsigned int ui;
@ -774,9 +741,6 @@ static MKFLOAT readFloat(MatroskaFile *mf,unsigned int len) {
float f; float f;
double d; double d;
} u; } u;
ui = 0;
d = 0;
ull = 0;
#endif #endif
if (len!=4 && len!=8) if (len!=4 && len!=8)
@ -850,7 +814,7 @@ static void readString(MatroskaFile *mf,ulonglong len,char *buffer,int buflen) {
nread = buflen - 1; nread = buflen - 1;
if (nread > (int)len) if (nread > len)
nread = (int)len; nread = (int)len;
readbytes(mf,buffer,nread); readbytes(mf,buffer,nread);
@ -916,6 +880,16 @@ static void readLangCC(MatroskaFile *mf, ulonglong len, char lcc[4]) {
#define STRGETA(f,v,len) STRGETF(f,v,len,myalloca) #define STRGETA(f,v,len) STRGETF(f,v,len,myalloca)
#define STRGETM(f,v,len) STRGETF(f,v,len,f->cache->memalloc) #define STRGETM(f,v,len) STRGETF(f,v,len,f->cache->memalloc)
static int IsWritingApp(MatroskaFile *mf,const char *str) {
const char *cp = mf->Seg.WritingApp;
if (!cp)
return 0;
while (*str && *str++==*cp++) ;
return !*str;
}
static void parseEBML(MatroskaFile *mf,ulonglong toplen) { static void parseEBML(MatroskaFile *mf,ulonglong toplen) {
ulonglong v; ulonglong v;
char buf[32]; char buf[32];
@ -1059,6 +1033,7 @@ static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) {
break; break;
case 0x4461: // DateUTC case 0x4461: // DateUTC
mf->Seg.DateUTC = readUInt(mf,(unsigned)len); mf->Seg.DateUTC = readUInt(mf,(unsigned)len);
mf->Seg.DateUTCValid = 1;
break; break;
case 0x7ba9: // Title case 0x7ba9: // Title
STRGETM(mf,mf->Seg.Title,len); STRGETM(mf,mf->Seg.Title,len);
@ -1075,6 +1050,8 @@ static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) {
} }
static void parseFirstCluster(MatroskaFile *mf,ulonglong toplen) { static void parseFirstCluster(MatroskaFile *mf,ulonglong toplen) {
ulonglong end = filepos(mf) + toplen;
mf->seen.Cluster = 1; mf->seen.Cluster = 1;
mf->firstTimecode = 0; mf->firstTimecode = 0;
@ -1086,7 +1063,7 @@ static void parseFirstCluster(MatroskaFile *mf,ulonglong toplen) {
readVLUInt(mf); // track number readVLUInt(mf); // track number
mf->firstTimecode += readSInt(mf, 2); mf->firstTimecode += readSInt(mf, 2);
skipbytes(mf,start + toplen - filepos(mf)); skipbytes(mf,end - filepos(mf));
return; return;
case 0xa0: // BlockGroup case 0xa0: // BlockGroup
FOREACH(mf,len) FOREACH(mf,len)
@ -1094,7 +1071,7 @@ static void parseFirstCluster(MatroskaFile *mf,ulonglong toplen) {
readVLUInt(mf); // track number readVLUInt(mf); // track number
mf->firstTimecode += readSInt(mf,2); mf->firstTimecode += readSInt(mf,2);
skipbytes(mf,start + toplen - filepos(mf)); skipbytes(mf,end - filepos(mf));
return; return;
ENDFOR(mf); ENDFOR(mf);
break; break;
@ -1244,7 +1221,7 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
ulonglong v; ulonglong v;
char *cp = NULL, *cs = NULL; char *cp = NULL, *cs = NULL;
size_t cplen = 0, cslen = 0, cpadd = 0; size_t cplen = 0, cslen = 0, cpadd = 0;
unsigned CompScope=0, num_comp = 0; unsigned CompScope, num_comp = 0;
if (mf->nTracks >= MAX_TRACKS) if (mf->nTracks >= MAX_TRACKS)
errorjmp(mf,"Too many tracks."); errorjmp(mf,"Too many tracks.");
@ -1421,7 +1398,7 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
// handle compressed CodecPrivate // handle compressed CodecPrivate
if (t.CompEnabled && t.CompMethod == COMP_ZLIB && (CompScope & 2) && cplen > 0) { if (t.CompEnabled && t.CompMethod == COMP_ZLIB && (CompScope & 2) && cplen > 0) {
z_stream zs; z_stream zs;
char tmp[64], *ncp; Bytef tmp[64], *ncp;
int code; int code;
uLong ncplen; uLong ncplen;
@ -1429,11 +1406,11 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
if (inflateInit(&zs) != Z_OK) if (inflateInit(&zs) != Z_OK)
errorjmp(mf, "inflateInit failed"); errorjmp(mf, "inflateInit failed");
zs.next_in = (Bytef*) cp; zs.next_in = (Bytef *)cp;
zs.avail_in = cplen; zs.avail_in = cplen;
do { do {
zs.next_out = (Bytef*) tmp; zs.next_out = tmp;
zs.avail_out = sizeof(tmp); zs.avail_out = sizeof(tmp);
code = inflate(&zs, Z_NO_FLUSH); code = inflate(&zs, Z_NO_FLUSH);
@ -1447,9 +1424,9 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
inflateReset(&zs); inflateReset(&zs);
zs.next_in = (Bytef*) cp; zs.next_in = (Bytef *)cp;
zs.avail_in = cplen; zs.avail_in = cplen;
zs.next_out = (Bytef*) ncp; zs.next_out = ncp;
zs.avail_out = ncplen; zs.avail_out = ncplen;
if (inflate(&zs, Z_FINISH) != Z_STREAM_END) if (inflate(&zs, Z_FINISH) != Z_STREAM_END)
@ -1457,7 +1434,7 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
inflateEnd(&zs); inflateEnd(&zs);
cp = ncp; cp = (char *)ncp;
cplen = ncplen; cplen = ncplen;
} }
#endif #endif
@ -1488,7 +1465,7 @@ static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) {
} }
if (cslen) { if (cslen) {
tp->CompMethodPrivate = (char *)(tp+1) + cplen; tp->CompMethodPrivate = (char *)(tp+1) + cplen;
tp->CompMethodPrivateSize = cslen; tp->CompMethodPrivateSize = (unsigned)cslen;
memcpy(tp->CompMethodPrivate, cs, cslen); memcpy(tp->CompMethodPrivate, cs, cslen);
} }
@ -1979,85 +1956,84 @@ static void parsePointers(MatroskaFile *mf) {
static void parseSegment(MatroskaFile *mf,ulonglong toplen) { static void parseSegment(MatroskaFile *mf,ulonglong toplen) {
ulonglong nextpos; ulonglong nextpos;
unsigned nSeekHeads = 0, dontstop = 0; unsigned nSeekHeads = 0, dontstop = 0;
jmp_buf jb;
// we want to read data until we find a seekhead or a trackinfo memcpy(&jb,&mf->jb,sizeof(jb));
FOREACH(mf,toplen)
case 0x114d9b74: // SeekHead
if (mf->flags & MKVF_AVOID_SEEKS) {
skipbytes(mf,len);
break;
}
nextpos = filepos(mf) + len; if (setjmp(mf->jb))
do { mf->flags &= ~MPF_ERROR;
mf->pSeekHead = 0; else {
parseSeekHead(mf,len); // we want to read data until we find a seekhead or a trackinfo
++nSeekHeads; FOREACH(mf,toplen)
if (mf->pSeekHead) { // this is possibly a chained SeekHead case 0x114d9b74: // SeekHead
seek(mf,mf->pSeekHead); if (mf->flags & MKVF_AVOID_SEEKS) {
id = readID(mf); skipbytes(mf,len);
if (id==EOF) // chained SeekHead points to EOF? break;
break; }
if (id != 0x114d9b74) // chained SeekHead doesnt point to a SeekHead?
break; nextpos = filepos(mf) + len;
len = readSize(mf); do {
} else if (mf->pSegmentInfo && mf->pTracks && mf->pCues && mf->pCluster) { // we have pointers to all key elements mf->pSeekHead = 0;
// XXX EVIL HACK parseSeekHead(mf,len);
// Some software doesnt index tags via SeekHead, so we continue ++nSeekHeads;
// reading the segment after the second SeekHead if (mf->pSeekHead) { // this is possibly a chained SeekHead
if (mf->pTags || nSeekHeads<2 || filepos(mf)>=start+toplen) { seek(mf,mf->pSeekHead);
parsePointers(mf); id = readID(mf);
return; if (id==EOF) // chained SeekHead points to EOF?
break;
if (id != 0x114d9b74) // chained SeekHead doesnt point to a SeekHead?
break;
len = readSize(mf);
} }
// reset nextpos pointer to current position } while (mf->pSeekHead && nSeekHeads < 10);
nextpos = filepos(mf); seek(mf,nextpos); // resume reading segment
dontstop = 1; break;
} case 0x1549a966: // SegmentInfo
} while (mf->pSeekHead); mf->pSegmentInfo = cur;
seek(mf,nextpos); // resume reading segment parseSegmentInfo(mf,len);
break; break;
case 0x1549a966: // SegmentInfo case 0x1f43b675: // Cluster
mf->pSegmentInfo = cur; if (!mf->pCluster)
parseSegmentInfo(mf,len); mf->pCluster = cur;
break; if (mf->seen.Cluster)
case 0x1f43b675: // Cluster skipbytes(mf,len);
if (!mf->pCluster) else
mf->pCluster = cur; parseFirstCluster(mf,len);
if (mf->seen.Cluster) break;
skipbytes(mf,len); case 0x1654ae6b: // Tracks
else mf->pTracks = cur;
parseFirstCluster(mf,len); parseTracks(mf,len);
break; break;
case 0x1654ae6b: // Tracks case 0x1c53bb6b: // Cues
mf->pTracks = cur; mf->pCues = cur;
parseTracks(mf,len); parseCues(mf,len);
break; break;
case 0x1c53bb6b: // Cues case 0x1941a469: // Attachments
mf->pCues = cur; mf->pAttachments = cur;
parseCues(mf,len); parseAttachments(mf,len);
break; break;
case 0x1941a469: // Attachments case 0x1043a770: // Chapters
mf->pAttachments = cur; mf->pChapters = cur;
parseAttachments(mf,len); parseChapters(mf,len);
break; break;
case 0x1043a770: // Chapters case 0x1254c367: // Tags
mf->pChapters = cur; mf->pTags = cur;
parseChapters(mf,len); parseTags(mf,len);
break; break;
case 0x1254c367: // Tags ENDFOR1(mf);
mf->pTags = cur; // if we have pointers to all key elements
parseTags(mf,len); if (!dontstop && mf->pSegmentInfo && mf->pTracks && mf->pCluster)
break; break;
ENDFOR1(mf); ENDFOR2();
// if we have pointers to all key elements }
if (!dontstop && mf->pSegmentInfo && mf->pTracks && mf->pCluster)
break; memcpy(&mf->jb,&jb,sizeof(jb));
ENDFOR2();
parsePointers(mf); parsePointers(mf);
} }
static void parseBlockAdditions(MatroskaFile *mf, ulonglong toplen, ulonglong timecode, unsigned track) { static void parseBlockAdditions(MatroskaFile *mf, ulonglong toplen, ulonglong timecode, unsigned track) {
ulonglong add_id = 1, add_pos=0, add_len=0; ulonglong add_id = 1, add_pos, add_len;
unsigned char have_add; unsigned char have_add;
FOREACH(mf, toplen) FOREACH(mf, toplen)
@ -2089,10 +2065,9 @@ static void parseBlockAdditions(MatroskaFile *mf, ulonglong toplen, ulonglong ti
} }
static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode, int blockex) { static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode, int blockex) {
ulonglong v=0; ulonglong v;
ulonglong duration = 0; ulonglong duration = 0;
ulonglong dpos=0; ulonglong dpos;
//unsigned add_id = 0;
struct QueueEntry *qe,*qf = NULL; struct QueueEntry *qe,*qf = NULL;
unsigned char have_duration = 0, have_block = 0; unsigned char have_duration = 0, have_block = 0;
unsigned char gap = 0; unsigned char gap = 0;
@ -2149,7 +2124,7 @@ found:
errorjmp(mf,"Unexpected EOF while reading Block flags"); errorjmp(mf,"Unexpected EOF while reading Block flags");
if (blockex) if (blockex)
ref = (unsigned char)(!(c & 0x80)); ref = (unsigned char)!(c & 0x80);
gap = (unsigned char)(c & 0x1); gap = (unsigned char)(c & 0x1);
lacing = (unsigned char)((c >> 1) & 3); lacing = (unsigned char)((c >> 1) & 3);
@ -2246,14 +2221,17 @@ out:
errorjmp(mf,"Found a BlockGroup without Block"); errorjmp(mf,"Found a BlockGroup without Block");
if (nframes > 1) { if (nframes > 1) {
ulonglong defd = mf->Tracks[tracknum]->DefaultDuration;
v = qf->Start;
if (have_duration) { if (have_duration) {
duration = mul3(mf->Tracks[tracknum]->TimecodeScale, duration = mul3(mf->Tracks[tracknum]->TimecodeScale,
duration * mf->Seg.TimecodeScale); duration * mf->Seg.TimecodeScale);
for (qe = qf; nframes > 1; --nframes, qe = qe->next) { for (qe = qf; nframes > 1; --nframes, qe = qe->next) {
qe->Start = v; qe->Start = v;
v += dpos; v += defd;
duration -= dpos; duration -= defd;
qe->End = v; qe->End = v;
#if 0 #if 0
qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END); qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
@ -2263,11 +2241,9 @@ out:
qe->End = v + duration; qe->End = v + duration;
qe->flags &= ~FRAME_UNKNOWN_END; qe->flags &= ~FRAME_UNKNOWN_END;
} else if (mf->Tracks[tracknum]->DefaultDuration) { } else if (mf->Tracks[tracknum]->DefaultDuration) {
dpos = mf->Tracks[tracknum]->DefaultDuration;
v = qf->Start;
for (qe = qf; nframes > 0; --nframes, qe = qe->next) { for (qe = qf; nframes > 0; --nframes, qe = qe->next) {
qe->Start = v; qe->Start = v;
v += dpos; v += defd;
qe->End = v; qe->End = v;
qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END); qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END);
} }
@ -2758,7 +2734,7 @@ MatroskaFile *mkv_OpenEx(InputStream *io,
{ {
MatroskaFile *mf = io->memalloc(io,sizeof(*mf)); MatroskaFile *mf = io->memalloc(io,sizeof(*mf));
if (mf == NULL) { if (mf == NULL) {
strlcpy(err_msg,"Out of memory",msgsize); mystrlcpy(err_msg,"Out of memory",msgsize);
return NULL; return NULL;
} }
@ -2772,7 +2748,7 @@ MatroskaFile *mkv_OpenEx(InputStream *io,
seek(mf,base); seek(mf,base);
parseFile(mf); parseFile(mf);
} else { // parser error } else { // parser error
strlcpy(err_msg,mf->errmsg,msgsize); mystrlcpy(err_msg,mf->errmsg,msgsize);
mkv_Close(mf); mkv_Close(mf);
return NULL; return NULL;
} }
@ -2913,7 +2889,7 @@ void mkv_Seek(MatroskaFile *mf,ulonglong timecode,unsigned flags) {
mkv_SetTrackMask(mf,mf->trackMask); mkv_SetTrackMask(mf,mf->trackMask);
if (flags & MKVF_SEEK_TO_PREV_KEYFRAME) { if (flags & (MKVF_SEEK_TO_PREV_KEYFRAME | MKVF_SEEK_TO_PREV_KEYFRAME_STRICT)) {
// we do this in two stages // we do this in two stages
// a. find the last keyframes before the require position // a. find the last keyframes before the require position
// b. seek to them // b. seek to them
@ -2928,7 +2904,7 @@ void mkv_Seek(MatroskaFile *mf,ulonglong timecode,unsigned flags) {
EmptyQueues(mf); EmptyQueues(mf);
mf->readPosition = mf->Cues[j].Position + mf->pSegment; mf->readPosition = mf->Cues[j].Position + mf->pSegment;
mf->tcCluster = mf->Cues[j].Time / mf->Seg.TimecodeScale; mf->tcCluster = mf->Cues[j].Time;
for (;;) { for (;;) {
if ((ret = fillQueues(mf,0)) < 0 || ret == RBRESYNC) if ((ret = fillQueues(mf,0)) < 0 || ret == RBRESYNC)
@ -2936,7 +2912,7 @@ void mkv_Seek(MatroskaFile *mf,ulonglong timecode,unsigned flags) {
// drain queues until we get to the required timecode // drain queues until we get to the required timecode
for (n=0;n<mf->nTracks;++n) { for (n=0;n<mf->nTracks;++n) {
if (mf->Queues[n].head && mf->Queues[n].head->Start<timecode) { if (mf->Queues[n].head && (mf->Queues[n].head->Start<timecode || (m_seendf[n] == 0 && m_kftime[n] == MAXU64))) {
if (IS_DELTA(mf->Queues[n].head)) if (IS_DELTA(mf->Queues[n].head))
m_seendf[n] = 1; m_seendf[n] = 1;
else else
@ -2952,9 +2928,14 @@ void mkv_Seek(MatroskaFile *mf,ulonglong timecode,unsigned flags) {
QFree(mf,QGet(&mf->Queues[n])); QFree(mf,QGet(&mf->Queues[n]));
} }
if (mf->Queues[n].head && (mf->Tracks[n]->Type != TT_AUDIO || mf->Queues[n].head->Start<=timecode)) // We've drained the queue, so the frame at head is the next one past the requered point.
if (!IS_DELTA(mf->Queues[n].head)) // In strict mode we are done, but when seeking is not strict we use the head frame
m_kftime[n] = mf->Queues[n].head->Start; // if it's not an audio track (we accept preroll within a frame for audio), and the head frame
// is a keyframe
if (!(flags & MKVF_SEEK_TO_PREV_KEYFRAME_STRICT))
if (mf->Queues[n].head && (mf->Tracks[n]->Type != TT_AUDIO || mf->Queues[n].head->Start<=timecode))
if (!IS_DELTA(mf->Queues[n].head))
m_kftime[n] = mf->Queues[n].head->Start;
} }
for (n=0;n<mf->nTracks;++n) for (n=0;n<mf->nTracks;++n)
@ -2983,7 +2964,7 @@ again:;
EmptyQueues(mf); EmptyQueues(mf);
mf->readPosition = mf->Cues[j].Position + mf->pSegment; mf->readPosition = mf->Cues[j].Position + mf->pSegment;
mf->tcCluster = mf->Cues[j].Time / mf->Seg.TimecodeScale; mf->tcCluster = mf->Cues[j].Time;
for (mask=0;;) { for (mask=0;;) {
if ((ret = fillQueues(mf,mask)) < 0 || ret == RBRESYNC) if ((ret = fillQueues(mf,mask)) < 0 || ret == RBRESYNC)
@ -3178,30 +3159,30 @@ CompressedStream *cs_Create(/* in */ MatroskaFile *mf,
ti = mkv_GetTrackInfo(mf, tracknum); ti = mkv_GetTrackInfo(mf, tracknum);
if (ti == NULL) { if (ti == NULL) {
strlcpy(errormsg, "No such track.", msgsize); mystrlcpy(errormsg, "No such track.", msgsize);
return NULL; return NULL;
} }
if (!ti->CompEnabled) { if (!ti->CompEnabled) {
strlcpy(errormsg, "Track is not compressed.", msgsize); mystrlcpy(errormsg, "Track is not compressed.", msgsize);
return NULL; return NULL;
} }
if (ti->CompMethod != COMP_ZLIB) { if (ti->CompMethod != COMP_ZLIB) {
strlcpy(errormsg, "Unsupported compression method.", msgsize); mystrlcpy(errormsg, "Unsupported compression method.", msgsize);
return NULL; return NULL;
} }
cs = mf->cache->memalloc(mf->cache,sizeof(*cs)); cs = mf->cache->memalloc(mf->cache,sizeof(*cs));
if (cs == NULL) { if (cs == NULL) {
strlcpy(errormsg, "Ouf of memory.", msgsize); mystrlcpy(errormsg, "Ouf of memory.", msgsize);
return NULL; return NULL;
} }
memset(&cs->zs,0,sizeof(cs->zs)); memset(&cs->zs,0,sizeof(cs->zs));
code = inflateInit(&cs->zs); code = inflateInit(&cs->zs);
if (code != Z_OK) { if (code != Z_OK) {
strlcpy(errormsg, "ZLib error.", msgsize); mystrlcpy(errormsg, "ZLib error.", msgsize);
mf->cache->memfree(mf->cache,cs); mf->cache->memfree(mf->cache,cs);
return NULL; return NULL;
} }
@ -3257,7 +3238,7 @@ int cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize)
cs->decoded_ptr += todo; cs->decoded_ptr += todo;
} else { } else {
/* setup output buffer */ /* setup output buffer */
cs->zs.next_out = (Bytef*) cs->decoded_buffer; cs->zs.next_out = (Bytef *)cs->decoded_buffer;
cs->zs.avail_out = sizeof(cs->decoded_buffer); cs->zs.avail_out = sizeof(cs->decoded_buffer);
/* try to read more data */ /* try to read more data */
@ -3267,11 +3248,11 @@ int cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize)
todo = sizeof(cs->frame_buffer); todo = sizeof(cs->frame_buffer);
if (cs->mf->cache->read(cs->mf->cache, cs->frame_pos, cs->frame_buffer, todo) != (int)todo) { if (cs->mf->cache->read(cs->mf->cache, cs->frame_pos, cs->frame_buffer, todo) != (int)todo) {
strlcpy(cs->errmsg, "File read failed", sizeof(cs->errmsg)); mystrlcpy(cs->errmsg, "File read failed", sizeof(cs->errmsg));
return -1; return -1;
} }
cs->zs.next_in = (Bytef*) cs->frame_buffer; cs->zs.next_in = (Bytef *)cs->frame_buffer;
cs->zs.avail_in = todo; cs->zs.avail_in = todo;
cs->frame_pos += todo; cs->frame_pos += todo;
@ -3281,7 +3262,7 @@ int cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize)
/* try to decode more data */ /* try to decode more data */
code = inflate(&cs->zs,Z_NO_FLUSH); code = inflate(&cs->zs,Z_NO_FLUSH);
if (code != Z_OK && code != Z_STREAM_END) { if (code != Z_OK && code != Z_STREAM_END) {
strlcpy(cs->errmsg, "ZLib error.", sizeof(cs->errmsg)); mystrlcpy(cs->errmsg, "ZLib error.", sizeof(cs->errmsg));
return -1; return -1;
} }

View file

@ -1,41 +1,11 @@
/* /*
* Copyright (c) 2004-2006 Mike Matsnev. All Rights Reserved. * Copyright (c) 2004-2009 Mike Matsnev. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Absolutely no warranty of function or purpose is made by the author
* Mike Matsnev.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: MatroskaParser.h,v 1.18.2.6 2006/01/13 01:44:45 mike Exp $
*
*/ */
#ifndef MATROSKA_PARSER_H #ifndef MATROSKA_PARSER_H
#define MATROSKA_PARSER_H #define MATROSKA_PARSER_H
#ifdef _MSC_VER
#pragma warning(disable: 4201)
#endif
/* Random notes: /* Random notes:
* *
* The parser does not process frame data in any way and does not read it into * The parser does not process frame data in any way and does not read it into
@ -132,13 +102,12 @@ struct TrackInfo {
void *CompMethodPrivate; void *CompMethodPrivate;
unsigned CompMethodPrivateSize; unsigned CompMethodPrivateSize;
unsigned MaxBlockAdditionID; unsigned MaxBlockAdditionID;
struct {
unsigned int Enabled:1; unsigned int Enabled:1;
unsigned int Default:1; unsigned int Default:1;
unsigned int Lacing:1; unsigned int Lacing:1;
unsigned int DecodeAll:1; unsigned int DecodeAll:1;
unsigned int CompEnabled:1; unsigned int CompEnabled:1;
};
union { union {
struct { struct {
@ -152,9 +121,8 @@ struct TrackInfo {
unsigned int CropL, CropT, CropR, CropB; unsigned int CropL, CropT, CropR, CropB;
unsigned int ColourSpace; unsigned int ColourSpace;
MKFLOAT GammaValue; MKFLOAT GammaValue;
struct {
unsigned int Interlaced:1; unsigned int Interlaced:1;
};
} Video; } Video;
struct { struct {
MKFLOAT SamplingFreq; MKFLOAT SamplingFreq;
@ -184,7 +152,8 @@ struct SegmentInfo {
char *WritingApp; char *WritingApp;
ulonglong TimecodeScale; ulonglong TimecodeScale;
ulonglong Duration; ulonglong Duration;
ulonglong DateUTC; longlong DateUTC;
char DateUTCValid;
}; };
typedef struct SegmentInfo SegmentInfo; typedef struct SegmentInfo SegmentInfo;
@ -236,14 +205,12 @@ struct Chapter {
char SegmentUID[16]; char SegmentUID[16];
struct { unsigned int Hidden:1;
unsigned int Hidden:1; unsigned int Enabled:1;
unsigned int Enabled:1;
// Editions // Editions
unsigned int Default:1; unsigned int Default:1;
unsigned int Ordered:1; unsigned int Ordered:1;
};
}; };
typedef struct Chapter Chapter; typedef struct Chapter Chapter;
@ -322,7 +289,8 @@ X ulonglong mkv_GetSegmentTop(MatroskaFile *mf);
* all tracks are set to return EOF * all tracks are set to return EOF
* on next read * on next read
*/ */
#define MKVF_SEEK_TO_PREV_KEYFRAME 1 #define MKVF_SEEK_TO_PREV_KEYFRAME 1
#define MKVF_SEEK_TO_PREV_KEYFRAME_STRICT 2
X void mkv_Seek(/* in */ MatroskaFile *mf, X void mkv_Seek(/* in */ MatroskaFile *mf,
/* in */ ulonglong timecode /* in ns */, /* in */ ulonglong timecode /* in ns */,
@ -399,8 +367,4 @@ X const char *cs_GetLastError(CompressedStream *cs);
#undef X #undef X
#ifdef _MSC_VER
#pragma warning(default: 4201)
#endif
#endif #endif

View file

@ -222,9 +222,6 @@ const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int _n, int FormatType)
// this is what we'll return eventually // this is what we'll return eventually
AegiVideoFrame &DstFrame = CurFrame; AegiVideoFrame &DstFrame = CurFrame;
// FIXME: find out how this actually works with ffmpeg
//bool big_endian = Endian::BigToMachine((unsigned int)1)==(unsigned int)1;
// choose output format // choose output format
if (FormatType & FORMAT_RGB32) { if (FormatType & FORMAT_RGB32) {
DstFormat = FFMS_GetPixFmt("bgra"); DstFormat = FFMS_GetPixFmt("bgra");