Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extern/audaspace/CMakeLists.txt6
-rw-r--r--extern/audaspace/bindings/C/AUD_PlaybackManager.h2
-rw-r--r--extern/audaspace/bindings/C/AUD_Sound.cpp42
-rw-r--r--extern/audaspace/bindings/C/AUD_Sound.h27
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.cpp8
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.h2
-rw-r--r--extern/audaspace/bindings/C/AUD_Types.h14
-rw-r--r--extern/audaspace/bindings/python/PySound.cpp12
-rw-r--r--extern/audaspace/include/IReader.h6
-rw-r--r--extern/audaspace/include/file/File.h23
-rw-r--r--extern/audaspace/include/file/FileInfo.h42
-rw-r--r--extern/audaspace/include/file/FileManager.h24
-rw-r--r--extern/audaspace/include/file/IFileInput.h24
-rw-r--r--extern/audaspace/include/fx/VolumeReader.h2
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEG.cpp18
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEG.h6
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp169
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGReader.h42
-rw-r--r--extern/audaspace/plugins/libsndfile/SndFile.cpp14
-rw-r--r--extern/audaspace/plugins/libsndfile/SndFile.h6
-rw-r--r--extern/audaspace/plugins/libsndfile/SndFileReader.cpp15
-rw-r--r--extern/audaspace/plugins/libsndfile/SndFileReader.h12
-rw-r--r--extern/audaspace/src/file/File.cpp20
-rw-r--r--extern/audaspace/src/file/FileManager.cpp36
-rw-r--r--extern/audaspace/src/fx/VolumeReader.cpp2
-rw-r--r--source/blender/blenkernel/BKE_sound.h13
-rw-r--r--source/blender/blenkernel/intern/sound.c47
-rw-r--r--source/blender/editors/space_graph/graph_edit.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c62
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c4
-rw-r--r--source/blender/imbuf/intern/anim_movie.c7
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c4
-rw-r--r--source/blender/sequencer/SEQ_add.h2
-rw-r--r--source/blender/sequencer/intern/strip_add.c74
34 files changed, 605 insertions, 185 deletions
diff --git a/extern/audaspace/CMakeLists.txt b/extern/audaspace/CMakeLists.txt
index 1599c03cbad..552ff749512 100644
--- a/extern/audaspace/CMakeLists.txt
+++ b/extern/audaspace/CMakeLists.txt
@@ -152,6 +152,7 @@ set(PUBLIC_HDR
include/devices/ThreadedDevice.h
include/Exception.h
include/file/File.h
+ include/file/FileInfo.h
include/file/FileManager.h
include/file/FileWriter.h
include/file/IFileInput.h
@@ -960,7 +961,10 @@ endif()
if(BUILD_DEMOS)
include_directories(${INCLUDE})
- set(DEMOS audaplay audaconvert audaremap signalgen randsounds dynamicmusic playbackmanager)
+ set(DEMOS audainfo audaplay audaconvert audaremap signalgen randsounds dynamicmusic playbackmanager)
+
+ add_executable(audainfo demos/audainfo.cpp)
+ target_link_libraries(audainfo audaspace)
add_executable(audaplay demos/audaplay.cpp)
target_link_libraries(audaplay audaspace)
diff --git a/extern/audaspace/bindings/C/AUD_PlaybackManager.h b/extern/audaspace/bindings/C/AUD_PlaybackManager.h
index 0fa8171599d..a2f5134602a 100644
--- a/extern/audaspace/bindings/C/AUD_PlaybackManager.h
+++ b/extern/audaspace/bindings/C/AUD_PlaybackManager.h
@@ -39,7 +39,7 @@ extern AUD_API void AUD_PlaybackManager_free(AUD_PlaybackManager* manager);
* Plays a sound through the playback manager, adding it into a category.
* \param manager The PlaybackManager object.
* \param sound The sound to be played.
-* \param catKey The key of the category into which the sound will be added. If it doesn't exist a new one will be creatd.
+* \param catKey The key of the category into which the sound will be added. If it doesn't exist a new one will be created.
*/
extern AUD_API void AUD_PlaybackManager_play(AUD_PlaybackManager* manager, AUD_Sound* sound, unsigned int catKey);
diff --git a/extern/audaspace/bindings/C/AUD_Sound.cpp b/extern/audaspace/bindings/C/AUD_Sound.cpp
index 8c99ce2341f..aa246b9a047 100644
--- a/extern/audaspace/bindings/C/AUD_Sound.cpp
+++ b/extern/audaspace/bindings/C/AUD_Sound.cpp
@@ -94,6 +94,36 @@ AUD_API int AUD_Sound_getLength(AUD_Sound* sound)
return (*sound)->createReader()->getLength();
}
+AUD_API int AUD_Sound_getFileStreams(AUD_Sound* sound, AUD_StreamInfo **stream_infos)
+{
+ assert(sound);
+
+ std::shared_ptr<File> file = std::dynamic_pointer_cast<File>(*sound);
+
+ if(file)
+ {
+ auto streams = file->queryStreams();
+
+ size_t size = sizeof(AUD_StreamInfo) * streams.size();
+
+ if(!size)
+ {
+ *stream_infos = nullptr;
+ return 0;
+ }
+
+ *stream_infos = reinterpret_cast<AUD_StreamInfo*>(std::malloc(size));
+ std::memcpy(*stream_infos, streams.data(), size);
+
+ return streams.size();
+ }
+ else
+ {
+ *stream_infos = nullptr;
+ return 0;
+ }
+}
+
AUD_API sample_t* AUD_Sound_data(AUD_Sound* sound, int* length, AUD_Specs* specs)
{
assert(sound);
@@ -252,6 +282,12 @@ AUD_API AUD_Sound* AUD_Sound_bufferFile(unsigned char* buffer, int size)
return new AUD_Sound(new File(buffer, size));
}
+AUD_API AUD_Sound* AUD_Sound_bufferFileStream(unsigned char* buffer, int size, int stream)
+{
+ assert(buffer);
+ return new AUD_Sound(new File(buffer, size, stream));
+}
+
AUD_API AUD_Sound* AUD_Sound_cache(AUD_Sound* sound)
{
assert(sound);
@@ -272,6 +308,12 @@ AUD_API AUD_Sound* AUD_Sound_file(const char* filename)
return new AUD_Sound(new File(filename));
}
+AUD_API AUD_Sound* AUD_Sound_fileStream(const char* filename, int stream)
+{
+ assert(filename);
+ return new AUD_Sound(new File(filename, stream));
+}
+
AUD_API AUD_Sound* AUD_Sound_sawtooth(float frequency, AUD_SampleRate rate)
{
return new AUD_Sound(new Sawtooth(frequency, rate));
diff --git a/extern/audaspace/bindings/C/AUD_Sound.h b/extern/audaspace/bindings/C/AUD_Sound.h
index 53172616781..fc73a31e15c 100644
--- a/extern/audaspace/bindings/C/AUD_Sound.h
+++ b/extern/audaspace/bindings/C/AUD_Sound.h
@@ -36,7 +36,15 @@ extern AUD_API AUD_Specs AUD_Sound_getSpecs(AUD_Sound* sound);
* \return The length of the sound in samples.
* \note This function creates a reader from the sound and deletes it again.
*/
-extern AUD_API int AUD_getLength(AUD_Sound* sound);
+extern AUD_API int AUD_Sound_getLength(AUD_Sound* sound);
+
+/**
+ * Retrieves the stream infos of a sound file.
+ * \param sound The sound to retrieve from which must be a file sound.
+ * \param infos A pointer to a AUD_StreamInfo array that will be allocated and must afterwards be freed by the caller.
+ * \return The number of items in the infos array.
+ */
+extern AUD_API int AUD_Sound_getFileStreams(AUD_Sound* sound, AUD_StreamInfo** stream_infos);
/**
* Reads a sound's samples into memory.
@@ -90,6 +98,15 @@ extern AUD_API AUD_Sound* AUD_Sound_buffer(sample_t* data, int length, AUD_Specs
extern AUD_API AUD_Sound* AUD_Sound_bufferFile(unsigned char* buffer, int size);
/**
+ * Loads a sound file from a memory buffer.
+ * \param buffer The buffer which contains the sound file.
+ * \param size The size of the buffer.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
+ * \return A handle of the sound file.
+ */
+extern AUD_API AUD_Sound* AUD_Sound_bufferFileStream(unsigned char* buffer, int size, int stream);
+
+/**
* Caches a sound into a memory buffer.
* \param sound The sound to cache.
* \return A handle of the cached sound.
@@ -104,6 +121,14 @@ extern AUD_API AUD_Sound* AUD_Sound_cache(AUD_Sound* sound);
extern AUD_API AUD_Sound* AUD_Sound_file(const char* filename);
/**
+ * Loads a sound file.
+ * \param filename The filename of the sound file.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
+ * \return A handle of the sound file.
+ */
+extern AUD_API AUD_Sound* AUD_Sound_fileStream(const char* filename, int stream);
+
+/**
* Creates a sawtooth sound.
* \param frequency The frequency of the generated sawtooth sound.
* \param rate The sample rate of the sawtooth sound.
diff --git a/extern/audaspace/bindings/C/AUD_Special.cpp b/extern/audaspace/bindings/C/AUD_Special.cpp
index 5cc33525d1d..1ce25dcd41c 100644
--- a/extern/audaspace/bindings/C/AUD_Special.cpp
+++ b/extern/audaspace/bindings/C/AUD_Special.cpp
@@ -86,7 +86,6 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
info.specs.channels = AUD_CHANNELS_INVALID;
info.specs.rate = AUD_RATE_INVALID;
info.length = 0.0f;
- info.start_offset = 0.0f;
try
{
@@ -96,7 +95,6 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
{
info.specs = convSpecToC(reader->getSpecs());
info.length = reader->getLength() / (float) info.specs.rate;
- info.start_offset = reader->getStartOffset();
}
}
catch(Exception&)
@@ -109,7 +107,7 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float high,
float attack, float release, float threshold,
int accumulate, int additive, int square,
- float sthreshold, double samplerate, int* length)
+ float sthreshold, double samplerate, int* length, int stream)
{
Buffer buffer;
DeviceSpecs specs;
@@ -117,7 +115,7 @@ AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float high,
specs.rate = (SampleRate)samplerate;
std::shared_ptr<ISound> sound;
- std::shared_ptr<ISound> file = std::shared_ptr<ISound>(new File(filename));
+ std::shared_ptr<ISound> file = std::shared_ptr<ISound>(new File(filename, stream));
int position = 0;
@@ -247,7 +245,7 @@ AUD_API int AUD_readSound(AUD_Sound* sound, float* buffer, int length, int sampl
buffer[i * 3] = min;
buffer[i * 3 + 1] = max;
- buffer[i * 3 + 2] = sqrt(power / len); // RMS
+ buffer[i * 3 + 2] = std::sqrt(power / len);
if(overallmax < max)
overallmax = max;
diff --git a/extern/audaspace/bindings/C/AUD_Special.h b/extern/audaspace/bindings/C/AUD_Special.h
index ce51fa2e04e..2f5d13c6fd9 100644
--- a/extern/audaspace/bindings/C/AUD_Special.h
+++ b/extern/audaspace/bindings/C/AUD_Special.h
@@ -37,7 +37,7 @@ extern AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float
float attack, float release, float threshold,
int accumulate, int additive, int square,
float sthreshold, double samplerate,
- int* length);
+ int* length, int stream);
/**
* Pauses a playing sound after a specific amount of time.
diff --git a/extern/audaspace/bindings/C/AUD_Types.h b/extern/audaspace/bindings/C/AUD_Types.h
index c6a96d30d3f..0f95366bc27 100644
--- a/extern/audaspace/bindings/C/AUD_Types.h
+++ b/extern/audaspace/bindings/C/AUD_Types.h
@@ -176,5 +176,17 @@ typedef struct
{
AUD_Specs specs;
float length;
- double start_offset;
} AUD_SoundInfo;
+
+/// Specification of a sound source.
+typedef struct
+{
+ /// Start time in seconds.
+ double start;
+
+ /// Duration in seconds. May be estimated or 0 if unknown.
+ double duration;
+
+ /// Audio data parameters.
+ AUD_DeviceSpecs specs;
+} AUD_StreamInfo;
diff --git a/extern/audaspace/bindings/python/PySound.cpp b/extern/audaspace/bindings/python/PySound.cpp
index 33628307249..2236057e7d2 100644
--- a/extern/audaspace/bindings/python/PySound.cpp
+++ b/extern/audaspace/bindings/python/PySound.cpp
@@ -89,10 +89,11 @@ Sound_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
self = (Sound*)type->tp_alloc(type, 0);
if(self != nullptr)
{
- static const char* kwlist[] = {"filename", nullptr};
+ static const char* kwlist[] = {"filename", "stream", nullptr};
const char* filename = nullptr;
+ int stream = 0;
- if(!PyArg_ParseTupleAndKeywords(args, kwds, "s:Sound", const_cast<char**>(kwlist), &filename))
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "s|i:Sound", const_cast<char**>(kwlist), &filename, &stream))
{
Py_DECREF(self);
return nullptr;
@@ -100,7 +101,7 @@ Sound_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
try
{
- self->sound = new std::shared_ptr<ISound>(new File(filename));
+ self->sound = new std::shared_ptr<ISound>(new File(filename, stream));
}
catch(Exception& e)
{
@@ -407,8 +408,9 @@ static PyObject *
Sound_file(PyTypeObject* type, PyObject* args)
{
const char* filename = nullptr;
+ int stream = 0;
- if(!PyArg_ParseTuple(args, "s:file", &filename))
+ if(!PyArg_ParseTuple(args, "s|i:file", &filename, &stream))
return nullptr;
Sound* self;
@@ -418,7 +420,7 @@ Sound_file(PyTypeObject* type, PyObject* args)
{
try
{
- self->sound = new std::shared_ptr<ISound>(new File(filename));
+ self->sound = new std::shared_ptr<ISound>(new File(filename, stream));
}
catch(Exception& e)
{
diff --git a/extern/audaspace/include/IReader.h b/extern/audaspace/include/IReader.h
index f6070b0f23b..c29900ca579 100644
--- a/extern/audaspace/include/IReader.h
+++ b/extern/audaspace/include/IReader.h
@@ -71,12 +71,6 @@ public:
virtual int getPosition() const=0;
/**
- * Returns the start offset the sound should have to line up with related sources.
- * \return The required start offset in seconds.
- */
- virtual double getStartOffset() const { return 0.0;}
-
- /**
* Returns the specification of the reader.
* \return The Specs structure.
*/
diff --git a/extern/audaspace/include/file/File.h b/extern/audaspace/include/file/File.h
index 24745a757e8..ac490acba38 100644
--- a/extern/audaspace/include/file/File.h
+++ b/extern/audaspace/include/file/File.h
@@ -23,9 +23,11 @@
*/
#include "ISound.h"
+#include "FileInfo.h"
#include <string>
#include <memory>
+#include <vector>
AUD_NAMESPACE_BEGIN
@@ -48,6 +50,14 @@ private:
*/
std::shared_ptr<Buffer> m_buffer;
+ /**
+ * The index of the stream within the file if it contains multiple.
+ * The first audio stream in the file has index 0 and the index increments by one
+ * for every other audio stream in the file. Other types of streams in the file
+ * do not count.
+ */
+ int m_stream;
+
// delete copy constructor and operator=
File(const File&) = delete;
File& operator=(const File&) = delete;
@@ -57,16 +67,25 @@ public:
* Creates a new sound.
* The file is read from the file system using the given path.
* \param filename The sound file path.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
*/
- File(std::string filename);
+ File(std::string filename, int stream = 0);
/**
* Creates a new sound.
* The file is read from memory using the supplied buffer.
* \param buffer The buffer to read from.
* \param size The size of the buffer.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
+ */
+ File(const data_t* buffer, int size, int stream = 0);
+
+ /**
+ * Queries the streams of the file.
+ * \return A vector with as many streams as there are in the file.
+ * \exception Exception Thrown if the file specified cannot be read.
*/
- File(const data_t* buffer, int size);
+ std::vector<StreamInfo> queryStreams();
virtual std::shared_ptr<IReader> createReader();
};
diff --git a/extern/audaspace/include/file/FileInfo.h b/extern/audaspace/include/file/FileInfo.h
new file mode 100644
index 00000000000..53ba99a5f67
--- /dev/null
+++ b/extern/audaspace/include/file/FileInfo.h
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+/**
+ * @file FileInfo.h
+ * @ingroup file
+ * The FileInfo data structures.
+ */
+
+#include "respec/Specification.h"
+
+AUD_NAMESPACE_BEGIN
+
+/// Specification of a sound source.
+struct StreamInfo
+{
+ /// Start time in seconds.
+ double start;
+
+ /// Duration in seconds. May be estimated or 0 if unknown.
+ double duration;
+
+ /// Audio data parameters.
+ DeviceSpecs specs;
+};
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/include/file/FileManager.h b/extern/audaspace/include/file/FileManager.h
index 56708607ea6..e19eef65b1c 100644
--- a/extern/audaspace/include/file/FileManager.h
+++ b/extern/audaspace/include/file/FileManager.h
@@ -22,12 +22,14 @@
* The FileManager class.
*/
+#include "FileInfo.h"
#include "respec/Specification.h"
#include "IWriter.h"
#include <list>
#include <memory>
#include <string>
+#include <vector>
AUD_NAMESPACE_BEGIN
@@ -66,18 +68,36 @@ public:
/**
* Creates a file reader for the given filename if a registed IFileInput is able to read it.
* @param filename The path to the file.
+ * @param stream The index of the audio stream within the file if it contains multiple audio streams.
* @return The reader created.
* @exception Exception If no file input can read the file an exception is thrown.
*/
- static std::shared_ptr<IReader> createReader(std::string filename);
+ static std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
/**
* Creates a file reader for the given buffer if a registed IFileInput is able to read it.
* @param buffer The buffer to read the file from.
+ * @param stream The index of the audio stream within the file if it contains multiple audio streams.
* @return The reader created.
* @exception Exception If no file input can read the file an exception is thrown.
*/
- static std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
+ static std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
+
+ /**
+ * Queries the streams of a sound file.
+ * \param filename Path to the file to be read.
+ * \return A vector with as many streams as there are in the file.
+ * \exception Exception Thrown if the file specified cannot be read.
+ */
+ static std::vector<StreamInfo> queryStreams(std::string filename);
+
+ /**
+ * Queries the streams of a sound file.
+ * \param buffer The in-memory file buffer.
+ * \return A vector with as many streams as there are in the file.
+ * \exception Exception Thrown if the file specified cannot be read.
+ */
+ static std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
/**
* Creates a file writer that writes a sound to the given file path.
diff --git a/extern/audaspace/include/file/IFileInput.h b/extern/audaspace/include/file/IFileInput.h
index 64074910d13..4a3fe446852 100644
--- a/extern/audaspace/include/file/IFileInput.h
+++ b/extern/audaspace/include/file/IFileInput.h
@@ -23,9 +23,11 @@
*/
#include "Audaspace.h"
+#include "FileInfo.h"
#include <memory>
#include <string>
+#include <vector>
AUD_NAMESPACE_BEGIN
@@ -48,18 +50,36 @@ public:
/**
* Creates a reader for a file to be read.
* \param filename Path to the file to be read.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \return The reader that reads the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
- virtual std::shared_ptr<IReader> createReader(std::string filename)=0;
+ virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0)=0;
/**
* Creates a reader for a file to be read from memory.
* \param buffer The in-memory file buffer.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \return The reader that reads the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
- virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer)=0;
+ virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0)=0;
+
+ /**
+ * Queries the streams of a sound file.
+ * \param filename Path to the file to be read.
+ * \return A vector with as many streams as there are in the file.
+ * \exception Exception Thrown if the file specified cannot be read.
+ */
+ virtual std::vector<StreamInfo> queryStreams(std::string filename)=0;
+
+ /**
+ * Queries the streams of a sound file.
+ * \param buffer The in-memory file buffer.
+ * \return A vector with as many streams as there are in the file.
+ * \exception Exception Thrown if the file specified cannot be read.
+ */
+ virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer)=0;
};
AUD_NAMESPACE_END
diff --git a/extern/audaspace/include/fx/VolumeReader.h b/extern/audaspace/include/fx/VolumeReader.h
index f7169f4c78b..13b6845e931 100644
--- a/extern/audaspace/include/fx/VolumeReader.h
+++ b/extern/audaspace/include/fx/VolumeReader.h
@@ -67,4 +67,4 @@ public:
virtual void read(int& length, bool& eos, sample_t* buffer);
};
-AUD_NAMESPACE_END
+AUD_NAMESPACE_END \ No newline at end of file
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
index 3ffe963b2b9..07c0fee691a 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
@@ -35,14 +35,24 @@ void FFMPEG::registerPlugin()
FileManager::registerOutput(plugin);
}
-std::shared_ptr<IReader> FFMPEG::createReader(std::string filename)
+std::shared_ptr<IReader> FFMPEG::createReader(std::string filename, int stream)
{
- return std::shared_ptr<IReader>(new FFMPEGReader(filename));
+ return std::shared_ptr<IReader>(new FFMPEGReader(filename, stream));
}
-std::shared_ptr<IReader> FFMPEG::createReader(std::shared_ptr<Buffer> buffer)
+std::shared_ptr<IReader> FFMPEG::createReader(std::shared_ptr<Buffer> buffer, int stream)
{
- return std::shared_ptr<IReader>(new FFMPEGReader(buffer));
+ return std::shared_ptr<IReader>(new FFMPEGReader(buffer, stream));
+}
+
+std::vector<StreamInfo> FFMPEG::queryStreams(std::string filename)
+{
+ return FFMPEGReader(filename).queryStreams();
+}
+
+std::vector<StreamInfo> FFMPEG::queryStreams(std::shared_ptr<Buffer> buffer)
+{
+ return FFMPEGReader(buffer).queryStreams();
}
std::shared_ptr<IWriter> FFMPEG::createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEG.h b/extern/audaspace/plugins/ffmpeg/FFMPEG.h
index 108ba547e0f..fb40ba05573 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEG.h
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEG.h
@@ -52,8 +52,10 @@ public:
*/
static void registerPlugin();
- virtual std::shared_ptr<IReader> createReader(std::string filename);
- virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
+ virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
+ virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
+ virtual std::vector<StreamInfo> queryStreams(std::string filename);
+ virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
virtual std::shared_ptr<IWriter> createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate);
};
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
index afdc7fcfcc6..de3ca099696 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
@@ -31,6 +31,25 @@ AUD_NAMESPACE_BEGIN
#define FFMPEG_OLD_CODE
#endif
+SampleFormat FFMPEGReader::convertSampleFormat(AVSampleFormat format)
+{
+ switch(av_get_packed_sample_fmt(format))
+ {
+ case AV_SAMPLE_FMT_U8:
+ return FORMAT_U8;
+ case AV_SAMPLE_FMT_S16:
+ return FORMAT_S16;
+ case AV_SAMPLE_FMT_S32:
+ return FORMAT_S32;
+ case AV_SAMPLE_FMT_FLT:
+ return FORMAT_FLOAT32;
+ case AV_SAMPLE_FMT_DBL:
+ return FORMAT_FLOAT64;
+ default:
+ AUD_THROW(FileException, "FFMPEG sample format unknown.");
+ }
+}
+
int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
{
int buf_size = buffer.getSize();
@@ -68,7 +87,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
- m_frame->data[channel] + i * single_size, single_size);
+ m_frame->data[channel] + i * single_size, single_size);
}
}
}
@@ -109,7 +128,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
- m_frame->data[channel] + i * single_size, single_size);
+ m_frame->data[channel] + i * single_size, single_size);
}
}
}
@@ -123,13 +142,10 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
return buf_pos;
}
-void FFMPEGReader::init()
+void FFMPEGReader::init(int stream)
{
m_position = 0;
- m_start_offset = 0.0f;
m_pkgbuf_left = 0;
- m_st_time = 0;
- m_duration = 0;
if(avformat_find_stream_info(m_formatCtx, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be read, ffmpeg couldn't find the stream info.");
@@ -137,43 +153,22 @@ void FFMPEGReader::init()
// find audio stream and codec
m_stream = -1;
- double dur_sec = 0;
-
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
{
#ifdef FFMPEG_OLD_CODE
- if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
#else
- if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+ if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
#endif
+ && (m_stream < 0))
{
- AVStream *audio_stream = m_formatCtx->streams[i];
- double audio_timebase = av_q2d(audio_stream->time_base);
-
- if (audio_stream->start_time != AV_NOPTS_VALUE)
+ if(stream == 0)
{
- m_st_time = audio_stream->start_time;
- }
-
- int64_t ctx_start_time = 0;
- if (m_formatCtx->start_time != AV_NOPTS_VALUE) {
- ctx_start_time = m_formatCtx->start_time;
- }
-
- m_start_offset = m_st_time * audio_timebase - (double)ctx_start_time / AV_TIME_BASE;
-
- if(audio_stream->duration != AV_NOPTS_VALUE)
- {
- dur_sec = audio_stream->duration * audio_timebase;
+ m_stream=i;
+ break;
}
else
- {
- /* If the audio starts after the stream start time, subract this from the total duration. */
- dur_sec = (double)m_formatCtx->duration / AV_TIME_BASE - m_start_offset;
- }
-
- m_stream=i;
- break;
+ stream--;
}
}
@@ -242,10 +237,9 @@ void FFMPEGReader::init()
}
m_specs.rate = (SampleRate) m_codecCtx->sample_rate;
- m_duration = lround(dur_sec * m_codecCtx->sample_rate);
}
-FFMPEGReader::FFMPEGReader(std::string filename) :
+FFMPEGReader::FFMPEGReader(std::string filename, int stream) :
m_pkgbuf(),
m_formatCtx(nullptr),
m_codecCtx(nullptr),
@@ -259,7 +253,7 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
try
{
- init();
+ init(stream);
}
catch(Exception&)
{
@@ -268,7 +262,7 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
}
}
-FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
+FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer, int stream) :
m_pkgbuf(),
m_codecCtx(nullptr),
m_frame(nullptr),
@@ -295,7 +289,7 @@ FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
try
{
- init();
+ init(stream);
}
catch(Exception&)
{
@@ -318,6 +312,51 @@ FFMPEGReader::~FFMPEGReader()
avformat_close_input(&m_formatCtx);
}
+std::vector<StreamInfo> FFMPEGReader::queryStreams()
+{
+ std::vector<StreamInfo> result;
+
+ for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
+ {
+#ifdef FFMPEG_OLD_CODE
+ if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+#else
+ if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+#endif
+ {
+ StreamInfo info;
+
+ double time_base = av_q2d(m_formatCtx->streams[i]->time_base);
+
+ if(m_formatCtx->streams[i]->start_time != AV_NOPTS_VALUE)
+ info.start = m_formatCtx->streams[i]->start_time * time_base;
+ else
+ info.start = 0;
+
+ if(m_formatCtx->streams[i]->duration != AV_NOPTS_VALUE)
+ info.duration = m_formatCtx->streams[i]->duration * time_base;
+ else if(m_formatCtx->duration != AV_NOPTS_VALUE)
+ info.duration = double(m_formatCtx->duration) / AV_TIME_BASE - info.start;
+ else
+ info.duration = 0;
+
+#ifdef FFMPEG_OLD_CODE
+ info.specs.channels = Channels(m_formatCtx->streams[i]->codec->channels);
+ info.specs.rate = m_formatCtx->streams[i]->codec->sample_rate;
+ info.specs.format = convertSampleFormat(m_formatCtx->streams[i]->codec->sample_fmt);
+#else
+ info.specs.channels = Channels(m_formatCtx->streams[i]->codecpar->channels);
+ info.specs.rate = m_formatCtx->streams[i]->codecpar->sample_rate;
+ info.specs.format = convertSampleFormat(AVSampleFormat(m_formatCtx->streams[i]->codecpar->format));
+#endif
+
+ result.emplace_back(info);
+ }
+ }
+
+ return result;
+}
+
int FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size)
{
FFMPEGReader* reader = reinterpret_cast<FFMPEGReader*>(opaque);
@@ -368,18 +407,16 @@ void FFMPEGReader::seek(int position)
{
if(position >= 0)
{
- double pts_time_base =
- av_q2d(m_formatCtx->streams[m_stream]->time_base);
+ double pts_time_base = av_q2d(m_formatCtx->streams[m_stream]->time_base);
- uint64_t seek_pts = (((uint64_t)position) / ((uint64_t)m_specs.rate)) / pts_time_base;
+ uint64_t st_time = m_formatCtx->streams[m_stream]->start_time;
+ uint64_t seek_pos = (uint64_t)(position / (pts_time_base * m_specs.rate));
- if(m_st_time != AV_NOPTS_VALUE) {
- seek_pts += m_st_time;
- }
+ if(st_time != AV_NOPTS_VALUE)
+ seek_pos += st_time;
// a value < 0 tells us that seeking failed
- if(av_seek_frame(m_formatCtx, m_stream, seek_pts,
- AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
+ if(av_seek_frame(m_formatCtx, m_stream, seek_pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
{
avcodec_flush_buffers(m_codecCtx);
m_position = position;
@@ -400,7 +437,7 @@ void FFMPEGReader::seek(int position)
if(packet.pts != AV_NOPTS_VALUE)
{
// calculate real position, and read to frame!
- m_position = (packet.pts - m_st_time) * pts_time_base * m_specs.rate;
+ m_position = (packet.pts - (st_time != AV_NOPTS_VALUE ? st_time : 0)) * pts_time_base * m_specs.rate;
if(m_position < position)
{
@@ -430,8 +467,25 @@ void FFMPEGReader::seek(int position)
int FFMPEGReader::getLength() const
{
+ auto stream = m_formatCtx->streams[m_stream];
+
+ double time_base = av_q2d(stream->time_base);
+ double duration;
+
+ if(stream->duration != AV_NOPTS_VALUE)
+ duration = stream->duration * time_base;
+ else if(m_formatCtx->duration != AV_NOPTS_VALUE)
+ {
+ duration = float(m_formatCtx->duration) / AV_TIME_BASE;
+
+ if(stream->start_time != AV_NOPTS_VALUE)
+ duration -= stream->start_time * time_base;
+ }
+ else
+ duration = -1;
+
// return approximated remaning size
- return m_duration - m_position;
+ return (int)(duration * m_codecCtx->sample_rate) - m_position;
}
int FFMPEGReader::getPosition() const
@@ -439,11 +493,6 @@ int FFMPEGReader::getPosition() const
return m_position;
}
-double FFMPEGReader::getStartOffset() const
-{
- return m_start_offset;
-}
-
Specs FFMPEGReader::getSpecs() const
{
return m_specs.specs;
@@ -480,13 +529,11 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
// decode the package
pkgbuf_pos = decode(packet, m_pkgbuf);
- if (packet.pts >= m_st_time) {
- // copy to output buffer
- data_size = std::min(pkgbuf_pos, left * sample_size);
- m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
- buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
- left -= data_size / sample_size;
- }
+ // copy to output buffer
+ data_size = std::min(pkgbuf_pos, left * sample_size);
+ m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
+ buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
+ left -= data_size / sample_size;
}
av_packet_unref(&packet);
}
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
index d613457c220..70f13911eca 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
@@ -29,9 +29,11 @@
#include "respec/ConverterFunctions.h"
#include "IReader.h"
#include "util/Buffer.h"
+#include "file/FileInfo.h"
#include <string>
#include <memory>
+#include <vector>
struct AVCodecContext;
extern "C" {
@@ -55,22 +57,6 @@ private:
int m_position;
/**
- * The start offset in seconds relative to the media container start time.
- * IE how much the sound should be delayed to be kept in sync with the rest of the containter streams.
- */
- double m_start_offset;
-
- /**
- * The start time pts of the stream. All packets before this timestamp shouldn't be played back (only decoded).
- */
- int64_t m_st_time;
-
- /**
- * The duration of the audio stream in samples.
- */
- int64_t m_duration;
-
- /**
* The specification of the audio data.
*/
DeviceSpecs m_specs;
@@ -136,6 +122,13 @@ private:
bool m_tointerleave;
/**
+ * Converts an ffmpeg sample format to an audaspace one.
+ * \param format The AVSampleFormat sample format.
+ * \return The sample format as SampleFormat.
+ */
+ AUD_LOCAL static SampleFormat convertSampleFormat(AVSampleFormat format);
+
+ /**
* Decodes a packet into the given buffer.
* \param packet The AVPacket to decode.
* \param buffer The target buffer.
@@ -145,8 +138,9 @@ private:
/**
* Initializes the object.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
*/
- AUD_LOCAL void init();
+ AUD_LOCAL void init(int stream);
// delete copy constructor and operator=
FFMPEGReader(const FFMPEGReader&) = delete;
@@ -156,18 +150,20 @@ public:
/**
* Creates a new reader.
* \param filename The path to the file to be read.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the file specified does not exist or
* cannot be read with ffmpeg.
*/
- FFMPEGReader(std::string filename);
+ FFMPEGReader(std::string filename, int stream = 0);
/**
* Creates a new reader.
* \param buffer The buffer to read from.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the buffer specified cannot be read
* with ffmpeg.
*/
- FFMPEGReader(std::shared_ptr<Buffer> buffer);
+ FFMPEGReader(std::shared_ptr<Buffer> buffer, int stream = 0);
/**
* Destroys the reader and closes the file.
@@ -175,6 +171,13 @@ public:
virtual ~FFMPEGReader();
/**
+ * Queries the streams of a sound file.
+ * \return A vector with as many streams as there are in the file.
+ * \exception Exception Thrown if the file specified cannot be read.
+ */
+ virtual std::vector<StreamInfo> queryStreams();
+
+ /**
* Reads data to a memory buffer.
* This function is used for avio only.
* @param opaque The FFMPEGReader.
@@ -198,7 +201,6 @@ public:
virtual void seek(int position);
virtual int getLength() const;
virtual int getPosition() const;
- virtual double getStartOffset() const;
virtual Specs getSpecs() const;
virtual void read(int& length, bool& eos, sample_t* buffer);
};
diff --git a/extern/audaspace/plugins/libsndfile/SndFile.cpp b/extern/audaspace/plugins/libsndfile/SndFile.cpp
index ba4ff24ad68..39335de9a1a 100644
--- a/extern/audaspace/plugins/libsndfile/SndFile.cpp
+++ b/extern/audaspace/plugins/libsndfile/SndFile.cpp
@@ -32,16 +32,26 @@ void SndFile::registerPlugin()
FileManager::registerOutput(plugin);
}
-std::shared_ptr<IReader> SndFile::createReader(std::string filename)
+std::shared_ptr<IReader> SndFile::createReader(std::string filename, int stream)
{
return std::shared_ptr<IReader>(new SndFileReader(filename));
}
-std::shared_ptr<IReader> SndFile::createReader(std::shared_ptr<Buffer> buffer)
+std::shared_ptr<IReader> SndFile::createReader(std::shared_ptr<Buffer> buffer, int stream)
{
return std::shared_ptr<IReader>(new SndFileReader(buffer));
}
+std::vector<StreamInfo> SndFile::queryStreams(std::string filename)
+{
+ return SndFileReader(filename).queryStreams();
+}
+
+std::vector<StreamInfo> SndFile::queryStreams(std::shared_ptr<Buffer> buffer)
+{
+ return SndFileReader(buffer).queryStreams();
+}
+
std::shared_ptr<IWriter> SndFile::createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)
{
return std::shared_ptr<IWriter>(new SndFileWriter(filename, specs, format, codec, bitrate));
diff --git a/extern/audaspace/plugins/libsndfile/SndFile.h b/extern/audaspace/plugins/libsndfile/SndFile.h
index 61afed1d564..10a7391180f 100644
--- a/extern/audaspace/plugins/libsndfile/SndFile.h
+++ b/extern/audaspace/plugins/libsndfile/SndFile.h
@@ -52,8 +52,10 @@ public:
*/
static void registerPlugin();
- virtual std::shared_ptr<IReader> createReader(std::string filename);
- virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
+ virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
+ virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
+ virtual std::vector<StreamInfo> queryStreams(std::string filename);
+ virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
virtual std::shared_ptr<IWriter> createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate);
};
diff --git a/extern/audaspace/plugins/libsndfile/SndFileReader.cpp b/extern/audaspace/plugins/libsndfile/SndFileReader.cpp
index d2d89814c07..21c733d8117 100644
--- a/extern/audaspace/plugins/libsndfile/SndFileReader.cpp
+++ b/extern/audaspace/plugins/libsndfile/SndFileReader.cpp
@@ -118,6 +118,21 @@ SndFileReader::~SndFileReader()
sf_close(m_sndfile);
}
+std::vector<StreamInfo> SndFileReader::queryStreams()
+{
+ std::vector<StreamInfo> result;
+
+ StreamInfo info;
+ info.start = 0;
+ info.duration = double(getLength()) / m_specs.rate;
+ info.specs.specs = m_specs;
+ info.specs.format = FORMAT_FLOAT32;
+
+ result.emplace_back(info);
+
+ return result;
+}
+
bool SndFileReader::isSeekable() const
{
return m_seekable;
diff --git a/extern/audaspace/plugins/libsndfile/SndFileReader.h b/extern/audaspace/plugins/libsndfile/SndFileReader.h
index 081c29c686c..b4158d9091a 100644
--- a/extern/audaspace/plugins/libsndfile/SndFileReader.h
+++ b/extern/audaspace/plugins/libsndfile/SndFileReader.h
@@ -28,9 +28,12 @@
* The SndFileReader class.
*/
+#include "file/FileInfo.h"
+
#include <string>
#include <sndfile.h>
#include <memory>
+#include <vector>
AUD_NAMESPACE_BEGIN
@@ -96,6 +99,7 @@ public:
/**
* Creates a new reader.
* \param filename The path to the file to be read.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the file specified does not exist or
* cannot be read with libsndfile.
*/
@@ -104,6 +108,7 @@ public:
/**
* Creates a new reader.
* \param buffer The buffer to read from.
+ * \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the buffer specified cannot be read
* with libsndfile.
*/
@@ -114,6 +119,13 @@ public:
*/
virtual ~SndFileReader();
+ /**
+ * Queries the streams of a sound file.
+ * \return A vector with as many streams as there are in the file.
+ * \exception Exception Thrown if the file specified cannot be read.
+ */
+ virtual std::vector<StreamInfo> queryStreams();
+
virtual bool isSeekable() const;
virtual void seek(int position);
virtual int getLength() const;
diff --git a/extern/audaspace/src/file/File.cpp b/extern/audaspace/src/file/File.cpp
index 0cdecb03657..5d4bae482d6 100644
--- a/extern/audaspace/src/file/File.cpp
+++ b/extern/audaspace/src/file/File.cpp
@@ -23,23 +23,31 @@
AUD_NAMESPACE_BEGIN
-File::File(std::string filename) :
- m_filename(filename)
+File::File(std::string filename, int stream) :
+ m_filename(filename), m_stream(stream)
{
}
-File::File(const data_t* buffer, int size) :
- m_buffer(new Buffer(size))
+File::File(const data_t* buffer, int size, int stream) :
+ m_buffer(new Buffer(size)), m_stream(stream)
{
std::memcpy(m_buffer->getBuffer(), buffer, size);
}
+std::vector<StreamInfo> File::queryStreams()
+{
+ if(m_buffer.get())
+ return FileManager::queryStreams(m_buffer);
+ else
+ return FileManager::queryStreams(m_filename);
+}
+
std::shared_ptr<IReader> File::createReader()
{
if(m_buffer.get())
- return FileManager::createReader(m_buffer);
+ return FileManager::createReader(m_buffer, m_stream);
else
- return FileManager::createReader(m_filename);
+ return FileManager::createReader(m_filename, m_stream);
}
AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/file/FileManager.cpp b/extern/audaspace/src/file/FileManager.cpp
index f8ef8deb409..7cbc0318f8c 100644
--- a/extern/audaspace/src/file/FileManager.cpp
+++ b/extern/audaspace/src/file/FileManager.cpp
@@ -43,13 +43,13 @@ void FileManager::registerOutput(std::shared_ptr<aud::IFileOutput> output)
outputs().push_back(output);
}
-std::shared_ptr<IReader> FileManager::createReader(std::string filename)
+std::shared_ptr<IReader> FileManager::createReader(std::string filename, int stream)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
- return input->createReader(filename);
+ return input->createReader(filename, stream);
}
catch(Exception&) {}
}
@@ -57,13 +57,41 @@ std::shared_ptr<IReader> FileManager::createReader(std::string filename)
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
}
-std::shared_ptr<IReader> FileManager::createReader(std::shared_ptr<Buffer> buffer)
+std::shared_ptr<IReader> FileManager::createReader(std::shared_ptr<Buffer> buffer, int stream)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
- return input->createReader(buffer);
+ return input->createReader(buffer, stream);
+ }
+ catch(Exception&) {}
+ }
+
+ AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
+}
+
+std::vector<StreamInfo> FileManager::queryStreams(std::string filename)
+{
+ for(std::shared_ptr<IFileInput> input : inputs())
+ {
+ try
+ {
+ return input->queryStreams(filename);
+ }
+ catch(Exception&) {}
+ }
+
+ AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
+}
+
+std::vector<StreamInfo> FileManager::queryStreams(std::shared_ptr<Buffer> buffer)
+{
+ for(std::shared_ptr<IFileInput> input : inputs())
+ {
+ try
+ {
+ return input->queryStreams(buffer);
}
catch(Exception&) {}
}
diff --git a/extern/audaspace/src/fx/VolumeReader.cpp b/extern/audaspace/src/fx/VolumeReader.cpp
index 627acbac9ef..ac1d4882a87 100644
--- a/extern/audaspace/src/fx/VolumeReader.cpp
+++ b/extern/audaspace/src/fx/VolumeReader.cpp
@@ -57,4 +57,4 @@ void VolumeReader::read(int& length, bool& eos, sample_t* buffer)
buffer[i] = buffer[i] * m_volumeStorage->getVolume();
}
-AUD_NAMESPACE_END
+AUD_NAMESPACE_END \ No newline at end of file
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index fa58813c5f8..8796e2c18f3 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -96,13 +96,24 @@ typedef struct SoundInfo {
eSoundChannels channels;
} specs;
float length;
- double start_offset;
} SoundInfo;
+typedef struct SoundStreamInfo {
+ double duration;
+ double start;
+} SoundStreamInfo;
+
/* Get information about given sound. Returns truth on success., false if sound can not be loaded
* or if the codes is not supported. */
bool BKE_sound_info_get(struct Main *main, struct bSound *sound, SoundInfo *sound_info);
+/* Get information about given sound. Returns truth on success., false if sound can not be loaded
+ * or if the codes is not supported. */
+bool BKE_sound_stream_info_get(struct Main *main,
+ const char *filepath,
+ int stream,
+ SoundStreamInfo *sound_info);
+
#if defined(WITH_AUDASPACE)
AUD_Device *BKE_sound_mixdown(const struct Scene *scene,
AUD_DeviceSpecs specs,
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index c61fa793367..ccb10f080e3 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -1213,7 +1213,6 @@ static bool sound_info_from_playback_handle(void *playback_handle, SoundInfo *so
AUD_SoundInfo info = AUD_getInfo(playback_handle);
sound_info->specs.channels = (eSoundChannels)info.specs.channels;
sound_info->length = info.length;
- sound_info->start_offset = info.start_offset;
return true;
}
@@ -1231,6 +1230,44 @@ bool BKE_sound_info_get(struct Main *main, struct bSound *sound, SoundInfo *soun
return result;
}
+bool BKE_sound_stream_info_get(struct Main *main, const char *filepath, int stream, SoundStreamInfo *sound_info)
+{
+ const char *path;
+ char str[FILE_MAX];
+ AUD_Sound *sound;
+ AUD_StreamInfo *stream_infos;
+ int stream_count;
+
+ BLI_strncpy(str, filepath, sizeof(str));
+ path = BKE_main_blendfile_path(main);
+ BLI_path_abs(str, path);
+
+ sound = AUD_Sound_file(str);
+ if (!sound) {
+ return false;
+ }
+
+ stream_count = AUD_Sound_getFileStreams(sound, &stream_infos);
+
+ AUD_Sound_free(sound);
+
+ if (!stream_infos) {
+ return false;
+ }
+
+ if ((stream < 0) || (stream >= stream_count)) {
+ free(stream_infos);
+ return false;
+ }
+
+ sound_info->start = stream_infos[stream].start;
+ sound_info->duration = stream_infos[stream].duration;
+
+ free(stream_infos);
+
+ return true;
+}
+
#else /* WITH_AUDASPACE */
# include "BLI_utildefines.h"
@@ -1400,6 +1437,14 @@ bool BKE_sound_info_get(struct Main *UNUSED(main),
return false;
}
+bool BKE_sound_stream_info_get(struct Main *UNUSED(main),
+ const char *UNUSED(filepath),
+ int UNUSED(stream),
+ SoundStreamInfo *UNUSED(sound_info))
+{
+ return false;
+}
+
#endif /* WITH_AUDASPACE */
void BKE_sound_reset_scene_runtime(Scene *scene)
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 2955c4ef7ae..872b17372de 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -1098,7 +1098,8 @@ static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op)
RNA_boolean_get(op->ptr, "use_square"),
RNA_float_get(op->ptr, "sthreshold"),
FPS,
- &sbi.length);
+ &sbi.length,
+ 0);
if (sbi.samples == NULL) {
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 081f0241e94..bdfa639b327 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -47,6 +47,7 @@
#include "BKE_mask.h"
#include "BKE_movieclip.h"
#include "BKE_report.h"
+#include "BKE_sound.h"
#include "IMB_imbuf.h"
@@ -643,7 +644,15 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
BLI_strncpy(load_data->name, file_only, sizeof(load_data->name));
Sequence *seq_movie = NULL;
Sequence *seq_sound = NULL;
- double video_start_offset;
+ double video_start_offset = -1;
+ double audio_start_offset = 0;
+
+ if (RNA_boolean_get(op->ptr, "sound")) {
+ SoundStreamInfo sound_info;
+ if (BKE_sound_stream_info_get(bmain, load_data->path, 0, &sound_info)) {
+ audio_start_offset = video_start_offset = sound_info.start;
+ }
+ }
load_data->channel++;
seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data, &video_start_offset);
@@ -653,9 +662,30 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
}
else {
if (RNA_boolean_get(op->ptr, "sound")) {
- seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, video_start_offset);
+ int minimum_frame_offset = MIN2(video_start_offset, audio_start_offset) * FPS;
+
+ int video_frame_offset = video_start_offset * FPS;
+ int audio_frame_offset = audio_start_offset * FPS;
+
+ double video_frame_remainder = video_start_offset * FPS - video_frame_offset;
+ double audio_frame_remainder = audio_start_offset * FPS - audio_frame_offset;
+
+ double audio_skip = (video_frame_remainder - audio_frame_remainder) / FPS;
+
+ video_frame_offset -= minimum_frame_offset;
+ audio_frame_offset -= minimum_frame_offset;
+
+ load_data->start_frame += audio_frame_offset;
+ seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip);
+
+ int min_startdisp = MIN2(seq_movie->startdisp, seq_sound->startdisp);
+ int max_enddisp = MAX2(seq_movie->enddisp, seq_sound->enddisp);
+
+ load_data->start_frame += max_enddisp - min_startdisp - audio_frame_offset;
+ }
+ else {
+ load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
}
- load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
seq_build_proxy(C, seq_movie);
@@ -672,7 +702,15 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
Sequence *seq_movie = NULL;
Sequence *seq_sound = NULL;
- double video_start_offset;
+ double video_start_offset = -1;
+ double audio_start_offset = 0;
+
+ if (RNA_boolean_get(op->ptr, "sound")) {
+ SoundStreamInfo sound_info;
+ if (BKE_sound_stream_info_get(bmain, load_data->path, 0, &sound_info)) {
+ audio_start_offset = video_start_offset = sound_info.start;
+ }
+ }
load_data->channel++;
seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data, &video_start_offset);
@@ -683,7 +721,21 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
return false;
}
if (RNA_boolean_get(op->ptr, "sound")) {
- seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, video_start_offset);
+ int minimum_frame_offset = MIN2(video_start_offset, audio_start_offset) * FPS;
+
+ int video_frame_offset = video_start_offset * FPS;
+ int audio_frame_offset = audio_start_offset * FPS;
+
+ double video_frame_remainder = video_start_offset * FPS - video_frame_offset;
+ double audio_frame_remainder = audio_start_offset * FPS - audio_frame_offset;
+
+ double audio_skip = (video_frame_remainder - audio_frame_remainder) / FPS;
+
+ video_frame_offset -= minimum_frame_offset;
+ audio_frame_offset -= minimum_frame_offset;
+
+ load_data->start_frame += audio_frame_offset;
+ seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip);
}
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index b56ad48cec2..bf817005a08 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -420,6 +420,10 @@ static void draw_seq_waveform_overlay(View2D *v2d,
float sample_offset = start_sample + i * samples_per_pix;
int p = sample_offset;
+ if (p < 0) {
+ continue;
+ }
+
if (p >= waveform->length) {
break;
}
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index dbca16ca82b..13f9356751e 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -664,11 +664,6 @@ static int startffmpeg(struct anim *anim)
anim->duration_in_frames = (int)(stream_dur * av_q2d(frame_rate) + 0.5f);
}
- double ctx_start = 0;
- if (pFormatCtx->start_time != AV_NOPTS_VALUE) {
- ctx_start = (double)pFormatCtx->start_time / AV_TIME_BASE;
- }
-
frs_num = frame_rate.num;
frs_den = frame_rate.den;
@@ -683,7 +678,7 @@ static int startffmpeg(struct anim *anim)
anim->frs_sec_base = frs_den;
/* Save the relative start time for the video. IE the start time in relation to where playback
* starts. */
- anim->start_offset = video_start - ctx_start;
+ anim->start_offset = video_start;
anim->params = 0;
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index a0564d3435b..b43b57a35be 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -323,8 +323,8 @@ static Sequence *rna_Sequences_new_movie(ID *id,
SEQ_add_load_data_init(&load_data, name, file, frame_start, channel);
load_data.fit_method = fit_method;
load_data.allow_invalid_file = true;
- double video_start_offset;
- Sequence *seq = SEQ_add_movie_strip(bmain, scene, seqbase, &load_data, &video_start_offset);
+ double start_offset = -1;
+ Sequence *seq = SEQ_add_movie_strip(bmain, scene, seqbase, &load_data, &start_offset);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h
index 4025f1a4a04..d2a731d9953 100644
--- a/source/blender/sequencer/SEQ_add.h
+++ b/source/blender/sequencer/SEQ_add.h
@@ -88,7 +88,7 @@ struct Sequence *SEQ_add_movie_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data,
- double *r_video_start_offset);
+ double *r_start_offset);
struct Sequence *SEQ_add_scene_strip(struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data);
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index 9081c655d2f..3cf7a4ebf4d 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -403,26 +403,8 @@ Sequence *SEQ_add_sound_strip(Main *bmain,
return NULL;
}
- /* If this sound it part of a video, then the sound might start after the video.
- * In this case we need to then offset the start frame of the audio so it syncs up
- * properly with the video.
- */
- int start_frame_offset = info.start_offset * FPS;
- double start_frame_offset_remainer = (info.start_offset * FPS - start_frame_offset) / FPS;
-
- if (start_frame_offset_remainer > FLT_EPSILON) {
- /* We can't represent a fraction of a frame, so skip the first frame fraction of sound so we
- * start on a "whole" frame.
- */
- start_frame_offset++;
- }
-
- sound->offset_time += start_frame_offset_remainer;
-
- Sequence *seq = SEQ_sequence_alloc(seqbase,
- load_data->start_frame + start_frame_offset,
- load_data->channel,
- SEQ_TYPE_SOUND_RAM);
+ Sequence *seq = SEQ_sequence_alloc(
+ seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SOUND_RAM);
seq->sound = sound;
seq->scene_sound = NULL;
@@ -508,7 +490,7 @@ Sequence *SEQ_add_movie_strip(Main *bmain,
Scene *scene,
ListBase *seqbase,
SeqLoadData *load_data,
- double *r_video_start_offset)
+ double *r_start_offset)
{
char path[sizeof(load_data->path)];
BLI_strncpy(path, load_data->path, sizeof(path));
@@ -554,8 +536,40 @@ Sequence *SEQ_add_movie_strip(Main *bmain,
return NULL;
}
+ int video_frame_offset = 0;
+ float video_fps = 0.0f;
+
+ if (anim_arr[0] != NULL) {
+ short fps_denom;
+ float fps_num;
+
+ IMB_anim_get_fps(anim_arr[0], &fps_denom, &fps_num, true);
+
+ video_fps = fps_denom / fps_num;
+
+ /* Adjust scene's frame rate settings to match. */
+ if (load_data->flags & SEQ_LOAD_MOVIE_SYNC_FPS) {
+ scene->r.frs_sec = fps_denom;
+ scene->r.frs_sec_base = fps_num;
+ }
+
+ double video_start_offset = IMD_anim_get_offset(anim_arr[0]);
+ int minimum_frame_offset;
+
+ if (*r_start_offset >= 0) {
+ minimum_frame_offset = MIN2(video_start_offset, *r_start_offset) * FPS;
+ }
+ else {
+ minimum_frame_offset = video_start_offset * FPS;
+ }
+
+ video_frame_offset = video_start_offset * FPS - minimum_frame_offset;
+
+ *r_start_offset = video_start_offset;
+ }
+
Sequence *seq = SEQ_sequence_alloc(
- seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIE);
+ seqbase, load_data->start_frame + video_frame_offset, load_data->channel, SEQ_TYPE_MOVIE);
/* Multiview settings. */
if (load_data->use_multiview) {
@@ -579,27 +593,11 @@ Sequence *SEQ_add_movie_strip(Main *bmain,
seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
- float video_fps = 0.0f;
-
if (anim_arr[0] != NULL) {
seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
- *r_video_start_offset = IMD_anim_get_offset(anim_arr[0]);
IMB_anim_load_metadata(anim_arr[0]);
- short fps_denom;
- float fps_num;
-
- IMB_anim_get_fps(anim_arr[0], &fps_denom, &fps_num, true);
-
- video_fps = fps_denom / fps_num;
-
- /* Adjust scene's frame rate settings to match. */
- if (load_data->flags & SEQ_LOAD_MOVIE_SYNC_FPS) {
- scene->r.frs_sec = fps_denom;
- scene->r.frs_sec_base = fps_num;
- }
-
/* Set initial scale based on load_data->fit_method. */
orig_width = IMB_anim_get_image_width(anim_arr[0]);
orig_height = IMB_anim_get_image_height(anim_arr[0]);