You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
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).
This commit is contained in:
@@ -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<Magick::Image> GetWaveform(int width, int height, int Red, int Green, int Blue);
|
||||
|
||||
@@ -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> frame);
|
||||
void ResampleMappedAudio(tr1::shared_ptr<Frame> frame, int original_frame_number);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ tr1::shared_ptr<Frame> Clip::get_time_mapped_frame(tr1::shared_ptr<Frame> 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<Frame>(new Frame(new_frame_number, 1, 1, "#000000", samples_in_frame, frame->GetAudioChannelsCount()));
|
||||
|
||||
// Copy the image from the new frame
|
||||
|
||||
@@ -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<Frame> FFmpegReader::CreateFrame(int requested_frame)
|
||||
else
|
||||
{
|
||||
// Create a new frame on the working cache
|
||||
tr1::shared_ptr<Frame> f(new Frame(requested_frame, info.width, info.height, "#000000", Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate), info.channels));
|
||||
tr1::shared_ptr<Frame> 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Frame> 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<Frame> 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> 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<Frame> 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<Frame> 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> 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<Frame> 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> frame)
|
||||
void FrameMapper::ResampleMappedAudio(tr1::shared_ptr<Frame> 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> 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> 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> 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> 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
|
||||
|
||||
@@ -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<Frame> f = r9.GetFrame(frame_number);
|
||||
tr1::shared_ptr<Frame> f = map.GetFrame(frame_number);
|
||||
cout << "display it (" << f->number << ", " << f << ")" << endl;
|
||||
//r9.GetFrame(frame_number)->DisplayWaveform();
|
||||
//if (frame == 49)
|
||||
|
||||
Reference in New Issue
Block a user