From cae545b1eb4d66b9d6498e3d36b2b4b0f0b1c833 Mon Sep 17 00:00:00 2001 From: Fredrik Mellbin Date: Sat, 11 Apr 2009 18:45:40 +0000 Subject: [PATCH] FFMS2 beta 6 (the real commit) Requires a recent FFmpeg Changes the HAALITS define into HAALISOURCE Originally committed to SVN as r2780. --- aegisub/FFmpegSource2/ffaudiosource.cpp | 30 +++--- aegisub/FFmpegSource2/ffaudiosource.h | 28 ++++++ aegisub/FFmpegSource2/ffavisynth.cpp | 3 +- aegisub/FFmpegSource2/ffms.cpp | 5 +- aegisub/FFmpegSource2/ffms.h | 10 +- aegisub/FFmpegSource2/ffms2.html | 16 +++- aegisub/FFmpegSource2/ffvideosource.cpp | 122 ++++++++++++++++-------- aegisub/FFmpegSource2/ffvideosource.h | 12 +-- aegisub/FFmpegSource2/guids.h | 7 +- aegisub/FFmpegSource2/indexing.cpp | 101 +++++++++++--------- aegisub/FFmpegSource2/indexing.h | 2 +- 11 files changed, 223 insertions(+), 113 deletions(-) diff --git a/aegisub/FFmpegSource2/ffaudiosource.cpp b/aegisub/FFmpegSource2/ffaudiosource.cpp index 96d3b022c..9430dee31 100644 --- a/aegisub/FFmpegSource2/ffaudiosource.cpp +++ b/aegisub/FFmpegSource2/ffaudiosource.cpp @@ -111,16 +111,18 @@ int FFAudioSource::DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, char *Erro const size_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8; int Ret = -1; *Count = 0; - AVPacket Packet; + AVPacket Packet, TempPacket; + av_init_packet(&Packet); + av_init_packet(&TempPacket); while (av_read_frame(FormatContext, &Packet) >= 0) { if (Packet.stream_index == AudioTrack) { - uint8_t *Data = Packet.data; - int Size = Packet.size; + TempPacket.data = Packet.data; + TempPacket.size = Packet.size; - while (Size > 0) { + while (TempPacket.size > 0) { int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE * 10; - Ret = avcodec_decode_audio2(CodecContext, (int16_t *)Buf, &TempOutputBufSize, Data, Size); + Ret = avcodec_decode_audio3(CodecContext, (int16_t *)Buf, &TempOutputBufSize, &TempPacket); if (Ret < 0) {// throw error or something? av_free_packet(&Packet); @@ -128,8 +130,8 @@ int FFAudioSource::DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, char *Erro } if (Ret > 0) { - Size -= Ret; - Data += Ret; + TempPacket.size -= Ret; + TempPacket.data += Ret; Buf += TempOutputBufSize; if (SizeConst) *Count += TempOutputBufSize / SizeConst; @@ -341,22 +343,24 @@ int MatroskaAudioSource::DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, uint const size_t SizeConst = (av_get_bits_per_sample_format(CodecContext->sample_fmt) * CodecContext->channels) / 8; int Ret = -1; *Count = 0; + AVPacket TempPacket; + av_init_packet(&TempPacket); // FIXME check return ReadFrame(FilePos, FrameSize, CS, MC, ErrorMsg, MsgSize); - int Size = FrameSize; - uint8_t *Data = MC.Buffer; + TempPacket.size = FrameSize; + TempPacket.data = MC.Buffer; - while (Size > 0) { + while (TempPacket.size > 0) { int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; - Ret = avcodec_decode_audio2(CodecContext, (int16_t *)Buf, &TempOutputBufSize, Data, Size); + Ret = avcodec_decode_audio3(CodecContext, (int16_t *)Buf, &TempOutputBufSize, &TempPacket); if (Ret < 0) // throw error or something? goto Done; if (Ret > 0) { - Size -= Ret; - Data += Ret; + TempPacket.size -= Ret; + TempPacket.data += Ret; Buf += TempOutputBufSize; if (SizeConst) *Count += TempOutputBufSize / SizeConst; diff --git a/aegisub/FFmpegSource2/ffaudiosource.h b/aegisub/FFmpegSource2/ffaudiosource.h index b66a44a17..739503a00 100644 --- a/aegisub/FFmpegSource2/ffaudiosource.h +++ b/aegisub/FFmpegSource2/ffaudiosource.h @@ -31,6 +31,17 @@ extern "C" { #include "utils.h" #include "ffms.h" +#ifdef HAALISOURCE +# define _WIN32_DCOM +# include +# include +# include +# include +# include "CoParser.h" +# include +# include "guids.h" +#endif + class AudioBase { protected: uint8_t *DecodingBuffer; @@ -77,4 +88,21 @@ public: int GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize); }; +#ifdef HAALISOURCE + +class HaaliAudioSource : public AudioBase { +private: + CComPtr pMMC; + + int DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, char *ErrorMsg, unsigned MsgSize); + void Free(bool CloseCodec); +public: + HaaliAudioSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize); + ~HaaliAudioSource(); + + int GetAudio(void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize); +}; + +#endif // HAALISOURCE + #endif diff --git a/aegisub/FFmpegSource2/ffavisynth.cpp b/aegisub/FFmpegSource2/ffavisynth.cpp index 1579ec526..2d4a40379 100644 --- a/aegisub/FFmpegSource2/ffavisynth.cpp +++ b/aegisub/FFmpegSource2/ffavisynth.cpp @@ -58,7 +58,8 @@ AvisynthVideoSource::AvisynthVideoSource(const char *SourceFile, int Track, Fram // Set AR variables Env->SetVar("FFSAR_NUM", VP.SARNum); Env->SetVar("FFSAR_DEN", VP.SARDen); - Env->SetVar("FFSAR", VP.SARNum / (double)VP.SARDen); + if (VP.SARNum > 0 && VP.SARDen > 0) + Env->SetVar("FFSAR", VP.SARNum / (double)VP.SARDen); // Set crop variables Env->SetVar("FFCROP_LEFT", VP.CropLeft); diff --git a/aegisub/FFmpegSource2/ffms.cpp b/aegisub/FFmpegSource2/ffms.cpp index 2f787bd7d..64cdce9c9 100644 --- a/aegisub/FFmpegSource2/ffms.cpp +++ b/aegisub/FFmpegSource2/ffms.cpp @@ -67,8 +67,9 @@ FFMS_API(VideoBase *) FFMS_CreateVideoSource(const char *SourceFile, int Track, switch (TrackIndices->Decoder) { case 0: return new FFVideoSource(SourceFile, Track, TrackIndices, PP, Threads, SeekMode, ErrorMsg, MsgSize); case 1: return new MatroskaVideoSource(SourceFile, Track, TrackIndices, PP, Threads, ErrorMsg, MsgSize); -#ifdef HAALITS - case 2: return new HaaliTSVideoSource(SourceFile, Track, TrackIndices, PP, Threads, ErrorMsg, MsgSize); +#ifdef HAALISOURCE + case 2: return new HaaliVideoSource(SourceFile, Track, TrackIndices, PP, Threads, 0, ErrorMsg, MsgSize); + case 3: return new HaaliVideoSource(SourceFile, Track, TrackIndices, PP, Threads, 1, ErrorMsg, MsgSize); #endif default: _snprintf(ErrorMsg, MsgSize, "Unsupported format"); diff --git a/aegisub/FFmpegSource2/ffms.h b/aegisub/FFmpegSource2/ffms.h index e78cf166a..a400f9a6d 100644 --- a/aegisub/FFmpegSource2/ffms.h +++ b/aegisub/FFmpegSource2/ffms.h @@ -49,7 +49,15 @@ class FrameInfoVector; typedef int (FFMS_CC *IndexCallback)(int State, int64_t Current, int64_t Total, void *Private); -enum TrackType { +enum FFMS_SeekMode { + FFMS_SEEK_LINEAR_NO_RW = -1, + FFMS_SEEK_LINEAR = 0, + FFMS_SEEK_NORMAL = 1, + FFMS_SEEK_UNSAFE = 2, + FFMS_SEEK_AGGRESSIVE = 3, +}; + +enum FFMS_TrackType { FFMS_TYPE_VIDEO = 0, FFMS_TYPE_AUDIO = 1, }; diff --git a/aegisub/FFmpegSource2/ffms2.html b/aegisub/FFmpegSource2/ffms2.html index d6bdebd1a..5751d3d06 100644 --- a/aegisub/FFmpegSource2/ffms2.html +++ b/aegisub/FFmpegSource2/ffms2.html @@ -10,14 +10,21 @@ FFmpegSource2 Documentation Opens files using ffmpeg and nothing else. May be frame accurate on good days. The source is MIT licensed and can be obtained from "http://svn.aegisub.net/trunk/aegisub/FFmpegSource2/". The precompiled binary is GPL licensed. If you are religious you may consider this the second coming.

+

Known issues

+
    +
  • Requires Haali's Media Splitter if ogm or mpeg ps/ts is to be opened.
  • +
  • Avi files with NVOPs (rarely occurs in xvid and such) will desync when these frames are encountered. Remux to mkv/mp4 before opening to solve it for now.
  • +
  • The audio sources still aren't sample accurate and sometimes exhibit many interesting issues. Dumping the audio during indexing is the only workaround. +
+

Compatibility - Video

  • AVI, MKV, MP4, FLV: Frame accurate
  • WMV: Frame accurate(?) but avformat seems to pick keyframes relatively far away
  • -
  • OGM: Messed up first frame and seeking produces smearing with seekmode=3, incredibly slow seeking without, remux to mkv or avi
  • +
  • OGM: Frame accurate(?)
  • VOB: No rff flags applied, frame accurate?
  • MPG: Seeking seems to be off by one or two frames now and then
  • -
  • M2TS, TS: Linear access only (seekmode=-1)
  • +
  • M2TS, TS: Seeking seems to be off a few frames here and there
  • Image files: Most formats can be opened if seekmode=-1 is set
@@ -227,8 +234,11 @@ Note that --enable-w32threads is required for multithreaded decoding to work.

Changes

  • 2.00 beta 6
      +
    • Haali's splitters have been improved for video and now have audio dumping during indexing implemented
    • +
    • SeekMode=1 has improved logic which will make it go back and decode more frames if necessary to figure out where it is, in theory SeekMode=0 should now be mostly obsolete
    • +
    • Haali's splitters are now used to open mpeg ps and ogm in addition to mpeg ts, only ogm is frame accurate at this time
    • Negative timecodes and other bugs caused by an integer overflow fixed
    • -
    • Updated FFmpeg to rev X (once again compilation fixes for the changes)
    • +
    • Updated FFmpeg to rev 18442 (once again compilation fixes for the changes)
  • 2.00 beta 5
      diff --git a/aegisub/FFmpegSource2/ffvideosource.cpp b/aegisub/FFmpegSource2/ffvideosource.cpp index c280c6926..68d61ba0e 100644 --- a/aegisub/FFmpegSource2/ffvideosource.cpp +++ b/aegisub/FFmpegSource2/ffvideosource.cpp @@ -282,6 +282,7 @@ FFVideoSource::~FFVideoSource() { int FFVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AStartTime, char *ErrorMsg, unsigned MsgSize) { AVPacket Packet; + av_init_packet(&Packet); int FrameFinished = 0; *AStartTime = -1; @@ -290,7 +291,7 @@ int FFVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AStartTime, char *E if (*AStartTime < 0) *AStartTime = Packet.dts; - avcodec_decode_video(CodecContext, AFrame, &FrameFinished, Packet.data, Packet.size); + avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &Packet); } av_free_packet(&Packet); @@ -300,8 +301,11 @@ int FFVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AStartTime, char *E } // Flush the last frames - if (CodecContext->has_b_frames) - avcodec_decode_video(CodecContext, AFrame, &FrameFinished, NULL, 0); + if (CodecContext->has_b_frames) { + AVPacket NullPacket; + av_init_packet(&NullPacket); + avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &NullPacket); + } if (!FrameFinished) goto Error; @@ -318,6 +322,7 @@ AVFrameLite *FFVideoSource::GetFrame(int n, char *ErrorMsg, unsigned MsgSize) { return OutputFrame(DecodeFrame); bool HasSeeked = false; + int SeekOffset = 0; if (SeekMode >= 0) { int ClosestKF = Frames.FindClosestKeyFrame(n); @@ -331,7 +336,8 @@ AVFrameLite *FFVideoSource::GetFrame(int n, char *ErrorMsg, unsigned MsgSize) { } else { // 10 frames is used as a margin to prevent excessive seeking since the predicted best keyframe isn't always selected by avformat if (n < CurrentFrame || ClosestKF > CurrentFrame + 10 || (SeekMode == 3 && n > CurrentFrame + 10)) { - av_seek_frame(FormatContext, VideoTrack, (SeekMode == 3) ? Frames[n].DTS : Frames[ClosestKF].DTS, AVSEEK_FLAG_BACKWARD); +ReSeek: + av_seek_frame(FormatContext, VideoTrack, (SeekMode == 3) ? Frames[n].DTS : Frames[ClosestKF + SeekOffset].DTS, AVSEEK_FLAG_BACKWARD); avcodec_flush_buffers(CodecContext); HasSeeked = true; } @@ -353,8 +359,14 @@ AVFrameLite *FFVideoSource::GetFrame(int n, char *ErrorMsg, unsigned MsgSize) { if (StartTime < 0 || (CurrentFrame = Frames.FrameFromDTS(StartTime)) < 0) { switch (SeekMode) { case 1: - _snprintf(ErrorMsg, MsgSize, "Frame accurate seeking is not possible in this file"); - return NULL; + // No idea where we are so go back a bit further + if (n + SeekOffset == 0) { + _snprintf(ErrorMsg, MsgSize, "Frame accurate seeking is not possible in this file\n"); + return NULL; + } + + SeekOffset -= FFMIN(20, n + SeekOffset); + goto ReSeek; case 2: case 3: CurrentFrame = Frames.ClosestFrameFromDTS(StartTime); @@ -502,6 +514,8 @@ MatroskaVideoSource::~MatroskaVideoSource() { int MatroskaVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize) { int FrameFinished = 0; *AFirstStartTime = -1; + AVPacket Packet; + av_init_packet(&Packet); ulonglong StartTime, EndTime, FilePos; unsigned int Track, FrameFlags, FrameSize; @@ -513,15 +527,24 @@ int MatroskaVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTi if (ReadFrame(FilePos, FrameSize, CS, MC, ErrorMsg, MsgSize)) return 1; - avcodec_decode_video(CodecContext, AFrame, &FrameFinished, MC.Buffer, FrameSize); + Packet.data = MC.Buffer; + Packet.size = FrameSize; + if (FrameFlags & FRAME_KF) + Packet.flags = PKT_FLAG_KEY; + else + Packet.flags = 0; + avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &Packet); if (FrameFinished) goto Done; } // Flush the last frames - if (CodecContext->has_b_frames) - avcodec_decode_video(CodecContext, AFrame, &FrameFinished, NULL, 0); + if (CodecContext->has_b_frames) { + AVPacket NullPacket; + av_init_packet(&NullPacket); + avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &NullPacket); + } if (!FrameFinished) goto Error; @@ -565,17 +588,17 @@ AVFrameLite *MatroskaVideoSource::GetFrame(int n, char *ErrorMsg, unsigned MsgSi return OutputFrame(DecodeFrame); } -#ifdef HAALITS +#ifdef HAALISOURCE -void HaaliTSVideoSource::Free(bool CloseCodec) { +void HaaliVideoSource::Free(bool CloseCodec) { if (CloseCodec) avcodec_close(CodecContext); av_free(CodecContext); } -HaaliTSVideoSource::HaaliTSVideoSource(const char *SourceFile, int Track, +HaaliVideoSource::HaaliVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, const char *PP, - int Threads, char *ErrorMsg, unsigned MsgSize) { + int Threads, int SourceMode, char *ErrorMsg, unsigned MsgSize) { AVCodec *Codec = NULL; CodecContext = NULL; @@ -589,20 +612,22 @@ HaaliTSVideoSource::HaaliTSVideoSource(const char *SourceFile, int Track, ::CoInitializeEx(NULL, COINIT_MULTITHREADED); - CLSID clsid = Haali_TS_Parser; + 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; + CComPtr pMA; if (FAILED(pMA.CoCreateInstance(CLSID_MemAlloc))) { _snprintf(ErrorMsg, MsgSize, "Can't create memory allocator"); throw ErrorMsg; } - CComPtr pMS; + CComPtr pMS; if (FAILED(pMS.CoCreateInstance(CLSID_DiskFile))) { _snprintf(ErrorMsg, MsgSize, "Can't create disk file reader"); throw ErrorMsg; @@ -626,11 +651,13 @@ HaaliTSVideoSource::HaaliTSVideoSource(const char *SourceFile, int Track, 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) { - CComQIPtr pBag = pU; + pBag = pU; + if (pBag) { VARIANT pV; @@ -700,7 +727,7 @@ HaaliTSVideoSource::HaaliTSVideoSource(const char *SourceFile, int Track, if (Frames.size() >= 2) { double DTSDiff = (double)(Frames.back().DTS - Frames.front().DTS); // FIXME - VP.FPSDenominator = (unsigned int)((DTSDiff * 1000000000) / (double)1000 / (double)(VP.NumFrames - 1) + 0.5); + VP.FPSDenominator = (unsigned int)((DTSDiff * 1000000) / (double)(VP.NumFrames - 1) + 0.5); VP.FPSNumerator = 1000000; } @@ -709,23 +736,22 @@ HaaliTSVideoSource::HaaliTSVideoSource(const char *SourceFile, int Track, LastFrameNum = 0; // Set AR variables -// VP.SARNum = TI->AV.Video.DisplayWidth * TI->AV.Video.PixelHeight; -// VP.SARDen = TI->AV.Video.DisplayHeight * TI->AV.Video.PixelWidth; - - // Set crop variables -// VP.CropLeft = TI->AV.Video.CropL; -// VP.CropRight = TI->AV.Video.CropR; -// VP.CropTop = TI->AV.Video.CropT; -// VP.CropBottom = TI->AV.Video.CropB; + VARIANT pV; + if (pBag->Read(L"Video.DisplayWidth", &pV, NULL) == S_OK) + VP.SARNum = pV.uiVal; + if (pBag->Read(L"Video.DisplayHeight", &pV, NULL) == S_OK) + VP.SARDen = pV.uiVal; } -HaaliTSVideoSource::~HaaliTSVideoSource() { +HaaliVideoSource::~HaaliVideoSource() { Free(true); } -int HaaliTSVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize) { +int HaaliVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize) { int FrameFinished = 0; *AFirstStartTime = -1; + AVPacket Packet; + av_init_packet(&Packet); for (;;) { CComPtr pMMF; @@ -741,7 +767,14 @@ int HaaliTSVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTim if (FAILED(pMMF->GetPointer(&Data))) goto Error; - avcodec_decode_video(CodecContext, AFrame, &FrameFinished, Data, pMMF->GetActualDataLength()); + Packet.data = Data; + Packet.size = pMMF->GetActualDataLength(); + if (pMMF->IsSyncPoint() == S_OK) + Packet.flags = PKT_FLAG_KEY; + else + Packet.flags = 0; + + avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &Packet); if (FrameFinished) goto Done; @@ -749,8 +782,11 @@ int HaaliTSVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTim } // Flush the last frames - if (CodecContext->has_b_frames) - avcodec_decode_video(CodecContext, AFrame, &FrameFinished, NULL, 0); + if (CodecContext->has_b_frames) { + AVPacket NullPacket; + av_init_packet(&NullPacket); + avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &NullPacket); + } if (!FrameFinished) goto Error; @@ -760,18 +796,18 @@ Done: return 0; } -AVFrameLite *HaaliTSVideoSource::GetFrame(int n, char *ErrorMsg, unsigned MsgSize) { +AVFrameLite *HaaliVideoSource::GetFrame(int n, char *ErrorMsg, unsigned MsgSize) { // PPFrame always holds frame LastFrameNum even if no PP is applied if (LastFrameNum == n) return OutputFrame(DecodeFrame); bool HasSeeked = false; + int SeekOffset = 0; - if (n < CurrentFrame || Frames.FindClosestKeyFrame(n) > CurrentFrame) { - int64_t dtsp = Frames[n].DTS; - pMMC->Seek(Frames[n].DTS, MMSF_PREV_KF); - // FIXME for some reason required to make it seek properly - //avcodec_flush_buffers(CodecContext); + if (n < CurrentFrame || Frames.FindClosestKeyFrame(n) > CurrentFrame + 10) { +ReSeek: + pMMC->Seek(Frames[n + SeekOffset].DTS, MMSF_PREV_KF); + avcodec_flush_buffers(CodecContext); HasSeeked = true; } @@ -784,8 +820,14 @@ AVFrameLite *HaaliTSVideoSource::GetFrame(int n, char *ErrorMsg, unsigned MsgSiz HasSeeked = false; if (StartTime < 0 || (CurrentFrame = Frames.FrameFromDTS(StartTime)) < 0) { - _snprintf(ErrorMsg, MsgSize, "Frame accurate seeking is not possible in this file\n"); - return NULL; + // No idea where we are so go back a bit further + if (n + SeekOffset == 0) { + _snprintf(ErrorMsg, MsgSize, "Frame accurate seeking is not possible in this file\n"); + return NULL; + } + + SeekOffset -= FFMIN(20, n + SeekOffset); + goto ReSeek; } } @@ -796,4 +838,4 @@ AVFrameLite *HaaliTSVideoSource::GetFrame(int n, char *ErrorMsg, unsigned MsgSiz return OutputFrame(DecodeFrame); } -#endif // HAALITS +#endif // HAALISOURCE diff --git a/aegisub/FFmpegSource2/ffvideosource.h b/aegisub/FFmpegSource2/ffvideosource.h index cb58a29d6..64bfabcc5 100644 --- a/aegisub/FFmpegSource2/ffvideosource.h +++ b/aegisub/FFmpegSource2/ffvideosource.h @@ -33,7 +33,7 @@ extern "C" { #include "utils.h" #include "ffms.h" -#ifdef HAALITS +#ifdef HAALISOURCE # define _WIN32_DCOM # include # include @@ -101,20 +101,20 @@ public: AVFrameLite *GetFrame(int n, char *ErrorMsg, unsigned MsgSize); }; -#ifdef HAALITS +#ifdef HAALISOURCE -class HaaliTSVideoSource : public VideoBase { +class HaaliVideoSource : public VideoBase { private: CComPtr pMMC; void Free(bool CloseCodec); int DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime, char *ErrorMsg, unsigned MsgSize); public: - HaaliTSVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, const char *PP, int Threads, char *ErrorMsg, unsigned MsgSize); - ~HaaliTSVideoSource(); + HaaliVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, const char *PP, int Threads, int SourceMode, char *ErrorMsg, unsigned MsgSize); + ~HaaliVideoSource(); AVFrameLite *GetFrame(int n, char *ErrorMsg, unsigned MsgSize); }; -#endif // HAALITS +#endif // HAALISOURCE #endif diff --git a/aegisub/FFmpegSource2/guids.h b/aegisub/FFmpegSource2/guids.h index 82e199d58..d6d162e06 100644 --- a/aegisub/FFmpegSource2/guids.h +++ b/aegisub/FFmpegSource2/guids.h @@ -116,9 +116,14 @@ DEFINE_GUID(MEDIASUBTYPE_WMV3, 0x33564d57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); // FIXME: move somewhere else? -DEFINE_GUID(Haali_TS_Parser, +DEFINE_GUID(HAALI_TS_Parser, 0xB841F346, 0x4835, 0x4de8, 0xAA, 0x5E, 0x2E, 0x7C, 0xD2, 0xD4, 0xC4, 0x35); +DEFINE_GUID(HAALI_OGM_Parser, +0xDB43B405, 0x43AA, 0x4F01, 0x82, 0xD8, 0xD8, 0x4D, 0x47, 0xE6, 0x01, 0x9C); + +//DB43B405-43AA-4F01-82D8-D84D47E6019C + typedef struct tagVORBISFORMAT2 { DWORD Channels; diff --git a/aegisub/FFmpegSource2/indexing.cpp b/aegisub/FFmpegSource2/indexing.cpp index 20033bf04..df4a1bdfe 100644 --- a/aegisub/FFmpegSource2/indexing.cpp +++ b/aegisub/FFmpegSource2/indexing.cpp @@ -95,20 +95,20 @@ public: } }; -#ifdef HAALITS -class HaaliTSIndexMemory { +#ifdef HAALISOURCE +class HaaliIndexMemory { private: int16_t *DecodingBuffer; MatroskaAudioContext *AudioContexts; public: - HaaliTSIndexMemory(int Tracks, int16_t *&DecodingBuffer, MatroskaAudioContext *&AudioContexts) { + HaaliIndexMemory(int Tracks, int16_t *&DecodingBuffer, MatroskaAudioContext *&AudioContexts) { DecodingBuffer = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*10]; AudioContexts = new MatroskaAudioContext[Tracks]; this->DecodingBuffer = DecodingBuffer; this->AudioContexts = AudioContexts; } - ~HaaliTSIndexMemory() { + ~HaaliIndexMemory() { delete [] DecodingBuffer; delete [] AudioContexts; } @@ -202,11 +202,13 @@ int WriteIndex(const char *IndexFile, FrameIndex *TrackIndices, char *ErrorMsg, return 0; } -#ifdef HAALITS -static FrameIndex *MakeHaaliTSIndex(const char *SourceFile, int IndexMask, int DumpMask, const char *AudioFile, bool IgnoreDecodeErrors, IndexCallback IP, void *Private, char *ErrorMsg, unsigned MsgSize) { +#ifdef HAALISOURCE +static FrameIndex *MakeHaaliIndex(const char *SourceFile, int IndexMask, int DumpMask, const char *AudioFile, bool IgnoreDecodeErrors, int SourceMode, IndexCallback IP, void *Private, char *ErrorMsg, unsigned MsgSize) { ::CoInitializeEx(NULL, COINIT_MULTITHREADED); - CLSID clsid = Haali_TS_Parser; + CLSID clsid = HAALI_TS_Parser; + if (SourceMode == 1) + clsid = HAALI_OGM_Parser; CComPtr pMMC; if (FAILED(pMMC.CoCreateInstance(clsid))) { @@ -253,10 +255,12 @@ static FrameIndex *MakeHaaliTSIndex(const char *SourceFile, int IndexMask, int D int16_t *db; MatroskaAudioContext *AudioContexts; - HaaliTSIndexMemory IM = HaaliTSIndexMemory(NumTracks, db, AudioContexts); + HaaliIndexMemory IM = HaaliIndexMemory(NumTracks, db, AudioContexts); FrameIndex *TrackIndices = new FrameIndex(); TrackIndices->Decoder = 2; + if (SourceMode == 1) + TrackIndices->Decoder = 3; int TrackTypes[32]; int CurrentTrack = 0; @@ -322,6 +326,9 @@ static FrameIndex *MakeHaaliTSIndex(const char *SourceFile, int IndexMask, int D } // + AVPacket TempPacket; + av_init_packet(&TempPacket); + for (;;) { if (IP) { if ((*IP)(0, 0, 1, Private)) { @@ -344,20 +351,18 @@ static FrameIndex *MakeHaaliTSIndex(const char *SourceFile, int IndexMask, int D if (TrackTypes[CurrentTrack] == TT_VIDEO) { (*TrackIndices)[CurrentTrack].push_back(FrameInfo(Ts, pMMF->IsSyncPoint() == S_OK)); } else if (TrackTypes[CurrentTrack] == TT_AUDIO && (IndexMask & (1 << CurrentTrack))) { -/* (*TrackIndices)[Track].push_back(FrameInfo(AudioContexts[Track].CurrentSample, FilePos, FrameSize, (FrameFlags & FRAME_KF) != 0)); - ReadFrame(FilePos, FrameSize, AudioContexts[Track].CS, MC, ErrorMsg, MsgSize); + (*TrackIndices)[CurrentTrack].push_back(FrameInfo(AudioContexts[CurrentTrack].CurrentSample, 0 /* FIXME? */, pMMF->GetActualDataLength(), pMMF->IsSyncPoint() == S_OK)); + AVCodecContext *AudioCodecContext = AudioContexts[CurrentTrack].CTX; + pMMF->GetPointer(&TempPacket.data); + TempPacket.size = pMMF->GetActualDataLength(); - int Size = FrameSize; - uint8_t *Data = MC.Buffer; - AVCodecContext *AudioCodecContext = AudioContexts[Track].CTX; - - while (Size > 0) { + while (TempPacket.size > 0) { int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10; - int Ret = avcodec_decode_audio2(AudioCodecContext, db, &dbsize, Data, Size); + int Ret = avcodec_decode_audio3(AudioCodecContext, db, &dbsize, &TempPacket); if (Ret < 0) { if (IgnoreDecodeErrors) { - (*TrackIndices)[Track].clear(); - IndexMask &= ~(1 << Track); + (*TrackIndices)[CurrentTrack].clear(); + IndexMask &= ~(1 << CurrentTrack); break; } else { _snprintf(ErrorMsg, MsgSize, "Audio decoding error"); @@ -367,30 +372,28 @@ static FrameIndex *MakeHaaliTSIndex(const char *SourceFile, int IndexMask, int D } if (Ret > 0) { - Size -= Ret; - Data += Ret; + TempPacket.size -= Ret; + TempPacket.data += Ret; } if (dbsize > 0) - AudioContexts[Track].CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_format(AudioCodecContext->sample_fmt) * AudioCodecContext->channels); + AudioContexts[CurrentTrack].CurrentSample += (dbsize * 8) / (av_get_bits_per_sample_format(AudioCodecContext->sample_fmt) * AudioCodecContext->channels); - if (dbsize > 0 && (DumpMask & (1 << Track))) { + 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[Track].W64W) { + if (!AudioContexts[CurrentTrack].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); + _snprintf(ABuf, sizeof(ABuf), ".%02d.delay.%d.w64", CurrentTrack, 0); WN += ABuf; - AudioContexts[Track].W64W = new Wave64Writer(WN.c_str(), av_get_bits_per_sample_format(AudioCodecContext->sample_fmt), + 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[Track].W64W->WriteData(db, dbsize); + AudioContexts[CurrentTrack].W64W->WriteData(db, dbsize); } } - */ } } @@ -480,6 +483,8 @@ static FrameIndex *MakeMatroskaIndex(const char *SourceFile, int IndexMask, int ulonglong StartTime, EndTime, FilePos; unsigned int Track, FrameFlags, FrameSize; + AVPacket TempPacket; + av_init_packet(&TempPacket); while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) { // Update progress @@ -497,14 +502,13 @@ static FrameIndex *MakeMatroskaIndex(const char *SourceFile, int IndexMask, int } else if (mkv_GetTrackInfo(MF, Track)->Type == TT_AUDIO && (IndexMask & (1 << Track))) { (*TrackIndices)[Track].push_back(FrameInfo(AudioContexts[Track].CurrentSample, FilePos, FrameSize, (FrameFlags & FRAME_KF) != 0)); ReadFrame(FilePos, FrameSize, AudioContexts[Track].CS, MC, ErrorMsg, MsgSize); - - int Size = FrameSize; - uint8_t *Data = MC.Buffer; AVCodecContext *AudioCodecContext = AudioContexts[Track].CTX; + TempPacket.data = MC.Buffer; + TempPacket.size = FrameSize; - while (Size > 0) { + while (TempPacket.size > 0) { int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10; - int Ret = avcodec_decode_audio2(AudioCodecContext, db, &dbsize, Data, Size); + int Ret = avcodec_decode_audio3(AudioCodecContext, db, &dbsize, &TempPacket); if (Ret < 0) { if (IgnoreDecodeErrors) { (*TrackIndices)[Track].clear(); @@ -518,8 +522,8 @@ static FrameIndex *MakeMatroskaIndex(const char *SourceFile, int IndexMask, int } if (Ret > 0) { - Size -= Ret; - Data += Ret; + TempPacket.size -= Ret; + TempPacket.data += Ret; } if (dbsize > 0) @@ -563,11 +567,16 @@ FrameIndex *MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, const return MakeMatroskaIndex(SourceFile, IndexMask, DumpMask, AudioFile, IgnoreDecodeErrors, IP, Private, ErrorMsg, MsgSize); } -#ifdef HAALITS +#ifdef HAALISOURCE // Do haali ts indexing instead? - if (!strcmp(FormatContext->iformat->name, "mpegts")) { + if (!strcmp(FormatContext->iformat->name, "mpeg") || !strcmp(FormatContext->iformat->name, "mpegts")) { av_close_input_file(FormatContext); - return MakeHaaliTSIndex(SourceFile, IndexMask, DumpMask, AudioFile, IgnoreDecodeErrors, IP, Private, ErrorMsg, MsgSize); + return MakeHaaliIndex(SourceFile, IndexMask, DumpMask, AudioFile, IgnoreDecodeErrors, 0, IP, Private, ErrorMsg, MsgSize); + } + + if (!strcmp(FormatContext->iformat->name, "ogg")) { + av_close_input_file(FormatContext); + return MakeHaaliIndex(SourceFile, IndexMask, DumpMask, AudioFile, IgnoreDecodeErrors, 1, IP, Private, ErrorMsg, MsgSize); } #endif @@ -614,7 +623,9 @@ FrameIndex *MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, const FormatContext->streams[i]->time_base.den, FormatContext->streams[i]->codec->codec_type)); - AVPacket Packet; + AVPacket Packet, TempPacket; + av_init_packet(&Packet); + av_init_packet(&TempPacket); while (av_read_frame(FormatContext, &Packet) >= 0) { // Update progress if (IP) { @@ -631,12 +642,12 @@ FrameIndex *MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, const } else if (FormatContext->streams[Packet.stream_index]->codec->codec_type == CODEC_TYPE_AUDIO && (IndexMask & (1 << Packet.stream_index))) { (*TrackIndices)[Packet.stream_index].push_back(FrameInfo(Packet.dts, AudioContexts[Packet.stream_index].CurrentSample, (Packet.flags & PKT_FLAG_KEY) ? 1 : 0)); AVCodecContext *AudioCodecContext = FormatContext->streams[Packet.stream_index]->codec; - int Size = Packet.size; - uint8_t *Data = Packet.data; + TempPacket.data = Packet.data; + TempPacket.size = Packet.size; - while (Size > 0) { + while (TempPacket.size > 0) { int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10; - int Ret = avcodec_decode_audio2(AudioCodecContext, db, &dbsize, Data, Size); + int Ret = avcodec_decode_audio3(AudioCodecContext, db, &dbsize, &TempPacket); if (Ret < 0) { if (IgnoreDecodeErrors) { (*TrackIndices)[Packet.stream_index].clear(); @@ -650,8 +661,8 @@ FrameIndex *MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, const } if (Ret > 0) { - Size -= Ret; - Data += Ret; + TempPacket.size -= Ret; + TempPacket.data += Ret; } if (dbsize > 0) diff --git a/aegisub/FFmpegSource2/indexing.h b/aegisub/FFmpegSource2/indexing.h index 2ab33c114..9f677a8a9 100644 --- a/aegisub/FFmpegSource2/indexing.h +++ b/aegisub/FFmpegSource2/indexing.h @@ -25,7 +25,7 @@ #include "utils.h" #include "ffms.h" -#define INDEXVERSION 15 +#define INDEXVERSION 17 #define INDEXID 0x53920873 struct IndexHeader {