Matroska parsing implemented

Originally committed to SVN as r120.
This commit is contained in:
Rodrigo Braz Monteiro 2006-02-23 01:44:48 +00:00
parent 2b27d5403e
commit 2216528544
7 changed files with 4138 additions and 5 deletions

3309
core/MatroskaParser.c Normal file

File diff suppressed because it is too large Load Diff

398
core/MatroskaParser.h Normal file
View File

@ -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

296
core/mkv_wrap.cpp Normal file
View File

@ -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);
}
}

94
core/mkv_wrap.h Normal file
View File

@ -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();
};

View File

@ -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

View File

@ -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);

View File

@ -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();