mirror of https://github.com/odrling/Aegisub
Matroska parsing implemented
Originally committed to SVN as r120.
This commit is contained in:
parent
2b27d5403e
commit
2216528544
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,398 @@
|
||||||
|
/*
|
||||||
|
* 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.18.2.6 2006/01/13 01:44:45 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;
|
||||||
|
ulonglong DateUTC;
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,296 @@
|
||||||
|
// Copyright (c) 2004-2006, Rodrigo Braz Monteiro, 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:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * 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.
|
||||||
|
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||||
|
// may be used to endorse or promote products derived from this software
|
||||||
|
// without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// AEGISUB
|
||||||
|
//
|
||||||
|
// Website: http://aegisub.cellosoft.com
|
||||||
|
// Contact: mailto:zeratul@cellosoft.com
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
///////////
|
||||||
|
// Headers
|
||||||
|
#include <algorithm>
|
||||||
|
#include "mkv_wrap.h"
|
||||||
|
|
||||||
|
|
||||||
|
///////////
|
||||||
|
// Defines
|
||||||
|
#define CACHESIZE 65536
|
||||||
|
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
// Constructor
|
||||||
|
MatroskaWrapper::MatroskaWrapper() {
|
||||||
|
file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////
|
||||||
|
// Destructor
|
||||||
|
MatroskaWrapper::~MatroskaWrapper() {
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// Open file
|
||||||
|
void MatroskaWrapper::Open(wxString filename) {
|
||||||
|
// Make sure it's closed first
|
||||||
|
Close();
|
||||||
|
|
||||||
|
// Open
|
||||||
|
char err[2048];
|
||||||
|
input = new MkvStdIO(filename);
|
||||||
|
if (input->fp) {
|
||||||
|
file = mkv_Open(input,err,sizeof(err));
|
||||||
|
|
||||||
|
// Failed parsing
|
||||||
|
if (!file) {
|
||||||
|
delete input;
|
||||||
|
throw wxString(_T("MatroskaParser error: ") + wxString(err,wxConvUTF8)).c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
Parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed opening
|
||||||
|
else {
|
||||||
|
delete input;
|
||||||
|
throw _T("Unable to open Matroska file for parsing.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////
|
||||||
|
// Close file
|
||||||
|
void MatroskaWrapper::Close() {
|
||||||
|
if (file) {
|
||||||
|
mkv_Close(file);
|
||||||
|
file = NULL;
|
||||||
|
fclose(input->fp);
|
||||||
|
delete input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// Return keyframes
|
||||||
|
wxArrayInt MatroskaWrapper::GetKeyFrames() {
|
||||||
|
return keyFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Comparison operator
|
||||||
|
bool operator < (MkvFrame &t1, MkvFrame &t2) {
|
||||||
|
return t1.time < t2.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////
|
||||||
|
// Actually parse
|
||||||
|
void MatroskaWrapper::Parse() {
|
||||||
|
// Clear keyframes and timecodes
|
||||||
|
keyFrames.Clear();
|
||||||
|
timecodes.clear();
|
||||||
|
std::list<MkvFrame> frames;
|
||||||
|
|
||||||
|
// Get info
|
||||||
|
int tracks = mkv_GetNumTracks(file);
|
||||||
|
TrackInfo *trackInfo;
|
||||||
|
SegmentInfo *segInfo = mkv_GetFileInfo(file);
|
||||||
|
|
||||||
|
// Parse tracks
|
||||||
|
for (int track=0;track<tracks;track++) {
|
||||||
|
trackInfo = mkv_GetTrackInfo(file,track);
|
||||||
|
|
||||||
|
// Video track
|
||||||
|
if (trackInfo->Type == 1) {
|
||||||
|
// Variables
|
||||||
|
ulonglong startTime, endTime, filePos;
|
||||||
|
unsigned int rt, frameSize, frameFlags;
|
||||||
|
CompressedStream *cs = NULL;
|
||||||
|
|
||||||
|
// Timecode scale
|
||||||
|
__int64 timecodeScale = mkv_TruncFloat(trackInfo->TimecodeScale) * segInfo->TimecodeScale;
|
||||||
|
|
||||||
|
// Mask other tracks away
|
||||||
|
mkv_SetTrackMask(file, ~(1 << track));
|
||||||
|
|
||||||
|
// Read frames
|
||||||
|
int frameN = 0;
|
||||||
|
while (mkv_ReadFrame(file,0,&rt,&startTime,&endTime,&filePos,&frameSize,&frameFlags) == 0) {
|
||||||
|
frames.push_back(MkvFrame((frameFlags & FRAME_KF) != 0,double(startTime) / timecodeScale));
|
||||||
|
frameN++;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process timecodes and keyframes
|
||||||
|
frames.sort();
|
||||||
|
MkvFrame curFrame(false,0);
|
||||||
|
int i = 0;
|
||||||
|
for (std::list<MkvFrame>::iterator cur=frames.begin();cur!=frames.end();cur++) {
|
||||||
|
curFrame = *cur;
|
||||||
|
if (curFrame.isKey) keyFrames.Add(i);
|
||||||
|
timecodes.push_back(curFrame.time);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// Set target to timecodes
|
||||||
|
void MatroskaWrapper::SetToTimecodes(FrameRate &target) {
|
||||||
|
// Enough frames?
|
||||||
|
int frames = timecodes.size();
|
||||||
|
if (frames <= 1) return;
|
||||||
|
|
||||||
|
// Sort
|
||||||
|
//std::sort<std::vector<double>::iterator>(timecodes.begin(),timecodes.end());
|
||||||
|
|
||||||
|
// Check if it's CFR
|
||||||
|
bool isCFR = true;
|
||||||
|
double estimateCFR = timecodes.back() / timecodes.size()-1;
|
||||||
|
double curTime = 0;
|
||||||
|
for (int i=0;i<frames;i++) {
|
||||||
|
int delta = int(curTime - timecodes[i]);
|
||||||
|
if (abs(delta > 1)) {
|
||||||
|
isCFR = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
curTime += estimateCFR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constant framerate
|
||||||
|
if (isCFR) {
|
||||||
|
if (abs(estimateCFR - 23.976) < 0.01) estimateCFR = 23.976;
|
||||||
|
if (abs(estimateCFR - 29.97) < 0.01) estimateCFR = 29.97;
|
||||||
|
target.SetCFR(estimateCFR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variable framerate
|
||||||
|
else {
|
||||||
|
std::vector<int> times;
|
||||||
|
for (int i=0;i<frames;i++) times.push_back(int(timecodes[i]+0.5));
|
||||||
|
target.SetVFR(times);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////// LOTS OF HAALI C CODE DOWN HERE ///////////////////////////////////////
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
// STDIO class
|
||||||
|
int StdIoRead(InputStream *_st, ulonglong pos, void *buffer, int count) {
|
||||||
|
MkvStdIO *st = (MkvStdIO *) _st;
|
||||||
|
size_t rd;
|
||||||
|
if (fseek(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(InputStream *_st, ulonglong start, unsigned signature) {
|
||||||
|
MkvStdIO *st = (MkvStdIO *) _st;
|
||||||
|
int c;
|
||||||
|
unsigned cmp = 0;
|
||||||
|
FILE *fp = st->fp;
|
||||||
|
|
||||||
|
if (fseek(fp, start, SEEK_SET))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while ((c = getc(fp)) != EOF) {
|
||||||
|
cmp = ((cmp << 8) | c) & 0xffffffff;
|
||||||
|
if (cmp == signature)
|
||||||
|
return ftell(fp) - 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return cache size, this is used to limit readahead */
|
||||||
|
unsigned StdIoGetCacheSize(InputStream *_st) {
|
||||||
|
return CACHESIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return last error message */
|
||||||
|
const char *StdIoGetLastError(InputStream *_st) {
|
||||||
|
MkvStdIO *st = (MkvStdIO *) _st;
|
||||||
|
return strerror(st->error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* memory allocation, this is done via stdlib */
|
||||||
|
void *StdIoMalloc(InputStream *_st, size_t size) {
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *StdIoRealloc(InputStream *_st, void *mem, size_t size) {
|
||||||
|
return realloc(mem,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StdIoFree(InputStream *_st, void *mem) {
|
||||||
|
free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
int StdIoProgress(InputStream *_st, ulonglong cur, ulonglong max) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MkvStdIO::MkvStdIO(wxString filename) {
|
||||||
|
read = StdIoRead;
|
||||||
|
scan = StdIoScan;
|
||||||
|
getcachesize = StdIoGetCacheSize;
|
||||||
|
geterror = StdIoGetLastError;
|
||||||
|
memalloc = StdIoMalloc;
|
||||||
|
memrealloc = StdIoRealloc;
|
||||||
|
memfree = StdIoFree;
|
||||||
|
progress = StdIoProgress;
|
||||||
|
fp = fopen(filename.mb_str(),"rb");
|
||||||
|
if (fp) {
|
||||||
|
setvbuf(fp, NULL, _IOFBF, CACHESIZE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
// Copyright (c) 2006, Rodrigo Braz Monteiro
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
// * 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.
|
||||||
|
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||||
|
// may be used to endorse or promote products derived from this software
|
||||||
|
// without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// AEGISUB
|
||||||
|
//
|
||||||
|
// Website: http://aegisub.cellosoft.com
|
||||||
|
// Contact: mailto:zeratul@cellosoft.com
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
///////////
|
||||||
|
// Headers
|
||||||
|
#include <wx/wxprec.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <vector>
|
||||||
|
#include "MatroskaParser.h"
|
||||||
|
#include "vfr.h"
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////
|
||||||
|
// STD IO for MatroskaParser
|
||||||
|
class MkvStdIO : public InputStream {
|
||||||
|
public:
|
||||||
|
MkvStdIO(wxString filename);
|
||||||
|
FILE *fp;
|
||||||
|
int error;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////
|
||||||
|
// MkvFrame class
|
||||||
|
class MkvFrame {
|
||||||
|
public:
|
||||||
|
double time;
|
||||||
|
bool isKey;
|
||||||
|
|
||||||
|
MkvFrame(bool keyframe,double timecode) {
|
||||||
|
isKey = keyframe;
|
||||||
|
time = timecode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator < (MkvFrame &t1, MkvFrame &t2);
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Matroska wrapper class
|
||||||
|
class MatroskaWrapper {
|
||||||
|
private:
|
||||||
|
MatroskaFile *file;
|
||||||
|
MkvStdIO *input;
|
||||||
|
wxArrayInt keyFrames;
|
||||||
|
std::vector<double> timecodes;
|
||||||
|
|
||||||
|
void Parse();
|
||||||
|
|
||||||
|
public:
|
||||||
|
MatroskaWrapper();
|
||||||
|
~MatroskaWrapper();
|
||||||
|
|
||||||
|
void Open(wxString filename);
|
||||||
|
void Close();
|
||||||
|
void SetToTimecodes(FrameRate &target);
|
||||||
|
wxArrayInt GetKeyFrames();
|
||||||
|
};
|
18
core/vfr.cpp
18
core/vfr.cpp
|
@ -314,6 +314,24 @@ void FrameRate::SetCFR(double fps,bool ifunset) {
|
||||||
AverageFrameRate = fps;
|
AverageFrameRate = fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
// Sets to VFR
|
||||||
|
void FrameRate::SetVFR(std::vector<int> newTimes) {
|
||||||
|
// Prepare
|
||||||
|
Unload();
|
||||||
|
loaded = true;
|
||||||
|
vfrFile = _T("");
|
||||||
|
FrameRateType = VFR;
|
||||||
|
|
||||||
|
// Set new VFR
|
||||||
|
AverageFrameRate = newTimes.back() / (newTimes.size()-1);
|
||||||
|
Frame = newTimes;
|
||||||
|
last_time = newTimes.back();
|
||||||
|
last_frame = newTimes.size()-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Get correct frame at time
|
// Get correct frame at time
|
||||||
// returns the adjusted time for end frames when start=false
|
// returns the adjusted time for end frames when start=false
|
||||||
|
|
|
@ -70,16 +70,18 @@ private:
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
void CalcAverage();
|
void CalcAverage();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FrameRate();
|
FrameRate();
|
||||||
~FrameRate();
|
~FrameRate();
|
||||||
|
|
||||||
|
|
||||||
wxString vfrFile;
|
wxString vfrFile;
|
||||||
bool loaded;
|
bool loaded;
|
||||||
ASS_FrameRateType FrameRateType;
|
ASS_FrameRateType FrameRateType;
|
||||||
|
|
||||||
void SetCFR(double fps,bool ifunset=false);
|
void SetCFR(double fps,bool ifunset=false);
|
||||||
|
void SetVFR(std::vector<int> times);
|
||||||
|
|
||||||
void Load(wxString file);
|
void Load(wxString file);
|
||||||
void Unload();
|
void Unload();
|
||||||
int GetFrameAtTime(int ms);
|
int GetFrameAtTime(int ms);
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "vfw_wrap.h"
|
#include "vfw_wrap.h"
|
||||||
|
#include "mkv_wrap.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "audio_display.h"
|
#include "audio_display.h"
|
||||||
|
@ -159,10 +160,25 @@ void VideoDisplay::SetVideo(const wxString &filename) {
|
||||||
provider = new VideoProvider(filename,GetTempWorkFile(),zoomValue,usedDirectshow,true);
|
provider = new VideoProvider(filename,GetTempWorkFile(),zoomValue,usedDirectshow,true);
|
||||||
|
|
||||||
// Set keyframes
|
// Set keyframes
|
||||||
if (filename.Right(4).Lower() == _T(".avi"))
|
wxString ext = filename.Right(4).Lower();
|
||||||
KeyFrames = VFWWrapper::GetKeyFrames(filename);
|
if (ext == _T(".avi")) KeyFrames = VFWWrapper::GetKeyFrames(filename);
|
||||||
else
|
else if (ext == _T(".mkv")) {
|
||||||
KeyFrames.Clear();
|
// Parse mkv
|
||||||
|
MatroskaWrapper mkvwrap;
|
||||||
|
mkvwrap.Open(filename);
|
||||||
|
|
||||||
|
// Get keyframes
|
||||||
|
KeyFrames = mkvwrap.GetKeyFrames();
|
||||||
|
|
||||||
|
// Ask to override timecodes
|
||||||
|
int override = wxYES;
|
||||||
|
if (VFR_Output.FrameRateType == VFR) override = wxMessageBox(_T("You already have timecodes loaded. Replace them with the timecodes from the Matroska file?"),_T("Replace timecodes?"),wxYES_NO | wxICON_QUESTION);
|
||||||
|
if (override == wxYES) mkvwrap.SetToTimecodes(VFR_Output);
|
||||||
|
|
||||||
|
// Close mkv
|
||||||
|
mkvwrap.Close();
|
||||||
|
}
|
||||||
|
else KeyFrames.Clear();
|
||||||
|
|
||||||
UpdateSize();
|
UpdateSize();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue