forked from mia/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
7 changed files with 162 additions and 91 deletions
|
@ -54,12 +54,14 @@ AVSValue __cdecl CreateFFIndex(AVSValue Args, void* UserData, IScriptEnvironment
|
|||
// 1: Index generated
|
||||
// 2: Index forced to be overwritten
|
||||
|
||||
FrameIndex *Index = FFMS_CreateFrameIndex();
|
||||
if (OverWrite || FFMS_ReadIndex(CacheFile, Index, ErrorMsg, MsgSize)) {
|
||||
if (FFMS_MakeIndex(Source, Index, TrackMask, AudioFile, NULL, ErrorMsg, MsgSize))
|
||||
FrameIndex *Index;
|
||||
if (OverWrite || !(Index = FFMS_ReadIndex(CacheFile, ErrorMsg, MsgSize))) {
|
||||
if (!(Index = FFMS_MakeIndex(Source, TrackMask, AudioFile, NULL, NULL, ErrorMsg, MsgSize)))
|
||||
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);
|
||||
}
|
||||
FFMS_DestroyFrameIndex(Index);
|
||||
if (!OverWrite)
|
||||
return AVSValue(1);
|
||||
|
@ -100,28 +102,44 @@ AVSValue __cdecl CreateFFVideoSource(AVSValue Args, void* UserData, IScriptEnvir
|
|||
if (Threads < 1)
|
||||
Env->ThrowError("FFVideoSource: Invalid thread count");
|
||||
|
||||
if (!_stricmp(Source, Timecodes))
|
||||
Env->ThrowError("FFVideoSource: Timecodes will overwrite the source");
|
||||
|
||||
std::string DefaultCache(Source);
|
||||
DefaultCache.append(".ffindex");
|
||||
if (!strcmp(CacheFile, ""))
|
||||
CacheFile = DefaultCache.c_str();
|
||||
|
||||
FrameIndex *Index = FFMS_CreateFrameIndex();
|
||||
FrameIndex *Index;
|
||||
if (Cache) {
|
||||
if (FFMS_ReadIndex(CacheFile, Index, ErrorMsg, MsgSize)) {
|
||||
if (FFMS_MakeIndex(Source, Index, 0, NULL, NULL, ErrorMsg, MsgSize))
|
||||
if (!(Index = FFMS_ReadIndex(CacheFile, ErrorMsg, MsgSize))) {
|
||||
if (!(Index = FFMS_MakeIndex(Source, 0, NULL, NULL, NULL, ErrorMsg, MsgSize)))
|
||||
Env->ThrowError("FFVideoSource: %s", ErrorMsg);
|
||||
|
||||
if (Cache)
|
||||
if (FFMS_WriteIndex(CacheFile, Index, ErrorMsg, MsgSize))
|
||||
if (FFMS_WriteIndex(CacheFile, Index, ErrorMsg, MsgSize)) {
|
||||
FFMS_DestroyFrameIndex(Index);
|
||||
Env->ThrowError("FFVideoSource: %s", ErrorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AvisynthVideoSource *Filter = new AvisynthVideoSource(Source, Track, Index, PP, Threads, SeekMode, Env, ErrorMsg, MsgSize);
|
||||
AvisynthVideoSource *Filter;
|
||||
|
||||
if (strcmp(Timecodes, ""))
|
||||
if (FFMS_WriteTimecodes(FFMS_GetTITrackIndex(Index, Filter->GetTrack(), ErrorMsg, MsgSize), Timecodes, ErrorMsg, MsgSize))
|
||||
try {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
FFMS_API(FrameIndex *) FFMS_CreateFrameIndex() {
|
||||
return new FrameIndex();
|
||||
}
|
||||
|
||||
FFMS_API(void) FFMS_DestroyFrameIndex(FrameIndex *FI) {
|
||||
delete FI;
|
||||
}
|
||||
|
@ -116,12 +112,12 @@ FFMS_API(int) FFMS_WriteTimecodes(FrameInfoVector *FIV, const char *TimecodeFile
|
|||
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) {
|
||||
return MakeIndex(SourceFile, TrackIndices, AudioTrackMask, AudioFile, IP, ErrorMsg, 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, AudioTrackMask, AudioFile, IP, Private, ErrorMsg, MsgSize);
|
||||
}
|
||||
|
||||
FFMS_API(int) FFMS_ReadIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize) {
|
||||
return ReadIndex(IndexFile, TrackIndices, ErrorMsg, MsgSize);
|
||||
FFMS_API(FrameIndex *) FFMS_ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize) {
|
||||
return ReadIndex(IndexFile, ErrorMsg, MsgSize);
|
||||
}
|
||||
|
||||
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize) {
|
||||
|
|
|
@ -31,17 +31,19 @@
|
|||
# define EXTERN_C
|
||||
#endif
|
||||
|
||||
#define FFMS_CC __stdcall
|
||||
|
||||
#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
|
||||
# define FFMS_API(ret) EXTERN_C __declspec(dllimport) ret __stdcall
|
||||
# define FFMS_API(ret) EXTERN_C __declspec(dllimport) ret FFMS_CC
|
||||
#endif
|
||||
|
||||
class VideoBase;
|
||||
class FrameIndex;
|
||||
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.
|
||||
// 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(const VideoProperties *) FFMS_GetVideoProperties(VideoBase *VB);
|
||||
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(int) FFMS_GetNumTracks(FrameIndex *TrackIndices, 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(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_MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMask, const char *AudioFile, IndexProgress *IP, char *ErrorMsg, unsigned MsgSize);
|
||||
FFMS_API(int) FFMS_ReadIndex(const char *IndexFile, FrameIndex *TrackIndices, 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(FrameIndex *) FFMS_ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize);
|
||||
FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "ffvideosource.h"
|
||||
|
||||
int VideoBase::InitPP(const char *PP, int PixelFormat, char *ErrorMsg, unsigned MsgSize) {
|
||||
if (!strcmp(PP, ""))
|
||||
if (PP == NULL || !strcmp(PP, ""))
|
||||
return 0;
|
||||
|
||||
PPMode = pp_get_mode_by_name_and_quality(PP, PP_QUALITY_MAX);
|
||||
|
|
|
@ -77,11 +77,10 @@ public:
|
|||
|
||||
class MatroskaVideoSource : public VideoBase {
|
||||
private:
|
||||
unsigned int BufferSize;
|
||||
CompressedStream *CS;
|
||||
MatroskaFile *MF;
|
||||
char ErrorMessage[256];
|
||||
MatroskaReaderContext MC;
|
||||
CompressedStream *CS;
|
||||
char ErrorMessage[256];
|
||||
|
||||
int DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize);
|
||||
int GetTrackIndex(int &Index, char *ErrorMsg, unsigned MsgSize);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <fstream>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include "indexing.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) {
|
||||
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.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMask, const char *AudioFile, IndexProgress *IP, char *ErrorMsg, unsigned MsgSize) {
|
||||
TrackIndices->Decoder = 1;
|
||||
|
||||
static FrameIndex *MakeMatroskaIndex(const char *SourceFile, int AudioTrackMask, const char *AudioFile, IndexCallback *IP, void *Private, char *ErrorMsg, unsigned MsgSize) {
|
||||
MatroskaFile *MF;
|
||||
char ErrorMessage[256];
|
||||
MatroskaReaderContext MC;
|
||||
|
@ -104,7 +136,7 @@ static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, i
|
|||
MC.ST.fp = fopen(SourceFile, "rb");
|
||||
if (MC.ST.fp == NULL) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Can't open '%s': %s", SourceFile, strerror(errno));
|
||||
return 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
setvbuf(MC.ST.fp, NULL, _IOFBF, CACHESIZE);
|
||||
|
@ -113,12 +145,16 @@ static int MakeMatroskaIndex(const char *SourceFile, FrameIndex *TrackIndices, i
|
|||
if (MF == NULL) {
|
||||
fclose(MC.ST.fp);
|
||||
_snprintf(ErrorMsg, MsgSize, "Can't parse Matroska file: %s", ErrorMessage);
|
||||
return 2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MatroskaMemory MM = MatroskaMemory(MF, &MC);
|
||||
|
||||
// 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++) {
|
||||
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));
|
||||
if (AudioContexts[i].CS == NULL) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Can't create decompressor: %s", ErrorMessage);
|
||||
return 3;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
AVCodec *AudioCodec = avcodec_find_decoder(MatroskaToFFCodecID(mkv_GetTrackInfo(MF, i)));
|
||||
if (AudioCodec == NULL) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Audio codec not found");
|
||||
return 4;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (avcodec_open(AudioCodecContext, AudioCodec) < 0) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
|
||||
return 5;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
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++)
|
||||
TrackIndices->push_back(FrameInfoVector(mkv_TruncFloat(mkv_GetTrackInfo(MF, i)->TimecodeScale), 1000000));
|
||||
|
||||
uint64_t StartTime, EndTime, FilePos;
|
||||
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) {
|
||||
// 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
|
||||
if (mkv_GetTrackInfo(MF, Track)->Type == TT_VIDEO)
|
||||
(*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);
|
||||
if (Ret < 0) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Audio decoding error");
|
||||
return 5;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
return 0;
|
||||
return TrackIndices;
|
||||
}
|
||||
|
||||
int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMask, const char *AudioFile, IndexProgress *IP, char *ErrorMsg, unsigned MsgSize) {
|
||||
TrackIndices->Decoder = 0;
|
||||
TrackIndices->clear();
|
||||
|
||||
FrameIndex *MakeIndex(const char *SourceFile, int AudioTrackMask, const char *AudioFile, IndexCallback *IP, void *Private, char *ErrorMsg, unsigned MsgSize) {
|
||||
AVFormatContext *FormatContext = NULL;
|
||||
|
||||
if (av_open_input_file(&FormatContext, SourceFile, NULL, 0, NULL) != 0) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Can't open '%s'", SourceFile);
|
||||
return 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Do matroska indexing instead?
|
||||
if (!strcmp(FormatContext->iformat->name, "matroska")) {
|
||||
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) {
|
||||
av_close_input_file(FormatContext);
|
||||
_snprintf(ErrorMsg, MsgSize, "Couldn't find stream information");
|
||||
return 2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
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);
|
||||
if (AudioCodec == NULL) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Audio codec not found");
|
||||
return 3;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (avcodec_open(AudioCodecContext, AudioCodec) < 0) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Could not open audio codec");
|
||||
return 4;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
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++)
|
||||
TrackIndices->push_back(FrameInfoVector(FormatContext->streams[i]->time_base.den,
|
||||
FormatContext->streams[i]->time_base.num * 1000));
|
||||
|
||||
int16_t *db = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*10];
|
||||
|
||||
AVPacket Packet;
|
||||
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
|
||||
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));
|
||||
|
@ -283,7 +335,7 @@ int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMa
|
|||
int Ret = avcodec_decode_audio2(AudioCodecContext, db, &dbsize, Data, Size);
|
||||
if (Ret < 0) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Audio decoding error");
|
||||
return 5;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (Ret > 0) {
|
||||
|
@ -313,21 +365,18 @@ int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMa
|
|||
av_free_packet(&Packet);
|
||||
}
|
||||
|
||||
delete [] db;
|
||||
delete [] AudioContexts;
|
||||
|
||||
av_close_input_file(FormatContext);
|
||||
|
||||
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);
|
||||
|
||||
if (!Index.is_open()) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Failed to open '%s' for reading", IndexFile);
|
||||
return 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 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));
|
||||
if (IH.Id != INDEXID) {
|
||||
_snprintf(ErrorMsg, MsgSize, "'%s' is not a valid index file", IndexFile);
|
||||
return 2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (IH.Version != INDEXVERSION) {
|
||||
_snprintf(ErrorMsg, MsgSize, "'%s' is not the expected index version", IndexFile);
|
||||
return 3;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TrackIndices->Decoder = IH.Decoder;
|
||||
TrackIndices->clear();
|
||||
FrameIndex *TrackIndices = new FrameIndex();
|
||||
|
||||
for (unsigned int i = 0; i < IH.Tracks; i++) {
|
||||
// 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));
|
||||
try {
|
||||
|
||||
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);
|
||||
TrackIndices->Decoder = IH.Decoder;
|
||||
|
||||
for (unsigned int i = 0; i < IH.Tracks; i++) {
|
||||
// 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 0;
|
||||
return TrackIndices;
|
||||
}
|
||||
|
||||
FrameInfo::FrameInfo(int64_t DTS, bool KeyFrame) {
|
||||
|
@ -410,6 +466,7 @@ int FrameInfoVector::ClosestFrameFromDTS(int64_t DTS) {
|
|||
}
|
||||
|
||||
int FrameInfoVector::FindClosestKeyFrame(int Frame) {
|
||||
Frame = FFMIN(FFMAX(Frame, 0), size() - 1);
|
||||
for (int i = Frame; i > 0; i--)
|
||||
if (at(i).KeyFrame)
|
||||
return i;
|
||||
|
|
|
@ -61,8 +61,8 @@ public:
|
|||
int Decoder;
|
||||
};
|
||||
|
||||
int MakeIndex(const char *SourceFile, FrameIndex *TrackIndices, int AudioTrackMask, const char *AudioFile, IndexProgress *IP, char *ErrorMsg, unsigned MsgSize);
|
||||
int ReadIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
||||
FrameIndex *MakeIndex(const char *SourceFile, int AudioTrackMask, const char *AudioFile, IndexCallback *IP, void *Private, char *ErrorMsg, unsigned MsgSize);
|
||||
FrameIndex *ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize);
|
||||
int WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue