Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@akirayou
Last active April 3, 2022 05:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akirayou/8d206c3d3ec4ef9434c7b20bef50fcd2 to your computer and use it in GitHub Desktop.
Save akirayou/8d206c3d3ec4ef9434c7b20bef50fcd2 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script src="digest-fetch.js"></script>
<script src="script.js"></script>
</head>
<body>
<a-scene>
<a-camera wasd-controls-enabled="false"></a-camera>
<a-sky theta_preview id="asky" rotation="0 -90 0">
<a-sphere
material="
shader: flat;
src:tex.png;
blending:multiply;
transparent:true;
side:back;"
position="0 1.7 0"
radius="4" > </a-sphere>
</a-sky>
</a-scene>
</body>
</html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>replit</title>
</head>
<body>
Hello world
<button onclick="THETA.stopPreview();">stop</button>
</body>
</html>
/*
nginxなどで、/osc/をTHETAのIPに転送してしたうえで、そこにhtmlをおくことで、corss origin問題を回避する必用がある。
帯域は20Mbps程度 @ THETA Z1
location /osc/ {
proxy_pass http://192.168.1.134/osc/;
}
*/
/*
認証をスキップするために以下のライブラリを利用
https://www.npmjs.com/package/digest-fetch
*/
const DigestFetch = window.DigestFetch;
var THETA = THETA || {};
THETA.fetch=new DigestFetch("THETAYN35100930","35100930", { algorithm: 'MD5' });//THETAのシリアル番号を入れる(パスワード)
THETA.sleep = msec => new Promise(resolve => setTimeout(resolve, msec));
THETA.getStatus = async function () {
const res = await THETA.fetch.fetch('/osc/state', { method: 'POST' });
const data = await res.json();
console.log(data)
return data;
}
THETA.waitIdle = async function () {
for (var i = 0; i < 100; i++) {//wait for max 20 sec
const st = await THETA.getStatus();
if (st.state._captureStatus == 'idle') return true;
await THETA.sleep(200);
}
return false;
}
THETA.exec = async function (cmd) {
var ret = await THETA.waitIdle();
if (!ret) return false;
const res = await THETA.fetch.fetch('/osc/commands/execute', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cmd)
});
const data = await res.json();
return data;
}
THETA.startPreview = async function(srcSetFunc) {
THETA.isPreviewing = true;
var cmd = {
'name': 'camera.setOptions',
'parameters': {
"options": {
"previewFormat": {"width": 1920, "height": 960, "framerate": 8} ,
},
},
}
console.log("Setoptions result:"+ JSON.stringify(await THETA.exec(cmd)));
cmd = {
'name': 'camera.getLivePreview',
'parameters': {},
}
var ret = await THETA.waitIdle();
if (!ret){
THETA.isPreviewing = false;
return false;
}
const res = await THETA.fetch.fetch('/osc/commands/execute', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cmd)
});
let headers = '';
let contentLength = -1;
let imageBuffer = null;
let bytesRead = 0;
let frame=null;
const getLength = (headers) => {
let contentLength = -1;
headers.split('\n').forEach((header, _) => {
const pair = header.split(':');
if (pair[0].toLowerCase() === 'content-length') contentLength = pair[1];
})
return contentLength;
};
const reader = res.body.getReader();
var readBuffer = new Uint8Array(0);
while (true) {
if (!THETA.isPreviewing)reader.cancel();
const { value, done } = await reader.read();
if (done) {
console.log("preview stream end");
break;
}
tmp=new Uint8Array(readBuffer.length+value.length);
tmp.set(readBuffer);
tmp.set(value,readBuffer.length);
readBuffer=tmp;
if(0<contentLength){//JPEGデータそのものをきりだしたい
if(readBuffer.length>contentLength){
imageBuffer=readBuffer.slice(0,contentLength);
readBuffer=readBuffer.slice(contentLength);
srcSetFunc(imageBuffer);
imageBuffer=null;
contentLength = -1;
}
}else{//ヘッダを処理したい
idx=readBuffer.findIndex(e => e==0xff);
if(0<idx){
contentLength = getLength(new TextDecoder().decode( readBuffer.slice(0,idx)));
readBuffer=readBuffer.slice(idx)
}
}
}
THETA.isPreviewing=false;
}
THETA.stopPreview = function(){THETA.isPreviewing=false;}
start_preview=function () {
now_loading=false;
THETA.frame_tex=null;
const loader=new THREE.TextureLoader();
THETA.startPreview(function(imageBuffer){ //例えばここでimgタグのimg.src frameに入っているblob:~~というURLを設定すれば画像が見える
if(THETA.frame_tex===null && now_loading===false){//tickが遅すぎてtextureの消費がまにあってないならskip && texture loader が遅すぎて再突入するのを防止する
now_loading=true;
frame = URL.createObjectURL(new Blob([imageBuffer], { type: 'image/jpeg' }))
loader.load(frame ,(tex) =>{THETA.frame_tex=tex;now_loading=false;URL.revokeObjectURL(frame);} ); //今回はA-Frameようにtextureとして読み込んでとっておく
}
}).then();
};
AFRAME.registerComponent('theta_preview', {
init:function(){
start_preview();
this.material=this.el.getObject3D("mesh").material;
},
tick: function (time, timeDelta) {
if(THETA.isPreviewing===false)start_preview();// 再スタートする(撮影ボタンなどで中断された時の再起動用)
if(THETA.frame_tex){
if(!this.material.map)this.material.needsUpdate=true;//今までtextureが使われてなかったら必須
else this.material.map.dispose();//使い終わったtextureを消す(これやらないとメモリが大変な事になる)
this.material.map=THETA.frame_tex;
THETA.frame_tex=null;
}
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment