できる?
/* 動画を動的に選択して読み込み、再生などする */
/*
<コントロール案>
・プログレスバー ・・・・・メイン画面の下の方にマウス置いたらプログレスバー出てきて欲しい
・再生ボタン ・・・・・
・停止ボタン ・・・・・
・終了ボタン ・・・・・
・色収差スライダ ・・・・・
・スリットスキャンスライダ ・・・・・スリットスキャンさせる
・ノイズ付加スライダ ・・・・・ノイズを付加させる(ノイズもいろんな種類を用意しておく)
・コントラストスライダ ・・・・・
・トーンカーブ ・・・・・
・スリットずらしスライダ ・・・・・Y軸の値ごとにスリットを左右にランダムでずらす機能(スリットの間隔もパラメタで決められるように)
・グリッチスライダ ・・・・・グリッチを発生させるスライダ
・残るグリッチスライダ ・・・・・なんかaviでグリッチやったらできる、画面に変化ない部分はピクセルが残っちゃうってタイプのグリッチスライダ
・顔だけ黒く塗りつぶすスライダ ・・・・・なんかホラーっぽくできるじゃん。openCVで可能かな
・目だけ黒く塗りつぶすスライダ ・・・・・同上。
・fps変更スライダ ・・・・・1~120くらいまで選べるようにする
・録画ボタン ・・・・・録画する
<その他案>
・スペース押したら再生/停止を切り替えられる
・動画選択後いきなり再生開始しないで、ちゃんと動画サイズに画面が切り替わって、再生ボタンを押してから再生開始する
<改善案>
・全画面とかにすると、カクカクになって、そうなったら録画する時もフレームが足りない状態になる
・それを避けるには録画する時だけ適切なフレームレートに切り替えるようにするしかない
・またはc++勉強してそっちで書きなおす
・いっぱいコントロール案書いたけど、もっともっと「processingらしいやつ」も足せるはずだよ。全部線にするとか。generativeなことしてくれ。
・あとノイズ、グリッチっぽいこともしてくれ。
・飯島真理のまりんの動画読み込んだら、なんかいつまでもmovie==nullのままらしい。実際画面でも読み込めてない。でも音声だけは再生される。
・これどうにかしてくれ。再生できないならできないで音声止めてくれ。
・しかもnullのままだと、動画をplay stopとかのボタンもバグっちゃうことになる。
・movieがnullの時は表示しないように、drawのなかでif文で書けばいいかな
・available==falseの場合、って書けば大丈夫っぽいな
・いやだめだった。
*/
/*
音声だけが出てフレームが画面に出ない場合、
なぜか「play」や「stop」のボタンを押せば出てくる場合もある
スライドバーを動かしたら出る時もある
これはなぜか後で解明
/*
<動画系関数>
■do系
movie.play() ・・・・・動画を再生
movie.pause() ・・・・・動画を一時停止
movie.stop() ・・・・・動画をストップ&巻き戻し
■セット系
movie.jump(フレーム数) ・・・・・指定された秒数?フレーム位置?どっち?かに動画を飛ばす
movie.speed(再生速度) ・・・・・再生速度を変更する(2なら2倍速、0.5なら0.5倍速)
movie.frameRate(fps値) ・・・・・任意のfpsに変更する(speed()と似てる)
■ゲット系
movie.duration() ・・・・・動画の全体フレーム数
movie.time() ・・・・・動画フレームの現在位置
movie.read() ・・・・・次のフレームを読み込む
*/
/* 留意
availableっていう関数がバグってる
if(movie.available()){
println(movie.available());
}
ってやったら「false」って表示される。意味不明
それでちょっとこのプログラムうまく制御できてない部分あったんだわ。
*/
/* インポート */
import processing.video.*;
import controlP5.*;
/* 変数宣言 */
//動画用
Movie movie = null; //動画
File selection; //ファイルパス
//コントロール用
ControlFrame cf; //コントロール用フレーム
int timeSlider; //タイムスライダ
boolean startUpdateProgressBar=false; //動画フレームとスライダをリンクさせるフラグ
int movieframeCnt=0; //動画のフレームカウンタ
void setup() {
/* 設定処理 */
size(500, 500); //初期カンバスサイズ
surface.setResizable(true); //リサイズ可にする
surface.setLocation(414,10); //メイン画面初期位置
/* 呼び出し処理 */
cf = new ControlFrame(this, 400, 500, "Controls"); //サブ画面大きさ指定
}
void draw() {
/* 動画選択前画面 */
if(movie == null){ //動画が読み込まれていないならば
background(0); //背景黒
}
/* 動画選択後画面 */
if (movie != null) { //動画が読み込まれているならば
image(movie, 0, 0, width, height); //現在フレームを表示
/* プログレスバーと動画進行の動機(現在不具合中。詳細はスライダの関数にて) */
//cf.updateProgressBar(int(movie.time())); //プログレスバーと動画フレームの同期
/* 動画編集処理 */
//編集かけるならここ
/* 録画処理 */
//録画機能を足すならここ
}
}
/* 動画の今のフレームを画像として読み込む(動画が読み込まれている時、毎フレームの先頭で発動) */
void movieEvent(Movie m) {
m.read(); //フレームを読み込む
/* フレーム編集画面 */
//ここでフレーム自体にグリッチかけるとかできる
}
/* ファイルを選択する(ボタンから発動)*/
void chooseFile(){
selection = new File(dataPath("") + ""); //動画に空欄パスを入れる
selectInput("動画を選択:", "fileSelected", selection); //動画を選択し、ファイル選択の設定を発動
}
/* ファイル選択の設定(ファイル選択後に発動) */
void fileSelected(File selection){ //ファイル選択画面において
/* ファイル画面 ― 分岐処理 */
if(selection == null) { //キャンセルをしたら
println ("選択キャンセル"); //ガイド
} else { //ファイルを選択したら
/* つじつま合わせ処理 */
cf.cp5.remove("タイムスライダ"); //前動画の編集で動的に配置したタイムスライダを一旦消す
startUpdateProgressBar=false; //前動画の編集で動的に設置したタイムスライダの設定を一旦消す
/* 動画読込処理 */
movie = new Movie(this, selection.getAbsolutePath()); //選択されたパスにある動画を読み込む
movie.play(); //動画再生開始
/* 動画情報取得ボタン追加処理 */
cf.cp5.addButton("動画情報取得ボタン").setLabel("GET MOVIE PARAMETER").plugTo(this, "getMovieParameter").setPosition(160,10); //動画情報取得ボタン設置
}
}
/* 動画情報を取得するフラグを立てる(動画情報取得ボタンを押したら発動) */
void getMovieParameter(){ //動画情報取得ボタンを押して、
if(movie!=null && movie.width>0){ //動画がちゃんと読み込まれているのならば、
cf.setProgressBarAround(); //動画情報取得(=プログレスバー表示)&その他つじつま合わせ
}
}
/* 動画サイズとフレームサイズを合わせる(ボタンから発動) */
void setOriginalSize(){ //リサイズボタンを押して
if(movie!=null && movie.width>0){ //動画がちゃんと読み込まれていたならば
surface.setSize(movie.width, movie.height); //動画に合わせて画面リサイズ
}
}
/* 終了する(ボタンから発動)(簡易版) */
void finApplet(){ //終了ボタンを押したら
exit(); //終了
/*案1(サブ画面に出せたらいいね)*/
//終了するか聞く
//YESなら終了(exit())
//NOなら何もしない
}
/* 動画を一時停止(ボタンから発動) */
void stopMovie(){ //stoボタン押して
if(movie!=null && movie.width>0){ //動画がちゃんと読み込まれているのならば
movie.pause(); //動画を一時停止
}
}
/* 動画を再生(ボタンから発動) */
void playMovie(){ //playボタンを押して
if(movie!=null && movie.width>0){ //動画がちゃんと読み込まれているのならば、
movie.play(); //動画を再生
}
}
/* タイムスライダ(スライダから発動) */
void timeSlider(int slider){
if(movie!=null && movie.width>0){
/*タイムスライダ調整処理(slider変数に入れた値=スライダーの値) */
/* movie.jump(slider)をやると、draw内からこの関数に常にアクセスされた時、「同じ秒数で変わらなくなる」という不具合が起こる。
でもupdateProgressBarをdraw内に置かないと、プログレスバーは動画と一緒には動かなくなる。
でも「同じ秒数で変わらなくなる」よりはマシなので、ひとまずその状態で保留中。
逆に「プログレスバーを動画に合わせて進行させて、プログレスバーをいじってジャンプさせるのを諦める」のならば、
movie.jump()をコメントアウトして、drawにあるupdateProgressBarをコメントアウトしなければいい
*/
movie.jump(slider); //スライダを動かしたらその位置にフレームを動かす(これが常に「現在のフレームに移動」を繰り返しちゃうのが問題)
/* 以下はok */
slider=(int)movie.time(); //初期位置として現在のフレーム位置をセット
}
}
/* 以下のような使い方をしないとprocessing3ではcontrolP5は動かせないのでこういう書き方してね */
class ControlFrame extends PApplet { //もう一つPAppletを作成(サブ画面)(使い方はコンストラクタ以外はメインの書き方と同じ)
/* グローバル変数宣言 ------------------------------------------------------------------------------ */
int w, h; //サブ画面のカンバスサイズ
PApplet parent; //親画面
ControlP5 cp5; //
/* コンストラクタ ---------------------------------------------------------------------------------- */
public ControlFrame(PApplet _parent, int _w, int _h, String _name) {
super(); //PAppletコンストラクタ呼び出し
parent = _parent; //親画面
w=_w; //サブ画面width
h=_h; //サブ画面height
PApplet.runSketch(new String[]{this.getClass().getName()}, this); //サブ画面起動
}
/* void settings() ---------------------------------------------------------------------------------- */
public void settings() {
size(w,h); //サブ画面のカンバスサイズ
}
/* void setup() ------------------------------------------------------------------------------------- */
public void setup() {
surface.setLocation(10,10); //サブ画面初期位置
cp5 = new ControlP5(this); //コントロールインスタンス生成
/* コントロール設定処理 */
//ボタン
cp5.addButton("ファイル選択ボタン").setLabel("CHOOSE FILE").plugTo(parent, "chooseFile").setPosition(10,10); //ファイル選択ボタン
cp5.addButton("リサイズボタン").setLabel("RESIZE").plugTo(parent, "setOriginalSize").setPosition(10,40); //リサイズボタン(動画サイズに合わせる)
cp5.addButton("終了ボタン").setLabel("FIN").plugTo(parent, "finApplet").setPosition(10,70); //終了ボタン
cp5.addButton("一時停止ボタン").setLabel("STOP").plugTo(parent, "stopMovie").setPosition(10,100); //一時停止ボタン
cp5.addButton("再生ボタン").setLabel("PLAY").plugTo(parent, "playMovie").setPosition(10,130); //再生ボタン
//スライダ
// cp5.addSlider("タイムスライダ").plugTo(parent, "timeSlider").setRange(0, (int) movie.duration()).setPosition(10, 260).setSize(200,10);
/* コントロール例
cp5.addSlider("speed").plugTo(parent, "speed").setRange(0, 0.1).setValue(0.01).setPosition(100, 260).setSize(200,20);
cp5.addButton("Save Frame").plugTo(parent, "saveFrame").setPosition(10,40);
cp5.addToggle("auto").plugTo(parent, "auto").setPosition(10,70);
cp5.addToggle("blend").plugTo(parent, "blend").setPosition(10,110);
cp5.addNumberbox("seed").plugTo(parent, "seed").setRange(0, 360).setValue(1).setPosition(100, 10).setSize(100,20);
cp5.addNumberbox("color").plugTo(parent, "c").setRange(0, 125).setValue(1).setPosition(100, 35).setSize(100,20);
cp5.addNumberbox("color2").plugTo(parent, "c2").setRange(0, 1000).setValue(1).setPosition(100, 60).setSize(100,20);
//パラメータ意味(大抵省略可能、追記可能)・・・・・例えばaddButtonを例に説明
addButton("ID名") ・・・・・
plugTo(parent, "変数名")・・・・・そのボタンを押した時に、メイン画面で使われてるその関数が起動する
そして、その関数の引数にスライダの値が入る
その関数が存在しない場合は、グローバル変数で同じ名前の変数があれば、それに値が入る
同じ名前のグローバル変数が無い場合は、機能しない
setLabel("表示名")・・・・・ボタンを表示する時の名前をセットする(省略すると最初にセットした関数名と同じものになる)
setPosition(x,y)・・・・・表示する座標
setSize(x,y)・・・・・表示サイズ
setRange(数1, 数2)・・・・・スライダーやトグルなどで、「最低値、最高値」をセットする(ボタンでは無理)
setValue(数1)・・・・・スライダのデフォ値を変更する(書かないと0)
//.setColorActive(C1) //押したときの色 引数はintとかcolorとか
//.setColorBackground(C1) //通常時の色
//.setColorForeground(recolor) //hoverしたときの色
*/
}
/* void draw() -------------------------------------------------------------------------------------- */
void draw() {
background(40); //サブ画面の背景色
}
/* 他関数群 -------------------------------------------------------------------------------------- */
/* プログレスバーを配置し、他つじつま合わせをする(動画情報取得ボタンで発動) */
void setProgressBarAround(){
cp5.addSlider("タイムスライダ").plugTo(parent, "timeSlider").setRange(movie.time(), (int) movie.duration()).setPosition(10, 260).setSize(200,10);
cp5.remove("動画情報取得ボタン"); //動画情報取得ボタンの削除
startUpdateProgressBar=true; //動画とプログレスバーをリンク開始する
}
/* スライダの値をプログレスバーと同期する */
void updateProgressBar(int progress){
if(movie!=null && movie.width>0 && startUpdateProgressBar==true){ //ちゃんと読み込めていて、なおかつプログレスバーと動画の同期フラグがtrueなら
cp5.getController("タイムスライダ").setValue(progress); //プログレスバー用スライダに、現在のタイム値を送る
}
}
}
これrunすれば再生はできる
だけどプログレッションバーみたいのができなくて困ってたんだ
結局今日はできなくてひとまず保留したんだ
なんか行数的にはめちゃくちゃ長いな
要らない機能足してるから、その1機能ごとに10数行とか使うからだよ
根幹は
・メイン画面
・サブ画面(クラス内にある)
・ボタンやスライダーとかのコントロール達(これを無駄に増やしつつある)
・膨大なコメント達
だから
メイン画面だけなら10行くらいで終わってる
サブ画面もボタンとかスルーしたら根幹は10行で終わってる
というかわりとコピペしてきたやつ
プログレッションバーはとりあえず保留しといて、
あと編集と録画機能加えれば動画編集になるんだよね
たぶん
(たまに動画ちゃんと読めないなどの不具合あれど)
思ったけどプログレッションバーいらなくない?
「現在の秒数=○○」とかいう感じで表示しておけば良くない?
上記のコードでは一応「好きな場所(秒数)にジャンプする」っていう機能はあるんだよね
スライドバーで
その横に現在の秒数を数字で表示しておけばひとまずよくない?いいよ。最終的には
じゃああとは編集機能足すことだね
それよりもまずは録画試してみるやつだね
録画機能足したら激重になって碌に動作しないみたいなことになるかもしれないし
しかし編集機能足した方が激重になる可能性大
毎フレーム毎フレームにprocessingから画像編集かけるとどうなるんだ
録画する時相当フレームレート下げないとフレーム抜けちゃうよ
( ˘ω˘ )