Added audio decoding using Haali's splitters
Restructuring
Big API changes
Many bug fixes

Originally committed to SVN as r2972.
This commit is contained in:
Fredrik Mellbin 2009-05-22 21:28:02 +00:00
parent 8a04053ff2
commit d2c469e3e0
12 changed files with 516 additions and 297 deletions

View file

@ -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<IMMFrame> 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<IMemAlloc> pMA;
if (FAILED(pMA.CoCreateInstance(CLSID_MemAlloc))) {
_snprintf(ErrorMsg, MsgSize, "Can't create memory allocator");
throw ErrorMsg;
}
CComPtr<IMMStream> 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<IMMStreamOpen> 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<IEnumUnknown> pEU;
CComQIPtr<IPropertyBag> pBag;
if (SUCCEEDED(pMMC->EnumTracks(&pEU))) {
CComPtr<IUnknown> 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<uint8_t *>(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

View file

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

View file

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

View file

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

View file

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

View file

@ -225,28 +225,31 @@ tn:64:128:256
<p><b>FFmpeg svn</b> from http://ffmpeg.mplayerhq.hu/</p>
<p><b>pthreads</b> only required for ffmpeg-mt compiles</p>
<p><b>pthreads</b> only required for FFmpeg-mt compiles</p>
<p><b>Required FFmpeg Configuration:</b>
./configure --enable-memalign-hack --enable-gpl --enable-postproc
<p><b>Suggested Additional Options:</b>
--enable-pthreads --disable-encoders --disable-muxers --disable-network --disable-debug --enable-libfaad --disable-decoder=aac</p>
--enable-w32threads --disable-encoders --disable-muxers --disable-network --disable-debug --enable-libfaad --disable-decoder=aac</p>
<p>
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.
</p>
<h2>Changes</h2>
<ul>
<li>2.00 beta 9<ul>
<li>Implemented audio decoding using Haali's splitters, FFAudioSource now works on ts, ps and ogm</li>
<li>Can now be compiled with ICL 10.1 (probably other versions too)</li>
<li>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</li>
<li>Now has stricter index checking to detect when different FFmpeg versions were used to create an index of the same version</li>
<li>Fixed an access violation occurring when unindexed or empty audio tracks in matroska files were opened</li>
<li>Fixed memory leaks when audio sources were destroyed and when errors happened during indexing</li>
<li>Fixed access violations occurring when unindexed or empty audio tracks in matroska/lavf read files were opened</li>
<li>Less type conversion/signedness warnings</li>
<li>When audio track dumping is performed a custom callback can now be supplied to name the tracks</li>
<li>The audio track delay is now exposed in the API in the same way as video tracks</li>
<li>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</li>
<li>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</li>
<li>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</li>
<li>Updated FFmpeg to rev X (now with faad2 again by popular demand, updated to GCC 4.4.0 for compiling all libraries)</li>
</ul></li>

View file

@ -23,125 +23,97 @@ extern "C" {
#include <libavutil/md5.h>
}
#include <cassert>
#include <iostream>
#include <fstream>
#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<char *>(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<AVMD5 *>(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<uint8_t *>(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<unsigned>(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;
}
}

View file

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

View file

@ -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<IEnumUnknown> 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) {

View file

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

View file

@ -25,7 +25,6 @@
#include <memory>
#include <errno.h>
#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<FFIndex> 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<FFIndex> 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<FFIndex> 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();
}

View file

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