diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index 2a05bd57..b74d66fc 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -186,6 +186,9 @@ namespace openshot /// Init a collection of software rescalers (thread safe) void InitScalers(); + /// Remove partial frames due to seek + bool IsPartialFrame(int requested_frame); + /// Process a video packet void ProcessVideoPacket(int requested_frame); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3764a8ec..19d9e33a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,13 +73,6 @@ FIND_PACKAGE(OpenShotAudio REQUIRED) include_directories(${LIBOPENSHOT_AUDIO_INCLUDE_DIRS}) ################# QT5 ################### -# As moc files are generated in the binary dir, tell CMake -# to always look for includes there: -#set(CMAKE_INCLUDE_CURRENT_DIR ON) - -#set(CMAKE_AUTOMOC ON) -#set (CMAKE_PREFIX_PATH "/usr/local/Cellar/qt5/5.1.1/") - # Find QT5 libraries find_package(Qt5Widgets REQUIRED) find_package(Qt5Core REQUIRED) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index c1d3db1a..c0cd735b 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -36,7 +36,7 @@ FFmpegReader::FFmpegReader(string path) throw(InvalidFile, NoStreamsFound, Inval : last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0), seek_count(0), audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false), check_fps(false), enable_seek(true), rescaler_position(0), num_of_rescalers(32), is_open(false), - seek_audio_frame_found(-1), seek_video_frame_found(-1), resampleCtx(NULL), prev_samples(0), prev_pts(0), + seek_audio_frame_found(0), seek_video_frame_found(0), resampleCtx(NULL), prev_samples(0), prev_pts(0), pts_total(0), pts_counter(0), is_duration_known(false), largest_frame_processed(0) { // Initialize FFMpeg, and register all formats and codecs @@ -670,7 +670,7 @@ bool FFmpegReader::CheckSeek(bool is_video) { // Determine if both an audio and video packet have been decoded since the seek happened. // If not, allow the ReadStream method to keep looping - if ((is_video_seek && seek_video_frame_found == 0) || (!is_video_seek && seek_audio_frame_found == 0)) + if ((is_video_seek && !seek_video_frame_found) || (!is_video_seek && !seek_audio_frame_found)) return false; // CHECK VIDEO SEEK? @@ -693,7 +693,7 @@ bool FFmpegReader::CheckSeek(bool is_video) } else { - // SEEKED TOO FAR + // SEEK WORKED #pragma omp critical (debug_output) AppendDebugMethod("FFmpegReader::CheckSeek (Successful)", "current_pts", current_pts, "seeking_pts", seeking_pts, "seeking_frame", seeking_frame, "", -1, "", -1, "", -1); @@ -701,8 +701,8 @@ bool FFmpegReader::CheckSeek(bool is_video) is_seeking = false; seeking_frame = 0; seeking_pts = -1; - seek_audio_frame_found = -1; // used to detect which frames to throw away after a seek - seek_video_frame_found = -1; // used to detect which frames to throw away after a seek + //seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek + //seek_video_frame_found = 0; // used to detect which frames to throw away after a seek } } @@ -758,7 +758,7 @@ void FFmpegReader::ProcessVideoPacket(int requested_frame) processing_video_frames[current_frame] = current_frame; // Track 1st video packet after a successful seek - if (!seek_video_frame_found) + if (!seek_video_frame_found && is_seeking) seek_video_frame_found = current_frame; #pragma omp task firstprivate(current_frame, my_cache, my_packet, my_frame, height, width, video_length, pix_fmt, img_convert_ctx) @@ -852,7 +852,7 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int processing_audio_frames[target_frame] = target_frame; // Track 1st audio packet after a successful seek - if (!seek_audio_frame_found) + if (!seek_audio_frame_found && is_seeking) seek_audio_frame_found = target_frame; // Debug output @@ -1135,8 +1135,8 @@ void FFmpegReader::Seek(int requested_frame) throw(TooManySeeks) is_seeking = false; seeking_frame = 1; seeking_pts = ConvertFrameToVideoPTS(1); - seek_audio_frame_found = -1; // used to detect which frames to throw away after a seek - seek_video_frame_found = -1; // used to detect which frames to throw away after a seek + seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek + seek_video_frame_found = 0; // used to detect which frames to throw away after a seek } else { @@ -1372,6 +1372,21 @@ tr1::shared_ptr FFmpegReader::CreateFrame(int requested_frame) } } +// Determine if frame is partial due to seek +bool FFmpegReader::IsPartialFrame(int requested_frame) { + + // Sometimes a seek gets partial frames, and we need to remove them + bool seek_trash = false; + int max_seeked_frame = seek_audio_frame_found; // determine max seeked frame + if (seek_video_frame_found > max_seeked_frame) + max_seeked_frame = seek_video_frame_found; + if ((info.has_audio && seek_audio_frame_found && max_seeked_frame >= requested_frame) || + (info.has_video && seek_video_frame_found && max_seeked_frame >= requested_frame)) + seek_trash = true; + + return seek_trash; +} + // Check the working queue, and move finished frames to the finished queue void FFmpegReader::CheckWorkingFrames(bool end_of_stream) { @@ -1388,25 +1403,20 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream) bool is_video_ready = processed_video_frames.count(f->number); bool is_audio_ready = processed_audio_frames.count(f->number); + bool is_seek_trash = IsPartialFrame(f->number); // Debug output #pragma omp critical (debug_output) AppendDebugMethod("FFmpegReader::CheckWorkingFrames", "frame_number", f->number, "is_video_ready", is_video_ready, "is_audio_ready", is_audio_ready, "processed_video_frames.count(f->number)", processed_video_frames.count(f->number), "processed_audio_frames.count(f->number)", processed_audio_frames.count(f->number), "", -1); // Check if working frame is final - if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || working_cache.Count() >= 200) + if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || is_seek_trash || working_cache.Count() >= 200) { - // Sometimes a seek gets partial frames, and we need to remove them - bool seek_trash = false; - if ((info.has_audio && seek_audio_frame_found != 0 && seek_audio_frame_found >= f->number) || - (info.has_video && seek_video_frame_found != 0 && seek_video_frame_found >= f->number)) - seek_trash = true; - // Debug output #pragma omp critical (debug_output) - AppendDebugMethod("FFmpegReader::CheckWorkingFrames (mark frame as final)", "f->number", f->number, "seek_trash", seek_trash, "Working Cache Count", working_cache.Count(), "Final Cache Count", final_cache.Count(), "seek_trash", seek_trash, "", -1); + AppendDebugMethod("FFmpegReader::CheckWorkingFrames (mark frame as final)", "f->number", f->number, "is_seek_trash", is_seek_trash, "Working Cache Count", working_cache.Count(), "Final Cache Count", final_cache.Count(), "", -1, "", -1); - if (!seek_trash) + if (!is_seek_trash) { // Move frame to final cache final_cache.Add(f->number, f); diff --git a/src/Main.cpp b/src/Main.cpp index 0a2d697d..44bfd70b 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -47,18 +47,15 @@ int main(int argc, char* argv[]) sinelReader.GetFrame(300)->Display(); sinelReader.GetFrame(301)->Display(); - sinelReader.GetFrame(302)->Display(); - sinelReader.GetFrame(303)->Display(); sinelReader.GetFrame(100)->Display(); sinelReader.GetFrame(101)->Display(); - sinelReader.GetFrame(102)->Display(); - sinelReader.GetFrame(103)->Display(); - sinelReader.GetFrame(500)->Display(); - sinelReader.GetFrame(501)->Display(); - sinelReader.GetFrame(502)->Display(); - sinelReader.GetFrame(503)->Display(); + sinelReader.GetFrame(600)->Display(); + sinelReader.GetFrame(601)->Display(); + + sinelReader.GetFrame(380)->Display(); + sinelReader.GetFrame(381)->Display(); cout << sinelReader.OutputDebugJSON() << endl;; sinelReader.Close(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b2d507fb..6753ffbf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -72,36 +72,43 @@ FIND_PACKAGE(OpenShotAudio REQUIRED) include_directories(${LIBOPENSHOT_AUDIO_INCLUDE_DIRS}) ################# QT5 ################### -set(CMAKE_AUTOMOC ON) - # Find QT5 libraries -find_package(Qt5Widgets) -find_package(Qt5Core) -find_package(Qt5Gui) -find_package(Qt5Multimedia) +find_package(Qt5Widgets REQUIRED) +find_package(Qt5Core REQUIRED) +find_package(Qt5Gui REQUIRED) +find_package(Qt5Multimedia REQUIRED) +find_package(Qt5MultimediaWidgets REQUIRED) # Include Qt headers (needed for compile) include_directories(${Qt5Widgets_INCLUDE_DIRS}) include_directories(${Qt5Core_INCLUDE_DIRS}) include_directories(${Qt5Gui_INCLUDE_DIRS}) include_directories(${Qt5Multimedia_INCLUDE_DIRS}) +include_directories(${Qt5MultimediaWidgets_INCLUDE_DIRS}) add_definitions(${Qt5Widgets_DEFINITIONS}) add_definitions(${Qt5Core_DEFINITIONS}) add_definitions(${Qt5Gui_DEFINITIONS}) add_definitions(${Qt5Multimedia_DEFINITIONS}) +add_definitions(${Qt5MultimediaWidgets_DEFINITIONS}) -# Add Multimedia library SET(QT_LIBRARIES ${Qt5Widgets_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} - ${Qt5Multimedia_LIBRARIES}) + ${Qt5Multimedia_LIBRARIES} + ${Qt5MultimediaWidgets_LIBRARIES}) # Set compiler flags for Qt set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS} ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS} ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Gui_EXECUTABLE_COMPILE_FLAGS} ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Multimedia_EXECUTABLE_COMPILE_FLAGS} ") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5MultimediaWidgets_EXECUTABLE_COMPILE_FLAGS} ") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb ") + +# Manually moc Qt files +qt5_wrap_cpp(MOC_FILES ${QT_HEADER_FILES}) + ################# BLACKMAGIC DECKLINK ################### IF (ENABLE_BLACKMAGIC)