Skip to content

Commit 211579c

Browse files
committed
Merge remote-tracking branch 'origin/remotecontrolling' into remotecontrolling
2 parents 3d0b30e + 3665e0f commit 211579c

28 files changed

+1475
-556
lines changed

.github/workflows/assemble.yml

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
name: Assemble
22

3-
on: [push, workflow_dispatch]
3+
on:
4+
push:
5+
branches:
6+
- do-not-use
47

58
jobs:
69
assemble:
@@ -23,8 +26,22 @@ jobs:
2326
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
2427
restore-keys: |
2528
${{ runner.os }}-gradle-
29+
30+
- name: Decode Keystore
31+
env:
32+
ENCODED_STRING: ${{ secrets.JKS_FILE }}
33+
SIGNING_KEY_STORE_PATH: ${{ secrets.KEYSTOREPATH }}
34+
35+
run: |
36+
echo $ENCODED_STRING | base64 -i -d - > "${SIGNING_KEY_STORE_PATH}"
37+
2638
2739
- name: Assemble release
40+
env:
41+
SIGNING_KEY_STORE_PATH: ${{ secrets.KEYSTOREPATH }}
42+
SIGNING_KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
43+
SIGNING_KEY_PASSWORD: ${{ secrets.JKS_PASSWORD }}
44+
SIGNING_STORE_PASSWORD: ${{ secrets.JKS_PASSWORD }}
2845
run: ./gradlew assembleRelease
2946

3047
- name: Run lint for release
@@ -41,7 +58,21 @@ jobs:
4158
with:
4259
name: lint-results
4360
path: app/build/reports/lint-results-*.*
61+
62+
63+
- name: Upload Debug
64+
uses: actions/upload-artifact@v2
65+
with:
66+
name: debug-apk
67+
path: app/build/outputs/apk/debug/app-debug.apk
68+
4469

