diff --git a/FFmpegSource/MatroskaParser.c b/FFmpegSource/MatroskaParser.c deleted file mode 100644 index d6ff7b320..000000000 --- a/FFmpegSource/MatroskaParser.c +++ /dev/null @@ -1,3311 +0,0 @@ -/* - * Copyright (c) 2004-2006 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.61 2006/10/28 10:39:45 mike Exp $ - * - */ - -#include -#include -#include -#include -#include - -#ifdef _WIN32 -// MS names some functions differently -#define alloca _alloca -#define inline __inline - -#include -#endif - -#ifndef EVCBUG -#define EVCBUG -#endif - -#include "MatroskaParser.h" - -#ifdef MATROSKA_COMPRESSION_SUPPORT -#include "zlib.h" -#endif - -#define EBML_VERSION 1 -#define EBML_MAX_ID_LENGTH 4 -#define EBML_MAX_SIZE_LENGTH 8 -#define MATROSKA_VERSION 2 -#define MATROSKA_DOCTYPE "matroska" - -#define MAX_STRING_LEN 1023 -#define QSEGSIZE 512 -#define MAX_TRACKS 32 -#define MAX_READAHEAD (256*1024) - -#define MAXCLUSTER (64*1048576) -#define MAXFRAME (4*1048576) - -#ifdef WIN32 -#define LL(x) x##i64 -#define ULL(x) x##ui64 -#else -#define LL(x) x##ll -#define ULL(x) x##ull -#endif - -#define MAXU64 ULL(0xffffffffffffffff) -#define ONE ULL(1) - -// compatibility -static char *mystrdup(struct InputStream *is,const char *src) { - size_t len; - char *dst; - - if (src==NULL) - return NULL; - - len = strlen(src); - dst = is->memalloc(is,len+1); - if (dst==NULL) - return NULL; - - memcpy(dst,src,len+1); - - return dst; -} - -#ifdef _WIN32 -static void strlcpy(char *dst,const char *src,unsigned size) { - unsigned i; - - for (i=0;i+1 0) - *dest = '\0'; - return; - } - - while (*fmt && dest < de) - switch (state) { - case 0: - if (*fmt == '%') { - ++fmt; - state = 1; - width = zero = neg = ll = 0; - } else - *dest++ = *fmt++; - break; - case 1: - if (*fmt == '-') { - neg = 1; - ++fmt; - state = 2; - break; - } - if (*fmt == '0') - zero = 1; - state = 2; - case 2: - if (*fmt >= '0' && *fmt <= '9') { - width = width * 10 + *fmt++ - '0'; - break; - } - state = 3; - case 3: - if (*fmt == 'l') { - ++ll; - ++fmt; - break; - } - state = 4; - case 4: - switch (*fmt) { - case 's': - myvsnprintf_string(&dest,de,va_arg(ap,const char *)); - break; - case 'd': - switch (ll) { - case 0: - myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,int)); - break; - case 1: - myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,long)); - break; - case 2: - myvsnprintf_int(&dest,de,width,zero,neg,10,'a',va_arg(ap,longlong)); - break; - } - break; - case 'u': - switch (ll) { - case 0: - myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,unsigned int)); - break; - case 1: - myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,unsigned long)); - break; - case 2: - myvsnprintf_uint(&dest,de,width,zero,neg,10,'a',va_arg(ap,ulonglong)); - break; - } - break; - case 'x': - switch (ll) { - case 0: - myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,unsigned int)); - break; - case 1: - myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,unsigned long)); - break; - case 2: - myvsnprintf_uint(&dest,de,width,zero,neg,16,'a',va_arg(ap,ulonglong)); - break; - } - break; - case 'X': - switch (ll) { - case 0: - myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,unsigned int)); - break; - case 1: - myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,unsigned long)); - break; - case 2: - myvsnprintf_uint(&dest,de,width,zero,neg,16,'A',va_arg(ap,ulonglong)); - break; - } - break; - default: - break; - } - ++fmt; - state = 0; - break; - default: - state = 0; - break; - } - *dest = '\0'; -} - -static void errorjmp(MatroskaFile *mf,const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - myvsnprintf(mf->errmsg,sizeof(mf->errmsg),fmt,ap); - va_end(ap); - - mf->flags |= MPF_ERROR; - - longjmp(mf->jb,1); -} - -/////////////////////////////////////////////////////////////////////////// -// arrays -static void *ArrayAlloc(MatroskaFile *mf,void **base, - unsigned *cur,unsigned *max,unsigned elem_size) -{ - if (*cur>=*max) { - void *np; - unsigned newsize = *max * 2; - if (newsize==0) - newsize = 1; - - np = mf->cache->memrealloc(mf->cache,*base,newsize*elem_size); - if (np==NULL) - errorjmp(mf,"Out of memory in ArrayAlloc"); - - *base = np; - *max = newsize; - } - - return (char*)*base + elem_size * (*cur)++; -} - -static void ArrayReleaseMemory(MatroskaFile *mf,void **base, - unsigned cur,unsigned *max,unsigned elem_size) -{ - if (cur<*max) { - void *np = mf->cache->memrealloc(mf->cache,*base,cur*elem_size); - *base = np; - *max = cur; - } -} - - -#define ASGET(f,s,name) ArrayAlloc((f),(void**)&(s)->name,&(s)->n##name,&(s)->n##name##Size,sizeof(*((s)->name))) -#define AGET(f,name) ArrayAlloc((f),(void**)&(f)->name,&(f)->n##name,&(f)->n##name##Size,sizeof(*((f)->name))) -#define ARELEASE(f,s,name) ArrayReleaseMemory((f),(void**)&(s)->name,(s)->n##name,&(s)->n##name##Size,sizeof(*((s)->name))) - -/////////////////////////////////////////////////////////////////////////// -// queues -static struct QueueEntry *QPut(struct Queue *q,struct QueueEntry *qe) { - if (q->tail) - q->tail->next = qe; - qe->next = NULL; - q->tail = qe; - if (q->head==NULL) - q->head = qe; - - return qe; -} - -static struct QueueEntry *QGet(struct Queue *q) { - struct QueueEntry *qe = q->head; - if (qe == NULL) - return NULL; - q->head = qe->next; - if (q->tail == qe) - q->tail = NULL; - return qe; -} - -static struct QueueEntry *QAlloc(MatroskaFile *mf) { - struct QueueEntry *qe,**qep; - if (mf->QFreeList == NULL) { - unsigned i; - - qep = AGET(mf,QBlocks); - - *qep = mf->cache->memalloc(mf->cache,QSEGSIZE * sizeof(*qe)); - if (*qep == NULL) - errorjmp(mf,"Ouf of memory"); - - qe = *qep; - - for (i=0;iQFreeList = qe; - } - - qe = mf->QFreeList; - mf->QFreeList = qe->next; - - return qe; -} - -static inline void QFree(MatroskaFile *mf,struct QueueEntry *qe) { - qe->next = mf->QFreeList; - mf->QFreeList = qe; -} - -// fill the buffer at current position -static void fillbuf(MatroskaFile *mf) { - int rd; - - // advance buffer pointers - mf->bufbase += mf->buflen; - mf->buflen = mf->bufpos = 0; - - // get the relevant page - rd = mf->cache->read(mf->cache, mf->bufbase, mf->inbuf, IBSZ); - if (rd<0) - errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache)); - - mf->buflen = rd; -} - -// fill the buffer and return next char -static int nextbuf(MatroskaFile *mf) { - fillbuf(mf); - - if (mf->bufpos < mf->buflen) - return (unsigned char)(mf->inbuf[mf->bufpos++]); - - return EOF; -} - -static inline int readch(MatroskaFile *mf) { - return mf->bufpos < mf->buflen ? (unsigned char)(mf->inbuf[mf->bufpos++]) : nextbuf(mf); -} - -static inline ulonglong filepos(MatroskaFile *mf) { - return mf->bufbase + mf->bufpos; -} - -static void readbytes(MatroskaFile *mf,void *buffer,int len) { - char *cp = buffer; - int nb = mf->buflen - mf->bufpos; - - if (nb > len) - nb = len; - - memcpy(cp, mf->inbuf + mf->bufpos, nb); - mf->bufpos += nb; - len -= nb; - cp += nb; - - if (len>0) { - mf->bufbase += mf->buflen; - mf->bufpos = mf->buflen = 0; - - nb = mf->cache->read(mf->cache, mf->bufbase, cp, len); - if (nb<0) - errorjmp(mf,"I/O Error: %s",mf->cache->geterror(mf->cache)); - if (nb != len) - errorjmp(mf,"Short read: got %d bytes of %d",nb,len); - mf->bufbase += len; - } -} - -static void skipbytes(MatroskaFile *mf,ulonglong len) { - int nb = mf->buflen - mf->bufpos; - - if (nb > len) - nb = (int)len; - - mf->bufpos += nb; - len -= nb; - - if (len>0) { - mf->bufbase += mf->buflen; - mf->bufpos = mf->buflen = 0; - - mf->bufbase += len; - } -} - -static void seek(MatroskaFile *mf,ulonglong pos) { - // see if pos is inside buffer - if (pos>=mf->bufbase && posbufbase+mf->buflen) - mf->bufpos = (unsigned)(pos - mf->bufbase); - else { - // invalidate buffer and set pointer - mf->bufbase = pos; - mf->buflen = mf->bufpos = 0; - } -} - -/////////////////////////////////////////////////////////////////////////// -// floating point -static inline MKFLOAT mkfi(int i) { -#ifdef MATROSKA_INTEGER_ONLY - MKFLOAT f; - f.v = (longlong)i << 32; - return f; -#else - return i; -#endif -} - -static inline longlong mul3(MKFLOAT scale,longlong tc) { -#ifdef MATROSKA_INTEGER_ONLY - // x1 x0 - // y1 y0 - // -------------- - // x0*y0 - // x1*y0 - // x0*y1 - // x1*y1 - // -------------- - // .. r1 r0 .. - // - // r = ((x0*y0) >> 32) + (x1*y0) + (x0*y1) + ((x1*y1) << 32) - unsigned x0,x1,y0,y1; - ulonglong p; - char sign = 0; - - if (scale.v < 0) - sign = !sign, scale.v = -scale.v; - if (tc < 0) - sign = !sign, tc = -tc; - - x0 = (unsigned)scale.v; - x1 = (unsigned)((ulonglong)scale.v >> 32); - y0 = (unsigned)tc; - y1 = (unsigned)((ulonglong)tc >> 32); - - p = (ulonglong)x0*y0 >> 32; - p += (ulonglong)x0*y1; - p += (ulonglong)x1*y0; - p += (ulonglong)(x1*y1) << 32; - - return p; -#else - return (longlong)(scale * tc); -#endif -} - -/////////////////////////////////////////////////////////////////////////// -// EBML support -static int readID(MatroskaFile *mf) { - int c1,c2,c3,c4; - - c1 = readch(mf); - if (c1 == EOF) - return EOF; - - if (c1 & 0x80) - return c1; - - if ((c1 & 0xf0) == 0) - errorjmp(mf,"Invalid first byte of EBML ID: %02X",c1); - - c2 = readch(mf); - if (c2 == EOF) -fail: - errorjmp(mf,"Got EOF while reading EBML ID"); - - if ((c1 & 0xc0) == 0x40) - return (c1<<8) | c2; - - c3 = readch(mf); - if (c3 == EOF) - goto fail; - - if ((c1 & 0xe0) == 0x20) - return (c1<<16) | (c2<<8) | c3; - - c4 = readch(mf); - if (c4 == EOF) - goto fail; - - if ((c1 & 0xf0) == 0x10) - return (c1<<24) | (c2<<16) | (c3<<8) | c4; - - return 0; // NOT REACHED -} - -static ulonglong readVLUIntImp(MatroskaFile *mf,int *mask) { - int c,d,m; - ulonglong v = 0; - - c = readch(mf); - if (c == EOF) - return EOF; - - if (c == 0) - errorjmp(mf,"Invalid first byte of EBML integer: 0"); - - for (m=0;;++m) { - if (c & (0x80 >> m)) { - c &= 0x7f >> m; - if (mask) - *mask = m; - return v | ((ulonglong)c << m*8); - } - d = readch(mf); - if (d == EOF) - errorjmp(mf,"Got EOF while reading EBML unsigned integer"); - v = (v<<8) | d; - } - // NOT REACHED -} - -static inline ulonglong readVLUInt(MatroskaFile *mf) { - return readVLUIntImp(mf,NULL); -} - -static ulonglong readSize(MatroskaFile *mf) { - int m; - ulonglong v = readVLUIntImp(mf,&m); - - // see if it's unspecified - if (v == (MAXU64 >> (57-m*7))) - errorjmp(mf,"Unspecified element size is not supported here."); - - return v; -} - -static inline longlong readVLSInt(MatroskaFile *mf) { - static longlong bias[8] = { (ONE<<6)-1, (ONE<<13)-1, (ONE<<20)-1, (ONE<<27)-1, - (ONE<<34)-1, (ONE<<41)-1, (ONE<<48)-1, (ONE<<55)-1 }; - - int m; - longlong v = readVLUIntImp(mf,&m); - - return v - bias[m]; -} - -static ulonglong readUInt(MatroskaFile *mf,unsigned int len) { - int c; - unsigned int m = len; - ulonglong v = 0; - - if (len==0) - return v; - if (len>8) - errorjmp(mf,"Unsupported integer size in readUInt: %u",len); - - do { - c = readch(mf); - if (c == EOF) - errorjmp(mf,"Got EOF while reading EBML unsigned integer"); - v = (v<<8) | c; - } while (--m); - - return v; -} - -static inline longlong readSInt(MatroskaFile *mf,unsigned int len) { - longlong v = readUInt(mf,(unsigned)len); - int s = 64 - (len<<3); - return (v << s) >> s; -} - -static MKFLOAT readFloat(MatroskaFile *mf,unsigned int len) { -#ifdef MATROSKA_INTEGER_ONLY - MKFLOAT f; - int shift; -#else - union { - unsigned int ui; - ulonglong ull; - float f; - double d; - } u; -#endif - - if (len!=4 && len!=8) - errorjmp(mf,"Invalid float size in readFloat: %u",len); - -#ifdef MATROSKA_INTEGER_ONLY - if (len == 4) { - unsigned ui = (unsigned)readUInt(mf,(unsigned)len); - f.v = (ui & 0x7fffff) | 0x800000; - if (ui & 0x80000000) - f.v = -f.v; - shift = (ui >> 23) & 0xff; - if (shift == 0) // assume 0 -zero: - shift = 0, f.v = 0; - else if (shift == 255) -inf: - if (ui & 0x80000000) - f.v = LL(0x8000000000000000); - else - f.v = LL(0x7fffffffffffffff); - else { - shift += -127 + 9; - if (shift > 39) - goto inf; -shift: - if (shift < 0) - f.v = f.v >> -shift; - else if (shift > 0) - f.v = f.v << shift; - } - } else if (len == 8) { - ulonglong ui = readUInt(mf,(unsigned)len); - f.v = (ui & LL(0xfffffffffffff)) | LL(0x10000000000000); - if (ui & 0x80000000) - f.v = -f.v; - shift = (int)((ui >> 52) & 0x7ff); - if (shift == 0) // assume 0 - goto zero; - else if (shift == 2047) - goto inf; - else { - shift += -1023 - 20; - if (shift > 10) - goto inf; - goto shift; - } - } - - return f; -#else - if (len==4) { - u.ui = (unsigned int)readUInt(mf,(unsigned)len); - return u.f; - } - - if (len==8) { - u.ull = readUInt(mf,(unsigned)len); - return u.d; - } - - return 0; -#endif -} - -static void readString(MatroskaFile *mf,ulonglong len,char *buffer,int buflen) { - int nread; - - if (buflen<1) - errorjmp(mf,"Invalid buffer size in readString: %d",buflen); - - nread = buflen - 1; - - if (nread > len) - nread = (int)len; - - readbytes(mf,buffer,nread); - len -= nread; - - if (len>0) - skipbytes(mf,len); - - buffer[nread] = '\0'; -} - -static void readLangCC(MatroskaFile *mf, ulonglong len, char lcc[4]) { - unsigned todo = len > 3 ? 3 : (int)len; - - lcc[0] = lcc[1] = lcc[2] = lcc[3] = 0; - readbytes(mf, lcc, todo); - skipbytes(mf, len - todo); -} - -/////////////////////////////////////////////////////////////////////////// -// file parser -#define FOREACH(f,tl) \ - { \ - ulonglong tmplen = (tl); \ - { \ - ulonglong start = filepos(f); \ - ulonglong cur,len; \ - int id; \ - for (;;) { \ - cur = filepos(mf); \ - if (cur == start + tmplen) \ - break; \ - id = readID(f); \ - if (id==EOF) \ - errorjmp(mf,"Unexpected EOF while reading EBML container"); \ - len = readSize(mf); \ - switch (id) { - -#define ENDFOR1(f) \ - default: \ - skipbytes(f,len); \ - break; \ - } -#define ENDFOR2() \ - } \ - } \ - } - -#define ENDFOR(f) ENDFOR1(f) ENDFOR2() - -#define myalloca(f,c) alloca(c) -#define STRGETF(f,v,len,func) \ - { \ - char *TmpVal; \ - unsigned TmpLen = (len)>MAX_STRING_LEN ? MAX_STRING_LEN : (unsigned)(len); \ - TmpVal = func(f->cache,TmpLen+1); \ - if (TmpVal == NULL) \ - errorjmp(mf,"Out of memory"); \ - readString(f,len,TmpVal,TmpLen+1); \ - (v) = TmpVal; \ - } - -#define STRGETA(f,v,len) STRGETF(f,v,len,myalloca) -#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) { - ulonglong v; - char buf[32]; - - FOREACH(mf,toplen) - case 0x4286: // Version - v = readUInt(mf,(unsigned)len); - break; - case 0x42f7: // ReadVersion - v = readUInt(mf,(unsigned)len); - if (v > EBML_VERSION) - errorjmp(mf,"File requires version %d EBML parser",(int)v); - break; - case 0x42f2: // MaxIDLength - v = readUInt(mf,(unsigned)len); - if (v > EBML_MAX_ID_LENGTH) - errorjmp(mf,"File has identifiers longer than %d",(int)v); - break; - case 0x42f3: // MaxSizeLength - v = readUInt(mf,(unsigned)len); - if (v > EBML_MAX_SIZE_LENGTH) - errorjmp(mf,"File has integers longer than %d",(int)v); - break; - case 0x4282: // DocType - readString(mf,len,buf,sizeof(buf)); - if (strcmp(buf,MATROSKA_DOCTYPE)) - errorjmp(mf,"Unsupported DocType: %s",buf); - break; - case 0x4287: // DocTypeVersion - v = readUInt(mf,(unsigned)len); - break; - case 0x4285: // DocTypeReadVersion - v = readUInt(mf,(unsigned)len); - if (v > MATROSKA_VERSION) - errorjmp(mf,"File requires version %d Matroska parser",(int)v); - break; - ENDFOR(mf); -} - -static void parseSeekEntry(MatroskaFile *mf,ulonglong toplen) { - int seekid = 0; - ulonglong pos = (ulonglong)-1; - - FOREACH(mf,toplen) - case 0x53ab: // SeekID - if (len>EBML_MAX_ID_LENGTH) - errorjmp(mf,"Invalid ID size in parseSeekEntry: %d\n",(int)len); - seekid = (int)readUInt(mf,(unsigned)len); - break; - case 0x53ac: // SeekPos - pos = readUInt(mf,(unsigned)len); - break; - ENDFOR(mf); - - if (pos == (ulonglong)-1) - errorjmp(mf,"Invalid element position in parseSeekEntry"); - - pos += mf->pSegment; - switch (seekid) { - case 0x114d9b74: // next SeekHead - if (mf->pSeekHead) - errorjmp(mf,"SeekHead contains more than one SeekHead pointer"); - mf->pSeekHead = pos; - break; - case 0x1549a966: // SegmentInfo - mf->pSegmentInfo = pos; - break; - case 0x1f43b675: // Cluster - if (!mf->pCluster) - mf->pCluster = pos; - break; - case 0x1654ae6b: // Tracks - mf->pTracks = pos; - break; - case 0x1c53bb6b: // Cues - mf->pCues = pos; - break; - case 0x1941a469: // Attachments - mf->pAttachments = pos; - break; - case 0x1043a770: // Chapters - mf->pChapters = pos; - break; - case 0x1254c367: // tags - mf->pTags = pos; - break; - } -} - -static void parseSeekHead(MatroskaFile *mf,ulonglong toplen) { - FOREACH(mf,toplen) - case 0x4dbb: - parseSeekEntry(mf,len); - break; - ENDFOR(mf); -} - -static void parseSegmentInfo(MatroskaFile *mf,ulonglong toplen) { - MKFLOAT duration = mkfi(0); - - if (mf->seen.SegmentInfo) { - skipbytes(mf,toplen); - return; - } - - mf->seen.SegmentInfo = 1; - mf->Seg.TimecodeScale = 1000000; // Default value - - FOREACH(mf,toplen) - case 0x73a4: // SegmentUID - if (len!=sizeof(mf->Seg.UID)) - errorjmp(mf,"SegmentUID size is not %d bytes",mf->Seg.UID); - readbytes(mf,mf->Seg.UID,sizeof(mf->Seg.UID)); - break; - case 0x7384: // SegmentFilename - STRGETM(mf,mf->Seg.Filename,len); - break; - case 0x3cb923: // PrevUID - if (len!=sizeof(mf->Seg.PrevUID)) - errorjmp(mf,"PrevUID size is not %d bytes",mf->Seg.PrevUID); - readbytes(mf,mf->Seg.PrevUID,sizeof(mf->Seg.PrevUID)); - break; - case 0x3c83ab: // PrevFilename - STRGETM(mf,mf->Seg.PrevFilename,len); - break; - case 0x3eb923: // NextUID - if (len!=sizeof(mf->Seg.NextUID)) - errorjmp(mf,"NextUID size is not %d bytes",mf->Seg.NextUID); - readbytes(mf,mf->Seg.NextUID,sizeof(mf->Seg.NextUID)); - break; - case 0x3e83bb: // NextFilename - STRGETM(mf,mf->Seg.NextFilename,len); - break; - case 0x2ad7b1: // TimecodeScale - mf->Seg.TimecodeScale = readUInt(mf,(unsigned)len); - if (mf->Seg.TimecodeScale == 0) - errorjmp(mf,"Segment timecode scale is zero"); - break; - case 0x4489: // Duration - duration = readFloat(mf,(unsigned)len); - break; - case 0x4461: // DateUTC - mf->Seg.DateUTC = readUInt(mf,(unsigned)len); - mf->Seg.DateUTCValid = 1; - break; - case 0x7ba9: // Title - STRGETM(mf,mf->Seg.Title,len); - break; - case 0x4d80: // MuxingApp - STRGETM(mf,mf->Seg.MuxingApp,len); - break; - case 0x5741: // WritingApp - STRGETM(mf,mf->Seg.WritingApp,len); - break; - ENDFOR(mf); - - mf->Seg.Duration = mul3(duration,mf->Seg.TimecodeScale); -} - -static void parseFirstCluster(MatroskaFile *mf,ulonglong toplen) { - mf->seen.Cluster = 1; - mf->firstTimecode = 0; - - FOREACH(mf,toplen) - case 0xe7: // Timecode - mf->firstTimecode += readUInt(mf,(unsigned)len); - break; - case 0xa3: // BlockEx - readVLUInt(mf); // track number - mf->firstTimecode += readSInt(mf, 2); - - skipbytes(mf,start + toplen - filepos(mf)); - return; - case 0xa0: // BlockGroup - FOREACH(mf,len) - case 0xa1: // Block - readVLUInt(mf); // track number - mf->firstTimecode += readSInt(mf,2); - - skipbytes(mf,start + toplen - filepos(mf)); - return; - ENDFOR(mf); - break; - ENDFOR(mf); -} - -static void parseVideoInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *ti) { - ulonglong v; - char dW = 0, dH = 0; - - FOREACH(mf,toplen) - case 0x9a: // FlagInterlaced - ti->AV.Video.Interlaced = readUInt(mf,(unsigned)len)!=0; - break; - case 0x53b8: // StereoMode - v = readUInt(mf,(unsigned)len); - if (v>3) - errorjmp(mf,"Invalid stereo mode"); - ti->AV.Video.StereoMode = (unsigned char)v; - break; - case 0xb0: // PixelWidth - v = readUInt(mf,(unsigned)len); - if (v>0xffffffff) - errorjmp(mf,"PixelWidth is too large"); - ti->AV.Video.PixelWidth = (unsigned)v; - if (!dW) - ti->AV.Video.DisplayWidth = ti->AV.Video.PixelWidth; - break; - case 0xba: // PixelHeight - v = readUInt(mf,(unsigned)len); - if (v>0xffffffff) - errorjmp(mf,"PixelHeight is too large"); - ti->AV.Video.PixelHeight = (unsigned)v; - if (!dH) - ti->AV.Video.DisplayHeight = ti->AV.Video.PixelHeight; - break; - case 0x54b0: // DisplayWidth - v = readUInt(mf,(unsigned)len); - if (v>0xffffffff) - errorjmp(mf,"DisplayWidth is too large"); - ti->AV.Video.DisplayWidth = (unsigned)v; - dW = 1; - break; - case 0x54ba: // DisplayHeight - v = readUInt(mf,(unsigned)len); - if (v>0xffffffff) - errorjmp(mf,"DisplayHeight is too large"); - ti->AV.Video.DisplayHeight = (unsigned)v; - dH = 1; - break; - case 0x54b2: // DisplayUnit - v = readUInt(mf,(unsigned)len); - if (v>2) - errorjmp(mf,"Invalid DisplayUnit: %d",(int)v); - ti->AV.Video.DisplayUnit = (unsigned char)v; - break; - case 0x54b3: // AspectRatioType - v = readUInt(mf,(unsigned)len); - if (v>2) - errorjmp(mf,"Invalid AspectRatioType: %d",(int)v); - ti->AV.Video.AspectRatioType = (unsigned char)v; - break; - case 0x54aa: // PixelCropBottom - v = readUInt(mf,(unsigned)len); - if (v>0xffffffff) - errorjmp(mf,"PixelCropBottom is too large"); - ti->AV.Video.CropB = (unsigned)v; - break; - case 0x54bb: // PixelCropTop - v = readUInt(mf,(unsigned)len); - if (v>0xffffffff) - errorjmp(mf,"PixelCropTop is too large"); - ti->AV.Video.CropT = (unsigned)v; - break; - case 0x54cc: // PixelCropLeft - v = readUInt(mf,(unsigned)len); - if (v>0xffffffff) - errorjmp(mf,"PixelCropLeft is too large"); - ti->AV.Video.CropL = (unsigned)v; - break; - case 0x54dd: // PixelCropRight - v = readUInt(mf,(unsigned)len); - if (v>0xffffffff) - errorjmp(mf,"PixelCropRight is too large"); - ti->AV.Video.CropR = (unsigned)v; - break; - case 0x2eb524: // ColourSpace - ti->AV.Video.ColourSpace = (unsigned)readUInt(mf,4); - break; - case 0x2fb523: // GammaValue - ti->AV.Video.GammaValue = readFloat(mf,(unsigned)len); - break; - ENDFOR(mf); -} - -static void parseAudioInfo(MatroskaFile *mf,ulonglong toplen,struct TrackInfo *ti) { - ulonglong v; - - FOREACH(mf,toplen) - case 0xb5: // SamplingFrequency - ti->AV.Audio.SamplingFreq = readFloat(mf,(unsigned)len); - break; - case 0x78b5: // OutputSamplingFrequency - ti->AV.Audio.OutputSamplingFreq = readFloat(mf,(unsigned)len); - break; - case 0x9f: // Channels - v = readUInt(mf,(unsigned)len); - if (v<1 || v>255) - errorjmp(mf,"Invalid Channels value"); - ti->AV.Audio.Channels = (unsigned char)v; - break; - case 0x7d7b: // ChannelPositions - skipbytes(mf,len); - break; - case 0x6264: // BitDepth - v = readUInt(mf,(unsigned)len); -#if 0 - if ((v<1 || v>255) && !IsWritingApp(mf,"AVI-Mux GUI")) - errorjmp(mf,"Invalid BitDepth: %d",(int)v); -#endif - ti->AV.Audio.BitDepth = (unsigned char)v; - break; - ENDFOR(mf); - - if (ti->AV.Audio.Channels == 0) - ti->AV.Audio.Channels = 1; - if (mkv_TruncFloat(ti->AV.Audio.SamplingFreq) == 0) - ti->AV.Audio.SamplingFreq = mkfi(8000); - if (mkv_TruncFloat(ti->AV.Audio.OutputSamplingFreq)==0) - ti->AV.Audio.OutputSamplingFreq = ti->AV.Audio.SamplingFreq; -} - -static void CopyStr(char **src,char **dst) { - size_t l; - - if (!*src) - return; - - l = strlen(*src)+1; - memcpy(*dst,*src,l); - *src = *dst; - *dst += l; -} - -static void parseTrackEntry(MatroskaFile *mf,ulonglong toplen) { - struct TrackInfo t,*tp,**tpp; - ulonglong v; - char *cp = NULL, *cs = NULL; - size_t cplen = 0, cslen = 0, cpadd = 0; - unsigned CompScope, num_comp = 0; - - if (mf->nTracks >= MAX_TRACKS) - errorjmp(mf,"Too many tracks."); - - // clear track info - memset(&t,0,sizeof(t)); - - // fill default values - t.Enabled = 1; - t.Default = 1; - t.Lacing = 1; - t.TimecodeScale = mkfi(1); - t.DecodeAll = 1; - - FOREACH(mf,toplen) - case 0xd7: // TrackNumber - v = readUInt(mf,(unsigned)len); - if (v>255) - errorjmp(mf,"Track number is >255 (%d)",(int)v); - t.Number = (unsigned char)v; - break; - case 0x73c5: // TrackUID - t.UID = readUInt(mf,(unsigned)len); - break; - case 0x83: // TrackType - v = readUInt(mf,(unsigned)len); - if (v<1 || v>254) - errorjmp(mf,"Invalid track type: %d",(int)v); - t.Type = (unsigned char)v; - break; - case 0xb9: // Enabled - t.Enabled = readUInt(mf,(unsigned)len)!=0; - break; - case 0x88: // Default - t.Default = readUInt(mf,(unsigned)len)!=0; - break; - case 0x9c: // Lacing - t.Lacing = readUInt(mf,(unsigned)len)!=0; - break; - case 0x6de7: // MinCache - v = readUInt(mf,(unsigned)len); - if (v > 0xffffffff) - errorjmp(mf,"MinCache is too large"); - t.MinCache = (unsigned)v; - break; - case 0x6df8: // MaxCache - v = readUInt(mf,(unsigned)len); - if (v > 0xffffffff) - errorjmp(mf,"MaxCache is too large"); - t.MaxCache = (unsigned)v; - break; - case 0x23e383: // DefaultDuration - t.DefaultDuration = readUInt(mf,(unsigned)len); - break; - case 0x23314f: // TrackTimecodeScale - t.TimecodeScale = readFloat(mf,(unsigned)len); - break; - case 0x55ee: // MaxBlockAdditionID - t.MaxBlockAdditionID = (unsigned)readUInt(mf,(unsigned)len); - break; - case 0x536e: // Name - if (t.Name) - errorjmp(mf,"Duplicate Track Name"); - STRGETA(mf,t.Name,len); - break; - case 0x22b59c: // Language - readLangCC(mf, len, t.Language); - break; - case 0x86: // CodecID - if (t.CodecID) - errorjmp(mf,"Duplicate CodecID"); - STRGETA(mf,t.CodecID,len); - break; - case 0x63a2: // CodecPrivate - if (cp) - errorjmp(mf,"Duplicate CodecPrivate"); - if (len>262144) // 256KB - errorjmp(mf,"CodecPrivate is too large: %d",(int)len); - cplen = (unsigned)len; - cp = alloca(cplen); - readbytes(mf,cp,(int)cplen); - break; - case 0x258688: // CodecName - skipbytes(mf,len); - break; - case 0x3a9697: // CodecSettings - skipbytes(mf,len); - break; - case 0x3b4040: // CodecInfoURL - skipbytes(mf,len); - break; - case 0x26b240: // CodecDownloadURL - skipbytes(mf,len); - break; - case 0xaa: // CodecDecodeAll - t.DecodeAll = readUInt(mf,(unsigned)len)!=0; - break; - case 0x6fab: // TrackOverlay - v = readUInt(mf,(unsigned)len); - if (v>255) - errorjmp(mf,"Track number in TrackOverlay is too large: %d",(int)v); - t.TrackOverlay = (unsigned char)v; - break; - case 0xe0: // VideoInfo - parseVideoInfo(mf,len,&t); - break; - case 0xe1: // AudioInfo - parseAudioInfo(mf,len,&t); - break; - case 0x6d80: // ContentEncodings - FOREACH(mf,len) - case 0x6240: // ContentEncoding - // fill in defaults - t.CompEnabled = 1; - t.CompMethod = COMP_ZLIB; - CompScope = 1; - if (++num_comp > 1) - return; // only one compression layer supported - FOREACH(mf,len) - case 0x5031: // ContentEncodingOrder - readUInt(mf,(unsigned)len); - break; - case 0x5032: // ContentEncodingScope - CompScope = (unsigned)readUInt(mf,(unsigned)len); - break; - case 0x5033: // ContentEncodingType - if (readUInt(mf,(unsigned)len) != 0) - return; // encryption is not supported - break; - case 0x5034: // ContentCompression - FOREACH(mf,len) - case 0x4254: // ContentCompAlgo - v = readUInt(mf,(unsigned)len); - t.CompEnabled = 1; - switch (v) { - case 0: // Zlib - t.CompMethod = COMP_ZLIB; - break; - case 3: // prepend fixed data - t.CompMethod = COMP_PREPEND; - break; - default: - return; // unsupported compression, skip track - } - break; - case 0x4255: // ContentCompSettings - if (len > 256) - return; - cslen = (unsigned)len; - cs = alloca(cslen); - readbytes(mf, cs, (int)cslen); - break; - ENDFOR(mf); - break; - // TODO Implement Encryption/Signatures - ENDFOR(mf); - break; - ENDFOR(mf); - break; - ENDFOR(mf); - - // validate track info - if (!t.CodecID) - errorjmp(mf,"Track has no Codec ID"); - - if (t.UID != 0) { - unsigned i; - for (i = 0; i < mf->nTracks; ++i) - if (mf->Tracks[i]->UID == t.UID) // duplicate track entry - return; - } - -#ifdef MATROSKA_COMPRESSION_SUPPORT - // handle compressed CodecPrivate - if (t.CompEnabled && t.CompMethod == COMP_ZLIB && (CompScope & 2) && cplen > 0) { - z_stream zs; - char tmp[64], *ncp; - int code; - uLong ncplen; - - memset(&zs,0,sizeof(zs)); - if (inflateInit(&zs) != Z_OK) - errorjmp(mf, "inflateInit failed"); - - zs.next_in = cp; - zs.avail_in = cplen; - - do { - zs.next_out = tmp; - zs.avail_out = sizeof(tmp); - - code = inflate(&zs, Z_NO_FLUSH); - } while (code == Z_OK); - - if (code != Z_STREAM_END) - errorjmp(mf, "invalid compressed data in CodecPrivate"); - - ncplen = zs.total_out; - ncp = alloca(ncplen); - - inflateReset(&zs); - - zs.next_in = cp; - zs.avail_in = cplen; - zs.next_out = ncp; - zs.avail_out = ncplen; - - if (inflate(&zs, Z_FINISH) != Z_STREAM_END) - errorjmp(mf, "inflate failed"); - - inflateEnd(&zs); - - cp = ncp; - cplen = ncplen; - } -#endif - - if (t.CompEnabled && !(CompScope & 1)) { - t.CompEnabled = 0; - cslen = 0; - } - - // allocate new track - tpp = AGET(mf,Tracks); - - // copy strings - if (t.Name) - cpadd += strlen(t.Name)+1; - if (t.CodecID) - cpadd += strlen(t.CodecID)+1; - - tp = mf->cache->memalloc(mf->cache,sizeof(*tp) + cplen + cslen + cpadd); - if (tp == NULL) - errorjmp(mf,"Out of memory"); - - memcpy(tp,&t,sizeof(*tp)); - if (cplen) { - tp->CodecPrivate = tp+1; - tp->CodecPrivateSize = (unsigned)cplen; - memcpy(tp->CodecPrivate,cp,cplen); - } - if (cslen) { - tp->CompMethodPrivate = (char *)(tp+1) + cplen; - tp->CompMethodPrivateSize = cslen; - memcpy(tp->CompMethodPrivate, cs, cslen); - } - - cp = (char*)(tp+1) + cplen + cslen; - CopyStr(&tp->Name,&cp); - CopyStr(&tp->CodecID,&cp); - - // set default language - if (!tp->Language[0]) - memcpy(tp->Language, "eng", 4); - - *tpp = tp; -} - -static void parseTracks(MatroskaFile *mf,ulonglong toplen) { - mf->seen.Tracks = 1; - FOREACH(mf,toplen) - case 0xae: // TrackEntry - parseTrackEntry(mf,len); - break; - ENDFOR(mf); -} - -static void addCue(MatroskaFile *mf,ulonglong pos,ulonglong timecode) { - struct Cue *cc = AGET(mf,Cues); - cc->Time = timecode; - cc->Position = pos; - cc->Track = 0; - cc->Block = 0; -} - -static void fixupCues(MatroskaFile *mf) { - // adjust cues, shift cues if file does not start at 0 - unsigned i; - longlong adjust = mf->firstTimecode * mf->Seg.TimecodeScale; - - for (i=0;inCues;++i) { - mf->Cues[i].Time *= mf->Seg.TimecodeScale; - mf->Cues[i].Time -= adjust; - } -} - -static void parseCues(MatroskaFile *mf,ulonglong toplen) { - jmp_buf jb; - ulonglong v; - struct Cue cc; - unsigned i,j,k; - - mf->seen.Cues = 1; - mf->nCues = 0; - cc.Block = 0; - - memcpy(&jb,&mf->jb,sizeof(jb)); - - if (setjmp(mf->jb)) { - memcpy(&mf->jb,&jb,sizeof(jb)); - mf->nCues = 0; - mf->seen.Cues = 0; - return; - } - - FOREACH(mf,toplen) - case 0xbb: // CuePoint - FOREACH(mf,len) - case 0xb3: // CueTime - cc.Time = readUInt(mf,(unsigned)len); - break; - case 0xb7: // CueTrackPositions - FOREACH(mf,len) - case 0xf7: // CueTrack - v = readUInt(mf,(unsigned)len); - if (v>255) - errorjmp(mf,"CueTrack points to an invalid track: %d",(int)v); - cc.Track = (unsigned char)v; - break; - case 0xf1: // CueClusterPosition - cc.Position = readUInt(mf,(unsigned)len); - break; - case 0x5378: // CueBlockNumber - cc.Block = readUInt(mf,(unsigned)len); - break; - case 0xea: // CodecState - readUInt(mf,(unsigned)len); - break; - case 0xdb: // CueReference - FOREACH(mf,len) - case 0x96: // CueRefTime - readUInt(mf,(unsigned)len); - break; - case 0x97: // CueRefCluster - readUInt(mf,(unsigned)len); - break; - case 0x535f: // CueRefNumber - readUInt(mf,(unsigned)len); - break; - case 0xeb: // CueRefCodecState - readUInt(mf,(unsigned)len); - break; - ENDFOR(mf); - break; - ENDFOR(mf); - break; - ENDFOR(mf); - - if (mf->nCues == 0 && mf->pCluster - mf->pSegment != cc.Position) - addCue(mf,mf->pCluster - mf->pSegment,mf->firstTimecode); - - memcpy(AGET(mf,Cues),&cc,sizeof(cc)); - break; - ENDFOR(mf); - - memcpy(&mf->jb,&jb,sizeof(jb)); - - ARELEASE(mf,mf,Cues); - - // bubble sort the cues and fuck the losers that write unordered cues - if (mf->nCues > 0) - for (i = mf->nCues - 1, k = 1; i > 0 && k > 0; --i) - for (j = k = 0; j < i; ++j) - if (mf->Cues[j].Time > mf->Cues[j+1].Time) { - struct Cue tmp = mf->Cues[j+1]; - mf->Cues[j+1] = mf->Cues[j]; - mf->Cues[j] = tmp; - ++k; - } -} - -static void parseAttachment(MatroskaFile *mf,ulonglong toplen) { - struct Attachment a,*pa; - - memset(&a,0,sizeof(a)); - FOREACH(mf,toplen) - case 0x467e: // Description - STRGETA(mf,a.Description,len); - break; - case 0x466e: // Name - STRGETA(mf,a.Name,len); - break; - case 0x4660: // MimeType - STRGETA(mf,a.MimeType,len); - break; - case 0x46ae: // UID - a.UID = readUInt(mf,(unsigned)len); - break; - case 0x465c: // Data - a.Position = filepos(mf); - a.Length = len; - skipbytes(mf,len); - break; - ENDFOR(mf); - - if (!a.Position) - return; - - pa = AGET(mf,Attachments); - memcpy(pa,&a,sizeof(a)); - - if (a.Description) - pa->Description = mystrdup(mf->cache,a.Description); - if (a.Name) - pa->Name = mystrdup(mf->cache,a.Name); - if (a.MimeType) - pa->MimeType = mystrdup(mf->cache,a.MimeType); -} - -static void parseAttachments(MatroskaFile *mf,ulonglong toplen) { - mf->seen.Attachments = 1; - - FOREACH(mf,toplen) - case 0x61a7: // AttachedFile - parseAttachment(mf,len); - break; - ENDFOR(mf); -} - -static void parseChapter(MatroskaFile *mf,ulonglong toplen,struct Chapter *parent) { - struct ChapterDisplay *disp; - struct ChapterProcess *proc; - struct ChapterCommand *cmd; - struct Chapter *ch = ASGET(mf,parent,Children); - - memset(ch,0,sizeof(*ch)); - - ch->Enabled = 1; - - FOREACH(mf,toplen) - case 0x73c4: // ChapterUID - ch->UID = readUInt(mf,(unsigned)len); - break; - case 0x6e67: // ChapterSegmentUID - if (len != sizeof(ch->SegmentUID)) - skipbytes(mf, len); - else - readbytes(mf, ch->SegmentUID, sizeof(ch->SegmentUID)); - break; - case 0x91: // ChapterTimeStart - ch->Start = readUInt(mf,(unsigned)len); - break; - case 0x92: // ChapterTimeEnd - ch->End = readUInt(mf,(unsigned)len); - break; - case 0x98: // ChapterFlagHidden - ch->Hidden = readUInt(mf,(unsigned)len)!=0; - break; - case 0x4598: // ChapterFlagEnabled - ch->Enabled = readUInt(mf,(unsigned)len)!=0; - break; - case 0x8f: // ChapterTrack - FOREACH(mf,len) - case 0x89: // ChapterTrackNumber - *(ulonglong*)(ASGET(mf,ch,Tracks)) = readUInt(mf,(unsigned)len); - break; - ENDFOR(mf); - break; - case 0x80: // ChapterDisplay - disp = NULL; - - FOREACH(mf,len) - case 0x85: // ChapterString - if (disp==NULL) { - disp = ASGET(mf,ch,Display); - memset(disp, 0, sizeof(*disp)); - } - if (disp->String) - skipbytes(mf,len); // Ignore duplicate string - else - STRGETM(mf,disp->String,len); - break; - case 0x437c: // ChapterLanguage - if (disp==NULL) { - disp = ASGET(mf,ch,Display); - memset(disp, 0, sizeof(*disp)); - } - readLangCC(mf, len, disp->Language); - break; - case 0x437e: // ChapterCountry - if (disp==NULL) { - disp = ASGET(mf,ch,Display); - memset(disp, 0, sizeof(*disp)); - } - readLangCC(mf, len, disp->Country); - break; - ENDFOR(mf); - - if (disp && !disp->String) - --ch->nDisplay; - break; - case 0x6944: // ChapProcess - proc = NULL; - - FOREACH(mf,len) - case 0x6955: // ChapProcessCodecID - if (proc == NULL) { - proc = ASGET(mf, ch, Process); - memset(proc, 0, sizeof(*proc)); - } - proc->CodecID = (unsigned)readUInt(mf,(unsigned)len); - break; - case 0x450d: // ChapProcessPrivate - if (proc == NULL) { - proc = ASGET(mf, ch, Process); - memset(proc, 0, sizeof(*proc)); - } - if (proc->CodecPrivate) - skipbytes(mf, len); - else { - proc->CodecPrivateLength = (unsigned)len; - STRGETM(mf,proc->CodecPrivate,len); - } - break; - case 0x6911: // ChapProcessCommand - if (proc == NULL) { - proc = ASGET(mf, ch, Process); - memset(proc, 0, sizeof(*proc)); - } - - cmd = NULL; - - FOREACH(mf,len) - case 0x6922: // ChapterCommandTime - if (cmd == NULL) { - cmd = ASGET(mf,proc,Commands); - memset(cmd, 0, sizeof(*cmd)); - } - cmd->Time = (unsigned)readUInt(mf,(unsigned)len); - break; - case 0x6933: // ChapterCommandString - if (cmd == NULL) { - cmd = ASGET(mf,proc,Commands); - memset(cmd, 0, sizeof(*cmd)); - } - if (cmd->Command) - skipbytes(mf,len); - else { - cmd->CommandLength = (unsigned)len; - STRGETM(mf,cmd->Command,len); - } - break; - ENDFOR(mf); - - if (cmd && !cmd->Command) - --proc->nCommands; - break; - ENDFOR(mf); - - if (proc && !proc->nCommands) - --ch->nProcess; - break; - case 0xb6: // Nested ChapterAtom - parseChapter(mf,len,ch); - break; - ENDFOR(mf); - - ARELEASE(mf,ch,Tracks); - ARELEASE(mf,ch,Display); - ARELEASE(mf,ch,Children); -} - -static void parseChapters(MatroskaFile *mf,ulonglong toplen) { - struct Chapter *ch; - - mf->seen.Chapters = 1; - - FOREACH(mf,toplen) - case 0x45b9: // EditionEntry - ch = AGET(mf,Chapters); - memset(ch, 0, sizeof(*ch)); - FOREACH(mf,len) - case 0x45bc: // EditionUID - ch->UID = readUInt(mf,(unsigned)len); - break; - case 0x45bd: // EditionFlagHidden - ch->Hidden = readUInt(mf,(unsigned)len)!=0; - break; - case 0x45db: // EditionFlagDefault - ch->Default = readUInt(mf,(unsigned)len)!=0; - break; - case 0x45dd: // EditionFlagOrdered - ch->Ordered = readUInt(mf,(unsigned)len)!=0; - break; - case 0xb6: // ChapterAtom - parseChapter(mf,len,ch); - break; - ENDFOR(mf); - break; - ENDFOR(mf); -} - -static void parseTags(MatroskaFile *mf,ulonglong toplen) { - struct Tag *tag; - struct Target *target; - struct SimpleTag *st; - - mf->seen.Tags = 1; - - FOREACH(mf,toplen) - case 0x7373: // Tag - tag = AGET(mf,Tags); - memset(tag,0,sizeof(*tag)); - - FOREACH(mf,len) - case 0x63c0: // Targets - FOREACH(mf,len) - case 0x63c5: // TrackUID - target = ASGET(mf,tag,Targets); - target->UID = readUInt(mf,(unsigned)len); - target->Type = TARGET_TRACK; - break; - case 0x63c4: // ChapterUID - target = ASGET(mf,tag,Targets); - target->UID = readUInt(mf,(unsigned)len); - target->Type = TARGET_CHAPTER; - break; - case 0x63c6: // AttachmentUID - target = ASGET(mf,tag,Targets); - target->UID = readUInt(mf,(unsigned)len); - target->Type = TARGET_ATTACHMENT; - break; - case 0x63c9: // EditionUID - target = ASGET(mf,tag,Targets); - target->UID = readUInt(mf,(unsigned)len); - target->Type = TARGET_EDITION; - break; - ENDFOR(mf); - break; - case 0x67c8: // SimpleTag - st = ASGET(mf,tag,SimpleTags); - memset(st,0,sizeof(*st)); - - FOREACH(mf,len) - case 0x45a3: // TagName - if (st->Name) - skipbytes(mf,len); - else - STRGETM(mf,st->Name,len); - break; - case 0x4487: // TagString - if (st->Value) - skipbytes(mf,len); - else - STRGETM(mf,st->Value,len); - break; - case 0x447a: // TagLanguage - readLangCC(mf, len, st->Language); - break; - case 0x4484: // TagDefault - st->Default = readUInt(mf,(unsigned)len)!=0; - break; - ENDFOR(mf); - - if (!st->Name || !st->Value) { - mf->cache->memfree(mf->cache,st->Name); - mf->cache->memfree(mf->cache,st->Value); - --tag->nSimpleTags; - } - break; - ENDFOR(mf); - break; - ENDFOR(mf); -} - -static void parseContainer(MatroskaFile *mf) { - ulonglong len; - int id = readID(mf); - if (id==EOF) - errorjmp(mf,"Unexpected EOF in parseContainer"); - - len = readSize(mf); - - switch (id) { - case 0x1549a966: // SegmentInfo - parseSegmentInfo(mf,len); - break; - case 0x1f43b675: // Cluster - parseFirstCluster(mf,len); - break; - case 0x1654ae6b: // Tracks - parseTracks(mf,len); - break; - case 0x1c53bb6b: // Cues - parseCues(mf,len); - break; - case 0x1941a469: // Attachments - parseAttachments(mf,len); - break; - case 0x1043a770: // Chapters - parseChapters(mf,len); - break; - case 0x1254c367: // Tags - parseTags(mf,len); - break; - } -} - -static void parseContainerPos(MatroskaFile *mf,ulonglong pos) { - seek(mf,pos); - parseContainer(mf); -} - -static void parsePointers(MatroskaFile *mf) { - jmp_buf jb; - - if (mf->pSegmentInfo && !mf->seen.SegmentInfo) - parseContainerPos(mf,mf->pSegmentInfo); - if (mf->pCluster && !mf->seen.Cluster) - parseContainerPos(mf,mf->pCluster); - if (mf->pTracks && !mf->seen.Tracks) - parseContainerPos(mf,mf->pTracks); - - memcpy(&jb,&mf->jb,sizeof(jb)); - - if (setjmp(mf->jb)) - mf->flags &= ~MPF_ERROR; // ignore errors - else { - if (mf->pCues && !mf->seen.Cues) - parseContainerPos(mf,mf->pCues); - if (mf->pAttachments && !mf->seen.Attachments) - parseContainerPos(mf,mf->pAttachments); - if (mf->pChapters && !mf->seen.Chapters) - parseContainerPos(mf,mf->pChapters); - if (mf->pTags && !mf->seen.Tags) - parseContainerPos(mf,mf->pTags); - } - - memcpy(&mf->jb,&jb,sizeof(jb)); -} - -static void parseSegment(MatroskaFile *mf,ulonglong toplen) { - ulonglong nextpos; - unsigned nSeekHeads = 0, dontstop = 0; - - // we want to read data until we find a seekhead or a trackinfo - FOREACH(mf,toplen) - case 0x114d9b74: // SeekHead - if (mf->flags & MKVF_AVOID_SEEKS) { - skipbytes(mf,len); - break; - } - - nextpos = filepos(mf) + len; - do { - mf->pSeekHead = 0; - parseSeekHead(mf,len); - ++nSeekHeads; - if (mf->pSeekHead) { // this is possibly a chained SeekHead - seek(mf,mf->pSeekHead); - id = readID(mf); - if (id==EOF) // chained SeekHead points to EOF? - break; - if (id != 0x114d9b74) // chained SeekHead doesnt point to a SeekHead? - break; - len = readSize(mf); - } else if (mf->pSegmentInfo && mf->pTracks && mf->pCues && mf->pCluster) { // we have pointers to all key elements - // XXX EVIL HACK - // Some software doesnt index tags via SeekHead, so we continue - // reading the segment after the second SeekHead - if (mf->pTags || nSeekHeads<2 || filepos(mf)>=start+toplen) { - parsePointers(mf); - return; - } - // reset nextpos pointer to current position - nextpos = filepos(mf); - dontstop = 1; - } - } while (mf->pSeekHead); - seek(mf,nextpos); // resume reading segment - break; - case 0x1549a966: // SegmentInfo - mf->pSegmentInfo = cur; - parseSegmentInfo(mf,len); - break; - case 0x1f43b675: // Cluster - if (!mf->pCluster) - mf->pCluster = cur; - if (mf->seen.Cluster) - skipbytes(mf,len); - else - parseFirstCluster(mf,len); - break; - case 0x1654ae6b: // Tracks - mf->pTracks = cur; - parseTracks(mf,len); - break; - case 0x1c53bb6b: // Cues - mf->pCues = cur; - parseCues(mf,len); - break; - case 0x1941a469: // Attachments - mf->pAttachments = cur; - parseAttachments(mf,len); - break; - case 0x1043a770: // Chapters - mf->pChapters = cur; - parseChapters(mf,len); - break; - case 0x1254c367: // Tags - mf->pTags = cur; - parseTags(mf,len); - break; - ENDFOR1(mf); - // if we have pointers to all key elements - if (!dontstop && mf->pSegmentInfo && mf->pTracks && mf->pCluster) - break; - ENDFOR2(); - parsePointers(mf); -} - -static void parseBlockAdditions(MatroskaFile *mf, ulonglong toplen, ulonglong timecode, unsigned track) { - ulonglong add_id = 1, add_pos, add_len; - unsigned char have_add; - - FOREACH(mf, toplen) - case 0xa6: // BlockMore - have_add = 0; - FOREACH(mf, len) - case 0xee: // BlockAddId - add_id = readUInt(mf, (unsigned)len); - break; - case 0xa5: // BlockAddition - add_pos = filepos(mf); - add_len = len; - skipbytes(mf, len); - ++have_add; - break; - ENDFOR(mf); - if (have_add == 1 && id > 0 && id < 255) { - struct QueueEntry *qe = QAlloc(mf); - qe->Start = qe->End = timecode; - qe->Position = add_pos; - qe->Length = (unsigned)add_len; - qe->flags = FRAME_UNKNOWN_START | FRAME_UNKNOWN_END | - (((unsigned)add_id << FRAME_STREAM_SHIFT) & FRAME_STREAM_MASK); - - QPut(&mf->Queues[track],qe); - } - break; - ENDFOR(mf); -} - -static void parseBlockGroup(MatroskaFile *mf,ulonglong toplen,ulonglong timecode, int blockex) { - ulonglong v; - ulonglong duration = 0; - ulonglong dpos; - unsigned add_id = 0; - struct QueueEntry *qe,*qf = NULL; - unsigned char have_duration = 0, have_block = 0; - unsigned char gap = 0; - unsigned char lacing = 0; - unsigned char ref = 0; - unsigned char trackid; - unsigned tracknum = 0; - int c; - unsigned nframes = 0,i; - unsigned *sizes; - signed short block_timecode; - - if (blockex) - goto blockex; - - FOREACH(mf,toplen) - case 0xfb: // ReferenceBlock - readSInt(mf,(unsigned)len); - ref = 1; - break; -blockex: - cur = start = filepos(mf); - len = tmplen = toplen; - case 0xa1: // Block - have_block = 1; - - dpos = filepos(mf); - - v = readVLUInt(mf); - if (v>255) - errorjmp(mf,"Invalid track number in Block: %d",(int)v); - trackid = (unsigned char)v; - - for (tracknum=0;tracknumnTracks;++tracknum) - if (mf->Tracks[tracknum]->Number == trackid) { - if (mf->trackMask & (1<Tracks[tracknum]->TimecodeScale, - (timecode - mf->firstTimecode + block_timecode) * mf->Seg.TimecodeScale); - - c = readch(mf); - if (c==EOF) - errorjmp(mf,"Unexpected EOF while reading Block flags"); - - if (blockex) - ref = !(c & 0x80); - - gap = c & 0x1; - lacing = (c >> 1) & 3; - - if (lacing) { - c = readch(mf); - if (c == EOF) - errorjmp(mf,"Unexpected EOF while reading lacing data"); - nframes = c+1; - } else - nframes = 1; - sizes = alloca(nframes*sizeof(*sizes)); - - switch (lacing) { - case 0: // No lacing - sizes[0] = (unsigned)(len - filepos(mf) + dpos); - break; - case 1: // Xiph lacing - sizes[nframes-1] = 0; - for (i=0;i1) - sizes[nframes-1] = (unsigned)(len - filepos(mf) + dpos) - sizes[0] - sizes[nframes-1]; - break; - case 2: // Fixed lacing - sizes[0] = (unsigned)(len - filepos(mf) + dpos)/nframes; - for (i=1;iStart = timecode; - qe->End = timecode; - qe->Position = v; - qe->Length = sizes[i]; - qe->flags = FRAME_UNKNOWN_END | FRAME_KF; - if (i == nframes-1 && gap) - qe->flags |= FRAME_GAP; - if (i > 0) - qe->flags |= FRAME_UNKNOWN_START; - - QPut(&mf->Queues[tracknum],qe); - - v += sizes[i]; - } - - // we want to still load these bytes into cache - for (v = filepos(mf) & ~0x3fff; v < len + dpos; v += 0x4000) - mf->cache->read(mf->cache,v,NULL,0); // touch page - - skipbytes(mf,len - filepos(mf) + dpos); - - if (blockex) - goto out; - break; - case 0x9b: // BlockDuration - duration = readUInt(mf,(unsigned)len); - have_duration = 1; - break; - case 0x75a1: // BlockAdditions - if (nframes > 0) // have some frames - parseBlockAdditions(mf, len, timecode, tracknum); - else - skipbytes(mf, len); - break; - ENDFOR(mf); - -out: - if (!have_block) - errorjmp(mf,"Found a BlockGroup without Block"); - - if (nframes > 1) { - ulonglong defd = mf->Tracks[tracknum]->DefaultDuration; - v = qf->Start; - - if (have_duration) { - duration = mul3(mf->Tracks[tracknum]->TimecodeScale, - duration * mf->Seg.TimecodeScale); - - for (qe = qf; nframes > 1; --nframes, qe = qe->next) { - qe->Start = v; - v += defd; - duration -= defd; - qe->End = v; -#if 0 - qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END); -#endif - } - qe->Start = v; - qe->End = v + duration; - qe->flags &= ~FRAME_UNKNOWN_END; - } else if (mf->Tracks[tracknum]->DefaultDuration) { - for (qe = qf; nframes > 0; --nframes, qe = qe->next) { - qe->Start = v; - v += defd; - qe->End = v; - qe->flags &= ~(FRAME_UNKNOWN_START|FRAME_UNKNOWN_END); - } - } - } else if (nframes == 1) { - if (have_duration) { - qf->End = qf->Start + mul3(mf->Tracks[tracknum]->TimecodeScale, - duration * mf->Seg.TimecodeScale); - qf->flags &= ~FRAME_UNKNOWN_END; - } else if (mf->Tracks[tracknum]->DefaultDuration) { - qf->End = qf->Start + mf->Tracks[tracknum]->DefaultDuration; - qf->flags &= ~FRAME_UNKNOWN_END; - } - } - - if (ref) - while (qf) { - qf->flags &= ~FRAME_KF; - qf = qf->next; - } -} - -static void ClearQueue(MatroskaFile *mf,struct Queue *q) { - struct QueueEntry *qe,*qn; - - for (qe=q->head;qe;qe=qn) { - qn = qe->next; - qe->next = mf->QFreeList; - mf->QFreeList = qe; - } - - q->head = NULL; - q->tail = NULL; -} - -static void EmptyQueues(MatroskaFile *mf) { - unsigned i; - - for (i=0;inTracks;++i) - ClearQueue(mf,&mf->Queues[i]); -} - -static int readMoreBlocks(MatroskaFile *mf) { - ulonglong toplen, cstop; - longlong cp; - int cid, ret = 0; - jmp_buf jb; - volatile unsigned retries = 0; - - if (mf->readPosition >= mf->pSegmentTop) - return EOF; - - memcpy(&jb,&mf->jb,sizeof(jb)); - - if (setjmp(mf->jb)) { // something evil happened here, try to resync - // always advance read position no matter what so - // we don't get caught in an endless loop - mf->readPosition = filepos(mf); - - ret = EOF; - - if (++retries > 3) // don't try too hard - goto ex; - - for (;;) { - if (filepos(mf) >= mf->pSegmentTop) - goto ex; - - cp = mf->cache->scan(mf->cache,filepos(mf),0x1f43b675); // cluster - - if (cp < 0 || (ulonglong)cp >= mf->pSegmentTop) - goto ex; - - seek(mf,cp); - - cid = readID(mf); - if (cid == EOF) - goto ex; - if (cid == 0x1f43b675) { - toplen = readSize(mf); - if (toplen < MAXCLUSTER) { - // reset error flags - mf->flags &= ~MPF_ERROR; - ret = RBRESYNC; - break; - } - } - } - - mf->readPosition = cp; - } - - cstop = mf->cache->getcachesize(mf->cache)>>1; - if (cstop > MAX_READAHEAD) - cstop = MAX_READAHEAD; - cstop += mf->readPosition; - - seek(mf,mf->readPosition); - - while (filepos(mf) < mf->pSegmentTop) { - cid = readID(mf); - if (cid == EOF) { - ret = EOF; - break; - } - toplen = readSize(mf); - - if (cid == 0x1f43b675) { // Cluster - unsigned char have_timecode = 0; - - FOREACH(mf,toplen) - case 0xe7: // Timecode - mf->tcCluster = readUInt(mf,(unsigned)len); - have_timecode = 1; - break; - case 0xa7: // Position - readUInt(mf,(unsigned)len); - break; - case 0xab: // PrevSize - readUInt(mf,(unsigned)len); - break; - case 0x5854: { // SilentTracks - unsigned stmask = 0, i, trk; - FOREACH(mf, len) - case 0x58d7: // SilentTrackNumber - trk = (unsigned)readUInt(mf, (unsigned)len); - for (i = 0; i < mf->nTracks; ++i) - if (mf->Tracks[i]->Number == trk) { - stmask |= 1 << i; - break; - } - break; - ENDFOR(mf); - // TODO pass stmask to reading app - break; } - case 0xa0: // BlockGroup - if (!have_timecode) - errorjmp(mf,"Found BlockGroup before cluster TimeCode"); - parseBlockGroup(mf,len,mf->tcCluster, 0); - goto out; - case 0xa3: // BlockEx - if (!have_timecode) - errorjmp(mf,"Found BlockGroup before cluster TimeCode"); - parseBlockGroup(mf, len, mf->tcCluster, 1); - goto out; - ENDFOR(mf); -out:; - } else { - if (toplen > MAXFRAME) - errorjmp(mf,"Element in a cluster is too large around %llu, %X [%u]",filepos(mf),cid,(unsigned)toplen); - if (cid == 0xa0) // BlockGroup - parseBlockGroup(mf,toplen,mf->tcCluster, 0); - else if (cid == 0xa3) // BlockEx - parseBlockGroup(mf, toplen, mf->tcCluster, 1); - else - skipbytes(mf,toplen); - } - - if ((mf->readPosition = filepos(mf)) > cstop) - break; - } - - mf->readPosition = filepos(mf); - -ex: - memcpy(&mf->jb,&jb,sizeof(jb)); - - return ret; -} - -// this is almost the same as readMoreBlocks, except it ensures -// there are no partial frames queued, however empty queues are ok -static int fillQueues(MatroskaFile *mf,unsigned int mask) { - unsigned i,j; - int ret = 0; - - for (;;) { - j = 0; - - for (i=0;inTracks;++i) - if (mf->Queues[i].head && !(mask & (1<0) // have at least some frames - return ret; - - if ((ret = readMoreBlocks(mf)) < 0) { - j = 0; - for (i=0;inTracks;++i) - if (mf->Queues[i].head && !(mask & (1<pCluster; - ulonglong step = 10*1024*1024; - ulonglong size, tc, isize; - longlong next_cluster; - int id, have_tc, bad; - struct Cue *cue; - - if (pos >= mf->pSegmentTop) - return; - - if (pos + step * 10 > mf->pSegmentTop) - step = (mf->pSegmentTop - pos) / 10; - if (step == 0) - step = 1; - - memcpy(&jb,&mf->jb,sizeof(jb)); - - // remove all cues - mf->nCues = 0; - - bad = 0; - - while (pos < mf->pSegmentTop) { - if (!mf->cache->progress(mf->cache,pos,mf->pSegmentTop)) - break; - - if (++bad > 50) { - pos += step; - bad = 0; - continue; - } - - // find next cluster header - next_cluster = mf->cache->scan(mf->cache,pos,0x1f43b675); // cluster - if (next_cluster < 0 || (ulonglong)next_cluster >= mf->pSegmentTop) - break; - - pos = next_cluster + 4; // prevent endless loops - - if (setjmp(mf->jb)) // something evil happened while reindexing - continue; - - seek(mf,next_cluster); - - id = readID(mf); - if (id == EOF) - break; - if (id != 0x1f43b675) // shouldn't happen - continue; - - size = readVLUInt(mf); - if (size >= MAXCLUSTER || size < 1024) - continue; - - have_tc = 0; - size += filepos(mf); - - while (filepos(mf) < (ulonglong)next_cluster + 1024) { - id = readID(mf); - if (id == EOF) - break; - - isize = readVLUInt(mf); - - if (id == 0xe7) { // cluster timecode - tc = readUInt(mf,(unsigned)isize); - have_tc = 1; - break; - } - - skipbytes(mf,isize); - } - - if (!have_tc) - continue; - - seek(mf,size); - id = readID(mf); - - if (id == EOF) - break; - - if (id != 0x1f43b675) // cluster - continue; - - // good cluster, remember it - cue = AGET(mf,Cues); - cue->Time = tc; - cue->Position = next_cluster - mf->pSegment; - cue->Block = 0; - cue->Track = 0; - - // advance to the next point - pos = next_cluster + step; - if (pos < size) - pos = size; - - bad = 0; - } - - fixupCues(mf); - - if (mf->nCues == 0) { - cue = AGET(mf,Cues); - cue->Time = mf->firstTimecode; - cue->Position = mf->pCluster - mf->pSegment; - cue->Block = 0; - cue->Track = 0; - } - - mf->cache->progress(mf->cache,0,0); - - memcpy(&mf->jb,&jb,sizeof(jb)); -} - -static void fixupChapter(ulonglong adj, struct Chapter *ch) { - unsigned i; - - if (ch->Start != 0) - ch->Start -= adj; - if (ch->End != 0) - ch->End -= adj; - - for (i=0;inChildren;++i) - fixupChapter(adj,&ch->Children[i]); -} - -static longlong findLastTimecode(MatroskaFile *mf) { - ulonglong nd = 0; - unsigned n,vtrack; - - if (mf->nTracks == 0) - return -1; - - for (n=vtrack=0;nnTracks;++n) - if (mf->Tracks[n]->Type == TT_VIDEO) { - vtrack = n; - goto ok; - } - - return -1; -ok: - - EmptyQueues(mf); - - if (mf->nCues == 0) { - mf->readPosition = mf->pCluster + 13000000 > mf->pSegmentTop ? mf->pCluster : mf->pSegmentTop - 13000000; - mf->tcCluster = 0; - } else { - mf->readPosition = mf->Cues[mf->nCues - 1].Position + mf->pSegment; - mf->tcCluster = mf->Cues[mf->nCues - 1].Time / mf->Seg.TimecodeScale; - } - mf->trackMask = ~(1 << vtrack); - - do - while (mf->Queues[vtrack].head) - { - ulonglong tc = mf->Queues[vtrack].head->flags & FRAME_UNKNOWN_END ? - mf->Queues[vtrack].head->Start : mf->Queues[vtrack].head->End; - if (nd < tc) - nd = tc; - QFree(mf,QGet(&mf->Queues[vtrack])); - } - while (fillQueues(mf,0) != EOF); - - mf->trackMask = 0; - - EmptyQueues(mf); - - // there may have been an error, but at this point we will ignore it - if (mf->flags & MPF_ERROR) { - mf->flags &= ~MPF_ERROR; - if (nd == 0) - return -1; - } - - return nd; -} - -static void parseFile(MatroskaFile *mf) { - ulonglong len = filepos(mf), adjust; - unsigned i; - int id = readID(mf); - int m; - - if (id==EOF) - errorjmp(mf,"Unexpected EOF at start of file"); - - // files with multiple concatenated segments can have only - // one EBML prolog - if (len > 0 && id == 0x18538067) - goto segment; - - if (id!=0x1a45dfa3) - errorjmp(mf,"First element in file is not EBML"); - - parseEBML(mf,readSize(mf)); - - // next we need to find the first segment - for (;;) { - id = readID(mf); - if (id==EOF) - errorjmp(mf,"No segments found in the file"); -segment: - len = readVLUIntImp(mf,&m); - // see if it's unspecified - if (len == (MAXU64 >> (57-m*7))) - len = MAXU64; - if (id == 0x18538067) // Segment - break; - skipbytes(mf,len); - } - - // found it - mf->pSegment = filepos(mf); - if (len == MAXU64) { - mf->pSegmentTop = MAXU64; - if (mf->cache->getfilesize) { - longlong seglen = mf->cache->getfilesize(mf->cache); - if (seglen > 0) - mf->pSegmentTop = seglen; - } - } else - mf->pSegmentTop = mf->pSegment + len; - parseSegment(mf,len); - - // check if we got all data - if (!mf->seen.SegmentInfo) - errorjmp(mf,"Couldn't find SegmentInfo"); - if (!mf->seen.Cluster) - mf->pCluster = mf->pSegmentTop; - - adjust = mf->firstTimecode * mf->Seg.TimecodeScale; - - for (i=0;inChapters;++i) - fixupChapter(adjust, &mf->Chapters[i]); - - fixupCues(mf); - - // release extra memory - ARELEASE(mf,mf,Tracks); - - // initialize reader - mf->Queues = mf->cache->memalloc(mf->cache,mf->nTracks * sizeof(*mf->Queues)); - if (mf->Queues == NULL) - errorjmp(mf, "Ouf of memory"); - memset(mf->Queues, 0, mf->nTracks * sizeof(*mf->Queues)); - - // try to detect real duration - if (!(mf->flags & MKVF_AVOID_SEEKS)) { - longlong nd = findLastTimecode(mf); - if (nd > 0) - mf->Seg.Duration = nd; - } - - // move to first frame - mf->readPosition = mf->pCluster; - mf->tcCluster = mf->firstTimecode; -} - -static void DeleteChapter(MatroskaFile *mf,struct Chapter *ch) { - unsigned i,j; - - for (i=0;inDisplay;++i) - mf->cache->memfree(mf->cache,ch->Display[i].String); - mf->cache->memfree(mf->cache,ch->Display); - mf->cache->memfree(mf->cache,ch->Tracks); - - for (i=0;inProcess;++i) { - for (j=0;jProcess[i].nCommands;++j) - mf->cache->memfree(mf->cache,ch->Process[i].Commands[j].Command); - mf->cache->memfree(mf->cache,ch->Process[i].Commands); - mf->cache->memfree(mf->cache,ch->Process[i].CodecPrivate); - } - mf->cache->memfree(mf->cache,ch->Process); - - for (i=0;inChildren;++i) - DeleteChapter(mf,&ch->Children[i]); - mf->cache->memfree(mf->cache,ch->Children); -} - -/////////////////////////////////////////////////////////////////////////// -// public interface -MatroskaFile *mkv_OpenEx(InputStream *io, - ulonglong base, - unsigned flags, - char *err_msg,unsigned msgsize) -{ - MatroskaFile *mf = io->memalloc(io,sizeof(*mf)); - if (mf == NULL) { - strlcpy(err_msg,"Out of memory",msgsize); - return NULL; - } - - memset(mf,0,sizeof(*mf)); - - mf->cache = io; - mf->flags = flags; - io->progress(io,0,0); - - if (setjmp(mf->jb)==0) { - seek(mf,base); - parseFile(mf); - } else { // parser error - strlcpy(err_msg,mf->errmsg,msgsize); - mkv_Close(mf); - return NULL; - } - - return mf; -} - -MatroskaFile *mkv_Open(InputStream *io, - char *err_msg,unsigned msgsize) -{ - return mkv_OpenEx(io,0,0,err_msg,msgsize); -} - -void mkv_Close(MatroskaFile *mf) { - unsigned i,j; - - if (mf==NULL) - return; - - for (i=0;inTracks;++i) - mf->cache->memfree(mf->cache,mf->Tracks[i]); - mf->cache->memfree(mf->cache,mf->Tracks); - - for (i=0;inQBlocks;++i) - mf->cache->memfree(mf->cache,mf->QBlocks[i]); - mf->cache->memfree(mf->cache,mf->QBlocks); - - mf->cache->memfree(mf->cache,mf->Queues); - - mf->cache->memfree(mf->cache,mf->Seg.Title); - mf->cache->memfree(mf->cache,mf->Seg.MuxingApp); - mf->cache->memfree(mf->cache,mf->Seg.WritingApp); - mf->cache->memfree(mf->cache,mf->Seg.Filename); - mf->cache->memfree(mf->cache,mf->Seg.NextFilename); - mf->cache->memfree(mf->cache,mf->Seg.PrevFilename); - - mf->cache->memfree(mf->cache,mf->Cues); - - for (i=0;inAttachments;++i) { - mf->cache->memfree(mf->cache,mf->Attachments[i].Description); - mf->cache->memfree(mf->cache,mf->Attachments[i].Name); - mf->cache->memfree(mf->cache,mf->Attachments[i].MimeType); - } - mf->cache->memfree(mf->cache,mf->Attachments); - - for (i=0;inChapters;++i) - DeleteChapter(mf,&mf->Chapters[i]); - mf->cache->memfree(mf->cache,mf->Chapters); - - for (i=0;inTags;++i) { - for (j=0;jTags[i].nSimpleTags;++j) { - mf->cache->memfree(mf->cache,mf->Tags[i].SimpleTags[j].Name); - mf->cache->memfree(mf->cache,mf->Tags[i].SimpleTags[j].Value); - } - mf->cache->memfree(mf->cache,mf->Tags[i].Targets); - mf->cache->memfree(mf->cache,mf->Tags[i].SimpleTags); - } - mf->cache->memfree(mf->cache,mf->Tags); - - mf->cache->memfree(mf->cache,mf); -} - -const char *mkv_GetLastError(MatroskaFile *mf) { - return mf->errmsg[0] ? mf->errmsg : NULL; -} - -SegmentInfo *mkv_GetFileInfo(MatroskaFile *mf) { - return &mf->Seg; -} - -unsigned int mkv_GetNumTracks(MatroskaFile *mf) { - return mf->nTracks; -} - -TrackInfo *mkv_GetTrackInfo(MatroskaFile *mf,unsigned track) { - if (track>mf->nTracks) - return NULL; - - return mf->Tracks[track]; -} - -void mkv_GetAttachments(MatroskaFile *mf,Attachment **at,unsigned *count) { - *at = mf->Attachments; - *count = mf->nAttachments; -} - -void mkv_GetChapters(MatroskaFile *mf,Chapter **ch,unsigned *count) { - *ch = mf->Chapters; - *count = mf->nChapters; -} - -void mkv_GetTags(MatroskaFile *mf,Tag **tag,unsigned *count) { - *tag = mf->Tags; - *count = mf->nTags; -} - -ulonglong mkv_GetSegmentTop(MatroskaFile *mf) { - return mf->pSegmentTop; -} - -#define IS_DELTA(f) (!((f)->flags & FRAME_KF) || ((f)->flags & FRAME_UNKNOWN_START)) - -void mkv_Seek(MatroskaFile *mf,ulonglong timecode,unsigned flags) { - int i,j,m,ret; - unsigned n,z,mask; - ulonglong m_kftime[MAX_TRACKS]; - unsigned char m_seendf[MAX_TRACKS]; - - if (mf->flags & MKVF_AVOID_SEEKS) - return; - - if (timecode == 0) { - EmptyQueues(mf); - mf->readPosition = mf->pCluster; - mf->tcCluster = mf->firstTimecode; - mf->flags &= ~MPF_ERROR; - - return; - } - - if (mf->nCues==0) - reindex(mf); - - if (mf->nCues==0) - return; - - mf->flags &= ~MPF_ERROR; - - i = 0; - j = mf->nCues - 1; - - for (;;) { - if (i>j) { - j = j>=0 ? j : 0; - - if (setjmp(mf->jb)!=0) - return; - - mkv_SetTrackMask(mf,mf->trackMask); - - if (flags & MKVF_SEEK_TO_PREV_KEYFRAME) { - // we do this in two stages - // a. find the last keyframes before the require position - // b. seek to them - - // pass 1 - for (;;) { - for (n=0;nnTracks;++n) { - m_kftime[n] = MAXU64; - m_seendf[n] = 0; - } - - EmptyQueues(mf); - - mf->readPosition = mf->Cues[j].Position + mf->pSegment; - mf->tcCluster = mf->Cues[j].Time / mf->Seg.TimecodeScale; - - for (;;) { - if ((ret = fillQueues(mf,0)) < 0 || ret == RBRESYNC) - return; - - // drain queues until we get to the required timecode - for (n=0;nnTracks;++n) { - if (mf->Queues[n].head && mf->Queues[n].head->StartQueues[n].head)) - m_seendf[n] = 1; - else - m_kftime[n] = mf->Queues[n].head->Start; - } - - while (mf->Queues[n].head && mf->Queues[n].head->StartQueues[n].head)) - m_seendf[n] = 1; - else - m_kftime[n] = mf->Queues[n].head->Start; - QFree(mf,QGet(&mf->Queues[n])); - } - - 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;nnTracks;++n) - if (mf->Queues[n].head && mf->Queues[n].head->Start>=timecode) - goto found; - } -found: - - for (n=0;nnTracks;++n) - if (!(mf->trackMask & (1<0) - { - // we need to restart the search from prev cue - --j; - goto again; - } - - break; -again:; - } - } else - for (n=0;nnTracks;++n) - m_kftime[n] = timecode; - - // now seek to this timecode - EmptyQueues(mf); - - mf->readPosition = mf->Cues[j].Position + mf->pSegment; - mf->tcCluster = mf->Cues[j].Time / mf->Seg.TimecodeScale; - - for (mask=0;;) { - if ((ret = fillQueues(mf,mask)) < 0 || ret == RBRESYNC) - return; - - // drain queues until we get to the required timecode - for (n=0;nnTracks;++n) { - struct QueueEntry *qe; - for (qe = mf->Queues[n].head;qe && qe->StartQueues[n].head) - QFree(mf,QGet(&mf->Queues[n])); - } - - for (n=z=0;nnTracks;++n) - if (m_kftime[n]==MAXU64 || (mf->Queues[n].head && mf->Queues[n].head->Start>=m_kftime[n])) { - ++z; - mask |= 1<nTracks) - return; - } - } - - m = (i+j)>>1; - - if (timecode < mf->Cues[m].Time) - j = m-1; - else - i = m+1; - } -} - -void mkv_SkipToKeyframe(MatroskaFile *mf) { - unsigned n,wait; - ulonglong ht; - - if (setjmp(mf->jb)!=0) - return; - - // remove delta frames from queues - do { - wait = 0; - - if (fillQueues(mf,0)<0) - return; - - for (n=0;nnTracks;++n) - if (mf->Queues[n].head && !(mf->Queues[n].head->flags & FRAME_KF)) { - ++wait; - QFree(mf,QGet(&mf->Queues[n])); - } - } while (wait); - - // find highest queued time - for (n=0,ht=0;nnTracks;++n) - if (mf->Queues[n].head && htQueues[n].head->Start) - ht = mf->Queues[n].head->Start; - - // ensure the time difference is less than 100ms - do { - wait = 0; - - if (fillQueues(mf,0)<0) - return; - - for (n=0;nnTracks;++n) - while (mf->Queues[n].head && mf->Queues[n].head->next && - (mf->Queues[n].head->next->flags & FRAME_KF) && - ht - mf->Queues[n].head->Start > 100000000) - { - ++wait; - QFree(mf,QGet(&mf->Queues[n])); - } - - } while (wait); -} - -ulonglong mkv_GetLowestQTimecode(MatroskaFile *mf) { - unsigned n,seen; - ulonglong t; - - // find the lowest queued timecode - for (n=seen=0,t=0;nnTracks;++n) - if (mf->Queues[n].head && (!seen || t > mf->Queues[n].head->Start)) - t = mf->Queues[n].head->Start, seen=1; - - return seen ? t : (ulonglong)LL(-1); -} - -int mkv_TruncFloat(MKFLOAT f) { -#ifdef MATROSKA_INTEGER_ONLY - return (int)(f.v >> 32); -#else - return (int)f; -#endif -} - -#define FTRACK 0xffffffff - -void mkv_SetTrackMask(MatroskaFile *mf,unsigned int mask) { - unsigned int i; - - if (mf->flags & MPF_ERROR) - return; - - mf->trackMask = mask; - - for (i=0;inTracks;++i) - if (mask & (1<Queues[i]); -} - -int mkv_ReadFrame(MatroskaFile *mf, - unsigned int mask,unsigned int *track, - ulonglong *StartTime,ulonglong *EndTime, - ulonglong *FilePos,unsigned int *FrameSize, - unsigned int *FrameFlags) -{ - unsigned int i,j; - struct QueueEntry *qe; - - if (setjmp(mf->jb)!=0) - return -1; - - do { - // extract required frame, use block with the lowest timecode - for (j=FTRACK,i=0;inTracks;++i) - if (!(mask & (1<Queues[i].head) { - j = i; - ++i; - break; - } - - for (;inTracks;++i) - if (!(mask & (1<Queues[i].head && - mf->Queues[j].head->Start > mf->Queues[i].head->Start) - j = i; - - if (j != FTRACK) { - qe = QGet(&mf->Queues[j]); - - *track = j; - *StartTime = qe->Start; - *EndTime = qe->End; - *FilePos = qe->Position; - *FrameSize = qe->Length; - *FrameFlags = qe->flags; - - QFree(mf,qe); - - return 0; - } - - if (mf->flags & MPF_ERROR) - return -1; - - } while (fillQueues(mf,mask)>=0); - - return EOF; -} - -#ifdef MATROSKA_COMPRESSION_SUPPORT -/************************************************************************* - * Compressed streams support - ************************************************************************/ -struct CompressedStream { - MatroskaFile *mf; - z_stream zs; - - /* current compressed frame */ - ulonglong frame_pos; - unsigned frame_size; - char frame_buffer[2048]; - - /* decoded data buffer */ - char decoded_buffer[2048]; - unsigned decoded_ptr; - unsigned decoded_size; - - /* error handling */ - char errmsg[128]; -}; - -CompressedStream *cs_Create(/* in */ MatroskaFile *mf, - /* in */ unsigned tracknum, - /* out */ char *errormsg, - /* in */ unsigned msgsize) -{ - CompressedStream *cs; - TrackInfo *ti; - int code; - - ti = mkv_GetTrackInfo(mf, tracknum); - if (ti == NULL) { - strlcpy(errormsg, "No such track.", msgsize); - return NULL; - } - - if (!ti->CompEnabled) { - strlcpy(errormsg, "Track is not compressed.", msgsize); - return NULL; - } - - if (ti->CompMethod != COMP_ZLIB) { - strlcpy(errormsg, "Unsupported compression method.", msgsize); - return NULL; - } - - cs = mf->cache->memalloc(mf->cache,sizeof(*cs)); - if (cs == NULL) { - strlcpy(errormsg, "Ouf of memory.", msgsize); - return NULL; - } - - memset(&cs->zs,0,sizeof(cs->zs)); - code = inflateInit(&cs->zs); - if (code != Z_OK) { - strlcpy(errormsg, "ZLib error.", msgsize); - mf->cache->memfree(mf->cache,cs); - return NULL; - } - - cs->frame_size = 0; - cs->decoded_ptr = cs->decoded_size = 0; - cs->mf = mf; - - return cs; -} - -void cs_Destroy(/* in */ CompressedStream *cs) { - if (cs == NULL) - return; - - inflateEnd(&cs->zs); - cs->mf->cache->memfree(cs->mf->cache,cs); -} - -/* advance to the next frame in matroska stream, you need to pass values returned - * by mkv_ReadFrame */ -void cs_NextFrame(/* in */ CompressedStream *cs, - /* in */ ulonglong pos, - /* in */ unsigned size) -{ - cs->zs.avail_in = 0; - inflateReset(&cs->zs); - cs->frame_pos = pos; - cs->frame_size = size; - cs->decoded_ptr = cs->decoded_size = 0; -} - -/* read and decode more data from current frame, return number of bytes decoded, - * 0 on end of frame, or -1 on error */ -int cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize) -{ - char *cp = buffer; - unsigned rd = 0; - unsigned todo; - int code; - - do { - /* try to copy data from decoded buffer */ - if (cs->decoded_ptr < cs->decoded_size) { - todo = cs->decoded_size - cs->decoded_ptr;; - if (todo > bufsize - rd) - todo = bufsize - rd; - - memcpy(cp, cs->decoded_buffer + cs->decoded_ptr, todo); - - rd += todo; - cp += todo; - cs->decoded_ptr += todo; - } else { - /* setup output buffer */ - cs->zs.next_out = cs->decoded_buffer; - cs->zs.avail_out = sizeof(cs->decoded_buffer); - - /* try to read more data */ - if (cs->zs.avail_in == 0 && cs->frame_size > 0) { - todo = cs->frame_size; - if (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) { - strlcpy(cs->errmsg, "File read failed", sizeof(cs->errmsg)); - return -1; - } - - cs->zs.next_in = cs->frame_buffer; - cs->zs.avail_in = todo; - - cs->frame_pos += todo; - cs->frame_size -= todo; - } - - /* try to decode more data */ - code = inflate(&cs->zs,Z_NO_FLUSH); - if (code != Z_OK && code != Z_STREAM_END) { - strlcpy(cs->errmsg, "ZLib error.", sizeof(cs->errmsg)); - return -1; - } - - /* handle decoded data */ - if (cs->zs.avail_out == sizeof(cs->decoded_buffer)) /* EOF */ - break; - - cs->decoded_ptr = 0; - cs->decoded_size = sizeof(cs->decoded_buffer) - cs->zs.avail_out; - } - } while (rd < bufsize); - - return rd; -} - -/* return error message for the last error */ -const char *cs_GetLastError(CompressedStream *cs) -{ - if (!cs->errmsg[0]) - return NULL; - return cs->errmsg; -} -#endif diff --git a/FFmpegSource/MatroskaParser.h b/FFmpegSource/MatroskaParser.h deleted file mode 100644 index 53dc49918..000000000 --- a/FFmpegSource/MatroskaParser.h +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright (c) 2004-2006 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.19 2006/03/11 10:57:13 mike Exp $ - * - */ - -#ifndef MATROSKA_PARSER_H -#define MATROSKA_PARSER_H - -/* Random notes: - * - * The parser does not process frame data in any way and does not read it into - * the queue. The app should read it via mkv_ReadData if it is interested. - * - * The code here is 64-bit clean and was tested on FreeBSD/sparc 64-bit big endian - * system - */ - -#ifdef MPDLLBUILD -#define X __declspec(dllexport) -#else -#ifdef MPDLL -#define X __declspec(dllimport) -#pragma comment(lib,"MatroskaParser") -#else -#define X -#endif -#endif - -#define MATROSKA_COMPRESSION_SUPPORT -#define MATROSKA_INTEGER_ONLY - -#ifdef __cplusplus -extern "C" { -#endif - -/* 64-bit integers */ -#ifdef _WIN32_WCE -typedef signed __int64 longlong; -typedef unsigned __int64 ulonglong; -#else -typedef signed long long longlong; -typedef unsigned long long ulonglong; -#endif - -/* MKFLOATing point */ -#ifdef MATROSKA_INTEGER_ONLY -typedef struct { - longlong v; -} MKFLOAT; -#else -typedef double MKFLOAT; -#endif - -/* generic I/O */ -struct InputStream { - /* read bytes from stream */ - int (*read)(struct InputStream *cc,ulonglong pos,void *buffer,int count); - /* scan for a four byte signature, bytes must be nonzero */ - longlong (*scan)(struct InputStream *cc,ulonglong start,unsigned signature); - /* get cache size, this is used to cap readahead */ - unsigned (*getcachesize)(struct InputStream *cc); - /* fetch last error message */ - const char *(*geterror)(struct InputStream *cc); - /* memory allocation */ - void *(*memalloc)(struct InputStream *cc,size_t size); - void *(*memrealloc)(struct InputStream *cc,void *mem,size_t newsize); - void (*memfree)(struct InputStream *cc,void *mem); - /* zero return causes parser to abort open */ - int (*progress)(struct InputStream *cc,ulonglong cur,ulonglong max); - /* get file size, optional, can be NULL or return -1 if filesize is unknown */ - longlong (*getfilesize)(struct InputStream *cc); -}; - -typedef struct InputStream InputStream; - -/* matroska file */ -struct MatroskaFile; /* opaque */ - -typedef struct MatroskaFile MatroskaFile; - -#define COMP_ZLIB 0 -#define COMP_BZIP 1 -#define COMP_LZO1X 2 -#define COMP_PREPEND 3 - -#define TT_VIDEO 1 -#define TT_AUDIO 2 -#define TT_SUB 17 - -struct TrackInfo { - unsigned char Number; - unsigned char Type; - unsigned char TrackOverlay; - ulonglong UID; - ulonglong MinCache; - ulonglong MaxCache; - ulonglong DefaultDuration; - MKFLOAT TimecodeScale; - void *CodecPrivate; - unsigned CodecPrivateSize; - unsigned CompMethod; - void *CompMethodPrivate; - unsigned CompMethodPrivateSize; - unsigned MaxBlockAdditionID; - struct { - unsigned int Enabled:1; - unsigned int Default:1; - unsigned int Lacing:1; - unsigned int DecodeAll:1; - unsigned int CompEnabled:1; - }; - - union { - struct { - unsigned char StereoMode; - unsigned char DisplayUnit; - unsigned char AspectRatioType; - unsigned int PixelWidth; - unsigned int PixelHeight; - unsigned int DisplayWidth; - unsigned int DisplayHeight; - unsigned int CropL, CropT, CropR, CropB; - unsigned int ColourSpace; - MKFLOAT GammaValue; - struct { - unsigned int Interlaced:1; - }; - } Video; - struct { - MKFLOAT SamplingFreq; - MKFLOAT OutputSamplingFreq; - unsigned char Channels; - unsigned char BitDepth; - } Audio; - } AV; - - /* various strings */ - char *Name; - char Language[4]; - char *CodecID; -}; - -typedef struct TrackInfo TrackInfo; - -struct SegmentInfo { - char UID[16]; - char PrevUID[16]; - char NextUID[16]; - char *Filename; - char *PrevFilename; - char *NextFilename; - char *Title; - char *MuxingApp; - char *WritingApp; - ulonglong TimecodeScale; - ulonglong Duration; - longlong DateUTC; - char DateUTCValid; -}; - -typedef struct SegmentInfo SegmentInfo; - -struct Attachment { - ulonglong Position; - ulonglong Length; - ulonglong UID; - char *Name; - char *Description; - char *MimeType; -}; - -typedef struct Attachment Attachment; - -struct ChapterDisplay { - char *String; - char Language[4]; - char Country[4]; -}; - -struct ChapterCommand { - unsigned Time; - unsigned CommandLength; - void *Command; -}; - -struct ChapterProcess { - unsigned CodecID; - unsigned CodecPrivateLength; - void *CodecPrivate; - unsigned nCommands,nCommandsSize; - struct ChapterCommand *Commands; -}; - -struct Chapter { - ulonglong UID; - ulonglong Start; - ulonglong End; - - unsigned nTracks,nTracksSize; - ulonglong *Tracks; - unsigned nDisplay,nDisplaySize; - struct ChapterDisplay *Display; - unsigned nChildren,nChildrenSize; - struct Chapter *Children; - unsigned nProcess,nProcessSize; - struct ChapterProcess *Process; - - char SegmentUID[16]; - - struct { - unsigned int Hidden:1; - unsigned int Enabled:1; - - // Editions - unsigned int Default:1; - unsigned int Ordered:1; - }; -}; - -typedef struct Chapter Chapter; - -#define TARGET_TRACK 0 -#define TARGET_CHAPTER 1 -#define TARGET_ATTACHMENT 2 -#define TARGET_EDITION 3 -struct Target { - ulonglong UID; - unsigned Type; -}; - -struct SimpleTag { - char *Name; - char *Value; - char Language[4]; - unsigned Default:1; -}; - -struct Tag { - unsigned nTargets,nTargetsSize; - struct Target *Targets; - - unsigned nSimpleTags,nSimpleTagsSize; - struct SimpleTag *SimpleTags; -}; - -typedef struct Tag Tag; - -/* Open a matroska file - * io pointer is recorded inside MatroskaFile - */ -X MatroskaFile *mkv_Open(/* in */ InputStream *io, - /* out */ char *err_msg, - /* in */ unsigned msgsize); - -#define MKVF_AVOID_SEEKS 1 /* use sequential reading only */ - -X MatroskaFile *mkv_OpenEx(/* in */ InputStream *io, - /* in */ ulonglong base, - /* in */ unsigned flags, - /* out */ char *err_msg, - /* in */ unsigned msgsize); - -/* Close and deallocate mf - * NULL pointer is ok and is simply ignored - */ -X void mkv_Close(/* in */ MatroskaFile *mf); - -/* Fetch the error message of the last failed operation */ -X const char *mkv_GetLastError(/* in */ MatroskaFile *mf); - -/* Get file information */ -X SegmentInfo *mkv_GetFileInfo(/* in */ MatroskaFile *mf); - -/* Get track information */ -X unsigned int mkv_GetNumTracks(/* in */ MatroskaFile *mf); -X TrackInfo *mkv_GetTrackInfo(/* in */ MatroskaFile *mf,/* in */ unsigned track); - -/* chapters, tags and attachments */ -X void mkv_GetAttachments(/* in */ MatroskaFile *mf, - /* out */ Attachment **at, - /* out */ unsigned *count); -X void mkv_GetChapters(/* in */ MatroskaFile *mf, - /* out */ Chapter **ch, - /* out */ unsigned *count); -X void mkv_GetTags(/* in */ MatroskaFile *mf, - /* out */ Tag **tag, - /* out */ unsigned *count); - -X ulonglong mkv_GetSegmentTop(MatroskaFile *mf); - -/* Seek to specified timecode, - * if timecode is past end of file, - * all tracks are set to return EOF - * on next read - */ -#define MKVF_SEEK_TO_PREV_KEYFRAME 1 - -X void mkv_Seek(/* in */ MatroskaFile *mf, - /* in */ ulonglong timecode /* in ns */, - /* in */ unsigned flags); - -X void mkv_SkipToKeyframe(MatroskaFile *mf); - -X ulonglong mkv_GetLowestQTimecode(MatroskaFile *mf); - -X int mkv_TruncFloat(MKFLOAT f); - -/************************************************************************* - * reading data, pull model - */ - -/* frame flags */ -#define FRAME_UNKNOWN_START 0x00000001 -#define FRAME_UNKNOWN_END 0x00000002 -#define FRAME_KF 0x00000004 -#define FRAME_GAP 0x00800000 -#define FRAME_STREAM_MASK 0xff000000 -#define FRAME_STREAM_SHIFT 24 - -/* This sets the masking flags for the parser, - * masked tracks [with 1s in their bit positions] - * will be ignored when reading file data. - * This call discards all parsed and queued frames - */ -X void mkv_SetTrackMask(/* in */ MatroskaFile *mf,/* in */ unsigned int mask); - -/* Read one frame from the queue. - * mask specifies what tracks to ignore. - * Returns -1 if there are no more frames in the specified - * set of tracks, 0 on success - */ -X int mkv_ReadFrame(/* in */ MatroskaFile *mf, - /* in */ unsigned int mask, - /* out */ unsigned int *track, - /* out */ ulonglong *StartTime /* in ns */, - /* out */ ulonglong *EndTime /* in ns */, - /* out */ ulonglong *FilePos /* in bytes from start of file */, - /* out */ unsigned int *FrameSize /* in bytes */, - /* out */ unsigned int *FrameFlags); - -#ifdef MATROSKA_COMPRESSION_SUPPORT -/* Compressed streams support */ -struct CompressedStream; - -typedef struct CompressedStream CompressedStream; - -X CompressedStream *cs_Create(/* in */ MatroskaFile *mf, - /* in */ unsigned tracknum, - /* out */ char *errormsg, - /* in */ unsigned msgsize); -X void cs_Destroy(/* in */ CompressedStream *cs); - -/* advance to the next frame in matroska stream, you need to pass values returned - * by mkv_ReadFrame */ -X void cs_NextFrame(/* in */ CompressedStream *cs, - /* in */ ulonglong pos, - /* in */ unsigned size); - -/* read and decode more data from current frame, return number of bytes decoded, - * 0 on end of frame, or -1 on error */ -X int cs_ReadData(CompressedStream *cs,char *buffer,unsigned bufsize); - -/* return error message for the last error */ -X const char *cs_GetLastError(CompressedStream *cs); -#endif - -#ifdef __cplusplus -} -#endif - -#undef X - -#endif diff --git a/FFmpegSource/avisynth.h b/FFmpegSource/avisynth.h deleted file mode 100644 index 54aff1cdf..000000000 --- a/FFmpegSource/avisynth.h +++ /dev/null @@ -1,749 +0,0 @@ -// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. -// http://www.avisynth.org - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit -// http://www.gnu.org/copyleft/gpl.html . -// -// Linking Avisynth statically or dynamically with other modules is making a -// combined work based on Avisynth. Thus, the terms and conditions of the GNU -// General Public License cover the whole combination. -// -// As a special exception, the copyright holders of Avisynth give you -// permission to link Avisynth with independent modules that communicate with -// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license -// terms of these independent modules, and to copy and distribute the -// resulting combined work under terms of your choice, provided that -// every copy of the combined work is accompanied by a complete copy of -// the source code of Avisynth (the version of Avisynth used to produce the -// combined work), being distributed under the terms of the GNU General -// Public License plus this exception. An independent module is a module -// which is not derived from or based on Avisynth, such as 3rd-party filters, -// import and export plugins, or graphical user interfaces. - - - - - -#ifndef __AVISYNTH_H__ -#define __AVISYNTH_H__ - -enum { AVISYNTH_INTERFACE_VERSION = 3 }; - - -/* Define all types necessary for interfacing with avisynth.dll - Moved from internal.h */ - -// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc. -#include - -// COM interface macros -#include - - -// Raster types used by VirtualDub & Avisynth -#define in64 (__int64)(unsigned short) -typedef unsigned long Pixel; // this will break on 64-bit machines! -typedef unsigned long Pixel32; -typedef unsigned char Pixel8; -typedef long PixCoord; -typedef long PixDim; -typedef long PixOffset; - - -/* Compiler-specific crap */ - -// Tell MSVC to stop precompiling here -#ifdef _MSC_VER - #pragma hdrstop -#endif - -// Set up debugging macros for MS compilers; for others, step down to the -// standard interface -#ifdef _MSC_VER - #include -#else - #define _RPT0(a,b) ((void)0) - #define _RPT1(a,b,c) ((void)0) - #define _RPT2(a,b,c,d) ((void)0) - #define _RPT3(a,b,c,d,e) ((void)0) - #define _RPT4(a,b,c,d,e,f) ((void)0) - - #define _ASSERTE(x) assert(x) - #include -#endif - - - -// I had problems with Premiere wanting 1-byte alignment for its structures, -// so I now set the Avisynth struct alignment explicitly here. -#pragma pack(push,8) - -#define FRAME_ALIGN 16 -// Default frame alignment is 16 bytes, to help P4, when using SSE2 - -// The VideoInfo struct holds global information about a clip (i.e. -// information that does not depend on the frame number). The GetVideoInfo -// method in IClip returns this struct. - -// Audio Sample information -typedef float SFLOAT; - -enum {SAMPLE_INT8 = 1<<0, - SAMPLE_INT16 = 1<<1, - SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware. - SAMPLE_INT32 = 1<<3, - SAMPLE_FLOAT = 1<<4}; - -enum { - PLANAR_Y=1<<0, - PLANAR_U=1<<1, - PLANAR_V=1<<2, - PLANAR_ALIGNED=1<<3, - PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED, - PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED, - PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED, - }; - -struct VideoInfo { - int width, height; // width=0 means no video - unsigned fps_numerator, fps_denominator; - int num_frames; - // This is more extensible than previous versions. More properties can be added seeminglesly. - - // Colorspace properties. - enum { - CS_BGR = 1<<28, - CS_YUV = 1<<29, - CS_INTERLEAVED = 1<<30, - CS_PLANAR = 1<<31 - }; - - // Specific colorformats - enum { CS_UNKNOWN = 0, - CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED, - CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED, - CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED, - CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, planar - CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, planar - CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above - }; - int pixel_type; // changed to int as of 2.5 - - - int audio_samples_per_second; // 0 means no audio - int sample_type; // as of 2.5 - __int64 num_audio_samples; // changed as of 2.5 - int nchannels; // as of 2.5 - - // Imagetype properties - - int image_type; - - enum { - IT_BFF = 1<<0, - IT_TFF = 1<<1, - IT_FIELDBASED = 1<<2 - }; - - // useful functions of the above - bool HasVideo() const { return (width!=0); } - bool HasAudio() const { return (audio_samples_per_second!=0); } - bool IsRGB() const { return !!(pixel_type&CS_BGR); } - bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties - bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; } - bool IsYUV() const { return !!(pixel_type&CS_YUV ); } - bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; } - bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); } - bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); } - bool Is(int property) const { return ((pixel_type & property)==property ); } - bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); } - bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); } - bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); } - bool IsBFF() const { return !!(image_type & IT_BFF); } - bool IsTFF() const { return !!(image_type & IT_TFF); } - - bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this - int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes - int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images - int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); } - __int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; } - int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; } - __int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; } - __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); } - int AudioChannels() const { return HasAudio() ? nchannels : 0; } - int SampleType() const{ return sample_type;} - bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);} - int SamplesPerSecond() const { return audio_samples_per_second; } - int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();} - void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; } - void Set(int property) { image_type|=property; } - void Clear(int property) { image_type&=~property; } - - int BitsPerPixel() const { - switch (pixel_type) { - case CS_BGR24: - return 24; - case CS_BGR32: - return 32; - case CS_YUY2: - return 16; - case CS_YV12: - case CS_I420: - return 12; - default: - return 0; - } - } - int BytesPerChannelSample() const { - switch (sample_type) { - case SAMPLE_INT8: - return sizeof(signed char); - case SAMPLE_INT16: - return sizeof(signed short); - case SAMPLE_INT24: - return 3; - case SAMPLE_INT32: - return sizeof(signed int); - case SAMPLE_FLOAT: - return sizeof(SFLOAT); - default: - _ASSERTE("Sample type not recognized!"); - return 0; - } - } - - // useful mutator - void SetFPS(unsigned numerator, unsigned denominator) { - if ((numerator == 0) || (denominator == 0)) { - fps_numerator = 0; - fps_denominator = 1; - } - else { - unsigned x=numerator, y=denominator; - while (y) { // find gcd - unsigned t = x%y; x = y; y = t; - } - fps_numerator = numerator/x; - fps_denominator = denominator/x; - } - } - - // Range protected multiply-divide of FPS - void MulDivFPS(unsigned multiplier, unsigned divisor) { - unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier); - unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor); - - unsigned __int64 x=numerator, y=denominator; - while (y) { // find gcd - unsigned __int64 t = x%y; x = y; y = t; - } - numerator /= x; // normalize - denominator /= x; - - unsigned __int64 temp = numerator | denominator; // Just looking top bit - unsigned u = 0; - while (temp & 0xffffffff80000000) { // or perhaps > 16777216*2 - temp = Int64ShrlMod32(temp, 1); - u++; - } - if (u) { // Scale to fit - const unsigned round = 1 << (u-1); - SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u), - (unsigned)Int64ShrlMod32(denominator + round, u) ); - } - else { - fps_numerator = (unsigned)numerator; - fps_denominator = (unsigned)denominator; - } - } - - // Test for same colorspace - bool IsSameColorspace(const VideoInfo& vi) const { - if (vi.pixel_type == pixel_type) return TRUE; - if (IsYV12() && vi.IsYV12()) return TRUE; - return FALSE; - } - -}; - - - - -// VideoFrameBuffer holds information about a memory block which is used -// for video data. For efficiency, instances of this class are not deleted -// when the refcount reaches zero; instead they're stored in a linked list -// to be reused. The instances are deleted when the corresponding AVS -// file is closed. - -class VideoFrameBuffer { - BYTE* const data; - const int data_size; - // sequence_number is incremented every time the buffer is changed, so - // that stale views can tell they're no longer valid. - long sequence_number; - - friend class VideoFrame; - friend class Cache; - friend class ScriptEnvironment; - long refcount; - -public: - VideoFrameBuffer(int size); - VideoFrameBuffer(); - ~VideoFrameBuffer(); - - const BYTE* GetReadPtr() const { return data; } - BYTE* GetWritePtr() { ++sequence_number; return data; } - int GetDataSize() { return data_size; } - int GetSequenceNumber() { return sequence_number; } - int GetRefcount() { return refcount; } -}; - - -class IClip; -class PClip; -class PVideoFrame; -class IScriptEnvironment; -class AVSValue; - - -// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new -// is overloaded to recycle class instances. - -class VideoFrame { - int refcount; - VideoFrameBuffer* const vfb; - const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture. - - friend class PVideoFrame; - void AddRef() { InterlockedIncrement((long *)&refcount); } - void Release() { if (refcount==1) InterlockedDecrement(&vfb->refcount); InterlockedDecrement((long *)&refcount); } - - friend class ScriptEnvironment; - friend class Cache; - - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV); - - void* operator new(unsigned size); -// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard! -public: - int GetPitch() const { return pitch; } - int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; } - int GetRowSize() const { return row_size; } - int GetRowSize(int plane) const { - switch (plane) { - case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0; - case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED: - if (pitchUV) { - int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize - if (r<=pitchUV) - return r; - return row_size>>1; - } else return 0; - case PLANAR_Y_ALIGNED: - int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize - if (r<=pitch) - return r; - return row_size; - } - return row_size; } - int GetHeight() const { return height; } - int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; } - - // generally you shouldn't use these three - VideoFrameBuffer* GetFrameBuffer() const { return vfb; } - int GetOffset() const { return offset; } - int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; } - - // in plugins use env->SubFrame() - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const; - - - const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; } - const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); } - - bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } - - BYTE* GetWritePtr() const { - if (vfb->GetRefcount()>1) { - _ASSERT(FALSE); - //throw AvisynthError("Internal Error - refcount was more than one!"); - } - return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; - } - - BYTE* GetWritePtr(int plane) const { - if (plane==PLANAR_Y) { - if (vfb->GetRefcount()>1) { - _ASSERT(FALSE); -// throw AvisynthError("Internal Error - refcount was more than one!"); - } - return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0; - } - return vfb->data + GetOffset(plane); - } - - ~VideoFrame() { InterlockedDecrement(&vfb->refcount); } -}; - -enum { - CACHE_NOTHING=0, - CACHE_RANGE=1, - CACHE_ALL=2, - CACHE_AUDIO=3, - CACHE_AUDIO_NONE=4 - }; - -// Base class for all filters. -class IClip { - friend class PClip; - friend class AVSValue; - int refcnt; - void AddRef() { InterlockedIncrement((long *)&refcnt); } - void Release() { InterlockedDecrement((long *)&refcnt); if (!refcnt) delete this; } -public: - IClip() : refcnt(0) {} - - virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } - - virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; - virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame - virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples - virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter. - virtual const VideoInfo& __stdcall GetVideoInfo() = 0; - virtual __stdcall ~IClip() {} -}; - - -// smart pointer to IClip -class PClip { - - IClip* p; - - IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } - friend class AVSValue; - friend class VideoFrame; - - void Init(IClip* x) { - if (x) x->AddRef(); - p=x; - } - void Set(IClip* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PClip() { p = 0; } - PClip(const PClip& x) { Init(x.p); } - PClip(IClip* x) { Init(x); } - void operator=(IClip* x) { Set(x); } - void operator=(const PClip& x) { Set(x.p); } - - IClip* operator->() const { return p; } - - // useful in conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PClip() { if (p) p->Release(); } -}; - - -// smart pointer to VideoFrame -class PVideoFrame { - - VideoFrame* p; - - void Init(VideoFrame* x) { - if (x) x->AddRef(); - p=x; - } - void Set(VideoFrame* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PVideoFrame() { p = 0; } - PVideoFrame(const PVideoFrame& x) { Init(x.p); } - PVideoFrame(VideoFrame* x) { Init(x); } - void operator=(VideoFrame* x) { Set(x); } - void operator=(const PVideoFrame& x) { Set(x.p); } - - VideoFrame* operator->() const { return p; } - - // for conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PVideoFrame() { if (p) p->Release();} -}; - - -class AVSValue { -public: - - AVSValue() { type = 'v'; } - AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } - AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } - AVSValue(bool b) { type = 'b'; boolean = b; } - AVSValue(int i) { type = 'i'; integer = i; } -// AVSValue(__int64 l) { type = 'l'; longlong = l; } - AVSValue(float f) { type = 'f'; floating_pt = f; } - AVSValue(double f) { type = 'f'; floating_pt = float(f); } - AVSValue(const char* s) { type = 's'; string = s; } - AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } - AVSValue(const AVSValue& v) { Assign(&v, true); } - - ~AVSValue() { if (IsClip() && clip) clip->Release(); } - AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } - - // Note that we transparently allow 'int' to be treated as 'float'. - // There are no int<->bool conversions, though. - - bool Defined() const { return type != 'v'; } - bool IsClip() const { return type == 'c'; } - bool IsBool() const { return type == 'b'; } - bool IsInt() const { return type == 'i'; } -// bool IsLong() const { return (type == 'l'|| type == 'i'); } - bool IsFloat() const { return type == 'f' || type == 'i'; } - bool IsString() const { return type == 's'; } - bool IsArray() const { return type == 'a'; } - - PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } - bool AsBool() const { _ASSERTE(IsBool()); return boolean; } - int AsInt() const { _ASSERTE(IsInt()); return integer; } -// int AsLong() const { _ASSERTE(IsLong()); return longlong; } - const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } - double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } - - bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } - int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } - double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } - const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } - - int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } - - const AVSValue& operator[](int index) const { - _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) - src->clip->AddRef(); - if (!init && IsClip() && clip) - clip->Release(); - // make sure this copies the whole struct! - ((__int32*)this)[0] = ((__int32*)src)[0]; - ((__int32*)this)[1] = ((__int32*)src)[1]; - } -}; - - -// instantiable null filter -class GenericVideoFilter : public IClip { -protected: - PClip child; - VideoInfo vi; -public: - GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } - void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } - const VideoInfo& __stdcall GetVideoInfo() { return vi; } - bool __stdcall GetParity(int n) { return child->GetParity(n); } - void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter. -}; - - -class AvisynthError /* exception */ { -public: - const char* const msg; - AvisynthError(const char* _msg) : msg(_msg) {} -}; - - - - -/* Helper classes useful to plugin authors */ - -class AlignPlanar : public GenericVideoFilter -{ -public: - AlignPlanar(PClip _clip); - static PClip Create(PClip clip); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); -}; - - - -class FillBorder : public GenericVideoFilter -{ -public: - FillBorder(PClip _clip); - static PClip Create(PClip clip); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); -}; - - - -class ConvertAudio : public GenericVideoFilter -/** - * Helper class to convert audio to any format - **/ -{ -public: - ConvertAudio(PClip _clip, int prefered_format); - void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env); - void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache! - - static PClip Create(PClip clip, int sample_type, int prefered_type); - static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_8bit(AVSValue args, void*, IScriptEnvironment*); - virtual ~ConvertAudio(); - -private: - void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count); - void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count); - - __inline int Saturate_int8(float n); - __inline short Saturate_int16(float n); - __inline int Saturate_int24(float n); - __inline int Saturate_int32(float n); - - char src_format; - char dst_format; - int src_bps; - char *tempbuffer; - SFLOAT *floatbuffer; - int tempbuffer_size; -}; - - -// For GetCPUFlags. These are backwards-compatible with those in VirtualDub. -enum { - /* slowest CPU to support extension */ - CPUF_FORCE = 0x01, // N/A - CPUF_FPU = 0x02, // 386/486DX - CPUF_MMX = 0x04, // P55C, K6, PII - CPUF_INTEGER_SSE = 0x08, // PIII, Athlon - CPUF_SSE = 0x10, // PIII, Athlon XP/MP - CPUF_SSE2 = 0x20, // PIV, Hammer - CPUF_3DNOW = 0x40, // K6-2 - CPUF_3DNOW_EXT = 0x80, // Athlon - CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which only Hammer - // will have anyway) - CPUF_SSE3 = 0x100, // Some P4 & Athlon 64. -}; -#define MAX_INT 0x7fffffff -#define MIN_INT -0x7fffffff - - - -class IScriptEnvironment { -public: - virtual __stdcall ~IScriptEnvironment() {} - - virtual /*static*/ long __stdcall GetCPUFlags() = 0; - - virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; - virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; - // note: val is really a va_list; I hope everyone typedefs va_list to a pointer - virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; - - __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; - - class NotFound /*exception*/ {}; // thrown by Invoke and GetVar - - typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); - - virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; - virtual bool __stdcall FunctionExists(const char* name) = 0; - virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; - - virtual AVSValue __stdcall GetVar(const char* name) = 0; - virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; - virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; - - virtual void __stdcall PushContext(int level=0) = 0; - virtual void __stdcall PopContext() = 0; - - // align should be 4 or 8 - virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0; - - virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; - - virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; - - typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); - virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; - - virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; - - virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; - - virtual int __stdcall SetMemoryMax(int mem) = 0; - - virtual int __stdcall SetWorkingDir(const char * newdir) = 0; - - virtual void* __stdcall ManageCache(int key, void* data) = 0; - - enum PlanarChromaAlignmentMode { - PlanarChromaAlignmentOff, - PlanarChromaAlignmentOn, - PlanarChromaAlignmentTest }; - - virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0; - - virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; -}; - - -// avisynth.dll exports this; it's a way to use it as a library, without -// writing an AVS script or without going through AVIFile. -IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); - - -#pragma pack(pop) - -#endif //__AVISYNTH_H__ diff --git a/FFmpegSource/ffaudiobase.cpp b/FFmpegSource/ffaudiobase.cpp deleted file mode 100644 index e29295aa0..000000000 --- a/FFmpegSource/ffaudiobase.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -FFAudioBase::FFAudioBase() { - memset(&VI, 0, sizeof(VI)); - DecodingBuffer = new uint8_t[AVCODEC_MAX_AUDIO_FRAME_SIZE]; -}; - -FFAudioBase::~FFAudioBase() { - delete[] DecodingBuffer; -}; - -size_t FFAudioBase::FindClosestAudioKeyFrame(int64_t Sample) { - for (size_t i = 0; i < SI.size(); i++) { - if (SI[i].SampleStart == Sample && SI[i].KeyFrame) - return i; - else if (SI[i].SampleStart > Sample && SI[i].KeyFrame) - return i - 1; - } - return SI.size() - 1; -} - -bool FFAudioBase::LoadSampleInfoFromFile(const char *AAudioCacheFile, const char *ASource, int AAudioTrack) { - char DefaultCacheFilename[1024]; - sprintf(DefaultCacheFilename, "%s.ffas%dcache", ASource, AAudioTrack); - if (!strcmp(AAudioCacheFile, "")) - AAudioCacheFile = DefaultCacheFilename; - - FILE *CacheFile = fopen(AAudioCacheFile, "r"); - if (!CacheFile) - return false; - - size_t AudioBlocks = 0; - - if (fscanf(CacheFile, "%lld %u\r\n", &VI.num_audio_samples, &AudioBlocks) <= 0 || VI.num_audio_samples <= 0 || AudioBlocks <= 0) { - VI.num_audio_samples = 0; - fclose(CacheFile); - return false; - } - - for (size_t i = 0; i < AudioBlocks; i++) { - int64_t SampleStart; - int64_t FilePos; - unsigned int FrameSize; - int Flags; - - fscanf(CacheFile, "%lld %lld %u %d\r\n", &SampleStart, &FilePos, &FrameSize, &Flags); - SI.push_back(SampleInfo(SampleStart, FilePos, FrameSize, (Flags & 1) != 0)); - } - - fclose(CacheFile); - return true; -} - -bool FFAudioBase::SaveSampleInfoToFile(const char *AAudioCacheFile, const char *ASource, int AAudioTrack) { - char DefaultCacheFilename[1024]; - sprintf(DefaultCacheFilename, "%s.ffas%dcache", ASource, AAudioTrack); - if (!strcmp(AAudioCacheFile, "")) - AAudioCacheFile = DefaultCacheFilename; - - FILE *CacheFile = fopen(AAudioCacheFile, "wb"); - if (!CacheFile) - return false; - - fprintf(CacheFile, "%lld %u\r\n", VI.num_audio_samples, SI.size()); - for (size_t i = 0; i < SI.size(); i++) { - int Flags = SI[i].KeyFrame ? 1 : 0; - fprintf(CacheFile, "%lld %lld %u %d\r\n", SI[i].SampleStart, SI[i].FilePos, SI[i].FrameSize, Flags); - } - - fclose(CacheFile); - return true; -} \ No newline at end of file diff --git a/FFmpegSource/ffbase.cpp b/FFmpegSource/ffbase.cpp deleted file mode 100644 index fc4799fd1..000000000 --- a/FFmpegSource/ffbase.cpp +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -int FFBase::FrameFromDTS(int64_t ADTS) { - for (int i = 0; i < (int)Frames.size(); i++) - if (Frames[i].DTS == ADTS) - return i; - return -1; -} - -int FFBase::ClosestFrameFromDTS(int64_t ADTS) { - int Frame = 0; - int64_t BestDiff = 0xFFFFFFFFFFFFFFLL; // big number - for (int i = 0; i < (int)Frames.size(); i++) { - int64_t CurrentDiff = FFABS(Frames[i].DTS - ADTS); - if (CurrentDiff < BestDiff) { - BestDiff = CurrentDiff; - Frame = i; - } - } - return Frame; -} - -int FFBase::FindClosestKeyFrame(int AFrame) { - for (int i = AFrame; i > 0; i--) - if (Frames[i].KeyFrame) - return i; - return 0; -} - -bool FFBase::LoadFrameInfoFromFile(const char *AVideoCacheFile, const char *ASource, int AVideoTrack) { - char DefaultCacheFilename[1024]; - sprintf(DefaultCacheFilename, "%s.ffv%dcache", ASource, AVideoTrack); - if (!strcmp(AVideoCacheFile, "")) - AVideoCacheFile = DefaultCacheFilename; - - FILE *CacheFile = fopen(AVideoCacheFile, "r"); - if (!CacheFile) - return false; - - if (fscanf(CacheFile, "%d\r\n", &VI.num_frames) <= 0 || VI.num_frames <= 0) { - VI.num_frames = 0; - fclose(CacheFile); - return false; - } - - for (int i = 0; i < VI.num_frames; i++) { - int64_t DTSTemp; - int KFTemp; - fscanf(CacheFile, "%lld %d\r\n", &DTSTemp, &KFTemp); - Frames.push_back(FrameInfo(DTSTemp, KFTemp != 0)); - } - - fclose(CacheFile); - return true; -} - -bool FFBase::SaveFrameInfoToFile(const char *AVideoCacheFile, const char *ASource, int AVideoTrack) { - char DefaultCacheFilename[1024]; - sprintf(DefaultCacheFilename, "%s.ffv%dcache", ASource, AVideoTrack); - if (!strcmp(AVideoCacheFile, "")) - AVideoCacheFile = DefaultCacheFilename; - - FILE *CacheFile = fopen(AVideoCacheFile, "wb"); - if (!CacheFile) - return false; - - fprintf(CacheFile, "%d\r\n", VI.num_frames); - for (int i = 0; i < VI.num_frames; i++) - fprintf(CacheFile, "%lld %d\r\n", Frames[i].DTS, (int)(Frames[i].KeyFrame ? 1 : 0)); - - fclose(CacheFile); - return true; -} - -bool FFBase::SaveTimecodesToFile(const char *ATimecodeFile, int64_t ScaleD, int64_t ScaleN) { - if (!strcmp(ATimecodeFile, "")) - return true; - - FILE *TimecodeFile = fopen(ATimecodeFile, "wb"); - if (!TimecodeFile) - return false; - - std::set Timecodes; - for (int i = 0; i < VI.num_frames; i++) - Timecodes.insert(Frames[i].DTS); - - fprintf(TimecodeFile, "# timecode format v2\r\n"); - - for (std::set::iterator Cur=Timecodes.begin(); Cur!=Timecodes.end(); Cur++) - fprintf(TimecodeFile, "%f\r\n", (*Cur * ScaleD) / (double)ScaleN); - - fclose(TimecodeFile); - return true; -} - -bool FFBase::OpenAudioCache(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, IScriptEnvironment *Env) { - char DefaultCacheFilename[1024]; - sprintf(DefaultCacheFilename, "%s.ffa%dcache", ASource, AAudioTrack); - if (!strcmp(AAudioCacheFile, "")) - AAudioCacheFile = DefaultCacheFilename; - - // Is an empty file? - FILE *FCFile = fopen(AAudioCacheFile, "rb"); - int64_t CacheSize; - if (FCFile) { - _fseeki64(FCFile, 0, SEEK_END); - CacheSize = _ftelli64(FCFile); - _fseeki64(FCFile, 0, SEEK_SET); - if (CacheSize <= 0) { - fclose(FCFile); - FCFile = NULL; - return false; - } - } else { - return false; - } - - // Raw audio - VI.num_audio_samples = VI.AudioSamplesFromBytes(CacheSize); - AudioCacheType = acRaw; - RawAudioCache = FCFile; - FCFile = NULL; - return true; -} - -FILE *FFBase::NewRawCacheWriter(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, IScriptEnvironment *Env) { - char DefaultCacheFilename[1024]; - sprintf(DefaultCacheFilename, "%s.ffa%dcache", ASource, AAudioTrack); - if (!strcmp(AAudioCacheFile, "")) - AAudioCacheFile = DefaultCacheFilename; - - FILE *RCF = fopen(AAudioCacheFile, "wb"); - if (RCF == NULL) - Env->ThrowError("FFmpegSource: Failed to open '%s' for writing", AAudioCacheFile); - return RCF; -} - -void FFBase::CloseRawCacheWriter(FILE *ARawCache) { - fclose(ARawCache); -} - -void FFBase::InitPP(int AWidth, int AHeight, const char *APPString, int AQuality, int APixelFormat, IScriptEnvironment *Env) { - if (!strcmp(APPString, "")) - return; - - if (AQuality < 0 || AQuality > PP_QUALITY_MAX) - Env->ThrowError("FFmpegSource: Quality is out of range"); - - // Unsafe? - PPMode = pp_get_mode_by_name_and_quality(APPString, AQuality); - if (!PPMode) - Env->ThrowError("FFmpegSource: Invalid postprocesing settings"); - - int Flags = GetPPCPUFlags(Env); - - switch (APixelFormat) { - case PIX_FMT_YUV420P: Flags |= PP_FORMAT_420; break; - case PIX_FMT_YUV422P: Flags |= PP_FORMAT_422; break; - case PIX_FMT_YUV411P: Flags |= PP_FORMAT_411; break; - case PIX_FMT_YUV444P: Flags |= PP_FORMAT_444; break; - default: - Env->ThrowError("FFmpegSource: Input format is not supported for postprocessing"); - } - - PPContext = pp_get_context(VI.width, VI.height, Flags); - - if (avpicture_alloc(&PPPicture, APixelFormat, AWidth, AHeight) < 0) - Env->ThrowError("FFmpegSource: Failed to allocate picture"); -} - -void FFBase::SetOutputFormat(int ACurrentFormat, IScriptEnvironment *Env) { - int Loss; - int BestFormat = avcodec_find_best_pix_fmt((1 << PIX_FMT_YUVJ420P) | (1 << PIX_FMT_YUV420P) | (1 << PIX_FMT_YUYV422) | (1 << PIX_FMT_RGB32) | (1 << PIX_FMT_BGR24), ACurrentFormat, 1 /* Required to prevent pointless RGB32 => RGB24 conversion */, &Loss); - - switch (BestFormat) { - case PIX_FMT_YUVJ420P: // stupid yv12 distinctions, also inexplicably completely undeniably incompatible with all other supported output formats - case PIX_FMT_YUV420P: VI.pixel_type = VideoInfo::CS_I420; break; - case PIX_FMT_YUYV422: VI.pixel_type = VideoInfo::CS_YUY2; break; - case PIX_FMT_RGB32: VI.pixel_type = VideoInfo::CS_BGR32; break; - case PIX_FMT_BGR24: VI.pixel_type = VideoInfo::CS_BGR24; break; - default: - Env->ThrowError("FFmpegSource: No suitable output format found"); - } - - if (BestFormat != ACurrentFormat) { - ConvertToFormat = BestFormat; - SWS = sws_getContext(VI.width, VI.height, ACurrentFormat, VI.width, VI.height, ConvertToFormat, GetSWSCPUFlags(Env) | SWS_BICUBIC, NULL, NULL, NULL); - } - - if (BestFormat == PIX_FMT_YUVJ420P || BestFormat == PIX_FMT_YUV420P) { - VI.height -= VI.height & 1; - VI.width -= VI.width & 1; - } - - if (BestFormat == PIX_FMT_YUYV422) { - VI.width -= VI.width & 1; - } -} - -PVideoFrame FFBase::OutputFrame(AVFrame *AFrame, IScriptEnvironment *Env) { - AVPicture *SrcPicture = (AVPicture *)AFrame; - - if (PPContext) { - pp_postprocess(const_cast(AFrame->data), AFrame->linesize, PPPicture.data, PPPicture.linesize, VI.width, VI.height, AFrame->qscale_table, AFrame->qstride, PPMode, PPContext, AFrame->pict_type | (AFrame->qscale_type ? PP_PICT_TYPE_QP2 : 0)); - SrcPicture = &PPPicture; - } - - PVideoFrame Dst = Env->NewVideoFrame(VI); - - if (ConvertToFormat != PIX_FMT_NONE && VI.pixel_type == VideoInfo::CS_I420) { - uint8_t *DstData[3] = {Dst->GetWritePtr(PLANAR_Y), Dst->GetWritePtr(PLANAR_U), Dst->GetWritePtr(PLANAR_V)}; - int DstStride[3] = {Dst->GetPitch(PLANAR_Y), Dst->GetPitch(PLANAR_U), Dst->GetPitch(PLANAR_V)}; - sws_scale(SWS, SrcPicture->data, SrcPicture->linesize, 0, VI.height, DstData, DstStride); - } else if (ConvertToFormat != PIX_FMT_NONE) { - if (VI.IsRGB()) { - uint8_t *DstData[1] = {Dst->GetWritePtr() + Dst->GetPitch() * (Dst->GetHeight() - 1)}; - int DstStride[1] = {-Dst->GetPitch()}; - sws_scale(SWS, SrcPicture->data, SrcPicture->linesize, 0, VI.height, DstData, DstStride); - } else { - uint8_t *DstData[1] = {Dst->GetWritePtr()}; - int DstStride[1] = {Dst->GetPitch()}; - sws_scale(SWS, SrcPicture->data, SrcPicture->linesize, 0, VI.height, DstData, DstStride); - } - } else if (VI.pixel_type == VideoInfo::CS_I420) { - Env->BitBlt(Dst->GetWritePtr(PLANAR_Y), Dst->GetPitch(PLANAR_Y), SrcPicture->data[0], SrcPicture->linesize[0], Dst->GetRowSize(PLANAR_Y), Dst->GetHeight(PLANAR_Y)); - Env->BitBlt(Dst->GetWritePtr(PLANAR_U), Dst->GetPitch(PLANAR_U), SrcPicture->data[1], SrcPicture->linesize[1], Dst->GetRowSize(PLANAR_U), Dst->GetHeight(PLANAR_U)); - Env->BitBlt(Dst->GetWritePtr(PLANAR_V), Dst->GetPitch(PLANAR_V), SrcPicture->data[2], SrcPicture->linesize[2], Dst->GetRowSize(PLANAR_V), Dst->GetHeight(PLANAR_V)); - } else { - if (VI.IsRGB()) - Env->BitBlt(Dst->GetWritePtr() + Dst->GetPitch() * (Dst->GetHeight() - 1), -Dst->GetPitch(), SrcPicture->data[0], SrcPicture->linesize[0], Dst->GetRowSize(), Dst->GetHeight()); - else - Env->BitBlt(Dst->GetWritePtr(), Dst->GetPitch(), SrcPicture->data[0], SrcPicture->linesize[0], Dst->GetRowSize(), Dst->GetHeight()); - } - - return Dst; -} - -void FFBase::GetAudio(void* Buf, __int64 Start, __int64 Count, IScriptEnvironment* Env) { - if (AudioCacheType == acRaw) { - _fseeki64(RawAudioCache, VI.BytesFromAudioSamples(Start), SEEK_SET); - fread(Buf, 1, static_cast(VI.BytesFromAudioSamples(Count)), RawAudioCache); - } else { - Env->ThrowError("FFmpegSource: Audio requested but none available"); - } -} - -FFBase::FFBase() { - memset(&VI, 0, sizeof(VI)); - AudioCacheType = acNone; - RawAudioCache = NULL; - PPContext = NULL; - PPMode = NULL; - SWS = NULL; - LastFrameNum = -1; - DecodingBuffer = new uint8_t[AVCODEC_MAX_AUDIO_FRAME_SIZE]; - ConvertToFormat = PIX_FMT_NONE; - memset(&PPPicture, 0, sizeof(PPPicture)); - DecodeFrame = avcodec_alloc_frame(); -} - -FFBase::~FFBase() { - delete [] DecodingBuffer; - if (RawAudioCache) - fclose(RawAudioCache); - if (SWS) - sws_freeContext(SWS); - if (PPMode) - pp_free_mode(PPMode); - if (PPContext) - pp_free_context(PPContext); - avpicture_free(&PPPicture); - av_free(DecodeFrame); -} diff --git a/FFmpegSource/ffmatroskaaudiosource.cpp b/FFmpegSource/ffmatroskaaudiosource.cpp deleted file mode 100644 index aaead6a2b..000000000 --- a/FFmpegSource/ffmatroskaaudiosource.cpp +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -int FFMatroskaAudioSource::GetTrackIndex(int Index, unsigned char ATrackType, IScriptEnvironment *Env) { - if (Index == -1) - for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) - if (mkv_GetTrackInfo(MF, i)->Type == ATrackType) { - Index = i; - break; - } - - if (Index == -1) - Env->ThrowError("FFmpegSource: No %s track found", (ATrackType & TT_VIDEO) ? "video" : "audio"); - if (Index <= -2) - return -2; - - if (Index >= (int)mkv_GetNumTracks(MF)) - Env->ThrowError("FFmpegSource: Invalid %s track number", (ATrackType & TT_VIDEO) ? "video" : "audio"); - - TrackInfo *TI = mkv_GetTrackInfo(MF, Index); - - if (TI->Type != ATrackType) - Env->ThrowError("FFmpegSource: Selected track is not %s", (ATrackType & TT_VIDEO) ? "video" : "audio"); - - return Index; -} - -FFMatroskaAudioSource::FFMatroskaAudioSource(const char *ASource, int AAudioTrack, const char *AAudioCache, IScriptEnvironment *Env) { - int AudioTrack; - AudioCodecContext = NULL; - AVCodec *AudioCodec = NULL; - TrackInfo *VideoTI = NULL; - BufferSize = 0; - Buffer = NULL; - AudioCS = NULL; - - memset(&ST,0,sizeof(ST)); - ST.base.read = (int (__cdecl *)(InputStream *,ulonglong,void *,int))StdIoRead; - ST.base.scan = (longlong (__cdecl *)(InputStream *,ulonglong,unsigned int))StdIoScan; - ST.base.getcachesize = (unsigned int (__cdecl *)(InputStream *))StdIoGetCacheSize; - ST.base.geterror = (const char *(__cdecl *)(InputStream *))StdIoGetLastError; - ST.base.memalloc = (void *(__cdecl *)(InputStream *,size_t))StdIoMalloc; - ST.base.memrealloc = (void *(__cdecl *)(InputStream *,void *,size_t))StdIoRealloc; - ST.base.memfree = (void (__cdecl *)(InputStream *,void *)) StdIoFree; - ST.base.progress = (int (__cdecl *)(InputStream *,ulonglong,ulonglong))StdIoProgress; - - ST.fp = fopen(ASource, "rb"); - if (ST.fp == NULL) - Env->ThrowError("FFmpegSource: Can't open '%s': %s", ASource, strerror(errno)); - - setvbuf(ST.fp, NULL, _IOFBF, CACHESIZE); - - MF = mkv_OpenEx(&ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage)); - if (MF == NULL) { - fclose(ST.fp); - Env->ThrowError("FFmpegSource: Can't parse Matroska file: %s", ErrorMessage); - } - - AudioTrack = GetTrackIndex(AAudioTrack, TT_AUDIO, Env); - mkv_SetTrackMask(MF, ~(1 << AudioTrack)); - - TrackInfo *AudioTI = mkv_GetTrackInfo(MF, AudioTrack); - - if (AudioTI->CompEnabled) { - AudioCS = cs_Create(MF, AudioTrack, ErrorMessage, sizeof(ErrorMessage)); - if (AudioCS == NULL) - Env->ThrowError("FFmpegSource: Can't create decompressor: %s", ErrorMessage); - } - - AudioCodecContext = avcodec_alloc_context(); - AudioCodecContext->extradata = (uint8_t *)AudioTI->CodecPrivate; - AudioCodecContext->extradata_size = AudioTI->CodecPrivateSize; - - AudioCodec = avcodec_find_decoder(MatroskaToFFCodecID(AudioTI)); - if (AudioCodec == NULL) - Env->ThrowError("FFmpegSource: Audio codec not found"); - - if (avcodec_open(AudioCodecContext, AudioCodec) < 0) - Env->ThrowError("FFmpegSource: Could not open audio codec"); - - // Fix for ac3 and other codecs where decoding a block of audio is required to get information about it - if (AudioCodecContext->channels == 0 || AudioCodecContext->sample_rate == 0) { - uint64_t StartTime, EndTime, FilePos; - unsigned int Track, FrameFlags, FrameSize; - mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags); - - int Size = ReadFrame(FilePos, FrameSize, AudioCS, Env); - uint8_t *Data = Buffer; - - while (Size > 0) { - int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; - int Ret = avcodec_decode_audio2(AudioCodecContext, (int16_t *)DecodingBuffer, &TempOutputBufSize, Data, Size); - if (Ret < 0) - Env->ThrowError("FFmpegSource: Audio decoding error"); - - Size -= Ret; - Data += Ret; - } - - mkv_Seek(MF, 0, MKVF_SEEK_TO_PREV_KEYFRAME); - avcodec_flush_buffers(AudioCodecContext); - } - - VI.nchannels = AudioCodecContext->channels; - VI.audio_samples_per_second = AudioCodecContext->sample_rate; - - switch (AudioCodecContext->sample_fmt) { - case SAMPLE_FMT_U8: VI.sample_type = SAMPLE_INT8; break; - case SAMPLE_FMT_S16: VI.sample_type = SAMPLE_INT16; break; - case SAMPLE_FMT_S24: VI.sample_type = SAMPLE_INT24; break; - case SAMPLE_FMT_S32: VI.sample_type = SAMPLE_INT32; break; - case SAMPLE_FMT_FLT: VI.sample_type = SAMPLE_FLOAT; break; - default: - Env->ThrowError("FFmpegSource: Unsupported/unknown sample format"); - } - - //load audio cache - bool ACacheIsValid = LoadSampleInfoFromFile(AAudioCache, ASource, AudioTrack); - - // Needs to be indexed? - if (!ACacheIsValid) { - uint64_t StartTime, EndTime, FilePos; - unsigned int Track, FrameFlags, FrameSize; - - while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) { - SI.push_back(SampleInfo(VI.num_audio_samples, FilePos, FrameSize, (FrameFlags & FRAME_KF) != 0)); - - if (AudioCodecContext->frame_size > 0) { - VI.num_audio_samples += AudioCodecContext->frame_size; - } else { - int Size = ReadFrame(FilePos, FrameSize, AudioCS, Env); - uint8_t *Data = Buffer; - - while (Size > 0) { - int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; - int Ret = avcodec_decode_audio2(AudioCodecContext, (int16_t *)DecodingBuffer, &TempOutputBufSize, Data, Size); - if (Ret < 0) - Env->ThrowError("FFmpegSource: Audio decoding error"); - - if (Ret > 0) { - int DecodedSamples = (int)VI.AudioSamplesFromBytes(TempOutputBufSize); - Size -= Ret; - Data += Ret; - VI.num_audio_samples += DecodedSamples; - } - } - } - } - - mkv_Seek(MF, 0, MKVF_SEEK_TO_PREV_KEYFRAME); - avcodec_flush_buffers(AudioCodecContext); - - if (!SaveSampleInfoToFile(AAudioCache, ASource, AudioTrack)) - Env->ThrowError("FFmpegSource: Failed to save audio cache index"); - } - - if (VI.num_audio_samples == 0) - Env->ThrowError("FFmpegSource: Audio track contains no samples"); -} - -FFMatroskaAudioSource::~FFMatroskaAudioSource() { - free(Buffer); - mkv_Close(MF); - fclose(ST.fp); - if (AudioCodecContext) - avcodec_close(AudioCodecContext); - av_free(AudioCodecContext); -} - -int FFMatroskaAudioSource::ReadFrame(uint64_t AFilePos, unsigned int AFrameSize, CompressedStream *ACS, IScriptEnvironment *Env) { - if (ACS) { - char CSBuffer[4096]; - - unsigned int DecompressedFrameSize = 0; - - cs_NextFrame(ACS, AFilePos, AFrameSize); - - for (;;) { - int ReadBytes = cs_ReadData(ACS, CSBuffer, sizeof(CSBuffer)); - if (ReadBytes < 0) - Env->ThrowError("FFmpegSource: Error decompressing data: %s", cs_GetLastError(ACS)); - if (ReadBytes == 0) { - return DecompressedFrameSize; - } - - if (BufferSize < DecompressedFrameSize + ReadBytes) { - BufferSize = AFrameSize; - Buffer = (uint8_t *)realloc(Buffer, BufferSize); - if (Buffer == NULL) - Env->ThrowError("FFmpegSource: Out of memory"); - } - - memcpy(Buffer + DecompressedFrameSize, CSBuffer, ReadBytes); - DecompressedFrameSize += ReadBytes; - } - } else { - if (_fseeki64(ST.fp, AFilePos, SEEK_SET)) - Env->ThrowError("FFmpegSource: fseek(): %s", strerror(errno)); - - if (BufferSize < AFrameSize) { - BufferSize = AFrameSize; - Buffer = (uint8_t *)realloc(Buffer, BufferSize); - if (Buffer == NULL) - Env->ThrowError("FFmpegSource: Out of memory"); - } - - size_t ReadBytes = fread(Buffer, 1, AFrameSize, ST.fp); - if (ReadBytes != AFrameSize) { - if (ReadBytes == 0) { - if (feof(ST.fp)) - Env->ThrowError("FFmpegSource: Unexpected EOF while reading frame"); - else - Env->ThrowError("FFmpegSource: Error reading frame: %s", strerror(errno)); - } else - Env->ThrowError("FFmpegSource: Short read while reading frame"); - Env->ThrowError("FFmpegSource: Unknown read error"); - } - - return AFrameSize; - } - - return 0; -} - -void __stdcall FFMatroskaAudioSource::GetAudio(void* Buf, __int64 Start, __int64 Count, IScriptEnvironment *Env) { - size_t CurrentAudioBlock = FFMAX((int64_t)FindClosestAudioKeyFrame(Start) - 10, (int64_t)0); - avcodec_flush_buffers(AudioCodecContext); - - memset(Buf, 0, VI.BytesFromAudioSamples(Count)); - - uint8_t *DstBuf = (uint8_t *)Buf; - int64_t RemainingSamples = Count; - int64_t DecodeCount; - - do { - int64_t DecodeStart = SI[CurrentAudioBlock].SampleStart; - int Ret = DecodeNextAudioBlock(DecodingBuffer, &DecodeCount, SI[CurrentAudioBlock].FilePos, SI[CurrentAudioBlock].FrameSize, Env); - if (Ret < 0) - Env->ThrowError("Bleh, bad audio decoding"); - CurrentAudioBlock++; - - int64_t OffsetBytes = VI.BytesFromAudioSamples(FFMAX(0, Start - DecodeStart)); - int64_t CopyBytes = FFMAX(0, VI.BytesFromAudioSamples(FFMIN(RemainingSamples, DecodeCount - FFMAX(0, Start - DecodeStart)))); - - memcpy(DstBuf, DecodingBuffer + OffsetBytes, CopyBytes); - DstBuf += CopyBytes; - - RemainingSamples -= VI.AudioSamplesFromBytes(CopyBytes); - - } while (RemainingSamples > 0 && CurrentAudioBlock < SI.size()); -} - -int FFMatroskaAudioSource::DecodeNextAudioBlock(uint8_t *ABuf, int64_t *ACount, uint64_t AFilePos, unsigned int AFrameSize, IScriptEnvironment *Env) { - int Ret = -1; - *ACount = 0; - - int FrameSize = ReadFrame(AFilePos, AFrameSize, AudioCS, Env); - uint8_t *Data = Buffer; - int Size = FrameSize; - - while (Size > 0) { - int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; - Ret = avcodec_decode_audio2(AudioCodecContext, (int16_t *)ABuf, &TempOutputBufSize, Data, Size); - - if (Ret < 0) // throw error or something? - goto Done; - - if (Ret > 0) { - Size -= Ret; - Data += Ret; - ABuf += TempOutputBufSize; - *ACount += VI.AudioSamplesFromBytes(TempOutputBufSize); - } - } - -Done: - return Ret; -} diff --git a/FFmpegSource/ffmatroskasource.cpp b/FFmpegSource/ffmatroskasource.cpp deleted file mode 100644 index 6bd09b9a2..000000000 --- a/FFmpegSource/ffmatroskasource.cpp +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -int FFMatroskaSource::GetTrackIndex(int Index, unsigned char ATrackType, IScriptEnvironment *Env) { - if (Index == -1) - for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) - if (mkv_GetTrackInfo(MF, i)->Type == ATrackType) { - Index = i; - break; - } - - if (Index == -1) - Env->ThrowError("FFmpegSource: No %s track found", (ATrackType & TT_VIDEO) ? "video" : "audio"); - if (Index <= -2) - return -2; - - if (Index >= (int)mkv_GetNumTracks(MF)) - Env->ThrowError("FFmpegSource: Invalid %s track number", (ATrackType & TT_VIDEO) ? "video" : "audio"); - - TrackInfo *TI = mkv_GetTrackInfo(MF, Index); - - if (TI->Type != ATrackType) - Env->ThrowError("FFmpegSource: Selected track is not %s", (ATrackType & TT_VIDEO) ? "video" : "audio"); - - return Index; -} - -FFMatroskaSource::FFMatroskaSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, - bool AVCache, const char *AVideoCache, const char *AAudioCache, const char *APPString, - int AQuality, int AThreads, IScriptEnvironment* Env) { - - CurrentFrame = 0; - int VideoTrack; - int AudioTrack; - unsigned int TrackMask = ~0; - AVCodecContext *AudioCodecContext = NULL; - AVCodec *AudioCodec = NULL; - VideoCodecContext = NULL; - AVCodec *VideoCodec = NULL; - TrackInfo *VideoTI = NULL; - BufferSize = 0; - Buffer = NULL; - VideoCS = NULL; - AudioCS = NULL; - - memset(&ST,0,sizeof(ST)); - ST.base.read = (int (__cdecl *)(InputStream *,ulonglong,void *,int))StdIoRead; - ST.base.scan = (longlong (__cdecl *)(InputStream *,ulonglong,unsigned int))StdIoScan; - ST.base.getcachesize = (unsigned int (__cdecl *)(InputStream *))StdIoGetCacheSize; - ST.base.geterror = (const char *(__cdecl *)(InputStream *))StdIoGetLastError; - ST.base.memalloc = (void *(__cdecl *)(InputStream *,size_t))StdIoMalloc; - ST.base.memrealloc = (void *(__cdecl *)(InputStream *,void *,size_t))StdIoRealloc; - ST.base.memfree = (void (__cdecl *)(InputStream *,void *)) StdIoFree; - ST.base.progress = (int (__cdecl *)(InputStream *,ulonglong,ulonglong))StdIoProgress; - - ST.fp = fopen(ASource, "rb"); - if (ST.fp == NULL) - Env->ThrowError("FFmpegSource: Can't open '%s': %s", ASource, strerror(errno)); - - setvbuf(ST.fp, NULL, _IOFBF, CACHESIZE); - - MF = mkv_OpenEx(&ST.base, 0, 0, ErrorMessage, sizeof(ErrorMessage)); - if (MF == NULL) { - fclose(ST.fp); - Env->ThrowError("FFmpegSource: Can't parse Matroska file: %s", ErrorMessage); - } - - VideoTrack = GetTrackIndex(AVideoTrack, TT_VIDEO, Env); - AudioTrack = GetTrackIndex(AAudioTrack, TT_AUDIO, Env); - - bool VCacheIsValid = true; - bool ACacheIsValid = true; - - if (VideoTrack >= 0) { - VCacheIsValid = LoadFrameInfoFromFile(AVideoCache, ASource, VideoTrack); - - VideoTI = mkv_GetTrackInfo(MF, VideoTrack); - - if (VideoTI->CompEnabled) { - VideoCS = cs_Create(MF, VideoTrack, ErrorMessage, sizeof(ErrorMessage)); - if (VideoCS == NULL) - Env->ThrowError("FFmpegSource: Can't create decompressor: %s", ErrorMessage); - } - - VideoCodecContext = avcodec_alloc_context(); - VideoCodecContext->extradata = (uint8_t *)VideoTI->CodecPrivate; - VideoCodecContext->extradata_size = VideoTI->CodecPrivateSize; - VideoCodecContext->thread_count = AThreads; - - VideoCodec = avcodec_find_decoder(MatroskaToFFCodecID(VideoTI)); - if (VideoCodec == NULL) - Env->ThrowError("FFmpegSource: Video codec not found"); - - if (avcodec_open(VideoCodecContext, VideoCodec) < 0) - Env->ThrowError("FFmpegSource: Could not open video codec"); - - // Fix for mpeg2 and other formats where decoding a frame is necessary to get information about the stream - if (VideoCodecContext->pix_fmt == PIX_FMT_NONE || VideoCodecContext->width == 0 || VideoCodecContext->height == 0) { - mkv_SetTrackMask(MF, ~(1 << VideoTrack)); - int64_t Dummy; - DecodeNextFrame(DecodeFrame, &Dummy, Env); - mkv_Seek(MF, 0, MKVF_SEEK_TO_PREV_KEYFRAME); - } - - VI.image_type = VideoInfo::IT_TFF; - VI.width = VideoCodecContext->width; - VI.height = VideoCodecContext->height;; - VI.fps_denominator = 1; - VI.fps_numerator = 30; - - if (VI.width <= 0 || VI.height <= 0) - Env->ThrowError("FFmpegSource: Codec returned zero size video"); - - SetOutputFormat(VideoCodecContext->pix_fmt, Env); - InitPP(VI.width, VI.height, APPString, AQuality, VideoCodecContext->pix_fmt, Env); - - if (!VCacheIsValid) - TrackMask &= ~(1 << VideoTrack); - } - - if (AudioTrack >= 0) { - TrackInfo *AudioTI = mkv_GetTrackInfo(MF, AudioTrack); - - if (AudioTI->CompEnabled) { - AudioCS = cs_Create(MF, AudioTrack, ErrorMessage, sizeof(ErrorMessage)); - if (AudioCS == NULL) - Env->ThrowError("FFmpegSource: Can't create decompressor: %s", ErrorMessage); - } - - AudioCodecContext = avcodec_alloc_context(); - AudioCodecContext->extradata = (uint8_t *)AudioTI->CodecPrivate; - AudioCodecContext->extradata_size = AudioTI->CodecPrivateSize; - - AudioCodec = avcodec_find_decoder(MatroskaToFFCodecID(AudioTI)); - if (AudioCodec == NULL) - Env->ThrowError("FFmpegSource: Audio codec not found"); - - if (avcodec_open(AudioCodecContext, AudioCodec) < 0) - Env->ThrowError("FFmpegSource: Could not open audio codec"); - - // Fix for ac3 and other codecs where decoding a block of audio is required to get information about it - if (AudioCodecContext->channels == 0 || AudioCodecContext->sample_rate == 0) { - mkv_SetTrackMask(MF, ~(1 << AudioTrack)); - uint64_t StartTime, EndTime, FilePos; - unsigned int Track, FrameFlags, FrameSize; - mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags); - - int Size = ReadFrame(FilePos, FrameSize, AudioCS, Env); - uint8_t *Data = Buffer; - - while (Size > 0) { - int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; - int Ret = avcodec_decode_audio2(AudioCodecContext, (int16_t *)DecodingBuffer, &TempOutputBufSize, Data, Size); - if (Ret < 0) - Env->ThrowError("FFmpegSource: Audio decoding error"); - - Size -= Ret; - Data += Ret; - } - - mkv_Seek(MF, 0, MKVF_SEEK_TO_PREV_KEYFRAME); - } - - VI.nchannels = AudioCodecContext->channels; - VI.audio_samples_per_second = AudioCodecContext->sample_rate; - - switch (AudioCodecContext->sample_fmt) { - case SAMPLE_FMT_U8: VI.sample_type = SAMPLE_INT8; break; - case SAMPLE_FMT_S16: VI.sample_type = SAMPLE_INT16; break; - case SAMPLE_FMT_S24: VI.sample_type = SAMPLE_INT24; break; - case SAMPLE_FMT_S32: VI.sample_type = SAMPLE_INT32; break; - case SAMPLE_FMT_FLT: VI.sample_type = SAMPLE_FLOAT; break; - default: - Env->ThrowError("FFmpegSource: Unsupported/unknown sample format"); - } - - ACacheIsValid = OpenAudioCache(AAudioCache, ASource, AudioTrack, Env); - if (!ACacheIsValid) - TrackMask &= ~(1 << AudioTrack); - } - - mkv_SetTrackMask(MF, TrackMask); - - // Needs to be indexed? - if (!ACacheIsValid || !VCacheIsValid) { - FILE *RawCache = NULL; - if (!ACacheIsValid) - AudioCacheType = acRaw; - - switch (AudioCacheType) { - case acRaw: RawCache = NewRawCacheWriter(AAudioCache, ASource, AudioTrack, Env); break; - } - - uint64_t StartTime, EndTime, FilePos; - unsigned int Track, FrameFlags, FrameSize; - - while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) - if (Track == VideoTrack && !VCacheIsValid) { - Frames.push_back(FrameInfo(StartTime, (FrameFlags & FRAME_KF) != 0)); - VI.num_frames++; - } else if (Track == AudioTrack && !ACacheIsValid) { - int Size = ReadFrame(FilePos, FrameSize, AudioCS, Env); - uint8_t *Data = Buffer; - - while (Size > 0) { - int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; - int Ret = avcodec_decode_audio2(AudioCodecContext, (int16_t *)DecodingBuffer, &TempOutputBufSize, Data, Size); - if (Ret < 0) - Env->ThrowError("FFmpegSource: Audio decoding error"); - - int DecodedSamples = (int)VI.AudioSamplesFromBytes(TempOutputBufSize); - - Size -= Ret; - Data += Ret; - VI.num_audio_samples += DecodedSamples; - - if (AudioCacheType == acRaw) { - fwrite(DecodingBuffer, 1, TempOutputBufSize, RawCache); - } - } - } - - if (!ACacheIsValid) { - switch (AudioCacheType) { - case acRaw: CloseRawCacheWriter(RawCache); break; - } - - ACacheIsValid = OpenAudioCache(AAudioCache, ASource, AudioTrack, Env); - if (!ACacheIsValid) - Env->ThrowError("FFmpegSource: Failed to open newly created audio cache for reading"); - } - - if (VideoTrack >= 0 && VI.num_frames == 0) - Env->ThrowError("FFmpegSource: Video track contains no frames"); - - if (AudioTrack >= 0 && VI.num_audio_samples == 0) - Env->ThrowError("FFmpegSource: Audio track contains no samples"); - - if (VideoTrack >= 0) - mkv_Seek(MF, Frames.front().DTS, MKVF_SEEK_TO_PREV_KEYFRAME); - - if (AVCache && !VCacheIsValid) - if (!SaveFrameInfoToFile(AVideoCache, ASource, VideoTrack)) - Env->ThrowError("FFmpegSource: Failed to write video cache info"); - } - - if (AudioTrack >= 0) { - avcodec_close(AudioCodecContext); - av_free(AudioCodecContext); - } - - if (VideoTrack >= 0) { - mkv_SetTrackMask(MF, ~(1 << VideoTrack)); - - // Calculate the average framerate - if (Frames.size() >= 2) { - double DTSDiff = (double)(Frames.back().DTS - Frames.front().DTS); - VI.fps_denominator = (unsigned int)(DTSDiff * mkv_TruncFloat(VideoTI->TimecodeScale) / (double)1000 / (double)(VI.num_frames - 1) + 0.5); - VI.fps_numerator = 1000000; - } - - if (!SaveTimecodesToFile(ATimecodes, mkv_TruncFloat(VideoTI->TimecodeScale), 1000000)) - Env->ThrowError("FFmpegSource: Failed to write timecodes"); - - // Set AR variables - int ffsar_num = VideoTI->AV.Video.DisplayWidth * VideoTI->AV.Video.PixelHeight; - int ffsar_den = VideoTI->AV.Video.DisplayHeight * VideoTI->AV.Video.PixelWidth; - Env->SetVar("FFSAR_NUM", ffsar_num); - Env->SetVar("FFSAR_DEN", ffsar_den); - Env->SetVar("FFSAR", ffsar_num / (double)ffsar_den); - - // Set crop variables - Env->SetVar("FFCROP_LEFT", (int)VideoTI->AV.Video.CropL); - Env->SetVar("FFCROP_RIGHT", (int)VideoTI->AV.Video.CropR); - Env->SetVar("FFCROP_TOP", (int)VideoTI->AV.Video.CropT); - Env->SetVar("FFCROP_BOTTOM", (int)VideoTI->AV.Video.CropB); - } -} - -FFMatroskaSource::~FFMatroskaSource() { - free(Buffer); - mkv_Close(MF); - fclose(ST.fp); - if (VideoCodecContext) - avcodec_close(VideoCodecContext); - av_free(VideoCodecContext); -} - -int FFMatroskaSource::ReadFrame(uint64_t AFilePos, unsigned int AFrameSize, CompressedStream *ACS, IScriptEnvironment *Env) { - if (ACS) { - char CSBuffer[4096]; - - unsigned int DecompressedFrameSize = 0; - - cs_NextFrame(ACS, AFilePos, AFrameSize); - - for (;;) { - int ReadBytes = cs_ReadData(ACS, CSBuffer, sizeof(CSBuffer)); - if (ReadBytes < 0) - Env->ThrowError("FFmpegSource: Error decompressing data: %s", cs_GetLastError(ACS)); - if (ReadBytes == 0) { - return DecompressedFrameSize; - } - - if (BufferSize < DecompressedFrameSize + ReadBytes) { - BufferSize = AFrameSize; - Buffer = (uint8_t *)realloc(Buffer, BufferSize); - if (Buffer == NULL) - Env->ThrowError("FFmpegSource: Out of memory"); - } - - memcpy(Buffer + DecompressedFrameSize, CSBuffer, ReadBytes); - DecompressedFrameSize += ReadBytes; - } - } else { - if (_fseeki64(ST.fp, AFilePos, SEEK_SET)) - Env->ThrowError("FFmpegSource: fseek(): %s", strerror(errno)); - - if (BufferSize < AFrameSize) { - BufferSize = AFrameSize; - Buffer = (uint8_t *)realloc(Buffer, BufferSize); - if (Buffer == NULL) - Env->ThrowError("FFmpegSource: Out of memory"); - } - - size_t ReadBytes = fread(Buffer, 1, AFrameSize, ST.fp); - if (ReadBytes != AFrameSize) { - if (ReadBytes == 0) { - if (feof(ST.fp)) - Env->ThrowError("FFmpegSource: Unexpected EOF while reading frame"); - else - Env->ThrowError("FFmpegSource: Error reading frame: %s", strerror(errno)); - } else - Env->ThrowError("FFmpegSource: Short read while reading frame"); - Env->ThrowError("FFmpegSource: Unknown read error"); - } - - return AFrameSize; - } - - return 0; -} - -int FFMatroskaSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, IScriptEnvironment* Env) { - int FrameFinished = 0; - int Ret = -1; - *AFirstStartTime = -1; - - uint64_t StartTime, EndTime, FilePos; - unsigned int Track, FrameFlags, FrameSize; - - while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) { - if (*AFirstStartTime < 0) - *AFirstStartTime = StartTime; - FrameSize = ReadFrame(FilePos, FrameSize, VideoCS, Env); - Ret = avcodec_decode_video(VideoCodecContext, AFrame, &FrameFinished, Buffer, FrameSize); - - if (FrameFinished) - goto Done; - } - - // Flush the last frames - if (VideoCodecContext->has_b_frames) - Ret = avcodec_decode_video(VideoCodecContext, AFrame, &FrameFinished, NULL, 0); - - if (!FrameFinished) - goto Error; - -Error: -Done: - return Ret; -} - -PVideoFrame FFMatroskaSource::GetFrame(int n, IScriptEnvironment* Env) { - if (LastFrameNum == n) - return LastFrame; - - bool HasSeeked = false; - - if (n < CurrentFrame || FindClosestKeyFrame(n) > CurrentFrame) { - mkv_Seek(MF, Frames[n].DTS, MKVF_SEEK_TO_PREV_KEYFRAME); - avcodec_flush_buffers(VideoCodecContext); - HasSeeked = true; - } - - do { - int64_t StartTime; - int Ret = DecodeNextFrame(DecodeFrame, &StartTime, Env); - - if (HasSeeked) { - HasSeeked = false; - - if (StartTime < 0 || (CurrentFrame = FrameFromDTS(StartTime)) < 0) - Env->ThrowError("FFmpegSource: Frame accurate seeking is not possible in this file"); - } - - CurrentFrame++; - } while (CurrentFrame <= n); - - LastFrame = OutputFrame(DecodeFrame, Env); - LastFrameNum = n; - return LastFrame; -} diff --git a/FFmpegSource/ffmpegaudiosource.cpp b/FFmpegSource/ffmpegaudiosource.cpp deleted file mode 100644 index 5e600cbfa..000000000 --- a/FFmpegSource/ffmpegaudiosource.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -int FFmpegAudioSource::GetTrackIndex(int Index, CodecType ATrackType, IScriptEnvironment *Env) { - if (Index == -1) - for (unsigned int i = 0; i < FormatContext->nb_streams; i++) - if (FormatContext->streams[i]->codec->codec_type == ATrackType) { - Index = i; - break; - } - - if (Index == -1) - Env->ThrowError("FFmpegSource: No %s track found", (ATrackType == CODEC_TYPE_VIDEO) ? "video" : "audio"); - if (Index <= -2) - return -2; - - if (Index >= (int)FormatContext->nb_streams) - Env->ThrowError("FFmpegSource: Invalid %s track number", (ATrackType == CODEC_TYPE_VIDEO) ? "video" : "audio"); - - if (FormatContext->streams[Index]->codec->codec_type != ATrackType) - Env->ThrowError("FFmpegSource: Selected track is not %s", (ATrackType == CODEC_TYPE_VIDEO) ? "video" : "audio"); - - return Index; -} - -bool FFmpegAudioSource::LoadSampleInfoFromFile(const char *AAudioCacheFile, const char *AAudioCacheFile2, const char *ASource, int AAudioTrack) { - if (!FFAudioBase::LoadSampleInfoFromFile(AAudioCacheFile, ASource, AAudioTrack)) - return false; - - char DefaultCacheFilename[1024]; - sprintf(DefaultCacheFilename, "%s.ffasd%dcache", ASource, AAudioTrack); - if (!strcmp(AAudioCacheFile2, "")) - AAudioCacheFile2 = DefaultCacheFilename; - - RawCache = fopen(AAudioCacheFile2, "rb"); - if (!RawCache) - return false; - - return true; -} - -FFmpegAudioSource::FFmpegAudioSource(const char *ASource, int AAudioTrack, const char *AAudioCache, const char *AAudioCache2, IScriptEnvironment *Env) { - BufferSize = 0; - Buffer = NULL; - RawCache = NULL; - FormatContext = NULL; - AudioCodecContext = NULL; - AVCodec *AudioCodec = NULL; - - if (av_open_input_file(&FormatContext, ASource, NULL, 0, NULL) != 0) - Env->ThrowError("FFmpegSource: Couldn't open '%s'", ASource); - - if (av_find_stream_info(FormatContext) < 0) - Env->ThrowError("FFmpegSource: Couldn't find stream information"); - - AudioTrack = GetTrackIndex(AAudioTrack, CODEC_TYPE_AUDIO, Env); - - AudioCodecContext = FormatContext->streams[AudioTrack]->codec; - - AudioCodec = avcodec_find_decoder(AudioCodecContext->codec_id); - if (AudioCodec == NULL) - Env->ThrowError("FFmpegSource: Audio codec not found"); - - if (avcodec_open(AudioCodecContext, AudioCodec) < 0) - Env->ThrowError("FFmpegSource: Could not open audio codec"); - - VI.nchannels = AudioCodecContext->channels; - VI.audio_samples_per_second = AudioCodecContext->sample_rate; - - switch (AudioCodecContext->sample_fmt) { - case SAMPLE_FMT_U8: VI.sample_type = SAMPLE_INT8; break; - case SAMPLE_FMT_S16: VI.sample_type = SAMPLE_INT16; break; - case SAMPLE_FMT_S24: VI.sample_type = SAMPLE_INT24; break; - case SAMPLE_FMT_S32: VI.sample_type = SAMPLE_INT32; break; - case SAMPLE_FMT_FLT: VI.sample_type = SAMPLE_FLOAT; break; - default: - Env->ThrowError("FFmpegSource: Unsupported/unknown sample format"); - } - - //load cache - bool ACacheIsValid = LoadSampleInfoFromFile(AAudioCache, AAudioCache2, ASource, AudioTrack); - - char DefaultCacheFilename[1024]; - sprintf(DefaultCacheFilename, "%s.ffasd%dcache", ASource, AudioTrack); - if (!strcmp(AAudioCache2, "")) - AAudioCache2 = DefaultCacheFilename; - if (!RawCache) - RawCache = fopen(AAudioCache2, "wb+"); - - // Needs to be indexed? - if (!ACacheIsValid) { - AVPacket Packet; - - while (av_read_frame(FormatContext, &Packet) >= 0) { - if (Packet.stream_index == AudioTrack) { - SI.push_back(SampleInfo(VI.num_audio_samples, _ftelli64(RawCache), Packet.size, (Packet.flags & PKT_FLAG_KEY) ? 1 : 0)); - fwrite(Packet.data, 1, Packet.size, RawCache); - - if (AudioCodecContext->frame_size > 0) { - VI.num_audio_samples += AudioCodecContext->frame_size; - } else { - int Size = Packet.size; - uint8_t *Data = Packet.data; - - while (Size > 0) { - int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; - int Ret = avcodec_decode_audio2(AudioCodecContext, (int16_t *)DecodingBuffer, &TempOutputBufSize, Data, Size); - if (Ret < 0) - Env->ThrowError("FFmpegSource: Audio decoding error"); - - if (Ret > 0) { - int DecodedSamples = (int)VI.AudioSamplesFromBytes(TempOutputBufSize); - Size -= Ret; - Data += Ret; - VI.num_audio_samples += DecodedSamples; - } - } - } - } - - av_free_packet(&Packet); - } - - av_seek_frame(FormatContext, AudioTrack, 0, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(AudioCodecContext); - - if (!SaveSampleInfoToFile(AAudioCache, ASource, AudioTrack)) - Env->ThrowError("FFmpegSource: Failed to save audio cache index"); - } - - if (VI.num_audio_samples == 0) - Env->ThrowError("FFmpegSource: Audio track contains no samples"); -} - -int FFmpegAudioSource::DecodeNextAudioBlock(uint8_t *ABuf, int64_t *ACount, uint64_t AFilePos, unsigned int AFrameSize, IScriptEnvironment *Env) { - int Ret = -1; - *ACount = 0; - - _fseeki64(RawCache, AFilePos, SEEK_SET); - - if (AFrameSize > BufferSize) { - Buffer = (uint8_t *)realloc(Buffer, AFrameSize); - BufferSize = AFrameSize; - } - - fread(Buffer, 1, AFrameSize, RawCache); - - uint8_t *Data = Buffer; - int Size = AFrameSize; - - while (Size > 0) { - int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; - Ret = avcodec_decode_audio2(AudioCodecContext, (int16_t *)ABuf, &TempOutputBufSize, Data, Size); - - if (Ret < 0) // throw error or something? - goto Done; - - if (Ret > 0) { - Size -= Ret; - Data += Ret; - ABuf += TempOutputBufSize; - *ACount += VI.AudioSamplesFromBytes(TempOutputBufSize); - } - } - -Done: - return Ret; -} - -void FFmpegAudioSource::GetAudio(void* Buf, __int64 Start, __int64 Count, IScriptEnvironment *Env) { - size_t CurrentAudioBlock = FFMAX((int64_t)FindClosestAudioKeyFrame(Start) - 10, (int64_t)0); - avcodec_flush_buffers(AudioCodecContext); - - memset(Buf, 0, VI.BytesFromAudioSamples(Count)); - - uint8_t *DstBuf = (uint8_t *)Buf; - int64_t RemainingSamples = Count; - int64_t DecodeCount; - - do { - int64_t DecodeStart = SI[CurrentAudioBlock].SampleStart; - int Ret = DecodeNextAudioBlock(DecodingBuffer, &DecodeCount, SI[CurrentAudioBlock].FilePos, SI[CurrentAudioBlock].FrameSize, Env); - if (Ret < 0) - Env->ThrowError("Bleh, bad audio decoding"); - CurrentAudioBlock++; - - int64_t OffsetBytes = VI.BytesFromAudioSamples(FFMAX(0, Start - DecodeStart)); - int64_t CopyBytes = FFMAX(0, VI.BytesFromAudioSamples(FFMIN(RemainingSamples, DecodeCount - FFMAX(0, Start - DecodeStart)))); - - memcpy(DstBuf, DecodingBuffer + OffsetBytes, CopyBytes); - DstBuf += CopyBytes; - - RemainingSamples -= VI.AudioSamplesFromBytes(CopyBytes); - } while (RemainingSamples > 0 && DecodeCount > 0); -} - -FFmpegAudioSource::~FFmpegAudioSource() { - if (RawCache) - fclose(RawCache); - if (AudioCodecContext) - avcodec_close(AudioCodecContext); - av_close_input_file(FormatContext); -} diff --git a/FFmpegSource/ffmpegsource.cpp b/FFmpegSource/ffmpegsource.cpp deleted file mode 100644 index 6f3113a75..000000000 --- a/FFmpegSource/ffmpegsource.cpp +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -int FFmpegSource::GetTrackIndex(int Index, CodecType ATrackType, IScriptEnvironment *Env) { - if (Index == -1) - for (unsigned int i = 0; i < FormatContext->nb_streams; i++) - if (FormatContext->streams[i]->codec->codec_type == ATrackType) { - Index = i; - break; - } - - if (Index == -1) - Env->ThrowError("FFmpegSource: No %s track found", (ATrackType == CODEC_TYPE_VIDEO) ? "video" : "audio"); - if (Index <= -2) - return -2; - - if (Index >= (int)FormatContext->nb_streams) - Env->ThrowError("FFmpegSource: Invalid %s track number", (ATrackType == CODEC_TYPE_VIDEO) ? "video" : "audio"); - - if (FormatContext->streams[Index]->codec->codec_type != ATrackType) - Env->ThrowError("FFmpegSource: Selected track is not %s", (ATrackType == CODEC_TYPE_VIDEO) ? "video" : "audio"); - - return Index; -} - - - -FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, - bool AVCache, const char *AVideoCache, const char *AAudioCache, const char *APPString, - int AQuality, int AThreads, int ASeekMode, IScriptEnvironment *Env) { - - CurrentFrame = 0; - SeekMode = ASeekMode; - - AVCodecContext *AudioCodecContext = NULL; - AVCodec *AudioCodec; - AVCodec *VideoCodec; - - FormatContext = NULL; - VideoCodecContext = NULL; - VideoCodec = NULL; - - if (av_open_input_file(&FormatContext, ASource, NULL, 0, NULL) != 0) - Env->ThrowError("FFmpegSource: Couldn't open '%s'", ASource); - - if (av_find_stream_info(FormatContext) < 0) - Env->ThrowError("FFmpegSource: Couldn't find stream information"); - - VideoTrack = GetTrackIndex(AVideoTrack, CODEC_TYPE_VIDEO, Env); - int AudioTrack = GetTrackIndex(AAudioTrack, CODEC_TYPE_AUDIO, Env); - - bool VCacheIsValid = true; - bool ACacheIsValid = true; - - if (VideoTrack >= 0) { - if (SeekMode >= 0 && av_seek_frame(FormatContext, VideoTrack, 0, AVSEEK_FLAG_BACKWARD) < 0) - Env->ThrowError("FFmpegSource: Video track is unseekable"); - - VCacheIsValid = LoadFrameInfoFromFile(AVideoCache, ASource, VideoTrack); - - VideoCodecContext = FormatContext->streams[VideoTrack]->codec; - VideoCodecContext->thread_count = AThreads; - - VideoCodec = avcodec_find_decoder(VideoCodecContext->codec_id); - if (VideoCodec == NULL) - Env->ThrowError("FFmpegSource: Video codec not found"); - - if (avcodec_open(VideoCodecContext, VideoCodec) < 0) - Env->ThrowError("FFmpegSource: Could not open video codec"); - - // Fix for mpeg2 and other formats where decoding a frame is necessary to get information about the stream - if (SeekMode >= 0 && (VideoCodecContext->pix_fmt == PIX_FMT_NONE || VideoCodecContext->width == 0 || VideoCodecContext->height == 0)) { - int64_t Dummy; - DecodeNextFrame(DecodeFrame, &Dummy); - av_seek_frame(FormatContext, VideoTrack, 0, AVSEEK_FLAG_BACKWARD); - } - - VI.image_type = VideoInfo::IT_TFF; - VI.width = VideoCodecContext->width; - VI.height = VideoCodecContext->height; - VI.fps_denominator = FormatContext->streams[VideoTrack]->time_base.num; - VI.fps_numerator = FormatContext->streams[VideoTrack]->time_base.den; - - if (VI.width <= 0 || VI.height <= 0) - Env->ThrowError("FFmpegSource: Codec returned zero size video"); - - // sanity check framerate - if (VI.fps_denominator > VI.fps_numerator || VI.fps_denominator <= 0 || VI.fps_numerator <= 0) { - VI.fps_denominator = 1; - VI.fps_numerator = 30; - } - - SetOutputFormat(VideoCodecContext->pix_fmt, Env); - InitPP(VI.width, VI.height, APPString, AQuality, VideoCodecContext->pix_fmt, Env); - } - - if (AudioTrack >= 0) { - AudioCodecContext = FormatContext->streams[AudioTrack]->codec; - - AudioCodec = avcodec_find_decoder(AudioCodecContext->codec_id); - if (AudioCodec == NULL) - Env->ThrowError("FFmpegSource: Audio codec not found"); - - if (avcodec_open(AudioCodecContext, AudioCodec) < 0) - Env->ThrowError("FFmpegSource: Could not open audio codec"); - - switch (AudioCodecContext->sample_fmt) { - case SAMPLE_FMT_U8: VI.sample_type = SAMPLE_INT8; break; - case SAMPLE_FMT_S16: VI.sample_type = SAMPLE_INT16; break; - case SAMPLE_FMT_S24: VI.sample_type = SAMPLE_INT24; break; - case SAMPLE_FMT_S32: VI.sample_type = SAMPLE_INT32; break; - case SAMPLE_FMT_FLT: VI.sample_type = SAMPLE_FLOAT; break; - default: - Env->ThrowError("FFmpegSource: Unsupported/unknown sample format"); - } - - VI.nchannels = AudioCodecContext->channels; - VI.audio_samples_per_second = AudioCodecContext->sample_rate; - - ACacheIsValid = OpenAudioCache(AAudioCache, ASource, AudioTrack, Env); - } - - if ((!ACacheIsValid || !VCacheIsValid) && SeekMode == -1) - Env->ThrowError("FFmpegSource: Unusual indexing error, report on doom9"); - - // Needs to be indexed? - if (!ACacheIsValid || !VCacheIsValid) { - FILE *RawCache = NULL; - if (!ACacheIsValid) - AudioCacheType = acRaw; - - switch (AudioCacheType) { - case acRaw: RawCache = NewRawCacheWriter(AAudioCache, ASource, AudioTrack, Env); break; - } - - AVPacket Packet; - while (av_read_frame(FormatContext, &Packet) >= 0) { - if (Packet.stream_index == VideoTrack && !VCacheIsValid) { - Frames.push_back(FrameInfo(Packet.dts, (Packet.flags & PKT_FLAG_KEY) ? 1 : 0)); - VI.num_frames++; - } else if (Packet.stream_index == AudioTrack && !ACacheIsValid) { - int Size = Packet.size; - uint8_t *Data = Packet.data; - - while (Size > 0) { - int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; - int Ret = avcodec_decode_audio2(AudioCodecContext, (int16_t *)DecodingBuffer, &TempOutputBufSize, Data, Size); - if (Ret < 0) - Env->ThrowError("FFmpegSource: Audio decoding error"); - - int DecodedSamples = (int)VI.AudioSamplesFromBytes(TempOutputBufSize); - - Size -= Ret; - Data += Ret; - VI.num_audio_samples += DecodedSamples; - - if (AudioCacheType == acRaw) { - fwrite(DecodingBuffer, 1, TempOutputBufSize, RawCache); - } - } - } - - av_free_packet(&Packet); - } - - if (!ACacheIsValid) { - switch (AudioCacheType) { - case acRaw: CloseRawCacheWriter(RawCache); break; - } - - ACacheIsValid = OpenAudioCache(AAudioCache, ASource, AudioTrack, Env); - if (!ACacheIsValid) - Env->ThrowError("FFmpegSource: Failed to open newly created audio cache for reading"); - } - - if (VideoTrack >= 0 && VI.num_frames == 0) - Env->ThrowError("FFmpegSource: Video track contains no frames"); - - if (AudioTrack >= 0 && VI.num_audio_samples == 0) - Env->ThrowError("FFmpegSource: Audio track contains no samples"); - - if (VideoTrack >= 0) - av_seek_frame(FormatContext, VideoTrack, Frames.front().DTS, AVSEEK_FLAG_BACKWARD); - - if (AVCache && !VCacheIsValid) - if (!SaveFrameInfoToFile(AVideoCache, ASource, VideoTrack)) - Env->ThrowError("FFmpegSource: Failed to write video cache info"); - } - - if (AudioTrack >= 0) - avcodec_close(AudioCodecContext); - - if (VideoTrack >= 0) { - if (!SaveTimecodesToFile(ATimecodes, FormatContext->streams[VideoTrack]->time_base.num * 1000, FormatContext->streams[VideoTrack]->time_base.den)) - Env->ThrowError("FFmpegSource: Failed to write timecodes"); - - // Adjust framerate to match the duration of the first frame - if (Frames.size() >= 2) { - unsigned int DTSDiff = (unsigned int)FFMAX(Frames[1].DTS - Frames[0].DTS, 1); - VI.fps_denominator *= DTSDiff; - } - - // Set AR variables - Env->SetVar("FFSAR_NUM", VideoCodecContext->sample_aspect_ratio.num); - Env->SetVar("FFSAR_DEN", VideoCodecContext->sample_aspect_ratio.den); - Env->SetVar("FFSAR", av_q2d(VideoCodecContext->sample_aspect_ratio)); - - // Set crop variables - Env->SetVar("FFCROP_LEFT", (int)0); - Env->SetVar("FFCROP_RIGHT", (int)0); - Env->SetVar("FFCROP_TOP", (int)0); - Env->SetVar("FFCROP_BOTTOM", (int)0); - } -} - -FFmpegSource::~FFmpegSource() { - if (VideoTrack >= 0) - avcodec_close(VideoCodecContext); - av_close_input_file(FormatContext); -} - - -int FFmpegSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AStartTime) { - AVPacket Packet; - int FrameFinished = 0; - int Ret = -1; - *AStartTime = -1; - - while (av_read_frame(FormatContext, &Packet) >= 0) { - if (Packet.stream_index == VideoTrack) { - if (*AStartTime < 0) - *AStartTime = Packet.dts; - - Ret = avcodec_decode_video(VideoCodecContext, AFrame, &FrameFinished, Packet.data, Packet.size); - } - - av_free_packet(&Packet); - - if (FrameFinished) - goto Done; - } - - // Flush the last frames - if (VideoCodecContext->has_b_frames) - Ret = avcodec_decode_video(VideoCodecContext, AFrame, &FrameFinished, NULL, 0); - - if (!FrameFinished) - goto Error; - -// Ignore errors for now -Error: -Done: - return Ret; -} - -PVideoFrame FFmpegSource::GetFrame(int n, IScriptEnvironment* Env) { - if (LastFrameNum == n) - return LastFrame; - - bool HasSeeked = false; - - if (SeekMode >= 0) { - int ClosestKF = FindClosestKeyFrame(n); - - if (SeekMode == 0) { - if (n < CurrentFrame) { - av_seek_frame(FormatContext, VideoTrack, 0, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(VideoCodecContext); - CurrentFrame = 0; - } - } else { - // 10 frames is used as a margin to prevent excessive seeking since the predicted best keyframe isn't always selected by avformat - if (n < CurrentFrame || ClosestKF > CurrentFrame + 10 || (SeekMode == 3 && n > CurrentFrame + 10)) { - av_seek_frame(FormatContext, VideoTrack, (SeekMode == 3) ? Frames[n].DTS : Frames[ClosestKF].DTS, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(VideoCodecContext); - HasSeeked = true; - } - } - } else if (n < CurrentFrame) { - Env->ThrowError("FFmpegSource: Non-linear access attempted"); - } - - do { - int64_t StartTime; - DecodeNextFrame(DecodeFrame, &StartTime); - - if (HasSeeked) { - HasSeeked = false; - - // Is the seek destination time known? Does it belong to a frame? - if (StartTime < 0 || (CurrentFrame = FrameFromDTS(StartTime)) < 0) { - switch (SeekMode) { - case 1: - Env->ThrowError("FFmpegSource: Frame accurate seeking is not possible in this file"); - case 2: - case 3: - CurrentFrame = ClosestFrameFromDTS(StartTime); - break; - default: - Env->ThrowError("FFmpegSource: Failed assertion"); - } - } - } - - CurrentFrame++; - } while (CurrentFrame <= n); - - LastFrame = OutputFrame(DecodeFrame, Env); - LastFrameNum = n; - return LastFrame; -} diff --git a/FFmpegSource/ffmpegsource.h b/FFmpegSource/ffmpegsource.h deleted file mode 100644 index 23d18d382..000000000 --- a/FFmpegSource/ffmpegsource.h +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef FFMPEGSOURCE_H -#define FFMPEGSOURCE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern "C" { -#include -#include -#include -#include - -#include "stdiostream.h" -} - -#include "MatroskaParser.h" -#include "avisynth.h" - -#define strcmpi _strcmpi - -enum AudioCacheFormat {acNone, acRaw}; - -struct FrameInfo { - int64_t DTS; - bool KeyFrame; - FrameInfo(int64_t ADTS, bool AKeyFrame) : DTS(ADTS), KeyFrame(AKeyFrame) {}; -}; - -typedef std::vector FrameInfoVector; - -struct SampleInfo { - int64_t SampleStart; - int64_t FilePos; - unsigned int FrameSize; - bool KeyFrame; - SampleInfo(int64_t ASampleStart, int64_t AFilePos, unsigned int AFrameSize, bool AKeyFrame) { - SampleStart = ASampleStart; - FilePos = AFilePos; - FrameSize = AFrameSize; - KeyFrame = AKeyFrame; - } -}; - -typedef std::vector SampleInfoVector; - -int GetPPCPUFlags(IScriptEnvironment *Env); -int GetSWSCPUFlags(IScriptEnvironment *Env); -int CSNameToPIXFMT(const char * ACSName, int ADefault); -int ResizerNameToSWSResizer(const char *AResizerName); -int GetNumberOfLogicalCPUs(); -CodecID MatroskaToFFCodecID(TrackInfo *TI); - -class FFPP : public GenericVideoFilter { -private: - pp_context_t *PPContext; - pp_mode_t *PPMode; - SwsContext *SWSTo422P; - SwsContext *SWSFrom422P; - AVPicture InputPicture; - AVPicture OutputPicture; -public: - FFPP(PClip AChild, const char *APPString, int AQuality, IScriptEnvironment *Env); - ~FFPP(); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* Env); -}; - -class SWScale : public GenericVideoFilter { -private: - SwsContext *Context; - int OrigWidth; - int OrigHeight; - bool FlipOutput; -public: - SWScale(PClip AChild, int AResizeToWidth, int AResizeToHeight, const char *AResizer, const char *AConvertToFormat, IScriptEnvironment *Env); - ~SWScale(); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *Env); -}; - -class FFBase : public IClip{ -private: - pp_context_t *PPContext; - pp_mode_t *PPMode; - SwsContext *SWS; - int ConvertToFormat; - AVPicture PPPicture; -protected: - VideoInfo VI; - AVFrame *DecodeFrame; - AudioCacheFormat AudioCacheType; - FILE *RawAudioCache; - PVideoFrame LastFrame; - int LastFrameNum; - uint8_t *DecodingBuffer; - - FrameInfoVector Frames; - - int FindClosestKeyFrame(int AFrame); - int FrameFromDTS(int64_t ADTS); - int ClosestFrameFromDTS(int64_t ADTS); - bool LoadFrameInfoFromFile(const char *AVideoCacheFile, const char *ASource, int AVideoTrack); - bool SaveFrameInfoToFile(const char *AVideoCacheFile, const char *ASource, int AVideoTrack); - bool SaveTimecodesToFile(const char *ATimecodeFile, int64_t ScaleD, int64_t ScaleN); - - bool OpenAudioCache(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, IScriptEnvironment *Env); - FILE *FFBase::NewRawCacheWriter(const char *AAudioCacheFile, const char *ASource, int AAudioTrack, IScriptEnvironment *Env); - void FFBase::CloseRawCacheWriter(FILE *ARawCache); - - void InitPP(int AWidth, int AHeight, const char *APPString, int AQuality, int APixelFormat, IScriptEnvironment *Env); - void SetOutputFormat(int ACurrentFormat, IScriptEnvironment *Env); - PVideoFrame OutputFrame(AVFrame *AFrame, IScriptEnvironment *Env); -public: - - FFBase(); - ~FFBase(); - - bool __stdcall GetParity(int n) { return false; } - void __stdcall SetCacheHints(int cachehints, int frame_range) { } - const VideoInfo& __stdcall GetVideoInfo() { return VI; } - void __stdcall GetAudio(void* Buf, __int64 Start, __int64 Count, IScriptEnvironment *Env); -}; - -class FFmpegSource : public FFBase { -private: - AVFormatContext *FormatContext; - AVCodecContext *VideoCodecContext; - - int VideoTrack; - int CurrentFrame; - int SeekMode; - - int GetTrackIndex(int Index, CodecType ATrackType, IScriptEnvironment *Env); - int DecodeNextFrame(AVFrame *Frame, int64_t *DTS); -public: - FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, bool AVCache, const char *AVideoCache, const char *AAudioCache, const char *APPString, int AQuality, int AThreads, int ASeekMode, IScriptEnvironment *Env); - ~FFmpegSource(); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *Env); -}; - -class FFMatroskaSource : public FFBase { -private: - StdIoStream ST; - unsigned int BufferSize; - CompressedStream *VideoCS; - CompressedStream *AudioCS; - AVCodecContext *VideoCodecContext; - MatroskaFile *MF; - char ErrorMessage[256]; - uint8_t *Buffer; - int CurrentFrame; - - int ReadFrame(uint64_t AFilePos, unsigned int AFrameSize, CompressedStream *ACS, IScriptEnvironment *Env); - int DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, IScriptEnvironment* Env); - int GetTrackIndex(int Index, unsigned char ATrackType, IScriptEnvironment *Env); -public: - FFMatroskaSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, bool AVCache, const char *AVideoCache, const char *AAudioCache, const char *APPString, int AQuality, int AThreads, IScriptEnvironment *Env); - ~FFMatroskaSource(); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *Env); -}; - -class FFAudioBase : public IClip{ -protected: - VideoInfo VI; - uint8_t *DecodingBuffer; - SampleInfoVector SI; - - size_t FindClosestAudioKeyFrame(int64_t Sample); - bool LoadSampleInfoFromFile(const char *AAudioCacheFile, const char *ASource, int AAudioTrack); - bool SaveSampleInfoToFile(const char *AAudioCacheFile, const char *ASource, int AAudioTrack); -public: - FFAudioBase(); - ~FFAudioBase(); - - bool __stdcall GetParity(int n) { return false; } - void __stdcall SetCacheHints(int cachehints, int frame_range) { } - const VideoInfo& __stdcall GetVideoInfo() { return VI; } - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *Env) { return NULL; } -}; - -class FFmpegAudioSource : public FFAudioBase { -private: - AVFormatContext *FormatContext; - AVCodecContext *AudioCodecContext; - - int AudioTrack; - FILE *RawCache; - unsigned int BufferSize; - uint8_t *Buffer; - - bool LoadSampleInfoFromFile(const char *AAudioCacheFile, const char *AAudioCacheFile2, const char *ASource, int AAudioTrack); - int DecodeNextAudioBlock(uint8_t *ABuf, int64_t *ACount, uint64_t AFilePos, unsigned int AFrameSize, IScriptEnvironment *Env); - int GetTrackIndex(int Index, CodecType ATrackType, IScriptEnvironment *Env); -public: - FFmpegAudioSource(const char *ASource, int AAudioTrack, const char *AAudioCache, const char *AAudioCacheFile2, IScriptEnvironment *Env); - ~FFmpegAudioSource(); - - void __stdcall GetAudio(void* Buf, __int64 Start, __int64 Count, IScriptEnvironment *Env); -}; - -class FFMatroskaAudioSource : public FFAudioBase { -private: - StdIoStream ST; - CompressedStream *AudioCS; - AVCodecContext *AudioCodecContext; - MatroskaFile *MF; - char ErrorMessage[256]; - unsigned int BufferSize; - uint8_t *Buffer; - - int ReadFrame(uint64_t AFilePos, unsigned int AFrameSize, CompressedStream *ACS, IScriptEnvironment *Env); - int DecodeNextAudioBlock(uint8_t *ABuf, int64_t *ACount, uint64_t AFilePos, unsigned int AFrameSize, IScriptEnvironment *Env); - int GetTrackIndex(int Index, unsigned char ATrackType, IScriptEnvironment *Env); -public: - FFMatroskaAudioSource(const char *ASource, int AAudioTrack, const char *AAudioCache, IScriptEnvironment *Env); - ~FFMatroskaAudioSource(); - - void __stdcall GetAudio(void* Buf, __int64 Start, __int64 Count, IScriptEnvironment *Env); -}; - -#endif diff --git a/FFmpegSource/ffmpegsource.html b/FFmpegSource/ffmpegsource.html deleted file mode 100644 index 1b40fe095..000000000 --- a/FFmpegSource/ffmpegsource.html +++ /dev/null @@ -1,337 +0,0 @@ - - - -FFmpegSource Documentation - - - -

