This code snippet is taken from a Cinder (C++) project, compiled in Xcode for Mac OSX. The program achieves smooth ‘video scrubbing’ of a 1080p HD *.mov file.
Cinder is an open-source Creative Coding framework. You can download it from its homepage here: libcinder.org
Once you have installed Cinder on your Mac, simply:
- Create a Cinder project in Xcode (adding the QuickTime Cinder Block).
- Use the code from the snippet below in your main App *.cpp.
- Run the App, you should then be able to scrub the video by dragging the mouse horizontally across the app window.
Please Note: It’s possible to compile this App for Windows, however it may be sluggish, as the Windows QuickTime player is rubbish!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
// ------------------------------------- // Video Scrubbing With Cinder (Mac OSX) // ------------------------------------- #include "cinder/app/AppNative.h" #include "cinder/qtime/QuickTime.h" using namespace ci; using namespace ci::app; using namespace std; class VideoScrubbingApp : public AppNative { public: void setup(); void mouseDown( MouseEvent event ); void mouseUp( MouseEvent event ); void mouseMove( MouseEvent event ); void calculateMousePosition(); void seek(); void update(); void draw(); qtime::MovieGl myVideo; Vec2i mousePos; int numFrames; bool canScrubVideo; double seekPos; int seekFrame; }; void VideoScrubbingApp::setup() { canScrubVideo = false; //TinderBox will create an 'assets' folder in the root of your project, put 'myVideo.mov' there. myVideo = qtime::MovieGl( loadAsset("myVideo.mov") ); //Execution halts until the 'myVideo.mov' is loaded... numFrames = myVideo.getNumFrames(); console() << "VideoScrubbingApp::setup() numFrames: " << numFrames << endl; myVideo.seekToStart(); } void VideoScrubbingApp::mouseDown( MouseEvent event ){ canScrubVideo = true; } void VideoScrubbingApp::mouseUp( MouseEvent event ){ canScrubVideo = false; } void VideoScrubbingApp::mouseMove( MouseEvent event ){} void VideoScrubbingApp::calculateMousePosition() { if(isFullScreen()){ mousePos = getMousePos(); } mousePos = getMousePos() - getWindowPos(); if(mousePos.x < 0){ mousePos.x = 0; } else if( mousePos.x > getWindowWidth() ){ mousePos.x = getWindowWidth(); } if(mousePos.y < 0){ mousePos.y = 0; } else if( mousePos.y > getWindowHeight() ){ mousePos.y = getWindowHeight(); } } void VideoScrubbingApp::seek() { seekPos = (double)mousePos.x / getWindowWidth(); seekFrame = (int)std::round(numFrames * seekPos); if(myVideo != NULL) { myVideo.seekToFrame(seekFrame); } } void VideoScrubbingApp::update() { if(!canScrubVideo) { return; } calculateMousePosition(); //console() << "VideoScrubbingApp::mouseMove() mousePos.x: " << mousePos.x << ", mousePos.y: " << mousePos.y << endl; seek(); } void VideoScrubbingApp::draw() { gl::disableAlphaBlending(); // clear out the window with black gl::clear( Color( 0, 0, 0 ) ); gl::Texture videoTexture = myVideo.getTexture(); if(videoTexture) { gl::draw( videoTexture); videoTexture.disable(); } gl::enableAlphaBlending(); //Alpha-channeled Overlays / GUI could go here! } CINDER_APP_NATIVE( VideoScrubbingApp, RendererGl ) |
For convenience, I’ve also uploaded the code as a GitHub Gist: https://gist.github.com/prucha/a1d8e286db0763837737