Hướng dẫn sử dụng
Cấu hình Camera Station & chạy test
1Cấu hình RTSP Templates
Các mẫu URL RTSP được định nghĩa trong Backend/appsettings.json, mục RtspConfig.Templates.
Mỗi template có hai trường:
- UrlTemplate – mẫu URL với placeholder
{creds},{host},{track},{start},{end} - TimeFormat – định dạng thời gian theo chuẩn .NET (ví dụ:
yyyyMMddTHHmmss,yyyy_MM_dd_HH_mm_ss)
Backend/appsettings.json
{
"RtspConfig": {
"Templates": {
"[ARYA]": {
"UrlTemplate": "rtsp://{creds}@{host}/cam/playback?channel={track}&subtype=0&starttime={start}&endtime={end}",
"TimeFormat": "yyyy_MM_dd_HH_mm_ss"
},
"[HIK_OLD]": {
"UrlTemplate": "rtsp://{creds}@{host}/Streaming/tracks/{track}/?starttime={start}&endtime={end}&size=1064413088&rw_timeout=50000000",
"TimeFormat": "yyyyMMddTHHmmss"
},
"DEFAULT": {
"UrlTemplate": "rtsp://{creds}@{host}/Streaming/tracks/{track}/?starttime={start}&endtime={end}&size=1064413088&rw_timeout=50000000",
"TimeFormat": "yyyyMMddTHHmmss"
}
}
}
}
Templates với key
là tag (ví dụ [DAHUA]), không cần sửa code.
2Nhập liệu Camera Station
Vào menu Camera Stations → Create hoặc chỉnh sửa station hiện có.
| Trường | Bắt buộc | Ví dụ | Mô tả |
|---|---|---|---|
ComputerName |
Có | dg-6bd |
Tên máy trạm, dùng để tìm kiếm khi tạo VideoClip |
Track |
Có | 101 |
Số kênh RTSP của đầu ghi |
IpAndPort |
Có | 192.168.60.115:554 |
IP và port của camera trực tiếp |
NvrIpAndPort |
Có | 192.168.60.3:554 |
IP và port của NVR (đầu ghi tập trung) |
Description |
Không | Camera kho 6 [ARYA] |
Chứa tag loại đầu ghi để chọn RTSP template phù hợp. Xem mục 3 để biết cú pháp. |
IsActive |
Không | ✓ |
Chỉ station đang Active mới được sử dụng để tạo VideoClip |
3Quy tắc trường Description
Hệ thống tự động chọn RTSP template và token dựa vào nội dung trường Description.
Có hai cú pháp hỗ trợ:
Cú pháp 1 — Chỉ chọn template (không override token)
Đặt tag là key trong appsettings.json vào bất kỳ vị trí nào trong Description:
| Description | Kết quả |
|---|---|
Camera dg-6bd [ARYA] | [ARYA] + token mặc định |
Đầu ghi cũ [HIK_OLD] | [HIK_OLD] + token mặc định |
[ARYA] kho 3 tầng 1 | [ARYA] + token mặc định |
| (để trống) | DEFAULT + token mặc định |
| Description | Lý do sai |
|---|---|
[[Format:ARYA]] | Không phải cú pháp hợp lệ |
ARYA | Thiếu dấu ngoặc vuông |
[arya] | Key phân biệt chữ hoa thường |
Cú pháp 2 — Chọn template và nhúng token riêng
Dùng khi camera station cần token khác với token mặc định.
Cú pháp: [[TYPE:token]]
Camera kho 6 [[ARYA:dXNlcjpwYXNz]]
^^^^^^^^^^^^
└─ token riêng của camera này (Base64 hoặc plaintext)
[[HIK_OLD:admin:abc123]] kho cũ tầng 2
# Kết quả sau khi parse:
# Template được chọn : [ARYA] hoặc [HIK_OLD]
# Token gửi lên backend: dXNlcjpwYXNz / admin:abc123
# Token mặc định bị BỎ QUA
| Description | Template | Token dùng |
|---|---|---|
Camera [[ARYA:dXNlcjpwYXNz]] | [ARYA] | dXNlcjpwYXNz (từ Description) |
[[HIK_OLD:tok123]] kho cũ | [HIK_OLD] | tok123 (từ Description) |
Camera [ARYA] | [ARYA] | Token mặc định của VideoClip |
| (để trống) | DEFAULT | Token mặc định của VideoClip |
- Token nhúng trong Description:
[[TYPE:token]] - Token lưu trên VideoClip (trường
Token) - Default token từ cấu hình (
VideoClip:DefaultToken)
[[TYPE:token]] phải là CHỮ HOA và chỉ chứa A-Z, 0-9, _.
Ví dụ hợp lệ: ARYA, HIK_OLD, DAHUA2.
Ví dụ KHÔNG hợp lệ: arya, Arya.
Luồng xử lý
- Khi tạo / trích xuất VideoClip, hệ thống đọc
Descriptioncủa CameraStation. - Frontend parse Description (
DescriptionParser):- Nếu tìm thấy
[[TYPE:token]]→ chuẩn hoá thành[TYPE]trong Description, lấy token override. - Ngược lại → giữ nguyên Description, token = token mặc định của VideoClip.
- Nếu tìm thấy
- Payload gửi Backend chứa
Description(đã chuẩn hoá) vàToken(đã chọn đúng). - Backend dùng
RtspTemplateHelper: duyệt keys, key nàoContainstrong Description → chọn template đó. - Nếu không có key nào khớp → dùng template
DEFAULT. TimeFormatcủa template được áp dụng cho{start}và{end}.
4Kiểm tra kết quả trích xuất
Sau khi tạo và chạy VideoClip, kiểm tra log của Backend container để xác nhận template đã được chọn đúng:
# Xem realtime log
docker logs -f <backend-container-name>
# Tìm dòng log template
docker logs <backend-container-name> 2>&1 | grep "RTSP template key matched"
Dòng log mẫu khi chọn đúng template [ARYA]:
info: Backend.Controllers.VideoCaptureController[0]
RTSP template key matched: [ARYA], TimeFormat: yyyy_MM_dd_HH_mm_ss
5Chạy Unit Test
Toàn bộ test chạy trong Docker container video-extraction-dev (image mcr.microsoft.com/dotnet/sdk:8.0).
Workspace được mount tại /app.
Backend Tests – RtspTemplateHelperTests
Kiểm tra logic chọn template và định dạng thời gian (14 test cases, không cần DB, không cần FFmpeg).
# Khởi động container (nếu chưa chạy)
docker start video-extraction-dev
# Chạy backend tests
docker exec video-extraction-dev \
dotnet test /app/Backend.Tests/Backend.Tests.csproj \
--logger "console;verbosity=normal"
| Test | Mục đích kiểm tra |
|---|---|
SelectsAryaTemplate_WhenDescriptionContainsAryaTag | Description chứa [ARYA] → chọn ARYA URL |
SelectsHikOldTemplate_WhenDescriptionContainsHikOldTag | Description chứa [HIK_OLD] → chọn HIK_OLD URL |
FallsBackToDefault_WhenDescriptionIsNull | Description null → dùng DEFAULT |
FallsBackToDefault_WhenDescriptionIsEmpty | Description rỗng → dùng DEFAULT |
FallsBackToDefault_WhenDescriptionHasNoKnownTag | Description không có tag → dùng DEFAULT |
AryaTemplate_UsesUnderscoreSeparatedTimeFormat | ARYA template dùng format yyyy_MM_dd_HH_mm_ss |
DefaultTemplate_UsesHikVisionTimeFormat_NoZSuffix | DEFAULT template dùng format yyyyMMddTHHmmss |
CustomTimeFormat_IsApplied_WhenConfiguredPerTemplate | TimeFormat bất kỳ từ config được áp dụng đúng |
ThrowsInvalidOperation_WhenNoDefaultTemplate | Thiếu entry DEFAULT → ném exception |
PicksFirstMatchingTag_WhenDescriptionContainsMultipleTags | Nhiều tag → lấy tag đầu tiên khớp |
ReplacesAllPlaceholders_* (×2) | Tất cả placeholder được thay thế đúng |
TrackIsConvertedToString_NotLeft_AsInt | Track int được convert sang string |
HikOldTemplate_UsesHikVisionTimeFormat_NoZSuffix | HIK_OLD dùng format không có Z |
Frontend Tests – StationDescriptionTests & DescriptionParserTests
Kiểm tra logic tìm kiếm Description từ DB, parse [[TYPE:token]] và đóng gói extract request (15 + 19 test cases).
# Chỉ chạy StationDescriptionTests
docker exec video-extraction-dev \
dotnet test /app/Frontend/UnitTest/UnitTest.csproj \
--filter "FullyQualifiedName~StationDescriptionTests" \
--logger "console;verbosity=normal"
# Chỉ chạy DescriptionParserTests (parser [[TYPE:token]])
docker exec video-extraction-dev \
dotnet test /app/Frontend/UnitTest/UnitTest.csproj \
--filter "FullyQualifiedName~DescriptionParserTests" \
--logger "console;verbosity=normal"
# Chạy toàn bộ frontend tests
docker exec video-extraction-dev \
dotnet test /app/Frontend/UnitTest/UnitTest.csproj \
--logger "console;verbosity=normal"
6Câu hỏi thường gặp
appsettings.json — bao gồm dấu ngoặc vuông và chữ hoa/thường.
(2) Tìm dòng log RTSP template key matched để xem backend đã đọc được key nào.
(3) Sau khi sửa appsettings.json, cần restart backend container để load lại config.
- Mở
Backend/appsettings.json, thêm entry mới vàoRtspConfig.Templates. Ví dụ:"[DAHUA]": {{ "UrlTemplate": "rtsp://...", "TimeFormat": "yyyyMMddTHHmmss" }} - Restart backend container.
- Trên trang Camera Stations, sửa Description của station đó để chứa tag mới (ví dụ:
Camera kho [DAHUA]).
DateTime.ToString(format) đều được hỗ trợ. Một số ví dụ:yyyyMMddTHHmmss – Hikvision tiêu chuẩnyyyy_MM_dd_HH_mm_ss – ARYA (dấu gạch dưới phân cách)yyyy-MM-ddTHH:mm:ss – ISO 8601yyyyMMdd_HHmmss – Định dạng tùy chỉnh với dấu gạch dưới
video-extraction-dev, không phải trên host.
Đảm bảo container đang chạy (docker start video-extraction-dev) rồi dùng docker exec như ví dụ ở mục 5.
[[TYPE:token]] trong trường Description của CameraStation.
Ví dụ: Camera kho 6 [[ARYA:dXNlcjpwYXNz]].
Token này sẽ được dùng thay cho token mặc định khi trích xuất clip từ station đó.
Token nên là giá trị Base64 của username:password.