forked from mia/Aegisub
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:
parent
e589bceaa6
commit
dfea9f9713
12 changed files with 6 additions and 1352 deletions
|
@ -47,9 +47,6 @@
|
|||
#ifdef WITH_AVISYNTH
|
||||
#include "audio_provider_avs.h"
|
||||
#endif
|
||||
#ifdef WITH_FFMPEG
|
||||
#include "audio_provider_lavc.h"
|
||||
#endif
|
||||
#ifdef WITH_FFMPEGSOURCE
|
||||
#include "audio_provider_ffmpegsource.h"
|
||||
#endif
|
||||
|
@ -283,9 +280,6 @@ void AudioProviderFactoryManager::RegisterProviders() {
|
|||
#ifdef WITH_AVISYNTH
|
||||
RegisterFactory(new AvisynthAudioProviderFactory(),_T("Avisynth"));
|
||||
#endif
|
||||
#ifdef WITH_FFMPEG
|
||||
RegisterFactory(new LAVCAudioProviderFactory(),_T("FFMPEG"));
|
||||
#endif
|
||||
#ifdef WITH_FFMPEGSOURCE
|
||||
RegisterFactory(new FFmpegSourceAudioProviderFactory(),_T("FFmpegSource"));
|
||||
#endif
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -75,6 +75,12 @@
|
|||
#define WITH_AVISYNTH
|
||||
|
||||
|
||||
// Enable ffmpegsource video and audio providers
|
||||
// Requires: FFmpegSource2 headers (in repository), loader library and DLL
|
||||
//#define WITH_FFMPEGSOURCE
|
||||
|
||||
|
||||
|
||||
|
||||
///////////// MEDIUM PRIORITY ////////////
|
||||
|
||||
|
@ -140,19 +146,6 @@
|
|||
//#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
|
||||
// Requires: Ruby 1.9
|
||||
//#define WITH_RUBY
|
||||
|
|
|
@ -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
|
|
@ -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; };
|
||||
};
|
|
@ -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
|
|
@ -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();
|
||||
};
|
|
@ -165,17 +165,6 @@
|
|||
#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
|
||||
#ifdef WITH_FREETYPE2
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -48,9 +48,6 @@
|
|||
#ifdef WITH_DIRECTSHOW
|
||||
#include "video_provider_dshow.h"
|
||||
#endif
|
||||
#ifdef WITH_FFMPEG
|
||||
#include "video_provider_lavc.h"
|
||||
#endif
|
||||
#ifdef WITH_FFMPEGSOURCE
|
||||
#include "video_provider_ffmpegsource.h"
|
||||
#endif
|
||||
|
@ -113,9 +110,6 @@ void VideoProviderFactoryManager::RegisterProviders() {
|
|||
#ifdef WITH_DIRECTSHOW
|
||||
RegisterFactory(new DirectShowVideoProviderFactory(),_T("DirectShow"));
|
||||
#endif
|
||||
#ifdef WITH_FFMPEG
|
||||
RegisterFactory(new LAVCVideoProviderFactory(),_T("FFMPEG"));
|
||||
#endif
|
||||
#ifdef WITH_FFMPEGSOURCE
|
||||
RegisterFactory(new FFmpegSourceVideoProviderFactory(),_T("FFmpegSource"));
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue