mirror of https://github.com/odrling/Aegisub
FFmpegSource2: fix lots of memory leaks, improve the api, add a progress callback
Originally committed to SVN as r2315.
This commit is contained in:
parent
b2153dd6cf
commit
19f9172d64
|
@ -54,12 +54,14 @@ AVSValue __cdecl CreateFFIndex(AVSValue Args, void* UserData, IScriptEnvironment
|
||||||
// 1: Index generated
|
// 1: Index generated
|
||||||
// 2: Index forced to be overwritten
|
// 2: Index forced to be overwritten
|
||||||
|
|
||||||
FrameIndex *Index = FFMS_CreateFrameIndex();
|
FrameIndex *Index;
|
||||||
if (OverWrite || FFMS_ReadIndex(CacheFile, Index, ErrorMsg, MsgSize)) {
|
if (OverWrite || !(Index = FFMS_ReadIndex(CacheFile, ErrorMsg, MsgSize))) {
|
||||||
if (FFMS_MakeIndex(Source, Index, TrackMask, AudioFile, NULL, ErrorMsg, MsgSize))
|
if (!(Index = FFMS_MakeIndex(Source, TrackMask, AudioFile, NULL, NULL, ErrorMsg, MsgSize)))
|
||||||
Env->ThrowError("FFIndex: %s", ErrorMsg);
|
Env->ThrowError("FFIndex: %s", ErrorMsg);
|
||||||
if (FFMS_WriteIndex(CacheFile, Index, ErrorMsg, MsgSize))
|
if (FFMS_WriteIndex(CacheFile, Index, ErrorMsg, MsgSize)) {
|
||||||
|
FFMS_DestroyFrameIndex(Index);
|
||||||
Env->ThrowError("FFIndex: %s", ErrorMsg);
|
Env->ThrowError("FFIndex: %s", ErrorMsg);
|
||||||
|
}
|
||||||
FFMS_DestroyFrameIndex(Index);
|
FFMS_DestroyFrameIndex(Index);
|
||||||
if (!OverWrite)
|
if (!OverWrite)
|
||||||
return AVSValue(1);
|
return AVSValue(1);
|
||||||
|
@ -100,28 +102,44 @@ AVSValue __cdecl CreateFFVideoSource(AVSValue Args, void* UserData, IScriptEnvir
|
||||||
if (Threads < 1)
|
if (Threads < 1)
|
||||||
Env->ThrowError("FFVideoSource: Invalid thread count");
|
Env->ThrowError("FFVideoSource: Invalid thread count");
|
||||||
|
|
||||||
|
if (!_stricmp(Source, Timecodes))
|
||||||
|
Env->ThrowError("FFVideoSource: Timecodes will overwrite the source");
|
||||||
|
|
||||||
std::string DefaultCache(Source);
|
std::string DefaultCache(Source);
|
||||||
DefaultCache.append(".ffindex");
|
DefaultCache.append(".ffindex");
|
||||||
if (!strcmp(CacheFile, ""))
|
if (!strcmp(CacheFile, ""))
|
||||||
CacheFile = DefaultCache.c_str();
|
CacheFile = DefaultCache.c_str();
|
||||||
|
|
||||||
FrameIndex *Index = FFMS_CreateFrameIndex();
|
FrameIndex *Index;
|
||||||
if (Cache) {
|
if (Cache) {
|
||||||
if (FFMS_ReadIndex(CacheFile, Index, ErrorMsg, MsgSize)) {
|
if (!(Index = FFMS_ReadIndex(CacheFile, ErrorMsg, MsgSize))) {
|
||||||
if (FFMS_MakeIndex(Source, Index, 0, NULL, NULL, ErrorMsg, MsgSize))
|
if (!(Index = FFMS_MakeIndex(Source, 0, NULL, NULL, NULL, ErrorMsg, MsgSize)))
|
||||||
Env->ThrowError("FFVideoSource: %s", ErrorMsg);
|
Env->ThrowError("FFVideoSource: %s", ErrorMsg);
|
||||||
|
|
||||||
if (Cache)
|
if (Cache)
|
||||||
if (FFMS_WriteIndex(CacheFile, Index, ErrorMsg, MsgSize))
|
if (FFMS_WriteIndex(CacheFile, Index, ErrorMsg, MsgSize)) {
|
||||||
|
FFMS_DestroyFrameIndex(Index);
|
||||||
Env->ThrowError("FFVideoSource: %s", ErrorMsg);
|
Env->ThrowError("FFVideoSource: %s", ErrorMsg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AvisynthVideoSource *Filter = new AvisynthVideoSource(Source, Track, Index, PP, Threads, SeekMode, Env, ErrorMsg, MsgSize);
|
AvisynthVideoSource *Filter;
|
||||||
|
|
||||||
if (strcmp(Timecodes, ""))
|
try {
|
||||||
if (FFMS_WriteTimecodes(FFMS_GetTITrackIndex(Index, Filter->GetTrack(), ErrorMsg, MsgSize), Timecodes, ErrorMsg, MsgSize))
|
Filter = new AvisynthVideoSource(Source, Track, Index, PP, Threads, SeekMode, Env, ErrorMsg, MsgSize);
|
||||||
|
} catch (...) {
|
||||||
|
FFMS_DestroyFrameIndex(Index);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(Timecodes, "")) {
|
||||||
|
if (FFMS_WriteTimecodes(FFMS_GetTITrackIndex(Index, Filter->GetTrack(), ErrorMsg, MsgSize), Timecodes, ErrorMsg, MsgSize)) {
|
||||||
|
FFMS_DestroyFrameIndex(Index);
|
||||||
|
delete Filter;
|
||||||
Env->ThrowError("FFVideoSource: %s", ErrorMsg);
|
Env->ThrowError("FFVideoSource: %s", ErrorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Filter;
|
return Filter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,10 +53,6 @@ FFMS_API(const AVFrameLite *) FFMS_GetFrame(VideoBase *VB, int n, char *ErrorMsg
|
||||||
return (AVFrameLite *)VB->GetFrame(n, ErrorMsg, MsgSize);
|
return (AVFrameLite *)VB->GetFrame(n, ErrorMsg, MsgSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
FFMS_API(FrameIndex *) FFMS_CreateFrameIndex() {
|
|
||||||
return new FrameIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
FFMS_API(void) FFMS_DestroyFrameIndex(FrameIndex *FI) {
|
FFMS_API(void) FFMS_DestroyFrameIndex(FrameIndex *FI) {
|
||||||
delete FI;
|
delete FI;
|
||||||
}
|
}
|
||||||
|
@ -116,12 +112,12 @@ FFMS_API(int) FFMS_WriteTimecodes(FrameInfoVector *FIV, const char *TimecodeFile
|
||||||
return FIV->WriteTimecodes(TimecodeFile, ErrorMsg, MsgSize);
|
return FIV->WriteTimecodes(TimecodeFile, ErrorMsg, MsgSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
FFMS_API(int) FFMS_MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMask, const char *AudioFile, IndexProgress *IP, char *ErrorMsg, unsigned MsgSize) {
|
FFMS_API(FrameIndex *) FFMS_MakeIndex(const char *SourceFile, int AudioTrackMask, const char *AudioFile, IndexCallback *IP, void *Private, char *ErrorMsg, unsigned MsgSize) {
|
||||||
return MakeIndex(SourceFile, TrackIndices, AudioTrackMask, AudioFile, IP, ErrorMsg, MsgSize);
|
return MakeIndex(SourceFile, AudioTrackMask, AudioFile, IP, Private, ErrorMsg, MsgSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
FFMS_API(int) FFMS_ReadIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize) {
|
FFMS_API(FrameIndex *) FFMS_ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize) {
|
||||||
return ReadIndex(IndexFile, TrackIndices, ErrorMsg, MsgSize);
|
return ReadIndex(IndexFile, ErrorMsg, MsgSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize) {
|
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize) {
|
||||||
|
|
|
@ -31,17 +31,19 @@
|
||||||
# define EXTERN_C
|
# define EXTERN_C
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FFMS_CC __stdcall
|
||||||
|
|
||||||
#ifdef FFMS_EXPORTS
|
#ifdef FFMS_EXPORTS
|
||||||
# define FFMS_API(ret) EXTERN_C __declspec(dllexport) ret __stdcall
|
# define FFMS_API(ret) EXTERN_C __declspec(dllexport) ret FFMS_CC
|
||||||
#else
|
#else
|
||||||
# define FFMS_API(ret) EXTERN_C __declspec(dllimport) ret __stdcall
|
# define FFMS_API(ret) EXTERN_C __declspec(dllimport) ret FFMS_CC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class VideoBase;
|
class VideoBase;
|
||||||
class FrameIndex;
|
class FrameIndex;
|
||||||
class FrameInfoVector;
|
class FrameInfoVector;
|
||||||
|
|
||||||
typedef int (*IndexProgress)(int64_t, int);
|
typedef int (*IndexCallback)(int State, int64_t Current, int64_t Total, void *Private);
|
||||||
|
|
||||||
// This is a subset of the original AVFrame only containing the most used parts.
|
// This is a subset of the original AVFrame only containing the most used parts.
|
||||||
// Even if it might seem like a good idea to cast it back to a full AVFrame to
|
// Even if it might seem like a good idea to cast it back to a full AVFrame to
|
||||||
|
@ -89,7 +91,6 @@ FFMS_API(void) FFMS_DestroyVideoSource(VideoBase *VB);
|
||||||
FFMS_API(int) FFMS_GetVSTrack(VideoBase *VB);
|
FFMS_API(int) FFMS_GetVSTrack(VideoBase *VB);
|
||||||
FFMS_API(const VideoProperties *) FFMS_GetVideoProperties(VideoBase *VB);
|
FFMS_API(const VideoProperties *) FFMS_GetVideoProperties(VideoBase *VB);
|
||||||
FFMS_API(const AVFrameLite *) FFMS_GetFrame(VideoBase *VB, int n, char *ErrorMsg, unsigned MsgSize);
|
FFMS_API(const AVFrameLite *) FFMS_GetFrame(VideoBase *VB, int n, char *ErrorMsg, unsigned MsgSize);
|
||||||
FFMS_API(FrameIndex *) FFMS_CreateFrameIndex();
|
|
||||||
FFMS_API(void) FFMS_DestroyFrameIndex(FrameIndex *FI);
|
FFMS_API(void) FFMS_DestroyFrameIndex(FrameIndex *FI);
|
||||||
FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
||||||
FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize);
|
FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize);
|
||||||
|
@ -101,8 +102,8 @@ FFMS_API(int) FFMS_FrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMs
|
||||||
FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize);
|
FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize);
|
||||||
FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize);
|
FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize);
|
||||||
FFMS_API(int) FFMS_WriteTimecodes(FrameInfoVector *FIV, const char *TimecodeFile, char *ErrorMsg, unsigned MsgSize);
|
FFMS_API(int) FFMS_WriteTimecodes(FrameInfoVector *FIV, const char *TimecodeFile, char *ErrorMsg, unsigned MsgSize);
|
||||||
FFMS_API(int) FFMS_MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMask, const char *AudioFile, IndexProgress *IP, char *ErrorMsg, unsigned MsgSize);
|
FFMS_API(FrameIndex *) FFMS_MakeIndex(const char *SourceFile, int AudioTrackMask, const char *AudioFile, IndexCallback *IP, void *Private, char *ErrorMsg, unsigned MsgSize);
|
||||||
FFMS_API(int) FFMS_ReadIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
FFMS_API(FrameIndex *) FFMS_ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize);
|
||||||
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "ffvideosource.h"
|
#include "ffvideosource.h"
|
||||||
|
|
||||||
int VideoBase::InitPP(const char *PP, int PixelFormat, char *ErrorMsg, unsigned MsgSize) {
|
int VideoBase::InitPP(const char *PP, int PixelFormat, char *ErrorMsg, unsigned MsgSize) {
|
||||||
if (!strcmp(PP, ""))
|
if (PP == NULL || !strcmp(PP, ""))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
PPMode = pp_get_mode_by_name_and_quality(PP, PP_QUALITY_MAX);
|
PPMode = pp_get_mode_by_name_and_quality(PP, PP_QUALITY_MAX);
|
||||||
|
|
|
@ -77,11 +77,10 @@ public:
|
||||||
|
|
||||||
class MatroskaVideoSource : public VideoBase {
|
class MatroskaVideoSource : public VideoBase {
|
||||||
private:
|
private:
|
||||||
unsigned int BufferSize;
|
|
||||||
CompressedStream *CS;
|
|
||||||
MatroskaFile *MF;
|
MatroskaFile *MF;
|
||||||
char ErrorMessage[256];
|
|
||||||
MatroskaReaderContext MC;
|
MatroskaReaderContext MC;
|
||||||
|
CompressedStream *CS;
|
||||||
|
char ErrorMessage[256];
|
||||||
|
|
||||||
int DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize);
|
int DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize);
|
||||||
int GetTrackIndex(int &Index, char *ErrorMsg, unsigned MsgSize);
|
int GetTrackIndex(int &Index, char *ErrorMsg, unsigned MsgSize);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
#include "indexing.h"
|
#include "indexing.h"
|
||||||
#include "wave64writer.h"
|
#include "wave64writer.h"
|
||||||
|
|
||||||
|
@ -48,6 +49,41 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IndexMemory {
|
||||||
|
private:
|
||||||
|
int16_t *DecodingBuffer;
|
||||||
|
AudioContext *AudioContexts;
|
||||||
|
public:
|
||||||
|
IndexMemory(int Tracks, int16_t *&DecodingBuffer, AudioContext *&AudioContexts) {
|
||||||
|
DecodingBuffer = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*10];
|
||||||
|
AudioContexts = new AudioContext[Tracks];
|
||||||
|
this->DecodingBuffer = DecodingBuffer;
|
||||||
|
this->AudioContexts = AudioContexts;
|
||||||
|
}
|
||||||
|
|
||||||
|
~IndexMemory() {
|
||||||
|
delete [] DecodingBuffer;
|
||||||
|
delete [] AudioContexts;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MatroskaMemory {
|
||||||
|
private:
|
||||||
|
MatroskaFile *MF;
|
||||||
|
MatroskaReaderContext *MC;
|
||||||
|
public:
|
||||||
|
MatroskaMemory(MatroskaFile *MF, MatroskaReaderContext *MC) {
|
||||||
|
this->MF = MF;
|
||||||
|
this->MC = MC;
|
||||||
|
}
|
||||||
|
|
||||||
|
~MatroskaMemory() {
|
||||||
|
mkv_Close(MF);
|
||||||
|
fclose(MC->ST.fp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static bool DTSComparison(FrameInfo FI1, FrameInfo FI2) {
|
static bool DTSComparison(FrameInfo FI1, FrameInfo FI2) {
|
||||||
return FI1.DTS < FI2.DTS;
|
return FI1.DTS < FI2.DTS;
|
||||||
}
|
}
|
||||||
|
@ -86,14 +122,10 @@ int WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg,
|
||||||
Index.write(reinterpret_cast<char *>(&(TrackIndices->at(i)[j])), sizeof(FrameInfo));
|
Index.write(reinterpret_cast<char *>(&(TrackIndices->at(i)[j])), sizeof(FrameInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
Index.close();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMask, const char *AudioFile, IndexProgress *IP, char *ErrorMsg, unsigned MsgSize) {
|
static FrameIndex *MakeMatroskaIndex(const char *SourceFile, int AudioTrackMask, const char *AudioFile, IndexCallback *IP, void *Private, char *ErrorMsg, unsigned MsgSize) {
|
||||||
TrackIndices->Decoder = 1;
|
|
||||||
|
|
||||||
MatroskaFile *MF;
|
MatroskaFile *MF;
|
||||||
char ErrorMessage[256];
|
char ErrorMessage[256];
|
||||||
MatroskaReaderContext MC;
|
MatroskaReaderContext MC;
|
||||||
|
@ -104,7 +136,7 @@ static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, i
|
||||||
MC.ST.fp = fopen(SourceFile, "rb");
|
MC.ST.fp = fopen(SourceFile, "rb");
|
||||||
if (MC.ST.fp == NULL) {
|
if (MC.ST.fp == NULL) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Can't open '%s': %s", SourceFile, strerror(errno));
|
_snprintf(ErrorMsg, MsgSize, "Can't open '%s': %s", SourceFile, strerror(errno));
|
||||||
return 1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);
|
setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);
|
||||||
|
@ -113,12 +145,16 @@ static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, i
|
||||||
if (MF == NULL) {
|
if (MF == NULL) {
|
||||||
fclose(MC.ST.fp);
|
fclose(MC.ST.fp);
|
||||||
_snprintf(ErrorMsg, MsgSize, "Can't parse Matroska file: %s", ErrorMessage);
|
_snprintf(ErrorMsg, MsgSize, "Can't parse Matroska file: %s", ErrorMessage);
|
||||||
return 2;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MatroskaMemory MM = MatroskaMemory(MF, &MC);
|
||||||
|
|
||||||
// Audio stuff
|
// Audio stuff
|
||||||
|
|
||||||
AudioContext *AudioContexts = new AudioContext[mkv_GetNumTracks(MF)];
|
int16_t *db;
|
||||||
|
AudioContext *AudioContexts;
|
||||||
|
IndexMemory IM = IndexMemory(mkv_GetNumTracks(MF), db, AudioContexts);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) {
|
for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) {
|
||||||
if (AudioTrackMask & (1 << i) && mkv_GetTrackInfo(MF, i)->Type == TT_AUDIO) {
|
if (AudioTrackMask & (1 << i) && mkv_GetTrackInfo(MF, i)->Type == TT_AUDIO) {
|
||||||
|
@ -131,19 +167,19 @@ static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, i
|
||||||
AudioContexts[i].CS = cs_Create(MF, i, ErrorMessage, sizeof(ErrorMessage));
|
AudioContexts[i].CS = cs_Create(MF, i, ErrorMessage, sizeof(ErrorMessage));
|
||||||
if (AudioContexts[i].CS == NULL) {
|
if (AudioContexts[i].CS == NULL) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Can't create decompressor: %s", ErrorMessage);
|
_snprintf(ErrorMsg, MsgSize, "Can't create decompressor: %s", ErrorMessage);
|
||||||
return 3;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AVCodec *AudioCodec = avcodec_find_decoder(MatroskaToFFCodecID(mkv_GetTrackInfo(MF, i)));
|
AVCodec *AudioCodec = avcodec_find_decoder(MatroskaToFFCodecID(mkv_GetTrackInfo(MF, i)));
|
||||||
if (AudioCodec == NULL) {
|
if (AudioCodec == NULL) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Audio codec not found");
|
_snprintf(ErrorMsg, MsgSize, "Audio codec not found");
|
||||||
return 4;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avcodec_open(AudioCodecContext, AudioCodec) < 0) {
|
if (avcodec_open(AudioCodecContext, AudioCodec) < 0) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
|
_snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
|
||||||
return 5;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AudioTrackMask &= ~(1 << i);
|
AudioTrackMask &= ~(1 << i);
|
||||||
|
@ -152,15 +188,29 @@ static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, i
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
int64_t CurrentPos = _ftelli64(MC.ST.fp);
|
||||||
|
_fseeki64(MC.ST.fp, 0, SEEK_END);
|
||||||
|
int64_t SourceSize = _ftelli64(MC.ST.fp);
|
||||||
|
_fseeki64(MC.ST.fp, CurrentPos, SEEK_SET);
|
||||||
|
|
||||||
|
FrameIndex *TrackIndices = new FrameIndex();
|
||||||
|
TrackIndices->Decoder = 1;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++)
|
for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++)
|
||||||
TrackIndices->push_back(FrameInfoVector(mkv_TruncFloat(mkv_GetTrackInfo(MF, i)->TimecodeScale), 1000000));
|
TrackIndices->push_back(FrameInfoVector(mkv_TruncFloat(mkv_GetTrackInfo(MF, i)->TimecodeScale), 1000000));
|
||||||
|
|
||||||
uint64_t StartTime, EndTime, FilePos;
|
uint64_t StartTime, EndTime, FilePos;
|
||||||
unsigned int Track, FrameFlags, FrameSize;
|
unsigned int Track, FrameFlags, FrameSize;
|
||||||
|
|
||||||
int16_t *db = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*10];
|
|
||||||
|
|
||||||
while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) {
|
while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) {
|
||||||
|
// Update progress
|
||||||
|
if (IP) {
|
||||||
|
if ((*IP)(0, _ftelli64(MC.ST.fp), SourceSize, Private)) {
|
||||||
|
_snprintf(ErrorMsg, MsgSize, "Cancelled by user");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only create index entries for video for now to save space
|
// Only create index entries for video for now to save space
|
||||||
if (mkv_GetTrackInfo(MF, Track)->Type == TT_VIDEO)
|
if (mkv_GetTrackInfo(MF, Track)->Type == TT_VIDEO)
|
||||||
(*TrackIndices)[Track].push_back(FrameInfo(StartTime, (FrameFlags & FRAME_KF) != 0));
|
(*TrackIndices)[Track].push_back(FrameInfo(StartTime, (FrameFlags & FRAME_KF) != 0));
|
||||||
|
@ -177,7 +227,7 @@ static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, i
|
||||||
int Ret = avcodec_decode_audio2(AudioCodecContext, db, &dbsize, Data, Size);
|
int Ret = avcodec_decode_audio2(AudioCodecContext, db, &dbsize, Data, Size);
|
||||||
if (Ret < 0) {
|
if (Ret < 0) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Audio decoding error");
|
_snprintf(ErrorMsg, MsgSize, "Audio decoding error");
|
||||||
return 5;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ret > 0) {
|
if (Ret > 0) {
|
||||||
|
@ -203,42 +253,35 @@ static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] db;
|
|
||||||
delete [] AudioContexts;
|
|
||||||
|
|
||||||
mkv_Close(MF);
|
|
||||||
fclose(MC.ST.fp);
|
|
||||||
|
|
||||||
SortTrackIndices(TrackIndices);
|
SortTrackIndices(TrackIndices);
|
||||||
return 0;
|
return TrackIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMask, const char *AudioFile, IndexProgress *IP, char *ErrorMsg, unsigned MsgSize) {
|
FrameIndex *MakeIndex(const char *SourceFile, int AudioTrackMask, const char *AudioFile, IndexCallback *IP, void *Private, char *ErrorMsg, unsigned MsgSize) {
|
||||||
TrackIndices->Decoder = 0;
|
|
||||||
TrackIndices->clear();
|
|
||||||
|
|
||||||
AVFormatContext *FormatContext = NULL;
|
AVFormatContext *FormatContext = NULL;
|
||||||
|
|
||||||
if (av_open_input_file(&FormatContext, SourceFile, NULL, 0, NULL) != 0) {
|
if (av_open_input_file(&FormatContext, SourceFile, NULL, 0, NULL) != 0) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Can't open '%s'", SourceFile);
|
_snprintf(ErrorMsg, MsgSize, "Can't open '%s'", SourceFile);
|
||||||
return 1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do matroska indexing instead?
|
// Do matroska indexing instead?
|
||||||
if (!strcmp(FormatContext->iformat->name, "matroska")) {
|
if (!strcmp(FormatContext->iformat->name, "matroska")) {
|
||||||
av_close_input_file(FormatContext);
|
av_close_input_file(FormatContext);
|
||||||
return MakeMatroskaIndex(SourceFile, TrackIndices, AudioTrackMask, AudioFile, IP, ErrorMsg, MsgSize);
|
return MakeMatroskaIndex(SourceFile, AudioTrackMask, AudioFile, IP, Private, ErrorMsg, MsgSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (av_find_stream_info(FormatContext) < 0) {
|
if (av_find_stream_info(FormatContext) < 0) {
|
||||||
av_close_input_file(FormatContext);
|
av_close_input_file(FormatContext);
|
||||||
_snprintf(ErrorMsg, MsgSize, "Couldn't find stream information");
|
_snprintf(ErrorMsg, MsgSize, "Couldn't find stream information");
|
||||||
return 2;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audio stuff
|
// Audio stuff
|
||||||
|
|
||||||
AudioContext *AudioContexts = new AudioContext[FormatContext->nb_streams];
|
int16_t *db;
|
||||||
|
AudioContext *AudioContexts;
|
||||||
|
IndexMemory IM = IndexMemory(FormatContext->nb_streams, db, AudioContexts);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < FormatContext->nb_streams; i++) {
|
for (unsigned int i = 0; i < FormatContext->nb_streams; i++) {
|
||||||
if (AudioTrackMask & (1 << i) && FormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
|
if (AudioTrackMask & (1 << i) && FormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
|
||||||
|
@ -247,12 +290,12 @@ int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMa
|
||||||
AVCodec *AudioCodec = avcodec_find_decoder(AudioCodecContext->codec_id);
|
AVCodec *AudioCodec = avcodec_find_decoder(AudioCodecContext->codec_id);
|
||||||
if (AudioCodec == NULL) {
|
if (AudioCodec == NULL) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Audio codec not found");
|
_snprintf(ErrorMsg, MsgSize, "Audio codec not found");
|
||||||
return 3;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avcodec_open(AudioCodecContext, AudioCodec) < 0) {
|
if (avcodec_open(AudioCodecContext, AudioCodec) < 0) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
|
_snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
|
||||||
return 4;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AudioTrackMask &= ~(1 << i);
|
AudioTrackMask &= ~(1 << i);
|
||||||
|
@ -261,14 +304,23 @@ int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMa
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
FrameIndex *TrackIndices = new FrameIndex();
|
||||||
|
TrackIndices->Decoder = 0;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < FormatContext->nb_streams; i++)
|
for (unsigned int i = 0; i < FormatContext->nb_streams; i++)
|
||||||
TrackIndices->push_back(FrameInfoVector(FormatContext->streams[i]->time_base.den,
|
TrackIndices->push_back(FrameInfoVector(FormatContext->streams[i]->time_base.den,
|
||||||
FormatContext->streams[i]->time_base.num * 1000));
|
FormatContext->streams[i]->time_base.num * 1000));
|
||||||
|
|
||||||
int16_t *db = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*10];
|
|
||||||
|
|
||||||
AVPacket Packet;
|
AVPacket Packet;
|
||||||
while (av_read_frame(FormatContext, &Packet) >= 0) {
|
while (av_read_frame(FormatContext, &Packet) >= 0) {
|
||||||
|
// Update progress
|
||||||
|
if (IP) {
|
||||||
|
if ((*IP)(0, FormatContext->pb->pos, FormatContext->file_size, Private)) {
|
||||||
|
_snprintf(ErrorMsg, MsgSize, "Cancelled by user");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only create index entries for video for now to save space
|
// Only create index entries for video for now to save space
|
||||||
if (FormatContext->streams[Packet.stream_index]->codec->codec_type == CODEC_TYPE_VIDEO)
|
if (FormatContext->streams[Packet.stream_index]->codec->codec_type == CODEC_TYPE_VIDEO)
|
||||||
(*TrackIndices)[Packet.stream_index].push_back(FrameInfo(Packet.dts, (Packet.flags & PKT_FLAG_KEY) ? 1 : 0));
|
(*TrackIndices)[Packet.stream_index].push_back(FrameInfo(Packet.dts, (Packet.flags & PKT_FLAG_KEY) ? 1 : 0));
|
||||||
|
@ -283,7 +335,7 @@ int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMa
|
||||||
int Ret = avcodec_decode_audio2(AudioCodecContext, db, &dbsize, Data, Size);
|
int Ret = avcodec_decode_audio2(AudioCodecContext, db, &dbsize, Data, Size);
|
||||||
if (Ret < 0) {
|
if (Ret < 0) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Audio decoding error");
|
_snprintf(ErrorMsg, MsgSize, "Audio decoding error");
|
||||||
return 5;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ret > 0) {
|
if (Ret > 0) {
|
||||||
|
@ -313,21 +365,18 @@ int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMa
|
||||||
av_free_packet(&Packet);
|
av_free_packet(&Packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] db;
|
|
||||||
delete [] AudioContexts;
|
|
||||||
|
|
||||||
av_close_input_file(FormatContext);
|
av_close_input_file(FormatContext);
|
||||||
|
|
||||||
SortTrackIndices(TrackIndices);
|
SortTrackIndices(TrackIndices);
|
||||||
return 0;
|
return TrackIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReadIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize) {
|
FrameIndex *ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize) {
|
||||||
std::ifstream Index(IndexFile, std::ios::in | std::ios::binary);
|
std::ifstream Index(IndexFile, std::ios::in | std::ios::binary);
|
||||||
|
|
||||||
if (!Index.is_open()) {
|
if (!Index.is_open()) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "Failed to open '%s' for reading", IndexFile);
|
_snprintf(ErrorMsg, MsgSize, "Failed to open '%s' for reading", IndexFile);
|
||||||
return 1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the index file header
|
// Read the index file header
|
||||||
|
@ -335,37 +384,44 @@ int ReadIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, u
|
||||||
Index.read(reinterpret_cast<char *>(&IH), sizeof(IH));
|
Index.read(reinterpret_cast<char *>(&IH), sizeof(IH));
|
||||||
if (IH.Id != INDEXID) {
|
if (IH.Id != INDEXID) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "'%s' is not a valid index file", IndexFile);
|
_snprintf(ErrorMsg, MsgSize, "'%s' is not a valid index file", IndexFile);
|
||||||
return 2;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IH.Version != INDEXVERSION) {
|
if (IH.Version != INDEXVERSION) {
|
||||||
_snprintf(ErrorMsg, MsgSize, "'%s' is not the expected index version", IndexFile);
|
_snprintf(ErrorMsg, MsgSize, "'%s' is not the expected index version", IndexFile);
|
||||||
return 3;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackIndices->Decoder = IH.Decoder;
|
FrameIndex *TrackIndices = new FrameIndex();
|
||||||
TrackIndices->clear();
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < IH.Tracks; i++) {
|
try {
|
||||||
// Read how many records belong to the current stream
|
|
||||||
size_t Frames;
|
|
||||||
Index.read(reinterpret_cast<char *>(&Frames), sizeof(Frames));
|
|
||||||
int Num;
|
|
||||||
Index.read(reinterpret_cast<char *>(&Num), sizeof(Num));
|
|
||||||
int Den;
|
|
||||||
Index.read(reinterpret_cast<char *>(&Den), sizeof(Den));
|
|
||||||
TrackIndices->push_back(FrameInfoVector(Num, Den));
|
|
||||||
|
|
||||||
FrameInfo FI(0, false);
|
TrackIndices->Decoder = IH.Decoder;
|
||||||
for (size_t j = 0; j < Frames; j++) {
|
|
||||||
Index.read(reinterpret_cast<char *>(&FI), sizeof(FrameInfo));
|
for (unsigned int i = 0; i < IH.Tracks; i++) {
|
||||||
TrackIndices->at(i).push_back(FI);
|
// Read how many records belong to the current stream
|
||||||
|
size_t Frames;
|
||||||
|
Index.read(reinterpret_cast<char *>(&Frames), sizeof(Frames));
|
||||||
|
int Num;
|
||||||
|
Index.read(reinterpret_cast<char *>(&Num), sizeof(Num));
|
||||||
|
int Den;
|
||||||
|
Index.read(reinterpret_cast<char *>(&Den), sizeof(Den));
|
||||||
|
TrackIndices->push_back(FrameInfoVector(Num, Den));
|
||||||
|
|
||||||
|
FrameInfo FI(0, false);
|
||||||
|
for (size_t j = 0; j < Frames; j++) {
|
||||||
|
Index.read(reinterpret_cast<char *>(&FI), sizeof(FrameInfo));
|
||||||
|
TrackIndices->at(i).push_back(FI);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
delete TrackIndices;
|
||||||
|
_snprintf(ErrorMsg, MsgSize, "Unknown error while reading index information in '%s'", IndexFile);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Index.close();
|
return TrackIndices;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameInfo::FrameInfo(int64_t DTS, bool KeyFrame) {
|
FrameInfo::FrameInfo(int64_t DTS, bool KeyFrame) {
|
||||||
|
@ -410,6 +466,7 @@ int FrameInfoVector::ClosestFrameFromDTS(int64_t DTS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int FrameInfoVector::FindClosestKeyFrame(int Frame) {
|
int FrameInfoVector::FindClosestKeyFrame(int Frame) {
|
||||||
|
Frame = FFMIN(FFMAX(Frame, 0), size() - 1);
|
||||||
for (int i = Frame; i > 0; i--)
|
for (int i = Frame; i > 0; i--)
|
||||||
if (at(i).KeyFrame)
|
if (at(i).KeyFrame)
|
||||||
return i;
|
return i;
|
||||||
|
|
|
@ -61,8 +61,8 @@ public:
|
||||||
int Decoder;
|
int Decoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMask, const char *AudioFile, IndexProgress *IP, char *ErrorMsg, unsigned MsgSize);
|
FrameIndex *MakeIndex(const char *SourceFile, int AudioTrackMask, const char *AudioFile, IndexCallback *IP, void *Private, char *ErrorMsg, unsigned MsgSize);
|
||||||
int ReadIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
FrameIndex *ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize);
|
||||||
int WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
int WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue