Skip to content

Commit d28a7ef

Browse files
authored
Merge pull request #152 from OpenShot/improved-fps-detection
Improved FPS detection and new Mask Properties
2 parents 53c400d + da01a2c commit d28a7ef

File tree

3 files changed

+57
-44
lines changed

3 files changed

+57
-44
lines changed

include/effects/Mask.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ namespace openshot
6565
private:
6666
ReaderBase *reader;
6767
std::shared_ptr<QImage> original_mask;
68+
bool needs_refresh;
6869

6970
/// Init effect settings
7071
void init_effect_details();

src/FFmpegReader.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -421,18 +421,6 @@ void FFmpegReader::UpdateVideoInfo()
421421
// Calculate FPS, duration, video bit rate, and video length manually
422422
// by scanning through all the video stream packets
423423
CheckFPS();
424-
425-
// If still an invalid FPS detected, just default to 24 FPS
426-
// Set a few important default video settings (so audio can be divided into frames)
427-
if (info.fps.ToFloat() > 240.0f || (info.fps.num == 0 || info.fps.den == 0)) {
428-
info.fps.num = 24;
429-
info.fps.den = 1;
430-
info.video_timebase.num = 1;
431-
info.video_timebase.den = 24;
432-
433-
// Calculate number of frames
434-
info.video_length = round(info.duration * info.fps.ToDouble());
435-
}
436424
}
437425

438426
// Add video metadata (if any)
@@ -1934,6 +1922,18 @@ void FFmpegReader::CheckFPS()
19341922

19351923
// Update video bit rate
19361924
info.video_bit_rate = info.file_size / info.duration;
1925+
} else {
1926+
1927+
// Too short to determine framerate, just default FPS
1928+
// Set a few important default video settings (so audio can be divided into frames)
1929+
info.fps.num = 30;
1930+
info.fps.den = 1;
1931+
info.video_timebase.num = info.fps.den;
1932+
info.video_timebase.den = info.fps.num;
1933+
1934+
// Calculate number of frames
1935+
info.video_length = frames_detected;
1936+
info.duration = frames_detected / info.video_timebase.ToFloat();
19371937
}
19381938
}
19391939

src/effects/Mask.cpp

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@
3030
using namespace openshot;
3131

