render: properly defined "out of bounds time" behavior with footage
If a user extends a clip beyond the footage's length, they can choose whether they want a black frame, the last frame continued, or for the footage to loop infinitely (same for extending earlier than the start of footage).
This commit is contained in:
+39
-7
@@ -107,7 +107,7 @@ FramePtr Decoder::RetrieveVideo(const rational &timecode, const int ÷r)
|
||||
return RetrieveVideoInternal(timecode, divider);
|
||||
}
|
||||
|
||||
SampleBufferPtr Decoder::RetrieveAudio(const TimeRange &range, const AudioParams ¶ms, const QString& cache_path, const QAtomicInt *cancelled)
|
||||
SampleBufferPtr Decoder::RetrieveAudio(const TimeRange &range, const AudioParams ¶ms, const QString& cache_path, Footage::LoopMode loop_mode, const QAtomicInt *cancelled)
|
||||
{
|
||||
QMutexLocker locker(&mutex_);
|
||||
|
||||
@@ -133,7 +133,7 @@ SampleBufferPtr Decoder::RetrieveAudio(const TimeRange &range, const AudioParams
|
||||
}
|
||||
|
||||
// See if we got the conform
|
||||
SampleBufferPtr buffer = RetrieveAudioFromConform(conform_filename, range);
|
||||
SampleBufferPtr buffer = RetrieveAudioFromConform(conform_filename, range, loop_mode);
|
||||
|
||||
if (!buffer) {
|
||||
// We'll need to conform this ourselves
|
||||
@@ -151,7 +151,7 @@ SampleBufferPtr Decoder::RetrieveAudio(const TimeRange &range, const AudioParams
|
||||
QFile::rename(working_fn, conform_filename);
|
||||
|
||||
// Return audio as planned
|
||||
buffer = RetrieveAudioFromConform(conform_filename, range);
|
||||
buffer = RetrieveAudioFromConform(conform_filename, range, loop_mode);
|
||||
} else {
|
||||
// Failed
|
||||
qCritical() << "Failed to conform audio";
|
||||
@@ -302,16 +302,48 @@ bool Decoder::ConformAudioInternal(const QString& filename, const AudioParams &p
|
||||
return false;
|
||||
}
|
||||
|
||||
SampleBufferPtr Decoder::RetrieveAudioFromConform(const QString &conform_filename, const TimeRange& range)
|
||||
SampleBufferPtr Decoder::RetrieveAudioFromConform(const QString &conform_filename, const TimeRange& range, Footage::LoopMode loop_mode)
|
||||
{
|
||||
WaveInput input(conform_filename);
|
||||
|
||||
if (input.open()) {
|
||||
const AudioParams& input_params = input.params();
|
||||
|
||||
// Read bytes from wav
|
||||
QByteArray packed_data = input.read(input_params.time_to_bytes(range.in()),
|
||||
input_params.time_to_bytes(range.length()));
|
||||
QByteArray packed_data(input_params.time_to_bytes(range.length()), Qt::Uninitialized);
|
||||
|
||||
qint64 read_index = input_params.time_to_bytes(range.in());
|
||||
qint64 write_index = 0;
|
||||
|
||||
while (write_index < packed_data.size()) {
|
||||
if (loop_mode == Footage::kLoopModeLoop) {
|
||||
while (read_index >= input.data_length()) {
|
||||
read_index -= input.data_length();
|
||||
}
|
||||
|
||||
while (read_index < 0) {
|
||||
read_index += input.data_length();
|
||||
}
|
||||
}
|
||||
|
||||
qint64 write_count = 0;
|
||||
|
||||
if (read_index < 0) {
|
||||
// Reading before 0, write silence here until audio data would actually start
|
||||
write_count = qMin(-read_index, qint64(packed_data.size()));
|
||||
memset(packed_data.data() + write_index, 0, write_count);
|
||||
} else if (read_index >= input.data_length()) {
|
||||
// Reading after data length, write silence until the end of the buffer
|
||||
write_count = packed_data.size() - write_index;
|
||||
memset(packed_data.data() + write_index, 0, write_count);
|
||||
} else {
|
||||
write_count = qMin(input.data_length() - read_index, packed_data.size() - write_index);
|
||||
input.read(read_index, packed_data.data() + write_index, write_count);
|
||||
}
|
||||
|
||||
read_index += write_count;
|
||||
write_index += write_count;
|
||||
}
|
||||
|
||||
input.close();
|
||||
|
||||
// Create sample buffer
|
||||
|
||||
Reference in New Issue
Block a user