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

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

아두이노 센서 인풋 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();
	}
}

저는 처음 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 로 테스트 해보시는 것이 좋을 것 같습니다.

안되면 말씀해 주세요

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

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()로 빠지면 좋을것 같습니다.

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

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

1 Like

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

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

1 Like

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