@@ -346,7 +346,7 @@ std::shared_ptr<Frame> Clip::GetFrame(int64_t frame_number)
346346}
347347
348348// Use an existing openshot::Frame object and draw this Clip's frame onto it
349- std::shared_ptr<Frame> Clip::GetFrame (std::shared_ptr<openshot::Frame> frame , int64_t frame_number)
349+ std::shared_ptr<Frame> Clip::GetFrame (std::shared_ptr<openshot::Frame> background_frame , int64_t frame_number)
350350{
351351 // Check for open reader (or throw exception)
352352 if (!is_open)
@@ -376,7 +376,7 @@ std::shared_ptr<Frame> Clip::GetFrame(std::shared_ptr<openshot::Frame> frame, in
376376 int enabled_video = has_video.GetInt (frame_number);
377377 if (enabled_video == -1 && reader && reader->info .has_video )
378378 enabled_video = 1 ;
379- else if (enabled_video == -1 && reader && !reader->info .has_audio )
379+ else if (enabled_video == -1 && reader && !reader->info .has_video )
380380 enabled_video = 0 ;
381381
382382 // Is a time map detected
@@ -386,27 +386,14 @@ std::shared_ptr<Frame> Clip::GetFrame(std::shared_ptr<openshot::Frame> frame, in
386386 new_frame_number = time_mapped_number;
387387
388388 // Now that we have re-mapped what frame number is needed, go and get the frame pointer
389- std::shared_ptr<Frame> original_frame;
390- original_frame = GetOrCreateFrame (new_frame_number);
391-
392- // Copy the image from the odd field
393- if (enabled_video)
394- frame->AddImage (std::make_shared<QImage>(*original_frame->GetImage ()));
395-
396- // Loop through each channel, add audio
397- if (enabled_audio && reader->info .has_audio )
398- for (int channel = 0 ; channel < original_frame->GetAudioChannelsCount (); channel++)
399- frame->AddAudio (true , channel, 0 , original_frame->GetAudioSamples (channel), original_frame->GetAudioSamplesCount (), 1.0 );
389+ std::shared_ptr<Frame> original_frame = GetOrCreateFrame (new_frame_number);
400390
401391 // Get time mapped frame number (used to increase speed, change direction, etc...)
402392 // TODO: Handle variable # of samples, since this resamples audio for different speeds (only when time curve is set)
403- get_time_mapped_frame (frame, new_frame_number);
404-
405- // Adjust # of samples to match requested (the interaction with time curves will make this tricky)
406- // TODO: Implement move samples to/from next frame
393+ get_time_mapped_frame (original_frame, new_frame_number);
407394
408395 // Apply effects to the frame (if any)
409- apply_effects (frame );
396+ apply_effects (original_frame );
410397
411398 // Determine size of image (from Timeline or Reader)
412399 int width = 0 ;
@@ -422,13 +409,13 @@ std::shared_ptr<Frame> Clip::GetFrame(std::shared_ptr<openshot::Frame> frame, in
422409 }
423410
424411 // Apply keyframe / transforms
425- apply_keyframes (frame, width, height );
412+ apply_keyframes (original_frame, background_frame-> GetImage () );
426413
427- // Cache frame
428- cache.Add (frame );
414+ // Cache frame
415+ cache.Add (original_frame );
429416
430417 // Return processed 'frame'
431- return frame ;
418+ return original_frame ;
432419 }
433420 else
434421 // Throw error if reader not initialized
@@ -709,7 +696,6 @@ std::shared_ptr<Frame> Clip::GetOrCreateFrame(int64_t number)
709696 // Create a new copy of reader frame
710697 // This allows a clip to modify the pixels and audio of this frame without
711698 // changing the underlying reader's frame data
712- // std::shared_ptr<Frame> reader_copy(new Frame(number, 1, 1, "#000000", reader_frame->GetAudioSamplesCount(), reader_frame->GetAudioChannelsCount()));
713699 auto reader_copy = std::make_shared<Frame>(*reader_frame.get ());
714700 reader_copy->SampleRate (reader_frame->SampleRate ());
715701 reader_copy->ChannelsLayout (reader_frame->ChannelsLayout ());
@@ -1126,18 +1112,84 @@ bool Clip::isEqual(double a, double b)
11261112 return fabs (a - b) < 0.000001 ;
11271113}
11281114
1115+ // Apply keyframes to the source frame (if any)
1116+ void Clip::apply_keyframes (std::shared_ptr<Frame> frame, std::shared_ptr<QImage> background_canvas) {
1117+ // Skip out if video was disabled or only an audio frame (no visualisation in use)
1118+ if (has_video.GetInt (frame->number ) == 0 ||
1119+ (!Waveform () && !Reader ()->info .has_video ))
1120+ // Skip the rest of the image processing for performance reasons
1121+ return ;
1122+
1123+ // Get image from clip
1124+ std::shared_ptr<QImage> source_image = frame->GetImage ();
1125+
1126+ // Size of final image
1127+ int width = background_canvas->width ();
1128+ int height = background_canvas->height ();
1129+
1130+ // Get transform from clip's keyframes
1131+ QTransform transform = get_transform (frame, width, height);
1132+
1133+ // Debug output
1134+ ZmqLogger::Instance ()->AppendDebugMethod (" Clip::ApplyKeyframes (Transform: Composite Image Layer: Prepare)" , " frame->number" , frame->number );
1135+
1136+ // Load timeline's new frame image into a QPainter
1137+ QPainter painter (background_canvas.get ());
1138+ painter.setRenderHints (QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing, true );
1139+
1140+ // Apply transform (translate, rotate, scale)
1141+ painter.setTransform (transform);
1142+
1143+ // Composite a new layer onto the image
1144+ painter.setCompositionMode (QPainter::CompositionMode_SourceOver);
1145+ painter.drawImage (0 , 0 , *source_image);
1146+
1147+ if (timeline) {
1148+ Timeline *t = (Timeline *) timeline;
1149+
1150+ // Draw frame #'s on top of image (if needed)
1151+ if (display != FRAME_DISPLAY_NONE) {
1152+ std::stringstream frame_number_str;
1153+ switch (display) {
1154+ case (FRAME_DISPLAY_NONE):
1155+ // This is only here to prevent unused-enum warnings
1156+ break ;
1157+
1158+ case (FRAME_DISPLAY_CLIP):
1159+ frame_number_str << frame->number ;
1160+ break ;
1161+
1162+ case (FRAME_DISPLAY_TIMELINE):
1163+ frame_number_str << (position * t->info .fps .ToFloat ()) + frame->number ;
1164+ break ;
1165+
1166+ case (FRAME_DISPLAY_BOTH):
1167+ frame_number_str << (position * t->info .fps .ToFloat ()) + frame->number << " (" << frame->number << " )" ;
1168+ break ;
1169+ }
1170+
1171+ // Draw frame number on top of image
1172+ painter.setPen (QColor (" #ffffff" ));
1173+ painter.drawText (20 , 20 , QString (frame_number_str.str ().c_str ()));
1174+ }
1175+ }
1176+ painter.end ();
1177+
1178+ // Add new QImage to frame
1179+ frame->AddImage (background_canvas);
1180+ }
11291181
11301182// Apply keyframes to the source frame (if any)
1131- void Clip::apply_keyframes (std::shared_ptr<Frame> frame, int width, int height)
1183+ QTransform Clip::get_transform (std::shared_ptr<Frame> frame, int width, int height)
11321184{
1133- // Get actual frame image data
1134- std::shared_ptr<QImage> source_image = frame->GetImage ();
1185+ // Get image from clip
1186+ std::shared_ptr<QImage> source_image = frame->GetImage ();
11351187
11361188 /* REPLACE IMAGE WITH WAVEFORM IMAGE (IF NEEDED) */
11371189 if (Waveform ())
11381190 {
11391191 // Debug output
1140- ZmqLogger::Instance ()->AppendDebugMethod (" Clip::apply_keyframes (Generate Waveform Image)" , " frame->number" , frame->number , " Waveform()" , Waveform ());
1192+ ZmqLogger::Instance ()->AppendDebugMethod (" Clip::get_transform (Generate Waveform Image)" , " frame->number" , frame->number , " Waveform()" , Waveform ());
11411193
11421194 // Get the color of the waveform
11431195 int red = wave_color.red .GetInt (frame->number );
@@ -1170,7 +1222,7 @@ void Clip::apply_keyframes(std::shared_ptr<Frame> frame, int width, int height)
11701222 }
11711223
11721224 // Debug output
1173- ZmqLogger::Instance ()->AppendDebugMethod (" Clip::apply_keyframes (Set Alpha & Opacity)" , " alpha_value" , alpha_value, " frame->number" , frame->number );
1225+ ZmqLogger::Instance ()->AppendDebugMethod (" Clip::get_transform (Set Alpha & Opacity)" , " alpha_value" , alpha_value, " frame->number" , frame->number );
11741226 }
11751227
11761228 /* RESIZE SOURCE IMAGE - based on scale type */
@@ -1181,21 +1233,21 @@ void Clip::apply_keyframes(std::shared_ptr<Frame> frame, int width, int height)
11811233 source_size.scale (width, height, Qt::KeepAspectRatio);
11821234
11831235 // Debug output
1184- ZmqLogger::Instance ()->AppendDebugMethod (" Clip::apply_keyframes (Scale: SCALE_FIT)" , " frame->number" , frame->number , " source_width" , source_size.width (), " source_height" , source_size.height ());
1236+ ZmqLogger::Instance ()->AppendDebugMethod (" Clip::get_transform (Scale: SCALE_FIT)" , " frame->number" , frame->number , " source_width" , source_size.width (), " source_height" , source_size.height ());
11851237 break ;
11861238 }
11871239 case (SCALE_STRETCH): {
11881240 source_size.scale (width, height, Qt::IgnoreAspectRatio);
11891241
11901242 // Debug output
1191- ZmqLogger::Instance ()->AppendDebugMethod (" Clip::apply_keyframes (Scale: SCALE_STRETCH)" , " frame->number" , frame->number , " source_width" , source_size.width (), " source_height" , source_size.height ());
1243+ ZmqLogger::Instance ()->AppendDebugMethod (" Clip::get_transform (Scale: SCALE_STRETCH)" , " frame->number" , frame->number , " source_width" , source_size.width (), " source_height" , source_size.height ());
11921244 break ;
11931245 }
11941246 case (SCALE_CROP): {
11951247 source_size.scale (width, height, Qt::KeepAspectRatioByExpanding);
11961248
11971249 // Debug output
1198- ZmqLogger::Instance ()->AppendDebugMethod (" Clip::apply_keyframes (Scale: SCALE_CROP)" , " frame->number" , frame->number , " source_width" , source_size.width (), " source_height" , source_size.height ());
1250+ ZmqLogger::Instance ()->AppendDebugMethod (" Clip::get_transform (Scale: SCALE_CROP)" , " frame->number" , frame->number , " source_width" , source_size.width (), " source_height" , source_size.height ());
11991251 break ;
12001252 }
12011253 case (SCALE_NONE): {
@@ -1207,7 +1259,7 @@ void Clip::apply_keyframes(std::shared_ptr<Frame> frame, int width, int height)
12071259 source_size.scale (width * source_width_ratio, height * source_height_ratio, Qt::KeepAspectRatio);
12081260
12091261 // Debug output
1210- ZmqLogger::Instance ()->AppendDebugMethod (" Clip::apply_keyframes (Scale: SCALE_NONE)" , " frame->number" , frame->number , " source_width" , source_size.width (), " source_height" , source_size.height ());
1262+ ZmqLogger::Instance ()->AppendDebugMethod (" Clip::get_transform (Scale: SCALE_NONE)" , " frame->number" , frame->number , " source_width" , source_size.width (), " source_height" , source_size.height ());
12111263 break ;
12121264 }
12131265 }
@@ -1258,7 +1310,7 @@ void Clip::apply_keyframes(std::shared_ptr<Frame> frame, int width, int height)
12581310 }
12591311
12601312 // Debug output
1261- ZmqLogger::Instance ()->AppendDebugMethod (" Clip::apply_keyframes (Gravity)" , " frame->number" , frame->number , " source_clip->gravity" , gravity, " scaled_source_width" , scaled_source_width, " scaled_source_height" , scaled_source_height);
1313+ ZmqLogger::Instance ()->AppendDebugMethod (" Clip::get_transform (Gravity)" , " frame->number" , frame->number , " source_clip->gravity" , gravity, " scaled_source_width" , scaled_source_width, " scaled_source_height" , scaled_source_height);
12621314
12631315 /* LOCATION, ROTATION, AND SCALE */
12641316 float r = rotation.GetValue (frame->number ); // rotate in degrees
@@ -1272,7 +1324,7 @@ void Clip::apply_keyframes(std::shared_ptr<Frame> frame, int width, int height)
12721324 QTransform transform;
12731325
12741326 // Transform source image (if needed)
1275- ZmqLogger::Instance ()->AppendDebugMethod (" Clip::apply_keyframes (Build QTransform - if needed)" , " frame->number" , frame->number , " x" , x, " y" , y, " r" , r, " sx" , sx, " sy" , sy);
1327+ ZmqLogger::Instance ()->AppendDebugMethod (" Clip::get_transform (Build QTransform - if needed)" , " frame->number" , frame->number , " x" , x, " y" , y, " r" , r, " sx" , sx, " sy" , sy);
12761328
12771329 if (!isEqual (x, 0 ) || !isEqual (y, 0 )) {
12781330 // TRANSLATE/MOVE CLIP
@@ -1297,56 +1349,5 @@ void Clip::apply_keyframes(std::shared_ptr<Frame> frame, int width, int height)
12971349 transform.scale (source_width_scale, source_height_scale);
12981350 }
12991351
1300- // Debug output
1301- ZmqLogger::Instance ()->AppendDebugMethod (" Clip::apply_keyframes (Transform: Composite Image Layer: Prepare)" , " frame->number" , frame->number );
1302-
1303- /* COMPOSITE SOURCE IMAGE (LAYER) ONTO FINAL IMAGE */
1304- auto new_image = std::make_shared<QImage>(QSize (width, height), source_image->format ());
1305- new_image->fill (QColor (QString::fromStdString (" #00000000" )));
1306-
1307- // Load timeline's new frame image into a QPainter
1308- QPainter painter (new_image.get ());
1309- painter.setRenderHints (QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing, true );
1310-
1311- // Apply transform (translate, rotate, scale)
1312- painter.setTransform (transform);
1313-
1314- // Composite a new layer onto the image
1315- painter.setCompositionMode (QPainter::CompositionMode_SourceOver);
1316- painter.drawImage (0 , 0 , *source_image);
1317-
1318- if (timeline) {
1319- Timeline *t = (Timeline *) timeline;
1320-
1321- // Draw frame #'s on top of image (if needed)
1322- if (display != FRAME_DISPLAY_NONE) {
1323- std::stringstream frame_number_str;
1324- switch (display) {
1325- case (FRAME_DISPLAY_NONE):
1326- // This is only here to prevent unused-enum warnings
1327- break ;
1328-
1329- case (FRAME_DISPLAY_CLIP):
1330- frame_number_str << frame->number ;
1331- break ;
1332-
1333- case (FRAME_DISPLAY_TIMELINE):
1334- frame_number_str << (position * t->info .fps .ToFloat ()) + frame->number ;
1335- break ;
1336-
1337- case (FRAME_DISPLAY_BOTH):
1338- frame_number_str << (position * t->info .fps .ToFloat ()) + frame->number << " (" << frame->number << " )" ;
1339- break ;
1340- }
1341-
1342- // Draw frame number on top of image
1343- painter.setPen (QColor (" #ffffff" ));
1344- painter.drawText (20 , 20 , QString (frame_number_str.str ().c_str ()));
1345- }
1346- }
1347-
1348- painter.end ();
1349-
1350- // Add new QImage to frame
1351- frame->AddImage (new_image);
1352+ return transform;
13521353}
0 commit comments