mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-10 07:26:32 +01:00
Add M4A support to the audio import dialog using FFMPEG.
This uses the existing optional runtime ffmpeg dependency to add support for m4a files (and in theory whatever other file formats ffmpeg supports) to the import audio dialog. The same functionality is mostly already available via Session -> Open Video, with the "import audio only" selection (even though m4a isn't currently included as one of the video formats, it still works). Having this in the import audio dialog however seems much more user friendly.
This commit is contained in:
parent
f4166fb61d
commit
0a54f96a44
8 changed files with 516 additions and 1 deletions
84
libs/ardour/ardour/ffmpegfileimportable.h
Normal file
84
libs/ardour/ardour/ffmpegfileimportable.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Marijn Kruisselbrink <mek@google.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _ardour_ffmpegfile_importable_source_h_
|
||||
#define _ardour_ffmpegfile_importable_source_h_
|
||||
|
||||
#include "pbd/g_atomic_compat.h"
|
||||
#include "pbd/ringbuffer.h"
|
||||
|
||||
#include "ardour/importable_source.h"
|
||||
#include "ardour/libardour_visibility.h"
|
||||
#include "ardour/system_exec.h"
|
||||
#include "ardour/types.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class LIBARDOUR_API FFMPEGFileImportableSource : public ImportableSource {
|
||||
public:
|
||||
enum {
|
||||
ALL_CHANNELS = -1,
|
||||
};
|
||||
FFMPEGFileImportableSource(const std::string &path, int channel = ALL_CHANNELS);
|
||||
virtual ~FFMPEGFileImportableSource();
|
||||
|
||||
/* ImportableSource API */
|
||||
uint32_t channels () const { return _channels; }
|
||||
samplecnt_t length () const { return _length; }
|
||||
samplecnt_t samplerate () const { return _samplerate; }
|
||||
samplepos_t natural_position () const { return _natural_position; }
|
||||
void seek (samplepos_t pos);
|
||||
samplecnt_t read (Sample*, samplecnt_t nframes);
|
||||
|
||||
bool clamped_at_unity () const { return false; }
|
||||
|
||||
std::string format_name () const { return _format_name; }
|
||||
|
||||
private:
|
||||
void start_ffmpeg ();
|
||||
void reset ();
|
||||
|
||||
void did_read_data (std::string data, size_t size);
|
||||
|
||||
std::string _path;
|
||||
int _channel;
|
||||
|
||||
uint32_t _channels;
|
||||
samplecnt_t _length;
|
||||
samplecnt_t _samplerate;
|
||||
samplepos_t _natural_position;
|
||||
std::string _format_name;
|
||||
|
||||
PBD::RingBuffer<Sample> _buffer;
|
||||
// Set to 1 to indicate that ffmpeg should be terminating.
|
||||
GATOMIC_QUAL gint _ffmpeg_should_terminate;
|
||||
|
||||
// To make sure we don't try to parse partial floats, we might have a couple of bytes
|
||||
// of leftover unparsable data after any `did_read_data` call. Those couple of bytes are
|
||||
// stored here until the next `did_read_data` call.
|
||||
std::string _leftover_data;
|
||||
|
||||
samplecnt_t _read_pos;
|
||||
|
||||
ARDOUR::SystemExec *_ffmpeg_exec;
|
||||
PBD::ScopedConnection _ffmpeg_conn;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* _ardour_ffmpegfile_importable_source_h_ */
|
||||
60
libs/ardour/ardour/ffmpegfilesource.h
Normal file
60
libs/ardour/ardour/ffmpegfilesource.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Marijn Kruisselbrink <mek@google.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _ardour_ffmpegfile_source_h_
|
||||
#define _ardour_ffmpegfile_source_h_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ardour/audiofilesource.h"
|
||||
#include "ardour/ffmpegfileimportable.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class LIBARDOUR_API FFMPEGFileSource : public AudioFileSource {
|
||||
public:
|
||||
FFMPEGFileSource(ARDOUR::Session &, const std::string &path, int chn, Flag);
|
||||
~FFMPEGFileSource();
|
||||
|
||||
/* AudioSource API */
|
||||
float sample_rate() const { return _ffmpeg.samplerate (); }
|
||||
bool clamped_at_unity () const { return false; }
|
||||
|
||||
/* AudioFileSource API */
|
||||
void flush () {}
|
||||
int update_header (samplepos_t when, struct tm&, time_t) { return 0; }
|
||||
int flush_header () { return 0; }
|
||||
void set_header_natural_position () {};
|
||||
|
||||
static int get_soundfile_info (const std::string& path, SoundFileInfo& _info, std::string& error_msg);
|
||||
static bool safe_audio_file_extension (const std::string &file);
|
||||
|
||||
protected:
|
||||
/* FileSource API */
|
||||
void close ();
|
||||
/* AudioSource API */
|
||||
samplecnt_t read_unlocked (Sample *dst, samplepos_t start, samplecnt_t cnt) const;
|
||||
samplecnt_t write_unlocked (Sample *, samplecnt_t) { return 0; }
|
||||
|
||||
private:
|
||||
mutable FFMPEGFileImportableSource _ffmpeg;
|
||||
int _channel;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -51,6 +51,7 @@
|
|||
|
||||
#include "ardour/audiofilesource.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/ffmpegfilesource.h"
|
||||
#include "ardour/mp3filesource.h"
|
||||
#include "ardour/sndfilesource.h"
|
||||
#include "ardour/session.h"
|
||||
|
|
@ -208,6 +209,10 @@ AudioFileSource::get_soundfile_info (const string& path, SoundFileInfo& _info, s
|
|||
return true;
|
||||
}
|
||||
|
||||
if (FFMPEGFileSource::get_soundfile_info (path, _info, error_msg) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -342,7 +347,6 @@ AudioFileSource::safe_audio_file_extension(const string& file)
|
|||
".mpeg", ".MPEG",
|
||||
".mp1", ".MP1",
|
||||
".mp4", ".MP4",
|
||||
".m4a", ".M4A",
|
||||
".sd2", ".SD2", // libsndfile supports sd2 also, but the resource fork is required to open.
|
||||
#endif // HAVE_COREAUDIO
|
||||
};
|
||||
|
|
@ -353,6 +357,10 @@ AudioFileSource::safe_audio_file_extension(const string& file)
|
|||
}
|
||||
}
|
||||
|
||||
if (FFMPEGFileSource::safe_audio_file_extension(file)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
243
libs/ardour/ffmpegfileimportable.cc
Normal file
243
libs/ardour/ffmpegfileimportable.cc
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Marijn Kruisselbrink <mek@google.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/compose.h"
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
#include "ardour/ffmpegfileimportable.h"
|
||||
#include "ardour/filesystem_paths.h"
|
||||
#include "ardour/system_exec.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
static void
|
||||
receive_stdout (std::string* out, const std::string& data, size_t size) {
|
||||
*out += data;
|
||||
}
|
||||
|
||||
FFMPEGFileImportableSource::FFMPEGFileImportableSource(const std::string &path, int channel)
|
||||
: _path (path)
|
||||
, _channel (channel)
|
||||
, _buffer (32768)
|
||||
, _ffmpeg_should_terminate (0)
|
||||
, _read_pos (0)
|
||||
, _ffmpeg_exec (nullptr)
|
||||
{
|
||||
std::string ffprobe_exe, unused;
|
||||
if (!ArdourVideoToolPaths::transcoder_exe (unused, ffprobe_exe)) {
|
||||
PBD::error << "FFMPEGFileImportableSource: Can't find ffprobe and ffmpeg" << endmsg;
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
int a = 0;
|
||||
char **argp = (char **)calloc(10, sizeof(char *));
|
||||
argp[a++] = strdup (ffprobe_exe.c_str ());
|
||||
argp[a++] = strdup (_path.c_str ());
|
||||
argp[a++] = strdup ("-show_streams");
|
||||
argp[a++] = strdup ("-of");
|
||||
argp[a++] = strdup ("json");
|
||||
|
||||
auto exec = std::make_unique<ARDOUR::SystemExec>(ffprobe_exe, argp);
|
||||
PBD::info << "Probe command: { " << exec->to_s () << "}" << endmsg;
|
||||
|
||||
if (exec->start ()) {
|
||||
PBD::error << "FFMPEGFileImportableSource: External decoder (ffprobe) cannot be started." << endmsg;
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
try {
|
||||
PBD::ScopedConnection c;
|
||||
std::string ffprobe_output;
|
||||
exec->ReadStdout.connect_same_thread (c, boost::bind (&receive_stdout, &ffprobe_output, _1, _2));
|
||||
while (exec->is_running ()) {
|
||||
// wait for system exec to terminate
|
||||
Glib::usleep (1000);
|
||||
}
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
std::istringstream is (ffprobe_output);
|
||||
pt::ptree root;
|
||||
pt::read_json (is, root);
|
||||
|
||||
// TODO: Find the stream with the most channels, rather than whatever the first one is.
|
||||
_channels = root.get<int> ("streams..channels");
|
||||
_length = root.get<int64_t> ("streams..duration_ts");
|
||||
_samplerate = root.get<int> ("streams..sample_rate");
|
||||
_natural_position = root.get<int64_t> ("streams..start_pts");
|
||||
_format_name = root.get<std::string> ("streams..codec_long_name");
|
||||
} catch (...) {
|
||||
PBD::error << "FFMPEGFileImportableSource: Failed to read file metadata" << endmsg;
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
if (_channel != ALL_CHANNELS && (_channel < 0 || _channel > (int) channels ())) {
|
||||
PBD::error << string_compose("FFMPEGFileImportableSource: file only contains %1 channels; %2 is invalid as a channel number", channels(), _channel) << endmsg;
|
||||
throw failed_constructor();
|
||||
}
|
||||
}
|
||||
|
||||
FFMPEGFileImportableSource::~FFMPEGFileImportableSource ()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void
|
||||
FFMPEGFileImportableSource::seek (samplepos_t pos)
|
||||
{
|
||||
if (pos < _read_pos) {
|
||||
reset();
|
||||
}
|
||||
|
||||
if (!_ffmpeg_exec) {
|
||||
start_ffmpeg();
|
||||
}
|
||||
|
||||
while (_read_pos < pos) {
|
||||
guint read_space = _buffer.read_space ();
|
||||
if (read_space == 0) {
|
||||
if (!_ffmpeg_exec->is_running ()) {
|
||||
// FFMPEG quit, must have reached EOF.
|
||||
PBD::warning << string_compose ("FFMPEGFileImportableSource: Reached EOF while trying to seek to %1", pos) << endmsg;
|
||||
break;
|
||||
}
|
||||
// TODO: don't just spin, but use some signalling
|
||||
Glib::usleep (1000);
|
||||
continue;
|
||||
}
|
||||
guint inc = std::min<guint>(read_space, pos - _read_pos);
|
||||
_buffer.increment_read_idx (inc);
|
||||
_read_pos += inc;
|
||||
}
|
||||
}
|
||||
|
||||
samplecnt_t
|
||||
FFMPEGFileImportableSource::read (Sample* dst, samplecnt_t nframes)
|
||||
{
|
||||
if (!_ffmpeg_exec) {
|
||||
start_ffmpeg();
|
||||
}
|
||||
|
||||
samplecnt_t total_read = 0;
|
||||
while (nframes > 0) {
|
||||
guint read = _buffer.read (dst + total_read, nframes);
|
||||
if (read == 0) {
|
||||
if (!_ffmpeg_exec->is_running ()) {
|
||||
// FFMPEG quit, must have reached EOF.
|
||||
break;
|
||||
}
|
||||
// TODO: don't just spin, but use some signalling
|
||||
Glib::usleep (1000);
|
||||
continue;
|
||||
}
|
||||
nframes -= read;
|
||||
total_read += read;
|
||||
_read_pos += read;
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
void
|
||||
FFMPEGFileImportableSource::start_ffmpeg ()
|
||||
{
|
||||
std::string ffmpeg_exe, unused;
|
||||
ArdourVideoToolPaths::transcoder_exe (ffmpeg_exe, unused);
|
||||
|
||||
int a = 0;
|
||||
char **argp = (char **)calloc(16, sizeof(char *));
|
||||
char tmp[32];
|
||||
argp[a++] = strdup (ffmpeg_exe.c_str ());
|
||||
argp[a++] = strdup ("-nostdin");
|
||||
argp[a++] = strdup ("-i");
|
||||
argp[a++] = strdup (_path.c_str ());
|
||||
if (_channel != ALL_CHANNELS) {
|
||||
argp[a++] = strdup ("-map_channel");
|
||||
snprintf (tmp, sizeof(tmp), "0.0.%d", _channel);
|
||||
argp[a++] = strdup (tmp);
|
||||
}
|
||||
argp[a++] = strdup ("-f");
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
argp[a++] = strdup ("f32le");
|
||||
#else
|
||||
argp[a++] = strdup ("f32be");
|
||||
#endif
|
||||
argp[a++] = strdup ("-");
|
||||
|
||||
_ffmpeg_exec = new ARDOUR::SystemExec (ffmpeg_exe, argp);
|
||||
PBD::info << "Decode command: { " << _ffmpeg_exec->to_s () << "}" << endmsg;
|
||||
if (_ffmpeg_exec->start ()) {
|
||||
PBD::error << "FFMPEGFileImportableSource: External decoder (ffmpeg) cannot be started." << endmsg;
|
||||
throw std::runtime_error("Failed to start ffmpeg");
|
||||
}
|
||||
|
||||
_ffmpeg_exec->ReadStdout.connect_same_thread (_ffmpeg_conn, boost::bind (&FFMPEGFileImportableSource::did_read_data, this, _1, _2));
|
||||
}
|
||||
|
||||
void
|
||||
FFMPEGFileImportableSource::reset ()
|
||||
{
|
||||
// TODO: actually signal did_read_data to unblock
|
||||
g_atomic_int_set (&_ffmpeg_should_terminate, 1);
|
||||
delete _ffmpeg_exec;
|
||||
_ffmpeg_conn.disconnect ();
|
||||
_buffer.reset ();
|
||||
_read_pos = 0;
|
||||
g_atomic_int_set (&_ffmpeg_should_terminate, 0);
|
||||
}
|
||||
|
||||
void
|
||||
FFMPEGFileImportableSource::did_read_data (std::string data, size_t size)
|
||||
{
|
||||
// Prepend the left-over data from a previous chunk of received data to this chunk.
|
||||
data = _leftover_data + data;
|
||||
samplecnt_t n_samples = data.length () / sizeof(float);
|
||||
|
||||
// Stash leftover data.
|
||||
_leftover_data = data.substr(n_samples * sizeof(float));
|
||||
|
||||
const char* cur = data.data ();
|
||||
while (n_samples > 0) {
|
||||
if (g_atomic_int_get (&_ffmpeg_should_terminate)) {
|
||||
break;
|
||||
}
|
||||
|
||||
PBD::RingBuffer<float>::rw_vector wv;
|
||||
_buffer.get_write_vector (&wv);
|
||||
if (wv.len[0] == 0) {
|
||||
// TODO: don't just spin, but use some signalling
|
||||
Glib::usleep (1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
samplecnt_t written = 0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
samplecnt_t cnt = std::min<samplecnt_t>(n_samples, wv.len[i]);
|
||||
memcpy (wv.buf[i], cur, cnt * sizeof(float));
|
||||
written += cnt;
|
||||
n_samples -= cnt;
|
||||
cur += cnt * sizeof(float);
|
||||
}
|
||||
_buffer.increment_write_idx (written);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
96
libs/ardour/ffmpegfilesource.cc
Normal file
96
libs/ardour/ffmpegfilesource.cc
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Marijn Kruisselbrink <mek@google.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "ardour/ffmpegfileimportable.h"
|
||||
#include "ardour/ffmpegfilesource.h"
|
||||
#include "ardour/filesystem_paths.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
/** Constructor to be called for existing external-to-session files
|
||||
* Sources created with this method are never writable or removable.
|
||||
*/
|
||||
|
||||
FFMPEGFileSource::FFMPEGFileSource (Session& s, const std::string& path, int chn, Flag flags)
|
||||
: Source (s, DataType::AUDIO, path,
|
||||
Source::Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
|
||||
, AudioFileSource (s, path,
|
||||
Source::Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
|
||||
, _ffmpeg (path, chn)
|
||||
{
|
||||
_length = _ffmpeg.length ();
|
||||
}
|
||||
|
||||
FFMPEGFileSource::~FFMPEGFileSource ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FFMPEGFileSource::close ()
|
||||
{
|
||||
}
|
||||
|
||||
samplecnt_t
|
||||
FFMPEGFileSource::read_unlocked (Sample* dst, samplepos_t start, samplecnt_t cnt) const
|
||||
{
|
||||
_ffmpeg.seek (start);
|
||||
return _ffmpeg.read (dst, cnt);
|
||||
}
|
||||
|
||||
int
|
||||
FFMPEGFileSource::get_soundfile_info (const std::string& path, SoundFileInfo &_info, std::string &error_msg)
|
||||
{
|
||||
if (!safe_audio_file_extension (path)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
FFMPEGFileImportableSource ffmpeg (path);
|
||||
_info.samplerate = ffmpeg.samplerate ();
|
||||
_info.channels = ffmpeg.channels ();
|
||||
_info.length = ffmpeg.length ();
|
||||
_info.format_name = ffmpeg.format_name ();
|
||||
_info.timecode = ffmpeg.natural_position ();
|
||||
_info.seekable = false;
|
||||
return 0;
|
||||
} catch (...) {}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
FFMPEGFileSource::safe_audio_file_extension (const std::string &file)
|
||||
{
|
||||
std::string unused;
|
||||
if (!ArdourVideoToolPaths::transcoder_exe (unused, unused)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *suffixes[] = {
|
||||
".m4a", ".M4A",
|
||||
};
|
||||
|
||||
for (size_t n = 0; n < sizeof(suffixes) / sizeof(suffixes[0]); ++n) {
|
||||
if (file.rfind(suffixes[n]) == file.length() - strlen(suffixes[n])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -53,6 +53,7 @@
|
|||
#include "ardour/ardour.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/audioregion.h"
|
||||
#include "ardour/ffmpegfileimportable.h"
|
||||
#include "ardour/import_status.h"
|
||||
#include "ardour/mp3fileimportable.h"
|
||||
#include "ardour/region_factory.h"
|
||||
|
|
@ -123,6 +124,18 @@ open_importable_source (const string& path, samplecnt_t samplerate, ARDOUR::SrcQ
|
|||
return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
|
||||
} catch (...) { }
|
||||
|
||||
/* finally try FFMPEG */
|
||||
try {
|
||||
boost::shared_ptr<FFMPEGFileImportableSource> source(new FFMPEGFileImportableSource(path));
|
||||
|
||||
if (source->samplerate() == samplerate) {
|
||||
return source;
|
||||
}
|
||||
|
||||
/* rewrap as a resampled source */
|
||||
return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
|
||||
} catch (...) { }
|
||||
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "ardour/audioplaylist.h"
|
||||
#include "ardour/audio_playlist_source.h"
|
||||
#include "ardour/boost_debug.h"
|
||||
#include "ardour/ffmpegfilesource.h"
|
||||
#include "ardour/midi_playlist.h"
|
||||
#include "ardour/midi_playlist_source.h"
|
||||
#include "ardour/mp3filesource.h"
|
||||
|
|
@ -272,6 +273,14 @@ SourceFactory::createExternal (DataType type, Session& s, const string& path,
|
|||
return ret;
|
||||
|
||||
} catch (failed_constructor& err) { }
|
||||
|
||||
try {
|
||||
Source* src = new FFMPEGFileSource (s, path, chn, flags);
|
||||
boost::shared_ptr<Source> ret (src);
|
||||
BOOST_MARK_SOURCE (ret);
|
||||
return ret;
|
||||
|
||||
} catch (failed_constructor& err) { }
|
||||
}
|
||||
|
||||
} else if (type == DataType::MIDI) {
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ libardour_sources = [
|
|||
'export_profile_manager.cc',
|
||||
'export_status.cc',
|
||||
'export_timespan.cc',
|
||||
'ffmpegfileimportable.cc',
|
||||
'ffmpegfilesource.cc',
|
||||
'file_source.cc',
|
||||
'filename_extensions.cc',
|
||||
'filesystem_paths.cc',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue