Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2198,6 +2198,91 @@
}
}
}
},
"post": {
"tags": [
"videos"
],
"summary": "Upload a new video file",
"description": "**Upload a new video file to the INPUT_VIDEO_DIR.**\n\n## Operation\n\n1. Validate file extension against supported formats\n2. Save file to INPUT_VIDEO_DIR in 8KB chunks\n3. Extract video metadata (resolution, fps, codec, etc.)\n4. Create TS conversion for looping support\n5. Return Video object with extracted metadata\n\n## Parameters\n\n- `file` (multipart/form-data) - Video file to upload\n\n## Response Format\n\n| Code | Description |\n|------|-------------|\n| 201 | Video uploaded successfully, returns Video object |\n| 400 | Invalid file (unsupported extension or codec, duplicate filename) |\n| 500 | Error during upload or processing |\n\n## Conditions\n\n### \u2705 Success\n- File has supported video extension (mp4, mkv, mov, avi, ts, 264, avc, h265, hevc)\n- File has supported codec (h264 or h265)\n- No file with same name exists in INPUT_VIDEO_DIR\n- Video metadata extraction successful\n\n### \u274c Failure\n- No file provided \u2192 400\n- File extension not supported \u2192 400\n- Filename already exists \u2192 400\n- Video codec not h264/h265 \u2192 400\n- Cannot extract metadata \u2192 500\n- Write error \u2192 500\n\n## Example Response\n\n```json\n{\n \"filename\": \"uploaded_video.mp4\",\n \"width\": 1920,\n \"height\": 1080,\n \"fps\": 30.0,\n \"frame_count\": 1800,\n \"codec\": \"h264\",\n \"duration\": 60.0\n}\n```",
"operationId": "upload_video",
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/Body_upload_video"
}
}
},
"required": true
},
"responses": {
"201": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Video"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/videos/check-video-input-exists": {
"get": {
"tags": [
"videos"
],
"summary": "Check if a video file already exists",
"description": "**Check if a video file with the given filename already exists in INPUT_VIDEO_DIR.**\n\n## Operation\n\n1. Validates filename against INPUT_VIDEO_DIR\n2. Returns whether the file exists\n\n## Parameters\n\n- `filename` (query) - Name of the video file to check\n\n## Response Format\n\n| Code | Description |\n|------|-------------|\n| 200 | Returns VideoExistsResponse with exists boolean |\n\n## Conditions\n\n### \u2705 Success\n- Always succeeds with boolean response\n\n## Example Response\n\n```json\n{\n \"exists\": true,\n \"filename\": \"traffic_1080p_h264.mp4\"\n}\n```",
"operationId": "check_video_input_exists",
"parameters": [
{
"name": "filename",
"in": "query",
"required": true,
"schema": {
"type": "string",
"description": "Video filename to check",
"title": "Filename"
},
"description": "Video filename to check"
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VideoExistsResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/cameras": {
Expand Down Expand Up @@ -2406,6 +2491,20 @@
"title": "AppStatus",
"description": "**Application status enum for tracking initialization progress.**\n\n## Values\n- `STARTING` - Application is starting, no initialization yet\n- `INITIALIZING` - Application is initializing resources (e.g., loading videos)\n- `READY` - Application is fully initialized and ready to serve requests\n- `SHUTDOWN` - Application is shutting down\n\n### Example\n```json\n\"ready\"\n```"
},
"Body_upload_video": {
"properties": {
"file": {
"type": "string",
"contentMediaType": "application/octet-stream",
"title": "File"
}
},
"type": "object",
"required": [
"file"
],
"title": "Body_upload_video"
},
"Camera": {
"properties": {
"device_id": {
Expand Down Expand Up @@ -4406,6 +4505,27 @@
],
"title": "Video",
"description": "**Metadata for a single input video file.**\n\n## Attributes\n- `filename` - Base name of the video file located under INPUT_VIDEO_DIR\n- `width` - Frame width in pixels\n- `height` - Frame height in pixels\n- `fps` - Frames per second for the stream\n- `frame_count` - Total number of frames in the file\n- `codec` - Normalized codec name (e.g., \"h264\" or \"h265\")\n- `duration` - Approximate duration in seconds\n\n### Example\n```json\n[\n {\n \"filename\": \"traffic_1080p_h264.mp4\",\n \"width\": 1920,\n \"height\": 1080,\n \"fps\": 30.0,\n \"frame_count\": 900,\n \"codec\": \"h264\",\n \"duration\": 30.0\n }\n]\n```"
},
"VideoExistsResponse": {
"properties": {
"exists": {
"type": "boolean",
"title": "Exists",
"description": "True if the video file exists, False otherwise."
},
"filename": {
"type": "string",
"title": "Filename",
"description": "The filename that was checked."
}
},
"type": "object",
"required": [
"exists",
"filename"
],
"title": "VideoExistsResponse",
"description": "**Response indicating whether a video file exists.**\n\n## Attributes\n- `exists` - True if file exists in INPUT_VIDEO_DIR, False otherwise\n- `filename` - The filename that was checked\n\n### Example\n```json\n{\n \"exists\": true,\n \"filename\": \"traffic_1080p_h264.mp4\"\n}\n```"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ server {

# Reverse proxy for API calls
location /api/ {
# Allow large file uploads (for video uploads)
client_max_body_size 2G;

proxy_pass http://vippet:7860;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
Expand All @@ -19,9 +22,9 @@ server {
proxy_set_header Access-Control-Allow-Headers "Content-Type, Authorization";

# Timeout settings
proxy_connect_timeout 30;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
}

# WebSocket proxy for metrics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,27 @@ const injectedRtkApi = api
}),
invalidatesTags: ["jobs"],
}),
getPerformanceJobMetadataSnapshot: build.query<
GetPerformanceJobMetadataSnapshotApiResponse,
GetPerformanceJobMetadataSnapshotApiArg
>({
query: (queryArg) => ({
url: `/jobs/tests/performance/${queryArg.jobId}/metadata/${queryArg.pipelineId}/${queryArg.fileIndex}`,
params: {
limit: queryArg.limit,
},
}),
providesTags: ["jobs"],
}),
streamPerformanceJobMetadata: build.query<
StreamPerformanceJobMetadataApiResponse,
StreamPerformanceJobMetadataApiArg
>({
query: (queryArg) => ({
url: `/jobs/tests/performance/${queryArg.jobId}/metadata/${queryArg.pipelineId}/${queryArg.fileIndex}/stream`,
}),
providesTags: ["jobs"],
}),
getDensityStatuses: build.query<
GetDensityStatusesApiResponse,
GetDensityStatusesApiArg
Expand Down Expand Up @@ -157,7 +178,7 @@ const injectedRtkApi = api
GetValidationJobStatusApiResponse,
GetValidationJobStatusApiArg
>({
query: (queryArg) => ({
query: (queryArg) => ({
url: `/jobs/validation/${queryArg.jobId}/status`,
}),
providesTags: ["jobs"],
Expand Down Expand Up @@ -324,6 +345,26 @@ const injectedRtkApi = api
query: () => ({ url: `/videos` }),
providesTags: ["videos"],
}),
uploadVideo: build.mutation<UploadVideoApiResponse, UploadVideoApiArg>({
query: (queryArg) => ({
url: `/videos`,
method: "POST",
body: queryArg.bodyUploadVideo,
}),
invalidatesTags: ["videos"],
}),
checkVideoInputExists: build.query<
CheckVideoInputExistsApiResponse,
CheckVideoInputExistsApiArg
>({
query: (queryArg) => ({
url: `/videos/check-video-input-exists`,
params: {
filename: queryArg.filename,
},
}),
providesTags: ["videos"],
}),
getCameras: build.query<GetCamerasApiResponse, GetCamerasApiArg>({
query: () => ({ url: `/cameras` }),
providesTags: ["cameras"],
Expand Down Expand Up @@ -384,6 +425,21 @@ export type StopPerformanceTestJobApiResponse =
export type StopPerformanceTestJobApiArg = {
jobId: string;
};
export type GetPerformanceJobMetadataSnapshotApiResponse =
/** status 200 List of metadata records for the specified pipeline stream */ object[];
export type GetPerformanceJobMetadataSnapshotApiArg = {
jobId: string;
pipelineId: string;
fileIndex: number;
limit?: number;
};
export type StreamPerformanceJobMetadataApiResponse =
/** status 200 SSE stream of metadata records */ any;
export type StreamPerformanceJobMetadataApiArg = {
jobId: string;
pipelineId: string;
fileIndex: number;
};
export type GetDensityStatusesApiResponse =
/** status 200 Successful Response */ DensityJobStatus[];
export type GetDensityStatusesApiArg = void;
Expand Down Expand Up @@ -521,6 +577,17 @@ export type RunDensityTestApiArg = {
export type GetVideosApiResponse =
/** status 200 Successful Response */ Video[];
export type GetVideosApiArg = void;
export type UploadVideoApiResponse =
/** status 201 Successful Response */ Video;
export type UploadVideoApiArg = {
bodyUploadVideo: BodyUploadVideo;
};
export type CheckVideoInputExistsApiResponse =
/** status 200 Successful Response */ VideoExistsResponse;
export type CheckVideoInputExistsApiArg = {
/** Video filename to check */
filename: string;
};
export type GetCamerasApiResponse =
/** status 200 List of all cameras successfully retrieved. */ Camera[];
export type GetCamerasApiArg = void;
Expand Down Expand Up @@ -576,7 +643,7 @@ export type ValidationError = {
loc: (string | number)[];
msg: string;
type: string;
input?: unknown;
input?: any;
ctx?: object;
};
export type HttpValidationError = {
Expand Down Expand Up @@ -618,11 +685,14 @@ export type PerformanceJobStatus = {
live_stream_urls: {
[key: string]: string;
} | null;
metadata_stream_urls: {
[key: string]: string[];
} | null;
};
export type PerformanceJobSummary = {
id: string;
request: {
[key: string]: unknown;
[key: string]: any;
};
};
export type DensityJobStatus = {
Expand All @@ -642,7 +712,7 @@ export type DensityJobStatus = {
export type DensityJobSummary = {
id: string;
request: {
[key: string]: unknown;
[key: string]: any;
};
};
export type OptimizationType = "preprocess" | "optimize";
Expand All @@ -665,7 +735,7 @@ export type OptimizationJobStatus = {
export type PipelineRequestOptimize = {
type: OptimizationType;
parameters: {
[key: string]: unknown;
[key: string]: any;
} | null;
};
export type OptimizationJobSummary = {
Expand All @@ -684,7 +754,7 @@ export type ValidationJobStatus = {
export type PipelineValidation = {
pipeline_graph: PipelineGraph;
parameters?: {
[key: string]: unknown;
[key: string]: any;
} | null;
};
export type ValidationJobSummary = {
Expand Down Expand Up @@ -760,7 +830,7 @@ export type ValidationJobResponse = {
export type PipelineValidation2 = {
pipeline_graph: PipelineGraph;
parameters?: {
[key: string]: unknown;
[key: string]: any;
} | null;
};
export type PipelineUpdate = {
Expand Down Expand Up @@ -821,11 +891,14 @@ export type PipelinePerformanceSpec = {
streams?: number;
};
export type OutputMode = "disabled" | "file" | "live_stream";
export type MetadataMode = "disabled" | "file";
export type ExecutionConfig = {
/** Mode for pipeline output generation. */
output_mode?: OutputMode;
/** Maximum runtime in seconds (0 = run until EOS, >0 = time limit with looping for live_stream/disabled). */
max_runtime?: number;
/** Metadata publishing mode. 'disabled' (default): no metadata produced. 'file': gvametapublish elements write JSON-Lines metadata, available via SSE endpoints. */
metadata_mode?: MetadataMode;
};
export type PerformanceTestSpec = {
/** List of pipelines with number of streams for each. */
Expand Down Expand Up @@ -865,6 +938,15 @@ export type Video = {
codec: string;
duration: number;
};
export type BodyUploadVideo = {
file: string;
};
export type VideoExistsResponse = {
/** True if the video file exists, False otherwise. */
exists: boolean;
/** The filename that was checked. */
filename: string;
};
export type CameraType = "USB" | "NETWORK";
export type V4L2BestCapture = {
fourcc: string;
Expand Down Expand Up @@ -920,6 +1002,10 @@ export const {
useGetPerformanceJobSummaryQuery,
useLazyGetPerformanceJobSummaryQuery,
useStopPerformanceTestJobMutation,
useGetPerformanceJobMetadataSnapshotQuery,
useLazyGetPerformanceJobMetadataSnapshotQuery,
useStreamPerformanceJobMetadataQuery,
useLazyStreamPerformanceJobMetadataQuery,
useGetDensityStatusesQuery,
useLazyGetDensityStatusesQuery,
useGetDensityJobStatusQuery,
Expand Down Expand Up @@ -963,6 +1049,9 @@ export const {
useRunDensityTestMutation,
useGetVideosQuery,
useLazyGetVideosQuery,
useUploadVideoMutation,
useCheckVideoInputExistsQuery,
useLazyCheckVideoInputExistsQuery,
useGetCamerasQuery,
useLazyGetCamerasQuery,
useGetCameraQuery,
Expand Down
Loading
Loading