diff --git a/control.sh b/control.sh index cfcb347..3793fc4 100644 --- a/control.sh +++ b/control.sh @@ -15,12 +15,13 @@ load_config() { [ -f "$CONFIG_FILE" ] || return SOURCE_TYPE=$(grep -o '"source_type":"[^"]*"' "$CONFIG_FILE" 2>/dev/null | cut -d'"' -f4) RTSP_URL=$(grep -o '"rtsp_url":"[^"]*"' "$CONFIG_FILE" 2>/dev/null | cut -d'"' -f4) + TCP_URL=$(grep -o '"tcp_url":"[^"]*"' "$CONFIG_FILE" 2>/dev/null | cut -d'"' -f4) MP4_PATH=$(grep -o '"mp4_path":"[^"]*"' "$CONFIG_FILE" 2>/dev/null | cut -d'"' -f4) RES_W=$(grep -o '"res_w":[0-9]*' "$CONFIG_FILE" 2>/dev/null | cut -d: -f2) RES_H=$(grep -o '"res_h":[0-9]*' "$CONFIG_FILE" 2>/dev/null | cut -d: -f2) FPS=$(grep -o '"fps":[0-9]*' "$CONFIG_FILE" 2>/dev/null | cut -d: -f2) ROTATION=$(grep -o '"rotation":[0-9]*' "$CONFIG_FILE" 2>/dev/null | cut -d: -f2) - : ${SOURCE_TYPE:=mp4} ${RTSP_URL:=rtsp://192.168.1.100:8554/stream} + : ${SOURCE_TYPE:=mp4} ${RTSP_URL:=rtsp://192.168.1.100:8554/stream} ${TCP_URL:=tcp://192.168.1.100:5000} : ${MP4_PATH:=/sdcard/Movies/2.mp4} ${RES_W:=1920} ${RES_H:=1080} ${FPS:=30} ${ROTATION:=0} } @@ -128,6 +129,11 @@ case "${1:-help}" in nohup "$FF" -rtsp_transport tcp -i "$RTSP_URL" \ -vf "${VFILTER}scale=${RES_W}:${RES_H},fps=${FPS:-30}" \ -f v4l2 -pix_fmt yuv420p /dev/video0 > /dev/null 2>&1 & + elif [ "$SOURCE_TYPE" = "tcp" ]; then + nohup "$FF" -fflags nobuffer -flags low_delay -analyzeduration 0 -use_wallclock_as_timestamps 1 \ + -i "$TCP_URL" \ + -vf "${VFILTER}scale=${RES_W}:${RES_H},fps=${FPS:-30}" \ + -f v4l2 -pix_fmt yuv420p /dev/video0 > /dev/null 2>&1 & elif [ "$SOURCE_TYPE" = "mp4" ] && [ -f "$MP4_PATH" ]; then nohup "$FF" -stream_loop -1 -re -i "$MP4_PATH" \ -vf "${VFILTER}scale=${RES_W}:${RES_H},fps=${FPS:-30}" \ @@ -150,7 +156,7 @@ case "${1:-help}" in ;; get_config) load_config - echo "{\"source_type\":\"$SOURCE_TYPE\",\"rtsp_url\":\"$RTSP_URL\",\"mp4_path\":\"$MP4_PATH\",\"res_w\":${RES_W:-1920},\"res_h\":${RES_H:-1080},\"fps\":${FPS:-30},\"rotation\":${ROTATION:-0}}" + echo "{\"source_type\":\"$SOURCE_TYPE\",\"rtsp_url\":\"$RTSP_URL\",\"tcp_url\":\"$TCP_URL\",\"mp4_path\":\"$MP4_PATH\",\"res_w\":${RES_W:-1920},\"res_h\":${RES_H:-1080},\"fps\":${FPS:-30},\"rotation\":${ROTATION:-0}}" ;; validate) PROVIDER_PID=$(pgrep -f "/virtual_camera_provider" | head -1) diff --git a/webroot/index.html b/webroot/index.html index b87cb59..13d593a 100644 --- a/webroot/index.html +++ b/webroot/index.html @@ -3,9 +3,11 @@
Status
Video Source
+
+
diff --git a/webroot/script.js b/webroot/script.js index 480e034..03a36fa 100644 --- a/webroot/script.js +++ b/webroot/script.js @@ -28,15 +28,41 @@ document.getElementById('btn-unfeed')?.addEventListener('click',()=>run('stop_fe document.getElementById('btn-refresh')?.addEventListener('click',updateDash); document.getElementById('btn-save')?.addEventListener('click',()=>{ const src=document.querySelector('.src-btn.active')?.dataset.src||'mp4'; - const json=JSON.stringify({source_type:src,rtsp_url:document.getElementById('rtsp-url').value,mp4_path:document.getElementById('mp4-path').value,res_w:parseInt(document.getElementById('res-w').value)||1920,res_h:parseInt(document.getElementById('res-h').value)||1080,fps:parseInt(document.getElementById('fps').value)||30,rotation:parseInt(document.getElementById('rotation').value)||0}); + const json=JSON.stringify({source_type:src,rtsp_url:document.getElementById('rtsp-url').value,tcp_url:document.getElementById('tcp-url').value,mp4_path:document.getElementById('mp4-path').value,res_w:parseInt(document.getElementById('res-w').value)||1920,res_h:parseInt(document.getElementById('res-h').value)||1080,fps:parseInt(document.getElementById('fps').value)||30,rotation:parseInt(document.getElementById('rotation').value)||0}); ksu.exec("echo '"+json+"' > /data/local/tmp/virtualcam_config.json"); log('Config saved','ok'); + // Restart feeder with new config if running + try { + const st = JSON.parse(ksu.exec(CMD+' status')||'{}'); + if (st.feeder_pid > 0) { + ksu.exec(CMD+' stop_feeder'); + setTimeout(function(){ksu.exec(CMD+' start_feeder');log('Feeder restarted','ok');},2000); + } + } catch(e) {} }); document.querySelectorAll('.src-btn').forEach(b=>b.addEventListener('click',()=>{ document.querySelectorAll('.src-btn').forEach(x=>x.classList.remove('active')); b.classList.add('active'); document.getElementById('rtsp-config').classList.toggle('hidden',b.dataset.src!=='rtsp'); + document.getElementById('tcp-config').classList.toggle('hidden',b.dataset.src!=='tcp'); document.getElementById('mp4-config').classList.toggle('hidden',b.dataset.src!=='mp4'); })); +// Load saved config into UI fields +try { + const cfg = JSON.parse(ksu.exec(CMD+' get_config')||'{}'); + if (cfg.source_type) { + document.querySelectorAll('.src-btn').forEach(b => b.classList.toggle('active', b.dataset.src === cfg.source_type)); + document.getElementById('rtsp-config').classList.toggle('hidden', cfg.source_type !== 'rtsp'); + document.getElementById('tcp-config').classList.toggle('hidden', cfg.source_type !== 'tcp'); + document.getElementById('mp4-config').classList.toggle('hidden', cfg.source_type !== 'mp4'); + } + if (cfg.rtsp_url) document.getElementById('rtsp-url').value = cfg.rtsp_url; + if (cfg.tcp_url) document.getElementById('tcp-url').value = cfg.tcp_url; + if (cfg.mp4_path) document.getElementById('mp4-path').value = cfg.mp4_path; + if (cfg.res_w) document.getElementById('res-w').value = cfg.res_w; + if (cfg.res_h) document.getElementById('res-h').value = cfg.res_h; + if (cfg.fps) document.getElementById('fps').value = cfg.fps; + if (cfg.rotation) document.getElementById('rotation').value = cfg.rotation; +} catch(e) {} updateDash(); setInterval(updateDash,5000);