From cdde046ca4e0bf3b0a6804c6f617ab37e9546d46 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Wed, 6 Nov 2013 23:17:35 -0600 Subject: [PATCH] Added PlayerBase, SDLPlayer, and QtPlayer. This forms the basis for the Player classes in libopenshot. --- include/OpenShot.h | 3 +- include/PlayerBase.h | 108 +++++++++++++++++ include/{Player.h => QtPlayer.h} | 2 +- include/SDLPlayer.h | 81 +++++++++++++ src/CMakeLists.txt | 3 +- src/Main.cpp | 9 ++ src/PlayerBase.cpp | 80 ++++++++++++ src/{Player.cpp => QtPlayer.cpp} | 2 +- src/SDLPlayer.cpp | 201 +++++++++++++++++++++++++++++++ src/openshot.i | 6 +- tests/FrameMapper_Tests.cpp | 37 ------ 11 files changed, 489 insertions(+), 43 deletions(-) create mode 100644 include/PlayerBase.h rename include/{Player.h => QtPlayer.h} (98%) create mode 100644 include/SDLPlayer.h create mode 100644 src/PlayerBase.cpp rename src/{Player.cpp => QtPlayer.cpp} (99%) create mode 100644 src/SDLPlayer.cpp diff --git a/include/OpenShot.h b/include/OpenShot.h index da020e37..23c59067 100644 --- a/include/OpenShot.h +++ b/include/OpenShot.h @@ -116,8 +116,9 @@ #include "FrameRate.h" #include "ImageReader.h" #include "KeyFrame.h" -#include "Player.h" +#include "PlayerBase.h" #include "Point.h" +#include "SDLPlayer.h" #include "Sleep.h" #include "TextReader.h" #include "Timeline.h" diff --git a/include/PlayerBase.h b/include/PlayerBase.h new file mode 100644 index 00000000..c6d938f1 --- /dev/null +++ b/include/PlayerBase.h @@ -0,0 +1,108 @@ +/** + * @file + * @brief Header file for PlayerBase class + * @author Jonathan Thomas + * + * @section LICENSE + * + * Copyright (c) 2008-2013 OpenShot Studios, LLC + * (http://www.openshotstudios.com). This file is part of + * OpenShot Library (http://www.openshot.org), an open-source project + * dedicated to delivering high quality video editing and animation solutions + * to the world. + * + * OpenShot Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenShot Library. If not, see . + */ + +#ifndef OPENSHOT_PLAYER_BASE_H +#define OPENSHOT_PLAYER_BASE_H + +#include +#include "../include/ReaderBase.h" + +using namespace std; + +namespace openshot +{ + /** + * @brief This enumeration determines the mode of the video player (i.e. playing, paused, etc...) + * + * A player can be in one of the following modes, which controls how it behaves. + */ + enum PlaybackMode + { + PLAYBACK_PLAY, ///< Play the video normally + PLAYBACK_PAUSED, ///< Pause the video (holding the last displayed frame) + PLAYBACK_LOADING, ///< Loading the video (display a loading animation) + PLAYBACK_STOPPED, ///< Stop playing the video (clear cache, done with player) + }; + + /** + * @brief This is the base class of all Players in libopenshot. + * + * Players are responsible for displaying images and playing back audio samples with specific + * frame rates and sample rates. All Players must be based on this class, and include these + * methods. + */ + class PlayerBase + { + protected: + float speed; + float volume; + ReaderBase *reader; + PlaybackMode mode; + + public: + + /// Display a loading animation + virtual void Loading() = 0; + + /// Play the video + virtual void Play() = 0; + + /// Pause the video + virtual void Pause() = 0; + + /// Get the current frame number being played + virtual int Position() = 0; + + /// Seek to a specific frame in the player + virtual void Seek(int new_frame) = 0; + + /// Get the Playback speed + float Speed(); + + /// Set the Playback speed (1.0 = normal speed, <1.0 = slower, >1.0 faster) + void Speed(float new_speed); + + /// Stop the video player and clear the cached frames + virtual void Stop() = 0; + + /// Get the current reader, such as a FFmpegReader + ReaderBase* Reader(); + + /// Set the current reader, such as a FFmpegReader + void Reader(ReaderBase *new_reader); + + /// Get the Volume + float Volume(); + + /// Set the Volume (1.0 = normal volume, <1.0 = quieter, >1.0 louder) + void Volume(float new_volume); + + }; + +} + +#endif diff --git a/include/Player.h b/include/QtPlayer.h similarity index 98% rename from include/Player.h rename to include/QtPlayer.h index 8c6cfb06..531bad2f 100644 --- a/include/Player.h +++ b/include/QtPlayer.h @@ -1,6 +1,6 @@ /** * @file - * @brief Header file for Player class + * @brief Header file for QtPlayer class * @author Jonathan Thomas * * @section LICENSE diff --git a/include/SDLPlayer.h b/include/SDLPlayer.h new file mode 100644 index 00000000..a0c78c09 --- /dev/null +++ b/include/SDLPlayer.h @@ -0,0 +1,81 @@ +/** + * @file + * @brief Header file for SDLPlayer class + * @author Jonathan Thomas + * + * @section LICENSE + * + * Copyright (c) 2008-2013 OpenShot Studios, LLC + * (http://www.openshotstudios.com). This file is part of + * OpenShot Library (http://www.openshot.org), an open-source project + * dedicated to delivering high quality video editing and animation solutions + * to the world. + * + * OpenShot Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenShot Library. If not, see . + */ + +#ifndef OPENSHOT_SDL_PLAYER_H +#define OPENSHOT_SDL_PLAYER_H + +#include +#include +#include "../include/PlayerBase.h" +#include "../include/ReaderBase.h" + +#define _SDL_main_h // This prevents SDL_main from replacing our main() function. +#include +#include + +using namespace std; + +namespace openshot +{ + /** + * @brief Player to display a video using SDL (Simple DirectMedia Layer) + * + * This player uses the SDL (Simple DirectMedia Layer) library to display the video. It uses + * an image overlay with YUV420 colorspace, and draws the video to any X11 window you specify. + */ + class SDLPlayer : public PlayerBase + { + private: + int position; ///< Current frame number being played + + public: + /// Default constructor + SDLPlayer(); + + /// Play the video + void Play(); + + /// Display a loading animation + void Loading(); + + /// Pause the video + void Pause(); + + /// Get the current frame number being played + int Position(); + + /// Seek to a specific frame in the player + void Seek(int new_frame); + + /// Stop the video player and clear the cached frames + void Stop(); + + }; + +} + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7aa99535..3abe2b21 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -128,8 +128,9 @@ SET ( OPENSHOT_SOURCE_FILES FrameRate.cpp KeyFrame.cpp ImageReader.cpp - Player.cpp + PlayerBase.cpp Point.cpp + SDLPlayer.cpp TextReader.cpp Timeline.cpp diff --git a/src/Main.cpp b/src/Main.cpp index d77c6316..6bd70561 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -41,6 +41,15 @@ using namespace tr1; int main(int argc, char* argv[]) { + FFmpegReader r2("/home/jonathan/Videos/sintel_trailer-720p.mp4"); + r2.Open(); + SDLPlayer p; + p.Reader(&r2); + p.Play(); + return 0; + + + // Image of interlaced frame // ImageReader ir("/home/jonathan/apps/libopenshot/src/examples/interlaced.png"); // ir.Open(); diff --git a/src/PlayerBase.cpp b/src/PlayerBase.cpp new file mode 100644 index 00000000..10a56028 --- /dev/null +++ b/src/PlayerBase.cpp @@ -0,0 +1,80 @@ +/** + * @file + * @brief Source file for PlayerBase class + * @author Jonathan Thomas + * + * @section LICENSE + * + * Copyright (c) 2008-2013 OpenShot Studios, LLC + * (http://www.openshotstudios.com). This file is part of + * OpenShot Library (http://www.openshot.org), an open-source project + * dedicated to delivering high quality video editing and animation solutions + * to the world. + * + * OpenShot Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenShot Library. If not, see . + */ + +#include "../include/PlayerBase.h" + +using namespace openshot; + +// Display a loading animation +void PlayerBase::Loading() { + mode = PLAYBACK_LOADING; +} + +// Play the video +void PlayerBase::Play() { + mode = PLAYBACK_PLAY; +} + +// Pause the video +void PlayerBase::Pause() { + mode = PLAYBACK_PAUSED; +} + +// Get the Playback speed +float PlayerBase::Speed() { + return speed; +} + +// Set the Playback speed multiplier (1.0 = normal speed, <1.0 = slower, >1.0 faster) +void PlayerBase::Speed(float new_speed) { + speed = new_speed; +} + +// Stop the video player and clear the cached frames +void PlayerBase::Stop() { + mode = PLAYBACK_STOPPED; +} + +// Get the current reader, such as a FFmpegReader +ReaderBase* PlayerBase::Reader() { + return reader; +} + +// Set the current reader, such as a FFmpegReader +void PlayerBase::Reader(ReaderBase *new_reader) { + reader = new_reader; +} + +// Get the Volume +float PlayerBase::Volume() { + return volume; +} + +// Set the Volume multiplier (1.0 = normal volume, <1.0 = quieter, >1.0 louder) +void PlayerBase::Volume(float new_volume) { + volume = new_volume; +} diff --git a/src/Player.cpp b/src/QtPlayer.cpp similarity index 99% rename from src/Player.cpp rename to src/QtPlayer.cpp index 99c4f87e..8b17c85f 100644 --- a/src/Player.cpp +++ b/src/QtPlayer.cpp @@ -1,6 +1,6 @@ /** * @file - * @brief Source file for Player class + * @brief Source file for QtPlayer class * @author Jonathan Thomas * * @section LICENSE diff --git a/src/SDLPlayer.cpp b/src/SDLPlayer.cpp new file mode 100644 index 00000000..9bebc849 --- /dev/null +++ b/src/SDLPlayer.cpp @@ -0,0 +1,201 @@ +/** + * @file + * @brief Source file for SDLPlayer class + * @author Jonathan Thomas + * + * @section LICENSE + * + * Copyright (c) 2008-2013 OpenShot Studios, LLC + * (http://www.openshotstudios.com). This file is part of + * OpenShot Library (http://www.openshot.org), an open-source project + * dedicated to delivering high quality video editing and animation solutions + * to the world. + * + * OpenShot Library is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenShot Library. If not, see . + */ + +#include "../include/SDLPlayer.h" + +using namespace openshot; + +// Default constructor +SDLPlayer::SDLPlayer() { + +}; + +// Display a loading animation +void SDLPlayer::Loading() { + mode = PLAYBACK_LOADING; +} + +// Pause the video +void SDLPlayer::Pause() { + mode = PLAYBACK_PAUSED; +} + +// Stop the video player and clear the cached frames +void SDLPlayer::Stop() { + mode = PLAYBACK_STOPPED; +} + +/// Get the current frame number being played +int SDLPlayer::Position() { + return position; +} + +/// Seek to a specific frame in the player +void SDLPlayer::Seek(int new_frame) { + position = new_frame; +} + +// Play the video +void SDLPlayer::Play() +{ + // Set mode + mode = PLAYBACK_PLAY; + + // Init SDL + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) { + fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); + exit(1); + } + + // Create an SDL surface + SDL_Surface *screen; + screen = SDL_SetVideoMode(reader->info.width, reader->info.height, 0, SDL_HWSURFACE | SDL_ANYFORMAT | SDL_DOUBLEBUF); + if (!screen) { + fprintf(stderr, "SDL: could not set video mode - exiting\n"); + exit(1); + } + + vector overlays; + int number_of_cycles = 60; + + + // Create YUV Overlay + SDL_Overlay *bmp; + bmp = SDL_CreateYUVOverlay(reader->info.width, reader->info.height, SDL_YV12_OVERLAY, screen); + + cout << setprecision(6); + cout << "START PREPARING SURFACES..." << endl; + + for (int stuff = 0; stuff < number_of_cycles; stuff++) + { + // Get pointer to pixels of image. + tr1::shared_ptr f = reader->GetFrame(300 + stuff); + + // Create YUV Overlay + SDL_Overlay *bmp; + bmp = SDL_CreateYUVOverlay(reader->info.width, reader->info.height, SDL_YV12_OVERLAY, screen); + SDL_LockYUVOverlay(bmp); + + // Get luminance of each pixel + int pixel_index = 0; + int biggest_y = 0; + int smallest_y = 512; + for (int row = 0; row < screen->h; row++) { + // Get array of pixels for this row + //cout << "row: " << row << endl; + const Magick::PixelPacket *imagepixels = f->GetPixels(row); + + // Loop through pixels on this row + for (int column = 0; column < screen->w; column++) { + + // Get a pixel from this row + const Magick::PixelPacket *pixel = imagepixels; + + // Get the RGB colors + float r = pixel[column].red / 255.0; + float b = pixel[column].blue / 255.0; + float g = pixel[column].green / 255.0; + + // Calculate the Y value (brightness or luminance) + float y = (0.299 * r) + (0.587 * g) + (0.114 * b); + + // Update the Y value for every pixel + bmp->pixels[0][pixel_index] = y; + + // Increment counter + pixel_index++; + + } + } + + // Get pixels for resized frame (for reduced color needed by YUV420p) + int divider = 2; + tr1::shared_ptr reduced_color = tr1::shared_ptr(new Magick::Image(*f->GetImage().get())); // copy frame image + Magick::Geometry new_size; + new_size.width(reader->info.width / divider); + new_size.height(reader->info.height / divider); + reduced_color->scale(new_size); + + int number_of_colors = (reader->info.width / divider) * (reader->info.height / divider); + + // Loop through the UV (color info) + for (int pixel_index = 0; pixel_index < number_of_colors; pixel_index++) + { + // Get a pixel from this row + const Magick::PixelPacket *pixel = reduced_color->getConstPixels(0,0, new_size.width(), new_size.height()); + + // Get the RGB colors + float r = pixel[pixel_index].red / 255.0; + float b = pixel[pixel_index].blue / 255.0; + float g = pixel[pixel_index].green / 255.0; + + // Calculate UV colors + float v = (0.439 * r) - (0.368 * g) - (0.071 * b) + 128; + float u = (-0.148 * r) - (0.291 * g) + (0.439 * b) + 128; + + // Update the UV values for every pixel + bmp->pixels[1][pixel_index] = v * 1.0; + bmp->pixels[2][pixel_index] = u * 1.0; + + } + SDL_UnlockYUVOverlay(bmp); + + // Add to vector + overlays.push_back(bmp); + } + + cout << "START DISPLAYING SURFACES..." << endl; + + SDL_Rect rect; + rect.x = 0; + rect.y = 0; + rect.w = reader->info.width; + rect.h = reader->info.height; + + // Loop through overlays and display them + for (int repeat = 0; repeat < 3; repeat++) + { + cout << "START OVERLAY LOOP:" << endl; + for (int z = 0; z < number_of_cycles; z++) + { + cout << z << endl; + //SDL_LockSurface( screen); + //primary_screen->pixels = surfaces[z].pixels; + //SDL_UnlockSurface(primary_screen); + //SDL_UpdateRect(screen, 0, 0, reader->info.width, reader->info.height); + + SDL_DisplayYUVOverlay(overlays[z], &rect); + //SDL_UnlockSurface( screen); + + SDL_Delay(41); + } + } + + cout << "DONE!" << endl; + SDL_Delay(1000); +} + diff --git a/src/openshot.i b/src/openshot.i index f0b8c3f3..bc00940d 100644 --- a/src/openshot.i +++ b/src/openshot.i @@ -66,9 +66,10 @@ #include "../include/FrameMapper.h" #include "../include/FrameRate.h" #include "../include/ImageReader.h" -#include "../include/Player.h" +#include "../include/PlayerBase.h" #include "../include/Point.h" #include "../include/KeyFrame.h" +#include "../include/SDLPlayer.h" #include "../include/TextReader.h" #include "../include/Timeline.h" @@ -110,9 +111,10 @@ %include "../include/FrameMapper.h" %include "../include/FrameRate.h" %include "../include/ImageReader.h" -%include "../include/Player.h" +%include "../include/PlayerBase.h" %include "../include/Point.h" %include "../include/KeyFrame.h" +%include "../include/SDLPlayer.h" %include "../include/TextReader.h" %include "../include/Timeline.h" diff --git a/tests/FrameMapper_Tests.cpp b/tests/FrameMapper_Tests.cpp index 6d12a96a..4a6bd0d7 100644 --- a/tests/FrameMapper_Tests.cpp +++ b/tests/FrameMapper_Tests.cpp @@ -188,40 +188,3 @@ TEST(FrameMapper_30_fps_to_24_fps_Pulldown_None) CHECK_EQUAL(6, frame5.Even.Frame); } -TEST(FrameMapper_MapTime) -{ - // Create a reader - DummyReader r(Framerate(24, 1), 720, 480, 22000, 2, 5.0); - - // Create mapping 24 fps and 24 fps - FrameMapper mapping(&r, Framerate(24, 1), PULLDOWN_NONE); - - // Create a Keyframe to re-map time (forward, reverse, and then forward again) - Keyframe kf; - kf.AddPoint(openshot::Point(Coordinate(1, 1), LINEAR)); - kf.AddPoint(openshot::Point(Coordinate(40, 40), LINEAR)); - kf.AddPoint(openshot::Point(Coordinate(60, 20), LINEAR)); - kf.AddPoint(openshot::Point(Coordinate(100, 100), LINEAR)); - - // Re-map time - mapping.MapTime(kf); - - // Check for OutOfBoundsFrames - CHECK_THROW(mapping.GetMappedFrame(0), OutOfBoundsFrame); - CHECK_THROW(mapping.GetMappedFrame(101), OutOfBoundsFrame); - - // Check to see if time remapping worked correctly -// CHECK_EQUAL(1, mapping.GetMappedFrame(1).Odd.Frame); -// CHECK_EQUAL(2, mapping.GetMappedFrame(2).Odd.Frame); -// CHECK_EQUAL(39, mapping.GetMappedFrame(39).Odd.Frame); -// CHECK_EQUAL(40, mapping.GetMappedFrame(40).Odd.Frame); -// CHECK_EQUAL(39, mapping.GetMappedFrame(41).Odd.Frame); -// CHECK_EQUAL(38, mapping.GetMappedFrame(42).Odd.Frame); -// CHECK_EQUAL(21, mapping.GetMappedFrame(59).Odd.Frame); -// CHECK_EQUAL(20, mapping.GetMappedFrame(60).Odd.Frame); -// CHECK_EQUAL(22, mapping.GetMappedFrame(61).Odd.Frame); -// CHECK_EQUAL(24, mapping.GetMappedFrame(62).Odd.Frame); -// CHECK_EQUAL(90, mapping.GetMappedFrame(95).Odd.Frame); -// CHECK_EQUAL(100, mapping.GetMappedFrame(100).Odd.Frame); - -}