From 1846814ac5efa0e232c4b01c66b457331a381a77 Mon Sep 17 00:00:00 2001
From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com>
Date: Fri, 2 Jun 2023 19:16:02 -0300
Subject: [PATCH] Dashcam Viewer: Screen Recordings support and interface
refresh (#160)
* init bootstrap 5.3
* bootstrap done
* watch screen records
* formatting
* syntax
* import
* specific path
* pathing
* text
* not needed
* sunnypilot home
* better name
* Revert "syntax"
This reverts commit 45c54a54ef978ca317d60a8d4b5581619151e452.
* path
* fix miss "/" at end of path and show current screenrecord video
* Created the About page
* Display errors in a more communicative way
* enable
at error messages
* display title on top of the page
* link to download screenrecord
* Update README.md
* Update styles
* Navbar on top, don't block content
* Don't center and format
* Update CHANGELOGS.md
* Update About page
---------
Co-authored-by: Jason Wen
---
CHANGELOGS.md | 1 +
system/dashcamviewer/README.md | 4 +-
system/dashcamviewer/dashcam_viewer.py | 126 +++++++-----------
system/dashcamviewer/helpers.py | 34 ++++-
system/dashcamviewer/static/favicon.ico | 2 +-
system/dashcamviewer/templates/about.html | 18 +++
system/dashcamviewer/templates/error.html | 11 ++
system/dashcamviewer/templates/footage.html | 14 ++
system/dashcamviewer/templates/index.html | 74 ++--------
system/dashcamviewer/templates/layout.html | 37 +++++
system/dashcamviewer/templates/route.html | 56 ++++++++
.../templates/screenrecords.html | 30 +++++
12 files changed, 256 insertions(+), 151 deletions(-)
mode change 100644 => 100755 system/dashcamviewer/dashcam_viewer.py
mode change 100644 => 120000 system/dashcamviewer/static/favicon.ico
create mode 100644 system/dashcamviewer/templates/about.html
create mode 100644 system/dashcamviewer/templates/error.html
create mode 100644 system/dashcamviewer/templates/footage.html
create mode 100644 system/dashcamviewer/templates/layout.html
create mode 100644 system/dashcamviewer/templates/route.html
create mode 100644 system/dashcamviewer/templates/screenrecords.html
diff --git a/CHANGELOGS.md b/CHANGELOGS.md
index a4793aa763..4b5160f2cf 100644
--- a/CHANGELOGS.md
+++ b/CHANGELOGS.md
@@ -1,5 +1,6 @@
sunnypilot - 0.9.2.x (2023-02-22)
========================
+* Dashcam Viewer (native & screen recordings) via Browser support thanks to actuallylemoncurd, AlexandreSato, ntegan1, and royjr!
* Honda Clarity 2018-22 support thanks to mcallbosco, vanillagorillaa and wirelessnet2!
sunnypilot - Version Latest (2023-02-22)
diff --git a/system/dashcamviewer/README.md b/system/dashcamviewer/README.md
index 4b2574ac9b..10d035ed68 100644
--- a/system/dashcamviewer/README.md
+++ b/system/dashcamviewer/README.md
@@ -1,5 +1,5 @@
# Dashcam Viewer
-View dashcam footage by connecting to the comma device via the same network, with your mobile device or PC. Big thanks to [actuallylemoncurd](https://github.com/actuallylemoncurd), [AlexandreSato](https://github.com/alexandreSato), [ntegan1](https://github.com/ntegan1), and [royjr](https://github.com/royjr).
+View dashcam footage and screen recordings by connecting to the comma device via the same network, with your mobile device or PC. Big thanks to [actuallylemoncurd](https://github.com/actuallylemoncurd), [AlexandreSato](https://github.com/alexandreSato), [ntegan1](https://github.com/ntegan1), and [royjr](https://github.com/royjr).
-The network can be set up by Wi-Fi, mobile hotspot, or tethering on the comma device. Navigate to http://tici:5000/ OR ipAddress:5000 to access the dashcam footage.
+The network can be set up by Wi-Fi, mobile hotspot, or tethering on the comma device. Navigate to http://tici:5050/ OR http://ipAddress:5050 to access the dashcam footage.
diff --git a/system/dashcamviewer/dashcam_viewer.py b/system/dashcamviewer/dashcam_viewer.py
old mode 100644
new mode 100755
index 9686bfe1e8..42c824cf4f
--- a/system/dashcamviewer/dashcam_viewer.py
+++ b/system/dashcamviewer/dashcam_viewer.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python3
-from flask import Flask, render_template, Response, request
-from system.dashcamviewer.helpers import *
+import os
+import system.dashcamviewer.helpers as dashcam
+from flask import Flask, render_template, Response, request, send_from_directory
+from system.loggerd.config import ROOT as REALDATA
app = Flask(__name__)
@@ -14,10 +16,10 @@ def index_page():
def full(cameratype, route):
chunk_size = 1024 * 512 # 5KiB
file_name = cameratype + (".ts" if cameratype == "qcamera" else ".hevc")
- vidlist = "|".join(ROOT + "/" + segment + "/" + file_name for segment in segments_in_route(route))
+ vidlist = "|".join(REALDATA + "/" + segment + "/" + file_name for segment in dashcam.segments_in_route(route))
def generate_buffered_stream():
- with ffmpeg_mp4_concat_wrap_process_builder(vidlist, cameratype, chunk_size) as process:
+ with dashcam.ffmpeg_mp4_concat_wrap_process_builder(vidlist, cameratype, chunk_size) as process:
for chunk in iter(lambda: process.stdout.read(chunk_size), b""):
yield bytes(chunk)
return Response(generate_buffered_stream(), status=200, mimetype='video/mp4')
@@ -25,17 +27,16 @@ def full(cameratype, route):
@app.route("/footage//")
def fcamera(cameratype, segment):
- if not is_valid_segment(segment):
- return "invalid segment"
- file_name = ROOT + "/" + segment + "/" + cameratype + (".ts" if cameratype == "qcamera" else ".hevc")
-
- return Response(ffmpeg_mp4_wrap_process_builder(file_name).stdout.read(), status=200, mimetype='video/mp4')
+ if not dashcam.is_valid_segment(segment):
+ return render_template("error.html", error="invalid segment")
+ file_name = REALDATA + "/" + segment + "/" + cameratype + (".ts" if cameratype == "qcamera" else ".hevc")
+ return Response(dashcam.ffmpeg_mp4_wrap_process_builder(file_name).stdout.read(), status=200, mimetype='video/mp4')
@app.route("/footage/")
def route(route):
if len(route) != 20:
- return "route not found"
+ return render_template("error.html", error="route not found")
if str(request.query_string) == "b''":
query_segment = str("0")
@@ -46,85 +47,48 @@ def route(route):
links = ""
segments = ""
- for segment in segments_in_route(route):
+ for segment in dashcam.segments_in_route(route):
links += ""+segment+"
"
segments += "'"+segment+"',"
- return """
-
-
-
- Dashcam Footage
-
-
-
-
-
- current segment:
-
- current view:
-
- download full route """ + query_type + """
-
- back to routes
-
- qcamera -
- fcamera -
- dcamera -
- ecamera
-
- """+links+"""
-
-
-
-
-"""
+ return render_template("route.html", route=route, query_type=query_type, links=links, segments=segments, query_segment=query_segment)
@app.route("/footage")
-def index():
- result = """
-
-
-
-
- Dashcam Footage
-
-
Back to landing page
"""
- for route in all_routes():
- result += ""+route+"
"
- result += """"""
- return result
+def footage():
+ return render_template("footage.html", rows=dashcam.all_routes())
+
+
+@app.route("/screenrecords")
+def screenrecords():
+ rows = dashcam.all_screenrecords()
+ if not rows:
+ return render_template("error.html", error="no screenrecords found at:
" + dashcam.SCREENRECORD_PATH)
+ return render_template("screenrecords.html", rows=rows, clip=rows[0])
+
+
+@app.route("/screenrecords/")
+def screenrecord(clip):
+ return render_template("screenrecords.html", rows=dashcam.all_screenrecords(), clip=clip)
+
+
+@app.route("/screenrecords/play/pipe/")
+def videoscreenrecord(file):
+ file_name = dashcam.SCREENRECORD_PATH + file
+ return Response(dashcam.ffplay_mp4_wrap_process_builder(file_name).stdout.read(), status=200, mimetype='video/mp4')
+
+
+@app.route("/screenrecords/download/")
+def download_file(clip):
+ return send_from_directory(dashcam.SCREENRECORD_PATH, clip, as_attachment=True)
+
+
+@app.route("/about")
+def about():
+ return render_template("about.html")
def main():
- app.run(host="0.0.0.0")
+ app.run(host="0.0.0.0", port=5050)
if __name__ == '__main__':
diff --git a/system/dashcamviewer/helpers.py b/system/dashcamviewer/helpers.py
index 7e0ce2ce9f..17fab408de 100644
--- a/system/dashcamviewer/helpers.py
+++ b/system/dashcamviewer/helpers.py
@@ -1,13 +1,26 @@
import os
import subprocess
-from system.loggerd.config import ROOT
+from pathlib import Path
+from system.hardware import PC
+from system.loggerd.config import ROOT as REALDATA
from system.loggerd.uploader import listdir_by_creation
from tools.lib.route import SegmentName
+# path to sunnypilot screen recordings
+if PC:
+ SCREENRECORD_PATH = os.path.join(str(Path.home()), ".comma", "media", "0", "videos", "")
+else:
+ SCREENRECORD_PATH = "/data/media/0/videos/"
+
+
+
+def all_screenrecords():
+ return sorted(listdir_by_creation(SCREENRECORD_PATH), reverse=True)
+
def is_valid_segment(segment):
try:
- segment_to_segment_name(ROOT, segment)
+ segment_to_segment_name(REALDATA, segment)
return True
except AssertionError:
return False
@@ -20,9 +33,9 @@ def segment_to_segment_name(data_dir, segment):
def all_segment_names():
segments = []
- for segment in listdir_by_creation(ROOT):
+ for segment in listdir_by_creation(REALDATA):
try:
- segments.append(segment_to_segment_name(ROOT, segment))
+ segments.append(segment_to_segment_name(REALDATA, segment))
except AssertionError:
pass
return segments
@@ -89,3 +102,16 @@ def ffmpeg_mp4_wrap_process_builder(filename):
return subprocess.Popen(
command_line, stdout=subprocess.PIPE
)
+
+
+def ffplay_mp4_wrap_process_builder(file_name):
+ command_line = ["ffmpeg"]
+ command_line += ["-i", file_name]
+ command_line += ["-c", "copy"]
+ command_line += ["-map", "0"]
+ command_line += ["-f", "mp4"]
+ command_line += ["-movflags", "empty_moov"]
+ command_line += ["-"]
+ return subprocess.Popen(
+ command_line, stdout=subprocess.PIPE
+ )
diff --git a/system/dashcamviewer/static/favicon.ico b/system/dashcamviewer/static/favicon.ico
deleted file mode 100644
index d6b869f84c..0000000000
--- a/system/dashcamviewer/static/favicon.ico
+++ /dev/null
@@ -1 +0,0 @@
-/data/openpilot/selfdrive/assets/img_spinner_comma.png
\ No newline at end of file
diff --git a/system/dashcamviewer/static/favicon.ico b/system/dashcamviewer/static/favicon.ico
new file mode 120000
index 0000000000..2f24c5828e
--- /dev/null
+++ b/system/dashcamviewer/static/favicon.ico
@@ -0,0 +1 @@
+../../../selfdrive/assets/img_spinner_comma.png
\ No newline at end of file
diff --git a/system/dashcamviewer/templates/about.html b/system/dashcamviewer/templates/about.html
new file mode 100644
index 0000000000..281b37965a
--- /dev/null
+++ b/system/dashcamviewer/templates/about.html
@@ -0,0 +1,18 @@
+{% extends "layout.html" %}
+
+{% block title %}
+ About
+{% endblock %}
+
+{% block main %}
+
+ About
+
+
+{% endblock %}
diff --git a/system/dashcamviewer/templates/error.html b/system/dashcamviewer/templates/error.html
new file mode 100644
index 0000000000..ebb182e4c6
--- /dev/null
+++ b/system/dashcamviewer/templates/error.html
@@ -0,0 +1,11 @@
+{% extends "layout.html" %}
+
+{% block title %}
+ About
+{% endblock %}
+
+{% block main %}
+
Oopss
+
+ {{ error | safe }}
+{% endblock %}
diff --git a/system/dashcamviewer/templates/footage.html b/system/dashcamviewer/templates/footage.html
new file mode 100644
index 0000000000..f2124382a0
--- /dev/null
+++ b/system/dashcamviewer/templates/footage.html
@@ -0,0 +1,14 @@
+{% extends "layout.html" %}
+
+{% block title %}
+ Dashcam Routes
+{% endblock %}
+
+{% block main %}
+
+ Dashcam Routes
+
+ {% for row in rows %}
+ {{ row }}
+ {% endfor %}
+{% endblock %}
diff --git a/system/dashcamviewer/templates/index.html b/system/dashcamviewer/templates/index.html
index 4704dbb244..638b6ae204 100644
--- a/system/dashcamviewer/templates/index.html
+++ b/system/dashcamviewer/templates/index.html
@@ -1,65 +1,13 @@
-
-
-
-
- remote door locker
-
-
-
-
-
-
Viem DashCam Footage
-
-
-
+{% block main %}
+
+ Dashcam Viewer
+
+ View Dashcam Footage
+
View Screen Recordings
+{% endblock %}
diff --git a/system/dashcamviewer/templates/layout.html b/system/dashcamviewer/templates/layout.html
new file mode 100644
index 0000000000..6ba6fa9d43
--- /dev/null
+++ b/system/dashcamviewer/templates/layout.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+ sunnypilot: {% block title %}{% endblock %}
+
+
+
+ {% block main %}{% endblock %}
+
+
diff --git a/system/dashcamviewer/templates/route.html b/system/dashcamviewer/templates/route.html
new file mode 100644
index 0000000000..5ebdefb39e
--- /dev/null
+++ b/system/dashcamviewer/templates/route.html
@@ -0,0 +1,56 @@
+{% extends "layout.html" %}
+
+{% block title %}
+ Dashcam Segments
+{% endblock %}
+
+
+{% block main %}
+{% autoescape false %}
+
+ Dashcam Segments (one per minute)
+
+
+
+ current segment:
+
+ current view:
+
+ download full route {{ query_type }}
+
+ qcamera -
+ fcamera -
+ dcamera -
+ ecamera
+
+ {{ links }}
+
+{% endautoescape %}
+{% endblock %}
diff --git a/system/dashcamviewer/templates/screenrecords.html b/system/dashcamviewer/templates/screenrecords.html
new file mode 100644
index 0000000000..922f5bbd41
--- /dev/null
+++ b/system/dashcamviewer/templates/screenrecords.html
@@ -0,0 +1,30 @@
+{% extends "layout.html" %}
+
+{% block title %}
+ Screen Recordings
+{% endblock %}
+
+{% block main %}
+
+ Screen Recordings
+
+
+
+ current view:
+
+ download: {{ clip }}
+
+ {% for row in rows %}
+ {{ row }}
+ {% endfor %}
+{% endblock %}