Fixed a few more show stopping bugs related to FrameMapper and converting frame rates, and re-mapping audio samples. Integrated in special handling of certain framerates (for pull down support), and Keyframe linear curves for all other frame rates.

This commit is contained in:
Jonathan Thomas
2013-10-17 17:46:58 -05:00
parent e30ca3e9d6
commit dda767affa
2 changed files with 116 additions and 87 deletions

View File

@@ -80,94 +80,118 @@ void FrameMapper::AddField(Field field)
// whether the frame rate is increasing or decreasing.
void FrameMapper::Init()
{
// Get the difference (in frames) between the original and target frame rates
float difference = target.GetRoundedFPS() - original.GetRoundedFPS();
// Find the number (i.e. interval) of fields that need to be skipped or repeated
int field_interval = 0;
int frame_interval = 0;
if (difference != 0)
{
field_interval = round(fabs(original.GetRoundedFPS() / difference));
// Get frame interval (2 fields per frame)
frame_interval = field_interval * 2.0f;
}
// Clear the fields & frames lists
fields.clear();
frames.clear();
// Calculate # of fields to map
int frame = 1;
int number_of_fields = reader->info.video_length * 2;
// if (reader->info.video_length * 2 > number_of_fields)
// number_of_fields = reader->info.video_length * 2;
// Some framerates are handled special, and some use a generic Keyframe curve to
// map the framerates. These are the special framerates:
if ((original.GetRoundedFPS() == 24 || original.GetRoundedFPS() == 25 || original.GetRoundedFPS() == 30) &&
(target.GetRoundedFPS() == 24 || target.GetRoundedFPS() == 25 || target.GetRoundedFPS() == 30)) {
// Loop through all fields in the original video file
for (int field = 1; field <= number_of_fields; field++)
{
// Get the difference (in frames) between the original and target frame rates
float difference = target.GetRoundedFPS() - original.GetRoundedFPS();
if (difference == 0) // Same frame rate, NO pull-down or special techniques required
// Find the number (i.e. interval) of fields that need to be skipped or repeated
int field_interval = 0;
int frame_interval = 0;
if (difference != 0)
{
// Add fields
AddField(frame);
}
else if (difference > 0) // Need to ADD fake fields & frames, because original video has too few frames
{
// Add current field
AddField(frame);
field_interval = round(fabs(original.GetRoundedFPS() / difference));
if (pulldown == PULLDOWN_CLASSIC && field % field_interval == 0)
{
// Add extra field for each 'field interval
AddField(frame);
}
else if (pulldown == PULLDOWN_ADVANCED && field % field_interval == 0 && field % frame_interval != 0)
{
// Add both extra fields in the middle 'together' (i.e. 2:3:3:2 technique)
AddField(frame); // add field for current frame
if (frame + 1 <= info.video_length)
// add field for next frame (if the next frame exists)
AddField(Field(frame + 1, field_toggle));
}
else if (pulldown == PULLDOWN_NONE && field % frame_interval == 0)
{
// No pull-down technique needed, just repeat this frame
AddField(frame);
AddField(frame);
}
}
else if (difference < 0) // Need to SKIP fake fields & frames, because we want to return to the original film frame rate
{
if (pulldown == PULLDOWN_CLASSIC && field % field_interval == 0)
{
// skip current field and toggle the odd/even flag
field_toggle = (field_toggle ? false : true);
}
else if (pulldown == PULLDOWN_ADVANCED && field % field_interval == 0 && field % frame_interval != 0)
{
// skip this field, plus the next field
field++;
}
else if (pulldown == PULLDOWN_NONE && frame % field_interval == 0)
{
// skip this field, plus the next one
field++;
}
else
{
// No skipping needed, so add the field
AddField(frame);
}
// Get frame interval (2 fields per frame)
frame_interval = field_interval * 2.0f;
}
// increment frame number (if field is divisible by 2)
if (field % 2 == 0 && field > 0)
frame++;
// Calculate # of fields to map
int frame = 1;
int number_of_fields = reader->info.video_length * 2;
// Loop through all fields in the original video file
for (int field = 1; field <= number_of_fields; field++)
{
if (difference == 0) // Same frame rate, NO pull-down or special techniques required
{
// Add fields
AddField(frame);
}
else if (difference > 0) // Need to ADD fake fields & frames, because original video has too few frames
{
// Add current field
AddField(frame);
if (pulldown == PULLDOWN_CLASSIC && field % field_interval == 0)
{
// Add extra field for each 'field interval
AddField(frame);
}
else if (pulldown == PULLDOWN_ADVANCED && field % field_interval == 0 && field % frame_interval != 0)
{
// Add both extra fields in the middle 'together' (i.e. 2:3:3:2 technique)
AddField(frame); // add field for current frame
if (frame + 1 <= info.video_length)
// add field for next frame (if the next frame exists)
AddField(Field(frame + 1, field_toggle));
}
else if (pulldown == PULLDOWN_NONE && field % frame_interval == 0)
{
// No pull-down technique needed, just repeat this frame
AddField(frame);
AddField(frame);
}
}
else if (difference < 0) // Need to SKIP fake fields & frames, because we want to return to the original film frame rate
{
if (pulldown == PULLDOWN_CLASSIC && field % field_interval == 0)
{
// skip current field and toggle the odd/even flag
field_toggle = (field_toggle ? false : true);
}
else if (pulldown == PULLDOWN_ADVANCED && field % field_interval == 0 && field % frame_interval != 0)
{
// skip this field, plus the next field
field++;
}
else if (pulldown == PULLDOWN_NONE && frame % field_interval == 0)
{
// skip this field, plus the next one
field++;
}
else
{
// No skipping needed, so add the field
AddField(frame);
}
}
// increment frame number (if field is divisible by 2)
if (field % 2 == 0 && field > 0)
frame++;
}
} else {
// Map the remaining framerates using a simple Keyframe curve
// Calculate the difference (to be used as a multiplier)
float rate_diff = target.GetFPS() / original.GetFPS();
int new_length = reader->info.video_length * rate_diff;
// Build curve for framerate mapping
Keyframe rate_curve;
rate_curve.AddPoint(1, 1, LINEAR);
rate_curve.AddPoint(new_length, reader->info.video_length, LINEAR);
// Loop through curve, and build list of frames
for (int frame_num = 1; frame_num <= new_length; frame_num++)
{
// Add 2 fields per frame
AddField(rate_curve.GetInt(frame_num));
AddField(rate_curve.GetInt(frame_num));
}
}
// Loop through the target frames again (combining fields into frames)
@@ -209,7 +233,7 @@ void FrameMapper::Init()
if (original_samples >= remaining_samples)
{
// Take all that we need, and break loop
end_samples_position = remaining_samples;
end_samples_position += remaining_samples;
remaining_samples = 0;
} else
{
@@ -220,6 +244,8 @@ void FrameMapper::Init()
}
}
// Create the sample mapping struct
SampleRange Samples = {start_samples_frame, start_samples_position, end_samples_frame, end_samples_position, GetSamplesPerFrame(frame_number, target.GetFraction())};

View File

@@ -41,10 +41,13 @@ using namespace tr1;
int main(int argc, char* argv[])
{
// Reader
FFmpegReader r("/home/jonathan/Videos/sintel_trailer-720p.mp4");
r.Open();
FFmpegReader r1("/home/jonathan/Videos/sintel_trailer-720p.mp4");
r1.Open();
// FrameMapper
FrameMapper r(&r1, Framerate(100,1), PULLDOWN_NONE);
//r.PrintMapping();
/* WRITER ---------------- */
FFmpegWriter w("/home/jonathan/output.mp4");
@@ -53,7 +56,7 @@ int main(int argc, char* argv[])
//w.SetAudioOptions(true, "libvorbis", 48000, 2, 188000);
w.SetAudioOptions(true, "libmp3lame", 44100, 2, 128000);
//w.SetVideoOptions(true, "libvpx", Fraction(24,1), 1280, 720, Fraction(1,1), false, false, 30000000);
w.SetVideoOptions(true, "mpeg4", Fraction(24,1), 1280, 720, Fraction(1,1), false, false, 30000000);
w.SetVideoOptions(true, "mpeg4", r.info.fps, 1280, 720, Fraction(1,1), false, false, 3000000);
// Prepare Streams
w.PrepareStreams();
@@ -65,13 +68,13 @@ int main(int argc, char* argv[])
w.OutputStreamInfo();
//for (int frame = 3096; frame <= 3276; frame++)
for (int frame = 1; frame <= 1000; frame++)
for (int frame = 1; frame <= 1500; frame++)
{
tr1::shared_ptr<Frame> f = r.GetFrame(frame);
if (f)
{
//if (frame >= 62)
//f->DisplayWaveform();
//if (frame >= 250)
// f->DisplayWaveform();
//f->AddOverlayNumber(frame);
//f->Display();
@@ -88,7 +91,7 @@ int main(int argc, char* argv[])
w.Close();
// Close timeline
r.Close();
r1.Close();
/* ---------------- */