From c7b18af340337ed2edec15eac34e4644b1411317 Mon Sep 17 00:00:00 2001 From: Eva Schindling Date: Tue, 18 Feb 2014 14:35:40 -0500 Subject: [PATCH 1/4] make addon work on ubuntu13 --- src/ofxThreadedVideo.cpp | 18 ++++++++++++------ src/ofxThreadedVideo.h | 5 ++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/ofxThreadedVideo.cpp b/src/ofxThreadedVideo.cpp index f39be3d..3dfaf16 100644 --- a/src/ofxThreadedVideo.cpp +++ b/src/ofxThreadedVideo.cpp @@ -70,9 +70,13 @@ ofxThreadedVideo::ofxThreadedVideo(){ instanceID = ofxThreadedVideoGlobalInstanceID; ofxThreadedVideoGlobalInstanceID++; + +#ifdef OF_VIDEO_PLAYER_GSTREAMER + setPlayer(); +#else initializeQuicktime(); - setPlayer(); +#endif // setup video instances video[0].setUseTexture(false); @@ -444,9 +448,9 @@ void ofxThreadedVideo::threadedFunction(){ }else{ frameEnd -= 1; - assert(frameStart >= 0); - assert(frameEnd >= frameStart); - assert(frameEnd <= frameTotal); + // assert(frameStart >= 0); + // assert(frameEnd >= frameStart); + // assert(frameEnd <= frameTotal); fades.push_back(ofxThreadedVideoFade(frameStart, frameEnd, fadeTarget, fadeSound, fadeVideo, fadeOnce)); } @@ -540,7 +544,7 @@ void ofxThreadedVideo::threadedFunction(){ lock(); if(bIsFrameNew){ - for(int i = 0; i < fades.size(); i++){ + for(unsigned int i = 0; i < fades.size(); i++){ ofxThreadedVideoFade& currentFade = fades.at(i); @@ -967,7 +971,7 @@ bool ofxThreadedVideo::isLoading(){ //-------------------------------------------------------------- bool ofxThreadedVideo::isLoading(string path){ ofScopedLock lock(ofxThreadedVideoGlobalMutex); - for(int i = 0; i < ofxThreadedVideoCommands.size(); i++){ + for(unsigned int i = 0; i < ofxThreadedVideoCommands.size(); i++){ if(ofxThreadedVideoCommands[i].getInstance() == instanceID){ if(ofxThreadedVideoCommands[i].getCommand() == "loadMovie"){ if(ofxThreadedVideoCommands[i].getArgument(0) == path){ @@ -1071,6 +1075,7 @@ int ofxThreadedVideo::getNextLoadID(){ case VIDEO_FLOP: return VIDEO_FLIP; break; + default: case VIDEO_FLIP: return VIDEO_FLOP; break; @@ -1083,6 +1088,7 @@ string ofxThreadedVideo::getEventTypeAsString(ofxThreadedVideoEventType eventTyp case VIDEO_EVENT_LOAD_OK: return "VIDEO_EVENT_LOAD_OK"; break; + default: case VIDEO_EVENT_LOAD_FAIL: return "VIDEO_EVENT_LOAD_FAIL"; break; diff --git a/src/ofxThreadedVideo.h b/src/ofxThreadedVideo.h index 2f5881e..f391224 100644 --- a/src/ofxThreadedVideo.h +++ b/src/ofxThreadedVideo.h @@ -37,8 +37,11 @@ #include "ofMain.h" +#ifndef OF_VIDEO_PLAYER_GSTREAMER #define USE_QUICKTIME_7 #define USE_JACK_AUDIO +#endif + enum ofxThreadedVideoEventType{ VIDEO_EVENT_LOAD_OK = 0, @@ -380,7 +383,7 @@ class ofxThreadedVideoCommand { string getCommandAsString(){ ostringstream os; os << command << "("; - for(int i = 0; i < args.size(); i++){ + for(unsigned int i = 0; i < args.size(); i++){ os << args[i] << string(i < args.size() - 1 ? "," : ""); } os << ")"; From 47a96692a386c16a4e02a80cedd17914bf1f36d0 Mon Sep 17 00:00:00 2001 From: Eva Schindling Date: Fri, 21 Mar 2014 17:34:14 -0400 Subject: [PATCH 2/4] fix __H_OFXTHREADEDVIDEO typo --- src/ofxThreadedVideo.cpp | 8 ++++++++ src/ofxThreadedVideo.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ofxThreadedVideo.cpp b/src/ofxThreadedVideo.cpp index 3dfaf16..d376d92 100644 --- a/src/ofxThreadedVideo.cpp +++ b/src/ofxThreadedVideo.cpp @@ -590,16 +590,22 @@ void ofxThreadedVideo::threadedFunction(){ //-------------------------------------------------------------- void ofxThreadedVideo::pushCommand(ofxThreadedVideoCommand& c, bool back){ + ofLogNotice() << instanceID << " + push " << c.getCommandAsString(); + ofLogNotice() << instanceID << " + lock "; lock(); + ofLogNotice() << instanceID << " + ofxThreadedVideoGlobalMutex.lock(); "; ofxThreadedVideoGlobalMutex.lock(); if(bVerbose) ofLogVerbose() << instanceID << " + push " << c.getCommandAsString(); if(back){ + ofLogNotice() << instanceID << " + back "; ofxThreadedVideoCommands.push_back(c); }else{ + ofLogNotice() << instanceID << " + not back"; ofxThreadedVideoCommands.push_front(c); } ofxThreadedVideoGlobalMutex.unlock(); unlock(); + ofLogNotice() << instanceID << " + unlock "; } //-------------------------------------------------------------- @@ -620,6 +626,7 @@ ofxThreadedVideoCommand ofxThreadedVideo::getCommand(){ //-------------------------------------------------------------- bool ofxThreadedVideo::loadMovie(string path){ + ofLogNotice() << instanceID << " - loadMovie " << path; ofxThreadedVideoCommand c("loadMovie", instanceID); c.setArgument(path); pushCommand(c); @@ -991,6 +998,7 @@ bool ofxThreadedVideo::isTextureReady(){ //-------------------------------------------------------------- bool ofxThreadedVideo::isLoaded(){ + ofLogNotice() << instanceID << " + isLoaded "; ofScopedLock lock(mutex); return bLoaded; } diff --git a/src/ofxThreadedVideo.h b/src/ofxThreadedVideo.h index f391224..61ff479 100644 --- a/src/ofxThreadedVideo.h +++ b/src/ofxThreadedVideo.h @@ -29,7 +29,7 @@ * */ -#ifndef __H_OFXHREADEDVIDEO +#ifndef __H_OFXTHREADEDVIDEO #define __H_OFXTHREADEDVIDEO #include From 5a9b2e3b6d2df6dc903f862fa7475c1c74e2792c Mon Sep 17 00:00:00 2001 From: Eva Schindling Date: Wed, 25 Jul 2018 12:17:34 -0400 Subject: [PATCH 3/4] comment out debug-logs --- src/ofxThreadedVideo.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ofxThreadedVideo.cpp b/src/ofxThreadedVideo.cpp index d376d92..113b775 100644 --- a/src/ofxThreadedVideo.cpp +++ b/src/ofxThreadedVideo.cpp @@ -590,22 +590,22 @@ void ofxThreadedVideo::threadedFunction(){ //-------------------------------------------------------------- void ofxThreadedVideo::pushCommand(ofxThreadedVideoCommand& c, bool back){ - ofLogNotice() << instanceID << " + push " << c.getCommandAsString(); - ofLogNotice() << instanceID << " + lock "; + // ofLogNotice() << instanceID << " + push " << c.getCommandAsString(); + // ofLogNotice() << instanceID << " + lock "; lock(); - ofLogNotice() << instanceID << " + ofxThreadedVideoGlobalMutex.lock(); "; + // ofLogNotice() << instanceID << " + ofxThreadedVideoGlobalMutex.lock(); "; ofxThreadedVideoGlobalMutex.lock(); if(bVerbose) ofLogVerbose() << instanceID << " + push " << c.getCommandAsString(); if(back){ - ofLogNotice() << instanceID << " + back "; + // ofLogNotice() << instanceID << " + back "; ofxThreadedVideoCommands.push_back(c); }else{ - ofLogNotice() << instanceID << " + not back"; + // ofLogNotice() << instanceID << " + not back"; ofxThreadedVideoCommands.push_front(c); } ofxThreadedVideoGlobalMutex.unlock(); unlock(); - ofLogNotice() << instanceID << " + unlock "; + // ofLogNotice() << instanceID << " + unlock "; } //-------------------------------------------------------------- @@ -626,7 +626,7 @@ ofxThreadedVideoCommand ofxThreadedVideo::getCommand(){ //-------------------------------------------------------------- bool ofxThreadedVideo::loadMovie(string path){ - ofLogNotice() << instanceID << " - loadMovie " << path; + // ofLogNotice() << instanceID << " - loadMovie " << path; ofxThreadedVideoCommand c("loadMovie", instanceID); c.setArgument(path); pushCommand(c); @@ -998,7 +998,7 @@ bool ofxThreadedVideo::isTextureReady(){ //-------------------------------------------------------------- bool ofxThreadedVideo::isLoaded(){ - ofLogNotice() << instanceID << " + isLoaded "; + // ofLogNotice() << instanceID << " + isLoaded "; ofScopedLock lock(mutex); return bLoaded; } From 10b5f12d91b823ac26a81240ee775ba63e08968b Mon Sep 17 00:00:00 2001 From: Eva Schindling Date: Mon, 11 Feb 2019 13:36:58 -0500 Subject: [PATCH 4/4] make work on Windows 10 --- src/ofxThreadedVideo.cpp | 353 +++++++++++++++++++++--------- src/ofxThreadedVideo.h | 459 ++++++++++++++++++++++++++------------- 2 files changed, 568 insertions(+), 244 deletions(-) diff --git a/src/ofxThreadedVideo.cpp b/src/ofxThreadedVideo.cpp index 113b775..bb4f06f 100644 --- a/src/ofxThreadedVideo.cpp +++ b/src/ofxThreadedVideo.cpp @@ -1,7 +1,7 @@ /* * ofxThreadedVideo.cpp * - * Copyright 2010-2013 (c) Matthew Gingold http://gingold.com.au + * Copyright 2010-2016 (c) Matthew Gingold http://gingold.com.au * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -67,35 +67,47 @@ int ofxThreadedVideo::getLoadFail(){ //-------------------------------------------------------------- ofxThreadedVideo::ofxThreadedVideo(){ + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo \t initialize"; + instanceID = ofxThreadedVideoGlobalInstanceID; ofxThreadedVideoGlobalInstanceID++; - -#ifdef OF_VIDEO_PLAYER_GSTREAMER - setPlayer(); -#else - initializeQuicktime(); - setPlayer(); -#endif + + #ifdef OF_VIDEO_PLAYER_QUICKTIME + initializeQuicktime(); + setPlayer(); + #endif + #ifdef OF_VIDEO_PLAYER_DIRECTSHOW + setPlayer(); + #endif + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo \t setPlayer " << STRINGIFYMACRO(OF_VID_PLAYER_TYPE); // setup video instances video[0].setUseTexture(false); video[1].setUseTexture(false); + + ofLog(OF_LOG_VERBOSE) << "ofVideoPlayer.getPosition " << video[0].getPosition; setPixelFormat(OF_PIXELS_RGB); + bUseInternalShader = false; + drawTexture.allocate(1, 1, GL_RGB); ofPixels p; p.allocate(1, 1, OF_IMAGE_COLOR); p.set(0); drawTexture.loadData(p.getPixels(), 1, 1, GL_RGB); - pixels = &video[0].getPixelsRef(); + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo \t drawTexture.loadData"; + // pixels = &video[0].getPixelsRef(); + // pixels = &video[0].getPixels(); + // ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo \t getPixels"; // set vars to default values currentVideoID = VIDEO_FLIP; bCriticalSection = false; bLoaded = false; + bUseBlackStop = bForceBlack = false; bUseTexture = true; bIsFrameNew = false; bIsPlaying = false; @@ -122,16 +134,19 @@ ofxThreadedVideo::ofxThreadedVideo(){ fade = 1.0f; fades.clear(); + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo \t fades clear"; prevMillis = ofGetElapsedTimeMillis(); lastFrameTime = timeNow = timeThen = fps = frameRate = 0; ofxThreadedVideoNullCommand.setCommand("NULL_COMMAND", -1); + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo \t setCommand"; bVerbose = false; // let's go! - startThread(); + startThread(true); + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo \t thread started"; } //-------------------------------------------------------------- @@ -150,16 +165,20 @@ ofxThreadedVideo::~ofxThreadedVideo(){ //-------------------------------------------------------------- void ofxThreadedVideo::update(){ + + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::update \t bLoaded " << bLoaded; lock(); if(!bCriticalSection && bLoaded){ + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::update \t !bCriticalSection "; bCriticalSection = true; int videoID = currentVideoID; bool bUpdate = bLoaded; unlock(); if(bUpdate){ + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::update \t bUpdate "; // lock(); video[videoID].update(); @@ -171,18 +190,100 @@ void ofxThreadedVideo::update(){ // unlock(); if(bIsFrameNew || bForceFrameNew){ - + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::update \t bIsFrameNew "; if(bForceFrameNew) lock(); if(!bIsTextureReady) bIsTextureReady = true; if(drawTexture.getWidth() != width || drawTexture.getHeight() != height){ - drawTexture.allocate(width, height, ofGetGLTypeFromPixelFormat(video[videoID].getPixelFormat())); + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::update \t width != "; + ofTextureData texData; + + texData.width = width; + texData.height = height; + texData.textureTarget = GL_TEXTURE_2D; + + switch (internalPixelFormat) { + case OF_PIXELS_RGB: + textureInternalType = GL_RGB; + textureFormatType = GL_RGB; + texturePixelType = GL_UNSIGNED_BYTE; + ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,width,1,3); + break; + case OF_PIXELS_RGBA: + textureInternalType = GL_RGBA; + textureFormatType = GL_RGBA; + texturePixelType = GL_UNSIGNED_BYTE; + ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,width,1,4); + break; + case OF_PIXELS_BGRA: + textureInternalType = GL_RGBA; + textureFormatType = GL_BGRA; + texturePixelType = GL_UNSIGNED_INT_8_8_8_8_REV; + ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,width,1,4); + break; +#if (OF_VERSION_MAJOR == 0) && (OF_VERSION_MINOR <= 8) + case OF_PIXELS_2YUV: +#else + case OF_PIXELS_YUY2: +#endif + if(bUseInternalShader){ + fboYUY2.allocate(width, height); + /*fboYUY2.begin(); + ofClear(0, 0, 0, 255); + ofPushStyle(); + ofFill(); + ofSetColor(0,0,0); + ofDrawRectangle(0, 0, width, height); + ofPopStyle(); + fboYUY2.end(); + shader.begin(); + shader.setUniformTexture("yuvTex", fboYUY2.getTexture(), 1); + shader.setUniform1i("conversionType", (false ? 709 : 601)); + shader.setUniform1f("fade", 0); + fboYUY2.draw(-1000, -1000, width, height); + shader.end();*/ + } + textureInternalType = GL_RGB; + textureFormatType = GL_RGB_422_APPLE; + texturePixelType = GL_UNSIGNED_SHORT_8_8_APPLE; + ofSetPixelStoreiAlignment(GL_UNPACK_ALIGNMENT,width,1,4); + break; + default: + break; + } + + + +#if (OF_VERSION_MAJOR == 0) && (OF_VERSION_MINOR <= 8) + texData.glTypeInternal = textureInternalType; +// texData.glType = textureFormatType; +// texData.pixelType = texturePixelType; +#else + texData.glInternalFormat = textureInternalType; +#endif + drawTexture.allocate(texData, textureFormatType, texturePixelType); +#if defined(TARGET_OSX) + drawTexture.bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_SHARED_APPLE); + drawTexture.unbind(); +#endif } - unsigned char * pixels = video[videoID].getPixels(); - if(pixels != NULL && bUseTexture) drawTexture.loadData(pixels, width, height, ofGetGLTypeFromPixelFormat(video[videoID].getPixelFormat())); + if(bForceBlack){ + video[videoID].getPixelsRef().set(0); + bForceBlack = bLoaded = false; + } + + ///// MESSING AROUND HERE DEBUG + // unsigned char * pixels = video[videoID].getPixels(); + // if(pixels != NULL && bUseTexture) drawTexture.loadData(pixels, width, height, textureFormatType, texturePixelType); + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::update \t drawTexture.loadData "; + ofPixels & pixels = video[videoID].getPixels(); + if(bUseTexture) drawTexture.loadData(pixels); + // if(pixels != NULL && bUseTexture) drawTexture.loadData(pixels, width, height, textureFormatType, texturePixelType); + if(bForceFrameNew){ bForceFrameNew = false; unlock(); @@ -212,6 +313,7 @@ void ofxThreadedVideo::update(){ lock(); ofxThreadedVideoGlobalMutex.lock(); + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::update \t lock "; if(!ofxThreadedVideoGlobalCritical && !bCriticalSection){ int videoID = currentVideoID; ofxThreadedVideoGlobalCritical = true; @@ -236,13 +338,17 @@ void ofxThreadedVideo::update(){ bIsFrameNew = false; bIsMovieDone = false; bLoaded = false; + if(bUseBlackStop) bForceBlack = bForceFrameNew = bIsFrameNew = bLoaded = true; unlock(); bPopCommand = true; } if(c.getCommand() == "loadMovie" && bCanStop){ if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString() << " execute in update"; - if(bIsPlaying) video[videoID].stop(); + if(bIsPlaying){ + video[videoID].stop(); + video[videoID].close(); + } lock(); currentVideoID = getNextLoadID(); bIsPaused = false; @@ -253,6 +359,18 @@ void ofxThreadedVideo::update(){ unlock(); } + if(c.getCommand() == "play"){ + if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); + video[videoID].play(); + + lock(); + bIsPlaying = true; + bIsPaused = false; + unlock(); + + bPopCommand = true; + } + if(c.getCommand() == "setSpeed"){ if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); lock(); @@ -262,6 +380,15 @@ void ofxThreadedVideo::update(){ bPopCommand = true; } + if(c.getCommand() == "setPaused"){ + if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); + lock(); + bIsPaused = c.getArgument(0); + unlock(); + video[videoID].setPaused(bIsPaused); + bPopCommand = true; + } + if(c.getCommand() == "setFrame"){ if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); lock(); @@ -311,18 +438,6 @@ void ofxThreadedVideo::threadedFunction(){ if(c.getInstance() == instanceID){ - if(c.getCommand() == "play"){ - if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); - video[videoID].play(); - - lock(); - bIsPlaying = true; - bIsPaused = false; - unlock(); - - bPopCommand = true; - } - if(c.getCommand() == "setPosition"){ if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); lock(); @@ -361,46 +476,6 @@ void ofxThreadedVideo::threadedFunction(){ bPopCommand = true; } -// if(c.getCommand() == "setSpeed"){ -// if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); -// lock(); -// speed = c.getArgument(0); -// unlock(); -// video[videoID].setSpeed(speed); -// bPopCommand = true; -// } - -// if(c.getCommand() == "setFrame"){ -// if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); -// int frameTarget = c.getArgument(0); -// CLAMP(frameTarget, 0, frameTotal); -// video[videoID].setFrame(frameTarget); -// bForceFrameNew = true; -// bPopCommand = true; -// } - -// if(c.getCommand() == "setFrame"){ -// if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); -// lock(); -// int frameTarget = c.getArgument(0); -// bForceFrameNew = true; -// frameTarget = CLAMP(frameTarget, 0, frameTotal); -// cout << "setframe A: " << frameTarget << " " << videoID << " " << bCriticalSection << endl; -// video[videoID].setFrame(frameTarget); -// cout << "setframe B: " << frameTarget << " " << videoID << " " << bCriticalSection << endl; -// unlock(); -// bPopCommand = true; -// } - - if(c.getCommand() == "setPaused"){ - if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); - lock(); - bIsPaused = c.getArgument(0); - unlock(); - video[videoID].setPaused(bIsPaused); - bPopCommand = true; - } - if(c.getCommand() == "setAnchorPercent"){ if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); video[videoID].setAnchorPercent(c.getArgument(0), c.getArgument(0)); @@ -441,18 +516,28 @@ void ofxThreadedVideo::threadedFunction(){ if(frameStart == frameEnd){ _fade = fadeTarget; + lock(); if(fadeVideo) fade = _fade; + unlock(); + lock(); - if(fadeSound) video[videoID].setVolume(_fade); + if(fadeSound){ + volume = _fade; + unlock(); + video[videoID].setVolume(_fade); + lock(); + } unlock(); }else{ frameEnd -= 1; - // assert(frameStart >= 0); - // assert(frameEnd >= frameStart); - // assert(frameEnd <= frameTotal); + assert(frameStart >= 0); + assert(frameEnd >= frameStart); + assert(frameEnd <= frameTotal); + lock(); fades.push_back(ofxThreadedVideoFade(frameStart, frameEnd, fadeTarget, fadeSound, fadeVideo, fadeOnce)); + unlock(); } @@ -475,13 +560,14 @@ void ofxThreadedVideo::threadedFunction(){ #endif if(c.getCommand() == "loadMovie" && bCanLoad){ + if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString(); if(video[videoID].loadMovie(c.getArgument(0))){ if(bVerbose) ofLogVerbose() << instanceID << " = " << c.getCommandAsString() << " executed in thread";; -// lock(); + lock(); fades.clear(); width = video[videoID].getWidth(); @@ -518,7 +604,7 @@ void ofxThreadedVideo::threadedFunction(){ bPopCommand = true; - ofxThreadedVideoEvent e = ofxThreadedVideoEvent(moviePath, VIDEO_EVENT_LOAD_OK, this); + ofxThreadedVideoEvent e = ofxThreadedVideoEvent(c.getArgument(0), VIDEO_EVENT_LOAD_OK, this); ofNotifyEvent(threadedVideoEvent, e, this); ofxThreadedVideoLoadOk++; @@ -527,7 +613,9 @@ void ofxThreadedVideo::threadedFunction(){ ofLogError() << "Could not load: " << instanceID << " + " << c.getCommandAsString(); - ofxThreadedVideoEvent e = ofxThreadedVideoEvent(moviePath, VIDEO_EVENT_LOAD_FAIL, this); + video[videoID].close(); + + ofxThreadedVideoEvent e = ofxThreadedVideoEvent(c.getArgument(0), VIDEO_EVENT_LOAD_FAIL, this); ofNotifyEvent(threadedVideoEvent, e, this); ofxThreadedVideoLoadFail++; @@ -537,14 +625,12 @@ void ofxThreadedVideo::threadedFunction(){ } - if(bPopCommand){ - video[videoID].update(); - } + if(bPopCommand) video[videoID].update(); lock(); if(bIsFrameNew){ - for(unsigned int i = 0; i < fades.size(); i++){ + for(int i = 0; i < fades.size(); i++){ ofxThreadedVideoFade& currentFade = fades.at(i); @@ -568,7 +654,7 @@ void ofxThreadedVideo::threadedFunction(){ } } - + ofxThreadedVideoGlobalMutex.lock(); if(bPopCommand) popCommand(); @@ -582,7 +668,7 @@ void ofxThreadedVideo::threadedFunction(){ unlock(); } - ofSleepMillis(1); + ofSleepMillis(1000.0/30.0); } @@ -590,22 +676,16 @@ void ofxThreadedVideo::threadedFunction(){ //-------------------------------------------------------------- void ofxThreadedVideo::pushCommand(ofxThreadedVideoCommand& c, bool back){ - // ofLogNotice() << instanceID << " + push " << c.getCommandAsString(); - // ofLogNotice() << instanceID << " + lock "; lock(); - // ofLogNotice() << instanceID << " + ofxThreadedVideoGlobalMutex.lock(); "; ofxThreadedVideoGlobalMutex.lock(); if(bVerbose) ofLogVerbose() << instanceID << " + push " << c.getCommandAsString(); if(back){ - // ofLogNotice() << instanceID << " + back "; ofxThreadedVideoCommands.push_back(c); }else{ - // ofLogNotice() << instanceID << " + not back"; ofxThreadedVideoCommands.push_front(c); } ofxThreadedVideoGlobalMutex.unlock(); unlock(); - // ofLogNotice() << instanceID << " + unlock "; } //-------------------------------------------------------------- @@ -625,15 +705,21 @@ ofxThreadedVideoCommand ofxThreadedVideo::getCommand(){ } //-------------------------------------------------------------- -bool ofxThreadedVideo::loadMovie(string path){ - // ofLogNotice() << instanceID << " - loadMovie " << path; +void ofxThreadedVideo::load(const string& path){ + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::load \t" << path; ofxThreadedVideoCommand c("loadMovie", instanceID); c.setArgument(path); pushCommand(c); } +//-------------------------------------------------------------- +void ofxThreadedVideo::loadMovie(const string& path){ + load(path); +} + //-------------------------------------------------------------- void ofxThreadedVideo::play(){ + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::play \t"; ofxThreadedVideoCommand c("play", instanceID); pushCommand(c); } @@ -644,6 +730,11 @@ void ofxThreadedVideo::stop(){ pushCommand(c); } +//-------------------------------------------------------------- +void ofxThreadedVideo:: setUseBlackStop(bool b){ + bUseBlackStop = b; +} + //-------------------------------------------------------------- void ofxThreadedVideo::close(){ closeMovie(); @@ -727,7 +818,7 @@ void ofxThreadedVideo::clearFades(){ //-------------------------------------------------------------- bool ofxThreadedVideo::isFrameNew(){ - ofScopedLock lock(mutex); + //ofScopedLock lock(mutex); return bIsFrameNew; } @@ -849,9 +940,52 @@ ofPixelsRef ofxThreadedVideo::getPixelsRef(){ } //-------------------------------------------------------------- -void ofxThreadedVideo::setPixelFormat(ofPixelFormat _pixelFormat){ +ofShader& ofxThreadedVideo::getShader(){ + return shader; +} + +//-------------------------------------------------------------- +void ofxThreadedVideo::setUseInternalShader(bool b){ +#if (OF_VERSION_MAJOR == 0) && (OF_VERSION_MINOR <= 8) + if(internalPixelFormat == OF_PIXELS_2YUV){ +#else + if(internalPixelFormat == OF_PIXELS_YUY2){ +#endif + bUseInternalShader = b; + }else{ +#if (OF_VERSION_MAJOR == 0) && (OF_VERSION_MINOR <= 8) + if(b) ofLogWarning() << "You need to be using OF_PIXELS_2YUV for the internal shader to be relevant"; +#else + if(b) ofLogWarning() << "You need to be using OF_PIXELS_YUY2 for the internal shader to be relevant"; +#endif + bUseInternalShader = false; + } +} + +//-------------------------------------------------------------- +bool ofxThreadedVideo::getUseInternalShader(){ + return bUseInternalShader; +} + +//-------------------------------------------------------------- +void ofxThreadedVideo::setPixelFormat(ofPixelFormat pixelFormat){ ofScopedLock lock(mutex); - internalPixelFormat = _pixelFormat; +#if (OF_VERSION_MAJOR == 0) && (OF_VERSION_MINOR <= 8) + if(pixelFormat == OF_PIXELS_2YUV){ +#else + if(pixelFormat == OF_PIXELS_YUY2){ +#endif + bool ok = shader.setupShaderFromSource(GL_VERTEX_SHADER, ofxThreadedVideoVertexShader); + if(ok) ok = shader.setupShaderFromSource(GL_FRAGMENT_SHADER, ofxThreadedVideoFragmentShader); + if(ok) ok = shader.linkProgram(); + if(!ok){ + ofLogError() << "Could not initialize shader - reverting to default pixel format"; + pixelFormat = internalPixelFormat; + } + bUseInternalShader = true; + } + + internalPixelFormat = pixelFormat; video[0].setPixelFormat(internalPixelFormat); video[1].setPixelFormat(internalPixelFormat); } @@ -869,9 +1003,35 @@ ofPtr ofxThreadedVideo::getPlayer(){ //-------------------------------------------------------------- void ofxThreadedVideo::draw(float x, float y, float w, float h){ + ofPushStyle(); - ofSetColor(255 * fade, 255 * fade, 255 * fade, 255 * fade); - drawTexture.draw(x, y, w, h); + + if(bUseInternalShader){ + if(!fboYUY2.isAllocated()){ + ofPopStyle(); + return; + } + + if(isFrameNew()){ + fboYUY2.begin(); + ofClear(0, 0, 0, 255); + drawTexture.draw(0, 0, w, h); + fboYUY2.end(); + } + + shader.begin(); + shader.setUniformTexture("yuvTex", fboYUY2.getTexture(), 1); + shader.setUniform1i("conversionType", (false ? 709 : 601)); + shader.setUniform1f("fade", getFade()); + fboYUY2.draw(x, y, w, h); + shader.end(); + + }else{ + ofLog(OF_LOG_VERBOSE) << "ofxThreadedVideo::draw \t" << x << "\t" << y << "\t" << w << "\t" << h; + ofSetColor(255 * fade, 255 * fade, 255 * fade, 255 * fade); + drawTexture.draw(x, y, w, h); + + } ofPopStyle(); } @@ -978,7 +1138,7 @@ bool ofxThreadedVideo::isLoading(){ //-------------------------------------------------------------- bool ofxThreadedVideo::isLoading(string path){ ofScopedLock lock(ofxThreadedVideoGlobalMutex); - for(unsigned int i = 0; i < ofxThreadedVideoCommands.size(); i++){ + for(int i = 0; i < ofxThreadedVideoCommands.size(); i++){ if(ofxThreadedVideoCommands[i].getInstance() == instanceID){ if(ofxThreadedVideoCommands[i].getCommand() == "loadMovie"){ if(ofxThreadedVideoCommands[i].getArgument(0) == path){ @@ -998,7 +1158,6 @@ bool ofxThreadedVideo::isTextureReady(){ //-------------------------------------------------------------- bool ofxThreadedVideo::isLoaded(){ - // ofLogNotice() << instanceID << " + isLoaded "; ofScopedLock lock(mutex); return bLoaded; } @@ -1083,7 +1242,6 @@ int ofxThreadedVideo::getNextLoadID(){ case VIDEO_FLOP: return VIDEO_FLIP; break; - default: case VIDEO_FLIP: return VIDEO_FLOP; break; @@ -1096,9 +1254,8 @@ string ofxThreadedVideo::getEventTypeAsString(ofxThreadedVideoEventType eventTyp case VIDEO_EVENT_LOAD_OK: return "VIDEO_EVENT_LOAD_OK"; break; - default: case VIDEO_EVENT_LOAD_FAIL: return "VIDEO_EVENT_LOAD_FAIL"; break; } -} +} \ No newline at end of file diff --git a/src/ofxThreadedVideo.h b/src/ofxThreadedVideo.h index 61ff479..6f6c338 100644 --- a/src/ofxThreadedVideo.h +++ b/src/ofxThreadedVideo.h @@ -1,7 +1,7 @@ /* * ofxThreadedVideo.h * - * Copyright 2010-2013 (c) Matthew Gingold http://gingold.com.au + * Copyright 2010-2016 (c) Matthew Gingold http://gingold.com.au * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -34,14 +34,163 @@ #include #include +#include #include "ofMain.h" -#ifndef OF_VIDEO_PLAYER_GSTREAMER -#define USE_QUICKTIME_7 -#define USE_JACK_AUDIO +#if __LP64__ + +#error ofxThreadedVideo support requires 32-bit QuickTime APIs but this target is 64-bit + +#else + +//#define USE_QUICKTIME_7 +//#define USE_JACK_AUDIO + +#define STRINGIFY(x) #x +#define STRINGIFYMACRO(y) STRINGIFY(y) + +#ifdef OF_VIDEO_PLAYER_QUICKTIME + #include "ofQtUtils.h" + #include "ofQuickTimePlayer.h" + #define OF_VID_PLAYER_TYPE ofQuickTimePlayer #endif +#ifdef OF_VIDEO_PLAYER_DIRECTSHOW + #include "ofDirectShowPlayer.h" + #define OF_VID_PLAYER_TYPE ofDirectShowPlayer +#endif + + + +// class implimentation overrides how ofQuicktimePlayer implements pixel +// decoding and allows setPixels for RGB, RGBA, BGRA and YUY2 pixel formats +// class ofQuickTimePlayerWithFastPixels: public ofQuickTimePlayer{ + +// public: + +// void createImgMemAndGWorld(){ + +// Rect movieRect; +// movieRect.top = 0; +// movieRect.left = 0; +// movieRect.bottom = height; +// movieRect.right = width; + +// switch(internalPixelFormat){ + +// case OF_PIXELS_RGB: +// { +// offscreenGWorldPixels = new unsigned char[3 * width * height + 24]; +// pixels.allocate(width, height, OF_PIXELS_RGB); +// QTNewGWorldFromPtr (&(offscreenGWorld), k24RGBPixelFormat, &(movieRect), NULL, NULL, 0, (pixels.getPixels()), 3 * width); +// break; +// } +// case OF_PIXELS_RGBA: +// { +// offscreenGWorldPixels = new unsigned char[4 * width * height + 32]; +// pixels.allocate(width, height, OF_PIXELS_RGBA); +// QTNewGWorldFromPtr (&(offscreenGWorld), k32RGBAPixelFormat, &(movieRect), NULL, NULL, 0, (pixels.getPixels()), 4 * width); +// break; +// } +// case OF_PIXELS_BGRA: +// { +// offscreenGWorldPixels = new unsigned char[4 * width * height + 32]; +// pixels.allocate(width, height, OF_PIXELS_BGRA); +// QTNewGWorldFromPtr (&(offscreenGWorld), k32BGRAPixelFormat, &(movieRect), NULL, NULL, 0, (pixels.getPixels()), 4 * width); +// break; +// } +// case OF_PIXELS_YUY2: +// { +// #if !defined (TARGET_OSX) && !defined (GL_APPLE_rgb_422) +// movieRect.right = width*2; // this makes it look correct but we lose some of the performance gains +// SetMovieBox(moviePtr, &(movieRect)); +// //width = width / 2; // this makes it go really fast but we only get 'half-resolution'... +// offscreenGWorldPixels = new unsigned char[4 * width * height + 32]; +// pixels.allocate(width, height, OF_IMAGE_COLOR_ALPHA); +// QTNewGWorldFromPtr (&(offscreenGWorld), k24RGBPixelFormat, &(movieRect), NULL, NULL, 0, (pixels.getPixels()), 4 * width); +// #else + +// // for some reason doesn't like non-even width's and height's +// if(width % 2 != 0) width++; +// if(height % 2 != 0) height++; +// movieRect.bottom = height; +// movieRect.right = width; + +// // this works perfectly on Mac platform! +// offscreenGWorldPixels = new unsigned char[2 * width * height + 32]; +// pixels.allocate(width, height, OF_IMAGE_COLOR_ALPHA); +// QTNewGWorldFromPtr (&(offscreenGWorld), k2vuyPixelFormat, &(movieRect), NULL, NULL, 0, (pixels.getPixels()), 2 * width); +// #endif + +// break; +// } +// } + +// LockPixels(GetGWorldPixMap(offscreenGWorld)); + +// // from : https://github.com/openframeworks/openFrameworks/issues/244 +// // SetGWorld do not seems to be necessary for offscreen rendering of the movie +// // only SetMovieGWorld should be called +// // if both are called, the app will crash after a few ofVideoPlayer object have been deleted + +// #ifndef TARGET_WIN32 +// SetGWorld (offscreenGWorld, NULL); +// #endif +// SetMovieGWorld (moviePtr, offscreenGWorld, nil); + +// } + +// //--------------------------------------------------------------------------- +// bool setPixelFormat(ofPixelFormat pixelFormat){ +// //note as we only support RGB we are just confirming that this pixel format is supported +// if( pixelFormat == OF_PIXELS_RGB || pixelFormat == OF_PIXELS_RGBA || pixelFormat == OF_PIXELS_BGRA || pixelFormat == OF_PIXELS_YUY2){ +// internalPixelFormat = pixelFormat; +// return true; +// } +// ofLogWarning("ofQuickTimePlayer") << "setPixelFormat(): requested pixel format " << pixelFormat << " not supported"; +// return false; +// } + +// protected: + +// int internalPixelFormat; + +// }; + +// YUV2 shader modified from: http://www.fourcc.org/fccyvrgb.php and http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c +const string ofxThreadedVideoVertexShader = "void main(void){\ +gl_TexCoord[0] = gl_MultiTexCoord0;\ +gl_TexCoord[1] = gl_MultiTexCoord0 + vec4(1,0,0,0);\ +gl_Position = ftransform();\ +}"; + +const string ofxThreadedVideoFragmentShader = "uniform sampler2DRect yuvTex;\ +uniform int conversionType;\ +uniform float fade;\ +void main(void){\ +float nx, ny, r, g, b, a, y, u, v;\ +vec4 txl,ux,vx;\ +nx = gl_TexCoord[0].x;\ +ny = gl_TexCoord[0].y;\ +y = texture2DRect(yuvTex, vec2(nx,ny)).g;\ +u = texture2DRect(yuvTex, vec2(nx,ny)).b;\ +v = texture2DRect(yuvTex, vec2(nx,ny)).r;\ +y = 1.164383561643836 * (y - 0.0625);\ +u = u - 0.5;\ +v = v - 0.5;\ +float kb = 0.114;\ +float kr = 0.299;\ +float c = 2.276785714285714;\ +if(conversionType == 709){\ +kb = 0.0722;\ +kr = 0.2126;\ +}\ +r = y + c * (1.0 - kr) * v;\ +g = y - c * (1.0 - kb) * (kb / (1.0 - kb - kr)) * u - c * (1.0 - kr) * (kr / (1.0 - kb - kr)) * v;\ +b = y + c * (1.0 - kb) * u;\ +gl_FragColor = vec4(r * fade, g * fade, b * fade, 1.0 * fade);\ +}"; enum ofxThreadedVideoEventType{ VIDEO_EVENT_LOAD_OK = 0, @@ -56,15 +205,151 @@ struct AudioChannelMap{ }; #endif -class ofxThreadedVideoFade; +class ofxThreadedVideo; class ofxThreadedVideoEvent; -class ofxThreadedVideoCommand; + +class ofxThreadedVideoFade { + +public: + + ofxThreadedVideoFade(){ + fadeOriginal = -1.0; + }; + ofxThreadedVideoFade(int _frameStart, int _frameEnd, float _fadeTarget, bool _fadeSound, bool _fadeVideo, bool _fadeOnce): + frameStart(_frameStart), frameEnd(_frameEnd), fadeTarget(_fadeTarget), fadeSound(_fadeSound), fadeVideo(_fadeVideo), fadeOnce(_fadeOnce){ + fadeOriginal = -1.0; + frameDuration = frameEnd - frameStart; + }; + ~ofxThreadedVideoFade(){}; + + float getFade(float fadeCurrent, int frameCurrent){ + + if(fadeOriginal == -1.0f) fadeOriginal = fadeCurrent; + + if((frameCurrent - frameStart) <= frameEnd){ + + return fadeOriginal + (fadeTarget - fadeOriginal) * (float)((float)(frameCurrent - frameStart) / (float)frameDuration); + }else{ + fadeOriginal = -1.0f; + return fadeTarget; + } + + } + + bool getIsFading(int frameCurrent){ + if(frameCurrent >= frameStart && frameCurrent <= frameEnd){ + return true; + }else{ + fadeOriginal = -1.0f; + return false; + } + } + + bool getFadeDone(int frameCurrent){ + if(frameCurrent > frameEnd){ + return true; + }else{ + return false; + } + } + + int frameStart; + int frameEnd; + float frameDuration; + float fadeTarget; + float fadeOriginal; + bool fadeSound; + bool fadeVideo; + bool fadeOnce; + +}; + +class ofxThreadedVideoCommand { + +public: + + ofxThreadedVideoCommand(){ + setCommand("NULL_COMMAND", -1); + } + ofxThreadedVideoCommand(string _command, int _instanceID){ + setCommand(_command, _instanceID); + } + ~ofxThreadedVideoCommand(){ + instanceID = -1; + command.clear(); + args.clear(); + } + + void setCommand(string _command, int _instanceID){ + instanceID = _instanceID; + command = _command; + } + + int getInstance(){ + return instanceID; + } + + string getCommand(){ + return command; + } + + template + void setArgument(T arg){ + args.push_back(ofToString(arg)); + } + + template + T getArgument(int index){ + if(index > args.size() || index < 0){ + ofLogError() << "Argument index out of range: " << index << " : " << args.size(); + return NULL; + } + return getArgument(index, T()); + } + + string getArgument(int index, string t){ + return args[index]; + } + + int getArgument(int index, int t){ + return ofToInt(args[index]); + } + + float getArgument(int index, float t){ + return ofToFloat(args[index]); + } + + bool getArgument(int index, bool t){ + return ofToBool(args[index]); + } + + int getNumArguments(){ + return args.size(); + } + + string getCommandAsString(){ + ostringstream os; + os << command << "("; + for(int i = 0; i < args.size(); i++){ + os << args[i] << string(i < args.size() - 1 ? "," : ""); + } + os << ")"; + return os.str(); + } + +private: + + int instanceID; + string command; + vector args; + +}; + +static ofxThreadedVideoCommand ofxThreadedVideoNullCommand; static ofMutex ofxThreadedVideoGlobalMutex; static bool ofxThreadedVideoGlobalCritical = false; static int ofxThreadedVideoGlobalInstanceID = 0; -//static deque ofxThreadedVideoCommands; -//static ofxThreadedVideoCommand ofxThreadedVideoNullCommand; (declared below) static int ofxThreadedVideoLoadOk; static int ofxThreadedVideoLoadFail; @@ -84,7 +369,8 @@ class ofxThreadedVideo : public ofThread { ofPtr getPlayer(); - bool loadMovie(string path); + void load(const string& path); + void loadMovie(const string& path); void setPixelFormat(ofPixelFormat pixelFormat); ofPixelFormat getPixelFormat(); void closeMovie(); @@ -94,6 +380,10 @@ class ofxThreadedVideo : public ofThread { void play(); void stop(); + ofShader& getShader(); + void setUseInternalShader(bool b); + bool getUseInternalShader(); + bool isFrameNew(); unsigned char * getPixels(); ofPixelsRef getPixelsRef(); @@ -116,6 +406,7 @@ class ofxThreadedVideo : public ofThread { void setSpeed(float speed); void setFrame(int frame); + void setUseBlackStop(bool b); void setUseTexture(bool bUse); ofTexture & getTextureReference(); @@ -209,6 +500,16 @@ class ofxThreadedVideo : public ofThread { ofPixels * pixels; ofTexture drawTexture; + ofFbo fboYUY2; + ofShader shader; + bool bUseInternalShader; + + int textureInternalType; + int textureFormatType; + int texturePixelType; + + bool bUseBlackStop; + bool bForceBlack; bool bUseTexture; bool bIsFrameNew; bool bForceFrameNew; @@ -260,145 +561,9 @@ class ofxThreadedVideo : public ofThread { }; -class ofxThreadedVideoFade { - -public: - - ofxThreadedVideoFade(){ - fadeOriginal = -1.0; - }; - ofxThreadedVideoFade(int _frameStart, int _frameEnd, float _fadeTarget, bool _fadeSound, bool _fadeVideo, bool _fadeOnce): - frameStart(_frameStart), frameEnd(_frameEnd), fadeTarget(_fadeTarget), fadeSound(_fadeSound), fadeVideo(_fadeVideo), fadeOnce(_fadeOnce){ - fadeOriginal = -1.0; - frameDuration = frameEnd - frameStart; - }; - ~ofxThreadedVideoFade(){}; - - float getFade(float fadeCurrent, int frameCurrent){ - - if(fadeOriginal == -1.0f) fadeOriginal = fadeCurrent; - - if((frameCurrent - frameStart) <= frameEnd){ - - return fadeOriginal + (fadeTarget - fadeOriginal) * (float)((float)(frameCurrent - frameStart) / (float)frameDuration); - }else{ - fadeOriginal = -1.0f; - return fadeTarget; - } - - } - - bool getIsFading(int frameCurrent){ - if(frameCurrent >= frameStart && frameCurrent <= frameEnd){ - return true; - }else{ - fadeOriginal = -1.0f; - return false; - } - } - - bool getFadeDone(int frameCurrent){ - if(frameCurrent > frameEnd){ - return true; - }else{ - return false; - } - } - - int frameStart; - int frameEnd; - float frameDuration; - float fadeTarget; - float fadeOriginal; - bool fadeSound; - bool fadeVideo; - bool fadeOnce; - -}; -class ofxThreadedVideoCommand { - -public: - - ofxThreadedVideoCommand(){ - setCommand("NULL_COMMAND", -1); - } - ofxThreadedVideoCommand(string _command, int _instanceID){ - setCommand(_command, _instanceID); - } - ~ofxThreadedVideoCommand(){ - instanceID = -1; - command.clear(); - args.clear(); - } - - void setCommand(string _command, int _instanceID){ - instanceID = _instanceID; - command = _command; - } - - int getInstance(){ - return instanceID; - } - - string getCommand(){ - return command; - } - - template - void setArgument(T arg){ - args.push_back(ofToString(arg)); - } - - template - T getArgument(int index){ - if(index > args.size() || index < 0){ - ofLogError() << "Argument index out of range: " << index << " : " << args.size(); - return NULL; - } - T t; // template overload hack - return getArgument(index, t); - } - - string getArgument(int index, string t){ - return args[index]; - } - - int getArgument(int index, int t){ - return ofToInt(args[index]); - } - - float getArgument(int index, float t){ - return ofToFloat(args[index]); - } - - bool getArgument(int index, bool t){ - return ofToBool(args[index]); - } - - int getNumArguments(){ - return args.size(); - } - - string getCommandAsString(){ - ostringstream os; - os << command << "("; - for(unsigned int i = 0; i < args.size(); i++){ - os << args[i] << string(i < args.size() - 1 ? "," : ""); - } - os << ")"; - return os.str(); - } - -private: - - int instanceID; - string command; - vector args; - -}; -static ofxThreadedVideoCommand ofxThreadedVideoNullCommand; + class ofxThreadedVideoEvent{ @@ -422,3 +587,5 @@ inline ostream& operator<<(ostream& os, const ofxThreadedVideoEvent &e){ }; #endif + +#endif