diff --git a/aegisub/FFmpegSource2/ffaudiosource.cpp b/aegisub/FFmpegSource2/ffaudiosource.cpp index fff5adeb4..1cca94c1a 100644 --- a/aegisub/FFmpegSource2/ffaudiosource.cpp +++ b/aegisub/FFmpegSource2/ffaudiosource.cpp @@ -108,7 +108,8 @@ FFAudio::~FFAudio() { void FFLAVFAudio::Free(bool CloseCodec) { if (CloseCodec) avcodec_close(CodecContext); - av_close_input_file(FormatContext); + if (FormatContext) + av_close_input_file(FormatContext); } FFLAVFAudio::FFLAVFAudio(const char *SourceFile, int Track, FFIndex *Index, char *ErrorMsg, unsigned MsgSize) { @@ -151,7 +152,7 @@ FFLAVFAudio::FFLAVFAudio(const char *SourceFile, int Track, FFIndex *Index, char // Always try to decode a frame to make sure all required parameters are known int64_t Dummy; - if (DecodeNextAudioBlock(DecodingBuffer, &Dummy, ErrorMsg, MsgSize) < 0) { + if (DecodeNextAudioBlock(&Dummy, ErrorMsg, MsgSize) < 0) { Free(true); throw ErrorMsg; } @@ -169,10 +170,11 @@ FFLAVFAudio::FFLAVFAudio(const char *SourceFile, int Track, FFIndex *Index, char AudioCache.Initialize((AP.Channels * AP.BitsPerSample) / 8, 50); } -int FFLAVFAudio::DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, char *ErrorMsg, unsigned MsgSize) { +int FFLAVFAudio::DecodeNextAudioBlock(int64_t *Count, char *ErrorMsg, unsigned MsgSize) { const size_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8; int Ret = -1; *Count = 0; + uint8_t *Buf = DecodingBuffer; AVPacket Packet, TempPacket; InitNullPacket(&Packet); InitNullPacket(&TempPacket); @@ -265,7 +267,7 @@ int FFLAVFAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMs int64_t DecodeCount; do { - int Ret = DecodeNextAudioBlock(DecodingBuffer, &DecodeCount, ErrorMsg, MsgSize); + int Ret = DecodeNextAudioBlock(&DecodeCount, ErrorMsg, MsgSize); if (Ret < 0) { // FIXME //Env->ThrowError("Bleh, bad audio decoding"); @@ -362,7 +364,7 @@ FFMatroskaAudio::FFMatroskaAudio(const char *SourceFile, int Track, FFIndex *Ind // Always try to decode a frame to make sure all required parameters are known int64_t Dummy; - if (DecodeNextAudioBlock(DecodingBuffer, &Dummy, Frames[0].FilePos, Frames[0].FrameSize, ErrorMsg, MsgSize) < 0) { + if (DecodeNextAudioBlock(&Dummy, 0, ErrorMsg, MsgSize) < 0) { Free(true); throw ErrorMsg; } @@ -396,7 +398,7 @@ int FFMatroskaAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *Err if (CacheEnd == Start + Count) return 0; - size_t CurrentAudioBlock; + int CurrentAudioBlock; // Is seeking required to decode the requested samples? // if (!(CurrentSample >= Start && CurrentSample <= CacheEnd)) { if (CurrentSample != CacheEnd) { @@ -410,7 +412,7 @@ int FFMatroskaAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *Err int64_t DecodeCount; do { - int Ret = DecodeNextAudioBlock(DecodingBuffer, &DecodeCount, Frames[CurrentAudioBlock].FilePos, Frames[CurrentAudioBlock].FrameSize, ErrorMsg, MsgSize); + int Ret = DecodeNextAudioBlock(&DecodeCount, CurrentAudioBlock, ErrorMsg, MsgSize); if (Ret < 0) { // FIXME //Env->ThrowError("Bleh, bad audio decoding"); @@ -432,17 +434,21 @@ int FFMatroskaAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *Err return 0; } -int FFMatroskaAudio::DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, uint64_t FilePos, unsigned int FrameSize, char *ErrorMsg, unsigned MsgSize) { +int FFMatroskaAudio::DecodeNextAudioBlock(int64_t *Count, int AudioBlock, char *ErrorMsg, unsigned MsgSize) { const size_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8; int Ret = -1; *Count = 0; + uint8_t *Buf = DecodingBuffer; AVPacket TempPacket; InitNullPacket(&TempPacket); - // FIXME check return - ReadFrame(FilePos, FrameSize, CS, MC, ErrorMsg, MsgSize); - TempPacket.size = FrameSize; + unsigned int FrameSize = Frames[AudioBlock].FrameSize; + if (ReadFrame(Frames[AudioBlock].FilePos, FrameSize, CS, MC, ErrorMsg, MsgSize)) + return 1; TempPacket.data = MC.Buffer; + TempPacket.size = FrameSize; + if (Frames[AudioBlock].KeyFrame) + TempPacket.flags = PKT_FLAG_KEY; while (TempPacket.size > 0) { int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; @@ -460,6 +466,247 @@ int FFMatroskaAudio::DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, uint64_t } } +Done: + return 0; +} + +#ifdef HAALISOURCE + +void FFHaaliAudio::Free(bool CloseCodec) { + if (CloseCodec) + avcodec_close(CodecContext); + av_free(CodecContext); + delete[] CodecPrivate; +} + +int FFHaaliAudio::DecodeNextAudioBlock(int64_t *AFirstStartTime, int64_t *Count, char *ErrorMsg, unsigned MsgSize) { + const size_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8; + int Ret = -1; + *AFirstStartTime = -1; + *Count = 0; + uint8_t *Buf = DecodingBuffer; + AVPacket Packet; + InitNullPacket(&Packet); + + for (;;) { + CComPtr pMMF; + if (pMMC->ReadFrame(NULL, &pMMF) != S_OK) + break; + + REFERENCE_TIME Ts, Te; + if (*AFirstStartTime < 0 && SUCCEEDED(pMMF->GetTime(&Ts, &Te))) + *AFirstStartTime = Ts; + + if (pMMF->GetTrack() == AudioTrack) { + BYTE *Data = NULL; + if (FAILED(pMMF->GetPointer(&Data))) + goto Done; + + Packet.data = Data; + Packet.size = pMMF->GetActualDataLength(); + if (pMMF->IsSyncPoint() == S_OK) + Packet.flags = PKT_FLAG_KEY; + else + Packet.flags = 0; + + while (Packet.size > 0) { + int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE * 10; + Ret = avcodec_decode_audio3(CodecContext, (int16_t *)Buf, &TempOutputBufSize, &Packet); + + if (Ret < 0) {// throw error or something? + goto Done; + } + + if (Ret > 0) { + Packet.size -= Ret; + Packet.data += Ret; + Buf += TempOutputBufSize; + if (SizeConst) + *Count += TempOutputBufSize / SizeConst; + } + } + + goto Done; + } + } + Done: return Ret; } + +FFHaaliAudio::FFHaaliAudio(const char *SourceFile, int Track, FFIndex *Index, int SourceMode, char *ErrorMsg, unsigned MsgSize) { + CodecPrivate = NULL; + AVCodec *Codec = NULL; + CodecContext = NULL; + AudioTrack = Track; + Frames = (*Index)[AudioTrack]; + + if (Frames.size() == 0) { + _snprintf(ErrorMsg, MsgSize, "Audio track contains no frames, was it indexed properly?"); + throw ErrorMsg; + } + + CLSID clsid = HAALI_TS_Parser; + if (SourceMode == 1) + clsid = HAALI_OGM_Parser; + + if (FAILED(pMMC.CoCreateInstance(clsid))) { + _snprintf(ErrorMsg, MsgSize, "Can't create parser"); + throw ErrorMsg; + } + + CComPtr pMA; + if (FAILED(pMA.CoCreateInstance(CLSID_MemAlloc))) { + _snprintf(ErrorMsg, MsgSize, "Can't create memory allocator"); + throw ErrorMsg; + } + + CComPtr pMS; + if (FAILED(pMS.CoCreateInstance(CLSID_DiskFile))) { + _snprintf(ErrorMsg, MsgSize, "Can't create disk file reader"); + throw ErrorMsg; + } + + WCHAR WSourceFile[2048]; + mbstowcs(WSourceFile, SourceFile, 2000); + CComQIPtr pMSO(pMS); + if (FAILED(pMSO->Open(WSourceFile))) { + _snprintf(ErrorMsg, MsgSize, "Can't open file"); + throw ErrorMsg; + } + + if (FAILED(pMMC->Open(pMS, 0, NULL, pMA))) { + _snprintf(ErrorMsg, MsgSize, "Can't parse file"); + throw ErrorMsg; + } + + int CodecPrivateSize = 0; + int CurrentTrack = 0; + CComPtr pEU; + CComQIPtr pBag; + if (SUCCEEDED(pMMC->EnumTracks(&pEU))) { + CComPtr pU; + while (pEU->Next(1, &pU, NULL) == S_OK) { + if (CurrentTrack++ == Track) { + pBag = pU; + + if (pBag) { + CComVariant pV; + + pV.Clear(); + if (SUCCEEDED(pBag->Read(L"CodecPrivate", &pV, NULL))) { + CodecPrivateSize = vtSize(pV); + CodecPrivate = new uint8_t[CodecPrivateSize]; + vtCopy(pV, CodecPrivate); + } + + pV.Clear(); + if (SUCCEEDED(pBag->Read(L"CodecID", &pV, NULL)) && SUCCEEDED(pV.ChangeType(VT_BSTR))) { + char ACodecID[2048]; + wcstombs(ACodecID, pV.bstrVal, 2000); + Codec = avcodec_find_decoder(MatroskaToFFCodecID(ACodecID, CodecPrivate)); + } + } + } + pU = NULL; + } + } + + CodecContext = avcodec_alloc_context(); + CodecContext->extradata = CodecPrivate; + CodecContext->extradata_size = CodecPrivateSize; + + if (Codec == NULL) { + Free(false); + _snprintf(ErrorMsg, MsgSize, "Audio codec not found"); + throw ErrorMsg; + } + + if (avcodec_open(CodecContext, Codec) < 0) { + Free(false); + _snprintf(ErrorMsg, MsgSize, "Could not open audio codec"); + throw ErrorMsg; + } + + // Always try to decode a frame to make sure all required parameters are known + int64_t Dummy1, Dummy2; + if (DecodeNextAudioBlock(&Dummy1, &Dummy2, ErrorMsg, MsgSize) < 0) { + Free(true); + throw ErrorMsg; + } + pMMC->Seek(Frames[0].DTS, MKVF_SEEK_TO_PREV_KEYFRAME_STRICT); + avcodec_flush_buffers(CodecContext); + + FillAP(AP, CodecContext, Frames); + + if (AP.SampleRate <= 0 || AP.BitsPerSample <= 0) { + Free(true); + _snprintf(ErrorMsg, MsgSize, "Codec returned zero size audio"); + throw ErrorMsg; + } + + AudioCache.Initialize((AP.Channels * AP.BitsPerSample) / 8, 50); +} + +FFHaaliAudio::~FFHaaliAudio() { + Free(true); +} + +int FFHaaliAudio::GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize) { + const int64_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8; + memset(Buf, 0, SizeConst * Count); + bool HasSeeked = false; + + int PreDecBlocks = 0; + uint8_t *DstBuf = static_cast(Buf); + + // Fill with everything in the cache + int64_t CacheEnd = AudioCache.FillRequest(Start, Count, DstBuf); + // Was everything in the cache? + if (CacheEnd == Start + Count) + return 0; + + int64_t CurrentAudioBlock; + // Is seeking required to decode the requested samples? +// if (!(CurrentSample >= Start && CurrentSample <= CacheEnd)) { + if (CurrentSample != CacheEnd) { + PreDecBlocks = 15; + CurrentAudioBlock = FFMAX((int64_t)Frames.FindClosestAudioKeyFrame(CacheEnd) - PreDecBlocks - 20, (int64_t)0); + pMMC->Seek(Frames[CurrentAudioBlock].DTS, MKVF_SEEK_TO_PREV_KEYFRAME_STRICT); + avcodec_flush_buffers(CodecContext); + HasSeeked = true; + } else { + CurrentAudioBlock = Frames.FindClosestAudioKeyFrame(CurrentSample); + } + + int64_t FirstTime, DecodeCount; + + do { + int Ret = DecodeNextAudioBlock(&FirstTime, &DecodeCount, ErrorMsg, MsgSize); + if (Ret < 0) { + // FIXME + //Env->ThrowError("Bleh, bad audio decoding"); + } + + if (HasSeeked) { + CurrentAudioBlock = Frames.ClosestFrameFromDTS(FirstTime); + HasSeeked = false; + } + + // Cache the block if enough blocks before it have been decoded to avoid garbage + if (PreDecBlocks == 0) { + AudioCache.CacheBlock(Frames[CurrentAudioBlock].SampleStart, DecodeCount, DecodingBuffer); + CacheEnd = AudioCache.FillRequest(CacheEnd, Start + Count - CacheEnd, DstBuf + (CacheEnd - Start) * SizeConst); + } else { + PreDecBlocks--; + } + + CurrentAudioBlock++; + if (CurrentAudioBlock < Frames.size()) + CurrentSample = Frames[CurrentAudioBlock].SampleStart; + } while (Start + Count - CacheEnd > 0 && CurrentAudioBlock < Frames.size()); + + return 0; +} + +#endif // HAALISOURCE \ No newline at end of file diff --git a/aegisub/FFmpegSource2/ffaudiosource.h b/aegisub/FFmpegSource2/ffaudiosource.h index 4884a14cd..5af001b20 100644 --- a/aegisub/FFmpegSource2/ffaudiosource.h +++ b/aegisub/FFmpegSource2/ffaudiosource.h @@ -74,6 +74,7 @@ protected: uint8_t *DecodingBuffer; FFTrack Frames; AVCodecContext *CodecContext; + int AudioTrack; TAudioProperties AP; public: FFAudio(); @@ -86,14 +87,12 @@ public: class FFLAVFAudio : public FFAudio { private: AVFormatContext *FormatContext; - int AudioTrack; - int DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, char *ErrorMsg, unsigned MsgSize); + int DecodeNextAudioBlock(int64_t *Count, char *ErrorMsg, unsigned MsgSize); void Free(bool CloseCodec); public: FFLAVFAudio(const char *SourceFile, int Track, FFIndex *Index, char *ErrorMsg, unsigned MsgSize); ~FFLAVFAudio(); - int GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize); }; @@ -104,27 +103,26 @@ private: CompressedStream *CS; char ErrorMessage[256]; - int DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, uint64_t FilePos, unsigned int FrameSize, char *ErrorMsg, unsigned MsgSize); + int DecodeNextAudioBlock(int64_t *Count, int AudioBlock, char *ErrorMsg, unsigned MsgSize); void Free(bool CloseCodec); public: FFMatroskaAudio(const char *SourceFile, int Track, FFIndex *Index, char *ErrorMsg, unsigned MsgSize); ~FFMatroskaAudio(); - int GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize); }; #ifdef HAALISOURCE -class HaaliAudioSource : public FFAudio { +class FFHaaliAudio : public FFAudio { private: CComPtr pMMC; + uint8_t * CodecPrivate; - int DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, char *ErrorMsg, unsigned MsgSize); void Free(bool CloseCodec); + int DecodeNextAudioBlock(int64_t *AFirstStartTime, int64_t *Count, char *ErrorMsg, unsigned MsgSize); public: - HaaliAudioSource(const char *SourceFile, int Track, FFIndex *Index, char *ErrorMsg, unsigned MsgSize); - ~HaaliAudioSource(); - + FFHaaliAudio(const char *SourceFile, int Track, FFIndex *Index, int SourceMode, char *ErrorMsg, unsigned MsgSize); + ~FFHaaliAudio(); int GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize); }; diff --git a/aegisub/FFmpegSource2/ffavsfilters.cpp b/aegisub/FFmpegSource2/ffavsfilters.cpp index 0c1871ebc..651d49caf 100644 --- a/aegisub/FFmpegSource2/ffavsfilters.cpp +++ b/aegisub/FFmpegSource2/ffavsfilters.cpp @@ -62,7 +62,7 @@ static AVSValue __cdecl CreateFFIndex(AVSValue Args, void* UserData, IScriptEnvi FFIndex *Index = NULL; if (OverWrite || !(Index = FFMS_ReadIndex(CacheFile, ErrorMsg, MsgSize))) { - if (!(Index = FFMS_MakeIndex(Source, IndexMask, DumpMask, AudioFile, true, NULL, NULL, ErrorMsg, MsgSize))) + if (!(Index = FFMS_MakeIndex(Source, IndexMask, DumpMask, FFMS_DefaultAudioFilename, NULL, true, NULL, NULL, ErrorMsg, MsgSize))) Env->ThrowError("FFIndex: %s", ErrorMsg); if (FFMS_WriteIndex(CacheFile, Index, ErrorMsg, MsgSize)) { FFMS_DestroyFFIndex(Index); @@ -122,7 +122,7 @@ static AVSValue __cdecl CreateFFVideoSource(AVSValue Args, void* UserData, IScri if (Cache) Index = FFMS_ReadIndex(CacheFile, ErrorMsg, MsgSize); if (!Index) { - if (!(Index = FFMS_MakeIndex(Source, 0, 0, NULL, true, NULL, NULL, ErrorMsg, MsgSize))) + if (!(Index = FFMS_MakeIndex(Source, 0, 0, NULL, NULL, true, NULL, NULL, ErrorMsg, MsgSize))) Env->ThrowError("FFVideoSource: %s", ErrorMsg); if (Cache) @@ -133,7 +133,7 @@ static AVSValue __cdecl CreateFFVideoSource(AVSValue Args, void* UserData, IScri } if (Track == -1) - Track = FFMS_GetFirstTrackOfType(Index, FFMS_TYPE_VIDEO, ErrorMsg, MsgSize); + Track = FFMS_GetFirstIndexedTrackOfType(Index, FFMS_TYPE_VIDEO, ErrorMsg, MsgSize); if (Track < 0) Env->ThrowError("FFVideoSource: No video track found"); @@ -183,7 +183,7 @@ static AVSValue __cdecl CreateFFAudioSource(AVSValue Args, void* UserData, IScri if (Cache) Index = FFMS_ReadIndex(CacheFile, ErrorMsg, MsgSize); if (!Index) { - if (!(Index = FFMS_MakeIndex(Source, -1, 0, CacheFile, true, NULL, NULL, ErrorMsg, MsgSize))) + if (!(Index = FFMS_MakeIndex(Source, -1, 0, NULL, NULL, true, NULL, NULL, ErrorMsg, MsgSize))) Env->ThrowError("FFAudioSource: %s", ErrorMsg); if (Cache) @@ -194,7 +194,7 @@ static AVSValue __cdecl CreateFFAudioSource(AVSValue Args, void* UserData, IScri } if (Track == -1) - Track = FFMS_GetFirstTrackOfType(Index, FFMS_TYPE_AUDIO, ErrorMsg, MsgSize); + Track = FFMS_GetFirstIndexedTrackOfType(Index, FFMS_TYPE_AUDIO, ErrorMsg, MsgSize); if (Track < 0) Env->ThrowError("FFAudioSource: No audio track found"); diff --git a/aegisub/FFmpegSource2/ffms.cpp b/aegisub/FFmpegSource2/ffms.cpp index 64a742ab5..baeca8ed7 100644 --- a/aegisub/FFmpegSource2/ffms.cpp +++ b/aegisub/FFmpegSource2/ffms.cpp @@ -31,13 +31,27 @@ extern "C" { #define _snprintf snprintf #endif -FFMS_API(void) FFMS_Init() { - static bool InitDone = false; - if (!InitDone) { +static int InitCount = 0; + +FFMS_API(int) FFMS_Init() { + if (!InitCount++) { av_register_all(); av_log_set_level(AV_LOG_QUIET); +#ifdef HAALISOURCE + if (::CoInitializeEx(NULL, COINIT_MULTITHREADED) != S_OK) + return 1; +#endif + } + return 0; +} + + +FFMS_API(void) FFMS_DeInit() { + if (!--InitCount) { +#ifdef HAALISOURCE + ::CoUninitialize(); +#endif } - InitDone = true; } FFMS_API(int) FFMS_GetLogLevel() { @@ -71,6 +85,8 @@ FFMS_API(FFAudio *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FF switch (Index->Decoder) { case 0: return new FFLAVFAudio(SourceFile, Track, Index, ErrorMsg, MsgSize); case 1: return new FFMatroskaAudio(SourceFile, Track, Index, ErrorMsg, MsgSize); + case 2: return new FFHaaliAudio(SourceFile, Track, Index, 0, ErrorMsg, MsgSize); + case 3: return new FFHaaliAudio(SourceFile, Track, Index, 1, ErrorMsg, MsgSize); default: _snprintf(ErrorMsg, MsgSize, "Unsupported format"); return NULL; @@ -190,6 +206,21 @@ FFMS_API(int) FFMS_WriteTimecodes(FFTrack *T, const char *TimecodeFile, char *Er return T->WriteTimecodes(TimecodeFile, ErrorMsg, MsgSize); } +FFMS_API(FFIndex *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, bool IgnoreDecodeErrors, TIndexCallback IC, void *ICPrivate, char *ErrorMsg, unsigned MsgSize) { + FFIndexer *Indexer = FFMS_CreateIndexer(SourceFile, ErrorMsg, MsgSize); + if (!Indexer) + return NULL; + return FFMS_DoIndexing(Indexer, IndexMask, DumpMask, ANC, ANCPrivate, IgnoreDecodeErrors, IC, ICPrivate, ErrorMsg, MsgSize); +} + +FFMS_API(int) FFMS_DefaultAudioFilename(const char *SourceFile, int Track, const TAudioProperties *AP, char *FileName, void *Private) { + const char * FormatString = "%s.%d2.w64"; + if (FileName == NULL) + return _scprintf(FormatString, SourceFile, Track) + 1; + else + return sprintf(FileName, FormatString, SourceFile, Track) + 1; +} + FFMS_API(FFIndexer *) FFMS_CreateIndexer(const char *SourceFile, char *ErrorMsg, unsigned MsgSize) { try { return FFIndexer::CreateFFIndexer(SourceFile, ErrorMsg, MsgSize); @@ -198,12 +229,13 @@ FFMS_API(FFIndexer *) FFMS_CreateIndexer(const char *SourceFile, char *ErrorMsg, } } -FFMS_API(FFIndex *) FFMS_DoIndexing(FFIndexer *Indexer, int IndexMask, int DumpMask, const char *AudioFile, bool IgnoreDecodeErrors, TIndexCallback IC, void *Private, char *ErrorMsg, unsigned MsgSize) { +FFMS_API(FFIndex *) FFMS_DoIndexing(FFIndexer *Indexer, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, bool IgnoreDecodeErrors, TIndexCallback IC, void *ICPrivate, char *ErrorMsg, unsigned MsgSize) { Indexer->SetIndexMask(IndexMask); Indexer->SetDumpMask(DumpMask); Indexer->SetIgnoreDecodeErrors(IgnoreDecodeErrors); - Indexer->SetProgressCallback(IC, Private); - FFIndex *Index = Indexer->DoIndexing(AudioFile, ErrorMsg, MsgSize); + Indexer->SetProgressCallback(IC, ICPrivate); + Indexer->SetAudioNameCallback(ANC, ANCPrivate); + FFIndex *Index = Indexer->DoIndexing(ErrorMsg, MsgSize); delete Indexer; return Index; } @@ -229,10 +261,3 @@ FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FFIndex *Index, char *Error FFMS_API(int) FFMS_GetPixFmt(const char *Name) { return avcodec_get_pix_fmt(Name); } - -FFMS_API(FFIndex *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, const char *AudioFile, bool IgnoreDecodeErrors, TIndexCallback IC, void *Private, char *ErrorMsg, unsigned MsgSize) { - FFIndexer *Indexer = FFMS_CreateIndexer(SourceFile, ErrorMsg, MsgSize); - if (!Indexer) - return NULL; - return FFMS_DoIndexing(Indexer, IndexMask, DumpMask, AudioFile, IgnoreDecodeErrors, IC, Private, ErrorMsg, MsgSize); -} diff --git a/aegisub/FFmpegSource2/ffms.h b/aegisub/FFmpegSource2/ffms.h index f189e297a..83843b4fc 100644 --- a/aegisub/FFmpegSource2/ffms.h +++ b/aegisub/FFmpegSource2/ffms.h @@ -117,12 +117,13 @@ struct TAudioProperties { double LastTime; }; -typedef int (FFMS_CC *TIndexCallback)(int64_t Current, int64_t Total, void *Private); -typedef int (FFMS_CC *TAudioNameCallback)(const char *SourceFile, int Track, const TAudioProperties *AP, char *FileName, unsigned FNSize); +typedef int (FFMS_CC *TIndexCallback)(int64_t Current, int64_t Total, void *ICPrivate); +typedef int (FFMS_CC *TAudioNameCallback)(const char *SourceFile, int Track, const TAudioProperties *AP, char *FileName, void *Private); // Most functions return 0 on success // Functions without error message output can be assumed to never fail -FFMS_API(void) FFMS_Init(); +FFMS_API(int) FFMS_Init(); +FFMS_API(void) FFMS_DeInit(); FFMS_API(int) FFMS_GetLogLevel(); FFMS_API(void) FFMS_SetLogLevel(int Level); FFMS_API(FFVideo *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, int SeekMode, char *ErrorMsg, unsigned MsgSize); @@ -151,14 +152,13 @@ FFMS_API(FFTrack *) FFMS_GetTrackFromVideo(FFVideo *V); FFMS_API(FFTrack *) FFMS_GetTrackFromAudio(FFAudio *A); FFMS_API(const TTrackTimeBase *) FFMS_GetTimeBase(FFTrack *T); FFMS_API(int) FFMS_WriteTimecodes(FFTrack *T, const char *TimecodeFile, char *ErrorMsg, unsigned MsgSize); +FFMS_API(FFIndex *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, bool IgnoreDecodeErrors, TIndexCallback IC, void *ICPrivate, char *ErrorMsg, unsigned MsgSize); +FFMS_API(int) FFMS_DefaultAudioFilename(const char *SourceFile, int Track, const TAudioProperties *AP, char *FileName, void *Private); FFMS_API(FFIndexer *) FFMS_CreateIndexer(const char *SourceFile, char *ErrorMsg, unsigned MsgSize); -FFMS_API(FFIndex *) FFMS_DoIndexing(FFIndexer *Indexer, int IndexMask, int DumpMask, const char *AudioFile, bool IgnoreDecodeErrors, TIndexCallback IC, void *Private, char *ErrorMsg, unsigned MsgSize); +FFMS_API(FFIndex *) FFMS_DoIndexing(FFIndexer *Indexer, int IndexMask, int DumpMask, TAudioNameCallback ANC, void *ANCPrivate, bool IgnoreDecodeErrors, TIndexCallback IC, void *ICPrivate, char *ErrorMsg, unsigned MsgSize); FFMS_API(void) FFMS_CancelIndexing(FFIndexer *Indexer); FFMS_API(FFIndex *) FFMS_ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize); FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FFIndex *Index, char *ErrorMsg, unsigned MsgSize); FFMS_API(int) FFMS_GetPixFmt(const char *Name); -// Deprecated, only provided for compatibility -FFMS_API(FFIndex *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, const char *AudioFile, bool IgnoreDecodeErrors, TIndexCallback IC, void *Private, char *ErrorMsg, unsigned MsgSize); - #endif diff --git a/aegisub/FFmpegSource2/ffms2.html b/aegisub/FFmpegSource2/ffms2.html index 25e22cdb9..9d82af309 100644 --- a/aegisub/FFmpegSource2/ffms2.html +++ b/aegisub/FFmpegSource2/ffms2.html @@ -225,28 +225,31 @@ tn:64:128:256

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

-

pthreads only required for ffmpeg-mt compiles

+

pthreads only required for FFmpeg-mt compiles

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

Suggested Additional Options: ---enable-pthreads --disable-encoders --disable-muxers --disable-network --disable-debug --enable-libfaad --disable-decoder=aac

+--enable-w32threads --disable-encoders --disable-muxers --disable-network --disable-debug --enable-libfaad --disable-decoder=aac

-Note that --enable-w32threads is required for multithreaded decoding to work. +Note that --enable-w32threads or --enable-pthreads is required for multithreaded decoding to work. For FFmpeg-mt only --enable-pthreads will work.

Changes

  • 2.00 beta 9
      +
    • Implemented audio decoding using Haali's splitters, FFAudioSource now works on ts, ps and ogm
    • +
    • Can now be compiled with ICL 10.1 (probably other versions too)
    • How indexing works has been split internally so the track numbers and types are reported, this makes it possible to create an interactive GUI or ask which audio tracks are to be indexed
    • Now has stricter index checking to detect when different FFmpeg versions were used to create an index of the same version
    • -
    • Fixed an access violation occurring when unindexed or empty audio tracks in matroska files were opened
    • +
    • Fixed memory leaks when audio sources were destroyed and when errors happened during indexing
    • +
    • Fixed access violations occurring when unindexed or empty audio tracks in matroska/lavf read files were opened
    • Less type conversion/signedness warnings
    • When audio track dumping is performed a custom callback can now be supplied to name the tracks
    • The audio track delay is now exposed in the API in the same way as video tracks
    • -
    • A big type and argument name cleanup in the API, many things have been renamed to be clearer and it should be completely C friendly now
    • +
    • A big type and argument name cleanup in the API, many things have been renamed to be clearer and ffms.h should be completely C friendly now
    • Removed FFNoLog and replaced it with FFSetLogLevel and FFGetLogLevel, the default logging is now also set to quiet, the magical numbers to supply it can be found in avutil/log.h
    • Updated FFmpeg to rev X (now with faad2 again by popular demand, updated to GCC 4.4.0 for compiling all libraries)
  • diff --git a/aegisub/FFmpegSource2/ffms2rt.cpp b/aegisub/FFmpegSource2/ffms2rt.cpp index 0076a502b..02475396a 100644 --- a/aegisub/FFmpegSource2/ffms2rt.cpp +++ b/aegisub/FFmpegSource2/ffms2rt.cpp @@ -23,125 +23,97 @@ extern "C" { #include } +#include #include #include #include "ffms.h" using namespace std; -//#define VERBOSE +#define VERBOSE static int FFMS_CC UpdateProgress(int64_t Current, int64_t Total, void *Private) { - static int LastPercentage = -1; + int LastPercentage = (int)Private; int Percentage = int((double(Current)/double(Total)) * 100); if (Percentage <= LastPercentage) return 0; - LastPercentage = Percentage; + Private = (void *)Percentage; #ifdef VERBOSE - cout << "Indexing " << static_cast(Private) << ", please wait... " << Percentage << "% \r" << flush; + cout << "Indexing, please wait... " << Percentage << "% \r" << flush; #endif return 0; } -int main(int argc, char *argv[]) { +void TestFullDump1(char *SrcFile, bool WithAudio) { char ErrorMsg[2000]; - AVMD5 *ctx = reinterpret_cast(new uint8_t[av_md5_size]); - uint8_t md5sum[16]; + int ret = FFMS_Init(); + assert(!ret); - if (argc != 2) - return -1; + FFIndexer *FIdx = FFMS_CreateIndexer(SrcFile, ErrorMsg, sizeof(ErrorMsg)); + assert(FIdx); + FFMS_CancelIndexing(FIdx); + FIdx = FFMS_CreateIndexer(SrcFile, ErrorMsg, sizeof(ErrorMsg)); + assert(FIdx); - FFMS_Init(); -#ifdef VERBOSE - FFMS_SetLogLevel(AV_LOG_INFO); -#endif + FFIndex *FI = FFMS_DoIndexing(FIdx, -1, -1, FFMS_DefaultAudioFilename, NULL, false, UpdateProgress, NULL, ErrorMsg, sizeof(ErrorMsg)); + assert(FI); - int FMT_YV12A = FFMS_GetPixFmt("yuv420p"); - int FMT_YV12B = FFMS_GetPixFmt("yuvj420p"); - int FMT_YUY2 = FFMS_GetPixFmt("yuv422p"); + int vtrack = FFMS_GetFirstTrackOfType(FI, FFMS_TYPE_VIDEO, ErrorMsg, sizeof(ErrorMsg)); + assert(vtrack >= 0); + int atrack = FFMS_GetFirstTrackOfType(FI, FFMS_TYPE_AUDIO, ErrorMsg, sizeof(ErrorMsg)); + assert(atrack >= 0); - av_md5_init(ctx); - FFIndex *FI = FFMS_MakeIndex(argv[1], -1, 0, NULL, false, UpdateProgress, argv[1], ErrorMsg, sizeof(ErrorMsg)); - if (!FI) { - cout << "Indexing error: " << ErrorMsg << endl; - return 1; - } + FFVideo *V = FFMS_CreateVideoSource(SrcFile, vtrack, FI, "", 1, 1, ErrorMsg, sizeof(ErrorMsg)); + assert(V); - int track = FFMS_GetFirstTrackOfType(FI, FFMS_TYPE_VIDEO, ErrorMsg, sizeof(ErrorMsg)); - if (track < 0) { - cout << "No usable track error: " << ErrorMsg << endl; - return 2; - } + if (WithAudio) { + uint8_t *DB = new uint8_t[100000]; + FFAudio *A = FFMS_CreateAudioSource(SrcFile, atrack, FI, ErrorMsg, sizeof(ErrorMsg)); + assert(A); - FFVideo *V = FFMS_CreateVideoSource(argv[1], track, FI, "", 1, 1, ErrorMsg, sizeof(ErrorMsg)); - FFMS_DestroyFFIndex(FI); - if (!V) { - cout << "Video source error: " << ErrorMsg << endl; - return 3; + const TAudioProperties *AP = FFMS_GetAudioProperties(A); + for (int i = 0; i < AP->NumSamples / 1000; i++) { + ret = FFMS_GetAudio(A, DB, i * 1000, 1000, ErrorMsg, sizeof(ErrorMsg)); + assert(!ret); + } + + FFMS_DestroyAudioSource(A); + delete[] DB; } const TVideoProperties *VP = FFMS_GetVideoProperties(V); for (int i = 0; i < VP->NumFrames; i++) { const TAVFrameLite *AVF = FFMS_GetFrame(V, i, ErrorMsg, sizeof(ErrorMsg)); - if (!AVF) { - cout << "Frame request error: " << ErrorMsg << " at frame " << i << endl; - return 4; - } - -#ifdef VERBOSE - int LastPercentage = -1; - int Percentage = int((double(i)/double(VP->NumFrames)) * 100); - - if (Percentage > LastPercentage) { - LastPercentage = Percentage; - cout << "Requesting frames " << argv[1] << ", please wait... " << Percentage << "% \r" << flush; - } -#endif - - uint8_t *Data[3]; - Data[0] = AVF->Data[0]; - Data[1] = AVF->Data[1]; - Data[2] = AVF->Data[2]; - - if (VP->VPixelFormat == FMT_YV12A || VP->VPixelFormat == FMT_YV12B) { - for (int j = 0; j < VP->Height / 2; j++) { - av_md5_update(ctx, Data[0], VP->Width); - Data[0] += AVF->Linesize[0]; - av_md5_update(ctx, Data[0], VP->Width); - Data[0] += AVF->Linesize[0]; - av_md5_update(ctx, Data[1], VP->Width / 2); - Data[1] += AVF->Linesize[1]; - av_md5_update(ctx, Data[2], VP->Width / 2); - Data[2] += AVF->Linesize[2]; - } - } else if (VP->VPixelFormat == FMT_YUY2) { - for (int j = 0; j < VP->Height / 2; j++) { - av_md5_update(ctx, Data[0], VP->Width); - Data[0] += AVF->Linesize[0]; - av_md5_update(ctx, Data[0], VP->Width); - Data[0] += AVF->Linesize[0]; - av_md5_update(ctx, Data[1], VP->Width / 2); - Data[1] += AVF->Linesize[1]; - av_md5_update(ctx, Data[2], VP->Width / 2); - Data[2] += AVF->Linesize[2]; - } - } + assert(AVF); } + FFMS_DestroyFFIndex(FI); FFMS_DestroyVideoSource(V); - av_md5_final(ctx, md5sum); + FFMS_DeInit(); +} - delete[] reinterpret_cast(ctx); +int main(int argc, char *argv[]) { + char *TestFiles1[10]; + TestFiles1[0] = "[FLV1]_The_Melancholy_of_Haruhi_Suzumiya_-_Full_Clean_Ending.flv"; + TestFiles1[1] = "jra_jupiter.avi"; + TestFiles1[2] = "h264_16-bframes_16-references_pyramid_crash-indexing.mkv"; + TestFiles1[3] = "pyramid-adaptive-10-bframes.mkv"; + TestFiles1[4] = "negative-timecodes.avi"; + TestFiles1[5] = "Zero1_ITV2_TS_Test.ts"; - cout << "Test successful, MD5: " << hex; - for (int i = 0; i < sizeof(md5sum); i++) - cout << static_cast(md5sum[i]); - cout << endl; + for (int i = 0; i < 5; i++) + TestFullDump1(TestFiles1[5], true); +/* + TestFullDump1(TestFiles1[5], false); + for (int i = 0; i < 5; i++) + TestFullDump1(TestFiles1[i], true); + TestFullDump1(TestFiles1[5], false); +*/ return 0; -} \ No newline at end of file +} diff --git a/aegisub/FFmpegSource2/ffmsindex.cpp b/aegisub/FFmpegSource2/ffmsindex.cpp index 779ae9f9a..bcb1116c3 100644 --- a/aegisub/FFmpegSource2/ffmsindex.cpp +++ b/aegisub/FFmpegSource2/ffmsindex.cpp @@ -186,7 +186,10 @@ int main(int argc, char *argv[]) { return 1; } - FFMS_Init(); + if (FFMS_Init()) { + std::cout << std::endl << "Error: initialization failed" << std::endl; + return 1; + } if (Verbose) FFMS_SetLogLevel(AV_LOG_INFO); @@ -208,5 +211,6 @@ int main(int argc, char *argv[]) { } FFMS_DestroyFFIndex(Index); + FFMS_DeInit(); return 0; } diff --git a/aegisub/FFmpegSource2/ffvideosource.cpp b/aegisub/FFmpegSource2/ffvideosource.cpp index bad82a1af..f2c1008ae 100644 --- a/aegisub/FFmpegSource2/ffvideosource.cpp +++ b/aegisub/FFmpegSource2/ffvideosource.cpp @@ -228,7 +228,7 @@ FFLAVFVideo::FFLAVFVideo(const char *SourceFile, int Track, FFIndex *Index, // Always try to decode a frame to make sure all required parameters are known int64_t Dummy; - if (DecodeNextFrame(DecodeFrame, &Dummy, ErrorMsg, MsgSize)) { + if (DecodeNextFrame(&Dummy, ErrorMsg, MsgSize)) { Free(true); throw ErrorMsg; } @@ -279,7 +279,7 @@ FFLAVFVideo::~FFLAVFVideo() { Free(true); } -int FFLAVFVideo::DecodeNextFrame(AVFrame *AFrame, int64_t *AStartTime, char *ErrorMsg, unsigned MsgSize) { +int FFLAVFVideo::DecodeNextFrame(int64_t *AStartTime, char *ErrorMsg, unsigned MsgSize) { AVPacket Packet; InitNullPacket(&Packet); int FrameFinished = 0; @@ -290,7 +290,7 @@ int FFLAVFVideo::DecodeNextFrame(AVFrame *AFrame, int64_t *AStartTime, char *Err if (*AStartTime < 0) *AStartTime = Packet.dts; - avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &Packet); + avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &Packet); } av_free_packet(&Packet); @@ -303,7 +303,7 @@ int FFLAVFVideo::DecodeNextFrame(AVFrame *AFrame, int64_t *AStartTime, char *Err if (CodecContext->has_b_frames) { AVPacket NullPacket; InitNullPacket(&NullPacket); - avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &NullPacket); + avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &NullPacket); } if (!FrameFinished) @@ -349,7 +349,7 @@ ReSeek: do { int64_t StartTime; - if (DecodeNextFrame(DecodeFrame, &StartTime, ErrorMsg, MsgSize)) + if (DecodeNextFrame(&StartTime, ErrorMsg, MsgSize)) return NULL; if (HasSeeked) { @@ -460,7 +460,7 @@ FFMatroskaVideo::FFMatroskaVideo(const char *SourceFile, int Track, // Always try to decode a frame to make sure all required parameters are known int64_t Dummy; - if (DecodeNextFrame(DecodeFrame, &Dummy, ErrorMsg, MsgSize)) { + if (DecodeNextFrame(&Dummy, ErrorMsg, MsgSize)) { Free(true); throw ErrorMsg; } @@ -510,7 +510,7 @@ FFMatroskaVideo::~FFMatroskaVideo() { Free(true); } -int FFMatroskaVideo::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize) { +int FFMatroskaVideo::DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize) { int FrameFinished = 0; *AFirstStartTime = -1; AVPacket Packet; @@ -532,7 +532,7 @@ int FFMatroskaVideo::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, Packet.flags = PKT_FLAG_KEY; else Packet.flags = 0; - avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &Packet); + avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &Packet); if (FrameFinished) goto Done; @@ -542,7 +542,7 @@ int FFMatroskaVideo::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, if (CodecContext->has_b_frames) { AVPacket NullPacket; InitNullPacket(&NullPacket); - avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &NullPacket); + avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &NullPacket); } if (!FrameFinished) @@ -568,7 +568,7 @@ TAVFrameLite *FFMatroskaVideo::GetFrame(int n, char *ErrorMsg, unsigned MsgSize) do { int64_t StartTime; - if (DecodeNextFrame(DecodeFrame, &StartTime, ErrorMsg, MsgSize)) + if (DecodeNextFrame(&StartTime, ErrorMsg, MsgSize)) return NULL; if (HasSeeked) { @@ -600,6 +600,7 @@ FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, int SourceMode, char *ErrorMsg, unsigned MsgSize) { + CodecPrivate = NULL; AVCodec *Codec = NULL; CodecContext = NULL; VideoTrack = Track; @@ -610,8 +611,6 @@ FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track, throw ErrorMsg; } - ::CoInitializeEx(NULL, COINIT_MULTITHREADED); - CLSID clsid = HAALI_TS_Parser; if (SourceMode == 1) clsid = HAALI_OGM_Parser; @@ -646,7 +645,6 @@ FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track, throw ErrorMsg; } - CodecPrivate = NULL; int CodecPrivateSize = 0; int CurrentTrack = 0; CComPtr pEU; @@ -698,7 +696,7 @@ FFHaaliVideo::FFHaaliVideo(const char *SourceFile, int Track, // Always try to decode a frame to make sure all required parameters are known int64_t Dummy; - if (DecodeNextFrame(DecodeFrame, &Dummy, ErrorMsg, MsgSize)) { + if (DecodeNextFrame(&Dummy, ErrorMsg, MsgSize)) { Free(true); throw ErrorMsg; } @@ -741,7 +739,7 @@ FFHaaliVideo::~FFHaaliVideo() { Free(true); } -int FFHaaliVideo::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize) { +int FFHaaliVideo::DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize) { int FrameFinished = 0; *AFirstStartTime = -1; AVPacket Packet; @@ -768,7 +766,7 @@ int FFHaaliVideo::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, cha else Packet.flags = 0; - avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &Packet); + avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &Packet); if (FrameFinished) goto Done; @@ -779,7 +777,7 @@ int FFHaaliVideo::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, cha if (CodecContext->has_b_frames) { AVPacket NullPacket; InitNullPacket(&NullPacket); - avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &NullPacket); + avcodec_decode_video2(CodecContext, DecodeFrame, &FrameFinished, &NullPacket); } if (!FrameFinished) @@ -807,7 +805,7 @@ ReSeek: do { int64_t StartTime; - if (DecodeNextFrame(DecodeFrame, &StartTime, ErrorMsg, MsgSize)) + if (DecodeNextFrame(&StartTime, ErrorMsg, MsgSize)) return NULL; if (HasSeeked) { diff --git a/aegisub/FFmpegSource2/ffvideosource.h b/aegisub/FFmpegSource2/ffvideosource.h index 384d26ac5..ee297e995 100644 --- a/aegisub/FFmpegSource2/ffvideosource.h +++ b/aegisub/FFmpegSource2/ffvideosource.h @@ -79,7 +79,7 @@ private: int SeekMode; void Free(bool CloseCodec); - int DecodeNextFrame(AVFrame *Frame, int64_t *DTS, char *ErrorMsg, unsigned MsgSize); + int DecodeNextFrame(int64_t *DTS, char *ErrorMsg, unsigned MsgSize); public: FFLAVFVideo(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, int SeekMode, char *ErrorMsg, unsigned MsgSize); ~FFLAVFVideo(); @@ -94,7 +94,7 @@ private: char ErrorMessage[256]; void Free(bool CloseCodec); - int DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize); + int DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize); public: FFMatroskaVideo(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, char *ErrorMsg, unsigned MsgSize); ~FFMatroskaVideo(); @@ -107,8 +107,9 @@ class FFHaaliVideo : public FFVideo { private: CComPtr pMMC; uint8_t * CodecPrivate; + void Free(bool CloseCodec); - int DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize); + int DecodeNextFrame(int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize); public: FFHaaliVideo(const char *SourceFile, int Track, FFIndex *Index, const char *PP, int Threads, int SourceMode, char *ErrorMsg, unsigned MsgSize); ~FFHaaliVideo(); diff --git a/aegisub/FFmpegSource2/indexing.cpp b/aegisub/FFmpegSource2/indexing.cpp index 1e50bcb04..ccd176547 100644 --- a/aegisub/FFmpegSource2/indexing.cpp +++ b/aegisub/FFmpegSource2/indexing.cpp @@ -25,7 +25,6 @@ #include #include #include "indexing.h" -#include "wave64writer.h" #ifdef __UNIX__ #define _fseeki64 fseeko @@ -51,48 +50,30 @@ extern "C" { # include "guids.h" #endif -class MatroskaAudioContext { +class MatroskaAudioContext : public SharedAudioContext { public: - Wave64Writer *W64W; - AVCodecContext *CTX; CompressedStream *CS; - int64_t CurrentSample; uint8_t *CodecPrivate; MatroskaAudioContext() { - W64W = NULL; - CTX = NULL; CS = NULL; - CurrentSample = 0; CodecPrivate = NULL; } ~MatroskaAudioContext() { - delete[] CodecPrivate; - delete W64W; if (CTX) { avcodec_close(CTX); av_free(CTX); } if (CS) cs_Destroy(CS); + delete[] CodecPrivate; } }; -class FFAudioContext { +class FFAudioContext : public SharedAudioContext { public: - Wave64Writer *W64W; - AVCodecContext *CTX; - int64_t CurrentSample; - - FFAudioContext() { - W64W = NULL; - CTX = NULL; - CurrentSample = 0; - } - ~FFAudioContext() { - delete W64W; if (CTX) avcodec_close(CTX); } @@ -101,42 +82,34 @@ public: #ifdef HAALISOURCE class HaaliIndexMemory { private: - int16_t *DecodingBuffer; MatroskaAudioContext *AudioContexts; public: - HaaliIndexMemory(int Tracks, int16_t *&DecodingBuffer, MatroskaAudioContext *&AudioContexts) { - DecodingBuffer = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*10]; + HaaliIndexMemory(int Tracks, MatroskaAudioContext *&AudioContexts) { AudioContexts = new MatroskaAudioContext[Tracks]; - this->DecodingBuffer = DecodingBuffer; this->AudioContexts = AudioContexts; } ~HaaliIndexMemory() { - delete [] DecodingBuffer; - delete [] AudioContexts; + delete[] AudioContexts; } }; #endif class MatroskaIndexMemory { private: - int16_t *DecodingBuffer; MatroskaAudioContext *AudioContexts; MatroskaFile *MF; MatroskaReaderContext *MC; public: - MatroskaIndexMemory(int Tracks, int16_t *&DecodingBuffer, MatroskaAudioContext *&AudioContexts, MatroskaFile *MF, MatroskaReaderContext *MC) { - DecodingBuffer = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*10]; + MatroskaIndexMemory(int Tracks, MatroskaAudioContext *&AudioContexts, MatroskaFile *MF, MatroskaReaderContext *MC) { AudioContexts = new MatroskaAudioContext[Tracks]; - this->DecodingBuffer = DecodingBuffer; this->AudioContexts = AudioContexts; this->MF = MF; this->MC = MC; } ~MatroskaIndexMemory() { - delete [] DecodingBuffer; - delete [] AudioContexts; + delete[] AudioContexts; mkv_Close(MF); fclose(MC->ST.fp); } @@ -144,21 +117,17 @@ public: class FFIndexMemory { private: - int16_t *DecodingBuffer; FFAudioContext *AudioContexts; AVFormatContext *FormatContext; public: - FFIndexMemory(int Tracks, int16_t *&DecodingBuffer, FFAudioContext *&AudioContexts, AVFormatContext *&FormatContext) { - DecodingBuffer = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*10]; + FFIndexMemory(int Tracks, FFAudioContext *&AudioContexts, AVFormatContext *&FormatContext) { AudioContexts = new FFAudioContext[Tracks]; - this->DecodingBuffer = DecodingBuffer; this->AudioContexts = AudioContexts; this->FormatContext = FormatContext; } ~FFIndexMemory() { - delete [] DecodingBuffer; - delete [] AudioContexts; + delete[] AudioContexts; av_close_input_file(FormatContext); } }; @@ -167,19 +136,44 @@ static bool DTSComparison(TFrameInfo FI1, TFrameInfo FI2) { return FI1.DTS < FI2.DTS; } -static void SortTrackIndices(FFIndex *Index) { +static void SortTrackIndex(FFIndex *Index) { for (FFIndex::iterator Cur=Index->begin(); Cur!=Index->end(); Cur++) std::sort(Cur->begin(), Cur->end(), DTSComparison); } +bool FFIndexer::WriteAudio(SharedAudioContext &AudioContext, FFIndex *Index, int Track, int DBSize, char *ErrorMsg, unsigned MsgSize) { + // Delay writer creation until after an audio frame has been decoded. This ensures that all parameters are known when writing the headers. + if (DBSize > 0) { + if (!AudioContext.W64W) { + TAudioProperties AP; + FillAP(AP, AudioContext.CTX, (*Index)[Track]); + char *WName = new char[(*ANC)(SourceFile, Track, &AP, NULL, ANCPrivate)]; + (*ANC)(SourceFile, Track, &AP, WName, ANCPrivate); + std::string WN(WName); + delete[] WName; + try { + AudioContext.W64W = new Wave64Writer(WN.c_str(), av_get_bits_per_sample_format(AudioContext.CTX->sample_fmt), + AudioContext.CTX->channels, AudioContext.CTX->sample_rate, AudioFMTIsFloat(AudioContext.CTX->sample_fmt)); + } catch (...) { + _snprintf(ErrorMsg, MsgSize, "Failed to write wave data"); + return false; + } + } + + AudioContext.W64W->WriteData(DecodingBuffer, DBSize); + } + + return true; +} + #ifdef HAALISOURCE -FFHaaliIndexer::FFHaaliIndexer(const char *SourceFile, int SourceMode, char *ErrorMsg, unsigned MsgSize) { +FFHaaliIndexer::FFHaaliIndexer(const char *Filename, int SourceMode, char *ErrorMsg, unsigned MsgSize) { + SourceFile = Filename; this->SourceMode = SourceMode; memset(TrackType, FFMS_TYPE_UNKNOWN, sizeof(TrackType)); memset(Codec, 0, sizeof(Codec)); memset(CodecPrivate, 0, sizeof(CodecPrivate)); memset(CodecPrivateSize, 0, sizeof(CodecPrivateSize)); - ::CoInitializeEx(NULL, COINIT_MULTITHREADED); CLSID clsid = HAALI_TS_Parser; if (SourceMode == 1) @@ -250,13 +244,12 @@ FFHaaliIndexer::FFHaaliIndexer(const char *SourceFile, int SourceMode, char *Err } } -FFIndex *FFHaaliIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsigned MsgSize) { +FFIndex *FFHaaliIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) { // Audio stuff - int16_t *db; MatroskaAudioContext *AudioContexts; - HaaliIndexMemory IM = HaaliIndexMemory(NumTracks, db, AudioContexts); + HaaliIndexMemory IM = HaaliIndexMemory(NumTracks, AudioContexts); - FFIndex *TrackIndices = new FFIndex(); + std::auto_ptr TrackIndices(new FFIndex()); TrackIndices->Decoder = 2; if (SourceMode == 1) TrackIndices->Decoder = 3; @@ -295,9 +288,8 @@ FFIndex *FFHaaliIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsig for (;;) { if (IC) { - if ((*IC)(0, 1, Private)) { + if ((*IC)(0, 1, ICPrivate)) { _snprintf(ErrorMsg, MsgSize, "Cancelled by user"); - delete TrackIndices; return NULL; } } @@ -309,28 +301,27 @@ FFIndex *FFHaaliIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsig REFERENCE_TIME Ts, Te; HRESULT hr = pMMF->GetTime(&Ts, &Te); - unsigned int CurrentTrack = pMMF->GetTrack(); + unsigned int Track = pMMF->GetTrack(); // Only create index entries for video for now to save space - if (TrackType[CurrentTrack] == FFMS_TYPE_VIDEO) { - (*TrackIndices)[CurrentTrack].push_back(TFrameInfo(Ts, pMMF->IsSyncPoint() == S_OK)); - } else if (TrackType[CurrentTrack] == FFMS_TYPE_AUDIO && (IndexMask & (1 << CurrentTrack))) { - (*TrackIndices)[CurrentTrack].push_back(TFrameInfo(Ts, AudioContexts[CurrentTrack].CurrentSample, 0 /* FIXME? */, pMMF->GetActualDataLength(), pMMF->IsSyncPoint() == S_OK)); - AVCodecContext *AudioCodecContext = AudioContexts[CurrentTrack].CTX; + if (TrackType[Track] == FFMS_TYPE_VIDEO) { + (*TrackIndices)[Track].push_back(TFrameInfo(Ts, pMMF->IsSyncPoint() == S_OK)); + } else if (TrackType[Track] == FFMS_TYPE_AUDIO && (IndexMask & (1 << Track))) { + (*TrackIndices)[Track].push_back(TFrameInfo(Ts, AudioContexts[Track].CurrentSample, 0 /* FIXME? */, pMMF->GetActualDataLength(), pMMF->IsSyncPoint() == S_OK)); + AVCodecContext *AudioCodecContext = AudioContexts[Track].CTX; pMMF->GetPointer(&TempPacket.data); TempPacket.size = pMMF->GetActualDataLength(); while (TempPacket.size > 0) { int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10; - int Ret = avcodec_decode_audio3(AudioCodecContext, db, &dbsize, &TempPacket); + int Ret = avcodec_decode_audio3(AudioCodecContext, DecodingBuffer, &dbsize, &TempPacket); if (Ret < 0) { if (IgnoreDecodeErrors) { - (*TrackIndices)[CurrentTrack].clear(); - IndexMask &= ~(1 << CurrentTrack); + (*TrackIndices)[Track].clear(); + IndexMask &= ~(1 << Track); break; } else { _snprintf(ErrorMsg, MsgSize, "Audio decoding error"); - delete TrackIndices; return NULL; } } @@ -341,33 +332,21 @@ FFIndex *FFHaaliIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsig } if (dbsize > 0) - AudioContexts[CurrentTrack].CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_format(AudioCodecContext->sample_fmt) * AudioCodecContext->channels); + AudioContexts[Track].CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_format(AudioCodecContext->sample_fmt) * AudioCodecContext->channels); - if (dbsize > 0 && (DumpMask & (1 << CurrentTrack))) { - // Delay writer creation until after an audio frame has been decoded. This ensures that all parameters are known when writing the headers. - if (!AudioContexts[CurrentTrack].W64W) { - AVCodecContext *CTX = AudioContexts[CurrentTrack].CTX; - char ABuf[50]; - std::string WN(AudioFile); - _snprintf(ABuf, sizeof(ABuf), ".%02d.delay.%d.w64", CurrentTrack, 0); - WN += ABuf; - - AudioContexts[CurrentTrack].W64W = new Wave64Writer(WN.c_str(), av_get_bits_per_sample_format(AudioCodecContext->sample_fmt), - AudioCodecContext->channels, AudioCodecContext->sample_rate, AudioFMTIsFloat(AudioCodecContext->sample_fmt)); - } - - AudioContexts[CurrentTrack].W64W->WriteData(db, dbsize); - } + if (DumpMask & (1 << Track)) + WriteAudio(AudioContexts[Track], TrackIndices.get(), Track, dbsize, ErrorMsg, MsgSize); } } } - SortTrackIndices(TrackIndices); - return TrackIndices; + SortTrackIndex(TrackIndices.get()); + return TrackIndices.release(); } #endif -FFMatroskaIndexer::FFMatroskaIndexer(const char *SourceFile, char *ErrorMsg, unsigned MsgSize) { +FFMatroskaIndexer::FFMatroskaIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize) { + SourceFile = Filename; char ErrorMessage[256]; InitStdIoStream(&MC.ST); @@ -387,13 +366,12 @@ FFMatroskaIndexer::FFMatroskaIndexer(const char *SourceFile, char *ErrorMsg, uns } } -FFIndex *FFMatroskaIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsigned MsgSize) { +FFIndex *FFMatroskaIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) { char ErrorMessage[256]; // Audio stuff - int16_t *db; MatroskaAudioContext *AudioContexts; - MatroskaIndexMemory IM = MatroskaIndexMemory(mkv_GetNumTracks(MF), db, AudioContexts, MF, &MC); + MatroskaIndexMemory IM = MatroskaIndexMemory(mkv_GetNumTracks(MF), AudioContexts, MF, &MC); for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) { TrackInfo *TI = mkv_GetTrackInfo(MF, i); @@ -439,7 +417,7 @@ FFIndex *FFMatroskaIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, un int64_t SourceSize = _ftelli64(MC.ST.fp); _fseeki64(MC.ST.fp, CurrentPos, SEEK_SET); - FFIndex *TrackIndices = new FFIndex(); + std::auto_ptr TrackIndices(new FFIndex()); TrackIndices->Decoder = 1; for (unsigned int i = 0; i < mkv_GetNumTracks(MF); i++) @@ -453,9 +431,8 @@ FFIndex *FFMatroskaIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, un while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) { // Update progress if (IC) { - if ((*IC)(_ftelli64(MC.ST.fp), SourceSize, Private)) { + if ((*IC)(_ftelli64(MC.ST.fp), SourceSize, ICPrivate)) { _snprintf(ErrorMsg, MsgSize, "Cancelled by user"); - delete TrackIndices; return NULL; } } @@ -472,7 +449,7 @@ FFIndex *FFMatroskaIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, un while (TempPacket.size > 0) { int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10; - int Ret = avcodec_decode_audio3(AudioCodecContext, db, &dbsize, &TempPacket); + int Ret = avcodec_decode_audio3(AudioCodecContext, DecodingBuffer, &dbsize, &TempPacket); if (Ret < 0) { if (IgnoreDecodeErrors) { (*TrackIndices)[Track].clear(); @@ -480,7 +457,6 @@ FFIndex *FFMatroskaIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, un break; } else { _snprintf(ErrorMsg, MsgSize, "Audio decoding error"); - delete TrackIndices; return NULL; } } @@ -493,27 +469,14 @@ FFIndex *FFMatroskaIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, un if (dbsize > 0) AudioContexts[Track].CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_format(AudioCodecContext->sample_fmt) * AudioCodecContext->channels); - if (dbsize > 0 && (DumpMask & (1 << Track))) { - // Delay writer creation until after an audio frame has been decoded. This ensures that all parameters are known when writing the headers. - if (!AudioContexts[Track].W64W) { - char ABuf[50]; - std::string WN(AudioFile); - int Offset = StartTime * mkv_TruncFloat(mkv_GetTrackInfo(MF, Track)->TimecodeScale) / (double)1000000; - _snprintf(ABuf, sizeof(ABuf), ".%02d.delay.%d.w64", Track, Offset); - WN += ABuf; - - AudioContexts[Track].W64W = new Wave64Writer(WN.c_str(), av_get_bits_per_sample_format(AudioCodecContext->sample_fmt), - AudioCodecContext->channels, AudioCodecContext->sample_rate, AudioFMTIsFloat(AudioCodecContext->sample_fmt)); - } - - AudioContexts[Track].W64W->WriteData(db, dbsize); - } + if (DumpMask & (1 << Track)) + WriteAudio(AudioContexts[Track], TrackIndices.get(), Track, dbsize, ErrorMsg, MsgSize); } } } - SortTrackIndices(TrackIndices); - return TrackIndices; + SortTrackIndex(TrackIndices.get()); + return TrackIndices.release(); } FFIndexer *FFIndexer::CreateFFIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize) { @@ -543,12 +506,13 @@ FFIndexer *FFIndexer::CreateFFIndexer(const char *Filename, char *ErrorMsg, unsi } #endif - return new FFLAVFIndexer(FormatContext, ErrorMsg, MsgSize); + return new FFLAVFIndexer(Filename, FormatContext, ErrorMsg, MsgSize); } -FFLAVFIndexer::FFLAVFIndexer(AVFormatContext *FormatContext, char *ErrorMsg, unsigned MsgSize) { - IsIndexing = false; +FFLAVFIndexer::FFLAVFIndexer(const char *Filename, AVFormatContext *FormatContext, char *ErrorMsg, unsigned MsgSize) { + SourceFile = Filename; this->FormatContext = FormatContext; + IsIndexing = false; if (av_find_stream_info(FormatContext) < 0) { av_close_input_file(FormatContext); @@ -562,13 +526,12 @@ FFLAVFIndexer::~FFLAVFIndexer() { av_close_input_file(FormatContext); } -FFIndex *FFLAVFIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsigned MsgSize) { +FFIndex *FFLAVFIndexer::DoIndexing(char *ErrorMsg, unsigned MsgSize) { IsIndexing = true; // Audio stuff - int16_t *db; FFAudioContext *AudioContexts; - FFIndexMemory IM = FFIndexMemory(FormatContext->nb_streams, db, AudioContexts, FormatContext); + FFIndexMemory IM = FFIndexMemory(FormatContext->nb_streams, AudioContexts, FormatContext); for (unsigned int i = 0; i < FormatContext->nb_streams; i++) { if (IndexMask & (1 << i) && FormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) { @@ -593,7 +556,7 @@ FFIndex *FFLAVFIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsign // - FFIndex *TrackIndices = new FFIndex(); + std::auto_ptr TrackIndices(new FFIndex()); TrackIndices->Decoder = 0; for (unsigned int i = 0; i < FormatContext->nb_streams; i++) @@ -607,9 +570,8 @@ FFIndex *FFLAVFIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsign while (av_read_frame(FormatContext, &Packet) >= 0) { // Update progress if (IC) { - if ((*IC)(FormatContext->pb->pos, FormatContext->file_size, Private)) { + if ((*IC)(FormatContext->pb->pos, FormatContext->file_size, ICPrivate)) { _snprintf(ErrorMsg, MsgSize, "Cancelled by user"); - delete TrackIndices; return NULL; } } @@ -625,7 +587,7 @@ FFIndex *FFLAVFIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsign while (TempPacket.size > 0) { int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10; - int Ret = avcodec_decode_audio3(AudioCodecContext, db, &dbsize, &TempPacket); + int Ret = avcodec_decode_audio3(AudioCodecContext, DecodingBuffer, &dbsize, &TempPacket); if (Ret < 0) { if (IgnoreDecodeErrors) { (*TrackIndices)[Packet.stream_index].clear(); @@ -633,7 +595,6 @@ FFIndex *FFLAVFIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsign break; } else { _snprintf(ErrorMsg, MsgSize, "Audio decoding error"); - delete TrackIndices; return NULL; } } @@ -646,28 +607,14 @@ FFIndex *FFLAVFIndexer::DoIndexing(const char *AudioFile, char *ErrorMsg, unsign if (dbsize > 0) AudioContexts[Packet.stream_index].CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_format(AudioCodecContext->sample_fmt) * AudioCodecContext->channels); - if (dbsize > 0 && (DumpMask & (1 << Packet.stream_index))) { - // Delay writer creation until after an audio frame has been decoded. This ensures that all parameters are known when writing the headers. - if (!AudioContexts[Packet.stream_index].W64W) { - char ABuf[50]; - std::string WN(AudioFile); - int Offset = (Packet.dts * FormatContext->streams[Packet.stream_index]->time_base.num) - / (double)(FormatContext->streams[Packet.stream_index]->time_base.den * 1000); - _snprintf(ABuf, sizeof(ABuf), ".%02d.delay.%d.w64", Packet.stream_index, Offset); - WN += ABuf; - - AudioContexts[Packet.stream_index].W64W = new Wave64Writer(WN.c_str(), av_get_bits_per_sample_format(AudioCodecContext->sample_fmt), - AudioCodecContext->channels, AudioCodecContext->sample_rate, AudioFMTIsFloat(AudioCodecContext->sample_fmt)); - } - - AudioContexts[Packet.stream_index].W64W->WriteData(db, dbsize); - } + if (DumpMask & (1 << Packet.stream_index)) + WriteAudio(AudioContexts[Packet.stream_index], TrackIndices.get(), Packet.stream_index, dbsize, ErrorMsg, MsgSize); } } av_free_packet(&Packet); } - SortTrackIndices(TrackIndices); - return TrackIndices; + SortTrackIndex(TrackIndices.get()); + return TrackIndices.release(); } diff --git a/aegisub/FFmpegSource2/indexing.h b/aegisub/FFmpegSource2/indexing.h index c007b6d85..c30d5de7e 100644 --- a/aegisub/FFmpegSource2/indexing.h +++ b/aegisub/FFmpegSource2/indexing.h @@ -22,9 +22,9 @@ #define INDEXING_H #include "utils.h" -#include "ffms.h" +#include "wave64writer.h" -#define INDEXVERSION 24 +#define INDEXVERSION 25 #define INDEXID 0x53920873 struct IndexHeader { @@ -39,21 +39,45 @@ struct IndexHeader { uint32_t LPPVersion; }; +class SharedAudioContext { +public: + Wave64Writer *W64W; + AVCodecContext *CTX; + int64_t CurrentSample; + + SharedAudioContext() { + W64W = NULL; + CTX = NULL; + CurrentSample = 0; + } + + ~SharedAudioContext() { + delete W64W; + } +}; + class FFIndexer { protected: int IndexMask; int DumpMask; bool IgnoreDecodeErrors; TIndexCallback IC; - void *Private; + void *ICPrivate; + TAudioNameCallback ANC; + void *ANCPrivate; + const char *SourceFile; + int16_t DecodingBuffer[AVCODEC_MAX_AUDIO_FRAME_SIZE * 5]; + + bool WriteAudio(SharedAudioContext &AudioContext, FFIndex *Index, int Track, int DBSize, char *ErrorMsg, unsigned MsgSize); public: static FFIndexer *CreateFFIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize); virtual ~FFIndexer() { } void SetIndexMask(int IndexMask) { this->IndexMask = IndexMask; } void SetDumpMask(int DumpMask) { this->DumpMask = DumpMask; } void SetIgnoreDecodeErrors(bool IgnoreDecodeErrors) { this->IgnoreDecodeErrors = IgnoreDecodeErrors; } - void SetProgressCallback(TIndexCallback IC, void *Private) { this->IC = IC; this->Private = Private; } - virtual FFIndex *DoIndexing(const char *AudioFile, char *ErrorMsg, unsigned MsgSize) = 0; + void SetProgressCallback(TIndexCallback IC, void *ICPrivate) { this->IC = IC; this->ICPrivate = ICPrivate; } + void SetAudioNameCallback(TAudioNameCallback ANC, void *ANCPrivate) { this->ANC = ANC; this->ANCPrivate = ANCPrivate; } + virtual FFIndex *DoIndexing(char *ErrorMsg, unsigned MsgSize) = 0; virtual int GetNumberOfTracks() = 0; virtual FFMS_TrackType GetTrackType(int Track) = 0; virtual const char *GetTrackCodec(int Track) = 0; @@ -64,9 +88,9 @@ private: bool IsIndexing; AVFormatContext *FormatContext; public: - FFLAVFIndexer(AVFormatContext *FormatContext, char *ErrorMsg, unsigned MsgSize); + FFLAVFIndexer(const char *Filename, AVFormatContext *FormatContext, char *ErrorMsg, unsigned MsgSize); ~FFLAVFIndexer(); - FFIndex *DoIndexing(const char *AudioFile, char *ErrorMsg, unsigned MsgSize); + FFIndex *DoIndexing(char *ErrorMsg, unsigned MsgSize); int GetNumberOfTracks() { return FormatContext->nb_streams; } FFMS_TrackType GetTrackType(int Track) { return static_cast(FormatContext->streams[Track]->codec->codec_type); } const char *GetTrackCodec(int Track) { return FormatContext->streams[Track]->codec->codec_name; } @@ -78,7 +102,7 @@ private: MatroskaReaderContext MC; public: FFMatroskaIndexer(const char *Filename, char *ErrorMsg, unsigned MsgSize); - FFIndex *DoIndexing(const char *AudioFile, char *ErrorMsg, unsigned MsgSize); + FFIndex *DoIndexing(char *ErrorMsg, unsigned MsgSize); int GetNumberOfTracks() { return mkv_GetNumTracks(MF); } FFMS_TrackType GetTrackType(int Track) { return HaaliTrackTypeToFFTrackType(mkv_GetTrackInfo(MF, Track)->Type); } const char *GetTrackCodec(int Track) { return mkv_GetTrackInfo(MF, Track)->CodecID; } @@ -98,7 +122,7 @@ private: public: FFHaaliIndexer(const char *Filename, int SourceMode, char *ErrorMsg, unsigned MsgSize); ~FFHaaliIndexer() { for (int i = 0; i < 32; i++) delete[] CodecPrivate[i]; } - FFIndex *DoIndexing(const char *AudioFile, char *ErrorMsg, unsigned MsgSize); + FFIndex *DoIndexing(char *ErrorMsg, unsigned MsgSize); int GetNumberOfTracks() { return NumTracks; } FFMS_TrackType GetTrackType(int Track) { return TrackType[Track]; } const char *GetTrackCodec(int Track) { if (Codec[Track]) return Codec[Track]->name; else return "Unsupported codec/Unknown codec name"; }