FFmpegSource Documentation

-

-Opens files using ffmpeg and nothing else. May be frame accurate on good days. The source is BSD licensed and can be obtained from https://spaceboyz.net/svn/aegisub/trunk/FFmpegSource. The precompiled binary is GPL licensed. -

- -

Compatibility - Video

-
    -
  • AVI, MKV, MP4, FLV: Frame accurate
  • -
  • WMV: Frame accurate(?) but avformat seems to pick keyframes relatively far away
  • -
  • OGM: Messed up first frame and seeking produces smearing with seekmode=3, incredibly slow seeking without, remux to mkv or avi
  • -
  • VOB: No rff flags applied, frame accurate?
  • -
  • MPG: Seeking seems to be off by one or two frames now and then
  • -
  • M2TS, TS: Linear access only (seekmode=-1)
  • -
  • Image files: most formats can be opened if seekmode=-1 is set
  • -
- -

Compatibility - Audio

-
    -
  • Should be sample accurate in all containers with audio cache
  • -
  • Can produce very bad distortions when caching is not used for certain formats like aac
  • -
- -

Usage

-

-FFmpegSource(string source, int vtrack = -1, int atrack = -2, string timecodes, bool vcache = true, string vcachefile, string acachefile, string pp, int ppquality = 6, int threads = -1, int seekmode = 1)
-

- -

-Note that the audio cache will always be created when opening files with audio and that it will be huge since it stores all audio as raw signed 16/24/32 bit pcm, unsigned 8 bit pcm or as float, using flac to compress it is also possible to reduce the size by half. -

- -

-FFAudioSource(string source, int atrack = -1, string acachefile, string acachefile2)
-

- -

-Experimental, may or may not be accurate enough for real usage. -

- -

-FFPP(clip, string pp, int ppquality = 6)
- Separate postprocessing which also seems to include a few simple deinterlacers -

- -

-SWScale(clip, width = -1, height = -1, resizer = "BICUBIC", colorspace = "")
- Separate postprocessing which also seems to include a few simple deinterlacers -

- -

-source: - Source file. -

- -

-atrack & vtrack: - Track number as seen by the relevant demuxer, starts from 0, -1 means it will pick the first suitable track and -2 means it's disabled. -

- - -

-timecodes: - File to output timecodes to, if the file exists it will be overwritten. -

- -

-vcache: - Write video indexing information to a file for later use. This setting does not control if The video index is loaded which it always is if it exists. -

- -

-vcachefile, acachefile & acachefile2: - Specifies the file to store the index information or raw audio in, if nothing is specified (source).ffv(tracknumber)cache is used for video and (source).ffa(d if FFAudioSource is used)(tracknumber)cache for audio. The second audio cache file is only required/created when not opening matroska files. -

- -

-pp: - See the table below for a full description, an empty string means no processing. It is recommended to avoid the autoq option since it's currently unknown what effect it will have on the processing. -

- -

-ppquality: - The quality to use for the specified postprocessing. Valid values are 0-6 where 0 usually means that no actual processing is done. -

- -

-threads: - Sets the number of decoder threads used. Defaults to the number of cpus reported by windows. Ignored by lavc if the used decoder doesn't implement it. -

- -

-seekmode: - Force how seeking is handled, has no effect on matroska files which always use the equivalent of seekmode=1
- -1: linear access without rewind, will throw an error if each successive requested frame number isn't bigger than the last one, only intended for opening images but might work on well with some obscure video format
- 0: linear access, the definition of slow but should make some formats "usable"
- 1: safe normal, bases seeking decisions on the reported keyframe positions
- 2: unsafe normal, same as 1 but no error will be thrown if the exact destination has to be guessed
- 3: aggressive, seek in the forward direction even if no closer keyframe is known to exist, only useful for testing and containers where avformat doesn't report keyframes properly -

- -

-width & height: - Width and height to resize to. Value below or equal to 0 is the same as specifying the input dimensions. -

- -

-resizer: - Selects the resizer used for resampling the chroma planes and normal resizing. The available methods are: FAST_BILINEAR, BILINEAR, BICUBIC, X, POINT, AREA, BICUBLIN, GAUSS, SINC, LANCZOS and SPLINE. -

- -

-colorspace: - The colorspace to convert to. The names are YV12, YUY2, RGB24, RGB32 and the empty string for same as input. -

- - - - -

PP string format

-
-Available postprocessing filters:
-Filters                        Options
-short  long name       short   long option     Description
-*      *               a       autoq           CPU power dependent enabler
-                       c       chrom           chrominance filtering enabled
-                       y       nochrom         chrominance filtering disabled
-                       n       noluma          luma filtering disabled
-hb     hdeblock        (2 threshold)           horizontal deblocking filter
-       1. difference factor: default=32, higher -> more deblocking
-       2. flatness threshold: default=39, lower -> more deblocking
-                       the h & v deblocking filters share these
-                       so you can't set different thresholds for h / v
-vb     vdeblock        (2 threshold)           vertical deblocking filter
-ha     hadeblock       (2 threshold)           horizontal deblocking filter
-va     vadeblock       (2 threshold)           vertical deblocking filter
-h1     x1hdeblock                              experimental h deblock filter 1
-v1     x1vdeblock                              experimental v deblock filter 1
-dr     dering                                  deringing filter
-al     autolevels                              automatic brightness / contrast
-                       f        fullyrange     stretch luminance to (0..255)
-lb     linblenddeint                           linear blend deinterlacer
-li     linipoldeint                            linear interpolating deinterlace
-ci     cubicipoldeint                          cubic interpolating deinterlacer
-md     mediandeint                             median deinterlacer
-fd     ffmpegdeint                             ffmpeg deinterlacer
-l5     lowpass5                                FIR lowpass deinterlacer
-de     default                                 hb:a,vb:a,dr:a
-fa     fast                                    h1:a,v1:a,dr:a
-ac                                             ha:a:128:7,va:a,dr:a
-tn     tmpnoise        (3 threshold)           temporal noise reducer
-                     1. <= 2. <= 3.            larger -> stronger filtering
-fq     forceQuant                   force quantizer
-Usage:
-[:
- -

Compiling

- -

zlib from http://www.zlib.net/

- -

FFmpeg svn from http://ffmpeg.mplayerhq.hu/

- -

Required FFmpeg Configuration: -./configure --enable-memalign-hack --enable-gpl --enable-swscale --enable-postproc - -

Suggested Additional Options: ---enable-w32threads --disable-encoders --disable-muxers --enable-small --enable-libfaad --disable-debug

-

-Note that --enable-w32threads is required for multithreaded decoding to work. -

- -

Changes

-
    -
  • 1.21
      -
    • Updated FFmpeg to rev 14845 (No more avi opening issues)
    • -
  • - -
  • 1.20
      -
    • Updated FFmpeg to rev 14461
    • -
  • - -
  • 1.19
      -
    • Now automatically detects the number of cpus and uses it as the default for the number of decoding threads
    • -
    • Added SWScale filter which can perform colorspace conversions and resizing and has many different resizers to choose from
    • -
    • Now exports the stored cropping values in mkv files in the variables FFCROP_LEFT, FFCROP_RIGHT, FFCROP_TOP and FFCROP_BOTTOM
    • -
    • Updated FFmpeg to rev 13572
    • -
  • - -
  • 1.18
      -
    • Reverted error handling because it broke vc1
    • -
  • - -
  • 1.17
      -
    • Now sets the video SAR (if any) in the variables FFSAR, FFSAR_NUM and FFSAR_DEN when being invoked
    • -
    • Changed error handling slightly in video decoding (most errors are still ignored)
    • -
    • Fixed a bug where the last frame(s) wouldn't be returned properly in h264 with b-frames+pyramid
    • -
    • Updated FFmpeg to rev 12685
    • -
  • - -
  • 1.16
      -
    • Added many new and missing matroska codec ids
    • -
    • Added threads argument to set the number of decoding threads used
    • -
    • Completely removed FLAC cache
    • -
    • Updated FFmpeg to rev 12382
    • -
  • - -
  • 1.15
      -
    • Updated FFmpeg to rev 11518
    • -
  • - -
  • 1.14
      -
    • If the output colorspace is YV12 or YUY2 the width and height may be automatically cropped by one pixel to make it an even number
    • -
    • FLAC cache is disabled because the static FLAC lib doesn't want to link
    • -
    • Added the experimental FFAudioSource which doesn't need a huge uncompressed cache
    • -
    • The plugin is now statically compiled
    • -
    • Updated FFmpeg to rev 11413
    • -
  • - -
  • 1.13
      -
    • Now always sorts the output timecodes so native avc in mkv won't have out of order values
    • -
    • Fixed the missing '# timecode format v2' line in saved timecode files
    • -
    • Now properly handles video files where the output resolution isn't known until a frame has been decoded (seems to fix flv4)
    • -
    • Now throws an error if the video decoder returns zero size video
    • -
    • Added an avsi file for easy autoloading
    • -
    • Updated libFLAC to 1.2.1
    • -
    • Updated FFmpeg to rev 10671 + camtasia swapped colors fix
    • -
  • - -
  • 1.12
      -
    • Now caches the last fully decoded frame to increase the reliability of seekmode=-1 and possibly reduce seeking in other modes
    • -
    • Video that needs to be converted to a suitable output format should now always have correct colors (was reversed in 1.11 and inconsistent in earlier versions)
    • -
    • Added seekmode=-1 which is mostly useful for opening image files very carefully
    • -
    • Now throws an error if the container is unseekable and seekmode=-1 isn't set
    • -
    • Updated FFmpeg to rev 10492 + camtasia swapped colors fix
    • -
  • - -
  • 1.11
      -
    • Now officially uses the MIT license
    • -
    • Much cleaner source
    • -
    • Can be compiled without support for compressing the audio cache with FLAC
    • -
    • Supports more audio formats in matroska
    • -
    • RGB24 output no longer has swapped colors if the video is converted to it for output (there still seems to be some bugs lurking when conversion is done with libswscale)
    • -
    • Fixed an access violation on close when no audio is opened (introduced in 1.10)
    • -
    • Updated FFmpeg to rev 10423
    • -
  • - -
  • 1.10
      -
    • The audio cache compression level is now ignored if the source isn't 16bit and the raw format is used instead
    • -
    • FLAC is now actually initialized properly so the cache actually works for files that aren't stereo (16bit limit still applies)
    • -
    • Now uses proper callbacks for FLAC so it works with larger than 2GB files
    • -
    • Doesn't (over)write the video cache with an empty one in certain cases when avformat is used for the source
    • -
  • - -
  • 1.9
      -
    • Added the possibility to compress the audio cache with FLAC (currently only works with 16bit audio)
    • -
    • Added another planar YUV 4:2:0 format to the supported output formats (fixes certain mov files)
    • -
    • Less memory is now allocated on the stack which makes av_find_stream_info() work for all files (fixes certain mov files)
    • -
    • Updated FFmpeg to rev 10186
    • -
  • - -
  • 1.8
      -
    • Updated FFmpeg to rev 10141
    • -
  • - -
  • 1.7
      -
    • Updated FFmpeg
    • -
    • Fixed error with mkv for codecs without codec private data and the first packet doesn't belong to them
    • -
  • - -
  • 1.6
      -
    • Fixed ac3 and other formats stored in mkv
    • -
    • Skip unnecessary seeking when index information already exists (gif file opening only 3/4 broken now)
    • -
    • Throws an error when the selected audio/video track has no frames/samples
    • -
  • - -
  • 1.5
      -
    • Fixed a bug that made avformat opened files only return audio if only the audio cache needed to be created
    • -
    • Rejects more corrupt cache files
    • -
    • Fixed crash when a 0 byte audio cache file is present
    • -
    • Improved framerate guessing for avformat which now takes takes the duration of the first frame into account
    • -
    • Fixed a bug introduced in 1.4 that would make the number of reported frames too high for files opened with avformat
    • -
    • Fixed mpeg2 and probably some other formats stored in mkv
    • -
    • Fixed issues with large mkv files and large audio cache files
    • -
    • FFmpeg is now compiled with liba52 and faad2
    • -
  • - -
  • 1.4
      -
    • Uses the average framerate for mkv files
    • -
    • Naming scheme of cache files changed to prevent confusion with the default names in files with multiple tracks of the same type
    • -
    • Use mmx optimizations in swscaler when possible
    • -
    • Now uses normal windows linebreaks in all files
    • -
    • Removed FFAudioSource
    • -
    • Merged FFVideoSource and FFAudioRefSource into FFmpegSource
    • -
    • Added postprocessing with libpostproc in FFmpegSource and separately in FFPP
    • -
  • - -
  • 1.3
      -
    • Compiled against ffmpeg rev9620
    • -
    • Added FFAudioRefSource
    • -
    • Added FFAudioSource (has big issues)
    • -
    • Renamed FFmpegSource to FFVideoSource
    • -
    • Adjusted seeking in the forward direction to only be done if the requested frame is more than 10 frames away to reduce unnecessary seeking
    • -
    • Now outputs the last frame properly when there are decoding delays
    • -
  • - -
  • 1.2
      -
    • Compiled against ffmpeg rev9451
    • -
    • Somewhat cleaner source code
    • -
    • Linear access in addition to a few other modes of seeking can now be forced
    • -
    • Can now save the index information to a file which makes subsequent file opening fast
    • -
    • No longer skips indexing for any format
    • -
  • - -
  • 1.1
      -
    • Skip indexing for avi
    • -
    • Prefix all error messages with the plugin name
    • -
    • Can write v2 timecodes to a file
    • -
    • Fixed reported framerate
    • -
  • - -
- - - diff --git a/FFmpegSource/ffpp.cpp b/FFmpegSource/ffpp.cpp deleted file mode 100644 index 4fd9b35f1..000000000 --- a/FFmpegSource/ffpp.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -FFPP::FFPP(PClip AChild, const char *APPString, int AQuality, IScriptEnvironment *Env) : GenericVideoFilter(AChild) { - if (!strcmp(APPString, "")) - Env->ThrowError("FFPP: PP argument is empty"); - if (AQuality < 0 || AQuality > PP_QUALITY_MAX) - Env->ThrowError("FFPP: Quality is out of range"); - - PPContext = NULL; - PPMode = NULL; - SWSTo422P = NULL; - SWSFrom422P = NULL; - - memset(&InputPicture, 0, sizeof(InputPicture)); - memset(&OutputPicture, 0, sizeof(OutputPicture)); - - PPMode = pp_get_mode_by_name_and_quality((char *)APPString, AQuality); - if (!PPMode) - Env->ThrowError("FFPP: Invalid postprocesing settings"); - - int Flags = GetPPCPUFlags(Env); - - if (vi.IsYV12()) { - Flags |= PP_FORMAT_420; - } else if (vi.IsYUY2()) { - Flags |= PP_FORMAT_422; - SWSTo422P = sws_getContext(vi.width, vi.height, PIX_FMT_YUV422, vi.width, vi.height, PIX_FMT_YUV422P, GetSWSCPUFlags(Env) | SWS_BICUBIC, NULL, NULL, NULL); - SWSFrom422P = sws_getContext(vi.width, vi.height, PIX_FMT_YUV422P, vi.width, vi.height, PIX_FMT_YUV422, GetSWSCPUFlags(Env) | SWS_BICUBIC, NULL, NULL, NULL); - avpicture_alloc(&InputPicture, PIX_FMT_YUV422P, vi.width, vi.height); - avpicture_alloc(&OutputPicture, PIX_FMT_YUV422P, vi.width, vi.height); - } else { - Env->ThrowError("FFPP: Only YV12 and YUY2 video supported"); - } - - PPContext = pp_get_context(vi.width, vi.height, Flags); - if (!PPContext) - Env->ThrowError("FFPP: Failed to create context"); -} - -FFPP::~FFPP() { - if (PPMode) - pp_free_mode(PPMode); - if (PPContext) - pp_free_context(PPContext); - if (SWSTo422P) - sws_freeContext(SWSTo422P); - if (SWSFrom422P) - sws_freeContext(SWSFrom422P); - avpicture_free(&InputPicture); - avpicture_free(&OutputPicture); -} - -PVideoFrame FFPP::GetFrame(int n, IScriptEnvironment* Env) { - PVideoFrame Src = child->GetFrame(n, Env); - PVideoFrame Dst = Env->NewVideoFrame(vi); - - if (vi.IsYV12()) { - const uint8_t *SrcData[3] = {(uint8_t *)Src->GetReadPtr(PLANAR_Y), (uint8_t *)Src->GetReadPtr(PLANAR_U), (uint8_t *)Src->GetReadPtr(PLANAR_V)}; - int SrcStride[3] = {Src->GetPitch(PLANAR_Y), Src->GetPitch(PLANAR_U), Src->GetPitch(PLANAR_V)}; - uint8_t *DstData[3] = {Dst->GetWritePtr(PLANAR_Y), Dst->GetWritePtr(PLANAR_U), Dst->GetWritePtr(PLANAR_V)}; - int DstStride[3] = {Dst->GetPitch(PLANAR_Y), Dst->GetPitch(PLANAR_U), Dst->GetPitch(PLANAR_V)}; - - pp_postprocess(SrcData, SrcStride, DstData, DstStride, vi.width, vi.height, NULL, 0, PPMode, PPContext, 0); - } else if (vi.IsYUY2()) { - uint8_t *SrcData[1] = {(uint8_t *)Src->GetReadPtr()}; - int SrcStride[1] = {Src->GetPitch()}; - sws_scale(SWSTo422P, SrcData, SrcStride, 0, vi.height, InputPicture.data, InputPicture.linesize); - - pp_postprocess(const_cast(InputPicture.data), InputPicture.linesize, OutputPicture.data, OutputPicture.linesize, vi.width, vi.height, NULL, 0, PPMode, PPContext, 0); - - uint8_t *DstData[1] = {Dst->GetWritePtr()}; - int DstStride[1] = {Dst->GetPitch()}; - sws_scale(SWSFrom422P, OutputPicture.data, OutputPicture.linesize, 0, vi.height, DstData, DstStride); - } - - return Dst; -} diff --git a/FFmpegSource/ffshared.cpp b/FFmpegSource/ffshared.cpp deleted file mode 100644 index 82ce305ec..000000000 --- a/FFmpegSource/ffshared.cpp +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -int GetPPCPUFlags(IScriptEnvironment *Env) { - int Flags = 0; - long CPUFlags = Env->GetCPUFlags(); - - if (CPUFlags & CPUF_MMX) - CPUFlags |= PP_CPU_CAPS_MMX; - if (CPUFlags & CPUF_INTEGER_SSE) - CPUFlags |= PP_CPU_CAPS_MMX2; - if (CPUFlags & CPUF_3DNOW) - CPUFlags |= PP_CPU_CAPS_3DNOW; - - return Flags; -} - -int GetSWSCPUFlags(IScriptEnvironment *Env) { - int Flags = 0; - long CPUFlags = Env->GetCPUFlags(); - - if (CPUFlags & CPUF_MMX) - CPUFlags |= SWS_CPU_CAPS_MMX; - if (CPUFlags & CPUF_INTEGER_SSE) - CPUFlags |= SWS_CPU_CAPS_MMX2; - if (CPUFlags & CPUF_3DNOW) - CPUFlags |= SWS_CPU_CAPS_3DNOW; - - return Flags; -} - -int CSNameToPIXFMT(const char * ACSName, int ADefault) { - if (!strcmpi(ACSName, "")) - return ADefault; - if (!strcmpi(ACSName, "YV12")) - return PIX_FMT_YUV420P; - if (!strcmpi(ACSName, "YUY2")) - return PIX_FMT_YUYV422; - if (!strcmpi(ACSName, "RGB24")) - return PIX_FMT_BGR24; - if (!strcmpi(ACSName, "RGB32")) - return PIX_FMT_RGB32; - return PIX_FMT_NONE; -} - -int ResizerNameToSWSResizer(const char *AResizerName) { - if (!strcmpi(AResizerName, "FAST_BILINEAR")) - return SWS_FAST_BILINEAR; - if (!strcmpi(AResizerName, "BILINEAR")) - return SWS_BILINEAR; - if (!strcmpi(AResizerName, "BICUBIC")) - return SWS_BICUBIC; - if (!strcmpi(AResizerName, "X")) - return SWS_X; - if (!strcmpi(AResizerName, "POINT")) - return SWS_POINT; - if (!strcmpi(AResizerName, "AREA")) - return SWS_AREA; - if (!strcmpi(AResizerName, "BICUBLIN")) - return SWS_BICUBLIN; - if (!strcmpi(AResizerName, "GAUSS")) - return SWS_GAUSS; - if (!strcmpi(AResizerName, "SINC")) - return SWS_SINC; - if (!strcmpi(AResizerName, "LANCZOS")) - return SWS_LANCZOS; - if (!strcmpi(AResizerName, "SPLINE")) - return SWS_SPLINE; - return 0; -} - -int GetNumberOfLogicalCPUs() { - SYSTEM_INFO SI; - GetSystemInfo(&SI); - return SI.dwNumberOfProcessors; -} - -AVSValue __cdecl CreateFFmpegSource(AVSValue Args, void* UserData, IScriptEnvironment* Env) { - if (!UserData) { - av_register_all(); - UserData = (void *)-1; - } - - if (!Args[0].Defined()) - Env->ThrowError("FFmpegSource: No source specified"); - - const char *Source = Args[0].AsString(); - int VTrack = Args[1].AsInt(-1); - int ATrack = Args[2].AsInt(-2); - const char *Timecodes = Args[3].AsString(""); - bool VCache = Args[4].AsBool(true); - const char *VCacheFile = Args[5].AsString(""); - const char *ACacheFile = Args[6].AsString(""); - const char *PPString = Args[7].AsString(""); - int PPQuality = Args[8].AsInt(PP_QUALITY_MAX); - int Threads = Args[9].AsInt(-1); - int SeekMode = Args[10].AsInt(1); - - if (VTrack <= -2 && ATrack <= -2) - Env->ThrowError("FFmpegSource: No tracks selected"); - - if (SeekMode < -1 || SeekMode > 3) - Env->ThrowError("FFmpegSource: Invalid seekmode selected"); - - if (Threads <= 0) - Threads = GetNumberOfLogicalCPUs(); - if (Threads < 1) - Env->ThrowError("FFmpegSource: Invalid thread count"); - - AVFormatContext *FormatContext; - - if (av_open_input_file(&FormatContext, Source, NULL, 0, NULL) != 0) - Env->ThrowError("FFmpegSource: Couldn't open %s", Args[0].AsString()); - bool IsMatroska = !strcmp(FormatContext->iformat->name, "matroska"); - av_close_input_file(FormatContext); - - if (IsMatroska) { - return new FFMatroskaSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, PPString, PPQuality, Threads, Env); - } else { - // Do a separate indexing pass, enjoy the constructor sideeffects - if (SeekMode == -1) - delete new FFmpegSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, PPString, PPQuality, Threads, -2, Env); - return new FFmpegSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, PPString, PPQuality, Threads, SeekMode, Env); - } -} - -AVSValue __cdecl CreateFFAudioSource(AVSValue Args, void* UserData, IScriptEnvironment* Env) { - if (!UserData) { - av_register_all(); - UserData = (void *)1; - } - - if (!Args[0].Defined()) - Env->ThrowError("FFmpegSource: No source specified"); - - const char *Source = Args[0].AsString(); - int ATrack = Args[1].AsInt(-1); - const char *ACacheFile = Args[2].AsString(""); - const char *ADemuxedFile = Args[3].AsString(""); - - if (ATrack <= -2) - Env->ThrowError("FFmpegSource: No tracks selected"); - - AVFormatContext *FormatContext; - - if (av_open_input_file(&FormatContext, Source, NULL, 0, NULL) != 0) - Env->ThrowError("FFmpegSource: Couldn't open %s", Args[0].AsString()); - bool IsMatroska = !strcmp(FormatContext->iformat->name, "matroska"); - av_close_input_file(FormatContext); - - if (IsMatroska) { - return new FFMatroskaAudioSource(Source, ATrack, ACacheFile, Env); - } else { - return new FFmpegAudioSource(Source, ATrack, ACacheFile, ADemuxedFile, Env); - } -} - -AVSValue __cdecl CreateFFPP(AVSValue Args, void* UserData, IScriptEnvironment* Env) { - return new FFPP(Args[0].AsClip(), Args[1].AsString(""), Args[2].AsInt(PP_QUALITY_MAX), Env); -} - -AVSValue __cdecl CreateSWScale(AVSValue Args, void* UserData, IScriptEnvironment* Env) { - return new SWScale(Args[0].AsClip(), Args[1].AsInt(0), Args[2].AsInt(0), Args[3].AsString("BICUBIC"), Args[4].AsString(""), Env); -} - -extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* Env) { - Env->AddFunction("FFmpegSource", "[source]s[vtrack]i[atrack]i[timecodes]s[vcache]b[vcachefile]s[acachefile]s[pp]s[ppquality]i[threads]i[seekmode]i", CreateFFmpegSource, 0); - Env->AddFunction("FFAudioSource", "[source]s[atrack]i[acachefile]s[acachefile2]s", CreateFFAudioSource, 0); - Env->AddFunction("FFPP", "c[pp]s[ppquality]i", CreateFFPP, 0); - Env->AddFunction("SWScale", "c[width]i[height]i[resizer]s[colorspace]s", CreateSWScale, 0); - return "FFmpegSource"; -}; diff --git a/FFmpegSource/ffswscale.cpp b/FFmpegSource/ffswscale.cpp deleted file mode 100644 index 73df357de..000000000 --- a/FFmpegSource/ffswscale.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -SWScale::SWScale(PClip AChild, int AResizeToWidth, int AResizeToHeight, const char *AResizer, const char *AConvertToFormat, IScriptEnvironment *Env) : GenericVideoFilter(AChild) { - Context = NULL; - OrigWidth = vi.width; - OrigHeight = vi.height; - FlipOutput = vi.IsYUV(); - - int ConvertFromFormat = PIX_FMT_NONE; - if (vi.IsYV12()) - ConvertFromFormat = PIX_FMT_YUV420P; - if (vi.IsYUY2()) - ConvertFromFormat = PIX_FMT_YUYV422; - if (vi.IsRGB24()) - ConvertFromFormat = PIX_FMT_BGR24; - if (vi.IsRGB32()) - ConvertFromFormat = PIX_FMT_RGB32; - - if (AResizeToHeight <= 0) - AResizeToHeight = OrigHeight; - else - vi.height = AResizeToHeight; - - if (AResizeToWidth <= 0) - AResizeToWidth = OrigWidth; - else - vi.width = AResizeToWidth; - - int ConvertToFormat = CSNameToPIXFMT(AConvertToFormat, ConvertFromFormat); - if (ConvertToFormat == PIX_FMT_NONE) - Env->ThrowError("SWScale: Invalid colorspace specified (%s)", AConvertToFormat); - - switch (ConvertToFormat) { - case PIX_FMT_YUV420P: vi.pixel_type = VideoInfo::CS_I420; break; - case PIX_FMT_YUYV422: vi.pixel_type = VideoInfo::CS_YUY2; break; - case PIX_FMT_BGR24: vi.pixel_type = VideoInfo::CS_BGR24; break; - case PIX_FMT_RGB32: vi.pixel_type = VideoInfo::CS_BGR32; break; - } - - FlipOutput ^= vi.IsYUV(); - - int Resizer = ResizerNameToSWSResizer(AResizer); - if (Resizer == 0) - Env->ThrowError("SWScale: Invalid resizer specified (%s)", AResizer); - - if (ConvertToFormat == PIX_FMT_YUV420P && vi.height & 1) - Env->ThrowError("SWScale: mod 2 output height required", AResizer); - - if ((ConvertToFormat == PIX_FMT_YUV420P || ConvertToFormat == PIX_FMT_YUYV422) && vi.width & 1) - Env->ThrowError("SWScale: mod 2 output width required", AResizer); - - // may one day need a SWS_CS_DEFAULT in flags - Context = sws_getContext(OrigWidth, OrigHeight, ConvertFromFormat, vi.width, vi.height, ConvertToFormat, GetSWSCPUFlags(Env) | Resizer, NULL, NULL, NULL); -} - -SWScale::~SWScale() { - if (Context) - sws_freeContext(Context); -} - -PVideoFrame SWScale::GetFrame(int n, IScriptEnvironment *Env) { - PVideoFrame Src = child->GetFrame(n, Env); - PVideoFrame Dst = Env->NewVideoFrame(vi); - - uint8_t *SrcData[3] = {(uint8_t *)Src->GetReadPtr(PLANAR_Y), (uint8_t *)Src->GetReadPtr(PLANAR_U), (uint8_t *)Src->GetReadPtr(PLANAR_V)}; - int SrcStride[3] = {Src->GetPitch(PLANAR_Y), Src->GetPitch(PLANAR_U), Src->GetPitch(PLANAR_V)}; - - if (FlipOutput) { - uint8_t *DstData[3] = {Dst->GetWritePtr(PLANAR_Y) + Dst->GetPitch(PLANAR_Y) * (Dst->GetHeight(PLANAR_Y) - 1), Dst->GetWritePtr(PLANAR_U) + Dst->GetPitch(PLANAR_U) * (Dst->GetHeight(PLANAR_U) - 1), Dst->GetWritePtr(PLANAR_V) + Dst->GetPitch(PLANAR_V) * (Dst->GetHeight(PLANAR_V) - 1)}; - int DstStride[3] = {-Dst->GetPitch(PLANAR_Y), -Dst->GetPitch(PLANAR_U), -Dst->GetPitch(PLANAR_V)}; - sws_scale(Context, SrcData, SrcStride, 0, OrigHeight, DstData, DstStride); - } else { - uint8_t *DstData[3] = {Dst->GetWritePtr(PLANAR_Y), Dst->GetWritePtr(PLANAR_U), Dst->GetWritePtr(PLANAR_V)}; - int DstStride[3] = {Dst->GetPitch(PLANAR_Y), Dst->GetPitch(PLANAR_U), Dst->GetPitch(PLANAR_V)}; - sws_scale(Context, SrcData, SrcStride, 0, OrigHeight, DstData, DstStride); - } - - return Dst; -} \ No newline at end of file diff --git a/FFmpegSource/matroskacodecs.cpp b/FFmpegSource/matroskacodecs.cpp deleted file mode 100644 index bf5f87f21..000000000 --- a/FFmpegSource/matroskacodecs.cpp +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "ffmpegsource.h" - -CodecID MatroskaToFFCodecID(TrackInfo *TI) { - char *Codec = TI->CodecID; -/* Video Codecs */ - if (!strcmp(Codec, "V_MS/VFW/FOURCC")) { - // fourcc list from ffdshow - switch (((BITMAPINFOHEADER *)TI->CodecPrivate)->biCompression) { - case MAKEFOURCC('F', 'F', 'D', 'S'): - case MAKEFOURCC('F', 'V', 'F', 'W'): - case MAKEFOURCC('X', 'V', 'I', 'D'): - case MAKEFOURCC('D', 'I', 'V', 'X'): - case MAKEFOURCC('D', 'X', '5', '0'): - case MAKEFOURCC('M', 'P', '4', 'V'): - case MAKEFOURCC('3', 'I', 'V', 'X'): - case MAKEFOURCC('W', 'V', '1', 'F'): - case MAKEFOURCC('F', 'M', 'P', '4'): - case MAKEFOURCC('S', 'M', 'P', '4'): - return CODEC_ID_MPEG4; - case MAKEFOURCC('D', 'I', 'V', '3'): - case MAKEFOURCC('D', 'V', 'X', '3'): - case MAKEFOURCC('M', 'P', '4', '3'): - return CODEC_ID_MSMPEG4V3; - case MAKEFOURCC('M', 'P', '4', '2'): - return CODEC_ID_MSMPEG4V2; - case MAKEFOURCC('M', 'P', '4', '1'): - return CODEC_ID_MSMPEG4V1; - case MAKEFOURCC('W', 'M', 'V', '1'): - return CODEC_ID_WMV1; - case MAKEFOURCC('W', 'M', 'V', '2'): - return CODEC_ID_WMV2; - case MAKEFOURCC('W', 'M', 'V', '3'): - return CODEC_ID_WMV3; -/* - case MAKEFOURCC('M', 'S', 'S', '1'): - case MAKEFOURCC('M', 'S', 'S', '2'): - case MAKEFOURCC('W', 'V', 'P', '2'): - case MAKEFOURCC('W', 'M', 'V', 'P'): - return CODEC_ID_WMV9_LIB; -*/ - case MAKEFOURCC('W', 'V', 'C', '1'): - return CODEC_ID_VC1; - case MAKEFOURCC('V', 'P', '5', '0'): - return CODEC_ID_VP5; - case MAKEFOURCC('V', 'P', '6', '0'): - case MAKEFOURCC('V', 'P', '6', '1'): - case MAKEFOURCC('V', 'P', '6', '2'): - return CODEC_ID_VP6; - case MAKEFOURCC('V', 'P', '6', 'F'): - case MAKEFOURCC('F', 'L', 'V', '4'): - return CODEC_ID_VP6F; - case MAKEFOURCC('C', 'A', 'V', 'S'): - return CODEC_ID_CAVS; - case MAKEFOURCC('M', 'P', 'G', '1'): - case MAKEFOURCC('M', 'P', 'E', 'G'): - return CODEC_ID_MPEG2VIDEO; // not a typo - case MAKEFOURCC('M', 'P', 'G', '2'): - case MAKEFOURCC('E', 'M', '2', 'V'): - case MAKEFOURCC('M', 'M', 'E', 'S'): - return CODEC_ID_MPEG2VIDEO; - case MAKEFOURCC('H', '2', '6', '3'): - case MAKEFOURCC('S', '2', '6', '3'): - case MAKEFOURCC('L', '2', '6', '3'): - case MAKEFOURCC('M', '2', '6', '3'): - case MAKEFOURCC('U', '2', '6', '3'): - case MAKEFOURCC('X', '2', '6', '3'): - return CODEC_ID_H263; - case MAKEFOURCC('H', '2', '6', '4'): - case MAKEFOURCC('X', '2', '6', '4'): - case MAKEFOURCC('V', 'S', 'S', 'H'): - case MAKEFOURCC('D', 'A', 'V', 'C'): - case MAKEFOURCC('P', 'A', 'V', 'C'): - case MAKEFOURCC('A', 'V', 'C', '1'): - return CODEC_ID_H264; - case MAKEFOURCC('M', 'J', 'P', 'G'): - case MAKEFOURCC('L', 'J', 'P', 'G'): - case MAKEFOURCC('M', 'J', 'L', 'S'): - case MAKEFOURCC('J', 'P', 'E', 'G'): // questionable fourcc? - case MAKEFOURCC('A', 'V', 'R', 'N'): - case MAKEFOURCC('M', 'J', 'P', 'A'): - return CODEC_ID_MJPEG; - case MAKEFOURCC('D', 'V', 'S', 'D'): - case MAKEFOURCC('D', 'V', '2', '5'): - case MAKEFOURCC('D', 'V', '5', '0'): - case MAKEFOURCC('C', 'D', 'V', 'C'): - case MAKEFOURCC('C', 'D', 'V', '5'): - case MAKEFOURCC('D', 'V', 'I', 'S'): - case MAKEFOURCC('P', 'D', 'V', 'C'): - return CODEC_ID_DVVIDEO; - case MAKEFOURCC('H', 'F', 'Y', 'U'): - return CODEC_ID_HUFFYUV; - case MAKEFOURCC('F', 'F', 'V', 'H'): - return CODEC_ID_FFVHUFF; - case MAKEFOURCC('C', 'Y', 'U', 'V'): - return CODEC_ID_CYUV; - case MAKEFOURCC('A', 'S', 'V', '1'): - return CODEC_ID_ASV1; - case MAKEFOURCC('A', 'S', 'V', '2'): - return CODEC_ID_ASV2; - case MAKEFOURCC('V', 'C', 'R', '1'): - return CODEC_ID_VCR1; - case MAKEFOURCC('T', 'H', 'E', 'O'): - return CODEC_ID_THEORA; - case MAKEFOURCC('S', 'V', 'Q', '1'): - return CODEC_ID_SVQ1; - case MAKEFOURCC('S', 'V', 'Q', '3'): - return CODEC_ID_SVQ3; - case MAKEFOURCC('R', 'P', 'Z', 'A'): - return CODEC_ID_RPZA; - case MAKEFOURCC('F', 'F', 'V', '1'): - return CODEC_ID_FFV1; - case MAKEFOURCC('V', 'P', '3', '1'): - return CODEC_ID_VP3; - case MAKEFOURCC('R', 'L', 'E', '8'): - return CODEC_ID_MSRLE; - case MAKEFOURCC('M', 'S', 'Z', 'H'): - return CODEC_ID_MSZH; - case MAKEFOURCC('Z', 'L', 'I', 'B'): - return CODEC_ID_ZLIB; - case MAKEFOURCC('F', 'L', 'V', '1'): - return CODEC_ID_FLV1; -/* - case MAKEFOURCC('P', 'N', 'G', '1'): - return CODEC_ID_COREPNG; -*/ - case MAKEFOURCC('M', 'P', 'N', 'G'): - return CODEC_ID_PNG; -/* - case MAKEFOURCC('A', 'V', 'I', 'S'): - return CODEC_ID_AVISYNTH; -*/ - case MAKEFOURCC('C', 'R', 'A', 'M'): - return CODEC_ID_MSVIDEO1; - case MAKEFOURCC('R', 'T', '2', '1'): - return CODEC_ID_INDEO2; - case MAKEFOURCC('I', 'V', '3', '2'): - case MAKEFOURCC('I', 'V', '3', '1'): - return CODEC_ID_INDEO3; - case MAKEFOURCC('C', 'V', 'I', 'D'): - return CODEC_ID_CINEPAK; - case MAKEFOURCC('R', 'V', '1', '0'): - return CODEC_ID_RV10; - case MAKEFOURCC('R', 'V', '2', '0'): - return CODEC_ID_RV20; - case MAKEFOURCC('8', 'B', 'P', 'S'): - return CODEC_ID_8BPS; - case MAKEFOURCC('Q', 'R', 'L', 'E'): - return CODEC_ID_QTRLE; - case MAKEFOURCC('D', 'U', 'C', 'K'): - return CODEC_ID_TRUEMOTION1; - case MAKEFOURCC('T', 'M', '2', '0'): - return CODEC_ID_TRUEMOTION2; - case MAKEFOURCC('T', 'S', 'C', 'C'): - return CODEC_ID_TSCC; - case MAKEFOURCC('S', 'N', 'O', 'W'): - return CODEC_ID_SNOW; - case MAKEFOURCC('Q', 'P', 'E', 'G'): - case MAKEFOURCC('Q', '1', '_', '0'): - case MAKEFOURCC('Q', '1', '_', '1'): - return CODEC_ID_QPEG; - case MAKEFOURCC('H', '2', '6', '1'): - case MAKEFOURCC('M', '2', '6', '1'): - return CODEC_ID_H261; - case MAKEFOURCC('L', 'O', 'C', 'O'): - return CODEC_ID_LOCO; - case MAKEFOURCC('W', 'N', 'V', '1'): - return CODEC_ID_WNV1; - case MAKEFOURCC('C', 'S', 'C', 'D'): - return CODEC_ID_CSCD; - case MAKEFOURCC('Z', 'M', 'B', 'V'): - return CODEC_ID_ZMBV; - case MAKEFOURCC('U', 'L', 'T', 'I'): - return CODEC_ID_ULTI; - case MAKEFOURCC('V', 'I', 'X', 'L'): - return CODEC_ID_VIXL; - case MAKEFOURCC('A', 'A', 'S', 'C'): - return CODEC_ID_AASC; - case MAKEFOURCC('F', 'P', 'S', '1'): - return CODEC_ID_FRAPS; - default: - return CODEC_ID_NONE; - } - - } else if (!strcmp(Codec, "V_MPEG4/ISO/AVC")) - return CODEC_ID_H264; - else if (!strcmp(Codec, "V_MPEG4/ISO/AP")) - return CODEC_ID_MPEG4; - else if (!strcmp(Codec, "V_MPEG4/ISO/ASP")) - return CODEC_ID_MPEG4; - else if (!strcmp(Codec, "V_MPEG4/ISO/SP")) - return CODEC_ID_MPEG4; - else if (!strcmp(Codec, "V_MPEG4/MS/V3")) - return CODEC_ID_MSMPEG4V3; - else if (!strcmp(Codec, "V_MPEG2")) - return CODEC_ID_MPEG2VIDEO; - else if (!strcmp(Codec, "V_MPEG1")) - return CODEC_ID_MPEG2VIDEO; // still not a typo - else if (!strcmp(Codec, "V_VC1")) - return CODEC_ID_VC1; - else if (!strcmp(Codec, "V_SNOW")) - return CODEC_ID_SNOW; - else if (!strcmp(Codec, "V_THEORA")) - return CODEC_ID_THEORA; - else if (!strcmp(Codec, "V_UNCOMPRESSED")) - return CODEC_ID_NONE; // bleh - else if (!strcmp(Codec, "V_QUICKTIME")) - return CODEC_ID_SVQ3; - else if (!strcmp(Codec, "V_CIPC")) - return CODEC_ID_NONE; // don't know, don't care - else if (!strncmp(Codec, "V_REAL/RV", 9)) { - switch (Codec[9]) { - case '1': - return CODEC_ID_RV10; - case '2': - return CODEC_ID_RV20; - case '3': - return CODEC_ID_RV30; - case '4': - return CODEC_ID_RV40; - default: - return CODEC_ID_NONE; - } -/* Audio Codecs */ - } else if (!strcmp(Codec, "A_AC3")) - return CODEC_ID_AC3; - else if (!strcmp(Codec, "A_EAC3")) - return CODEC_ID_AC3; - else if (!strcmp(Codec, "A_MPEG/L3")) - return CODEC_ID_MP3; - else if (!strcmp(Codec, "A_MPEG/L2")) - return CODEC_ID_MP2; - else if (!strcmp(Codec, "A_MPEG/L1")) - return CODEC_ID_MP2; // correct? - else if (!strcmp(Codec, "A_DTS")) - return CODEC_ID_DTS; - else if (!strcmp(Codec, "A_PCM/INT/LIT")) { - switch (TI->AV.Audio.BitDepth) { - case 8: return CODEC_ID_PCM_S8; - case 16: return CODEC_ID_PCM_S16LE; - case 24: return CODEC_ID_PCM_S24LE; - case 32: return CODEC_ID_PCM_S32LE; - default: return CODEC_ID_NONE; - } - } else if (!strcmp(Codec, "A_PCM/INT/BIG")) { - switch (TI->AV.Audio.BitDepth) { - case 8: return CODEC_ID_PCM_S8; - case 16: return CODEC_ID_PCM_S16BE; - case 24: return CODEC_ID_PCM_S24BE; - case 32: return CODEC_ID_PCM_S32BE; - default: return CODEC_ID_NONE; - } - } else if (!strcmp(Codec, "A_PCM/FLOAT/IEEE")) - return CODEC_ID_NONE; // no float codec id? - else if (!strcmp(Codec, "A_FLAC")) - return CODEC_ID_FLAC; - else if (!strcmp(Codec, "A_MPC")) - return CODEC_ID_MUSEPACK8; - else if (!strcmp(Codec, "A_TTA1")) - return CODEC_ID_TTA; - else if (!strcmp(Codec, "A_WAVPACK4")) - return CODEC_ID_WAVPACK; - else if (!strcmp(Codec, "A_VORBIS")) - return CODEC_ID_VORBIS; - else if (!strcmp(Codec, "A_REAL/14_4")) - return CODEC_ID_RA_144; - else if (!strcmp(Codec, "A_REAL/28_8")) - return CODEC_ID_RA_288; - else if (!strcmp(Codec, "A_REAL/COOK")) - return CODEC_ID_COOK; - else if (!strcmp(Codec, "A_REAL/SIPR")) - return CODEC_ID_NONE; // no sipr codec id? - else if (!strcmp(Codec, "A_REAL/ATRC")) - return CODEC_ID_ATRAC3; - else if (!strncmp(Codec, "A_AAC", 5)) - return CODEC_ID_AAC; - else if (!strcmp(Codec, "A_SPEEX")) - return CODEC_ID_SPEEX; - else if (!strcmp(Codec, "A_QUICKTIME")) - return CODEC_ID_NONE; // no - else if (!strcmp(Codec, "A_MS/ACM")) { - // nothing useful here anyway? - //#include "Mmreg.h" - //((WAVEFORMATEX *)TI->CodecPrivate)->wFormatTag - return CODEC_ID_NONE; - } else - return CODEC_ID_NONE; -} diff --git a/FFmpegSource/stdiostream.c b/FFmpegSource/stdiostream.c deleted file mode 100644 index b660ff7d1..000000000 --- a/FFmpegSource/stdiostream.c +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "stdiostream.h" - -/* StdIoStream methods */ - -/* read count bytes into buffer starting at file position pos - * return the number of bytes read, -1 on error or 0 on EOF - */ -int StdIoRead(StdIoStream *st, ulonglong pos, void *buffer, int count) { - size_t rd; - if (_fseeki64(st->fp, pos, SEEK_SET)) { - st->error = errno; - return -1; - } - rd = fread(buffer, 1, count, st->fp); - if (rd == 0) { - if (feof(st->fp)) - return 0; - st->error = errno; - return -1; - } - return rd; -} - -/* scan for a signature sig(big-endian) starting at file position pos - * return position of the first byte of signature or -1 if error/not found - */ -longlong StdIoScan(StdIoStream *st, ulonglong start, unsigned signature) { - int c; - unsigned cmp = 0; - FILE *fp = st->fp; - - if (_fseeki64(fp, start, SEEK_SET)) - return -1; - - while ((c = getc(fp)) != EOF) { - cmp = ((cmp << 8) | c) & 0xffffffff; - if (cmp == signature) - return _ftelli64(fp) - 4; - } - - return -1; -} - -/* return cache size, this is used to limit readahead */ -unsigned StdIoGetCacheSize(StdIoStream *st) { - return CACHESIZE; -} - -/* return last error message */ -const char *StdIoGetLastError(StdIoStream *st) { - return strerror(st->error); -} - -/* memory allocation, this is done via stdlib */ -void *StdIoMalloc(StdIoStream *st, size_t size) { - return malloc(size); -} - -void *StdIoRealloc(StdIoStream *st, void *mem, size_t size) { - return realloc(mem,size); -} - -void StdIoFree(StdIoStream *st, void *mem) { - free(mem); -} - -/* progress report handler for lengthy operations - * returns 0 to abort operation, nonzero to continue - */ -int StdIoProgress(StdIoStream *st, ulonglong cur, ulonglong max) { - return 1; -} diff --git a/FFmpegSource/stdiostream.h b/FFmpegSource/stdiostream.h deleted file mode 100644 index eaf74d28e..000000000 --- a/FFmpegSource/stdiostream.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2007-2008 Fredrik Mellbin -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef STDIOSTREAM_H -#define STDIOSTREAM_H - -#include -#include -#include -#include -#include -#include -#include "MatroskaParser.h" - -#define CACHESIZE 65536 - -/************\ -* Structures * -\************/ - -/* first we need to create an I/O object that the parser will use to read the - * source file - */ -struct StdIoStream { - struct InputStream base; - FILE *fp; - int error; -}; - -typedef struct StdIoStream StdIoStream; - -/***********\ -* Functions * -\***********/ - -/* read count bytes into buffer starting at file position pos - * return the number of bytes read, -1 on error or 0 on EOF - */ -int StdIoRead(StdIoStream *st, ulonglong pos, void *buffer, int count); - -/* scan for a signature sig(big-endian) starting at file position pos - * return position of the first byte of signature or -1 if error/not found - */ -longlong StdIoScan(StdIoStream *st, ulonglong start, unsigned signature); - -/* return cache size, this is used to limit readahead */ -unsigned StdIoGetCacheSize(StdIoStream *st); - -/* return last error message */ -const char *StdIoGetLastError(StdIoStream *st); - -/* memory allocation, this is done via stdlib */ -void *StdIoMalloc(StdIoStream *st, size_t size); - -void *StdIoRealloc(StdIoStream *st, void *mem, size_t size); - -void StdIoFree(StdIoStream *st, void *mem); - -/* progress report handler for lengthy operations - * returns 0 to abort operation, nonzero to continue - */ -int StdIoProgress(StdIoStream *st, ulonglong cur, ulonglong max); - - -#endif /* #ifndef STDIOSTREAM_H */