FFMS2:
Several bugfixes which should fix crashes in recent versions Added a simple regression test application Removed a few useless functions from the API Add TheFluff's FFmpegSource 1.21 syntax compatibility script Originally committed to SVN as r2843.
This commit is contained in:
parent
45d6e37ee8
commit
83586d2b18
8 changed files with 203 additions and 14 deletions
|
@ -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);
|
||||
|
|
32
aegisub/FFmpegSource2/ffms2.avsi
Normal file
32
aegisub/FFmpegSource2/ffms2.avsi
Normal file
|
@ -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)
|
||||
}
|
|
@ -234,6 +234,10 @@ Note that --enable-w32threads is required for multithreaded decoding to work.
|
|||
<h2>Changes</h2>
|
||||
<ul>
|
||||
<li>2.00 beta 7<ul>
|
||||
<li>Fix a crash bug at the end of files with b-frames in beta 6 caused by uninitialized null packets</li>
|
||||
<li>Includes TheFluff's wrapper function for 1.21 style syntax</li>
|
||||
<li>Added a simple regression test application to the source</li>
|
||||
<li>Removed a few pointless functions from the API</li>
|
||||
<li>Fixed the accessing of codecprivate data with Haali's splitters</li>
|
||||
<li>Timecode output should be fixed to include decimals AND not be in scientific format</li>
|
||||
<li>Fixed a memory leak when using Haali's splitters</li>
|
||||
|
|
146
aegisub/FFmpegSource2/ffms2rt.cpp
Normal file
146
aegisub/FFmpegSource2/ffms2rt.cpp
Normal file
|
@ -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 <libavutil/md5.h>
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#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<char *>(Private) << ", please wait... " << Percentage << "% \r" << flush;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char ErrorMsg[2000];
|
||||
AVMD5 *ctx = reinterpret_cast<AVMD5 *>(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<uint8_t *>(ctx);
|
||||
|
||||
cout << "Test successful, MD5: " << hex;
|
||||
for (int i = 0; i < sizeof(md5sum); i++)
|
||||
cout << static_cast<unsigned>(md5sum[i]);
|
||||
cout << endl;
|
||||
// cin >> argc;
|
||||
return 0;
|
||||
}
|
|
@ -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<IMMFrame> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue