From 6878e5884a12925f57f33a2492035fd66b999ebe 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 {