Remove the deprecated ffmpeg audio/video providers. They have not yet been removed from any of the build systems; verm will remove them from the Unix one and I will remove them from the MSVC project file shortly.

Originally committed to SVN as r3148.
This commit is contained in:
Karl Blomster 2009-07-16 19:08:40 +00:00
parent e589bceaa6
commit dfea9f9713
12 changed files with 6 additions and 1352 deletions

View file

@ -47,9 +47,6 @@
#ifdef WITH_AVISYNTH #ifdef WITH_AVISYNTH
#include "audio_provider_avs.h" #include "audio_provider_avs.h"
#endif #endif
#ifdef WITH_FFMPEG
#include "audio_provider_lavc.h"
#endif
#ifdef WITH_FFMPEGSOURCE #ifdef WITH_FFMPEGSOURCE
#include "audio_provider_ffmpegsource.h" #include "audio_provider_ffmpegsource.h"
#endif #endif
@ -283,9 +280,6 @@ void AudioProviderFactoryManager::RegisterProviders() {
#ifdef WITH_AVISYNTH #ifdef WITH_AVISYNTH
RegisterFactory(new AvisynthAudioProviderFactory(),_T("Avisynth")); RegisterFactory(new AvisynthAudioProviderFactory(),_T("Avisynth"));
#endif #endif
#ifdef WITH_FFMPEG
RegisterFactory(new LAVCAudioProviderFactory(),_T("FFMPEG"));
#endif
#ifdef WITH_FFMPEGSOURCE #ifdef WITH_FFMPEGSOURCE
RegisterFactory(new FFmpegSourceAudioProviderFactory(),_T("FFmpegSource")); RegisterFactory(new FFmpegSourceAudioProviderFactory(),_T("FFmpegSource"));
#endif #endif

View file

@ -1,297 +0,0 @@
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include "config.h"
#ifdef WITH_FFMPEG
#ifdef WIN32
#define EMULATE_INTTYPES
#endif
#include <wx/wxprec.h>
/* avcodec.h uses INT64_C in a *single* place. This prolly breaks on Win32,
* but, well. Let's at least fix it for Linux.
*/
/* Update: this used to be commented out but is now needed on Windows.
* Not sure about Linux, so it's wrapped in an ifdef.
*/
#ifdef WIN32
#define __STDC_CONSTANT_MACROS 1
#include <stdint.h>
#endif /* WIN32 */
/* - done in posix/defines.h
*/
#include "audio_provider_lavc.h"
#include "mkv_wrap.h"
#include "lavc_file.h"
#include "lavc_file.h"
#include "utils.h"
#include "options.h"
///////////////
// Constructor
LAVCAudioProvider::LAVCAudioProvider(Aegisub::String _filename)
: lavcfile(NULL), codecContext(NULL), rsct(NULL), buffer(NULL)
{
try {
#if 0
/* since seeking currently is likely to be horribly broken with two
* providers accessing the same stream, this is disabled for now.
*/
LAVCVideoProvider *vpro_lavc = dynamic_cast<LAVCVideoProvider *>(vpro);
if (vpro_lavc) {
lavcfile = vpro->lavcfile->AddRef();
filename = vpro_lavc->GetFilename();
} else {
#endif
lavcfile = LAVCFile::Create(_filename);
filename = _filename.c_str();
#if 0
}
#endif
audStream = -1;
for (int i = 0; i < (int)lavcfile->fctx->nb_streams; i++) {
codecContext = lavcfile->fctx->streams[i]->codec;
if (codecContext->codec_type == CODEC_TYPE_AUDIO) {
stream = lavcfile->fctx->streams[i];
audStream = i;
break;
}
}
if (audStream == -1) {
codecContext = NULL;
throw _T("ffmpeg audio provider: Could not find an audio stream");
}
AVCodec *codec = avcodec_find_decoder(codecContext->codec_id);
if (!codec) {
codecContext = NULL;
throw _T("ffmpeg audio provider: Could not find a suitable audio decoder");
}
if (avcodec_open(codecContext, codec) < 0)
throw _T("ffmpeg audio provider: Failed to open audio decoder");
sample_rate = Options.AsInt(_T("Audio Sample Rate"));
if (!sample_rate) {
/* aegisub wants audio with sample rate higher than 32khz */
if (codecContext->sample_rate < 32000)
sample_rate = 48000;
else
sample_rate = codecContext->sample_rate;
}
/* we rely on the intermediate audio provider to do downmixing for us later if necessary */
channels = codecContext->channels;
/* TODO: test if anything but S16 actually works! */
switch (codecContext->sample_fmt) {
case SAMPLE_FMT_U8: bytes_per_sample = 1; break;
case SAMPLE_FMT_S16: bytes_per_sample = 2; break;
case SAMPLE_FMT_S32: bytes_per_sample = 4; break; /* downmixing provider doesn't support this, will definitely not work */
default:
throw _T("ffmpeg audio provider: Unknown or unsupported sample format");
}
/* initiate resampling if necessary */
if (sample_rate != codecContext->sample_rate) {
rsct = audio_resample_init(channels, channels, sample_rate, codecContext->sample_rate);
if (!rsct)
throw _T("ffmpeg audio provider: Failed to initialize resampling");
resample_ratio = (float)sample_rate / (float)codecContext->sample_rate;
}
/* libavcodec seems to give back invalid stream length values for Matroska files.
* As a workaround, we can use the overall file length.
*/
double length;
if(stream->duration == AV_NOPTS_VALUE)
length = (double)lavcfile->fctx->duration / AV_TIME_BASE;
else
length = (double)stream->duration * av_q2d(stream->time_base);
num_samples = (int64_t)(length * sample_rate); /* number of samples per channel */
buffer = (int16_t *)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
if (!buffer)
throw _T("ffmpeg audio provider: Failed to allocate audio decoding buffer, out of memory?");
leftover_samples = 0;
last_output_sample = -1;
} catch (...) {
Destroy();
throw;
}
}
LAVCAudioProvider::~LAVCAudioProvider()
{
Destroy();
}
void LAVCAudioProvider::Destroy()
{
if (buffer)
free(buffer);
if (rsct)
audio_resample_close(rsct);
if (codecContext)
avcodec_close(codecContext);
if (lavcfile)
lavcfile->Release();
}
void LAVCAudioProvider::GetAudio(void *buf, int64_t start, int64_t count)
{
int16_t *_buf = (int16_t *)buf;
/* this exception disabled for now */
/* if (last_output_sample != start-1)
throw _T("ffmpeg audio provider: nonlinear access attempted, try loading audio to RAM or HD cache"); */
last_output_sample += count;
int64_t samples_to_decode = (num_samples - start) * channels; /* samples left to the end of the stream */
if (count < samples_to_decode) /* haven't reached the end yet, so just decode the requested number of samples */
samples_to_decode = count * channels; /* times the number of channels */
if (samples_to_decode < 0) /* requested beyond the end of the stream */
samples_to_decode = 0;
/* if we got asked for more samples than there are left in the stream, add zeros to the decoding buffer until
we have enough to fill the request */
memset(_buf + samples_to_decode, 0, ((count * channels) - samples_to_decode) * bytes_per_sample);
/* do we have leftover samples from last time we were called? */
/* FIXME: this assumes that requests are always linear! attempts at random access give bogus results! */
if (leftover_samples > 0) {
int length = (samples_to_decode > leftover_samples) ? leftover_samples : samples_to_decode;
samples_to_decode -= length;
leftover_samples -= length;
/* put them in the output buffer */
samples_to_decode -= leftover_samples;
while (length > 0) {
*(_buf++) = *(overshoot_buffer++);
length--;
}
}
AVPacket packet;
while (samples_to_decode > 0 && av_read_frame(lavcfile->fctx, &packet) >= 0) {
/* we're not dealing with video packets in this here provider */
if (packet.stream_index == audStream) {
int size = packet.size;
uint8_t *data = packet.data;
while (size > 0) {
int temp_output_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; /* see constructor, it malloc()'s buffer to this */
int retval, decoded_bytes, decoded_samples;
retval = avcodec_decode_audio2(codecContext, buffer, &temp_output_buffer_size, data, size);
/* decoding failed, skip this packet and hope next one doesn't fail too */
if (retval < 0)
break;
/* throw _T("ffmpeg audio provider: failed to decode audio"); */
size -= retval;
data += retval;
/* decoding succeeded but this audio frame is empty, continue to next frame */
if (temp_output_buffer_size <= 0)
continue;
decoded_bytes = temp_output_buffer_size;
decoded_samples = decoded_bytes / bytes_per_sample; /* FIXME: stop assuming everything is 16-bit! */
/* do we need to resample? */
if (rsct) {
/* allocate some memory to save the resampled data in */
int16_t *temp_output_buffer = (int16_t *)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
if (!temp_output_buffer)
throw _T("ffmpeg audio provider: Failed to allocate audio resampling buffer, out of memory?");
/* do the actual resampling */
decoded_samples = audio_resample(rsct, temp_output_buffer, buffer, decoded_samples / codecContext->channels);
/* did we end up with more samples than we were asked for? */
if (decoded_samples > samples_to_decode) {
/* in that case, count them */
leftover_samples = decoded_samples - samples_to_decode;
/* and put them aside for later */
memcpy(buffer, &temp_output_buffer[samples_to_decode+1], leftover_samples * bytes_per_sample);
overshoot_buffer = buffer;
/* output the other samples that didn't overflow */
memcpy(_buf, temp_output_buffer, samples_to_decode * bytes_per_sample);
_buf += samples_to_decode;
} else {
memcpy(_buf, temp_output_buffer, decoded_samples * bytes_per_sample);
_buf += decoded_samples;
}
free(temp_output_buffer);
} else { /* no resampling needed */
/* overflow? (as above) */
if (decoded_samples > samples_to_decode) {
/* count sheep^H^H^H^H^Hsamples */
leftover_samples = decoded_samples - samples_to_decode;
/* and put them aside for later (mm, lamb chops) */
overshoot_buffer = &buffer[samples_to_decode+1];
/* output the other samples that didn't overflow */
memcpy(_buf, buffer, samples_to_decode * bytes_per_sample);
_buf += samples_to_decode;
} else {
/* just do a straight copy to buffer */
memcpy(_buf, buffer, decoded_bytes);
_buf += decoded_samples;
}
}
samples_to_decode -= decoded_samples;
}
}
av_free_packet(&packet);
}
}
#endif

View file

@ -1,102 +0,0 @@
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#ifdef WITH_FFMPEG
#ifdef WIN32
#define EMULATE_INTTYPES
#endif
#include <wx/wxprec.h>
/* avcodec.h uses INT64_C in a *single* place. This prolly breaks on Win32,
* but, well. Let's at least fix it for Linux.
*
#define __STDC_CONSTANT_MACROS 1
#include <stdint.h>
* - done in posix/defines.h
*/
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
#include "mkv_wrap.h"
#include "lavc_file.h"
#include "include/aegisub/audio_provider.h"
///////////////////////
// LAVC Audio Provider
class LAVCAudioProvider : public AudioProvider {
private:
LAVCFile *lavcfile;
AVCodecContext *codecContext;
ReSampleContext *rsct;
float resample_ratio;
AVStream *stream;
int audStream;
int16_t *buffer;
int16_t *overshoot_buffer;
int64_t last_output_sample;
int leftover_samples;
void Destroy();
public:
LAVCAudioProvider(Aegisub::String _filename);
virtual ~LAVCAudioProvider();
// Supposedly lavc always returns machine endian samples
bool AreSamplesNativeEndian() { return true; }
virtual void GetAudio(void *buf, int64_t start, int64_t count);
};
///////////
// Factory
class LAVCAudioProviderFactory : public AudioProviderFactory {
public:
AudioProvider *CreateProvider(Aegisub::String file) { return new LAVCAudioProvider(file); }
};
#endif

View file

@ -75,6 +75,12 @@
#define WITH_AVISYNTH #define WITH_AVISYNTH
// Enable ffmpegsource video and audio providers
// Requires: FFmpegSource2 headers (in repository), loader library and DLL
//#define WITH_FFMPEGSOURCE
///////////// MEDIUM PRIORITY //////////// ///////////// MEDIUM PRIORITY ////////////
@ -140,19 +146,6 @@
//#define WITH_LIBASS //#define WITH_LIBASS
// Enable FFmpeg video and audio decoders
// Requires: libavcodec, libavformat, libswscale, libavutil
// If you compiled static libraries (yes, by default), uncomment the second line as well,
// and remember to add the correct .a files to the linker's additional dependencies.
// #define WITH_FFMPEG
// #define WITH_STATIC_FFMPEG
// Enable ffmpegsource video and audio providers
// Requires: ffmpegsource version 2
//#define WITH_FFMPEGSOURCE
// Enable Ruby support for Automation // Enable Ruby support for Automation
// Requires: Ruby 1.9 // Requires: Ruby 1.9
//#define WITH_RUBY //#define WITH_RUBY

View file

@ -1,83 +0,0 @@
// Copyright (c) 2005, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
#include "config.h"
#ifdef WITH_FFMPEG
#include <wx/wxprec.h>
#include <wx/filename.h>
#include "lavc_file.h"
LAVCFile::Initializer LAVCFile::init;
LAVCFile::Initializer::Initializer()
{
av_register_all();
}
LAVCFile::LAVCFile(Aegisub::String _filename)
{
int result = 0;
fctx = NULL;
wxString filename = _filename.c_str();
#ifdef WIN32
wxFileName fn(filename);
filename = fn.GetShortPath();
#endif
result = av_open_input_file(&fctx,filename.mb_str(csConvLocal),NULL,0,NULL);
if (result != 0) throw _T("Failed opening file.");
// Get stream info
result = av_find_stream_info(fctx);
if (result < 0) {
av_close_input_file(fctx);
fctx = NULL;
throw _T("Unable to read stream info");
}
refs = 1;
}
LAVCFile::~LAVCFile()
{
if (fctx)
av_close_input_file(fctx);
}
#endif // WITH_FFMPEG

View file

@ -1,69 +0,0 @@
// Copyright (c) 2005, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
#pragma once
#ifdef WIN32
#define EMULATE_INTTYPES
#endif
#include <wx/filename.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
#include "include/aegisub/aegisub.h"
class LAVCFile {
private:
unsigned refs;
LAVCFile(Aegisub::String filename);
~LAVCFile();
class Initializer {
public:
Initializer();
};
static Initializer init;
public:
AVFormatContext *fctx;
static LAVCFile *Create(Aegisub::String filename) { return new LAVCFile(filename); }
LAVCFile *AddRef() { refs++; return this; };
void Release() { if (!--refs) delete this; };
};

View file

@ -1,142 +0,0 @@
// Copyright (c) 2007, 2points
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include "config.h"
#ifdef WITH_FFMPEG
#ifdef WIN32
#define __STDC_CONSTANT_MACROS 1
#include <stdint.h>
#endif /* WIN32 */
#include "dialog_progress.h"
#include "lavc_keyframes.h"
///////////////
// Constructor
LAVCKeyFrames::LAVCKeyFrames(const Aegisub::String filename)
: file(0), stream(0), streamN(-1), numFrames(0) {
// Open LAVCFile
file = LAVCFile::Create(filename);
// Find video stream
for (unsigned int i = 0; i < file->fctx->nb_streams; ++i) {
if (file->fctx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
stream = file->fctx->streams[i];
streamN = i;
break;
}
}
if (streamN == -1) throw _T("ffmpeg keyframes reader: Could not find a video stream");
}
//////////////
// Destructor
LAVCKeyFrames::~LAVCKeyFrames() {
if (file) file->Release();
}
////////////////////////////
// Parse file for keyframes
wxArrayInt LAVCKeyFrames::GetKeyFrames() {
wxArrayInt keyframes;
AVPacket packet;
int total_frames;
// check if the stream duration is bogus (will happen for MKV files)
if (stream->duration == AV_NOPTS_VALUE) {
// throw _T("ffmpeg keyframes reader: demuxer returned invalid stream length");
// FIXME: find some less dumb way to do this
total_frames = 123456; // random suitably big number
}
else {
total_frames = stream->duration;
}
register unsigned int frameN = 0; // Number of parsed frames
numFrames = 0;
volatile bool canceled = false;
DialogProgress *progress = new DialogProgress(NULL,_("Load keyframes"),&canceled,_("Reading keyframes from video"),0,total_frames);
progress->Show();
progress->SetProgress(0,1);
while (av_read_frame(file->fctx, &packet) == 0 && !canceled) {
// Check if packet is part of video stream
if (packet.stream_index == streamN) {
framesData.push_back(LAVCFrameInfo(packet.dts, (packet.flags & PKT_FLAG_KEY) ? 1 : 0));
// Check if the packet contains a keyframe
if (packet.flags & PKT_FLAG_KEY)
// note: frame numbers start from 0, watch out for the fencepost error
keyframes.Add(frameN);
// Increment number of passed frames
frameN++;
/* Might need some adjustments here, to make it
appear as fluid as wanted. Just copied 2points thingy,
and reduced it a bit */
if ((frameN & (1024 - 1)) == 0)
progress->SetProgress(frameN,total_frames);
}
av_free_packet(&packet);
}
numFrames = frameN;
// Clean up progress
if (!canceled) progress->Destroy();
else throw wxString(_T("Keyframe loading cancelled by user"));
return keyframes;
}
// returns the video duration in frames
int LAVCKeyFrames::GetNumFrames() {
return numFrames;
}
// returns the frame metadata vector
LAVCFrameInfoVector LAVCKeyFrames::GetFrameData() {
return framesData;
}
#endif // WITH_FFMPEG

View file

@ -1,64 +0,0 @@
// Copyright (c) 2007, 2points
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
#pragma once
#include <wx/wxprec.h>
#include "lavc_file.h"
#include <vector>
struct LAVCFrameInfo {
int64_t DTS;
bool isKeyFrame;
LAVCFrameInfo(int64_t ADTS, bool isAKeyFrame) : DTS(ADTS), isKeyFrame(isAKeyFrame) {};
};
typedef std::vector<LAVCFrameInfo> LAVCFrameInfoVector;
class LAVCKeyFrames {
private:
LAVCFile* file; // Video file
AVStream* stream; // Used stream
int streamN; // Stream index
int numFrames; // number of frames in the video
protected:
LAVCFrameInfoVector framesData;
public:
LAVCKeyFrames(const Aegisub::String filename);
~LAVCKeyFrames();
wxArrayInt GetKeyFrames();
int GetNumFrames();
LAVCFrameInfoVector GetFrameData();
};

View file

@ -165,17 +165,6 @@
#endif #endif
//////////
// FFMPEG
#ifdef WITH_FFMPEG
#ifndef WITH_STATIC_FFMPEG
#pragma comment(lib, "avcodec-51.lib")
#pragma comment(lib, "avformat-51.lib")
#pragma comment(lib, "avutil-49.lib")
#endif
#endif
///////////// /////////////
// FreeType2 // FreeType2
#ifdef WITH_FREETYPE2 #ifdef WITH_FREETYPE2

View file

@ -1,419 +0,0 @@
// Copyright (c) 2006-2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include "config.h"
#ifdef WITH_FFMPEG
#ifdef WIN32
#define EMULATE_INTTYPES
#define __STDC_CONSTANT_MACROS 1
#include <stdint.h>
#endif /* WIN32 */
#include <wx/wxprec.h>
#include <wx/image.h>
#include <algorithm>
#include <vector>
#include "video_provider_lavc.h"
#include "mkv_wrap.h"
#include "lavc_file.h"
#include "utils.h"
#include "vfr.h"
#include "ass_file.h"
#include "lavc_keyframes.h"
#include "video_context.h"
#include "options.h"
///////////////
// Constructor
LAVCVideoProvider::LAVCVideoProvider(Aegisub::String filename,double fps) {
// Init variables
codecContext = NULL;
lavcfile = NULL;
codec = NULL;
stream = NULL;
frame = NULL;
frameRGB = NULL;
bufferRGB = NULL;
sws_context = NULL;
buffer1 = NULL;
buffer2 = NULL;
buffer1Size = 0;
buffer2Size = 0;
vidStream = -1;
validFrame = false;
framesData.clear();
// Load
LoadVideo(filename,fps);
}
//////////////
// Destructor
LAVCVideoProvider::~LAVCVideoProvider() {
Close();
}
//////////////
// Load video
void LAVCVideoProvider::LoadVideo(Aegisub::String filename, double fps) {
// Close first
Close();
lavcfile = LAVCFile::Create(filename);
// Load
try {
int result = 0;
// Find video stream
vidStream = -1;
codecContext = NULL;
for (int i=0; i < (int)lavcfile->fctx->nb_streams; i++) {
codecContext = lavcfile->fctx->streams[i]->codec;
if (codecContext->codec_type == CODEC_TYPE_VIDEO) {
stream = lavcfile->fctx->streams[i];
vidStream = i;
break;
}
}
if (vidStream == -1) throw _T("ffmpeg video provider: Could not find a video stream");
// Find codec
codec = avcodec_find_decoder(codecContext->codec_id);
if (!codec) throw _T("ffmpeg video provider: Could not find suitable video decoder");
// Enable truncation
//if (codec->capabilities & CODEC_CAP_TRUNCATED) codecContext->flags |= CODEC_FLAG_TRUNCATED;
// Open codec
result = avcodec_open(codecContext,codec);
if (result < 0) throw _T("ffmpeg video provider: Failed to open video decoder");
// Parse file for keyframes and other useful stuff
LAVCKeyFrames LAVCFrameData(filename);
KeyFramesList = LAVCFrameData.GetKeyFrames();
keyFramesLoaded = true;
// set length etc.
length = LAVCFrameData.GetNumFrames();
framesData = LAVCFrameData.GetFrameData();
std::vector<int> timecodesVector;
for (int i = 0; i < length; i++) {
int timestamp = (int)((framesData[i].DTS * (int64_t)lavcfile->fctx->streams[vidStream]->time_base.num * 1000)
/ (int64_t)lavcfile->fctx->streams[vidStream]->time_base.den);
timecodesVector.push_back(timestamp);
}
timecodes.SetVFR(timecodesVector);
int OverrideTC = wxYES;
if (VFR_Output.IsLoaded()) {
OverrideTC = wxMessageBox(_("You already have timecodes loaded. Would you like to replace them with timecodes from the video file?"), _("Replace timecodes?"), wxYES_NO | wxICON_QUESTION);
if (OverrideTC == wxYES) {
VFR_Input.SetVFR(timecodesVector);
VFR_Output.SetVFR(timecodesVector);
}
} else { // no timecodes loaded, go ahead and apply
VFR_Input.SetVFR(timecodesVector);
VFR_Output.SetVFR(timecodesVector);
}
// Allocate frame
frame = avcodec_alloc_frame();
// Set frame
frameNumber = -1;
lastFrameNumber = -1;
allowUnsafeSeeking = Options.AsBool(_T("FFmpeg allow unsafe seeking"));
}
// Catch errors
catch (...) {
Close();
throw;
}
}
///////////////
// Close video
void LAVCVideoProvider::Close() {
// Clean buffers
if (buffer1) delete buffer1;
if (buffer2) delete buffer2;
buffer1 = NULL;
buffer2 = NULL;
buffer1Size = 0;
buffer2Size = 0;
// Clean frame
if (frame) av_free((void*)frame);
frame = NULL;
// Free SWS context and other stuff from RGB conversion
if (sws_context)
sws_freeContext(sws_context);
sws_context = NULL;
if(frameRGB)
av_free(frameRGB);
frameRGB = NULL;
if(bufferRGB)
delete(bufferRGB);
bufferRGB = NULL;
// Close codec context
if (codec && codecContext) avcodec_close(codecContext);
codecContext = NULL;
codec = NULL;
// Close format context
if (lavcfile)
lavcfile->Release();
lavcfile = NULL;
}
//////////////////
// Get next frame
bool LAVCVideoProvider::GetNextFrame(int64_t *startDTS) {
AVPacket packet;
*startDTS = -1; // magic
// Read packet
while (av_read_frame(lavcfile->fctx, &packet)>=0) {
// Check if packet is part of video stream
if(packet.stream_index == vidStream) {
// Decode frame
int frameFinished;
if (*startDTS < 0)
*startDTS = packet.dts;
avcodec_decode_video(codecContext, frame, &frameFinished, packet.data, packet.size);
// Success?
if(frameFinished) {
// Set time
lastDecodeTime = packet.dts;
// Free packet and return
av_free_packet(&packet);
return true;
}
}
// free packet
av_free_packet(&packet);
}
// No more packets
return false;
}
/////////////
// Get frame
const AegiVideoFrame LAVCVideoProvider::GetFrame(int n,int formatType) {
// Return stored frame
// n = MID(0,n,GetFrameCount()-1);
if (n == lastFrameNumber) {
if (!validFrame) validFrame = true;
return curFrame;
}
if (frameNumber < 0)
frameNumber = 0;
// Find closest keyframe to the frame we want
int closestKeyFrame = FindClosestKeyframe(n);
bool hasSeeked = false;
// do we really need to seek?
// 10 frames is used as a margin to prevent excessive seeking since the predicted best keyframe isn't always selected by avformat
if (n < frameNumber || closestKeyFrame > frameNumber+10) {
// turns out we did need it, just do it
av_seek_frame(lavcfile->fctx, vidStream, framesData[closestKeyFrame].DTS, AVSEEK_FLAG_BACKWARD);
avcodec_flush_buffers(codecContext);
hasSeeked = true;
}
// regardless of whether we sekeed or not, decode frames until we have the one we want
do {
int64_t startTime;
GetNextFrame(&startTime);
if (hasSeeked) {
hasSeeked = false;
// is the seek destination known? does it belong to a frame?
if (startTime < 0 || (frameNumber = FrameFromDTS(startTime)) < 0) {
// guessing destination, may be unsafe
if (allowUnsafeSeeking)
frameNumber = ClosestFrameFromDTS(startTime);
else
throw _T("ffmpeg video provider: frame accurate seeking failed");
}
}
frameNumber++;
} while (frameNumber <= n);
// Get aegisub frame
AegiVideoFrame &final = curFrame;
if (frame) {
int w = codecContext->width;
int h = codecContext->height;
PixelFormat srcFormat = codecContext->pix_fmt;
PixelFormat dstFormat = PIX_FMT_BGRA;
// Allocate RGB32 buffer
if(!sws_context) //first frame
{
frameRGB = avcodec_alloc_frame();
unsigned int dstSize = avpicture_get_size(dstFormat,w,h);
bufferRGB = new uint8_t[dstSize];
sws_context = sws_getContext(w, h, srcFormat, w, h, dstFormat, SWS_PRINT_INFO | SWS_BICUBIC, NULL, NULL, NULL);
// sws_getContext() always returns NULL if context creation failed
if (sws_context == NULL)
throw _T("ffmpeg video provider: failed to initialize SwScaler colorspace conversion");
}
avpicture_fill((AVPicture*) frameRGB, bufferRGB, dstFormat, w, h);
// Set AegiVideoFrame
final.w = codecContext->width;
final.h = codecContext->height;
final.flipped = false;
final.invertChannels = true;
final.format = FORMAT_RGB32;
// Allocate
for (int i=0;i<4;i++) final.pitch[i] = frameRGB->linesize[i];
final.Allocate();
// Convert to RGB32, and write directly to the output frame
sws_scale(sws_context, frame->data, frame->linesize, 0, h, final.data, frameRGB->linesize);
}
else // No frame available
{
final = AegiVideoFrame(GetWidth(),GetHeight());
}
// Set current frame
validFrame = true;
lastFrameNumber = n;
// Return
return final;
}
////////////////
// Get position
int LAVCVideoProvider::GetPosition() {
return frameNumber;
}
////////////////////////
// Get number of frames
int LAVCVideoProvider::GetFrameCount() {
return length;
}
//////////////////
// Get frame rate
double LAVCVideoProvider::GetFPS() {
return double(stream->r_frame_rate.num) / double(stream->r_frame_rate.den);
}
//////////////////////
// Get original width
int LAVCVideoProvider::GetWidth() {
return codecContext->width;
}
///////////////////////
// Get original height
int LAVCVideoProvider::GetHeight() {
return codecContext->height;
}
//////////////////////
// Find the keyframe we should seek to if we want to seek to a given frame N
int LAVCVideoProvider::FindClosestKeyframe(int frameN) {
for (int i = frameN; i > 0; i--)
if (framesData[i].isKeyFrame)
return i;
return 0;
}
//////////////////////
// Convert a DTS into a frame number
int LAVCVideoProvider::FrameFromDTS(int64_t ADTS) {
for (int i = 0; i < (int)framesData.size(); i++)
if (framesData[i].DTS == ADTS)
return i;
return -1;
}
//////////////////////
// Find closest frame to the given DTS
int LAVCVideoProvider::ClosestFrameFromDTS(int64_t ADTS) {
int n = 0;
int64_t bestDiff = 0xFFFFFFFFFFFFFFLL; // big number
for (int i = 0; i < (int)framesData.size(); i++) {
int64_t currentDiff = FFABS(framesData[i].DTS - ADTS);
if (currentDiff < bestDiff) {
bestDiff = currentDiff;
n = i;
}
}
return n;
}
#endif // WITH_FFMPEG

View file

@ -1,140 +0,0 @@
// Copyright (c) 2006-2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#ifdef WITH_FFMPEG
#ifdef WIN32
#define EMULATE_INTTYPES
#endif
#include <vector>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
#include "include/aegisub/video_provider.h"
#include "include/aegisub/aegisub.h"
#include "mkv_wrap.h"
#include "lavc_file.h"
#include "lavc_keyframes.h"
///////////////////////
// LibAVCodec provider
class LAVCVideoProvider : public VideoProvider {
friend class LAVCAudioProvider;
private:
MatroskaWrapper mkv;
LAVCFile *lavcfile;
AVCodecContext *codecContext;
AVStream *stream;
AVCodec *codec;
AVFrame *frame;
int vidStream;
AVFrame *frameRGB;
uint8_t *bufferRGB;
SwsContext *sws_context;
wxArrayInt KeyFramesList;
bool keyFramesLoaded;
// bool isVfr; // currently unused
int display_w;
int display_h;
wxArrayInt bytePos;
bool allowUnsafeSeeking;
bool isMkv;
int64_t lastDecodeTime;
int frameNumber;
int lastFrameNumber;
int length;
AegiVideoFrame curFrame;
bool validFrame;
LAVCFrameInfoVector framesData;
FrameRate timecodes;
uint8_t *buffer1;
uint8_t *buffer2;
int buffer1Size;
int buffer2Size;
int FindClosestKeyframe(int frameN);
int FrameFromDTS(int64_t ADTS);
int ClosestFrameFromDTS(int64_t ADTS);
bool GetNextFrame(int64_t *DTS);
void LoadVideo(Aegisub::String filename, double fps);
void Close();
protected:
public:
LAVCVideoProvider(Aegisub::String filename, double fps);
~LAVCVideoProvider();
const AegiVideoFrame GetFrame(int n,int formatType);
int GetPosition();
int GetFrameCount();
int GetWidth();
int GetHeight();
double GetFPS();
bool AreKeyFramesLoaded() { return keyFramesLoaded; };
wxArrayInt GetKeyFrames() { return KeyFramesList; };
bool IsVFR() { return true; };
FrameRate GetTrueFrameRate() { return timecodes; };
Aegisub::String GetDecoderName() { return L"FFMpeg/libavcodec"; }
bool IsNativelyByFrames() { return true; }
int GetDesiredCacheSize() { return 8; }
};
///////////
// Factory
class LAVCVideoProviderFactory : public VideoProviderFactory {
public:
VideoProvider *CreateProvider(Aegisub::String video,double fps=0.0) { return new LAVCVideoProvider(video,fps); }
};
#endif

View file

@ -48,9 +48,6 @@
#ifdef WITH_DIRECTSHOW #ifdef WITH_DIRECTSHOW
#include "video_provider_dshow.h" #include "video_provider_dshow.h"
#endif #endif
#ifdef WITH_FFMPEG
#include "video_provider_lavc.h"
#endif
#ifdef WITH_FFMPEGSOURCE #ifdef WITH_FFMPEGSOURCE
#include "video_provider_ffmpegsource.h" #include "video_provider_ffmpegsource.h"
#endif #endif
@ -113,9 +110,6 @@ void VideoProviderFactoryManager::RegisterProviders() {
#ifdef WITH_DIRECTSHOW #ifdef WITH_DIRECTSHOW
RegisterFactory(new DirectShowVideoProviderFactory(),_T("DirectShow")); RegisterFactory(new DirectShowVideoProviderFactory(),_T("DirectShow"));
#endif #endif
#ifdef WITH_FFMPEG
RegisterFactory(new LAVCVideoProviderFactory(),_T("FFMPEG"));
#endif
#ifdef WITH_FFMPEGSOURCE #ifdef WITH_FFMPEGSOURCE
RegisterFactory(new FFmpegSourceVideoProviderFactory(),_T("FFmpegSource")); RegisterFactory(new FFmpegSourceVideoProviderFactory(),_T("FFmpegSource"));
#endif #endif