Skip to content

Commit 7a20aae

Browse files
authored
Merge branch 'develop' into fix-ffmpeg3_2-empty-frames
2 parents a92ed9f + d28a7ef commit 7a20aae

File tree

3 files changed

+83
-100
lines changed

3 files changed

+83
-100
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: 38 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -339,19 +339,21 @@ void FFmpegReader::UpdateAudioInfo()
339339

340340
void FFmpegReader::UpdateVideoInfo()
341341
{
342+
if (check_fps)
343+
// Already initialized all the video metadata, no reason to do it again
344+
return;
345+
342346
// Set values of FileInfo struct
343347
info.has_video = true;
344348
info.file_size = pFormatCtx->pb ? avio_size(pFormatCtx->pb) : -1;
345349
info.height = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->height;
346350
info.width = AV_GET_CODEC_ATTRIBUTES(pStream, pCodecCtx)->width;
347351
info.vcodec = pCodecCtx->codec->name;
348-
info.video_bit_rate = pFormatCtx->bit_rate;
349-
if (!check_fps)
350-
{
351-
// set frames per second (fps)
352-
info.fps.num = pStream->avg_frame_rate.num;
353-
info.fps.den = pStream->avg_frame_rate.den;
354-
}
352+
info.video_bit_rate = (pFormatCtx->bit_rate / 8);
353+
354+
// set frames per second (fps)
355+
info.fps.num = pStream->avg_frame_rate.num;
356+
info.fps.den = pStream->avg_frame_rate.den;
355357

356358
if (pStream->sample_aspect_ratio.num != 0)
357359
{
@@ -415,16 +417,10 @@ void FFmpegReader::UpdateVideoInfo()
415417
}
416418

417419
// Override an invalid framerate
418-
if (info.fps.ToFloat() > 240.0f || (info.fps.num == 0 || info.fps.den == 0))
419-
{
420-
// Set a few important default video settings (so audio can be divided into frames)
421-
info.fps.num = 24;
422-
info.fps.den = 1;
423-
info.video_timebase.num = 1;
424-
info.video_timebase.den = 24;
425-
426-
// Calculate number of frames
427-
info.video_length = round(info.duration * info.fps.ToDouble());
420+
if (info.fps.ToFloat() > 240.0f || (info.fps.num == 0 || info.fps.den == 0)) {
421+
// Calculate FPS, duration, video bit rate, and video length manually
422+
// by scanning through all the video stream packets
423+
CheckFPS();
428424
}
429425

430426
// Add video metadata (if any)
@@ -1857,16 +1853,12 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream, int64_t requested_fram
18571853
void FFmpegReader::CheckFPS()
18581854
{
18591855
check_fps = true;
1860-
AV_ALLOCATE_IMAGE(pFrame, AV_GET_CODEC_PIXEL_FORMAT(pStream, pCodecCtx), info.width, info.height);
1861-
18621856
int first_second_counter = 0;
18631857
int second_second_counter = 0;
18641858
int third_second_counter = 0;
18651859
int forth_second_counter = 0;
18661860
int fifth_second_counter = 0;
1867-
1868-
int iterations = 0;
1869-
int threshold = 500;
1861+
int frames_detected = 0;
18701862

18711863
// Loop through the stream
18721864
while (true)
@@ -1908,63 +1900,41 @@ void FFmpegReader::CheckFPS()
19081900
forth_second_counter++;
19091901
else if (video_seconds > 4.0 && video_seconds <= 5.0)
19101902
fifth_second_counter++;
1911-
else
1912-
// Too far
1913-
break;
1903+
1904+
// Increment counters
1905+
frames_detected++;
19141906
}
19151907
}
1916-
1917-
// Increment counters
1918-
iterations++;
1919-
1920-
// Give up (if threshold exceeded)
1921-
if (iterations > threshold)
1922-
break;
19231908
}
19241909

19251910
// Double check that all counters have greater than zero (or give up)
1926-
if (second_second_counter == 0 || third_second_counter == 0 || forth_second_counter == 0 || fifth_second_counter == 0)
1927-
{
1928-
// Seek to frame 1
1929-
Seek(1);
1911+
if (second_second_counter != 0 && third_second_counter != 0 && forth_second_counter != 0 && fifth_second_counter != 0) {
1912+
// Calculate average FPS
1913+
int sum_fps = second_second_counter + third_second_counter + forth_second_counter + fifth_second_counter;
1914+
int avg_fps = round(sum_fps / 4.0f);
19301915

1931-
// exit with no changes to FPS (not enough data to calculate)
1932-
return;
1933-
}
1916+
// Update FPS
1917+
info.fps = Fraction(avg_fps, 1);
19341918

1935-
int sum_fps = second_second_counter + third_second_counter + forth_second_counter + fifth_second_counter;
1936-
int avg_fps = round(sum_fps / 4.0f);
1919+
// Update Duration and Length
1920+
info.video_length = frames_detected;
1921+
info.duration = frames_detected / round(sum_fps / 4.0f);
19371922

1938-
// Sometimes the FPS is incorrectly detected by FFmpeg. If the 1st and 2nd seconds counters
1939-
// agree with each other, we are going to adjust the FPS of this reader instance. Otherwise, print
1940-
// a warning message.
1923+
// Update video bit rate
1924+
info.video_bit_rate = info.file_size / info.duration;
1925+
} else {
19411926

1942-
// Get diff from actual frame rate
1943-
double fps = info.fps.ToDouble();
1944-
double diff = fps - double(avg_fps);
1945-
1946-
// Is difference bigger than 1 frame?
1947-
if (diff <= -1 || diff >= 1)
1948-
{
1949-
// Compare to half the frame rate (the most common type of issue)
1950-
double half_fps = Fraction(info.fps.num / 2, info.fps.den).ToDouble();
1951-
diff = half_fps - double(avg_fps);
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;
19521933

1953-
// Is difference bigger than 1 frame?
1954-
if (diff <= -1 || diff >= 1)
1955-
{
1956-
// Update FPS for this reader instance
1957-
info.fps = Fraction(avg_fps, 1);
1958-
}
1959-
else
1960-
{
1961-
// Update FPS for this reader instance (to 1/2 the original framerate)
1962-
info.fps = Fraction(info.fps.num / 2, info.fps.den);
1963-
}
1934+
// Calculate number of frames
1935+
info.video_length = frames_detected;
1936+
info.duration = frames_detected / info.video_timebase.ToFloat();
19641937
}
1965-
1966-
// Seek to frame 1
1967-
Seek(1);
19681938
}
19691939

19701940
// Remove AVFrame from cache (and deallocate it's memory)

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)