diff --git a/aegisub/FFmpegSource2/ffaudiosource.cpp b/aegisub/FFmpegSource2/ffaudiosource.cpp
index 9430dee31..1222924e1 100644
--- a/aegisub/FFmpegSource2/ffaudiosource.cpp
+++ b/aegisub/FFmpegSource2/ffaudiosource.cpp
@@ -112,8 +112,8 @@ int FFAudioSource::DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, char *Erro
int Ret = -1;
*Count = 0;
AVPacket Packet, TempPacket;
- av_init_packet(&Packet);
- av_init_packet(&TempPacket);
+ init_null_packet(&Packet);
+ init_null_packet(&TempPacket);
while (av_read_frame(FormatContext, &Packet) >= 0) {
if (Packet.stream_index == AudioTrack) {
@@ -344,7 +344,7 @@ int MatroskaAudioSource::DecodeNextAudioBlock(uint8_t *Buf, int64_t *Count, uint
int Ret = -1;
*Count = 0;
AVPacket TempPacket;
- av_init_packet(&TempPacket);
+ init_null_packet(&TempPacket);
// FIXME check return
ReadFrame(FilePos, FrameSize, CS, MC, ErrorMsg, MsgSize);
diff --git a/aegisub/FFmpegSource2/ffms2.avsi b/aegisub/FFmpegSource2/ffms2.avsi
new file mode 100644
index 000000000..045c094c6
--- /dev/null
+++ b/aegisub/FFmpegSource2/ffms2.avsi
@@ -0,0 +1,32 @@
+# FFmpegSource 1.21 syntax compatibility
+# Created by TheFluff
+
+function FFmpegSource2(string source, int "vtrack", int "atrack", bool "cache", \
+ string "cachefile", int "fpsnum", int "fpsden", string "pp", int "threads", \
+ string "timecodes", int "seekmode", bool "overwrite") {
+
+ vtrack = default(vtrack,-1)
+ atrack = default(atrack,-2)
+ cache = default(cache,true)
+ cachefile = default(cachefile,source+".ffindex")
+ fpsnum = default(fpsnum,-1)
+ fpsden = default(fpsden,1)
+ pp = default(pp,"")
+ threads = default(threads,-1)
+ timecodes = default(timecodes,"")
+ seekmode = default(seekmode,1)
+ overwrite = default(overwrite,false)
+
+ ((cache == true) && (atrack <= -2)) ? ffindex(source=source, cachefile=cachefile, \
+ indexmask=0, overwrite=overwrite) : (cache == true) ? ffindex(source=source, \
+ cachefile=cachefile, indexmask=-1, overwrite=overwrite) : nop
+
+ v = ffvideosource(source=source, track=vtrack, cache=cache, cachefile=cachefile, \
+ fpsnum=fpsnum, fpsden=fpsden, pp=pp, threads=threads, timecodes=timecodes, \
+ seekmode=seekmode)
+
+ a = (atrack <= -2) ? blankclip(audio_rate=0) : ffaudiosource(source=source, \
+ track=atrack, cache=cache, cachefile=cachefile)
+
+ return audiodubex(v,a)
+}
diff --git a/aegisub/FFmpegSource2/ffms2.html b/aegisub/FFmpegSource2/ffms2.html
index 4dfd0261b..8a1ceb373 100644
--- a/aegisub/FFmpegSource2/ffms2.html
+++ b/aegisub/FFmpegSource2/ffms2.html
@@ -234,6 +234,10 @@ Note that --enable-w32threads is required for multithreaded decoding to work.
Changes
- 2.00 beta 7
+- Fix a crash bug at the end of files with b-frames in beta 6 caused by uninitialized null packets
+- Includes TheFluff's wrapper function for 1.21 style syntax
+- Added a simple regression test application to the source
+- Removed a few pointless functions from the API
- Fixed the accessing of codecprivate data with Haali's splitters
- Timecode output should be fixed to include decimals AND not be in scientific format
- Fixed a memory leak when using Haali's splitters
diff --git a/aegisub/FFmpegSource2/ffms2rt.cpp b/aegisub/FFmpegSource2/ffms2rt.cpp
new file mode 100644
index 000000000..a7b993b45
--- /dev/null
+++ b/aegisub/FFmpegSource2/ffms2rt.cpp
@@ -0,0 +1,146 @@
+// Copyright (c) 2009 Fredrik Mellbin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+extern "C" {
+#include
+}
+
+#include
+#include
+#include "ffms.h"
+
+using namespace std;
+
+//#define VERBOSE
+
+static int FFMS_CC UpdateProgress(int State, int64_t Current, int64_t Total, void *Private) {
+
+ static int LastPercentage = -1;
+ int Percentage = int((double(Current)/double(Total)) * 100);
+
+ if (Percentage <= LastPercentage)
+ return 0;
+
+ LastPercentage = Percentage;
+
+#ifdef VERBOSE
+ cout << "Indexing " << static_cast(Private) << ", please wait... " << Percentage << "% \r" << flush;
+#endif
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ char ErrorMsg[2000];
+ AVMD5 *ctx = reinterpret_cast(new uint8_t[av_md5_size]);
+ uint8_t md5sum[16];
+
+ if (argc != 2)
+ return -1;
+
+ FFMS_Init();
+#ifndef VERBOSE
+ FFMS_NoLog();
+#endif
+
+ av_md5_init(ctx);
+ FrameIndex *FI = FFMS_MakeIndex(argv[1], -1, 0, NULL, false, UpdateProgress, argv[1], ErrorMsg, sizeof(ErrorMsg));
+ if (!FI) {
+ cout << "Indexing error: " << ErrorMsg << endl;
+ return 1;
+ }
+
+ int track = FFMS_GetFirstTrackOfType(FI, FFMS_TYPE_VIDEO, ErrorMsg, sizeof(ErrorMsg));
+ if (track < 0) {
+ cout << "No usable track error: " << ErrorMsg << endl;
+ return 2;
+ }
+
+ VideoBase *FV = FFMS_CreateVideoSource(argv[1], track, FI, "", 1, 1, ErrorMsg, sizeof(ErrorMsg));
+ FFMS_DestroyFrameIndex(FI);
+ if (!FV) {
+ cout << "Video source error: " << ErrorMsg << endl;
+ return 3;
+ }
+
+ const VideoProperties *VP = FFMS_GetVideoProperties(FV);
+ for (int i = 0; i < VP->NumFrames; i++) {
+ const AVFrameLite *AVF = FFMS_GetFrame(FV, i, ErrorMsg, sizeof(ErrorMsg));
+ if (!AVF) {
+ cout << "Frame request error: " << ErrorMsg << " at frame " << i << endl;
+ return 4;
+ }
+
+#ifdef VERBOSE
+ int LastPercentage = -1;
+ int Percentage = int((double(i)/double(VP->NumFrames)) * 100);
+
+ if (Percentage > LastPercentage) {
+ LastPercentage = Percentage;
+ cout << "Requesting frames " << argv[1] << ", please wait... " << Percentage << "% \r" << flush;
+ }
+#endif
+
+ uint8_t *Data[3];
+ Data[0] = AVF->Data[0];
+ Data[1] = AVF->Data[1];
+ Data[2] = AVF->Data[2];
+
+ switch (VP->VPixelFormat) {
+ case PIX_FMT_YUV420P:
+ case PIX_FMT_YUVJ420P:
+ for (int j = 0; j < VP->Height / 2; j++) {
+ av_md5_update(ctx, Data[0], VP->Width);
+ Data[0] += AVF->Linesize[0];
+ av_md5_update(ctx, Data[0], VP->Width);
+ Data[0] += AVF->Linesize[0];
+ av_md5_update(ctx, Data[1], VP->Width / 2);
+ Data[1] += AVF->Linesize[1];
+ av_md5_update(ctx, Data[2], VP->Width / 2);
+ Data[2] += AVF->Linesize[2];
+ }
+ break;
+ case PIX_FMT_YUV422P:
+ for (int j = 0; j < VP->Height / 2; j++) {
+ av_md5_update(ctx, Data[0], VP->Width);
+ Data[0] += AVF->Linesize[0];
+ av_md5_update(ctx, Data[0], VP->Width);
+ Data[0] += AVF->Linesize[0];
+ av_md5_update(ctx, Data[1], VP->Width / 2);
+ Data[1] += AVF->Linesize[1];
+ av_md5_update(ctx, Data[2], VP->Width / 2);
+ Data[2] += AVF->Linesize[2];
+ }
+ break;
+ }
+ }
+
+ FFMS_DestroyVideoSource(FV);
+ av_md5_final(ctx, md5sum);
+
+ delete[] reinterpret_cast(ctx);
+
+ cout << "Test successful, MD5: " << hex;
+ for (int i = 0; i < sizeof(md5sum); i++)
+ cout << static_cast(md5sum[i]);
+ cout << endl;
+// cin >> argc;
+ return 0;
+}
\ No newline at end of file
diff --git a/aegisub/FFmpegSource2/ffvideosource.cpp b/aegisub/FFmpegSource2/ffvideosource.cpp
index ec5aa8bab..a601d6b39 100644
--- a/aegisub/FFmpegSource2/ffvideosource.cpp
+++ b/aegisub/FFmpegSource2/ffvideosource.cpp
@@ -175,7 +175,7 @@ void FFVideoSource::Free(bool CloseCodec) {
if (CloseCodec)
avcodec_close(CodecContext);
av_close_input_file(FormatContext);
- // how was it allocated? how was it deallocate? nobody knows
+ //FIXME how was it allocated? how was it deallocate? nobody knows
//av_free(FormatContext);
}
@@ -282,7 +282,7 @@ FFVideoSource::~FFVideoSource() {
int FFVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AStartTime, char *ErrorMsg, unsigned MsgSize) {
AVPacket Packet;
- av_init_packet(&Packet);
+ init_null_packet(&Packet);
int FrameFinished = 0;
*AStartTime = -1;
@@ -303,7 +303,7 @@ int FFVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AStartTime, char *E
// Flush the last frames
if (CodecContext->has_b_frames) {
AVPacket NullPacket;
- av_init_packet(&NullPacket);
+ init_null_packet(&NullPacket);
avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &NullPacket);
}
@@ -516,7 +516,7 @@ int MatroskaVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTi
int FrameFinished = 0;
*AFirstStartTime = -1;
AVPacket Packet;
- av_init_packet(&Packet);
+ init_null_packet(&Packet);
ulonglong StartTime, EndTime, FilePos;
unsigned int Track, FrameFlags, FrameSize;
@@ -543,7 +543,7 @@ int MatroskaVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTi
// Flush the last frames
if (CodecContext->has_b_frames) {
AVPacket NullPacket;
- av_init_packet(&NullPacket);
+ init_null_packet(&NullPacket);
avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &NullPacket);
}
@@ -773,7 +773,7 @@ int HaaliVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime,
int FrameFinished = 0;
*AFirstStartTime = -1;
AVPacket Packet;
- av_init_packet(&Packet);
+ init_null_packet(&Packet);
for (;;) {
CComPtr pMMF;
@@ -806,7 +806,7 @@ int HaaliVideoSource::DecodeNextFrame(AVFrame *AFrame, int64_t *AFirstStartTime,
// Flush the last frames
if (CodecContext->has_b_frames) {
AVPacket NullPacket;
- av_init_packet(&NullPacket);
+ init_null_packet(&NullPacket);
avcodec_decode_video2(CodecContext, AFrame, &FrameFinished, &NullPacket);
}
diff --git a/aegisub/FFmpegSource2/indexing.cpp b/aegisub/FFmpegSource2/indexing.cpp
index 7eb135f6a..1444e401d 100644
--- a/aegisub/FFmpegSource2/indexing.cpp
+++ b/aegisub/FFmpegSource2/indexing.cpp
@@ -324,7 +324,7 @@ static FrameIndex *MakeHaaliIndex(const char *SourceFile, int IndexMask, int Dum
//
AVPacket TempPacket;
- av_init_packet(&TempPacket);
+ init_null_packet(&TempPacket);
for (;;) {
if (IP) {
@@ -481,7 +481,7 @@ static FrameIndex *MakeMatroskaIndex(const char *SourceFile, int IndexMask, int
ulonglong StartTime, EndTime, FilePos;
unsigned int Track, FrameFlags, FrameSize;
AVPacket TempPacket;
- av_init_packet(&TempPacket);
+ init_null_packet(&TempPacket);
while (mkv_ReadFrame(MF, 0, &Track, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) {
// Update progress
@@ -621,8 +621,8 @@ FrameIndex *MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, const
FormatContext->streams[i]->codec->codec_type));
AVPacket Packet, TempPacket;
- av_init_packet(&Packet);
- av_init_packet(&TempPacket);
+ init_null_packet(&Packet);
+ init_null_packet(&TempPacket);
while (av_read_frame(FormatContext, &Packet) >= 0) {
// Update progress
if (IP) {
diff --git a/aegisub/FFmpegSource2/utils.cpp b/aegisub/FFmpegSource2/utils.cpp
index a8896bd97..3d296df21 100644
--- a/aegisub/FFmpegSource2/utils.cpp
+++ b/aegisub/FFmpegSource2/utils.cpp
@@ -131,6 +131,12 @@ bool AudioFMTIsFloat(SampleFormat FMT){
}
}
+void init_null_packet(AVPacket *pkt) {
+ av_init_packet(pkt);
+ pkt->data = NULL;
+ pkt->size = 0;
+}
+
// used for matroska<->ffmpeg codec ID mapping to avoid Win32 dependency
typedef struct BITMAPINFOHEADER {
uint32_t biSize;
diff --git a/aegisub/FFmpegSource2/utils.h b/aegisub/FFmpegSource2/utils.h
index cb3bbb8dc..770cd0f60 100644
--- a/aegisub/FFmpegSource2/utils.h
+++ b/aegisub/FFmpegSource2/utils.h
@@ -51,6 +51,7 @@ public:
int GetCPUFlags();
int ReadFrame(uint64_t FilePos, unsigned int &FrameSize, CompressedStream *CS, MatroskaReaderContext &Context, char *ErrorMsg, unsigned MsgSize);
bool AudioFMTIsFloat(SampleFormat FMT);
+void init_null_packet(AVPacket *pkt);
CodecID MatroskaToFFCodecID(char *Codec, void *CodecPrivate);
#endif