OF 아두이노 다중 영상제어 질문있습니다!

#1

미디어 아트 공부하고 있는 예술대학교 학생입니다!

아두이노 센서 인풋 3개에 따라서 영상을 제어하려고 하는데 어려움이 있습니다
아두이노 센서 인풋은 문자열 전체로 받아서 문자열 자른 후 정수로 변환해서 출력하고 있습니다

문제는 영상 부분입니다
센서 인풋 들어오기 전에 3분할로 영상을 띄워놓다가 각 센서에 따라 3분할 영상을 끄고 전체화면으로 영상을 띄우고 영상이 끝나면 다시 3분할 영상으로 돌아가려고 하는데 정상적으로 재생이 될 때도 있고 사운드만 재생되고 영상은 실행창에 띄워지지 않는 경우가 다반사입니다
지금은 테스트로 키인풋으로 지정해뒀는데 키 인풋도 정상적으로 들어갈 때, 그렇지 않을 때가 있으며, 사운드만 재생되고 영상이 띄워지지 않을 때는 더이상 루프가 돌지 않습니다. 정상적으로 될때도 두번 이상은 되지 않는 것 같습니다

콘솔 창이나 오류 창에 문제가 없어서 주변에 오픈프레임웍스를 다루는 사람이 없어서 물어볼 사람도 없고 자료도 많지 않아서 포럼에 질문 올립니다!

알고리즘에 어떤 문제가 있을까요?

헤더파일입니다.

#pragma once

#include "ofMain.h"
#include <string.h>
#include <stdlib.h>
#include <cstdlib>

class ofApp : public ofBaseApp
{

	public:
		void setup();
		void update();
		void draw();

		void videokey1Pressed(int key);
		void videokey2Pressed(int key);
		void videokey3Pressed(int key);
		void video3Update();
		void video4Update();
		void video5Update();



		char *sArr[3];
		int num[3];
		bool serialMessage;
		ofSerial serial;
		ofVideoPlayer myVideo[6];		
};

cpp 파일입니다

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup() {
	ofSetWindowShape(1280, 720);
	ofSetFrameRate(60);
	serialMessage = false;

	serial.enumerateDevices();
	//serial.listDevices();
	//vector <ofSerialDeviceInfo> deviceList = serial.getDeviceList();
	//serial.setup("COM3", 9600);

	myVideo[0].loadMovie("IMG_3076.MOV");
	myVideo[1].loadMovie("IMG_3076.MOV");
	myVideo[2].loadMovie("IMG_3076.MOV");
	myVideo[0].play();
	myVideo[1].play();
	myVideo[2].play();


}

//--------------------------------------------------------------
void ofApp::update() {
	myVideo[0].update();
	myVideo[1].update();
	myVideo[2].update();
	

	if (myVideo[3].isPlaying()) {
		myVideo[3].update();
	}

	if (myVideo[4].isPlaying()) {
		myVideo[4].update();
	}

	if (myVideo[5].isPlaying()) {
		myVideo[5].update();
	}
	
	/*serial.writeByte('a');

	if (serial.available()) {
		char byteData[15] = "";

		serial.readBytes(byteData, 15);
		char *sArr[3] = { NULL, };
		int i, j = 0;
		char *tok1 = strtok(byteData, ",");
		num[3];


		while (tok1 != NULL) {
			sArr[i] = tok1;
			i++;
			tok1 = strtok(NULL, ",");
		}

		for (i = 0; i < 3; i++) {
			if (sArr[i] != NULL) {
				//cout << sArr[i] << "\n";
				num[i] = atoi(sArr[i]);
				cout << num[i] << "\n";
			}
		}
	}
	//serial.flush();*/
}

//--------------------------------------------------------------
void ofApp::draw() {
	ofBackground(0);
	ofSetColor(255);
	
	myVideo[0].draw(0, ofGetHeight() / 3, ofGetWidth() / 3, ofGetHeight() / 3);
	myVideo[1].draw(ofGetWidth() / 3, ofGetHeight() / 3, ofGetWidth() / 3, ofGetHeight() / 3);
	myVideo[2].draw(ofGetWidth() / 3 * 2, ofGetHeight() / 3, ofGetWidth() / 3, ofGetHeight() / 3);


	if (myVideo[0].isPlaying() ||
		myVideo[1].isPlaying() ||
		myVideo[2].isPlaying())
	{
		myVideo[0].draw(0, ofGetHeight() / 3, ofGetWidth() / 3, ofGetHeight() / 3);
		myVideo[1].draw(ofGetWidth() / 3, ofGetHeight() / 3, ofGetWidth() / 3, ofGetHeight() / 3);
		myVideo[2].draw(ofGetWidth() / 3 * 2, ofGetHeight() / 3, ofGetWidth() / 3, ofGetHeight() / 3);


		videokey1Pressed('s');
		videokey2Pressed('b');
		videokey3Pressed('c');

	}


	if (myVideo[3].isPlaying()) {
		video3Update();
	}

	if (myVideo[4].isPlaying()) {
		video4Update();
	}

	if (myVideo[5].isPlaying()) {
		video5Update();
	}
}

void ofApp::video3Update() 
{
	myVideo[3].draw(0, 0, ofGetWidth(), ofGetHeight());
	if (myVideo[3].getCurrentFrame() >= myVideo[3].getTotalNumFrames() - 3) {
		myVideo[3].close();
		myVideo[0].loadMovie("IMG_3076.MOV");
		myVideo[1].loadMovie("IMG_3076.MOV");
		myVideo[2].loadMovie("IMG_3076.MOV");
		myVideo[0].play();
		myVideo[1].play();
		myVideo[2].play();
	}
}


