tirtc-devtools-cli 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -0
- package/USAGE.md +417 -0
- package/bin/tirtc-devtool.js +2 -0
- package/dist/app-server/protocol-client/index.d.ts +25 -0
- package/dist/app-server/protocol-client/index.js +114 -0
- package/dist/devtools/cli/src/config.d.ts +46 -0
- package/dist/devtools/cli/src/config.js +98 -0
- package/dist/devtools/cli/src/dummy.d.ts +0 -0
- package/dist/devtools/cli/src/dummy.js +1 -0
- package/dist/devtools/cli/src/embedded_paths.d.ts +7 -0
- package/dist/devtools/cli/src/embedded_paths.js +85 -0
- package/dist/devtools/cli/src/facade.d.ts +723 -0
- package/dist/devtools/cli/src/facade.js +194 -0
- package/dist/devtools/cli/src/ffmpeg_tool.d.ts +6 -0
- package/dist/devtools/cli/src/ffmpeg_tool.js +146 -0
- package/dist/devtools/cli/src/guide.d.ts +1 -0
- package/dist/devtools/cli/src/guide.js +49 -0
- package/dist/devtools/cli/src/index.d.ts +1 -0
- package/dist/devtools/cli/src/index.js +753 -0
- package/dist/devtools/cli/src/media_assets.d.ts +25 -0
- package/dist/devtools/cli/src/media_assets.js +121 -0
- package/dist/devtools/cli/src/session_manager.d.ts +25 -0
- package/dist/devtools/cli/src/session_manager.js +393 -0
- package/dist/devtools/cli/src/token_tool.d.ts +33 -0
- package/dist/devtools/cli/src/token_tool.js +217 -0
- package/dist/devtools/cli/src/transport.d.ts +30 -0
- package/dist/devtools/cli/src/transport.js +84 -0
- package/dist/dummy.d.ts +0 -0
- package/dist/dummy.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +48 -0
- package/package.json +54 -0
- package/script/ensure_ffmpeg.sh +22 -0
- package/vendor/app-server/bin/native/macos-arm64/credential_napi.node +0 -0
- package/vendor/app-server/bin/native/macos-arm64/libcrypto.dylib +0 -0
- package/vendor/app-server/bin/native/macos-arm64/libssl.dylib +0 -0
- package/vendor/app-server/bin/native/macos-arm64/libtgrtc.dylib +0 -0
- package/vendor/app-server/bin/native/macos-arm64/runtime_host_napi.node +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_codec.h +23 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_frame.h +36 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io.h +56 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_android.h +19 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_apple.h +19 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_harmony.h +19 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_windows.h +19 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_processing.h +56 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_sample_rate.h +18 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/error.h +20 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/logging.h +53 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_codec.h +21 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_downlink.h +89 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_uplink.h +115 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/runtime.h +236 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_codec.h +57 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_frame.h +55 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io.h +46 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_android.h +32 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_apple.h +34 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_harmony.h +32 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_windows.h +26 -0
- package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_processing.h +34 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_audio.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_facade.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_foundation_logging.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_media.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_video.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libwebrtc_apm.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/lib/libxlog.a +0 -0
- package/vendor/app-server/bin/runtime/linux-x64/manifest.txt +34 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio.h +398 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_codec.h +23 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_frame.h +36 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io.h +56 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io_android.h +19 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io_apple.h +19 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io_harmony.h +19 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_io_windows.h +19 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_processing.h +56 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio_sample_rate.h +18 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/av.h +452 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/credential.h +34 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/error.h +30 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/foundation/build_info.h +27 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/http.h +57 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/logging.h +55 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_codec.h +21 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_downlink.h +95 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_fixture_av_sync.h +61 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_fixture_source.h +77 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_live_source.h +71 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_uplink.h +116 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/transport.h +481 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/trp.h +541 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_codec.h +58 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_frame.h +55 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io.h +46 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io_android.h +32 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io_apple.h +47 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io_harmony.h +32 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_io_windows.h +26 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/video_processing.h +34 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libcrypto.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libcrypto.dylib +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_audio.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_credential.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_facade.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_http.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_logging.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_media.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_transport.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_video.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libssl.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libssl.dylib +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libwebrtc_apm.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libxlog.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/manifest.txt +50 -0
- package/vendor/app-server/bin/tirtc-devtool-host.js +2 -0
- package/vendor/app-server/dist/host/ArtifactManager.d.ts +18 -0
- package/vendor/app-server/dist/host/ArtifactManager.js +83 -0
- package/vendor/app-server/dist/host/HostProtocol.d.ts +107 -0
- package/vendor/app-server/dist/host/HostProtocol.js +256 -0
- package/vendor/app-server/dist/host/HostServer.d.ts +49 -0
- package/vendor/app-server/dist/host/HostServer.js +635 -0
- package/vendor/app-server/dist/host/HostState.d.ts +60 -0
- package/vendor/app-server/dist/host/HostState.js +19 -0
- package/vendor/app-server/dist/host/RuntimeAdapter.d.ts +81 -0
- package/vendor/app-server/dist/host/RuntimeAdapter.js +559 -0
- package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.d.ts +30 -0
- package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.js +224 -0
- package/vendor/app-server/dist/host/RuntimeReceiveWorker.d.ts +37 -0
- package/vendor/app-server/dist/host/RuntimeReceiveWorker.js +186 -0
- package/vendor/app-server/dist/host/RuntimeSendWorker.d.ts +42 -0
- package/vendor/app-server/dist/host/RuntimeSendWorker.js +274 -0
- package/vendor/app-server/dist/host/TokenTool.d.ts +15 -0
- package/vendor/app-server/dist/host/TokenTool.js +84 -0
- package/vendor/app-server/dist/host/WebPreviewGateway.d.ts +28 -0
- package/vendor/app-server/dist/host/WebPreviewGateway.js +815 -0
- package/vendor/app-server/dist/host/native/RuntimeCredentialTokenIssuer.d.ts +26 -0
- package/vendor/app-server/dist/host/native/RuntimeCredentialTokenIssuer.js +118 -0
- package/vendor/app-server/dist/host/native/RuntimeHostBridge.d.ts +19 -0
- package/vendor/app-server/dist/host/native/RuntimeHostBridge.js +141 -0
- package/vendor/app-server/dist/host/runtime_backed_preflight.d.ts +10 -0
- package/vendor/app-server/dist/host/runtime_backed_preflight.js +78 -0
- package/vendor/app-server/dist/host/tests/helpers/host_socket_client.d.ts +28 -0
- package/vendor/app-server/dist/host/tests/helpers/host_socket_client.js +85 -0
- package/vendor/app-server/dist/host/tests/helpers/runtime_e2e_local_config.d.ts +10 -0
- package/vendor/app-server/dist/host/tests/helpers/runtime_e2e_local_config.js +41 -0
- package/vendor/app-server/dist/host/tests/helpers/runtime_test_env.d.ts +11 -0
- package/vendor/app-server/dist/host/tests/helpers/runtime_test_env.js +32 -0
- package/vendor/app-server/dist/protocol/contract.d.ts +983 -0
- package/vendor/app-server/dist/protocol/contract.js +198 -0
- package/vendor/app-server/dist/protocol-client/index.d.ts +25 -0
- package/vendor/app-server/dist/protocol-client/index.js +114 -0
- package/vendor/app-server/dist/src/index.d.ts +1 -0
- package/vendor/app-server/dist/src/index.js +294 -0
- package/vendor/runtime/script/prepare_runtime_media_dataset.sh +427 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
print_usage() {
|
|
5
|
+
cat <<'USAGE'
|
|
6
|
+
Usage:
|
|
7
|
+
prepare_runtime_media_dataset.sh --source <mp4> --output-root <dir> [--output-dir <dir>] [--overwrite]
|
|
8
|
+
|
|
9
|
+
Options:
|
|
10
|
+
--source <mp4> source mp4 file
|
|
11
|
+
--output-root <dir> root directory that stores prepared local assets
|
|
12
|
+
--output-dir <dir> exact prepared local assets directory (overrides hashed subdir)
|
|
13
|
+
--overwrite rebuild prepared assets even when cache entry exists
|
|
14
|
+
-h, --help show help
|
|
15
|
+
USAGE
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fail() {
|
|
19
|
+
echo "[prepare_runtime_media_dataset] error: $*" >&2
|
|
20
|
+
exit 1
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
require_cmd() {
|
|
24
|
+
command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
sha256_file() {
|
|
28
|
+
local file="$1"
|
|
29
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
30
|
+
shasum -a 256 "$file" | awk '{print $1}'
|
|
31
|
+
return
|
|
32
|
+
fi
|
|
33
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
34
|
+
sha256sum "$file" | awk '{print $1}'
|
|
35
|
+
return
|
|
36
|
+
fi
|
|
37
|
+
if command -v openssl >/dev/null 2>&1; then
|
|
38
|
+
openssl dgst -sha256 "$file" | awk '{print $NF}'
|
|
39
|
+
return
|
|
40
|
+
fi
|
|
41
|
+
fail "no sha256 tool found (shasum/sha256sum/openssl)"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
json_escape() {
|
|
45
|
+
local input="$1"
|
|
46
|
+
input="${input//\\/\\\\}"
|
|
47
|
+
input="${input//\"/\\\"}"
|
|
48
|
+
input="${input//$'\n'/\\n}"
|
|
49
|
+
input="${input//$'\r'/\\r}"
|
|
50
|
+
input="${input//$'\t'/\\t}"
|
|
51
|
+
printf '%s' "$input"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
emit_result() {
|
|
55
|
+
local assets_dir="$1"
|
|
56
|
+
local manifest_path="$2"
|
|
57
|
+
local cache_hit="$3"
|
|
58
|
+
printf '{"assets_dir":"%s","manifest_path":"%s","cache_hit":%s}\n' \
|
|
59
|
+
"$(json_escape "$assets_dir")" \
|
|
60
|
+
"$(json_escape "$manifest_path")" \
|
|
61
|
+
"$cache_hit"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
SOURCE=""
|
|
65
|
+
OUTPUT_ROOT=""
|
|
66
|
+
OUTPUT_DIR=""
|
|
67
|
+
OVERWRITE=0
|
|
68
|
+
|
|
69
|
+
while [[ $# -gt 0 ]]; do
|
|
70
|
+
case "$1" in
|
|
71
|
+
--source)
|
|
72
|
+
SOURCE="${2:-}"
|
|
73
|
+
shift 2
|
|
74
|
+
;;
|
|
75
|
+
--output-root)
|
|
76
|
+
OUTPUT_ROOT="${2:-}"
|
|
77
|
+
shift 2
|
|
78
|
+
;;
|
|
79
|
+
--output-dir)
|
|
80
|
+
OUTPUT_DIR="${2:-}"
|
|
81
|
+
shift 2
|
|
82
|
+
;;
|
|
83
|
+
--overwrite)
|
|
84
|
+
OVERWRITE=1
|
|
85
|
+
shift
|
|
86
|
+
;;
|
|
87
|
+
-h|--help)
|
|
88
|
+
print_usage
|
|
89
|
+
exit 0
|
|
90
|
+
;;
|
|
91
|
+
*)
|
|
92
|
+
fail "unknown argument: $1"
|
|
93
|
+
;;
|
|
94
|
+
esac
|
|
95
|
+
done
|
|
96
|
+
|
|
97
|
+
[[ -n "$SOURCE" ]] || fail "--source is required"
|
|
98
|
+
[[ -n "$OUTPUT_ROOT" ]] || fail "--output-root is required"
|
|
99
|
+
[[ -f "$SOURCE" ]] || fail "source not found: $SOURCE"
|
|
100
|
+
[[ "$SOURCE" == *.mp4 ]] || fail "source must be an .mp4 file: $SOURCE"
|
|
101
|
+
|
|
102
|
+
require_cmd node
|
|
103
|
+
|
|
104
|
+
FFMPEG_BIN="ffmpeg"
|
|
105
|
+
FFPROBE_BIN="ffprobe"
|
|
106
|
+
if [[ -n "${TIRTC_ENSURE_FFMPEG_SCRIPT:-}" ]]; then
|
|
107
|
+
[[ -x "$TIRTC_ENSURE_FFMPEG_SCRIPT" ]] || fail "ffmpeg bootstrap script is not executable: $TIRTC_ENSURE_FFMPEG_SCRIPT"
|
|
108
|
+
FFMPEG_TOOLS_JSON="$($TIRTC_ENSURE_FFMPEG_SCRIPT)" || fail "ffmpeg bootstrap failed"
|
|
109
|
+
FFMPEG_FIELDS="$(FFMPEG_TOOLS_JSON="$FFMPEG_TOOLS_JSON" node <<'NODE'
|
|
110
|
+
const payload = process.env.FFMPEG_TOOLS_JSON;
|
|
111
|
+
if (!payload) {
|
|
112
|
+
throw new Error('missing FFMPEG_TOOLS_JSON');
|
|
113
|
+
}
|
|
114
|
+
const parsed = JSON.parse(payload);
|
|
115
|
+
if (!parsed.ffmpeg || !parsed.ffprobe) {
|
|
116
|
+
throw new Error('ffmpeg bootstrap returned incomplete result');
|
|
117
|
+
}
|
|
118
|
+
process.stdout.write(String(parsed.ffmpeg) + ' ' + String(parsed.ffprobe));
|
|
119
|
+
NODE
|
|
120
|
+
)"
|
|
121
|
+
IFS=$' ' read -r FFMPEG_BIN FFPROBE_BIN <<EOF
|
|
122
|
+
$FFMPEG_FIELDS
|
|
123
|
+
EOF
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
require_cmd "$FFMPEG_BIN"
|
|
127
|
+
require_cmd "$FFPROBE_BIN"
|
|
128
|
+
|
|
129
|
+
SOURCE_ABS="$(cd "$(dirname "$SOURCE")" && pwd)/$(basename "$SOURCE")"
|
|
130
|
+
SOURCE_FILE_NAME="$(basename "$SOURCE_ABS")"
|
|
131
|
+
|
|
132
|
+
readonly k_schema_version=1
|
|
133
|
+
readonly k_tool_version="runtime_local_assets_prepare_v4"
|
|
134
|
+
readonly k_video_max_width=1280
|
|
135
|
+
readonly k_video_max_height=720
|
|
136
|
+
readonly k_video_fps=15
|
|
137
|
+
readonly k_audio_sample_rate_hz=8000
|
|
138
|
+
readonly k_audio_channels=1
|
|
139
|
+
readonly k_audio_packet_duration_ms=40
|
|
140
|
+
readonly k_loop_policy="continuous_pts"
|
|
141
|
+
readonly k_video_codec="h264_annexb"
|
|
142
|
+
readonly k_audio_codec="g711a"
|
|
143
|
+
readonly k_output_audio_format="pcm_s16"
|
|
144
|
+
readonly k_output_video_format="rgba8888"
|
|
145
|
+
|
|
146
|
+
VIDEO_STREAM_FIELDS="$(
|
|
147
|
+
VIDEO_STREAM_JSON="$("$FFPROBE_BIN" -v error -select_streams v:0 \
|
|
148
|
+
-show_entries stream=width,height,bit_rate -of json "$SOURCE_ABS")" \
|
|
149
|
+
MAX_WIDTH="$k_video_max_width" \
|
|
150
|
+
MAX_HEIGHT="$k_video_max_height" \
|
|
151
|
+
node <<'NODE'
|
|
152
|
+
const payload = process.env.VIDEO_STREAM_JSON;
|
|
153
|
+
if (!payload) {
|
|
154
|
+
throw new Error('missing VIDEO_STREAM_JSON');
|
|
155
|
+
}
|
|
156
|
+
const maxWidth = Number(process.env.MAX_WIDTH || '1280');
|
|
157
|
+
const maxHeight = Number(process.env.MAX_HEIGHT || '720');
|
|
158
|
+
if (!Number.isFinite(maxWidth) || maxWidth <= 0 || !Number.isFinite(maxHeight) || maxHeight <= 0) {
|
|
159
|
+
throw new Error('invalid target video bound');
|
|
160
|
+
}
|
|
161
|
+
const parsed = JSON.parse(payload);
|
|
162
|
+
const stream = Array.isArray(parsed.streams) ? parsed.streams[0] : null;
|
|
163
|
+
if (!stream) {
|
|
164
|
+
throw new Error('source mp4 is missing a video stream');
|
|
165
|
+
}
|
|
166
|
+
const width = Number(stream.width || 0);
|
|
167
|
+
const height = Number(stream.height || 0);
|
|
168
|
+
if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) {
|
|
169
|
+
throw new Error('source video dimensions are invalid');
|
|
170
|
+
}
|
|
171
|
+
const bitRate = Number(stream.bit_rate || 0);
|
|
172
|
+
const bitrateKbps = Number.isFinite(bitRate) && bitRate > 0 ? Math.max(1, Math.ceil(bitRate / 1000)) : 0;
|
|
173
|
+
const scale = Math.min(1, maxWidth / width, maxHeight / height);
|
|
174
|
+
let targetWidth = Math.floor(width * scale);
|
|
175
|
+
let targetHeight = Math.floor(height * scale);
|
|
176
|
+
if ((targetWidth % 2) !== 0 && targetWidth > 2) {
|
|
177
|
+
targetWidth -= 1;
|
|
178
|
+
}
|
|
179
|
+
if ((targetHeight % 2) !== 0 && targetHeight > 2) {
|
|
180
|
+
targetHeight -= 1;
|
|
181
|
+
}
|
|
182
|
+
targetWidth = Math.max(2, targetWidth);
|
|
183
|
+
targetHeight = Math.max(2, targetHeight);
|
|
184
|
+
const scaledBitrateKbps = bitrateKbps > 0
|
|
185
|
+
? Math.max(1, Math.ceil(bitrateKbps * ((targetWidth * targetHeight) / (width * height))))
|
|
186
|
+
: 0;
|
|
187
|
+
process.stdout.write([
|
|
188
|
+
String(width),
|
|
189
|
+
String(height),
|
|
190
|
+
String(bitrateKbps),
|
|
191
|
+
String(targetWidth),
|
|
192
|
+
String(targetHeight),
|
|
193
|
+
String(scaledBitrateKbps),
|
|
194
|
+
].join('\t'));
|
|
195
|
+
NODE
|
|
196
|
+
)"
|
|
197
|
+
IFS=$'\t' read -r SOURCE_VIDEO_WIDTH SOURCE_VIDEO_HEIGHT SOURCE_VIDEO_BITRATE_KBPS TARGET_VIDEO_WIDTH TARGET_VIDEO_HEIGHT TARGET_VIDEO_BITRATE_KBPS <<EOF
|
|
198
|
+
$VIDEO_STREAM_FIELDS
|
|
199
|
+
EOF
|
|
200
|
+
|
|
201
|
+
[[ "$SOURCE_VIDEO_WIDTH" -gt 0 ]] || fail "failed to resolve source video width"
|
|
202
|
+
[[ "$SOURCE_VIDEO_HEIGHT" -gt 0 ]] || fail "failed to resolve source video height"
|
|
203
|
+
[[ "$TARGET_VIDEO_WIDTH" -gt 0 ]] || fail "failed to resolve target video width"
|
|
204
|
+
[[ "$TARGET_VIDEO_HEIGHT" -gt 0 ]] || fail "failed to resolve target video height"
|
|
205
|
+
|
|
206
|
+
mkdir -p "$OUTPUT_ROOT"
|
|
207
|
+
SOURCE_SHA256="$(sha256_file "$SOURCE_ABS")"
|
|
208
|
+
ASSETS_ID="${SOURCE_SHA256}_s${k_schema_version}_${k_tool_version}"
|
|
209
|
+
ASSETS_DIR="$OUTPUT_ROOT/$ASSETS_ID"
|
|
210
|
+
if [[ -n "$OUTPUT_DIR" ]]; then
|
|
211
|
+
ASSETS_DIR="$OUTPUT_DIR"
|
|
212
|
+
fi
|
|
213
|
+
MANIFEST_PATH="$ASSETS_DIR/manifest.json"
|
|
214
|
+
|
|
215
|
+
if [[ -f "$MANIFEST_PATH" && "$OVERWRITE" -ne 1 ]]; then
|
|
216
|
+
emit_result "$ASSETS_DIR" "$MANIFEST_PATH" true
|
|
217
|
+
exit 0
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
if [[ -e "$ASSETS_DIR" ]]; then
|
|
221
|
+
rm -rf "$ASSETS_DIR"
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
mkdir -p "$ASSETS_DIR/video"
|
|
225
|
+
mkdir -p "$ASSETS_DIR/audio"
|
|
226
|
+
|
|
227
|
+
VIDEO_PATH="$ASSETS_DIR/video/video.h264"
|
|
228
|
+
VIDEO_PACKET_INDEX_PATH="$ASSETS_DIR/video/video_packets.csv"
|
|
229
|
+
AUDIO_PATH="$ASSETS_DIR/audio/audio.g711a"
|
|
230
|
+
AUDIO_PACKET_INDEX_PATH="$ASSETS_DIR/audio/audio_packets.csv"
|
|
231
|
+
|
|
232
|
+
video_encode_args=(
|
|
233
|
+
-vf "fps=${k_video_fps},scale=${TARGET_VIDEO_WIDTH}:${TARGET_VIDEO_HEIGHT}:flags=lanczos"
|
|
234
|
+
-c:v libx264
|
|
235
|
+
-preset medium
|
|
236
|
+
-tune zerolatency
|
|
237
|
+
-pix_fmt yuv420p
|
|
238
|
+
-bf 0
|
|
239
|
+
-g "${k_video_fps}"
|
|
240
|
+
-keyint_min "${k_video_fps}"
|
|
241
|
+
-sc_threshold 0
|
|
242
|
+
-x264-params repeat-headers=1:aud=1
|
|
243
|
+
)
|
|
244
|
+
if [[ "$TARGET_VIDEO_BITRATE_KBPS" -gt 0 ]]; then
|
|
245
|
+
video_encode_args+=(
|
|
246
|
+
-b:v "${TARGET_VIDEO_BITRATE_KBPS}k"
|
|
247
|
+
-maxrate "${TARGET_VIDEO_BITRATE_KBPS}k"
|
|
248
|
+
-bufsize "$((TARGET_VIDEO_BITRATE_KBPS * 2))k"
|
|
249
|
+
)
|
|
250
|
+
else
|
|
251
|
+
video_encode_args+=(-crf 18)
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
"$FFMPEG_BIN" -hide_banner -loglevel error -y \
|
|
255
|
+
-i "$SOURCE_ABS" \
|
|
256
|
+
-an \
|
|
257
|
+
"${video_encode_args[@]}" \
|
|
258
|
+
-f h264 \
|
|
259
|
+
"$VIDEO_PATH"
|
|
260
|
+
|
|
261
|
+
"$FFMPEG_BIN" -hide_banner -loglevel error -y \
|
|
262
|
+
-i "$SOURCE_ABS" \
|
|
263
|
+
-vn \
|
|
264
|
+
-ac ${k_audio_channels} \
|
|
265
|
+
-ar ${k_audio_sample_rate_hz} \
|
|
266
|
+
-c:a pcm_alaw \
|
|
267
|
+
-f alaw \
|
|
268
|
+
"$AUDIO_PATH"
|
|
269
|
+
|
|
270
|
+
VIDEO_PACKET_INDEX_PATH="$VIDEO_PACKET_INDEX_PATH" \
|
|
271
|
+
VIDEO_PATH="$VIDEO_PATH" \
|
|
272
|
+
VIDEO_FPS="$k_video_fps" \
|
|
273
|
+
node <<'NODE'
|
|
274
|
+
const fs = require('fs');
|
|
275
|
+
|
|
276
|
+
const videoPath = process.env.VIDEO_PATH;
|
|
277
|
+
const outputPath = process.env.VIDEO_PACKET_INDEX_PATH;
|
|
278
|
+
const fps = Number(process.env.VIDEO_FPS || '15');
|
|
279
|
+
|
|
280
|
+
if (!videoPath || !outputPath || !Number.isFinite(fps) || fps <= 0) {
|
|
281
|
+
throw new Error('video packet index env is incomplete');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const data = fs.readFileSync(videoPath);
|
|
285
|
+
const starts = [];
|
|
286
|
+
for (let index = 0; index < data.length - 3; index += 1) {
|
|
287
|
+
if (data[index] === 0 && data[index + 1] === 0) {
|
|
288
|
+
if (data[index + 2] === 1) {
|
|
289
|
+
starts.push({offset: index, prefix: 3});
|
|
290
|
+
index += 2;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (index + 3 < data.length && data[index + 2] === 0 && data[index + 3] === 1) {
|
|
294
|
+
starts.push({offset: index, prefix: 4});
|
|
295
|
+
index += 3;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (starts.length === 0) {
|
|
301
|
+
throw new Error('video bitstream missing annexb start codes');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const packetOffsets = [];
|
|
305
|
+
let currentPacketStart = 0;
|
|
306
|
+
let currentPacketHasData = false;
|
|
307
|
+
let currentPacketKeyFrame = false;
|
|
308
|
+
|
|
309
|
+
for (let index = 0; index < starts.length; index += 1) {
|
|
310
|
+
const start = starts[index];
|
|
311
|
+
const nextOffset = index + 1 < starts.length ? starts[index + 1].offset : data.length;
|
|
312
|
+
const nalHeaderOffset = start.offset + start.prefix;
|
|
313
|
+
if (nalHeaderOffset >= nextOffset) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const nalType = data[nalHeaderOffset] & 0x1f;
|
|
318
|
+
if (nalType === 9) {
|
|
319
|
+
if (currentPacketHasData) {
|
|
320
|
+
packetOffsets.push({
|
|
321
|
+
offset: currentPacketStart,
|
|
322
|
+
size: start.offset - currentPacketStart,
|
|
323
|
+
keyFrame: currentPacketKeyFrame,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
currentPacketStart = start.offset;
|
|
327
|
+
currentPacketHasData = true;
|
|
328
|
+
currentPacketKeyFrame = false;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (!currentPacketHasData) {
|
|
333
|
+
currentPacketStart = start.offset;
|
|
334
|
+
currentPacketHasData = true;
|
|
335
|
+
currentPacketKeyFrame = false;
|
|
336
|
+
}
|
|
337
|
+
if (nalType === 5) {
|
|
338
|
+
currentPacketKeyFrame = true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (currentPacketHasData && currentPacketStart < data.length) {
|
|
343
|
+
packetOffsets.push({
|
|
344
|
+
offset: currentPacketStart,
|
|
345
|
+
size: data.length - currentPacketStart,
|
|
346
|
+
keyFrame: currentPacketKeyFrame,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (packetOffsets.length === 0) {
|
|
351
|
+
throw new Error('video packet index is empty');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const frameDurationUs = Math.round(1_000_000 / fps);
|
|
355
|
+
const lines = ['pts_us,offset,size,is_key_frame'];
|
|
356
|
+
for (let index = 0; index < packetOffsets.length; index += 1) {
|
|
357
|
+
const entry = packetOffsets[index];
|
|
358
|
+
lines.push(`${index * frameDurationUs},${entry.offset},${entry.size},${entry.keyFrame ? 1 : 0}`);
|
|
359
|
+
}
|
|
360
|
+
fs.writeFileSync(outputPath, `${lines.join('\n')}\n`, 'utf8');
|
|
361
|
+
NODE
|
|
362
|
+
|
|
363
|
+
AUDIO_BYTES="$(wc -c < "$AUDIO_PATH" | tr -d '[:space:]')"
|
|
364
|
+
AUDIO_PACKET_BYTES=$((k_audio_sample_rate_hz * k_audio_packet_duration_ms / 1000))
|
|
365
|
+
[[ "$AUDIO_PACKET_BYTES" -gt 0 ]] || fail "invalid audio packet bytes"
|
|
366
|
+
AUDIO_REMAINDER=$((AUDIO_BYTES % AUDIO_PACKET_BYTES))
|
|
367
|
+
if [[ "$AUDIO_REMAINDER" -ne 0 ]]; then
|
|
368
|
+
AUDIO_ALIGNED_BYTES=$((AUDIO_BYTES - AUDIO_REMAINDER))
|
|
369
|
+
[[ "$AUDIO_ALIGNED_BYTES" -gt 0 ]] || fail "audio output is too short for one full packet"
|
|
370
|
+
echo "[prepare_runtime_media_dataset] trim trailing audio bytes to packet boundary: removed=${AUDIO_REMAINDER}" >&2
|
|
371
|
+
AUDIO_PATH="$AUDIO_PATH" AUDIO_ALIGNED_BYTES="$AUDIO_ALIGNED_BYTES" node <<'NODE'
|
|
372
|
+
const fs = require('fs');
|
|
373
|
+
const audioPath = process.env.AUDIO_PATH;
|
|
374
|
+
const alignedBytes = Number(process.env.AUDIO_ALIGNED_BYTES || '0');
|
|
375
|
+
if (!audioPath || !Number.isFinite(alignedBytes) || alignedBytes <= 0) {
|
|
376
|
+
throw new Error('audio trim env is incomplete');
|
|
377
|
+
}
|
|
378
|
+
fs.truncateSync(audioPath, alignedBytes);
|
|
379
|
+
NODE
|
|
380
|
+
AUDIO_BYTES="$AUDIO_ALIGNED_BYTES"
|
|
381
|
+
fi
|
|
382
|
+
AUDIO_PACKET_COUNT=$((AUDIO_BYTES / AUDIO_PACKET_BYTES))
|
|
383
|
+
[[ "$AUDIO_PACKET_COUNT" -gt 0 ]] || fail "generated audio packets are empty"
|
|
384
|
+
|
|
385
|
+
{
|
|
386
|
+
echo "pts_us,offset,size"
|
|
387
|
+
for ((i = 0; i < AUDIO_PACKET_COUNT; i += 1)); do
|
|
388
|
+
pts_us=$((i * k_audio_packet_duration_ms * 1000))
|
|
389
|
+
offset=$((i * AUDIO_PACKET_BYTES))
|
|
390
|
+
echo "${pts_us},${offset},${AUDIO_PACKET_BYTES}"
|
|
391
|
+
done
|
|
392
|
+
} > "$AUDIO_PACKET_INDEX_PATH"
|
|
393
|
+
|
|
394
|
+
cat > "$MANIFEST_PATH" <<JSON
|
|
395
|
+
{
|
|
396
|
+
"schema_version": ${k_schema_version},
|
|
397
|
+
"tool_version": "${k_tool_version}",
|
|
398
|
+
"source": {
|
|
399
|
+
"file_name": "${SOURCE_FILE_NAME}",
|
|
400
|
+
"sha256": "${SOURCE_SHA256}"
|
|
401
|
+
},
|
|
402
|
+
"video": {
|
|
403
|
+
"path": "video/video.h264",
|
|
404
|
+
"packet_index_path": "video/video_packets.csv",
|
|
405
|
+
"codec": "${k_video_codec}",
|
|
406
|
+
"width": ${TARGET_VIDEO_WIDTH},
|
|
407
|
+
"height": ${TARGET_VIDEO_HEIGHT},
|
|
408
|
+
"fps": ${k_video_fps},
|
|
409
|
+
"bitrate_kbps": ${TARGET_VIDEO_BITRATE_KBPS}
|
|
410
|
+
},
|
|
411
|
+
"audio": {
|
|
412
|
+
"path": "audio/audio.g711a",
|
|
413
|
+
"packet_index_path": "audio/audio_packets.csv",
|
|
414
|
+
"codec": "${k_audio_codec}",
|
|
415
|
+
"sample_rate_hz": ${k_audio_sample_rate_hz},
|
|
416
|
+
"channels": ${k_audio_channels},
|
|
417
|
+
"packet_duration_ms": ${k_audio_packet_duration_ms}
|
|
418
|
+
},
|
|
419
|
+
"output": {
|
|
420
|
+
"audio_format": "${k_output_audio_format}",
|
|
421
|
+
"video_format": "${k_output_video_format}"
|
|
422
|
+
},
|
|
423
|
+
"loop_policy": "${k_loop_policy}"
|
|
424
|
+
}
|
|
425
|
+
JSON
|
|
426
|
+
|
|
427
|
+
emit_result "$ASSETS_DIR" "$MANIFEST_PATH" false
|