70+
- name: Upload Release
71+
uses: actions/upload-artifact@v2
72+
with:
73+
name: release-apk
74+
path: app/build/outputs/apk/release/*.apk
75+
4576
- name: Cleanup Gradle Cache
4677
# Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
4778
# Restoring these files from a GitHub Actions cache might cause problems for future builds.

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,8 @@ opencamera-extended-firebase-adminsdk-yv5yz-e33a8ce5c1.json
4646
#
4747
# Python stuff
4848
*.pyc
49+
50+
#
51+
# Project specific
52+
venv
53+
PythonTools/uploads

CaptureSync.iml

Lines changed: 0 additions & 19 deletions
This file was deleted.

Pics/RemoteController-GUI.png

308 KB
Loading
977 KB
Loading

Pics/Slide-NetworkConcept.png

314 KB
Loading

PostProcessing/README.md

Lines changed: 0 additions & 23 deletions
This file was deleted.

PythonTools/CollateVideos.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import argparse
2+
from pathlib import Path
3+
import subprocess
4+
import math
5+
6+
from video import video_info
7+
8+
from typing import List, Tuple
9+
10+
# See https://ffmpeg.org/ffmpeg-filters.html#xstack-1 for documentation on the xstack filter
11+
# Example (assuming HD input videos):
12+
"""
13+
ffmpeg -y -i video1.mp4 \
14+
-i video2.mp4 \
15+
-i video3.mp4 \
16+
-filter_complex \
17+
"\
18+
[0:v]scale=w=960:h=540[v0]; \
19+
[1:v]scale=w=960:h=540[v1]; \
20+
[2:v]scale=w=960:h=540[v2]; \
21+
[v0][v1][v2]xstack=inputs=3:layout=0_0|960_0|0_540[v]\
22+
" \
23+
-map "[v]" \
24+
finalOutput.mp4
25+
"""
26+
27+
28+
def create_video_grid_collage(video_files: List[str], output_file: str, grid_size: Tuple[int, int]) -> None:
29+
# Determine the dimensions of each grid cell
30+
grid_width, grid_height = grid_size
31+
input_width, input_height, _ = video_info(video_files[0])
32+
cell_width = input_width // grid_width
33+
cell_height = input_height // grid_height
34+
35+
# Compose the ffmpeg command to create the collage
36+
cmd = [
37+
"ffmpeg",
38+
"-y", # Overwrite output file if it exists
39+
]
40+
41+
# Set the list of input videos
42+
for i, video_file in enumerate(video_files):
43+
cmd.extend(["-i", video_file])
44+
45+
#
46+
# Generate the ffmpeg filtergraph
47+
filtergraph = ""
48+
49+
# First, created the scaled video instances
50+
for i, video_file in enumerate(video_files):
51+
filtergraph += f"[{i}:v]scale=w={cell_width}:h={cell_height}[v{i}];"
52+
53+
# Now compose the layout for the xstack filter
54+
xscale_positions = []
55+
for i, video_file in enumerate(video_files):
56+
col = i % grid_width
57+
row = i // grid_width
58+
xscale_positions.append(f"{cell_width*col}_{cell_height*row}")
59+
60+
filtergraph += "".join([f"[v{i}]" for i in range(len(video_files))])
61+
filtergraph += f"xstack=inputs={len(xscale_positions)}:layout="
62+
filtergraph += "|".join(xscale_positions) # Compose the xstack layout (e.g.: "0_0|960_0|0_540")
63+
filtergraph += "[v]"
64+
65+
# Append the complex filter and the remaining parameters
66+
cmd.extend([
67+
"-filter_complex", filtergraph,
68+
"-map", "[v]",
69+
"-c:v", "libx264",
70+
"-crf", "18",
71+
"-preset", "fast",
72+
"-pix_fmt", "yuv420p",
73+
output_file
74+
])
75+
print("CMD:", cmd)
76+
subprocess.run(cmd, capture_output=False)
77+
78+
79+
#
80+
# MAIN
81+
if __name__ == "__main__":
82+
83+
parser = argparse.ArgumentParser(
84+
description="Fixes the videos produced by the RecSync recording sessions."
85+
"Converts the input recorder videos into videos with the same number of frames,"
86+
"with missing/dropped frames inserted as (black) artificial data."
87+
)
88+
parser.add_argument(
89+
"--infolder", "-i", type=str, help="The folder containing the fixed videos.",
90+
required=True
91+
)
92+
parser.add_argument(
93+
"--outvideo", "-o", type=str, help="The filename to save the generated video.",
94+
required=True
95+
)
96+
97+
args = parser.parse_args()
98+
99+
input_dir = Path(args.infolder)
100+
out_filename = args.outvideo
101+
102+
input_video_paths = input_dir.glob("*.mp4")
103+
video_list = [str(p) for p in input_video_paths]
104+
# print("Input videos: ", video_list)
105+
106+
# Compute the most squared grid to contain the given number of input videos (drops a row if needed)
107+
n_videos = len(video_list)
108+
n_cols = math.ceil(math.sqrt(n_videos))
109+
n_rows = math.ceil(n_videos / n_cols)
110+
# print(f"Composing grid of (cols X rows): {n_cols}X{n_rows}")
111+
112+
# Number of rows will be the same as number of columns, or one less
113+
assert n_rows * n_cols >= n_videos
114+
assert n_cols - 1 <= n_rows <= n_cols
115+
116+
grid_size = (n_cols, n_rows)
117+
118+
create_video_grid_collage(video_list, out_filename, grid_size)

fileserver/file_server.py renamed to PythonTools/FileServer.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
# TODO:// Need to do changes based on file storage idea. i.e what folder structure etc
2-
from flask import Flask, json, request, jsonify
2+
from flask import Flask, request, jsonify
33
import os
4-
import urllib.request
5-
import base64
64
from werkzeug.utils import secure_filename
7-
import multipart as mp
85

96
try:
107
from io import BytesIO
@@ -14,21 +11,24 @@
1411

1512
app.secret_key = "recSync-fileserver"
1613

17-
UPLOAD_FOLDER = 'static/uploads/'
14+
UPLOAD_FOLDER = 'uploads/'
1815
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
1916

2017
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'mov', 'mp4', 'csv'])
2118

19+
2220
def allowed_file(filename):
2321
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
2422

23+
2524
@app.route('/')
2625
def main():
2726
return 'Homepage'
2827

28+
2929
@app.route('/upload', methods=['POST'])
3030
def upload_file():
31-
#import pdb; pdb.set_trace()
31+
3232
if 'file' not in request.files:
3333
resp = jsonify({'message' : 'No file part in the request'})
3434
resp.status_code = 400
@@ -60,6 +60,7 @@ def upload_file():
6060
resp.status_code = 201
6161
return resp
6262

63+
6364
@app.route('/namelist', methods=['POST'])
6465
def print_filelist():
6566
print("CLIENT ID:" + request.form.get("client_id", "") +" have these FILES:" + request.form.get("file_list", []) )
@@ -68,8 +69,8 @@ def print_filelist():
6869
return resp
6970

7071

71-
72-
73-
72+
#
73+
# MAIN
74+
#
7475
if __name__ == '__main__':
7576
app.run(host='0.0.0.0', port=5000,debug=True)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
ifndef RECSYNC_DOWNLOAD_DIR
2+
$(error RECSYNC_DOWNLOAD_DIR variable is not set)
3+
endif
4+
5+
# Remove trailing slash, if any
6+
RECSYNC_DOWNLOAD_DIR := $(patsubst %/,%,$(RECSYNC_DOWNLOAD_DIR))
7+
8+
# E.g.: path/to/230531-ExposureTests
9+
10+
ALL_SESSIONS := $(wildcard $(RECSYNC_DOWNLOAD_DIR)/*)
11+
12+
PARENT_DIR = $(dir $(RECSYNC_DOWNLOAD_DIR))
13+
DIR_NAME = $(notdir $(RECSYNC_DOWNLOAD_DIR))
14+
DEST_DIR = $(PARENT_DIR)$(DIR_NAME)-postproc
15+
16+
# Compose the names of the target dirs
17+
DEST_SESSIONS = $(subst $(RECSYNC_DOWNLOAD_DIR),$(DEST_DIR),$(ALL_SESSIONS))
18+
# Append a "/_done", which will be used as destination target file
19+
DEST_SESSIONS := $(addsuffix /_done,$(DEST_SESSIONS))
20+
21+
# Debugging ...
22+
#@echo $(ALL_SESSIONS)
23+
#@echo PARENT: $(PARENT_DIR)
24+
#@echo DIR_NAME: $(DIR_NAME)
25+
#@echo DEST_DIR: $(DEST_DIR)
26+
#@echo Wanna create: $(DEST_SESSIONS)
27+
28+
all: $(DEST_SESSIONS)
29+
@echo Filled dir $(DEST_DIR)
30+
31+
# Rule matching the pattern in the DEST_SESSIONS items
32+
$(DEST_DIR)/%/_done: $(RECSYNC_DOWNLOAD_DIR)/% | $(DEST_DIR)
33+
$(eval tgt_dir = $(dir $@))
34+
@echo "Processing $< into $(tgt_dir)..."
35+
mkdir -p "$(tgt_dir)"
36+
python PostProcessVideos.py -i "$<" -o "$(tgt_dir)"
37+
touch "$@"
38+
39+
$(DEST_DIR):
40+
mkdir -p $@

0 commit comments

Comments
 (0)