parent
eb68c1e5c9
commit
eaad8a51c2
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,406 @@ |
|||||||
|
<template> |
||||||
|
<v-card class="fill-height align-center"> |
||||||
|
<v-dialog v-model="fileSystem"> |
||||||
|
<v-card> |
||||||
|
<v-card-title>File System</v-card-title> |
||||||
|
<v-card-text> |
||||||
|
<v-file-input label="Upload" id="ufile"></v-file-input><v-btn @click="uploadfile">upload</v-btn> |
||||||
|
<v-row> |
||||||
|
<v-col cols="12" md="2" v-for="file in files" :key="file"> |
||||||
|
<v-card> |
||||||
|
{{file}} |
||||||
|
</v-card> |
||||||
|
</v-col> |
||||||
|
</v-row> |
||||||
|
</v-card-text> |
||||||
|
</v-card> |
||||||
|
</v-dialog> |
||||||
|
<v-dialog v-model="createSceneModel" max-width="300px"> |
||||||
|
<v-card> |
||||||
|
<v-card-title>New Scene</v-card-title> |
||||||
|
<v-card-text> |
||||||
|
<v-text-field v-model="sceneName" label="Scene Name"></v-text-field> |
||||||
|
</v-card-text> |
||||||
|
<v-card-actions> |
||||||
|
<v-btn text @click="createSceneModel=false">Cancel</v-btn> |
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn text color="primary" @click="createScene">Save</v-btn> |
||||||
|
</v-card-actions> |
||||||
|
</v-card> |
||||||
|
</v-dialog> |
||||||
|
<v-dialog v-model="createSceneItem" max-width="300px"> |
||||||
|
<v-card> |
||||||
|
<v-card-title>New Source</v-card-title> |
||||||
|
<v-card-text> |
||||||
|
<v-text-field v-model="sourceName" label="Source Name"></v-text-field> |
||||||
|
<v-select v-model="sourceType" item-value="value" item-text="name" :items="[{name:'Image', value:'image_source'},{name: 'VLC Source', value: 'vlc_source'},{name: 'Media Source', value: 'ffmpeg_source'},{name: 'Text', value: 'text_ft2_source_v2'}]" label="Source Type"></v-select> |
||||||
|
<v-text-field label="Image Path" v-model="sourceSettings.file" v-if="sourceType === 'image_source'"></v-text-field> |
||||||
|
<v-text-field label="File Path" v-model="sourceSettings.localFile" v-if="sourceType === 'ffmpeg_source'"></v-text-field> |
||||||
|
<div v-if="sourceType === 'vlc_source'"> |
||||||
|
<div v-for="(file, index) in sourceSettings.playlist" :key="index"> |
||||||
|
{{file}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<v-text-field v-if="sourceType === 'vlc_source'" v-model="sourceSettings.file"></v-text-field><v-btn small text @click="addPlaylist(sourceSettings.file)">+</v-btn> |
||||||
|
</v-card-text> |
||||||
|
<v-card-actions> |
||||||
|
<v-btn text @click="createSceneItem=false">Cancel</v-btn> |
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn text color="primary" @click="createSource">Save</v-btn> |
||||||
|
</v-card-actions> |
||||||
|
</v-card> |
||||||
|
</v-dialog> |
||||||
|
<v-card-text> |
||||||
|
<v-row> |
||||||
|
<v-col cols="12" md="9"> |
||||||
|
<v-card ref="mainvid" id="mainvid" |
||||||
|
:style="`font-size:10px;height: ${vidheight}px;background: #ccc;position: relative`" |
||||||
|
v-if="selecteScene"> |
||||||
|
<div :style="`border:1px solid #ccc;width:${source.cx*vidperm}px;z-index:${selecteScene.sources.length - index};height:${source.cy*vidperm}px;background-size: 100% 100%;top:${source.y*vidperm}px;left:${source.x*vidperm}px;position:absolute;min-width:50px;min-height:50px;background:url()`" |
||||||
|
v-for="(source,index) in selecteScene.sources" :key="index"> |
||||||
|
<div style="top:0;left:0;position: absolute;color:#fff;text-shadow: #000 1px 1px"> |
||||||
|
{{source.name}} ({{source.id}}) |
||||||
|
</div> |
||||||
|
<div style="top:0;right:0;position: absolute;color:#fff;text-shadow: #000 1px 1px"> |
||||||
|
{{source.type}} ({{source.source_cx}} x {{source.source_cy}} ) |
||||||
|
</div> |
||||||
|
<img v-if="source.srcdata" width="100%" height="100%" :src="source.srcdata"/> |
||||||
|
</div> |
||||||
|
</v-card> |
||||||
|
</v-col> |
||||||
|
<v-col cols="12" md="3"> |
||||||
|
<v-card v-if="selectedItemProps"> |
||||||
|
<v-card-text> |
||||||
|
<v-text-field label="Name" v-model="selectedItemProps.name"></v-text-field> |
||||||
|
<v-text-field :label="`Width (Source: ${selectedItemProps.sourceWidth})`" |
||||||
|
v-model="selectedItemProps.width" @keyup="selectedItemProps.height=selectedItemProps.width * (selectedItemProps.sourceHeight/selectedItemProps.sourceWidth)"></v-text-field> |
||||||
|
<v-text-field :label="`Height (Source: ${selectedItemProps.sourceHeight})`" |
||||||
|
v-model="selectedItemProps.height"></v-text-field> |
||||||
|
</v-card-text> |
||||||
|
<v-card-actions> |
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn small @click="saveSelectedItem">Save</v-btn> |
||||||
|
</v-card-actions> |
||||||
|
</v-card> |
||||||
|
<br/> |
||||||
|
<v-card v-if="selectedItemSourceProps"> |
||||||
|
<v-card-title>Source Options |
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn icon x-smal @click="panels.source = !panels.source"> |
||||||
|
<v-icon>mdi-menu</v-icon> |
||||||
|
</v-btn> |
||||||
|
</v-card-title> |
||||||
|
<v-card-text v-show="panels.source"> |
||||||
|
<v-text-field v-if="selectedItemSourceProps.sourceType === 'xcomposite_input'" |
||||||
|
label="Capture Window" |
||||||
|
v-model="selectedItemSourceProps.sourceSettings.capture_window"></v-text-field> |
||||||
|
<v-text-field v-if="selectedItemSourceProps.sourceType === 'image_source'" label="File" |
||||||
|
v-model="selectedItemSourceProps.sourceSettings.file"></v-text-field> |
||||||
|
<div v-if="selectedItemSourceProps.sourceType === 'vlc_source'"> |
||||||
|
<div v-for="(item, index) in selectedItemSourceProps.sourceSettings.playlist" |
||||||
|
:key="index"> |
||||||
|
<v-row> |
||||||
|
<v-col cols="12" md="10">{{item.value}}</v-col> |
||||||
|
<v-col cols="12" md="2"> |
||||||
|
<v-btn icon small |
||||||
|
@click="selectedItemSourceProps.sourceSettings.playlist.splice(index,1)"> |
||||||
|
<v-icon>mdi-delete</v-icon> |
||||||
|
</v-btn> |
||||||
|
</v-col> |
||||||
|
</v-row> |
||||||
|
</div> |
||||||
|
<v-text-field v-if="selectedItemSourceProps.sourceType === 'vlc_source'" label="File" |
||||||
|
v-model="selectedItemSourceProps.file"></v-text-field> |
||||||
|
|
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn small |
||||||
|
@click="selectedItemSourceProps.sourceSettings.playlist.push({ hidden: false, selected: false, value: selectedItemSourceProps.file}); selectedItemSourceProps.file=''"> |
||||||
|
Add To Playlist |
||||||
|
</v-btn> |
||||||
|
|
||||||
|
</div> |
||||||
|
</v-card-text> |
||||||
|
<v-card-actions v-show="panels.source"> |
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn small>Save</v-btn> |
||||||
|
</v-card-actions> |
||||||
|
</v-card> |
||||||
|
<br/> |
||||||
|
<v-card v-if="selectedItemProps"> |
||||||
|
<v-card-title>Position |
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn icon x-smal @click="panels.position = !panels.position" l> |
||||||
|
<v-icon>mdi-menu</v-icon> |
||||||
|
</v-btn> |
||||||
|
</v-card-title> |
||||||
|
<v-card-text v-show="panels.position"> |
||||||
|
<v-text-field label="X" v-model="selectedItemProps.position.x"></v-text-field> |
||||||
|
<v-text-field label="Y" v-model="selectedItemProps.position.y"></v-text-field> |
||||||
|
<v-text-field label="Rotation" v-model="selectedItemProps.rotation"></v-text-field> |
||||||
|
</v-card-text> |
||||||
|
<v-card-actions v-show="panels.position"> |
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn small>Save</v-btn> |
||||||
|
</v-card-actions> |
||||||
|
|
||||||
|
</v-card> |
||||||
|
<br/> |
||||||
|
|
||||||
|
<v-card v-if="selectedItemProps"> |
||||||
|
<v-card-title>Crop |
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn icon x-smal @click="panels.crop = !panels.crop"> |
||||||
|
<v-icon>mdi-menu</v-icon> |
||||||
|
</v-btn> |
||||||
|
</v-card-title> |
||||||
|
<v-card-text v-show="panels.crop"> |
||||||
|
<v-text-field label="Top" v-model="selectedItemProps.crop.top"></v-text-field> |
||||||
|
<v-text-field label="Left" v-model="selectedItemProps.crop.left"></v-text-field> |
||||||
|
<v-text-field label="Bottom" v-model="selectedItemProps.crop.bottom"></v-text-field> |
||||||
|
<v-text-field label="Right" v-model="selectedItemProps.crop.right"></v-text-field> |
||||||
|
</v-card-text> |
||||||
|
<v-card-actions v-show="panels.crop"> |
||||||
|
<v-spacer></v-spacer> |
||||||
|
<v-btn small>Save</v-btn> |
||||||
|
</v-card-actions> |
||||||
|
|
||||||
|
</v-card> |
||||||
|
</v-col> |
||||||
|
</v-row> |
||||||
|
<v-row> |
||||||
|
<v-col cols="12" md="3"> |
||||||
|
<v-list> |
||||||
|
<v-list-item-group v-model="selecteSceneName" color="primary"> |
||||||
|
|
||||||
|
<v-list-item v-for="(scene,index) in scenes" :key="index" @click="setSelect(scene)"> |
||||||
|
<v-list-item-content> |
||||||
|
<v-list-item-title v-text="scene.name"></v-list-item-title> |
||||||
|
</v-list-item-content> |
||||||
|
</v-list-item> |
||||||
|
<v-list-item> |
||||||
|
<v-list-item-content> |
||||||
|
<v-list-item-title @click="createSceneModel=true">New Scene</v-list-item-title> |
||||||
|
</v-list-item-content> |
||||||
|
</v-list-item> |
||||||
|
</v-list-item-group> |
||||||
|
</v-list> |
||||||
|
</v-col> |
||||||
|
|
||||||
|
<v-col cols="12" md="3"> |
||||||
|
<v-list v-if="selecteScene"> |
||||||
|
<v-list-item v-for="(source,index) in selecteScene.sources" :key="index" |
||||||
|
@click="setItemSelect(source)"> |
||||||
|
<v-list-item-content> |
||||||
|
<v-list-item-title v-text="source.name"></v-list-item-title> |
||||||
|
</v-list-item-content> |
||||||
|
</v-list-item> |
||||||
|
<v-list-item> |
||||||
|
<v-list-item-content> |
||||||
|
<v-list-item-title @click="createSceneItem=true">New Item</v-list-item-title> |
||||||
|
</v-list-item-content> |
||||||
|
</v-list-item> |
||||||
|
</v-list> |
||||||
|
</v-col> |
||||||
|
</v-row> |
||||||
|
</v-card-text> |
||||||
|
</v-card> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
const OBSWebSocket = require('obs-websocket-js'); |
||||||
|
|
||||||
|
export default { |
||||||
|
name: "ObsVue", |
||||||
|
props: { |
||||||
|
server: String |
||||||
|
}, |
||||||
|
data: () => ({ |
||||||
|
obs: null, |
||||||
|
selectedItemProps: null, |
||||||
|
selectedItemSourceProps: null, |
||||||
|
createSceneModel: false, |
||||||
|
createSceneItem: false, |
||||||
|
sourceSettings: { |
||||||
|
playlist: [], |
||||||
|
file: '', |
||||||
|
localFile: '' |
||||||
|
}, |
||||||
|
files: [ |
||||||
|
'test.jpg', |
||||||
|
'test.png' |
||||||
|
], |
||||||
|
sourceType: '', |
||||||
|
sourceName: '', |
||||||
|
scenes: [], |
||||||
|
sources: [], |
||||||
|
panels: { |
||||||
|
source: false, |
||||||
|
position: false, |
||||||
|
crop: false |
||||||
|
}, |
||||||
|
previewInterval: 0, |
||||||
|
selecteScene: null, |
||||||
|
sceneName: '', |
||||||
|
vidheight: 0, |
||||||
|
vidperm: 0, |
||||||
|
selecteSceneName: null, |
||||||
|
fileSystem: true |
||||||
|
|
||||||
|
}), |
||||||
|
mounted() { |
||||||
|
this.obs = new OBSWebSocket() |
||||||
|
this.getfiles() |
||||||
|
this.obs.connect({address: 'ws://localhost:4444', password: 'neverdie'}).then(this.connected) |
||||||
|
this.obs.on('error', err => { |
||||||
|
console.error('socket error:', err); |
||||||
|
}); |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
uploadfile() { |
||||||
|
var file = document.getElementById('ufile') |
||||||
|
console.log(file.files[0]) |
||||||
|
var filereader = new FileReader() |
||||||
|
filereader.onloadend = () => { |
||||||
|
this.$axios.post('http://localhost:5000/api/upload', {"file": filereader.result.split(';base64,')[1], 'file_name': file.files[0].name}).then(this.getfiles) |
||||||
|
} |
||||||
|
|
||||||
|
filereader.readAsDataURL(file.files[0]); |
||||||
|
}, |
||||||
|
getfiles () { |
||||||
|
this.$axios.get('http://localhost:5000/api/files').then(result => { |
||||||
|
this.files = result.data |
||||||
|
}) |
||||||
|
}, |
||||||
|
addPlaylist(item) { |
||||||
|
this.sourceSettings.playlist.push({hidden: false, selected: false, value:item}) |
||||||
|
console.log(this.sourceSettings) |
||||||
|
}, |
||||||
|
createScene() { |
||||||
|
this.obs.send('CreateNewScene', {'sceneName': this.sceneName}).then(response => { |
||||||
|
console.log(response) |
||||||
|
this.sceneName = '' |
||||||
|
this.createSceneModel = false |
||||||
|
this.sceneList() |
||||||
|
}) |
||||||
|
}, |
||||||
|
createSource() { |
||||||
|
var sourceSetting; |
||||||
|
if (this.sourceType === 'vlc_source') sourceSetting = {playlist: this.sourceSettings.playlist} |
||||||
|
if (this.sourceType === 'ffmpeg_source') sourceSetting = {localfile: this.sourceSettings.localfile} |
||||||
|
if (this.sourceType === 'image_source') sourceSetting = {file: this.sourceSettings.file} |
||||||
|
console.log({sourceName: this.sourceName,sourceSettings: sourceSetting, sourceType: this.sourceType }) |
||||||
|
this.obs.send('CreateNewSource', {sourceName: this.sourceName,sourceSettings: sourceSetting, sourceType: this.sourceType }).then(response => { |
||||||
|
console.log(response) |
||||||
|
this.sceneName = '' |
||||||
|
this.createSceneModel = false |
||||||
|
this.obs.send('AddToScene', {sourceName:this.sourceName }) |
||||||
|
this.sceneList() |
||||||
|
}) |
||||||
|
}, |
||||||
|
onAuth() { |
||||||
|
console.log("auth") |
||||||
|
}, |
||||||
|
newScene() { |
||||||
|
|
||||||
|
}, |
||||||
|
setItemSelect(item) { |
||||||
|
this.obs.send("GetSceneItemProperties", { |
||||||
|
item: item.name, |
||||||
|
"scene-name": this.selecteScene.name |
||||||
|
}).then(data => { |
||||||
|
console.log("GetSceneItemProperties") |
||||||
|
console.log(data) |
||||||
|
this.selectedItemProps = data |
||||||
|
}) |
||||||
|
this.obs.send("GetSourceSettings", {sourceName: item.name}).then(data => { |
||||||
|
console.log("GetSourceSettings") |
||||||
|
console.log(data) |
||||||
|
this.selectedItemSourceProps = data |
||||||
|
}) |
||||||
|
}, |
||||||
|
setSelect(item) { |
||||||
|
console.log(item) |
||||||
|
this.selecteScene = item |
||||||
|
this.selecteSceneName = item.name |
||||||
|
this.obs.send('GetSourcesList').then(data => { |
||||||
|
console.log('GetSourcesList') |
||||||
|
console.log(data) |
||||||
|
}) |
||||||
|
|
||||||
|
if (this.previewInterval > 0) clearInterval(this.previewInterval) |
||||||
|
this.previewInterval = setInterval(() => { |
||||||
|
this.selecteScene.sources.forEach(sitem => { |
||||||
|
this.obs.send('TakeSourceScreenshot', { |
||||||
|
sourceName: sitem.name, |
||||||
|
embedPictureFormat: 'png' |
||||||
|
}).then(data => { |
||||||
|
sitem.srcdata = data.img |
||||||
|
this.selecteScene.__ob__.dep.notify() |
||||||
|
this.vidheight = document.getElementById('mainvid').offsetWidth / (16 / 9) |
||||||
|
this.vidperm = this.vidheight / 1080.0 |
||||||
|
}).catch(err => { |
||||||
|
console.log(err) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, 500) |
||||||
|
|
||||||
|
}, |
||||||
|
saveSelectedItem() { |
||||||
|
console.log( { |
||||||
|
'item': this.selectedItemProps.name, |
||||||
|
position: { |
||||||
|
x: parseInt(this.selectedItemProps.position.x), |
||||||
|
y: parseInt(this.selectedItemProps.position.y), |
||||||
|
}, |
||||||
|
crop: this.selectedItemProps.crop, |
||||||
|
rotation: this.selectedItemProps.rotation, |
||||||
|
height: this.selectedItemProps.height, |
||||||
|
scale: {x:this.selectedItemProps.width/this.selectedItemProps.sourceWidth,y:this.selectedItemProps.height/this.selectedItemProps.sourceHeight} |
||||||
|
}) |
||||||
|
this.obs.send('SetSceneItemProperties', { |
||||||
|
item: this.selectedItemProps.name, |
||||||
|
position: { |
||||||
|
x: parseInt(this.selectedItemProps.position.x), |
||||||
|
y: parseInt(this.selectedItemProps.position.y), |
||||||
|
}, |
||||||
|
crop: { |
||||||
|
top:parseInt(this.selectedItemProps.crop.top), |
||||||
|
bottom:parseInt(this.selectedItemProps.crop.bottom), |
||||||
|
left:parseInt(this.selectedItemProps.crop.left), |
||||||
|
right:parseInt(this.selectedItemProps.crop.right), |
||||||
|
}, |
||||||
|
rotation: this.selectedItemProps.rotation, |
||||||
|
height: this.selectedItemProps.height, |
||||||
|
scale: {x:this.selectedItemProps.width/this.selectedItemProps.sourceWidth,y:this.selectedItemProps.height/this.selectedItemProps.sourceHeight} |
||||||
|
}).then(data => { |
||||||
|
console.log(data) |
||||||
|
this.sceneList() |
||||||
|
}) |
||||||
|
}, |
||||||
|
sceneList() { |
||||||
|
this.obs.send('GetSceneList').then(data => { |
||||||
|
console.log("scene", data) |
||||||
|
this.scenes = data.scenes |
||||||
|
data.scenes.forEach(item => { |
||||||
|
if (item.name === data["current-scene"]) { |
||||||
|
this.setSelect(item) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
}, |
||||||
|
connected() { |
||||||
|
this.obs.send('GetVersion').then(data => { |
||||||
|
this.obs.send('GetVersion').then(data2 => { |
||||||
|
console.log(data) |
||||||
|
console.log(data2) |
||||||
|
}) |
||||||
|
}) |
||||||
|
this.sceneList() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,112 @@ |
|||||||
|
<template> |
||||||
|
<RemoteFeed v-if="remoteStream" :single-view="true" :opaqueId="opaqueId" :mypvtid="mypvtid" :feedid="remoteStream.id" :remote-stream="remoteStream" :janusInit="janusInit" :room="1234" ></RemoteFeed> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import RemoteFeed from "@/lib/RemoteFeed"; |
||||||
|
export default { |
||||||
|
name: "RemoteFeedOnly", |
||||||
|
props: { |
||||||
|
server: String, |
||||||
|
room: Number, |
||||||
|
user: String |
||||||
|
}, |
||||||
|
components: {RemoteFeed}, |
||||||
|
data: () => ({ |
||||||
|
remoteStream: null, |
||||||
|
opaqueId: null, |
||||||
|
mypvtid: null, |
||||||
|
janusInit: null, |
||||||
|
run: false |
||||||
|
}), |
||||||
|
mounted() { |
||||||
|
this.janusInit = new this.$janus({ |
||||||
|
success: this.janusSuccess, |
||||||
|
server: this.server, |
||||||
|
error: function (error) { |
||||||
|
this.$janus.error(error); |
||||||
|
}, |
||||||
|
//webrtcState: this.webrtcState, |
||||||
|
destroyed: function () { |
||||||
|
window.location.reload(); |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
}, |
||||||
|
methods: { |
||||||
|
janusMessage(msg, jsep) { |
||||||
|
console.log(msg); |
||||||
|
var event = msg["videoroom"]; |
||||||
|
|
||||||
|
if (event !== undefined) { |
||||||
|
|
||||||
|
if (event === "joined") { |
||||||
|
this.myid = msg["id"]; |
||||||
|
this.mypvtid = msg["private_id"]; |
||||||
|
this.$janus.log("Successfully joined room " + msg["room"] + " with ID " + this.myid); |
||||||
|
// this.restartDevices() |
||||||
|
if (msg["publishers"] !== undefined && msg["publishers"] !== null) { |
||||||
|
msg['publishers'].forEach(publisher => { |
||||||
|
console.log(publisher.id) |
||||||
|
console.log(publisher) |
||||||
|
if (publisher.display === this.user) { |
||||||
|
this.remoteStream = publisher |
||||||
|
this.run = true |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} else if (event === "event") { |
||||||
|
if (msg["publishers"] !== undefined && msg["publishers"] !== null) { |
||||||
|
msg['publishers'].forEach(publisher => { |
||||||
|
console.log(publisher.id) |
||||||
|
console.log(publisher) |
||||||
|
if (publisher.display === this.user) { |
||||||
|
this.remoteStream = publisher |
||||||
|
this.run = true |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} else if (msg["leaving"] !== undefined && msg["leaving"] !== null) { |
||||||
|
console.log("leaving") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (jsep !== undefined && jsep !== null) { |
||||||
|
|
||||||
|
console.log("Handling SDP as well..."); |
||||||
|
console.log(jsep); |
||||||
|
this.pluginHandle.handleRemoteJsep({jsep: jsep}); |
||||||
|
var audio = msg["audio_codec"]; |
||||||
|
if (this.mystream && this.mystream.getAudioTracks() && this.mystream.getAudioTracks().length > 0 && !audio) { |
||||||
|
console.log("Our audio stream has been rejected, viewers won't hear us"); |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
janusPluginSuccess (pluginHandle) { |
||||||
|
this.pluginHandle = pluginHandle |
||||||
|
this.$janus.log("Plugin attached! (" + this.pluginHandle.getPlugin() + ", id=" + this.pluginHandle.getId() + ")"); |
||||||
|
this.$janus.log(" -- This is a publisher/manager"); |
||||||
|
|
||||||
|
var register = { "request": "join", "room": this.room, "ptype": "publisher" }; |
||||||
|
pluginHandle.send({"message": register}); |
||||||
|
}, |
||||||
|
janusSuccess() { |
||||||
|
this.opaqueId = "videoroomtest-" + this.$janus.randomString(12); |
||||||
|
|
||||||
|
this.janusInit.attach( |
||||||
|
{ |
||||||
|
plugin: "janus.plugin.videoroom", |
||||||
|
opaqueId: this.opaqueId, |
||||||
|
success: this.janusPluginSuccess, |
||||||
|
error: this.janusPluginError, |
||||||
|
onmessage: this.janusMessage, |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,720 @@ |
|||||||
|
<template> |
||||||
|
<v-container> |
||||||
|
<v-row class="fill-height"> |
||||||
|
<v-col cols="24" md="1"> |
||||||
|
<v-card width="100%" dark class="fill-height"> |
||||||
|
<v-card-text> |
||||||
|
<v-row> |
||||||
|
<v-col> |
||||||
|
<v-icon @click="addItemStart('text')">mdi-format-color-text</v-icon> |
||||||
|
</v-col> |
||||||
|
<v-col> |
||||||
|
<v-icon @mousedown="addItemStart('rect')" @mouseup="clearStart()"> |
||||||
|
mdi-rectangle-outline |
||||||
|
</v-icon> |
||||||
|
</v-col> |
||||||
|
<v-col> |
||||||
|
<v-icon @mousedown="addItemStart('image')" @mouseup="clearStart()">mdi-image</v-icon> |
||||||
|
</v-col> |
||||||
|
</v-row> |
||||||
|
</v-card-text> |
||||||
|
</v-card> |
||||||
|
</v-col> |
||||||
|
<v-col cols="24" md="9"> |
||||||
|
<v-card width="100%" min-height="600" dark class="fill-height"> |
||||||
|
<v-card-text color="white"> |
||||||
|
<div ref="vid" @click="handleAction" style="width: 100%;background: #fff;position: relative"> |
||||||
|
<div v-for="(track, index) in mainTracks" :key="index"> |
||||||
|
<div v-for="(keyframe, index) in track.keyframes" :key="index"> |
||||||
|
<div @click="selectTrack(track)" |
||||||
|
v-if="keyframe.start <= currentTime && keyframe.end >=currentTime && track.type === 'text'" |
||||||
|
@mouseenter="colorBorder(track)" |
||||||
|
@mouseleave="colorBorderClear(track)" @mousedown="itemMoveStart" |
||||||
|
@mouseup="itemMoveEnd" :ref="'item'+track.id" @dblclick="editText(track)" |
||||||
|
:style="`padding:4px;color:${track.color};position:absolute;opacity:${vidTracks[track.id].opacity};top:${vidTracks[track.id].y-4}px;left:${vidTracks[track.id].x-4}px;font-size:${track.size};font-family:${track.font};border: 1px solid ${selectedTrack?(selectedTrack.id === track.id?'#ff0000':'transparent'):'transparent'}`" |
||||||
|
> |
||||||
|
<span :style="`line-height:${vidTracks[track.id].lineHeight}!important;letter-spacing:${vidTracks[track.id].letterSpacing}!important;`" v-html="track.text.replace(/\n/g, '<br>')"></span> |
||||||
|
<div></div> |
||||||
|
</div> |
||||||
|
<div @click="selectTrack(track)" @mouseenter="colorBorder(track)" |
||||||
|
v-if="keyframe.start <= currentTime && keyframe.end >=currentTime && track.type === 'image'" |
||||||
|
@mouseleave="colorBorderClear(track)" @mousedown="itemMoveStart" |
||||||
|
@mouseup="itemMoveEnd" :ref="'item'+track.id" @dblclick="editText(track)" |
||||||
|
:style="`padding:4px;color:${track.color};position:absolute;opacity:${vidTracks[track.id].opacity};top:${vidTracks[track.id].y-4}px;left:${vidTracks[track.id].x-4}px;font-size:${track.size};font-family:${track.font};border: 1px solid ${selectedTrack?(selectedTrack.id === track.id?'#ff0000':'transparent'):'transparent'}`" |
||||||
|
> |
||||||
|
<img :src="track.image_data" |
||||||
|
:width="vidTracks[track.id].width>0?vidTracks[track.id].width+'px':''" |
||||||
|
:height="vidTracks[track.id].height>0?vidTracks[track.id].height+'px':''"> |
||||||
|
<div></div> |
||||||
|
</div> |
||||||
|
<div @click="selectTrack(track)" @mouseenter="colorBorder(track)" |
||||||
|
v-if="keyframe.start <= currentTime && keyframe.end >=currentTime && track.type === 'rect'" |
||||||
|
@mouseleave="colorBorderClear(track)" @mousedown="itemMoveStart" |
||||||
|
@mouseup="itemMoveEnd" :ref="'item'+track.id" @dblclick="editText(track)" |
||||||
|
:style="`padding:4px;color:${track.color};position:absolute;opacity:${vidTracks[track.id].opacity};top:${vidTracks[track.id].y-4}px;left:${vidTracks[track.id].x-4}px;font-size:${track.size};font-family:${track.font};border: 1px solid ${selectedTrack?(selectedTrack.id === track.id?'#ff0000':'transparent'):'transparent'}`" |
||||||
|
> |
||||||
|
<div :style="`width:${vidTracks[track.id].width}px;height:${vidTracks[track.id].height}px;background-color:${track.color}`"></div> |
||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</v-card-text> |
||||||
|
</v-card> |
||||||
|
</v-col> |
||||||
|
<v-col cols="24" md="2"> |
||||||
|
<v-card width="100%" dark class="fill-height"> |
||||||
|
<v-card-text> |
||||||
|
<v-row> |
||||||
|
<v-col v-if="selectedTrack"> |
||||||
|
<v-text-field v-if="selectedTrack.type === 'text'" label="Font Size" |
||||||
|
placeholder="Font Size" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].size" |
||||||
|
@keyup="mainTracks.__ob__.dep.notify()"></v-text-field> |
||||||
|
<v-textarea v-if="selectedTrack.type === 'text'" label="Text" |
||||||
|
@keyup="mainTracks.__ob__.dep.notify()" placeholder="Text" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].text"></v-textarea> |
||||||
|
<v-text-field v-if="selectedTrack.type !== 'text'" label="Name" |
||||||
|
@keyup="mainTracks.__ob__.dep.notify()" placeholder="Name" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].text"></v-text-field> |
||||||
|
|
||||||
|
<v-menu |
||||||
|
ref="menu" |
||||||
|
v-model="colorMenu" |
||||||
|
:close-on-content-click="false" |
||||||
|
|
||||||
|
transition="scale-transition" |
||||||
|
offset-y |
||||||
|
min-width="290px" |
||||||
|
v-if="selectedTrack.type !== 'image'" |
||||||
|
> |
||||||
|
<template v-slot:activator="{ on }"> |
||||||
|
<v-text-field |
||||||
|
v-model="mainTracks[currentKeyTrack.track].color" |
||||||
|
label="Color" |
||||||
|
readonly |
||||||
|
v-on="on" |
||||||
|
></v-text-field> |
||||||
|
</template> |
||||||
|
<v-color-picker v-model="mainTracks[currentKeyTrack.track].color" no-title |
||||||
|
scrollable show-swatches> |
||||||
|
<v-spacer></v-spacer> |
||||||
|
</v-color-picker> |
||||||
|
</v-menu> |
||||||
|
<v-text-field v-if="selectedTrack.type !== 'text'" label="Width" |
||||||
|
@keyup="mainTracks.__ob__.dep.notify()" placeholder="Width" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].keyframes[currentKeyTrack.keyframe].width"></v-text-field> |
||||||
|
|
||||||
|
<v-text-field v-if="selectedTrack.type === 'text'" label="Line Height" |
||||||
|
@keyup="mainTracks.__ob__.dep.notify()" placeholder="Line Height" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].keyframes[currentKeyTrack.keyframe].lineHeight"></v-text-field> |
||||||
|
<v-text-field v-if="selectedTrack.type === 'text'" label="Letter Spacing" |
||||||
|
@keyup="mainTracks.__ob__.dep.notify()" placeholder="Letter Spacing" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].keyframes[currentKeyTrack.keyframe].letterSpacing"></v-text-field> |
||||||
|
<v-text-field v-if="selectedTrack.type !== 'text'" label="Height" |
||||||
|
@keyup="mainTracks.__ob__.dep.notify()" placeholder="Height" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].keyframes[currentKeyTrack.keyframe].height"></v-text-field> |
||||||
|
<v-text-field v-if="selectedTrack.type === 'text'" label="Font" |
||||||
|
@keyup="mainTracks.__ob__.dep.notify()" placeholder="Text" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].font"></v-text-field> |
||||||
|
<v-text-field label="X" @keyup="mainTracks.__ob__.dep.notify()" placeholder="X" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].keyframes[currentKeyTrack.keyframe].x"></v-text-field> |
||||||
|
<v-text-field label="Y" @keyup="mainTracks.__ob__.dep.notify()" placeholder="Y" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].keyframes[currentKeyTrack.keyframe].y"></v-text-field> |
||||||
|
<v-text-field label="Opacity" @keyup="mainTracks.__ob__.dep.notify()" |
||||||
|
placeholder="Opacity" |
||||||
|
v-model="mainTracks[currentKeyTrack.track].keyframes[currentKeyTrack.keyframe].opacity"></v-text-field> |
||||||
|
<v-btn small text @click="newKeyFrame">new keyframe</v-btn> |
||||||
|
<v-btn small text @click="newMask">new mask</v-btn> |
||||||
|
|
||||||
|
</v-col> |
||||||
|
</v-row> |
||||||
|
</v-card-text> |
||||||
|
</v-card> |
||||||
|
</v-col> |
||||||
|
<v-col cols="12" md="12"> |
||||||
|
<v-card width="100%" min-height="100" dark> |
||||||
|
<v-card-text ref="videoPanel"> |
||||||
|
<div id="video_tracks" ref="vidPanelTracks" @mouseleave="allmoveend"> |
||||||
|
<div :ref="'vidtrack'+track.id" v-for="(track, index) in mainTracks" :key="index" |
||||||
|
style="position: relative;padding: 3px"> |
||||||
|
<div @click="selectTrack(track)" @mousedown="startPositionTrack" @mouseup="allmoveend" |
||||||
|
|
||||||
|
:style="`border:1px solid ${selectedTrack?(selectedTrack.id===track.id?'#f00':'#ccc'):'#ccc'};position: absolute;height:23px;top:${(index*23)}px;left:${((track.start/timeLength)*100)}%;width:${((track.end-track.start)/timeLength)*100}%`"> |
||||||
|
<div style="background: #ededed;right: 0px;top:0px;position: absolute;height: 22px;width: 5px;" |
||||||
|
@mousedown="startChangeSizeTrack" @mouseup="allmoveend()"></div> |
||||||
|
<div>{{ track.text }} ({{ (track.end - track.start).toFixed(2) }} sec)</div> |
||||||
|
<div v-for="(keyframe , index) in track.keyframes" :key="index" |
||||||
|
:style="`position:absolute;height:8px;width:8px;background:red;top:6px;margin-left:-4px;left:${(((keyframe.start - track.start)/track.end)*100)}%`"></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div style="position: absolute;width: 5px; background: #aa00ff;height: 120px;top:3px;" |
||||||
|
ref="currentTime" @mousedown="moveStartTime=true" @mouseup="moveStartTime=false"> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
</v-card-text> |
||||||
|
<v-card-actions> |
||||||
|
<v-text-field label="Total Secs" v-model="timeLength"></v-text-field> |
||||||
|
<v-text-field label="Current" v-model="currentTime"></v-text-field> |
||||||
|
<v-btn @click="preview">Start</v-btn> |
||||||
|
<v-btn @click="previewStop">Stop</v-btn> |
||||||
|
</v-card-actions> |
||||||
|
</v-card> |
||||||
|
</v-col> |
||||||
|
</v-row> |
||||||
|
<div ref="vm"> |
||||||
|
<v-icon color="primary" :style="'position: absolute;left:' + moveX + 'px;top:'+ moveY + 'px'" |
||||||
|
v-if="create==='text'">mdi-format-color-text |
||||||
|
</v-icon> |
||||||
|
<v-icon color="primary" :style="'position: absolute;left:' + moveX + 'px;top:'+ moveY + 'px'" |
||||||
|
v-if="create==='image'">mdi-image |
||||||
|
</v-icon> |
||||||
|
<v-icon color="primary" :style="'position: absolute;left:' + moveX + 'px;top:'+ moveY + 'px'" |
||||||
|
v-if="create==='rect'">mdi-rectangle-outline |
||||||
|
</v-icon> |
||||||
|
<div :style="`position: absolute;border:1px solid #ff0000;width:${width}px;height:${height}px;left:${moveX}px;top:${moveY}px`" |
||||||
|
ref="rectcreate" v-if="create==='rect' && action==='paint'"></div> |
||||||
|
<div :style="`position: absolute;border:1px solid #ff0000;width:${width}px;height:${height}px;left:${moveX}px;top:${moveY}px`" |
||||||
|
ref="mask" v-if="oncreateMask && action==='paint'"></div> |
||||||
|
</div> |
||||||
|
</v-container> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: "Animator", |
||||||
|
data: () => ({ |
||||||
|
currentKeyTrack: { |
||||||
|
keyframe: 0, |
||||||
|
track: 0 |
||||||
|
}, |
||||||
|
vidTracks: {}, |
||||||
|
action: null, |
||||||
|
item: null, |
||||||
|
create: null, |
||||||
|
index: 1, |
||||||
|
colorPick: '', |
||||||
|
timeLength: 60, |
||||||
|
moveStartTime: false, |
||||||
|
currentTime: 0, |
||||||
|
oncreateMask: false, |
||||||
|
pinterval: 0, |
||||||
|
width: 0, |
||||||
|
colorMenu: false, |
||||||
|
heigth: 0, |
||||||
|
clickOffset: { |
||||||
|
x: 0, |
||||||
|
y: 0 |
||||||
|
}, |
||||||
|
moveX: 0, |
||||||
|
mainTracks: localStorage.getItem('animator')?JSON.parse(localStorage.getItem('animator')):[], |
||||||
|
moveItem: false, |
||||||
|
moveY: 0, |
||||||
|
selectedTrack: null, |
||||||
|
sizeChangeStart: false, |
||||||
|
positionChangeStart: false, |
||||||
|
editingItem: null |
||||||
|
}), |
||||||
|
mounted() { |
||||||
|
this.$refs.vid.style.height = (this.$refs.vid.offsetWidth / (16 / 9)) + "px" |
||||||
|
window.onmousemove = (event) => { |
||||||
|
this.itemMove(event) |
||||||
|
var bodyRect = document.body.getBoundingClientRect() |
||||||
|
if (this.moveItem && this.currentKeyTrack) { |
||||||
|
var elemRect = this.$refs.vid.getBoundingClientRect(), |
||||||
|
offsetY = elemRect.top - bodyRect.top, |
||||||
|
offsetX = elemRect.left - bodyRect.left |
||||||
|
this.mainTracks[this.currentKeyTrack.track].y = (event.clientY - offsetY) - this.clickOffset.y |
||||||
|
this.mainTracks[this.currentKeyTrack.track].x = (event.clientX - offsetX) - this.clickOffset.x |
||||||
|
this.mainTracks[this.currentKeyTrack.track].keyframes[this.currentKeyTrack.keyframe].x = (event.clientX - offsetX) - this.clickOffset.x |
||||||
|
this.mainTracks[this.currentKeyTrack.track].keyframes[this.currentKeyTrack.keyframe].y = (event.clientY - offsetY) - this.clickOffset.y |
||||||
|
this.mainTracks.__ob__.dep.notify() |
||||||
|
} |
||||||
|
if (this.moveStartTime) { |
||||||
|
console.log('') |
||||||
|
|
||||||
|
var vidtrack = this.$refs.vidPanelTracks.getBoundingClientRect() |
||||||
|
var offsetXVid = vidtrack.left - bodyRect.left |
||||||
|
var pos = (event.clientX - offsetXVid + 12) |
||||||
|
if (pos >= 15 && pos <= vidtrack.width + 15) { |
||||||
|
this.$refs.currentTime.style.left = pos + "px" |
||||||
|
console.log(offsetXVid, pos, vidtrack.width) |
||||||
|
this.currentTime = (this.timeLength / vidtrack.width) * (pos - 15) |
||||||
|
} |
||||||
|
} |
||||||
|
if (this.selectedTrack && this.positionChangeStart) { |
||||||
|
var bodyRect3 = document.body.getBoundingClientRect(), |
||||||
|
elemRect3 = this.$refs['vidtrack' + this.selectedTrack.id][0].getBoundingClientRect(), |
||||||
|
offsetX3 = elemRect3.left - bodyRect3.left |
||||||
|
var length2 = this.timeLength / 100 |
||||||
|
|
||||||
|
var totalLength2 = (((((event.clientX - this.clickOffset.x) - offsetX3)) / elemRect3.width) * length2) * 100 |
||||||
|
this.mainTracks.forEach(track => { |
||||||
|
var tn = track.end - track.start |
||||||
|
var originalstart = track.start |
||||||
|
if (track.id === this.selectedTrack.id) { |
||||||
|
track.start = totalLength2 |
||||||
|
track.end = track.start + tn |
||||||
|
track.keyframes.forEach(keyframe => { |
||||||
|
var tnx = track.end - track.start |
||||||
|
keyframe.start = track.start + (originalstart - track.start) |
||||||
|
keyframe.end = track.start + tnx |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
if (this.selectedTrack && this.sizeChangeStart) { |
||||||
|
var bodyRect2 = document.body.getBoundingClientRect(), |
||||||
|
elemRect2 = this.$refs['vidtrack' + this.selectedTrack.id][0].getBoundingClientRect(), |
||||||
|
offsetX2 = elemRect2.left - bodyRect2.left |
||||||
|
var length = this.timeLength / 100 |
||||||
|
|
||||||
|
var totalLength = ((((event.clientX - offsetX2) + 2) / elemRect2.width) * length) * 100 |
||||||
|
this.mainTracks.forEach(track => { |
||||||
|
if (track.id === this.selectedTrack.id) track.end = totalLength |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
window.onkeyup = (event) => { |
||||||
|
console.log(event.key) |
||||||
|
if (event.target === document.body) { |
||||||
|
if (event.key === 'ArrowDown' && this.selectedTrack) this.mainTracks[this.currentKeyTrack.track].keyframes[this.currentKeyTrack.keyframe].y++ |
||||||
|
if (event.key === 'ArrowUp' && this.selectedTrack) this.mainTracks[this.currentKeyTrack.track].keyframes[this.currentKeyTrack.keyframe].y-- |
||||||
|
if (event.key === 'ArrowLeft' && this.selectedTrack) this.mainTracks[this.currentKeyTrack.track].keyframes[this.currentKeyTrack.keyframe].x-- |
||||||
|
if (event.key === 'ArrowRight' && this.selectedTrack) this.mainTracks[this.currentKeyTrack.track].keyframes[this.currentKeyTrack.keyframe].x++ |
||||||
|
if (event.key === "Escape") { |
||||||
|
this.selectedTrack = null |
||||||
|
this.action = null |
||||||
|
this.create = null |
||||||
|
this.moveItem = false |
||||||
|
this.sizeChangeStart = false |
||||||
|
this.positionChangeStart = false |
||||||
|
this.moveStartTime = false |
||||||
|
this.previewStop() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
|
||||||
|
editingItem(newval, oldval) { |
||||||
|
console.log(newval) |
||||||
|
console.log('old', oldval) |
||||||
|
// if (oldval !== null) { |
||||||
|
// this.vidTracks.forEach(item => { |
||||||
|
// if (item.id === newval.id) item = newval |
||||||
|
// }) |
||||||
|
// } |
||||||
|
}, |
||||||
|
mainTracks (newval) { |
||||||
|
console.log('maintrack change') |
||||||
|
localStorage.setItem('animator', JSON.stringify(newval)) |
||||||
|
}, |
||||||
|
currentTime(newval) { |
||||||
|
if (newval) { |
||||||
|
var videoPanel = this.$refs.vidPanelTracks.getBoundingClientRect() |
||||||
|
var left = videoPanel.width / this.timeLength |
||||||
|
if (!this.moveStartTime) this.$refs.currentTime.style.left = ((left * newval) + 15) + "px" |
||||||
|
this.vidTracks = [] |
||||||
|
this.mainTracks.forEach((track, tindex) => { |
||||||
|
|
||||||
|
if (track.start <= newval && newval <= track.end) { |
||||||
|
var ttrack = track |
||||||
|
var keyframe = null |
||||||
|
var nextframe = null |
||||||
|
track.keyframes.forEach((kvarey, index) => { |
||||||
|
if (kvarey.start <= newval && newval <= kvarey.end) { |
||||||
|
keyframe = kvarey |
||||||
|
|
||||||
|
if (this.selectedTrack) { |
||||||
|
if (this.selectedTrack.id === track.id) { |
||||||
|
this.currentKeyTrack.keyframe = index |
||||||
|
this.currentKeyTrack.track = tindex |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
ttrack.x = keyframe.x |
||||||
|
ttrack.y = keyframe.y |
||||||
|
ttrack.width = keyframe.width |
||||||
|
ttrack.height = keyframe.height |
||||||
|
ttrack.opacity = keyframe.opacity |
||||||
|
|
||||||
|
var starter = null |
||||||
|
track.keyframes.forEach((kvarey, index) => { |
||||||
|
if (keyframe.end <= kvarey.start) { |
||||||
|
if (kvarey.start < starter || starter === null) nextframe = index |
||||||
|
if (starter === null) starter = kvarey.start |
||||||
|
} |
||||||
|
}) |
||||||
|
if (nextframe !== null) { |
||||||
|
console.log(nextframe) |
||||||
|
if (track.type === 'text') { |
||||||
|
ttrack.letterSpacing = keyframe.letterSpacing |
||||||
|
ttrack.lineHeight = keyframe.lineHeight |
||||||
|
if (track.keyframes[nextframe].lineHeight !== ttrack.lineHeight) { |
||||||
|
var difflineHeight = (track.keyframes[nextframe].lineHeight - ttrack.lineHeight) |
||||||
|
difflineHeight = difflineHeight / (keyframe.end - keyframe.start) |
||||||
|
difflineHeight = (newval - keyframe.start) * difflineHeight |
||||||
|
ttrack.lineHeight = parseFloat(ttrack.lineHeight) + parseFloat(difflineHeight) |
||||||
|
} |
||||||
|
if (track.keyframes[nextframe].letterSpacing !== ttrack.letterSpacing) { |
||||||
|
var diffletterSpacing = (track.keyframes[nextframe].letterSpacing - ttrack.letterSpacing) |
||||||
|
diffletterSpacing = diffletterSpacing / (keyframe.end - keyframe.start) |
||||||
|
diffletterSpacing = (newval - keyframe.start) * diffletterSpacing |
||||||
|
ttrack.lineHeight = parseFloat(ttrack.letterSpacing) + parseFloat(diffletterSpacing) |
||||||
|
} |
||||||
|
} |
||||||
|
if (track.keyframes[nextframe].x !== ttrack.x) { |
||||||
|
var diffx = (track.keyframes[nextframe].x - ttrack.x) |
||||||
|
diffx = diffx / (keyframe.end - keyframe.start) |
||||||
|
diffx = (newval - keyframe.start) * diffx |
||||||
|
ttrack.x = parseFloat(ttrack.x) + parseFloat(diffx) |
||||||
|
} |
||||||
|
if (track.keyframes[nextframe].width !== ttrack.width) { |
||||||
|
var diffwidth = (track.keyframes[nextframe].width - ttrack.width) |
||||||
|
diffwidth = diffwidth / (keyframe.end - keyframe.start) |
||||||
|
diffwidth = (newval - keyframe.start) * diffwidth |
||||||
|
ttrack.width = parseFloat(ttrack.width) + parseFloat(diffwidth) |
||||||
|
} |
||||||
|
if (track.keyframes[nextframe].height !== ttrack.height) { |
||||||
|
|
||||||
|
console.log('heig', track.keyframes[nextframe].height, ttrack.height) |
||||||
|
var diffheight = (track.keyframes[nextframe].height - ttrack.height) |
||||||
|
diffheight = diffheight / (keyframe.end - keyframe.start) |
||||||
|
diffheight = (newval - keyframe.start) * diffheight |
||||||
|
ttrack.height = parseFloat(ttrack.height) + parseFloat(diffheight) |
||||||
|
console.log(ttrack.height) |
||||||
|
|
||||||
|
} |
||||||
|
if (track.keyframes[nextframe].opacity !== ttrack.opacity) { |
||||||
|
console.log('opa', track.keyframes[nextframe].opacity, ttrack.opacity) |
||||||
|
var diffopacity = (track.keyframes[nextframe].opacity - ttrack.opacity) |
||||||
|
diffopacity = parseFloat(diffopacity) / parseFloat(keyframe.end - keyframe.start) |
||||||
|
console.log(diffopacity) |
||||||
|
diffopacity = (newval - keyframe.start) * diffopacity |
||||||
|
ttrack.opacity = parseFloat(ttrack.opacity) + parseFloat(diffopacity) |
||||||
|
console.log(ttrack.opacity) |
||||||
|
} |
||||||
|
|
||||||
|
if (track.keyframes[nextframe].y !== ttrack.y) { |
||||||
|
var diffy = (track.keyframes[nextframe].y - ttrack.y) |
||||||
|
diffy = diffy / (keyframe.end - keyframe.start) |
||||||
|
diffy = (newval - keyframe.start) * diffy |
||||||
|
ttrack.y = parseFloat(ttrack.y) + parseFloat(diffy) |
||||||
|
} |
||||||
|
} |
||||||
|
this.vidTracks[track.id] = ttrack |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
newMask() { |
||||||
|
this.oncreateMask = true |
||||||
|
this.create = 'mask' |
||||||
|
this.action = "create" |
||||||
|
}, |
||||||
|
itemMoveStart(event) { |
||||||
|
console.log(event) |
||||||
|
this.moveItem = true |
||||||
|
this.clickOffset.x = event.offsetX |
||||||
|
this.clickOffset.y = event.offsetY |
||||||
|
}, |
||||||
|
preview() { |
||||||
|
this.pinterval = setInterval(() => { |
||||||
|
this.currentTime += 1 / 60 |
||||||
|
if (this.currentTime >= 60) this.currentTime = 0 |
||||||
|
}, 1000 / 60) |
||||||
|
}, |
||||||
|
previewStop() { |
||||||
|
if (this.pinterval) clearInterval(this.pinterval) |
||||||
|
}, |
||||||
|
newKeyFrame() { |
||||||
|
this.mainTracks.forEach(track => { |
||||||
|
if (track.id === this.selectedTrack.id) { |
||||||
|
var pushFrame = null |
||||||
|
var newFrames = [] |
||||||
|
var endTime = null |
||||||
|
track.keyframes.forEach(keyframe => { |
||||||
|
if (keyframe.start <= this.currentTime && keyframe.end >= this.currentTime) { |
||||||
|
pushFrame = { |
||||||
|
start: keyframe.start, |
||||||
|
x: keyframe.x, |
||||||
|
y: keyframe.y, |
||||||
|
width: keyframe.width, |
||||||
|
opacity: keyframe.opacity, |
||||||
|
height: keyframe.height, |
||||||
|
} |
||||||
|
pushFrame.start = this.currentTime |
||||||
|
keyframe.end = this.currentTime |
||||||
|
} |
||||||
|
if (pushFrame && pushFrame.start < keyframe.start) { |
||||||
|
endTime = keyframe.start |
||||||
|
} |
||||||
|
newFrames.push(keyframe) |
||||||
|
}) |
||||||
|
pushFrame.end = endTime |
||||||
|
if (!pushFrame.end) pushFrame.end = track.end |
||||||
|
newFrames.push(pushFrame) |
||||||
|
track.keyframes = newFrames |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
selectTrack(track) { |
||||||
|
if (this.selectedTrack === track) { |
||||||
|
this.selectedTrack = null |
||||||
|
return |
||||||
|
} |
||||||
|
this.selectedTrack = track |
||||||
|
console.log(this.selectedTrack) |
||||||
|
this.mainTracks.forEach((track, tindex) => { |
||||||
|
|
||||||
|
if (this.selectedTrack.id === track.id) { |
||||||
|
|
||||||
|
track.keyframes.forEach((kvarey, index) => { |
||||||
|
if (kvarey.start <= this.currentTime && this.currentTime <= kvarey.end) { |
||||||
|
this.currentKeyTrack.keyframe = index |
||||||
|
this.currentKeyTrack.track = tindex |
||||||
|
|
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
startChangeSizeTrack() { |
||||||
|
this.sizeChangeStart = true |
||||||
|
console.log("start size") |
||||||
|
} |
||||||
|
, startPositionTrack(event) { |
||||||
|
|
||||||
|
if (!this.sizeChangeStart) this.positionChangeStart = true |
||||||
|
console.log("start pos", event) |
||||||
|
this.clickOffset.x = event.offsetX |
||||||
|
}, |
||||||
|
deselectTrack() { |
||||||
|
this.selectedTrack = null |
||||||
|
this.sizeChangeStart = false |
||||||
|
this.positionChangeStart = false |
||||||
|
}, |
||||||
|
allmoveend() { |
||||||
|
this.sizeChangeStart = false |
||||||
|
this.positionChangeStart = false |
||||||
|
}, |
||||||
|
colorBorderClear(track) { |
||||||
|
var refItem = this.$refs['item' + track.id][0] |
||||||
|
var id = "" |
||||||
|
if (this.selectedTrack !== null) { |
||||||
|
id = this.selectedTrack.id |
||||||
|
} |
||||||
|
if (id !== track.id) { |
||||||
|
refItem.style.border = "1px solid transparent" |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
colorBorder(track) { |
||||||
|
|
||||||
|
var refItem = this.$refs['item' + track.id][0] |
||||||
|
var id = "" |
||||||
|
if (this.selectedTrack !== null) { |
||||||
|
id = this.selectedTrack.id |
||||||
|
} |
||||||
|
if (id !== track.id) { |
||||||
|
refItem.style.border = "1px solid #ededed" |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
itemMoveEnd() { |
||||||
|
this.moveItem = false |
||||||
|
}, |
||||||
|
newTrack() { |
||||||
|
this.tracks.push({}) |
||||||
|
}, |
||||||
|
editItem(item) { |
||||||
|
console.log(item) |
||||||
|
this.editingItem = item |
||||||
|
var ref = this.$refs['item' + item.id][0] |
||||||
|
console.log(ref) |
||||||
|
// this.vidTracks.forEach(item => { |
||||||
|
// var refItem = this.$refs['item' + item.id][0] |
||||||
|
// refItem.style.border = "1px solid transparent" |
||||||
|
// |
||||||
|
// }) |
||||||
|
ref.style.border = "1px solid #000" |
||||||
|
}, |
||||||
|
itemMove(event) { |
||||||
|
|
||||||
|
if (this.action) { |
||||||
|
if (this.action === 'create') { |
||||||
|
this.moveX = event.clientX - 30 |
||||||
|
this.moveY = event.clientY - 30 |
||||||
|
} |
||||||
|
|
||||||
|
if (this.action === 'paint') { |
||||||
|
this.width = event.clientX - this.moveX |
||||||
|
this.height = event.clientY - this.moveY |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
handleAction() { |
||||||
|
console.log(this.action) |
||||||
|
if (this.action === "create" || this.action === 'paint') { |
||||||
|
var bodyRect = document.body.getBoundingClientRect(), |
||||||
|
elemRect = this.$refs.vid.getBoundingClientRect(), |
||||||
|
offsetY = elemRect.top - bodyRect.top, |
||||||
|
offsetX = elemRect.left - bodyRect.left |
||||||
|
if ((this.create === 'rect' || this.create === 'mask') && this.action === 'create') { |
||||||
|
this.action = 'paint' |
||||||
|
return |
||||||
|
} |
||||||
|
if (this.create === 'mask') { |
||||||
|
|
||||||
|
|
||||||
|
this.mainTracks[this.currentKeyTrack.track].mask = { |
||||||
|
x: this.moveX - offsetX, |
||||||
|
y: this.moveY - offsetY, |
||||||
|
width: this.width, |
||||||
|
height: this.height, |
||||||
|
} |
||||||
|
this.mainTracks.__ob__.dep.notify() |
||||||
|
this.oncreateMask = false |
||||||
|
return |
||||||
|
} |
||||||
|
console.log(offsetY, offsetX) |
||||||
|
var item = { |
||||||
|
x: this.moveX - offsetX, |
||||||
|
y: this.moveY - offsetY, |
||||||
|
width: 0, |
||||||
|
height: 0, |
||||||
|
type: this.create, |
||||||
|
opacity: 1, |
||||||
|
index: this.index, |
||||||
|
id: new Date().getTime(), |
||||||
|
color: "#000", |
||||||
|
mask: null |
||||||
|
} |
||||||
|
if (this.create === 'image') { |
||||||
|
var upload = document.createElement('input') |
||||||
|
upload.type = 'file' |
||||||
|
upload.click() |
||||||
|
upload.onchange = () => { |
||||||
|
const reader = new FileReader(); |
||||||
|
reader.readAsDataURL(upload.files[0]); |
||||||
|
reader.onloadend = () => { |
||||||
|
item.image_data = reader.result |
||||||
|
var image = new Image(); |
||||||
|
image.src = reader.result |
||||||
|
image.onload = () => { |
||||||
|
console.log(item) |
||||||
|
this.index++ |
||||||
|
|
||||||
|
var maintrack = item |
||||||
|
maintrack.keyframes = [{ |
||||||
|
x: item.x, |
||||||
|
y: item.y, |
||||||
|
width: image.width, |
||||||
|
opacity: 1, |
||||||
|
height: image.height, |
||||||
|
start: this.currentTime, |
||||||
|
end: this.timeLength, |
||||||
|
lineHeight: 'default', |
||||||
|
letterSpacing: 'default' |
||||||
|
}] |
||||||
|
maintrack.start = this.currentTime |
||||||
|
maintrack.end = this.timeLength |
||||||
|
this.mainTracks.push(maintrack) |
||||||
|
this.vidTracks[item.id] = item |
||||||
|
this.action = null |
||||||
|
this.create = null |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
console.log(item) |
||||||
|
|
||||||
|
console.log(upload.files) |
||||||
|
} |
||||||
|
} else { |
||||||
|
|
||||||
|
|
||||||
|
console.log(item) |
||||||
|
this.index++ |
||||||
|
|
||||||
|
var maintrack = item |
||||||
|
maintrack.keyframes = [{ |
||||||
|
x: item.x, |
||||||
|
y: item.y, |
||||||
|
width: 0, |
||||||
|
height: 0, |
||||||
|
opacity: 1, |
||||||
|
lineHeight: 'initial', |
||||||
|
letterSpacing: 'initial', |
||||||
|
start: this.currentTime, |
||||||
|
end: this.timeLength |
||||||
|
}] |
||||||
|
if (this.create === 'rect') { |
||||||
|
maintrack.keyframes[0].width = this.width |
||||||
|
maintrack.keyframes[0].height = this.height |
||||||
|
} |
||||||
|
maintrack.start = this.currentTime |
||||||
|
maintrack.end = this.timeLength |
||||||
|
this.mainTracks.push(maintrack) |
||||||
|
|
||||||
|
if (this.create === 'text') { |
||||||
|
item.text = "Text" |
||||||
|
item.font = "Arial" |
||||||
|
item.size = '24px' |
||||||
|
item.color = '#000' |
||||||
|
item.align = 'left' |
||||||
|
item.lineHeight = 'initial' |
||||||
|
item.letterSpacing = 'initial' |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
this.vidTracks[item.id] = item |
||||||
|
this.action = null |
||||||
|
this.create = null |
||||||
|
} |
||||||
|
this.currentTime += 0.01 |
||||||
|
this.selectTrack(maintrack) |
||||||
|
|
||||||
|
} |
||||||
|
}, |
||||||
|
addItemStart(type) { |
||||||
|
console.log(type) |
||||||
|
this.create = type |
||||||
|
this.action = 'create' |
||||||
|
}, |
||||||
|
clearStart() { |
||||||
|
this.create = null |
||||||
|
}, |
||||||
|
getTracks() { |
||||||
|
this.tracks.forEach(item => { |
||||||
|
console.log(item) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
#video_edit { |
||||||
|
width: 1280px; |
||||||
|
height: 720px; |
||||||
|
border: 1px solid #ccc; |
||||||
|
} |
||||||
|
|
||||||
|
#video_tracks { |
||||||
|
min-height: 100px; |
||||||
|
padding: 2px; |
||||||
|
width: 100%; |
||||||
|
border: 1px solid #ccc; |
||||||
|
overflow-y: auto; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,15 @@ |
|||||||
|
<template> |
||||||
|
<obs-vue server="ws://localhost:4444/"></obs-vue> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import ObsVue from "@/lib/ObsVue"; |
||||||
|
export default { |
||||||
|
name: "StreamControl", |
||||||
|
components: {ObsVue} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,52 @@ |
|||||||
|
<template> |
||||||
|
<div style="width: 1280px; height: 720px"> |
||||||
|
|
||||||
|
<RemoteFeedOnly @kick="kick" @rtp="rtp" v-if="rid" :creator="creator" :user="$route.params.user" :room="rid" server="ws://localhost:8188/ws" :username="name"></RemoteFeedOnly> |
||||||
|
<!-- <ObsVue server="ws://localhost:4444/"></ObsVue>--> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
// import VueJanus from "@/lib/VueJanus"; |
||||||
|
import RemoteFeedOnly from "@/lib/RemoteFeedOnly"; |
||||||
|
export default { |
||||||
|
name: "RoomView", |
||||||
|
// components: {VueJanus}, |
||||||
|
components: {RemoteFeedOnly}, |
||||||
|
data: () => ({ |
||||||
|
rid:'', |
||||||
|
name:'', |
||||||
|
dialog:false, |
||||||
|
creator:false |
||||||
|
}), |
||||||
|
mounted () { |
||||||
|
// if (!name) this.dialog = true |
||||||
|
this.getRoom() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
kick (user) { |
||||||
|
this.$axios.get(`kick/${this.$route.params.id}/${user}`).then(response => { |
||||||
|
console.log(response) |
||||||
|
}) |
||||||
|
}, |
||||||
|
rtp (user) { |
||||||
|
this.$axios.get(`rtp/${this.$route.params.id}/${user}`).then(response => { |
||||||
|
console.log(response) |
||||||
|
}) |
||||||
|
}, |
||||||
|
getRoom () { |
||||||
|
this.dialog = false |
||||||
|
this.$axios.get(`room/${this.$route.params.id}`).then(response => { |
||||||
|
this.rid = response.data.rid |
||||||
|
this.creator = response.data.can_modify |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
body , html, div { |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue