From 591cfbdb5a8560be2fced11d5d9dbfe448b0dba0 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Sun, 8 Mar 2015 21:42:53 -0500 Subject: [PATCH] Fixed some major issues with the frame mapper. openshot::FrameMapper is now fully multi-threaded. Fixed a bug in calculating the # of samples on a frame (to always be evenly divisible by the # of channels). --- include/Frame.h | 4 +- include/FrameMapper.h | 5 +- src/AudioReaderSource.cpp | 2 +- src/Clip.cpp | 2 +- src/FFmpegReader.cpp | 14 +- src/Frame.cpp | 20 ++- src/FrameMapper.cpp | 274 +++++++++++++++++++++----------------- src/examples/Example.cpp | 8 +- 8 files changed, 187 insertions(+), 142 deletions(-) diff --git a/include/Frame.h b/include/Frame.h index e9a4238d..6f894bb4 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -233,10 +233,10 @@ namespace openshot int GetHeight(); /// Calculate the # of samples per video frame (for the current frame number) - int GetSamplesPerFrame(Fraction fps, int sample_rate); + int GetSamplesPerFrame(Fraction fps, int sample_rate, int channels); /// Calculate the # of samples per video frame (for a specific frame number and frame rate) - static int GetSamplesPerFrame(int frame_number, Fraction fps, int sample_rate); + static int GetSamplesPerFrame(int frame_number, Fraction fps, int sample_rate, int channels); /// Get an audio waveform image tr1::shared_ptr GetWaveform(int width, int height, int Red, int Green, int Blue); diff --git a/include/FrameMapper.h b/include/FrameMapper.h index 2c2c5ddd..19fc2a00 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -40,8 +40,11 @@ #include "../include/Exceptions.h" #include "../include/KeyFrame.h" + // Include FFmpeg headers and macros #include "FFmpegUtilities.h" +#include "OpenMPUtilities.h" + using namespace std; @@ -196,7 +199,7 @@ namespace openshot void PrintMapping(); /// Resample audio and map channels (if needed) - void ResampleMappedAudio(tr1::shared_ptr frame); + void ResampleMappedAudio(tr1::shared_ptr frame, int original_frame_number); }; } diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp index 12470cc8..f6338e3e 100644 --- a/src/AudioReaderSource.cpp +++ b/src/AudioReaderSource.cpp @@ -214,7 +214,7 @@ void AudioReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& info) } // Adjust estimate frame number (the estimated frame number that is being played) - estimated_samples_per_frame = Frame::GetSamplesPerFrame(estimated_frame, reader->info.fps, reader->info.sample_rate); + estimated_samples_per_frame = Frame::GetSamplesPerFrame(estimated_frame, reader->info.fps, reader->info.sample_rate, buffer_channels); if (speed == 1) estimated_frame += double(info.numSamples) / double(estimated_samples_per_frame); } diff --git a/src/Clip.cpp b/src/Clip.cpp index 46023b2a..b1c3cbaa 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -305,7 +305,7 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, int new_frame_number = time.GetInt(frame_number); // Create a new frame - int samples_in_frame = Frame::GetSamplesPerFrame(new_frame_number, reader->info.fps, reader->info.sample_rate); + int samples_in_frame = Frame::GetSamplesPerFrame(new_frame_number, reader->info.fps, reader->info.sample_rate, frame->GetAudioChannelsCount()); 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 diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 59a4f2d3..622aee56 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -937,7 +937,7 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int while (pts_remaining_samples) { // Get Samples per frame (for this frame number) - int samples_per_frame = Frame::GetSamplesPerFrame(previous_packet_location.frame, info.fps, info.sample_rate); + int samples_per_frame = Frame::GetSamplesPerFrame(previous_packet_location.frame, info.fps, info.sample_rate, info.channels); // Calculate # of samples to add to this frame int samples = samples_per_frame - previous_packet_location.sample_start; @@ -980,8 +980,11 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int audio_converted->nb_samples = audio_frame->nb_samples; av_samples_alloc(audio_converted->data, audio_converted->linesize, info.channels, audio_frame->nb_samples, AV_SAMPLE_FMT_S16, 0); + AVAudioResampleContext *avr = NULL; + #pragma ordered + { // setup resample context - AVAudioResampleContext *avr = avresample_alloc_context(); + avr = avresample_alloc_context(); av_opt_set_int(avr, "in_channel_layout", aCodecCtx->channel_layout, 0); av_opt_set_int(avr, "out_channel_layout", aCodecCtx->channel_layout, 0); av_opt_set_int(avr, "in_sample_fmt", aCodecCtx->sample_fmt, 0); @@ -1001,6 +1004,7 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int 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 + } // Copy audio samples over original samples memcpy(audio_buf, audio_converted->data[0], audio_converted->nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * info.channels); @@ -1061,7 +1065,7 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int while (remaining_samples > 0) { // Get Samples per frame (for this frame number) - int samples_per_frame = Frame::GetSamplesPerFrame(starting_frame_number, info.fps, info.sample_rate); + int samples_per_frame = Frame::GetSamplesPerFrame(starting_frame_number, info.fps, info.sample_rate, info.channels); // Calculate # of samples to add to this frame int samples = samples_per_frame - start; @@ -1355,7 +1359,7 @@ AudioLocation FFmpegReader::GetAudioPTSLocation(int pts) double sample_start_percentage = frame - double(whole_frame); // Get Samples per frame - int samples_per_frame = Frame::GetSamplesPerFrame(whole_frame, info.fps, info.sample_rate); + int samples_per_frame = Frame::GetSamplesPerFrame(whole_frame, info.fps, info.sample_rate, info.channels); // Calculate the sample # to start on int sample_start = round(double(samples_per_frame) * sample_start_percentage); @@ -1415,7 +1419,7 @@ tr1::shared_ptr FFmpegReader::CreateFrame(int requested_frame) else { // Create a new frame on the working cache - tr1::shared_ptr f(new Frame(requested_frame, info.width, info.height, "#000000", Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate), info.channels)); + tr1::shared_ptr f(new Frame(requested_frame, info.width, info.height, "#000000", Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels), info.channels)); f->SetPixelRatio(info.pixel_ratio.num, info.pixel_ratio.den); // update pixel ratio f->ChannelsLayout(info.channel_layout); // update audio channel layout from the parent reader f->SampleRate(info.sample_rate); // update the frame's sample rate of the parent reader diff --git a/src/Frame.cpp b/src/Frame.cpp index cdc7759b..7cea2a34 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -454,23 +454,31 @@ void Frame::SetFrameNumber(int new_number) } // Calculate the # of samples per video frame (for a specific frame number and frame rate) -int Frame::GetSamplesPerFrame(int number, Fraction fps, int sample_rate) +int Frame::GetSamplesPerFrame(int number, Fraction fps, int sample_rate, int channels) { // Get the total # of samples for the previous frame, and the current frame (rounded) double fps_rate = fps.Reciprocal().ToDouble(); - double previous_samples = round((sample_rate * fps_rate) * (number - 1)); - double total_samples = round((sample_rate * fps_rate) * number); + + // Determine previous samples total, and make sure it's evenly divisible by the # of channels + double previous_samples = (sample_rate * fps_rate) * (number - 1); + double previous_samples_remainder = fmod(previous_samples, (double)channels); // subtract the remainder to the total (to make it evenly divisible) + previous_samples -= previous_samples_remainder; + + // Determine the current samples total, and make sure it's evenly divisible by the # of channels + double total_samples = (sample_rate * fps_rate) * number; + double total_samples_remainder = fmod(total_samples, (double)channels); // subtract the remainder to the total (to make it evenly divisible) + total_samples -= total_samples_remainder; // Subtract the previous frame's total samples with this frame's total samples. Not all sample rates can // be evenly divided into frames, so each frame can have have different # of samples. - double samples_per_frame = total_samples - previous_samples; + int samples_per_frame = round(total_samples - previous_samples); return samples_per_frame; } // Calculate the # of samples per video frame (for the current frame number) -int Frame::GetSamplesPerFrame(Fraction fps, int sample_rate) +int Frame::GetSamplesPerFrame(Fraction fps, int sample_rate, int channels) { - return GetSamplesPerFrame(number, fps, sample_rate); + return GetSamplesPerFrame(number, fps, sample_rate, channels); } // Get height of image diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 3e5e8388..ce617d1d 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -230,12 +230,12 @@ void FrameMapper::Init() // the original sample rate. int end_samples_frame = start_samples_frame; int end_samples_position = start_samples_position; - int remaining_samples = Frame::GetSamplesPerFrame(frame_number, target, reader->info.sample_rate); + int remaining_samples = Frame::GetSamplesPerFrame(frame_number, target, reader->info.sample_rate, reader->info.channels); while (remaining_samples > 0) { // get original samples - int original_samples = Frame::GetSamplesPerFrame(end_samples_frame, original, reader->info.sample_rate) - end_samples_position; + int original_samples = Frame::GetSamplesPerFrame(end_samples_frame, original, reader->info.sample_rate, reader->info.channels) - end_samples_position; // Enough samples if (original_samples >= remaining_samples) @@ -255,12 +255,12 @@ void FrameMapper::Init() // Create the sample mapping struct - SampleRange Samples = {start_samples_frame, start_samples_position, end_samples_frame, end_samples_position, Frame::GetSamplesPerFrame(frame_number, target, reader->info.sample_rate)}; + SampleRange Samples = {start_samples_frame, start_samples_position, end_samples_frame, end_samples_position, Frame::GetSamplesPerFrame(frame_number, target, reader->info.sample_rate, reader->info.channels)}; // Reset the audio variables start_samples_frame = end_samples_frame; start_samples_position = end_samples_position + 1; - if (start_samples_position >= Frame::GetSamplesPerFrame(start_samples_frame, original, reader->info.sample_rate)) + if (start_samples_position >= Frame::GetSamplesPerFrame(start_samples_frame, original, reader->info.sample_rate, reader->info.channels)) { start_samples_frame += 1; // increment the frame (since we need to wrap onto the next one) start_samples_position = 0; // reset to 0, since we wrapped @@ -311,100 +311,128 @@ tr1::shared_ptr FrameMapper::GetFrame(int requested_frame) throw(ReaderCl if (final_cache.Exists(requested_frame)) return final_cache.GetFrame(requested_frame); - // Get the mapped frame - MappedFrame mapped = GetMappedFrame(requested_frame); - tr1::shared_ptr mapped_frame = reader->GetFrame(mapped.Odd.Frame); - int channels_in_frame = mapped_frame->GetAudioChannelsCount(); - // Return the original frame if no mapping is needed - if (original.num == info.fps.num && original.den == info.fps.den && - info.sample_rate == mapped_frame->SampleRate() && info.channels == mapped_frame->GetAudioChannelsCount() && - info.channel_layout == mapped_frame->ChannelsLayout()) - // Return original frame (performance optimization) - return mapped_frame; + // 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); - // Init some basic properties about this frame - int samples_in_frame = Frame::GetSamplesPerFrame(requested_frame, target, mapped_frame->SampleRate()); - - // Create a new frame - tr1::shared_ptr frame(new Frame(requested_frame, 1, 1, "#000000", samples_in_frame, channels_in_frame)); - frame->SampleRate(mapped_frame->SampleRate()); - - #pragma omp critical (debug_output) - AppendDebugMethod("FrameMapper::GetFrame", "requested_frame", requested_frame, "target.num", target.num, "target.den", target.den, "mapped_frame->SampleRate()", mapped_frame->SampleRate(), "samples_in_frame", samples_in_frame, "mapped_frame->GetAudioSamplesCount()", mapped_frame->GetAudioSamplesCount()); - - // Copy the image from the odd field - frame->AddImage(reader->GetFrame(mapped.Odd.Frame)->GetImage(), true); - if (mapped.Odd.Frame != mapped.Even.Frame) - // Add even lines (if different than the previous image) - frame->AddImage(reader->GetFrame(mapped.Even.Frame)->GetImage(), false); - - // Copy the samples - int samples_copied = 0; - int starting_frame = mapped.Samples.frame_start; - while (samples_copied < mapped.Samples.total) + #pragma omp parallel { - // Init number of samples to copy this iteration - int remaining_samples = mapped.Samples.total - samples_copied; - int number_to_copy = 0; - - // Loop through each channel - for (int channel = 0; channel < channels_in_frame; channel++) + #pragma omp single { - // number of original samples on this frame - tr1::shared_ptr original_frame = reader->GetFrame(starting_frame); - int original_samples = original_frame->GetAudioSamplesCount(); + // Debug output + #pragma omp critical (debug_output) + AppendDebugMethod("FrameMapper::GetFrame (Loop through frames)", "requested_frame", requested_frame, "minimum_frames", minimum_frames, "", -1, "", -1, "", -1, "", -1); - if (starting_frame == mapped.Samples.frame_start) + // Loop through all requested frames + for (int frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++) { - // Starting frame (take the ending samples) - number_to_copy = original_samples - mapped.Samples.sample_start; - if (number_to_copy > remaining_samples) - number_to_copy = remaining_samples; + #pragma omp task firstprivate(frame_number) + { - // Add samples to new frame - 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) + + // Get the mapped frame + MappedFrame mapped = GetMappedFrame(frame_number); + tr1::shared_ptr mapped_frame = reader->GetFrameSafe(mapped.Odd.Frame); + int channels_in_frame = mapped_frame->GetAudioChannelsCount(); + + // Init some basic properties about this frame + int samples_in_frame = Frame::GetSamplesPerFrame(frame_number, target, mapped_frame->SampleRate(), channels_in_frame); + + // Create a new frame + tr1::shared_ptr frame(new Frame(frame_number, 1, 1, "#000000", samples_in_frame, channels_in_frame)); + frame->SampleRate(mapped_frame->SampleRate()); + + // Copy the image from the odd field + frame->AddImage(reader->GetFrameSafe(mapped.Odd.Frame)->GetImage(), true); + if (mapped.Odd.Frame != mapped.Even.Frame) + // Add even lines (if different than the previous image) + frame->AddImage(reader->GetFrameSafe(mapped.Even.Frame)->GetImage(), false); + + // Copy the samples + int samples_copied = 0; + int starting_frame = mapped.Samples.frame_start; + while (samples_copied < mapped.Samples.total) { - // Middle frame (take all samples) - number_to_copy = original_samples; - if (number_to_copy > remaining_samples) - number_to_copy = remaining_samples; + // Init number of samples to copy this iteration + int remaining_samples = mapped.Samples.total - samples_copied; + int number_to_copy = 0; - // Add samples to new frame - frame->AddAudio(true, channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0); + // Loop through each channel + for (int channel = 0; channel < channels_in_frame; channel++) + { + // number of original samples on this frame + tr1::shared_ptr original_frame = reader->GetFrameSafe(starting_frame); + int original_samples = original_frame->GetAudioSamplesCount(); + + if (starting_frame == mapped.Samples.frame_start) + { + // Starting frame (take the ending samples) + number_to_copy = original_samples - mapped.Samples.sample_start; + if (number_to_copy > remaining_samples) + 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) + { + // 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 + #pragma omp critical (openshot_adding_audio) + 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 = mapped.Samples.sample_end; + if (number_to_copy > remaining_samples) + 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); + } + } + + // increment frame + samples_copied += number_to_copy; + starting_frame++; } - else - { - // Ending frame (take the beginning samples) - number_to_copy = mapped.Samples.sample_end; - 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); - } - } - - // increment frame - samples_copied += number_to_copy; - starting_frame++; - } - // Resample audio on frame (if needed) - if (info.sample_rate != frame->SampleRate() || info.channels != frame->GetAudioChannelsCount() || - info.channel_layout != frame->ChannelsLayout()) - // Resample audio and correct # of channels if needed - ResampleMappedAudio(frame); + // Resample audio on frame (if needed) + if (info.sample_rate != frame->SampleRate() || info.channels != frame->GetAudioChannelsCount() || + info.channel_layout != frame->ChannelsLayout()) + // Resample audio and correct # of channels if needed + #pragma ordered + ResampleMappedAudio(frame, mapped.Odd.Frame); - // Add frame to final cache - final_cache.Add(frame->number, frame); + // Add frame to final cache + #pragma omp critical (openshot_cache) + final_cache.Add(frame->number, frame); + + } // omp task + + // TODO: Fix this bug. Wait on the task to complete. This is not ideal, but solves an issue with the + // audio_frame being modified by the next call to this method. I think this is a scope issue with OpenMP. + #pragma omp taskwait + + } // for loop + } // omp single + } // omp parallel // Return processed 'frame' - return final_cache.GetFrame(frame->number); + return final_cache.GetFrame(requested_frame); } void FrameMapper::PrintMapping() @@ -465,15 +493,15 @@ void FrameMapper::Close() #pragma omp critical (debug_output) AppendDebugMethod("FrameMapper::Open", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + // Close internal reader + reader->Close(); + // Deallocate resample buffer if (avr) { avresample_close(avr); avresample_free(&avr); avr = NULL; } - - // Close internal reader - reader->Close(); } } @@ -549,20 +577,11 @@ void FrameMapper::ChangeMapping(Fraction target_fps, PulldownType target_pulldow info.channels = target_channels; info.channel_layout = target_channel_layout; - // Deallocate resample buffer - if (avr) { - avresample_close(avr); - avresample_free(&avr); - avr = NULL; - } } // Resample audio and map channels (if needed) -void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame) +void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame, int original_frame_number) { - #pragma omp critical (debug_output) - AppendDebugMethod("FrameMapper::ResampleMappedAudio", "frame->number", frame->number, "", -1, "", -1, "", -1, "", -1, "", -1); - // Init audio buffers / variables int total_frame_samples = 0; int channels_in_frame = frame->GetAudioChannelsCount(); @@ -570,6 +589,9 @@ void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame) int samples_in_frame = frame->GetAudioSamplesCount(); ChannelLayout channel_layout_in_frame = frame->ChannelsLayout(); + #pragma omp critical (debug_output) + AppendDebugMethod("FrameMapper::ResampleMappedAudio", "frame->number", frame->number, "channels_in_frame", channels_in_frame, "samples_in_frame", samples_in_frame, "sample_rate_in_frame", sample_rate_in_frame, "", -1, "", -1); + // Get audio sample array float* frame_samples_float = NULL; // Get samples interleaved together (c1 c2 c1 c2 c1 c2) @@ -610,41 +632,47 @@ void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame) } // Update total samples & input frame size (due to bigger or smaller data types) - total_frame_samples *= (float(info.sample_rate) / sample_rate_in_frame); // adjust for different byte sizes - total_frame_samples *= (float(info.channels) / channels_in_frame); // adjust for different # of channels + //total_frame_samples = round((float)total_frame_samples * (float(info.sample_rate) / sample_rate_in_frame) * (float(info.channels) / channels_in_frame)) + 1; // adjust for different byte sizes and channels + total_frame_samples = Frame::GetSamplesPerFrame(original_frame_number, target, info.sample_rate, info.channels); + + #pragma omp critical (debug_output) + AppendDebugMethod("FrameMapper::ResampleMappedAudio (adjust # of samples)", "total_frame_samples", total_frame_samples, "info.sample_rate", info.sample_rate, "sample_rate_in_frame", sample_rate_in_frame, "info.channels", info.channels, "channels_in_frame", channels_in_frame, "original_frame_number", original_frame_number); // Create output frame (and allocate arrays) AVFrame *audio_converted = avcodec_alloc_frame(); avcodec_get_frame_defaults(audio_converted); - audio_converted->nb_samples = audio_frame->nb_samples; - av_samples_alloc(audio_converted->data, audio_converted->linesize, info.channels, audio_frame->nb_samples, AV_SAMPLE_FMT_S16, 0); + audio_converted->nb_samples = total_frame_samples; + av_samples_alloc(audio_converted->data, audio_converted->linesize, info.channels, total_frame_samples, AV_SAMPLE_FMT_S16, 0); #pragma omp critical (debug_output) 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); - // 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); - } int nb_samples = 0; + #pragma omp critical (openshot_audio_resample) + { + // 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 + // 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]; @@ -661,6 +689,7 @@ void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame) // 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); #pragma omp critical (debug_output) @@ -702,10 +731,11 @@ void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame) } // Add samples to frame for this channel - frame->AddAudio(true, channel_filter, 0, channel_buffer, position - 1, 1.0f); + #pragma omp critical (openshot_adding_audio) + frame->AddAudio(true, channel_filter, 0, channel_buffer, position, 1.0f); #pragma omp critical (debug_output) - AppendDebugMethod("FrameMapper::ResampleMappedAudio (Add audio to channel)", "number of samples", position - 1, "channel_filter", channel_filter, "", -1, "", -1, "", -1, "", -1); + AppendDebugMethod("FrameMapper::ResampleMappedAudio (Add audio to channel)", "number of samples", position, "channel_filter", channel_filter, "", -1, "", -1, "", -1, "", -1); } // clear channel buffer diff --git a/src/examples/Example.cpp b/src/examples/Example.cpp index 0aea3486..89621d38 100644 --- a/src/examples/Example.cpp +++ b/src/examples/Example.cpp @@ -48,9 +48,9 @@ int main(int argc, char* argv[]) r9.debug = false; // Mapper - FrameMapper map(&r9, Fraction(24,1), PULLDOWN_NONE, 44100, 2, LAYOUT_STEREO); + FrameMapper map(&r9, Fraction(30,1), PULLDOWN_NONE, 48000, 2, LAYOUT_STEREO); map.DisplayInfo(); - map.debug = false; + map.debug = true; map.Open(); /* WRITER ---------------- */ @@ -59,7 +59,7 @@ int main(int argc, char* argv[]) //ImageWriter w9("/home/jonathan/output.gif"); // Set options - w9.SetAudioOptions(true, "libmp3lame", r9.info.sample_rate, r9.info.channels, r9.info.channel_layout, 120000); + w9.SetAudioOptions(true, "libmp3lame", map.info.sample_rate, map.info.channels, map.info.channel_layout, 120000); //w9.SetAudioOptions(true, "libmp3lame", 44100, r9.info.channels, r9.info.channel_layout, 120000); //w9.SetVideoOptions(true, "libvpx", map.info.fps, map.info.width, map.info.height, map.info.pixel_ratio, false, false, 1500000); //w9.SetVideoOptions(true, "rawvideo", r9.info.fps, 400, 2, r9.info.pixel_ratio, false, false, 20000000); @@ -93,7 +93,7 @@ int main(int argc, char* argv[]) int frame_number = ( frame); cout << "get " << frame << " (frame: " << frame_number << ") " << endl; - tr1::shared_ptr f = r9.GetFrame(frame_number); + tr1::shared_ptr f = map.GetFrame(frame_number); cout << "display it (" << f->number << ", " << f << ")" << endl; //r9.GetFrame(frame_number)->DisplayWaveform(); //if (frame == 49)