28 #include "../include/FrameMapper.h"
31 using namespace openshot;
34 reader(reader), target(target), pulldown(target_pulldown), final_cache(820 * 1024), is_dirty(true), avr(NULL)
66 void FrameMapper::AddField(
long int frame)
69 AddField(
Field(frame, field_toggle));
72 void FrameMapper::AddField(
Field field)
78 field_toggle = (field_toggle ?
false :
true);
85 void FrameMapper::Init()
87 AppendDebugMethod(
"FrameMapper::Init (Calculate frame mappings)",
"", -1,
"", -1,
"", -1,
"", -1,
"", -1,
"", -1);
106 if ((original.
ToInt() == 24 || original.
ToInt() == 25 || original.
ToInt() == 30) &&
107 (target.
ToInt() == 24 || target.
ToInt() == 25 || target.
ToInt() == 30)) {
110 float difference = target.
ToInt() - original.
ToInt();
113 int field_interval = 0;
114 int frame_interval = 0;
118 field_interval = round(fabs(original.
ToInt() / difference));
121 frame_interval = field_interval * 2.0f;
130 for (
long int field = 1; field <= number_of_fields; field++)
138 else if (difference > 0)
148 else if (pulldown ==
PULLDOWN_ADVANCED && field % field_interval == 0 && field % frame_interval != 0)
155 AddField(
Field(frame + 1, field_toggle));
157 else if (pulldown ==
PULLDOWN_NONE && field % frame_interval == 0)
164 else if (difference < 0)
170 field_toggle = (field_toggle ?
false :
true);
172 else if (pulldown ==
PULLDOWN_ADVANCED && field % field_interval == 0 && field % frame_interval != 0)
177 else if (pulldown ==
PULLDOWN_NONE && frame % field_interval == 0)
190 if (field % 2 == 0 && field > 0)
206 for (
long int frame_num = 1; frame_num <= new_length; frame_num++)
209 AddField(rate_curve.
GetInt(frame_num));
210 AddField(rate_curve.
GetInt(frame_num));
219 int start_samples_frame = 1;
220 int start_samples_position = 0;
222 for (
long int field = 1; field <=
fields.size(); field++)
228 if (field % 2 == 0 && field > 0)
231 long int frame_number = field / 2;
242 int end_samples_frame = start_samples_frame;
243 int end_samples_position = start_samples_position;
246 while (remaining_samples > 0)
252 if (original_samples >= remaining_samples)
255 end_samples_position += remaining_samples;
256 remaining_samples = 0;
260 end_samples_frame += 1;
261 end_samples_position = 0;
262 remaining_samples -= original_samples;
272 start_samples_frame = end_samples_frame;
273 start_samples_position = end_samples_position + 1;
276 start_samples_frame += 1;
277 start_samples_position = 0;
301 if (info.has_video and !info.has_audio and info.has_single_image) {
305 frame.
Odd.
Frame = TargetFrameNumber;
315 if(TargetFrameNumber < 1 || frames.size() == 0)
317 throw OutOfBoundsFrame(
"An invalid frame was requested.", TargetFrameNumber, frames.size());
319 else if (TargetFrameNumber > frames.size())
321 TargetFrameNumber = frames.size();
324 return frames[TargetFrameNumber - 1];
328 tr1::shared_ptr<Frame> FrameMapper::GetOrCreateFrame(
long int number)
330 tr1::shared_ptr<Frame> new_frame;
337 new_frame = reader->
GetFrame(number);
361 tr1::shared_ptr<Frame> final_frame = final_cache.GetFrame(requested_frame);
362 if (final_frame)
return final_frame;
365 const GenericScopedLock<CriticalSection> lock(getFrameCriticalSection);
373 final_frame = final_cache.GetFrame(requested_frame);
374 if (final_frame)
return final_frame;
382 omp_set_nested(
true);
387 AppendDebugMethod(
"FrameMapper::GetFrame (Loop through frames)",
"requested_frame", requested_frame,
"minimum_frames", minimum_frames,
"", -1,
"", -1,
"", -1,
"", -1);
390 #pragma omp for ordered
391 for (
long int frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++)
395 tr1::shared_ptr<Frame> mapped_frame;
398 mapped_frame = GetOrCreateFrame(mapped.
Odd.
Frame);
401 int channels_in_frame = mapped_frame->GetAudioChannelsCount();
405 if (info.sample_rate == mapped_frame->SampleRate() &&
406 info.channels == mapped_frame->GetAudioChannelsCount() &&
407 info.channel_layout == mapped_frame->ChannelsLayout() &&
408 info.fps.num == reader->info.fps.num &&
409 info.fps.den == reader->info.fps.den) {
411 final_cache.Add(frame_number, mapped_frame);
416 tr1::shared_ptr<Frame> frame = tr1::shared_ptr<Frame>(
new Frame(frame_number, 1, 1,
"#000000", samples_in_frame, channels_in_frame));
417 frame->SampleRate(mapped_frame->SampleRate());
418 frame->ChannelsLayout(mapped_frame->ChannelsLayout());
422 tr1::shared_ptr<Frame> odd_frame;
424 odd_frame = GetOrCreateFrame(mapped.
Odd.
Frame);
427 frame->AddImage(tr1::shared_ptr<QImage>(
new QImage(*odd_frame->GetImage())),
true);
430 tr1::shared_ptr<Frame> even_frame;
432 even_frame = GetOrCreateFrame(mapped.
Even.
Frame);
434 frame->AddImage(tr1::shared_ptr<QImage>(
new QImage(*even_frame->GetImage())),
false);
438 int samples_copied = 0;
440 while (info.has_audio && samples_copied < mapped.
Samples.
total)
443 int remaining_samples = mapped.
Samples.
total - samples_copied;
444 int number_to_copy = 0;
447 for (
int channel = 0; channel < channels_in_frame; channel++)
450 tr1::shared_ptr<Frame> original_frame = GetOrCreateFrame(starting_frame);
451 int original_samples = original_frame->GetAudioSamplesCount();
457 if (number_to_copy > remaining_samples)
458 number_to_copy = remaining_samples;
461 frame->AddAudio(
true, channel, samples_copied, original_frame->GetAudioSamples(channel) + mapped.
Samples.
sample_start, number_to_copy, 1.0);
466 number_to_copy = original_samples;
467 if (number_to_copy > remaining_samples)
468 number_to_copy = remaining_samples;
471 frame->AddAudio(
true, channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0);
477 if (number_to_copy > remaining_samples)
478 number_to_copy = remaining_samples;
481 frame->AddAudio(
false, channel, samples_copied, original_frame->GetAudioSamples(channel), number_to_copy, 1.0);
486 samples_copied += number_to_copy;
491 if (info.has_audio &&
492 (info.sample_rate != frame->SampleRate() ||
493 info.channels != frame->GetAudioChannelsCount() ||
494 info.channel_layout != frame->ChannelsLayout()))
496 ResampleMappedAudio(frame, mapped.
Odd.
Frame);
499 final_cache.Add(frame->number, frame);
505 return final_cache.GetFrame(requested_frame);
511 float difference = target.
ToInt() - original.
ToInt();
513 int field_interval = 0;
514 int frame_interval = 0;
519 field_interval = round(fabs(original.
ToInt() / difference));
522 frame_interval = field_interval * 2.0f;
526 for (
float map = 1; map <=
frames.size(); map++)
529 cout <<
"Target frame #: " << map <<
" mapped to original frame #:\t(" << frame.
Odd.
Frame <<
" odd, " << frame.
Even.
Frame <<
" even)" << endl;
550 AppendDebugMethod(
"FrameMapper::Open",
"", -1,
"", -1,
"", -1,
"", -1,
"", -1,
"", -1);
557 reader->
debug =
true;
569 AppendDebugMethod(
"FrameMapper::Open",
"", -1,
"", -1,
"", -1,
"", -1,
"", -1,
"", -1);
576 avresample_close(avr);
577 avresample_free(&avr);
596 root[
"type"] =
"FrameMapper";
608 bool success = reader.parse( value, root );
611 throw InvalidJSON(
"JSON could not be parsed (or is invalid)",
"");
621 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)",
"");
642 AppendDebugMethod(
"FrameMapper::ChangeMapping",
"target_fps.num", target_fps.
num,
"target_fps.den", target_fps.
num,
"target_pulldown", target_pulldown,
"target_sample_rate", target_sample_rate,
"target_channels", target_channels,
"target_channel_layout", target_channel_layout);
649 pulldown = target_pulldown;
659 avresample_close(avr);
660 avresample_free(&avr);
669 int total_frame_samples = 0;
670 int channels_in_frame = frame->GetAudioChannelsCount();
671 int sample_rate_in_frame = frame->SampleRate();
672 int samples_in_frame = frame->GetAudioSamplesCount();
673 ChannelLayout channel_layout_in_frame = frame->ChannelsLayout();
675 AppendDebugMethod(
"FrameMapper::ResampleMappedAudio",
"frame->number", frame->number,
"original_frame_number", original_frame_number,
"channels_in_frame", channels_in_frame,
"samples_in_frame", samples_in_frame,
"sample_rate_in_frame", sample_rate_in_frame,
"", -1);
678 float* frame_samples_float = NULL;
680 frame_samples_float = frame->GetInterleavedAudioSamples(sample_rate_in_frame, NULL, &samples_in_frame);
683 total_frame_samples = samples_in_frame * channels_in_frame;
686 int16_t* frame_samples =
new int16_t[total_frame_samples];
689 for (
int s = 0; s < total_frame_samples; s++)
691 frame_samples[s] =
int(frame_samples_float[s] * (1 << 15));
695 delete[] frame_samples_float;
696 frame_samples_float = NULL;
698 AppendDebugMethod(
"FrameMapper::ResampleMappedAudio (got sample data from frame)",
"frame->number", frame->number,
"total_frame_samples", total_frame_samples,
"target channels",
info.
channels,
"channels_in_frame", channels_in_frame,
"target sample_rate",
info.
sample_rate,
"samples_in_frame", samples_in_frame);
704 audio_frame->nb_samples = total_frame_samples / channels_in_frame;
706 int error_code = avcodec_fill_audio_frame(audio_frame, channels_in_frame, AV_SAMPLE_FMT_S16, (uint8_t *) frame_samples,
707 audio_frame->nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * channels_in_frame, 1);
711 AppendDebugMethod(
"FrameMapper::ResampleMappedAudio ERROR [" + (
string)
av_err2str(error_code) +
"]",
"error_code", error_code,
"", -1,
"", -1,
"", -1,
"", -1,
"", -1);
712 throw ErrorEncodingVideo(
"Error while resampling audio in frame mapper", frame->number);
718 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);
723 audio_converted->nb_samples = total_frame_samples;
724 av_samples_alloc(audio_converted->data, audio_converted->linesize,
info.
channels, total_frame_samples, AV_SAMPLE_FMT_S16, 0);
726 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);
735 avr = avresample_alloc_context();
736 av_opt_set_int(avr,
"in_channel_layout", channel_layout_in_frame, 0);
738 av_opt_set_int(avr,
"in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
739 av_opt_set_int(avr,
"out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
740 av_opt_set_int(avr,
"in_sample_rate", sample_rate_in_frame, 0);
742 av_opt_set_int(avr,
"in_channels", channels_in_frame, 0);
744 avresample_open(avr);
748 nb_samples = avresample_convert(avr,
749 audio_converted->data,
750 audio_converted->linesize[0],
751 audio_converted->nb_samples,
753 audio_frame->linesize[0],
754 audio_frame->nb_samples);
758 int16_t* resampled_samples =
new int16_t[(nb_samples *
info.
channels)];
761 memcpy(resampled_samples, audio_converted->data[0], (nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) *
info.
channels));
764 free(audio_frame->data[0]);
766 av_free(audio_converted->data[0]);
768 frame_samples = NULL;
771 int channel_buffer_size = nb_samples;
774 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);
777 float *channel_buffer =
new float[channel_buffer_size];
780 for (
int channel_filter = 0; channel_filter <
info.
channels; channel_filter++)
783 for (
int z = 0; z < channel_buffer_size; z++)
784 channel_buffer[z] = 0.0f;
790 for (
int sample = 0; sample < (nb_samples *
info.
channels); sample++)
793 if (channel_filter == channel)
796 channel_buffer[position] = resampled_samples[sample] * (1.0f / (1 << 15));
812 frame->AddAudio(
true, channel_filter, 0, channel_buffer, position, 1.0f);
814 AppendDebugMethod(
"FrameMapper::ResampleMappedAudio (Add audio to channel)",
"number of samples", position,
"channel_filter", channel_filter,
"", -1,
"", -1,
"", -1,
"", -1);
822 delete[] channel_buffer;
823 channel_buffer = NULL;
826 delete[] resampled_samples;
827 resampled_samples = NULL;
#define AV_RESET_FRAME(av_frame)
Classic 2:3:2:3 pull-down.
#define AV_FREE_FRAME(av_frame)
int num
Numerator for the fraction.
CriticalSection getFrameCriticalSection
Section lock for multiple threads.
vector< MappedFrame > frames
ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
int width
The width of the video (in pixesl)
tr1::shared_ptr< Frame > GetFrame(long int requested_frame)
This method is required for all derived classes of ReaderBase, and return the openshot::Frame object...
This class represents a single frame of video (i.e. image & audio data)
void ResampleMappedAudio(tr1::shared_ptr< Frame > frame, long int original_frame_number)
Resample audio and map channels (if needed)
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
~FrameMapper()
Destructor.
float duration
Length of time (in seconds)
void Close()
Close the openshot::FrameMapper and internal reader.
virtual void Close()=0
Close the reader (and any resources it was consuming)
This abstract class is the base class, used by all readers in libopenshot.
#define OPEN_MP_NUM_PROCESSORS
Exception when a reader is closed, and a frame is requested.
bool has_video
Determines if this file has a video stream.
This struct holds a single field (half a frame).
Exception when encoding audio packet.
void AddPoint(Point p)
Add a new point on the key-frame. Each point has a primary coordinate, a left handle, and a right handle.
This struct holds a the range of samples needed by this frame.
MappedFrame GetMappedFrame(long int TargetFrameNumber)
Get a frame based on the target frame rate and the new frame number of a frame.
bool has_audio
Determines if this file has an audio stream.
void AppendDebugMethod(string method_name, string arg1_name, float arg1_value, string arg2_name, float arg2_value, string arg3_name, float arg3_value, string arg4_name, float arg4_value, string arg5_name, float arg5_value, string arg6_name, float arg6_value)
Append debug information as JSON.
void ChangeMapping(Fraction target_fps, PulldownType pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout)
Change frame rate or audio mapping details.
int height
The height of the video (in pixels)
#define AV_ALLOCATE_FRAME()
Exception for files that can not be found or opened.
bool IsOpen()
Determine if reader is open or closed.
This class represents a fraction.
bool has_single_image
Determines if this file only contains a single image.
ChannelLayout
This enumeration determines the audio channel layout (such as stereo, mono, 5 point surround...
virtual Json::Value JsonValue()=0
Generate Json::JsonValue for this object.
virtual void SetJsonValue(Json::Value root)=0
Load Json::JsonValue into this object.
#define av_err2str(errnum)
ReaderInfo info
Information about the current media file.
int ToInt()
Return a rounded integer of the fraction (for example 30000/1001 returns 30)
This struct holds two fields which together make up a complete video frame.
Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
string Json()
Get and Set JSON methods.
Exception for frames that are out of bounds.
int GetInt(long int index)
Get the rounded INT value at a specific index.
void Clear()
Clear the cache of all frames.
virtual tr1::shared_ptr< Frame > GetFrame(long int number)=0
Do not apply pull-down techniques, just repeat or skip entire frames.
Linear curves are angular, straight lines between two points.
void PrintMapping()
Print all of the original frames and which new frames they map to.
Exception for invalid JSON.
PulldownType
This enumeration determines how frame rates are increased or decreased.
int den
Denominator for the fraction.
int channels
The number of audio channels used in the audio stream.
A Keyframe is a collection of Point instances, which is used to vary a number or property over time...
long int video_length
The number of frames in the video stream.
int GetSamplesPerFrame(Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
void SetJsonValue(Json::Value root)
Load Json::JsonValue into this object.
Json::Value JsonValue()
Generate Json::JsonValue for this object.
Advanced 2:3:3:2 pull-down (minimal dirty frames)
void SetJson(string value)
Load JSON string into this object.
void Open()
Open the internal reader.
double ToDouble()
Return this fraction as a double (i.e. 1/2 = 0.5)
virtual void Open()=0
Open the reader (and start consuming resources, such as images or video files)
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Exception when too many seek attempts happen.
virtual bool IsOpen()=0
A thread safe version of GetFrame.