FFMS2 beta 6 (the real commit)
Requires a recent FFmpeg Changes the HAALITS define into HAALISOURCE Originally committed to SVN as r2780.
This commit is contained in:
parent
5f5960ef00
commit
6878e5884a
11 changed files with 223 additions and 113 deletions
|
@ -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;
|
||||
|
|
|
@ -31,6 +31,17 @@ extern "C" {
|
|||
#include "utils.h"
|
||||
#include "ffms.h"
|
||||
|
||||
#ifdef HAALISOURCE
|
||||
# define _WIN32_DCOM
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# include <atlbase.h>
|
||||
# include <dshow.h>
|
||||
# include "CoParser.h"
|
||||
# include <initguid.h>
|
||||
# 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<IMMContainer> 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
</p>
|
||||
|
||||
<h2>Known issues</h2>
|
||||
<ul>
|
||||
<li>Requires <a href='http://haali.cs.msu.ru/mkv/'>Haali's Media Splitter</a> if ogm or mpeg ps/ts is to be opened.</li>
|
||||
<li>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.</li>
|
||||
<li>The audio sources still aren't sample accurate and sometimes exhibit many interesting issues. Dumping the audio during indexing is the only workaround.
|
||||
</ul>
|
||||
|
||||
<h2>Compatibility - Video</h2>
|
||||
<ul>
|
||||
<li>AVI, MKV, MP4, FLV: Frame accurate</li>
|
||||
<li>WMV: Frame accurate(?) but avformat seems to pick keyframes relatively far away</li>
|
||||
<li>OGM: Messed up first frame and seeking produces smearing with seekmode=3, incredibly slow seeking without, remux to mkv or avi</li>
|
||||
<li>OGM: Frame accurate(?)</li>
|
||||
<li>VOB: No rff flags applied, frame accurate?</li>
|
||||
<li>MPG: Seeking seems to be off by one or two frames now and then</li>
|
||||
<li>M2TS, TS: Linear access only (seekmode=-1)</li>
|
||||
<li>M2TS, TS: Seeking seems to be off a few frames here and there</li>
|
||||
<li>Image files: Most formats can be opened if seekmode=-1 is set</li>
|
||||
</ul>
|
||||
|
||||
|
@ -227,8 +234,11 @@ Note that --enable-w32threads is required for multithreaded decoding to work.
|
|||
<h2>Changes</h2>
|
||||
<ul>
|
||||
<li>2.00 beta 6<ul>
|
||||
<li>Haali's splitters have been improved for video and now have audio dumping during indexing implemented</li>
|
||||
<li>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</li>
|
||||
<li>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</li>
|
||||
<li>Negative timecodes and other bugs caused by an integer overflow fixed</li>
|
||||
<li>Updated FFmpeg to rev X (once again compilation fixes for the changes)</li>
|
||||
<li>Updated FFmpeg to rev 18442 (once again compilation fixes for the changes)</li>
|
||||
</ul></li>
|
||||
|
||||
<li>2.00 beta 5<ul>
|
||||
|
|
|
@ -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<IMemAlloc> pMA;
|
||||
CComPtr<IMemAlloc> pMA;
|
||||
if (FAILED(pMA.CoCreateInstance(CLSID_MemAlloc))) {
|
||||
_snprintf(ErrorMsg, MsgSize, "Can't create memory allocator");
|
||||
throw ErrorMsg;
|
||||
}
|
||||
|
||||
CComPtr<IMMStream> pMS;
|
||||
CComPtr<IMMStream> 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<IEnumUnknown> pEU;
|
||||
CComQIPtr<IPropertyBag> pBag;
|
||||
if (SUCCEEDED(pMMC->EnumTracks(&pEU))) {
|
||||
CComPtr<IUnknown> pU;
|
||||
while (pEU->Next(1, &pU, NULL) == S_OK) {
|
||||
if (CurrentTrack++ == Track) {
|
||||
CComQIPtr<IPropertyBag> 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<IMMFrame> 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
|
||||
|
|
|
@ -33,7 +33,7 @@ extern "C" {
|
|||
#include "utils.h"
|
||||
#include "ffms.h"
|
||||
|
||||
#ifdef HAALITS
|
||||
#ifdef HAALISOURCE
|
||||
# define _WIN32_DCOM
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
|
@ -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<IMMContainer> 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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<IMMContainer> 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)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "utils.h"
|
||||
#include "ffms.h"
|
||||
|
||||
#define INDEXVERSION 15
|
||||
#define INDEXVERSION 17
|
||||
#define INDEXID 0x53920873
|
||||
|
||||
struct IndexHeader {
|
||||
|
|
Loading…
Reference in a new issue