diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index 996cd85b..58c24049 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -73,6 +73,8 @@ namespace openshot Cache working_cache; map packets; map frames; + map processing_video_frames; + map processing_audio_frames; bool is_seeking; int seeking_pts; @@ -118,6 +120,12 @@ namespace openshot /// Get the next packet (if any) int GetNextPacket(); + /// Get the smallest video frame that is still being processed + int GetSmallestVideoFrame(); + + /// Get the smallest audio frame that is still being processed + int GetSmallestAudioFrame(); + /// Calculate the # of samples per video frame (for a specific frame number) int GetSamplesPerFrame(int frame_number); diff --git a/include/Frame.h b/include/Frame.h index e9da89d5..8588c93e 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -113,18 +113,6 @@ namespace openshot /// Play audio samples for this frame void Play(); - /// Set if the audio has been completely loaded into a channel (for this frame) - void SetAudioComplete(int channel); - - /// Set if the image has been completely loaded into the frame - void SetImageComplete(); - - /// Gets whether the frame has completely loaded all it's audio data (for each channel) - bool IsAudioReady(bool has_audio); - - /// Gets whether the frame has completely loaded it's image and audio data - bool IsReady(bool has_video, bool has_audio); - }; } diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index d3af08f3..2768dd95 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -516,6 +516,10 @@ void FFmpegReader::ProcessVideoPacket(int requested_frame) AVPacket *my_packet = packets[packet]; AVFrame *my_frame = frames[pFrame]; + // Add video frame to list of processing video frames + #pragma omp critical (processing_list) + processing_video_frames[current_frame] = current_frame; + #pragma omp task firstprivate(current_frame, my_last_video_frame, my_cache, my_packet, my_frame, height, width, video_length, pix_fmt) { // Create variables for a RGB Frame (since most videos are not in RGB, we must convert it) @@ -566,7 +570,6 @@ void FFmpegReader::ProcessVideoPacket(int requested_frame) f.AddImage(width, height, "RGB", Magick::CharPixel, buffer); // Update working cache - f.SetImageComplete(); my_cache->Add(f.number, f); // Update shared variable (last video frame processed) @@ -585,6 +588,10 @@ void FFmpegReader::ProcessVideoPacket(int requested_frame) RemoveAVPacket(my_packet); } + // Remove video frame from list of processing video frames + #pragma omp critical (processing_list) + processing_video_frames.erase(current_frame); + } // end omp task @@ -728,6 +735,10 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int // Get Samples per frame (for this frame number) int samples_per_frame = GetSamplesPerFrame(starting_frame_number); + // Add video frame to list of processing video frames + #pragma omp critical (processing_list) + processing_audio_frames[starting_frame_number] = starting_frame_number; + #pragma omp critical (openshot_cache) { // Create or get frame object @@ -744,26 +755,6 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int // Decrement remaining samples remaining_samples -= samples; - // DEBUG CODE - if (f.number == 3) - { - cout << "Frame 3: AddAudio (start: " << start << ", samples: " << samples << ", channel: " << channel_filter << ")" << endl; - cout << "remaining_samples: " << remaining_samples << endl; - cout << "samples_per_frame: " << samples_per_frame << endl; - cout << "start + samples: : " << start + samples << endl; - cout << "packet.pts: " << pts << endl; - } - - // Update working cache (if audio is completed for this frame + channel) - if (remaining_samples > 0 || start + samples >= samples_per_frame) - { - if (f.number == 3) - cout << "SET AUDIO COMPLETE - Channel: " << channel_filter << endl; - - // If more samples remain, this frame must all it's audio data now - f.SetAudioComplete(channel_filter); - } - // Add or update cache my_cache->Add(f.number, f); @@ -797,6 +788,14 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int if (*my_last_audio_frame < (starting_frame_number - 1)) *my_last_audio_frame = (starting_frame_number - 1); } + + // Add video frame to list of processing video frames + #pragma omp critical (processing_list) + { + // Update all frames as completed + for (int f = target_frame; f < starting_frame_number; f++) + processing_audio_frames.erase(f); + } } } @@ -1038,11 +1037,20 @@ Frame FFmpegReader::CreateFrame(int requested_frame) // Check the working queue, and move finished frames to the finished queue void FFmpegReader::CheckWorkingFrames(bool end_of_stream) { - // Adjust for video only, or audio only - if (!info.has_video) - last_video_frame = last_audio_frame; - if (!info.has_audio) - last_audio_frame = last_video_frame; + // Get the smallest processing video and audio frame numbers + int smallest_video_frame = 1; + int smallest_audio_frame = 1; + #pragma omp critical (processing_list) + { + smallest_video_frame = GetSmallestVideoFrame() - 8; // requires that at least 8 frames bigger have already been processed + smallest_audio_frame = GetSmallestAudioFrame() - 8; // requires that at least 8 frames bigger have already been processed + + // Adjust for video only, or audio only + if (!info.has_video) + smallest_video_frame = smallest_audio_frame; + if (!info.has_audio) + smallest_audio_frame = smallest_video_frame; + } // Loop through all working queue frames while (true) @@ -1053,17 +1061,10 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream) // Get the front frame of working cache Frame f = working_cache.GetSmallestFrame(); - bool is_ready = f.IsReady(info.has_video, info.has_audio); // Check if working frame is final - if (is_ready || end_of_stream) + if ((!end_of_stream && f.number < smallest_video_frame && f.number < smallest_audio_frame) || end_of_stream) { - // DEBUG - if (f.number == 3) - { - cout << "Moving frame 3 to FINAL CACHE" << endl; - } - // Move frame to final cache final_cache.Add(f.number, f); @@ -1230,4 +1231,36 @@ void FFmpegReader::RemoveAVPacket(AVPacket* remove_packet) } } +/// Get the smallest video frame that is still being processed +int FFmpegReader::GetSmallestVideoFrame() +{ + // Loop through frame numbers + map::iterator itr; + int smallest_frame = -1; + for(itr = processing_video_frames.begin(); itr != processing_video_frames.end(); ++itr) + { + if (itr->first < smallest_frame || smallest_frame == -1) + smallest_frame = itr->first; + } + + // Return frame number + return smallest_frame; +} + +/// Get the smallest audio frame that is still being processed +int FFmpegReader::GetSmallestAudioFrame() +{ + // Loop through frame numbers + map::iterator itr; + int smallest_frame = -1; + for(itr = processing_audio_frames.begin(); itr != processing_audio_frames.end(); ++itr) + { + if (itr->first < smallest_frame || smallest_frame == -1) + smallest_frame = itr->first; + } + + // Return frame number + return smallest_frame; +} + diff --git a/src/Frame.cpp b/src/Frame.cpp index 227bef53..790424de 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -336,76 +336,6 @@ void Frame::AddAudio(int destChannel, int destStartSample, const float* source, audio->addFrom(destChannel, destStartSample, source, numSamples, gainToApplyToSource); } -// Set if the audio has been completed loaded into the frame -void Frame::SetAudioComplete(int channel) -{ - // Add channel as completed - channels_complete[channel] = true; -} - -// Set if the image has been completed loaded into the frame -void Frame::SetImageComplete() -{ - image_complete = true; -} - -// Gets whether the frame has completely loaded all it's audio data (for each channel) -bool Frame::IsAudioReady(bool has_audio) -{ - if (has_audio) - { - if (number == 300) - cout << "IsAudioReady channels: " << channels_complete.size() << endl; - - // Do all channels have audio loaded? - if (channels_complete.size() == channels) - return true; - else - // still waiting on some channel to be loaded - return false; - } - else - // No audio needed for this frame - return true; -} - -// Gets whether the frame has completed loading it's image and audio data -bool Frame::IsReady(bool has_video, bool has_audio) -{ - if (has_video && has_audio) - { - // Does the frame have both audio and image data? - if (image_complete && IsAudioReady(has_audio)) - return true; - else - return false; - - } - else if (has_video) - { - // Does the frame have image data? - if (image_complete) - return true; - else - return false; - - } - else if (has_audio) - { - // Does the frame have audio data? - if (IsAudioReady(has_audio)) - return true; - else - return false; - - } - else - { - // Invalid - return false; - } -} - // Play audio samples for this frame void Frame::Play() { diff --git a/src/Main.cpp b/src/Main.cpp index a92f16d4..75c6f455 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -13,7 +13,6 @@ void FrameReady(int number) int main() { - // openshot::FFmpegReader r("/home/jonathan/Apps/libopenshot/src/examples/test.mp4"); // openshot::FFmpegReader r("/home/jonathan/Apps/libopenshot/src/examples/test1.mp4"); // openshot::FFmpegReader r("/home/jonathan/Apps/libopenshot/src/examples/piano.wav");