diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index b7c459f0..eee06cdb 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -85,6 +85,8 @@ namespace openshot int seeking_frame; bool is_video_seek; int seek_count; + int seek_audio_frame_found; + int seek_video_frame_found; int audio_pts_offset; int video_pts_offset; diff --git a/src/Clip.cpp b/src/Clip.cpp index 9e49cfb1..31c0fc6e 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -427,6 +427,8 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, // Add reversed samples to the frame object for (int channel = 0; channel < channels; channel++) new_frame->AddAudio(channel, 0, samples->getSampleData(channel), number_of_samples, 1.0f); + + } // clean up diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index dcc46855..48ba00e4 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -6,7 +6,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), working_cache(0), final_cache(820 * 1024), 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) { + rescaler_position(0), num_of_rescalers(32), is_open(false), seek_audio_frame_found(0), seek_video_frame_found(0) { // Init FileInfo struct (clear all values) InitFileInfo(); @@ -601,6 +601,10 @@ void FFmpegReader::ProcessVideoPacket(int requested_frame) #pragma omp critical (processing_list) processing_video_frames[current_frame] = current_frame; + // Track 1st video packet after a successful seek + if (!seek_video_frame_found) + 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) { // Create variables for a RGB Frame (since most videos are not in RGB, we must convert it) @@ -680,7 +684,9 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int #pragma omp critical (processing_list) processing_audio_frames[target_frame] = target_frame; - + // Track 1st audio packet after a successful seek + if (!seek_audio_frame_found) + seek_audio_frame_found = target_frame; // Allocate audio buffer int16_t *audio_buf = new int16_t[AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; @@ -897,6 +903,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 } else { @@ -941,6 +949,8 @@ void FFmpegReader::Seek(int requested_frame) throw(TooManySeeks) is_seeking = true; seeking_pts = seek_target; seeking_frame = requested_frame; + 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 { @@ -1133,14 +1143,26 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream) // Check if working frame is final if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || working_cache.Count() >= 200) { - // Move frame to final cache - final_cache.Add(f->number, f); + // 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; - // Remove frame from working cache - working_cache.Remove(f->number); + if (!seek_trash) + { + // Move frame to final cache + final_cache.Add(f->number, f); - // Update last frame processed - last_frame = f->number; + // Remove frame from working cache + working_cache.Remove(f->number); + + // Update last frame processed + last_frame = f->number; + } else { + // Seek trash, so delete the frame from the working cache, and never add it to the final cache. + working_cache.Remove(f->number); + } } else // Stop looping diff --git a/src/Main.cpp b/src/Main.cpp index 23e8c3b6..820375fd 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -38,19 +38,31 @@ int main() Timeline t(640, 360, Framerate(24,1)); // Add some clips - Clip c1(new FFmpegReader("/home/jonathan/Videos/sintel-1024-stereo.mp4")); + Clip c1(new FFmpegReader("/home/jonathan/Videos/sintel_trailer-720p.mp4")); c1.Position(0.0); // LINEAR Reverse //c1.time.AddPoint(1, 500, LINEAR); //c1.time.AddPoint(500, 1, LINEAR); + // LINEAR Fast Reverse (sounds wavy, due to periodic repeated frames) + //c1.time.AddPoint(1, 500, LINEAR); + //c1.time.AddPoint(500, 100, LINEAR); + + // LINEAR Slow Reverse (sounds wavy, due to periodic repeated frames) + //c1.time.AddPoint(1, 600, LINEAR); + //c1.time.AddPoint(500, 1, LINEAR); + + // BEZIER Reverse + c1.time.AddPoint(1, 500); + c1.time.AddPoint(300, 1); + c1.time.AddPoint(500, 500); // c1.time.AddPoint(1, 500, LINEAR); // c1.time.AddPoint(500, 1, LINEAR); - c1.time.AddPoint(1, 500, LINEAR); - c1.time.AddPoint(200, 200); - c1.time.AddPoint(500, 500, LINEAR); +// c1.time.AddPoint(1, 500, LINEAR); +// c1.time.AddPoint(200, 200); +// c1.time.AddPoint(500, 500, LINEAR); c1.time.PrintValues(); // Add clips