diff --git a/include/Clip.h b/include/Clip.h index 6b8edb50..f924691d 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -121,7 +121,7 @@ namespace openshot { bool manage_reader; /// Adjust frame number minimum value - int adjust_frame_number_minimum(long int frame_number); + long int adjust_frame_number_minimum(long int frame_number); /// Apply effects to the source frame (if any) tr1::shared_ptr apply_effects(tr1::shared_ptr frame); @@ -129,6 +129,9 @@ namespace openshot { /// Get file extension string get_file_extension(string path); + /// Get a frame object or create a blank one + tr1::shared_ptr GetOrCreateFrame(long int number); + /// Adjust the audio and image of a time mapped frame tr1::shared_ptr get_time_mapped_frame(tr1::shared_ptr frame, long int frame_number) throw(ReaderClosed); diff --git a/src/Clip.cpp b/src/Clip.cpp index fc1e8f3f..95e103e3 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -258,7 +258,7 @@ tr1::shared_ptr Clip::GetFrame(long int requested_frame) throw(ReaderClos // Now that we have re-mapped what frame number is needed, go and get the frame pointer - tr1::shared_ptr original_frame = reader->GetFrame(new_frame_number); + tr1::shared_ptr original_frame = GetOrCreateFrame(new_frame_number); // Create a new frame tr1::shared_ptr frame(new Frame(new_frame_number, 1, 1, "#000000", original_frame->GetAudioSamplesCount(), original_frame->GetAudioChannelsCount())); @@ -329,11 +329,11 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, // Throw error if reader not initialized throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.", ""); - tr1::shared_ptr new_frame; - // Check for a valid time map curve if (time.Values.size() > 1) { + tr1::shared_ptr new_frame; + // create buffer and resampler juce::AudioSampleBuffer *samples = NULL; if (!resampler) @@ -347,7 +347,7 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, new_frame = tr1::shared_ptr(new Frame(new_frame_number, 1, 1, "#000000", samples_in_frame, frame->GetAudioChannelsCount())); // Copy the image from the new frame - new_frame->AddImage(reader->GetFrame(new_frame_number)->GetImage()); + new_frame->AddImage(GetOrCreateFrame(new_frame_number)->GetImage()); // Get delta (difference in previous Y value) @@ -356,7 +356,7 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, // Init audio vars int sample_rate = reader->info.sample_rate; int channels = reader->info.channels; - int number_of_samples = reader->GetFrame(new_frame_number)->GetAudioSamplesCount(); + int number_of_samples = GetOrCreateFrame(new_frame_number)->GetAudioSamplesCount(); // Determine if we are speeding up or slowing down if (time.GetRepeatFraction(frame_number).den > 1) @@ -373,7 +373,7 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, // Loop through channels, and get audio samples for (int channel = 0; channel < channels; channel++) // Get the audio samples for this channel - samples->addFrom(channel, 0, reader->GetFrame(new_frame_number)->GetAudioSamples(channel), number_of_samples, 1.0f); + samples->addFrom(channel, 0, GetOrCreateFrame(new_frame_number)->GetAudioSamples(channel), number_of_samples, 1.0f); // Reverse the samples (if needed) if (!time.IsIncreasing(frame_number)) @@ -402,23 +402,28 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, } else if (abs(delta) > 1 && abs(delta) < 100) { - // SPEED UP (multiple frames of audio), as long as it's not more than X frames - samples = new juce::AudioSampleBuffer(channels, number_of_samples * abs(delta)); - samples->clear(); int start = 0; - if (delta > 0) { + // SPEED UP (multiple frames of audio), as long as it's not more than X frames + int total_delta_samples = 0; + for (int delta_frame = new_frame_number - (delta - 1); delta_frame <= new_frame_number; delta_frame++) + total_delta_samples += Frame::GetSamplesPerFrame(delta_frame, reader->info.fps, reader->info.sample_rate, reader->info.channels); + + // Allocate a new sample buffer for these delta frames + samples = new juce::AudioSampleBuffer(channels, total_delta_samples); + samples->clear(); + // Loop through each frame in this delta for (int delta_frame = new_frame_number - (delta - 1); delta_frame <= new_frame_number; delta_frame++) { // buffer to hold detal samples - int number_of_delta_samples = reader->GetFrame(delta_frame)->GetAudioSamplesCount(); + int number_of_delta_samples = GetOrCreateFrame(delta_frame)->GetAudioSamplesCount(); AudioSampleBuffer* delta_samples = new juce::AudioSampleBuffer(channels, number_of_delta_samples); delta_samples->clear(); for (int channel = 0; channel < channels; channel++) - delta_samples->addFrom(channel, 0, reader->GetFrame(delta_frame)->GetAudioSamples(channel), number_of_delta_samples, 1.0f); + delta_samples->addFrom(channel, 0, GetOrCreateFrame(delta_frame)->GetAudioSamples(channel), number_of_delta_samples, 1.0f); // Reverse the samples (if needed) if (!time.IsIncreasing(frame_number)) @@ -439,16 +444,25 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, } else { + // SPEED UP (multiple frames of audio), as long as it's not more than X frames + int total_delta_samples = 0; + for (int delta_frame = new_frame_number - (delta + 1); delta_frame >= new_frame_number; delta_frame--) + total_delta_samples += Frame::GetSamplesPerFrame(delta_frame, reader->info.fps, reader->info.sample_rate, reader->info.channels); + + // Allocate a new sample buffer for these delta frames + samples = new juce::AudioSampleBuffer(channels, total_delta_samples); + samples->clear(); + // Loop through each frame in this delta for (int delta_frame = new_frame_number - (delta + 1); delta_frame >= new_frame_number; delta_frame--) { // buffer to hold delta samples - int number_of_delta_samples = reader->GetFrame(delta_frame)->GetAudioSamplesCount(); + int number_of_delta_samples = GetOrCreateFrame(delta_frame)->GetAudioSamplesCount(); AudioSampleBuffer* delta_samples = new juce::AudioSampleBuffer(channels, number_of_delta_samples); delta_samples->clear(); for (int channel = 0; channel < channels; channel++) - delta_samples->addFrom(channel, 0, reader->GetFrame(delta_frame)->GetAudioSamples(channel), number_of_delta_samples, 1.0f); + delta_samples->addFrom(channel, 0, GetOrCreateFrame(delta_frame)->GetAudioSamples(channel), number_of_delta_samples, 1.0f); // Reverse the samples (if needed) if (!time.IsIncreasing(frame_number)) @@ -505,19 +519,19 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, } - delete samples; - samples = NULL; + delete samples; + samples = NULL; + + // Return new time mapped frame + return new_frame; } else // Use original frame return frame; - - // Return new time mapped frame - return new_frame; } // Adjust frame number minimum value -int Clip::adjust_frame_number_minimum(long int frame_number) +long int Clip::adjust_frame_number_minimum(long int frame_number) { // Never return a frame number 0 or below if (frame_number < 1) @@ -527,6 +541,36 @@ int Clip::adjust_frame_number_minimum(long int frame_number) } +// Get or generate a blank frame +tr1::shared_ptr Clip::GetOrCreateFrame(long int number) +{ + tr1::shared_ptr new_frame; + + // Init some basic properties about this frame + int samples_in_frame = Frame::GetSamplesPerFrame(number, reader->info.fps, reader->info.sample_rate, reader->info.channels); + + try { + // Attempt to get a frame (but this could fail if a reader has just been closed) + new_frame = reader->GetFrame(number); + + // Return real frame + return new_frame; + + } catch (const ReaderClosed & e) { + // ... + } catch (const TooManySeeks & e) { + // ... + } catch (const OutOfBoundsFrame & e) { + // ... + } + + // Create blank frame + new_frame = tr1::shared_ptr(new Frame(number, reader->info.width, reader->info.height, "#000000", samples_in_frame, reader->info.channels)); + new_frame->SampleRate(reader->info.sample_rate); + new_frame->ChannelsLayout(reader->info.channel_layout); + return new_frame; +} + // Generate JSON string of this object string Clip::Json() { diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 1274fb7e..6a29b269 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -449,7 +449,6 @@ tr1::shared_ptr FrameMapper::GetFrame(long int requested_frame) throw(Rea number_to_copy = remaining_samples; // Add samples to new frame - #pragma omp critical (openshot_adding_audio) frame->AddAudio(true, channel, samples_copied, original_frame->GetAudioSamples(channel) + mapped.Samples.sample_start, number_to_copy, 1.0); } else if (starting_frame > mapped.Samples.frame_start && starting_frame < mapped.Samples.frame_end) @@ -460,7 +459,6 @@ tr1::shared_ptr FrameMapper::GetFrame(long int requested_frame) throw(Rea number_to_copy = remaining_samples; // Add samples to new frame - #pragma omp critical (openshot_adding_audio) frame->AddAudio(true, channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0); } else @@ -471,7 +469,6 @@ tr1::shared_ptr FrameMapper::GetFrame(long int requested_frame) throw(Rea number_to_copy = remaining_samples; // Add samples to new frame - #pragma omp critical (openshot_adding_audio) frame->AddAudio(false, channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0); } } @@ -483,13 +480,12 @@ tr1::shared_ptr FrameMapper::GetFrame(long int requested_frame) throw(Rea // Resample audio on frame (if needed) if (info.has_audio && - ( info.sample_rate != frame->SampleRate() || - info.channels != frame->GetAudioChannelsCount() || - info.channel_layout != frame->ChannelsLayout())) + (info.sample_rate != frame->SampleRate() || + info.channels != frame->GetAudioChannelsCount() || + info.channel_layout != frame->ChannelsLayout())) // Resample audio and correct # of channels if needed ResampleMappedAudio(frame, mapped.Odd.Frame); - // Add frame to final cache final_cache.Add(frame->number, frame); @@ -765,7 +761,6 @@ void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame, long int ori // Resize the frame to hold the right # of channels and samples int channel_buffer_size = nb_samples; - #pragma omp critical (openshot_adding_audio) frame->ResizeAudio(info.channels, channel_buffer_size, info.sample_rate, info.channel_layout); AppendDebugMethod("FrameMapper::ResampleMappedAudio (Audio successfully resampled)", "nb_samples", nb_samples, "total_frame_samples", total_frame_samples, "info.sample_rate", info.sample_rate, "channels_in_frame", channels_in_frame, "info.channels", info.channels, "info.channel_layout", info.channel_layout); @@ -806,7 +801,6 @@ void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame, long int ori } // Add samples to frame for this channel - #pragma omp critical (openshot_adding_audio) frame->AddAudio(true, channel_filter, 0, channel_buffer, position, 1.0f); AppendDebugMethod("FrameMapper::ResampleMappedAudio (Add audio to channel)", "number of samples", position, "channel_filter", channel_filter, "", -1, "", -1, "", -1, "", -1); diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 69e90b00..941428bb 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -264,7 +264,6 @@ void Timeline::add_layer(tr1::shared_ptr new_frame, Clip* source_clip, lo // Copy audio samples (and set initial volume). Mix samples with existing audio samples. The gains are added together, to // be sure to set the gain's correctly, so the sum does not exceed 1.0 (of audio distortion will happen). - #pragma omp critical (openshot_adding_audio) new_frame->AddAudio(false, channel, 0, source_frame->GetAudioSamples(channel), source_frame->GetAudioSamplesCount(), initial_volume); } @@ -594,9 +593,6 @@ tr1::shared_ptr Timeline::GetFrame(long int requested_frame) throw(Reader // This also opens the readers for intersecting clips, and marks non-intersecting clips as 'needs closing' vector nearby_clips = find_intersecting_clips(requested_frame, minimum_frames, true); - // TODO: OpenMP is disabled in this function, due to conditional calls the ImageMagick methods, which also - // contain OpenMP parallel regions. This is a violation of OpenMP, and causes the threads to hang in some cases. - // Set the number of threads in OpenMP omp_set_num_threads(OPEN_MP_NUM_PROCESSORS); // Allow nested OpenMP sections omp_set_nested(true);