3232
/// Blank constructor, useful when using Json to load the effect properties
33-
Mask::Mask() : reader(NULL), replace_image(false) {
33+
Mask::Mask() : reader(NULL), replace_image(false), needs_refresh(true) {
3434
// Init effect properties
3535
init_effect_details();
3636
}
3737

3838
// Default constructor
3939
Mask::Mask(ReaderBase *mask_reader, Keyframe mask_brightness, Keyframe mask_contrast) :
40-
reader(mask_reader), brightness(mask_brightness), contrast(mask_contrast), replace_image(false)
40+
reader(mask_reader), brightness(mask_brightness), contrast(mask_contrast), replace_image(false), needs_refresh(true)
4141
{
4242
// Init effect properties
4343
init_effect_details();
@@ -77,7 +77,7 @@ std::shared_ptr<Frame> Mask::GetFrame(std::shared_ptr<Frame> frame, int64_t fram
7777
// Get mask image (if missing or different size than frame image)
7878
#pragma omp critical (open_mask_reader)
7979
{
80-
if (!original_mask || !reader->info.has_single_image ||
80+
if (!original_mask || !reader->info.has_single_image || needs_refresh ||
8181
(original_mask && original_mask->size() != frame_image->size())) {
8282

8383
// Only get mask if needed
@@ -91,6 +91,9 @@ std::shared_ptr<Frame> Mask::GetFrame(std::shared_ptr<Frame> frame, int64_t fram
9191
}
9292
}
9393

94+
// Refresh no longer needed
95+
needs_refresh = false;
96+
9497
// Get pixel arrays
9598
unsigned char *pixels = (unsigned char *) frame_image->bits();
9699
unsigned char *mask_pixels = (unsigned char *) original_mask->bits();
@@ -206,47 +209,51 @@ void Mask::SetJsonValue(Json::Value root) {
206209
contrast.SetJsonValue(root["contrast"]);
207210
if (!root["reader"].isNull()) // does Json contain a reader?
208211
{
209-
210-
if (!root["reader"]["type"].isNull()) // does the reader Json contain a 'type'?
212+
#pragma omp critical (open_mask_reader)
211213
{
212-
// Close previous reader (if any)
213-
if (reader)
214+
// This reader has changed, so refresh cached assets
215+
needs_refresh = true;
216+
217+
if (!root["reader"]["type"].isNull()) // does the reader Json contain a 'type'?
214218
{
215-
// Close and delete existing reader (if any)
216-
reader->Close();
217-
delete reader;
218-
reader = NULL;
219-
}
219+
// Close previous reader (if any)
220+
if (reader) {
221+
// Close and delete existing reader (if any)
222+
reader->Close();
223+
delete reader;
224+
reader = NULL;
225+
}
220226

221-
// Create new reader (and load properties)
222-
string type = root["reader"]["type"].asString();
227+
// Create new reader (and load properties)
228+
string type = root["reader"]["type"].asString();
223229

224-
if (type == "FFmpegReader") {
230+
if (type == "FFmpegReader") {
225231

226-
// Create new reader
227-
reader = new FFmpegReader(root["reader"]["path"].asString());
228-
reader->SetJsonValue(root["reader"]);
232+
// Create new reader
233+
reader = new FFmpegReader(root["reader"]["path"].asString());
234+
reader->SetJsonValue(root["reader"]);
229235

230-
#ifdef USE_IMAGEMAGICK
231-
} else if (type == "ImageReader") {
236+
#ifdef USE_IMAGEMAGICK
237+
} else if (type == "ImageReader") {
232238

233-
// Create new reader
234-
reader = new ImageReader(root["reader"]["path"].asString());
235-
reader->SetJsonValue(root["reader"]);
236-
#endif
239+
// Create new reader
240+
reader = new ImageReader(root["reader"]["path"].asString());
241+
reader->SetJsonValue(root["reader"]);
242+
#endif
237243

238-
} else if (type == "QtImageReader") {
244+
} else if (type == "QtImageReader") {
239245

240-
// Create new reader
241-
reader = new QtImageReader(root["reader"]["path"].asString());
242-
reader->SetJsonValue(root["reader"]);
246+
// Create new reader
247+
reader = new QtImageReader(root["reader"]["path"].asString());
248+
reader->SetJsonValue(root["reader"]);
243249

244-
} else if (type == "ChunkReader") {
250+
} else if (type == "ChunkReader") {
245251

246-
// Create new reader
247-
reader = new ChunkReader(root["reader"]["path"].asString(), (ChunkVersion) root["reader"]["chunk_version"].asInt());
248-
reader->SetJsonValue(root["reader"]);
252+
// Create new reader
253+
reader = new ChunkReader(root["reader"]["path"].asString(), (ChunkVersion) root["reader"]["chunk_version"].asInt());
254+
reader->SetJsonValue(root["reader"]);
249255

256+
}
250257
}
251258

252259
}
@@ -275,6 +282,11 @@ string Mask::PropertiesJSON(int64_t requested_frame) {
275282
root["brightness"] = add_property_json("Brightness", brightness.GetValue(requested_frame), "float", "", &brightness, -1.0, 1.0, false, requested_frame);
276283
root["contrast"] = add_property_json("Contrast", contrast.GetValue(requested_frame), "float", "", &contrast, 0, 20, false, requested_frame);
277284

285+
if (reader)
286+
root["reader"] = add_property_json("Source", 0.0, "reader", reader->Json(), NULL, 0, 1, false, requested_frame);
287+
else
288+
root["reader"] = add_property_json("Source", 0.0, "reader", "{}", NULL, 0, 1, false, requested_frame);
289+
278290
// Return formatted string
279291
return root.toStyledString();
280292
}

0 commit comments

Comments
 (0)