diff --git a/src/Clip.cpp b/src/Clip.cpp
index 57d3e0f7..e139612b 100644
--- a/src/Clip.cpp
+++ b/src/Clip.cpp
@@ -356,6 +356,7 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame,
// Check for a valid time map curve
if (time.Values.size() > 1)
{
+ const GenericScopedLock lock(getFrameCriticalSection);
tr1::shared_ptr new_frame;
// create buffer and resampler
diff --git a/src/Frame.cpp b/src/Frame.cpp
index 18103ea7..3096f25d 100644
--- a/src/Frame.cpp
+++ b/src/Frame.cpp
@@ -410,13 +410,19 @@ float* Frame::GetInterleavedAudioSamples(int new_sample_rate, AudioResampler* re
// Get number of audio channels
int Frame::GetAudioChannelsCount()
{
- return audio->getNumChannels();
+ int i;
+ #pragma omp critical
+ i = audio->getNumChannels();
+ return i;
}
// Get number of audio samples
int Frame::GetAudioSamplesCount()
{
- return audio->getNumSamples();
+ int i;
+ #pragma omp critical
+ i = audio->getNumSamples();
+ return i;
}
juce::AudioSampleBuffer *Frame::GetAudioSampleBuffer()
diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp
index 6a0fe111..3e548d42 100644
--- a/src/FrameMapper.cpp
+++ b/src/FrameMapper.cpp
@@ -401,191 +401,180 @@ tr1::shared_ptr FrameMapper::GetFrame(long int requested_frame) throw(Rea
// Minimum number of frames to process (for performance reasons)
int minimum_frames = OPEN_MP_NUM_PROCESSORS;
- // Set the number of threads in OpenMP
- omp_set_num_threads(OPEN_MP_NUM_PROCESSORS);
- // Allow nested OpenMP sections
- omp_set_nested(true);
-
// Debug output
ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::GetFrame (Loop through frames)", "requested_frame", requested_frame, "minimum_frames", minimum_frames, "", -1, "", -1, "", -1, "", -1);
- #pragma omp parallel
+ // Loop through all requested frames
+ for (long int frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++)
{
- // Loop through all requested frames, each frame gets it's own thread
- #pragma omp for ordered firstprivate(requested_frame, minimum_frames)
- for (long int frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++)
+
+ // Debug output
+ ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::GetFrame (inside omp for loop)", "frame_number", frame_number, "minimum_frames", minimum_frames, "requested_frame", requested_frame, "", -1, "", -1, "", -1);
+
+ // Get the mapped frame
+ MappedFrame mapped = GetMappedFrame(frame_number);
+ tr1::shared_ptr mapped_frame;
+
+ // Get the mapped frame (keeping the sample rate and channels the same as the original... for the moment)
+ mapped_frame = GetOrCreateFrame(mapped.Odd.Frame);
+
+ // Get # of channels in the actual frame
+ int channels_in_frame = mapped_frame->GetAudioChannelsCount();
+ int samples_in_frame = Frame::GetSamplesPerFrame(frame_number + timeline_frame_offset, target, mapped_frame->SampleRate(), channels_in_frame);
+
+ // Determine if mapped frame is identical to source frame
+ // including audio sample distribution according to mapped.Samples,
+ // and frame_number. In some cases such as end of stream, the reader
+ // will return a frame with a different frame number. In these cases,
+ // we cannot use the frame as is, nor can we modify the frame number,
+ // otherwise the reader's cache object internals become invalid.
+ if (info.sample_rate == mapped_frame->SampleRate() &&
+ info.channels == mapped_frame->GetAudioChannelsCount() &&
+ info.channel_layout == mapped_frame->ChannelsLayout() &&
+ mapped.Samples.total == mapped_frame->GetAudioSamplesCount() &&
+ mapped.Samples.frame_start == mapped.Odd.Frame &&
+ mapped.Samples.sample_start == 0 &&
+ mapped_frame->number == frame_number &&// in some conditions (e.g. end of stream)
+ info.fps.num == reader->info.fps.num &&
+ info.fps.den == reader->info.fps.den) {
+ // Add original frame to cache, and skip the rest (for performance reasons)
+ final_cache.Add(mapped_frame);
+ continue;
+ }
+
+ // Create a new frame
+ tr1::shared_ptr frame = tr1::shared_ptr(new Frame(frame_number, 1, 1, "#000000", samples_in_frame, channels_in_frame));
+ frame->SampleRate(mapped_frame->SampleRate());
+ frame->ChannelsLayout(mapped_frame->ChannelsLayout());
+
+
+ // Copy the image from the odd field
+ tr1::shared_ptr odd_frame;
+ odd_frame = GetOrCreateFrame(mapped.Odd.Frame);
+
+ if (odd_frame)
+ frame->AddImage(tr1::shared_ptr(new QImage(*odd_frame->GetImage())), true);
+ if (mapped.Odd.Frame != mapped.Even.Frame) {
+ // Add even lines (if different than the previous image)
+ tr1::shared_ptr even_frame;
+ even_frame = GetOrCreateFrame(mapped.Even.Frame);
+ if (even_frame)
+ frame->AddImage(tr1::shared_ptr(new QImage(*even_frame->GetImage())), false);
+ }
+
+ // Resample audio on frame (if needed)
+ bool need_resampling = false;
+ if (info.has_audio &&
+ (info.sample_rate != frame->SampleRate() ||
+ info.channels != frame->GetAudioChannelsCount() ||
+ info.channel_layout != frame->ChannelsLayout()))
+ // Resample audio and correct # of channels if needed
+ need_resampling = true;
+
+ // create a copy of mapped.Samples that will be used by copy loop
+ SampleRange copy_samples = mapped.Samples;
+
+ if (need_resampling)
{
+ // Resampling needed, modify copy of SampleRange object that
+ // includes some additional input samples on first iteration,
+ // and continues the offset to ensure that the sample rate
+ // converter isn't input limited.
+ const int EXTRA_INPUT_SAMPLES = 20;
- // Debug output
- ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::GetFrame (inside omp for loop)", "frame_number", frame_number, "minimum_frames", minimum_frames, "requested_frame", requested_frame, "", -1, "", -1, "", -1);
-
- // Get the mapped frame
- MappedFrame mapped = GetMappedFrame(frame_number);
- tr1::shared_ptr mapped_frame;
-
- // Get the mapped frame (keeping the sample rate and channels the same as the original... for the moment)
- mapped_frame = GetOrCreateFrame(mapped.Odd.Frame);
-
- // Get # of channels in the actual frame
- int channels_in_frame = mapped_frame->GetAudioChannelsCount();
- int samples_in_frame = Frame::GetSamplesPerFrame(frame_number + timeline_frame_offset, target, mapped_frame->SampleRate(), channels_in_frame);
-
- // Determine if mapped frame is identical to source frame
- // including audio sample distribution according to mapped.Samples,
- // and frame_number. In some cases such as end of stream, the reader
- // will return a frame with a different frame number. In these cases,
- // we cannot use the frame as is, nor can we modify the frame number,
- // otherwise the reader's cache object internals become invalid.
- if (info.sample_rate == mapped_frame->SampleRate() &&
- info.channels == mapped_frame->GetAudioChannelsCount() &&
- info.channel_layout == mapped_frame->ChannelsLayout() &&
- mapped.Samples.total == mapped_frame->GetAudioSamplesCount() &&
- mapped.Samples.frame_start == mapped.Odd.Frame &&
- mapped.Samples.sample_start == 0 &&
- mapped_frame->number == frame_number &&// in some conditions (e.g. end of stream)
- info.fps.num == reader->info.fps.num &&
- info.fps.den == reader->info.fps.den) {
- // Add original frame to cache, and skip the rest (for performance reasons)
- final_cache.Add(mapped_frame);
- continue;
- }
-
- // Create a new frame
- tr1::shared_ptr frame = tr1::shared_ptr(new Frame(frame_number, 1, 1, "#000000", samples_in_frame, channels_in_frame));
- frame->SampleRate(mapped_frame->SampleRate());
- frame->ChannelsLayout(mapped_frame->ChannelsLayout());
-
-
- // Copy the image from the odd field
- tr1::shared_ptr odd_frame;
- #pragma omp ordered
- odd_frame = GetOrCreateFrame(mapped.Odd.Frame);
-
- if (odd_frame)
- frame->AddImage(tr1::shared_ptr(new QImage(*odd_frame->GetImage())), true);
- if (mapped.Odd.Frame != mapped.Even.Frame) {
- // Add even lines (if different than the previous image)
- tr1::shared_ptr even_frame;
- #pragma omp ordered
- even_frame = GetOrCreateFrame(mapped.Even.Frame);
- if (even_frame)
- frame->AddImage(tr1::shared_ptr(new QImage(*even_frame->GetImage())), false);
- }
-
- // Resample audio on frame (if needed)
- bool need_resampling = false;
- if (info.has_audio &&
- (info.sample_rate != frame->SampleRate() ||
- info.channels != frame->GetAudioChannelsCount() ||
- info.channel_layout != frame->ChannelsLayout()))
- // Resample audio and correct # of channels if needed
- need_resampling = true;
-
- // create a copy of mapped.Samples that will be used by copy loop
- SampleRange copy_samples = mapped.Samples;
-
- if (need_resampling)
+ // Extend end sample count by an addtional EXTRA_INPUT_SAMPLES samples
+ copy_samples.sample_end += EXTRA_INPUT_SAMPLES;
+ int samples_per_end_frame =
+ Frame::GetSamplesPerFrame(copy_samples.frame_end, original,
+ reader->info.sample_rate, reader->info.channels);
+ if (copy_samples.sample_end >= samples_per_end_frame)
{
- // Resampling needed, modify copy of SampleRange object that
- // includes some additional input samples on first iteration,
- // and continues the offset to ensure that the sample rate
- // converter isn't input limited.
- const int EXTRA_INPUT_SAMPLES = 20;
+ // check for wrapping
+ copy_samples.frame_end++;
+ copy_samples.sample_end -= samples_per_end_frame;
+ }
+ copy_samples.total += EXTRA_INPUT_SAMPLES;
- // Extend end sample count by an addtional EXTRA_INPUT_SAMPLES samples
- copy_samples.sample_end += EXTRA_INPUT_SAMPLES;
- int samples_per_end_frame =
- Frame::GetSamplesPerFrame(copy_samples.frame_end, original,
+ if (avr) {
+ // Sample rate conversion has been allocated on this clip, so
+ // this is not the first iteration. Extend start position by
+ // EXTRA_INPUT_SAMPLES to keep step with previous frame
+ copy_samples.sample_start += EXTRA_INPUT_SAMPLES;
+ int samples_per_start_frame =
+ Frame::GetSamplesPerFrame(copy_samples.frame_start, original,
reader->info.sample_rate, reader->info.channels);
- if (copy_samples.sample_end >= samples_per_end_frame)
+ if (copy_samples.sample_start >= samples_per_start_frame)
{
// check for wrapping
- copy_samples.frame_end++;
- copy_samples.sample_end -= samples_per_end_frame;
- }
- copy_samples.total += EXTRA_INPUT_SAMPLES;
-
- if (avr) {
- // Sample rate conversion has been allocated on this clip, so
- // this is not the first iteration. Extend start position by
- // EXTRA_INPUT_SAMPLES to keep step with previous frame
- copy_samples.sample_start += EXTRA_INPUT_SAMPLES;
- int samples_per_start_frame =
- Frame::GetSamplesPerFrame(copy_samples.frame_start, original,
- reader->info.sample_rate, reader->info.channels);
- if (copy_samples.sample_start >= samples_per_start_frame)
- {
- // check for wrapping
- copy_samples.frame_start++;
- copy_samples.sample_start -= samples_per_start_frame;
- }
- copy_samples.total -= EXTRA_INPUT_SAMPLES;
+ copy_samples.frame_start++;
+ copy_samples.sample_start -= samples_per_start_frame;
}
+ copy_samples.total -= EXTRA_INPUT_SAMPLES;
}
+ }
- // Copy the samples
- int samples_copied = 0;
- long int starting_frame = copy_samples.frame_start;
- while (info.has_audio && samples_copied < copy_samples.total)
+ // Copy the samples
+ int samples_copied = 0;
+ long int starting_frame = copy_samples.frame_start;
+ while (info.has_audio && samples_copied < copy_samples.total)
+ {
+ // Init number of samples to copy this iteration
+ int remaining_samples = copy_samples.total - samples_copied;
+ int number_to_copy = 0;
+
+ // Loop through each channel
+ for (int channel = 0; channel < channels_in_frame; channel++)
{
- // Init number of samples to copy this iteration
- int remaining_samples = copy_samples.total - samples_copied;
- int number_to_copy = 0;
+ // number of original samples on this frame
+ tr1::shared_ptr original_frame = GetOrCreateFrame(starting_frame);
+ int original_samples = original_frame->GetAudioSamplesCount();
- // Loop through each channel
- for (int channel = 0; channel < channels_in_frame; channel++)
+ if (starting_frame == copy_samples.frame_start)
{
- // number of original samples on this frame
- tr1::shared_ptr original_frame = GetOrCreateFrame(starting_frame);
- int original_samples = original_frame->GetAudioSamplesCount();
+ // Starting frame (take the ending samples)
+ number_to_copy = original_samples - copy_samples.sample_start;
+ if (number_to_copy > remaining_samples)
+ number_to_copy = remaining_samples;
- if (starting_frame == copy_samples.frame_start)
- {
- // Starting frame (take the ending samples)
- number_to_copy = original_samples - copy_samples.sample_start;
- if (number_to_copy > remaining_samples)
- number_to_copy = remaining_samples;
-
- // Add samples to new frame
- frame->AddAudio(true, channel, samples_copied, original_frame->GetAudioSamples(channel) + copy_samples.sample_start, number_to_copy, 1.0);
- }
- else if (starting_frame > copy_samples.frame_start && starting_frame < copy_samples.frame_end)
- {
- // Middle frame (take all samples)
- number_to_copy = original_samples;
- if (number_to_copy > remaining_samples)
- number_to_copy = remaining_samples;
-
- // Add samples to new frame
- frame->AddAudio(true, channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0);
- }
- else
- {
- // Ending frame (take the beginning samples)
- number_to_copy = copy_samples.sample_end + 1;
- if (number_to_copy > remaining_samples)
- number_to_copy = remaining_samples;
-
- // Add samples to new frame
- frame->AddAudio(false, channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0);
- }
+ // Add samples to new frame
+ frame->AddAudio(true, channel, samples_copied, original_frame->GetAudioSamples(channel) + copy_samples.sample_start, number_to_copy, 1.0);
}
+ else if (starting_frame > copy_samples.frame_start && starting_frame < copy_samples.frame_end)
+ {
+ // Middle frame (take all samples)
+ number_to_copy = original_samples;
+ if (number_to_copy > remaining_samples)
+ number_to_copy = remaining_samples;
- // increment frame
- samples_copied += number_to_copy;
- starting_frame++;
+ // Add samples to new frame
+ frame->AddAudio(true, channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0);
+ }
+ else
+ {
+ // Ending frame (take the beginning samples)
+ number_to_copy = copy_samples.sample_end + 1;
+ if (number_to_copy > remaining_samples)
+ number_to_copy = remaining_samples;
+
+ // Add samples to new frame
+ frame->AddAudio(false, channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0);
+ }
}
- // Resample audio on frame (if needed)
- if (need_resampling)
- // Resample audio and correct # of channels if needed
- ResampleMappedAudio(frame, mapped.Odd.Frame);
+ // increment frame
+ samples_copied += number_to_copy;
+ starting_frame++;
+ }
- // Add frame to final cache
- final_cache.Add(frame);
+ // Resample audio on frame (if needed)
+ if (need_resampling)
+ // Resample audio and correct # of channels if needed
+ ResampleMappedAudio(frame, mapped.Odd.Frame);
- } // for loop
- } // omp parallel
+ // Add frame to final cache
+ final_cache.Add(frame);
+
+ } // for loop
// Return processed openshot::Frame
return final_cache.GetFrame(requested_frame);
@@ -836,33 +825,29 @@ void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame, long int ori
ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::ResampleMappedAudio (preparing for resample)", "in_sample_fmt", AV_SAMPLE_FMT_S16, "out_sample_fmt", AV_SAMPLE_FMT_S16, "in_sample_rate", sample_rate_in_frame, "out_sample_rate", info.sample_rate, "in_channels", channels_in_frame, "out_channels", info.channels);
int nb_samples = 0;
- // Force the audio resampling to happen in order (1st thread to last thread), so the waveform
- // is smooth and continuous.
- #pragma omp ordered
- {
- // setup resample context
- if (!avr) {
- avr = avresample_alloc_context();
- av_opt_set_int(avr, "in_channel_layout", channel_layout_in_frame, 0);
- av_opt_set_int(avr, "out_channel_layout", info.channel_layout, 0);
- av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
- av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
- av_opt_set_int(avr, "in_sample_rate", sample_rate_in_frame, 0);
- av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0);
- av_opt_set_int(avr, "in_channels", channels_in_frame, 0);
- av_opt_set_int(avr, "out_channels", info.channels, 0);
- avresample_open(avr);
- }
- // Convert audio samples
- nb_samples = avresample_convert(avr, // audio resample context
- audio_converted->data, // output data pointers
- audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown)
- audio_converted->nb_samples, // maximum number of samples that the output buffer can hold
- audio_frame->data, // input data pointers
- audio_frame->linesize[0], // input plane size, in bytes (0 if unknown)
- audio_frame->nb_samples); // number of input samples to convert
- }
+ // setup resample context
+ if (!avr) {
+ avr = avresample_alloc_context();
+ av_opt_set_int(avr, "in_channel_layout", channel_layout_in_frame, 0);
+ av_opt_set_int(avr, "out_channel_layout", info.channel_layout, 0);
+ av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
+ av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
+ av_opt_set_int(avr, "in_sample_rate", sample_rate_in_frame, 0);
+ av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0);
+ av_opt_set_int(avr, "in_channels", channels_in_frame, 0);
+ av_opt_set_int(avr, "out_channels", info.channels, 0);
+ avresample_open(avr);
+ }
+
+ // Convert audio samples
+ nb_samples = avresample_convert(avr, // audio resample context
+ audio_converted->data, // output data pointers
+ audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown)
+ audio_converted->nb_samples, // maximum number of samples that the output buffer can hold
+ audio_frame->data, // input data pointers
+ audio_frame->linesize[0], // input plane size, in bytes (0 if unknown)
+ audio_frame->nb_samples); // number of input samples to convert
// Create a new array (to hold all resampled S16 audio samples)
int16_t* resampled_samples = new int16_t[(nb_samples * info.channels)];