void ofApp::video4Update() 
{
	myVideo[4].draw(0, 0, ofGetWidth(), ofGetHeight());
	if (myVideo[4].getCurrentFrame() >= myVideo[4].getTotalNumFrames() - 3) {
		myVideo[4].close();
		myVideo[0].loadMovie("IMG_3076.MOV");
		myVideo[1].loadMovie("IMG_3076.MOV");
		myVideo[2].loadMovie("IMG_3076.MOV");
		myVideo[0].play();
		myVideo[1].play();
		myVideo[2].play();
	}
}

void ofApp::video5Update()
{
	myVideo[5].draw(0, 0, ofGetWidth(), ofGetHeight());
	if (myVideo[5].getCurrentFrame() >= myVideo[5].getTotalNumFrames() - 3) {
		myVideo[5].close();
		myVideo[0].loadMovie("IMG_3076.MOV");
		myVideo[1].loadMovie("IMG_3076.MOV");
		myVideo[2].loadMovie("IMG_3076.MOV");
		myVideo[0].play();
		myVideo[1].play();
		myVideo[2].play();
	}
}
//--------------------------------------------------------------

void ofApp::videokey1Pressed(int key) {
	if (ofGetKeyPressed(key))
	{

		myVideo[0].close();
		myVideo[1].close();
		myVideo[2].close();
		myVideo[3].loadMovie("sample1.mp4");
		myVideo[3].play();

	}
}

void ofApp::videokey2Pressed(int key) {
	if (ofGetKeyPressed(key))
	{

		myVideo[0].close();
		myVideo[1].close();
		myVideo[2].close();
		myVideo[4].loadMovie("sample2.mp4");
		myVideo[4].play();

	}
}

void ofApp::videokey3Pressed(int key) {
	if (ofGetKeyPressed(key))
	{
		myVideo[0].close();
		myVideo[1].close();
		myVideo[2].close();
		myVideo[5].loadMovie("sample3.mp4");
		myVideo[5].play();
	}
}
#2

저는 처음 setup()에서 비디오를 다 로드시켜놓고 플레이 하는 방법을 사용합니다.

myVideo[0].loadMovie(" “);
myVideo[1].loadMovie(” “);
myVideo[2].loadMovie(” “);
myVideo[4].loadMovie(” “);
myVideo[5].loadMovie(” “);
myVideo[6].loadMovie(” ");

그리고 .setLoop 를 적용한 뒤,
필요한 부분에서 play, stop, draw를 해주는데요.

소스를 실행해 보진 않았지만

  1. close대신 stop으로 적용하면 될 것 같고
  2. video3,4,5는 OF_LOOP_NONE, video0,1,2는 OF_LOOP_NORMAL 로 테스트 해보시는 것이 좋을 것 같습니다.

안되면 말씀해 주세요

#3

우선 키입력부분에 있어서…

void videokey1Pressed(int key);
void videokey2Pressed(int key);
void videokey3Pressed(int key);

요부분이 s,b,c키로 대응되게끔 구현하신거 같은데.
그냥 keyPressed 함수 하나로 구현해야 하지 않을까요 ?

void keyPressed(int key){
    switch(key){
        case : 's'
            // do something
            break;
        case : 'b'
            break;
        case : 'c'
            // do something
            break;
        default : 
            // do something
            break;
    }
}

그리고 loadMovie()와 같이 저장장치에서 파일을 불러오는 함수는 상대적으로 상당히 무거운 작업이므로, @Subong_Jeong 님의 의견처럼 미리 전부 불러와놓고 상황에 따라서만 draw() 내에서 그려내는것이 좋습니다.(안그릴때는 stop()등을 사용) 다만 메모리가 많이 필요하겠죠.

그리고 update()내에서

요부분이 좀 수상해보이기도 한데요.

필요에 따라서 myVideo[]배열 중 일부분의 비디오를 update()한다면.
각 비디오가 재생되어야 하는지를 나타내는 bool 변수를 만들고, bool 변수 플래그를 true/false로 제어해서, 변수 상태에 따라서 update를 하도록 하는건 어떨까요 ?

저 상태라면 가령 myVideo[3]이 close()되버렸을때 문제가 발생할것 같기도 합니다.

다른 부분에서 말씀드릴부분이 있는데.
draw()에서는 화면에 그려내는 기능들만 구현하고, 그렇지 않은 로직부분들은 update()로 분리해두는것이 좋습니다.

아래부분들이 update()로 빠지면 좋을것 같습니다.

#4

setloop를 사용해보니 영상 초기화되는 부분에서 알고리즘 문제가 있더군요…

stop으로 사용하면 메모리 부하가 많이 걸려서 close로 그대로 사용하고
영상 초기화부분에 문제 있던 isPlaying 메서드를 isInitialized 바꿨더니 문제 없이 작동 되었습니다-

1 Like
#5

isPlaying 이게 영상 초기화 되는 부분에서 명확하게 동작을 안했던게 문제였습니다
isInitialized로 바꾸니 정상적으로 작동되더군요

업데이트가 항상 작동되면 메모리 부하때문에 일부 조건에서만 작동하도록 하는게 목적이었습니다…
저 코드에서 영상 초기화에 대한 판단만 바꾸면 정상적인 것 같습니다

1 Like
#6

그렇군요, 좋은 부분 공유해 주셔서 감사합니다.