diff --git a/include/DecklinkInput.h b/include/DecklinkInput.h index 6cb970d8..84cf1991 100644 --- a/include/DecklinkInput.h +++ b/include/DecklinkInput.h @@ -73,11 +73,11 @@ #include #include #include -#include #include "DeckLinkAPI.h" #include "../include/Frame.h" #include "../include/Cache.h" +#include "../include/OpenMPUtilities.h" /// Implementation of the Blackmagic Decklink API (used by the DecklinkReader) class DeckLinkInputDelegate : public IDeckLinkInputCallback diff --git a/include/DecklinkOutput.h b/include/DecklinkOutput.h index 9bef4736..75f7995d 100644 --- a/include/DecklinkOutput.h +++ b/include/DecklinkOutput.h @@ -73,12 +73,12 @@ #include #include #include -#include #include "Magick++.h" #include "DeckLinkAPI.h" #include "../include/Cache.h" #include "../include/Frame.h" +#include "../include/OpenMPUtilities.h" enum OutputSignal { kOutputSignalPip = 0, diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index c0fadc9f..ade88d6f 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -52,12 +52,12 @@ #include #include #include -#include #include #include #include "Magick++.h" #include "Cache.h" #include "Exceptions.h" +#include "OpenMPUtilities.h" #include "Sleep.h" diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index fe22b827..5b4c7882 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -58,12 +58,12 @@ #include #include #include -#include #include #include #include "Magick++.h" #include "Cache.h" #include "Exceptions.h" +#include "OpenMPUtilities.h" #include "Sleep.h" diff --git a/include/OpenMPUtilities.h b/include/OpenMPUtilities.h new file mode 100644 index 00000000..44290b96 --- /dev/null +++ b/include/OpenMPUtilities.h @@ -0,0 +1,50 @@ +/** + * @file + * @brief Header file for OpenMPUtilities (set some common macros) + * @author Jonathan Thomas + * + * @section LICENSE + * + * Copyright (c) 2008-2014 OpenShot Studios, LLC + * . This file is part of + * OpenShot Library (libopenshot), an open-source project dedicated to + * delivering high quality video editing and animation solutions to the + * world. For more information visit . + * + * OpenShot Library (libopenshot) is free software: you can redistribute it + * and/or modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * OpenShot Library (libopenshot) is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with OpenShot Library. If not, see . + * + * Also, if your software can interact with users remotely through a computer + * network, you should also make sure that it provides a way for users to + * get its source. For example, if your program is a web application, its + * interface could display a "Source" link that leads users to an archive + * of the code. There are many ways you could offer source, and different + * solutions will be better for different programs; see section 13 for the + * specific requirements. + * + * You should also get your employer (if you work as a programmer) or school, + * if any, to sign a "copyright disclaimer" for the program, if necessary. + * For more information on this, and how to apply and follow the GNU AGPL, see + * . + */ + +#ifndef OPENSHOT_OPENMP_UTILITIES_H +#define OPENSHOT_OPENMP_UTILITIES_H + +#include + + // Calculate the # of OpenMP Threads to allow (HACK / WORK-AROUND for an ImageMagick bug: preventing use of all 8 cores) + #define OPEN_MP_NUM_PROCESSORS (omp_get_num_procs() <= 4 ? omp_get_num_procs() : 4) + //#define OPEN_MP_NUM_PROCESSORS 1 + +#endif diff --git a/include/Qt/AudioPlaybackThread.h b/include/Qt/AudioPlaybackThread.h index 3c9a67f1..d6d92b3c 100644 --- a/include/Qt/AudioPlaybackThread.h +++ b/include/Qt/AudioPlaybackThread.h @@ -95,6 +95,7 @@ namespace openshot int getSpeed() const { if (source) return source->getSpeed(); else return 1; } friend class PlayerPrivate; + friend class QtPlayer; }; } diff --git a/include/Qt/PlayerPrivate.h b/include/Qt/PlayerPrivate.h index ae4f9e94..67cb38dc 100644 --- a/include/Qt/PlayerPrivate.h +++ b/include/Qt/PlayerPrivate.h @@ -74,9 +74,6 @@ namespace openshot /// Start thread void run(); - /// Seek to a frame - void Seek(int new_position); - /// Start the video/audio playback bool startPlayback(); @@ -86,14 +83,6 @@ namespace openshot /// Get the next frame (based on speed and direction) tr1::shared_ptr getFrame(); - /// Set Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) - void Speed(int new_speed); - /// Get Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) - int Speed() const { return speed; } - - /// Set the current reader - void Reader(ReaderBase *new_reader); - /// The parent class of PlayerPrivate friend class QtPlayer; }; diff --git a/include/Qt/VideoPlaybackThread.h b/include/Qt/VideoPlaybackThread.h index 01beb4fb..b76c89f1 100644 --- a/include/Qt/VideoPlaybackThread.h +++ b/include/Qt/VideoPlaybackThread.h @@ -74,6 +74,7 @@ namespace openshot /// Parent class of VideoPlaybackThread friend class PlayerPrivate; + friend class QtPlayer; }; } diff --git a/include/QtPlayer.h b/include/QtPlayer.h index 83edd182..c42d82ef 100644 --- a/include/QtPlayer.h +++ b/include/QtPlayer.h @@ -95,6 +95,9 @@ namespace openshot /// This is required due to SIP and SWIG incompatibility in the Python bindings. void SetQWidget(long qwidget_address); + /// Get the Renderer pointer address (for Python to cast back into a QObject) + long GetRendererQObject(); + /// Get the Playback speed float Speed(); diff --git a/include/Timeline.h b/include/Timeline.h index 79786c20..ed474989 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -50,7 +50,6 @@ #endif #include -#include #include #include "Magick++.h" #include "Cache.h" @@ -62,6 +61,7 @@ #include "Fraction.h" #include "Frame.h" #include "KeyFrame.h" +#include "OpenMPUtilities.h" #include "ReaderBase.h" using namespace std; diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp index 2cadd123..2bc13548 100644 --- a/src/AudioReaderSource.cpp +++ b/src/AudioReaderSource.cpp @@ -124,12 +124,12 @@ void AudioReaderSource::GetMoreSamplesFromReader() { // Load all of its samples into the buffer for (int channel = 0; channel < new_buffer->getNumChannels(); channel++) - if (speed >= 0) + //if (speed >= 0) // playback normal new_buffer->addFrom(channel, position, *frame->GetAudioSampleBuffer(), channel, frame_position, amount_to_copy); - else + //else // reverse playback - new_buffer->addFrom(channel, position, *reverse_buffer(frame->GetAudioSampleBuffer()), channel, frame_position, amount_to_copy); + //new_buffer->addFrom(channel, position, *reverse_buffer(frame->GetAudioSampleBuffer()), channel, frame_position, amount_to_copy); // Adjust remaining samples position += amount_to_copy; diff --git a/src/DecklinkInput.cpp b/src/DecklinkInput.cpp index 2c654a6e..5c545a53 100644 --- a/src/DecklinkInput.cpp +++ b/src/DecklinkInput.cpp @@ -201,7 +201,7 @@ HRESULT DeckLinkInputDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* // Process frames once we have a few (to take advantage of multiple threads) int number_to_process = raw_video_frames.size(); - if (number_to_process >= omp_get_num_procs()) + if (number_to_process >= OPEN_MP_NUM_PROCESSORS) { //omp_set_num_threads(1); diff --git a/src/DecklinkOutput.cpp b/src/DecklinkOutput.cpp index 3421b36d..e639d905 100644 --- a/src/DecklinkOutput.cpp +++ b/src/DecklinkOutput.cpp @@ -217,7 +217,7 @@ void DeckLinkOutputDelegate::WriteFrame(tr1::shared_ptr frame) // Process frames once we have a few (to take advantage of multiple threads) - if (raw_video_frames.size() >= omp_get_num_procs()) + if (raw_video_frames.size() >= OPEN_MP_NUM_PROCESSORS) { //omp_set_num_threads(1); diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 6fd92ccc..cae00b56 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -172,7 +172,7 @@ void FFmpegReader::Open() throw(InvalidFile, NoStreamsFound, InvalidCodec) pCodecCtx = pFormatCtx->streams[videoStream]->codec; // Set number of threads equal to number of processors + 1 - pCodecCtx->thread_count = omp_get_num_procs() / 2; + pCodecCtx->thread_count = OPEN_MP_NUM_PROCESSORS; // Find the decoder for the video stream AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id); @@ -201,7 +201,7 @@ void FFmpegReader::Open() throw(InvalidFile, NoStreamsFound, InvalidCodec) aCodecCtx = pFormatCtx->streams[audioStream]->codec; // Set number of threads equal to number of processors + 1 - aCodecCtx->thread_count = omp_get_num_procs() / 2; + aCodecCtx->thread_count = OPEN_MP_NUM_PROCESSORS; // Find the decoder for the audio stream AVCodec *aCodec = avcodec_find_decoder(aCodecCtx->codec_id); @@ -466,13 +466,15 @@ tr1::shared_ptr FFmpegReader::ReadStream(int requested_frame) // Minimum number of packets to process (for performance reasons) int packets_processed = 0; - int minimum_packets = omp_get_num_procs() / 2; // DEBUG, WORK-AROUND for an ImageMagick bug (preventing use of all 8 cores) - omp_set_num_threads(minimum_packets); // DEBUG, WORK-AROUND for an ImageMagick bug (preventing use of all 8 cores) + int minimum_packets = OPEN_MP_NUM_PROCESSORS; + + // Set the number of threads in OpenMP + omp_set_num_threads(OPEN_MP_NUM_PROCESSORS); + // Allow nested OpenMP sections omp_set_nested(true); #pragma omp parallel { - #pragma omp single { // Loop through the stream until the correct frame is found diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index d709ee41..7e61d355 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -354,8 +354,11 @@ void FFmpegWriter::write_queued_frames() spooled_video_frames.clear(); spooled_audio_frames.clear(); - omp_set_num_threads(omp_get_num_procs() / 2); + // Set the number of threads in OpenMP + omp_set_num_threads(OPEN_MP_NUM_PROCESSORS); + // Allow nested OpenMP sections omp_set_nested(true); + #pragma omp parallel { #pragma omp single @@ -877,7 +880,7 @@ void FFmpegWriter::open_audio(AVFormatContext *oc, AVStream *st) audio_codec = st->codec; // Set number of threads equal to number of processors + 1 - audio_codec->thread_count = omp_get_num_procs() / 2; + audio_codec->thread_count = OPEN_MP_NUM_PROCESSORS; // Find the audio encoder codec = avcodec_find_encoder(audio_codec->codec_id); @@ -928,7 +931,7 @@ void FFmpegWriter::open_video(AVFormatContext *oc, AVStream *st) video_codec = st->codec; // Set number of threads equal to number of processors + 1 - video_codec->thread_count = omp_get_num_procs() / 2; + video_codec->thread_count = OPEN_MP_NUM_PROCESSORS; /* find the video encoder */ codec = avcodec_find_encoder(video_codec->codec_id); diff --git a/src/Qt/PlayerPrivate.cpp b/src/Qt/PlayerPrivate.cpp index d7f6b9b5..6090e606 100644 --- a/src/Qt/PlayerPrivate.cpp +++ b/src/Qt/PlayerPrivate.cpp @@ -64,13 +64,14 @@ namespace openshot // Start thread void PlayerPrivate::run() { + // bail if no reader set + if (!reader) + return; + // Kill audio and video threads (if they are currently running) if (audioPlayback->isThreadRunning() && reader->info.has_audio) audioPlayback->stopThread(-1); if (videoPlayback->isThreadRunning() && reader->info.has_video) videoPlayback->stopThread(-1); - // Set the reader for the Audio thread - audioPlayback->Reader(reader); - // Start the threads if (reader->info.has_audio) audioPlayback->startThread(1); @@ -125,6 +126,10 @@ namespace openshot // the video to catch up. sleep_time += (video_frame_diff * (1000.0 / reader->info.fps.ToDouble())); + //else if (video_frame_diff < 4) + // Video is too far behind, so skip to the current frame + //video_position += (abs(video_frame_diff) - speed); + // Sleep (leaving the video frame on the screen for the correct amount of time) if (sleep_time > 0) sleep(sleep_time); @@ -132,8 +137,6 @@ namespace openshot std::cout << "video frame diff: " << video_frame_diff << std::endl; } - - std::cout << "stopped thread" << endl; // Kill audio and video threads (if they are still running) if (audioPlayback->isThreadRunning() && reader->info.has_audio) audioPlayback->stopThread(-1); @@ -144,7 +147,6 @@ namespace openshot tr1::shared_ptr PlayerPrivate::getFrame() { try { - // Get the next frame (based on speed) video_position = video_position + speed; return reader->GetFrameSafe(video_position); @@ -171,36 +173,8 @@ namespace openshot // Stop video/audio playback void PlayerPrivate::stopPlayback(int timeOutMilliseconds) { - std::cout << "stop playback!!!" << std::endl; if (isThreadRunning()) stopThread(timeOutMilliseconds); } - // Seek to a frame - void PlayerPrivate::Seek(int new_position) - { - // Check for seek - if (new_position > 0) { - // Update current position - video_position = new_position; - - // Notify audio thread that seek has occured - audioPlayback->Seek(video_position); - } - } - - // Set Speed (The speed and direction to playback a reader (1=normal, 2=fast, 3=faster, -1=rewind, etc...) - void PlayerPrivate::Speed(int new_speed) - { - speed = new_speed; - if (reader->info.has_audio) - audioPlayback->setSpeed(new_speed); - } - - // Set the reader object - void PlayerPrivate::Reader(ReaderBase *new_reader) - { - reader = new_reader; - audioPlayback->Reader(new_reader); - } } diff --git a/src/QtPlayer.cpp b/src/QtPlayer.cpp index 6cb45734..adf65a23 100644 --- a/src/QtPlayer.cpp +++ b/src/QtPlayer.cpp @@ -68,7 +68,8 @@ void QtPlayer::SetSource(const std::string &source) { reader = new FFmpegReader(source); reader->Open(); - p->Reader(reader); + //reader->info.has_video = false; + Reader(reader); } void QtPlayer::Play() @@ -76,7 +77,6 @@ void QtPlayer::Play() cout << "PLAY() on QTPlayer" << endl; if (reader && !threads_started) { mode = PLAYBACK_PLAY; - p->Reader(reader); p->startPlayback(); threads_started = true; } else { @@ -109,8 +109,14 @@ int QtPlayer::Position() void QtPlayer::Seek(int new_frame) { - // Seek the reader to a new position - p->Seek(new_frame); + // Check for seek + if (new_frame > 0) { + // Update current position + p->video_position = new_frame; + + // Notify audio thread that seek has occured + p->audioPlayback->Seek(new_frame); + } } void QtPlayer::Stop() @@ -124,8 +130,10 @@ void QtPlayer::Stop() // Set the reader object void QtPlayer::Reader(ReaderBase *new_reader) { + cout << "Reader SET: " << new_reader << endl; reader = new_reader; - p->Reader(new_reader); + p->reader = new_reader; + p->audioPlayback->Reader(new_reader); } // Get the current reader, such as a FFmpegReader @@ -139,6 +147,11 @@ void QtPlayer::SetQWidget(long qwidget_address) { p->renderer->OverrideWidget(qwidget_address); } +// Get the Renderer pointer address (for Python to cast back into a QObject) +long QtPlayer::GetRendererQObject() { + return (long) (VideoRenderer*)p->renderer; +} + // Get the Playback speed float QtPlayer::Speed() { return speed; @@ -147,7 +160,9 @@ float QtPlayer::Speed() { // Set the Playback speed multiplier (1.0 = normal speed, <1.0 = slower, >1.0 faster) void QtPlayer::Speed(float new_speed) { speed = new_speed; - p->Speed(new_speed); + p->speed = new_speed; + if (p->reader->info.has_audio) + p->audioPlayback->setSpeed(new_speed); } // Get the Volume diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 794d58aa..79bef3dc 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -452,11 +452,11 @@ tr1::shared_ptr Timeline::GetFrame(int requested_frame) throw(ReaderClose else { // Minimum number of packets to process (for performance reasons) - //int minimum_frames = omp_get_num_procs() / 2; + //int minimum_frames = OPEN_MP_NUM_PROCESSORS; int minimum_frames = 1; - //omp_set_num_threads(1); omp_set_nested(true); + #pragma xx omp parallel { #pragma xx omp single