diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/docs/user-guide/_assets/vippet.json b/tools/visual-pipeline-and-platform-evaluation-tool/docs/user-guide/_assets/vippet.json
index 66abb98a50..a04789c2c3 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/docs/user-guide/_assets/vippet.json
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/docs/user-guide/_assets/vippet.json
@@ -1305,13 +1305,13 @@
"tests"
],
"summary": "Run Performance Test",
- "description": "Start an asynchronous performance test job.\n\nOperation:\n * Validate the performance test request.\n * Create a PerformanceJob with RUNNING state.\n * Spawn a background thread that runs the pipelines using\n a GStreamer-based runner.\n * Return the job identifier so the caller can poll status endpoints.\n\nRequest body:\n body: PerformanceTestSpec\n * pipeline_performance_specs \u2013 list of pipelines and number of\n streams per pipeline.\n * video_output \u2013 configuration for optional encoded video output\n (enabled flag and encoder_device).\n\nReturns:\n 202 Accepted:\n TestJobResponse with job_id of the created performance job.\n 400 Bad Request:\n MessageResponse if the request is invalid at manager level, for\n example:\n * all stream counts are zero,\n * pipeline ids do not exist (if validated up front in future).\n 500 Internal Server Error:\n MessageResponse if an unexpected error occurs when creating the\n job or starting the background thread.\n\nSuccess conditions:\n * At least one stream is requested across all pipelines.\n * TestsManager.test_performance() successfully enqueues the job.\n\nFailure conditions (high level):\n * Validation or configuration error inside TestsManager \u2192 400.\n * Any unhandled exception in job creation \u2192 500.\n\nRequest example:\n .. code-block:: json\n\n {\n \"pipeline_performance_specs\": [\n {\"id\": \"pipeline-a3f5d9e1\", \"streams\": 8},\n {\"id\": \"pipeline-b7c2e114\", \"streams\": 4}\n ],\n \"video_output\": {\n \"enabled\": false,\n \"encoder_device\": {\"device_name\": \"GPU\", \"gpu_id\": 0}\n }\n }\n\nSuccessful response example (202):\n .. code-block:: json\n\n {\n \"job_id\": \"job123\"\n }\n\nError response example (400, invalid request):\n .. code-block:: json\n\n {\n \"message\": \"At least one stream must be specified to run the pipeline.\"\n }",
+ "description": "Start an asynchronous performance test job.\n\nOperation:\n * Validate the performance test request.\n * Create a PerformanceJob with RUNNING state.\n * Spawn a background thread that runs the pipelines using\n a GStreamer-based runner.\n * Return the job identifier so the caller can poll status endpoints.\n\nRequest body:\n body: PerformanceTestSpec\n * pipeline_performance_specs \u2013 list of pipelines and number of\n streams per pipeline.\n * video_output \u2013 configuration for optional encoded video output\n (enabled flag).\n\nReturns:\n 202 Accepted:\n TestJobResponse with job_id of the created performance job.\n 400 Bad Request:\n MessageResponse if the request is invalid at manager level, for\n example:\n * all stream counts are zero,\n * pipeline ids do not exist (if validated up front in future).\n 500 Internal Server Error:\n MessageResponse if an unexpected error occurs when creating the\n job or starting the background thread.\n\nSuccess conditions:\n * At least one stream is requested across all pipelines.\n * TestsManager.test_performance() successfully enqueues the job.\n\nFailure conditions (high level):\n * Validation or configuration error inside TestsManager \u2192 400.\n * Any unhandled exception in job creation \u2192 500.\n\nRequest example:\n .. code-block:: json\n\n {\n \"pipeline_performance_specs\": [\n {\"id\": \"pipeline-a3f5d9e1\", \"streams\": 8},\n {\"id\": \"pipeline-b7c2e114\", \"streams\": 4}\n ],\n \"video_output\": {\n \"enabled\": false\n }\n }\n\nSuccessful response example (202):\n .. code-block:: json\n\n {\n \"job_id\": \"job123\"\n }\n\nError response example (400, invalid request):\n .. code-block:: json\n\n {\n \"message\": \"At least one stream must be specified to run the pipeline.\"\n }",
"operationId": "run_performance_test",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/PerformanceTestSpec-Input"
+ "$ref": "#/components/schemas/PerformanceTestSpec"
}
}
},
@@ -1367,13 +1367,13 @@
"tests"
],
"summary": "Run Density Test",
- "description": "Start an asynchronous density test job.\n\nOperation:\n * Validate the density test request.\n * Use requested fps_floor and per\u2011pipeline stream_rate ratios.\n * Create a DensityJob with RUNNING state.\n * Spawn a background thread that runs a Benchmark to determine the\n maximum number of streams that still meets fps_floor.\n * Return the job identifier so the caller can poll status endpoints.\n\nRequest body:\n body: DensityTestSpec\n * fps_floor \u2013 minimum acceptable FPS per stream.\n * pipeline_density_specs \u2013 list of pipelines with stream_rate\n percentages that must sum to 100.\n * video_output \u2013 configuration for optional encoded video output.\n\nReturns:\n 202 Accepted:\n TestJobResponse with job_id of the created density job.\n 400 Bad Request:\n MessageResponse when:\n * pipeline_density_specs.stream_rate values do not sum to 100,\n * other validation errors raised by Benchmark or TestsManager.\n 500 Internal Server Error:\n MessageResponse for unexpected errors when creating or starting\n the job.\n\nSuccess conditions:\n * stream_rate ratios sum to 100%.\n * DensityTestSpec is valid and Benchmark.run() can be started in a\n background thread.\n\nFailure conditions:\n * Validation errors in Benchmark._calculate_streams_per_pipeline() or\n TestsManager.test_density() \u2192 400.\n * Any other unhandled exception \u2192 500.\n\nRequest example:\n .. code-block:: json\n\n {\n \"fps_floor\": 30,\n \"pipeline_density_specs\": [\n {\"id\": \"pipeline-a3f5d9e1\", \"stream_rate\": 50},\n {\"id\": \"pipeline-b7c2e114\", \"stream_rate\": 50}\n ],\n \"video_output\": {\n \"enabled\": false,\n \"encoder_device\": {\"device_name\": \"GPU\", \"gpu_id\": 0}\n }\n }\n\nSuccessful response example (202):\n .. code-block:: json\n\n {\n \"job_id\": \"job456\"\n }\n\nError response example (400, bad ratios):\n .. code-block:: json\n\n {\n \"message\": \"Pipeline stream_rate ratios must sum to 100%, got 110%\"\n }",
+ "description": "Start an asynchronous density test job.\n\nOperation:\n * Validate the density test request.\n * Use requested fps_floor and per\u2011pipeline stream_rate ratios.\n * Create a DensityJob with RUNNING state.\n * Spawn a background thread that runs a Benchmark to determine the\n maximum number of streams that still meets fps_floor.\n * Return the job identifier so the caller can poll status endpoints.\n\nRequest body:\n body: DensityTestSpec\n * fps_floor \u2013 minimum acceptable FPS per stream.\n * pipeline_density_specs \u2013 list of pipelines with stream_rate\n percentages that must sum to 100.\n * video_output \u2013 configuration for optional encoded video output.\n\nReturns:\n 202 Accepted:\n TestJobResponse with job_id of the created density job.\n 400 Bad Request:\n MessageResponse when:\n * pipeline_density_specs.stream_rate values do not sum to 100,\n * other validation errors raised by Benchmark or TestsManager.\n 500 Internal Server Error:\n MessageResponse for unexpected errors when creating or starting\n the job.\n\nSuccess conditions:\n * stream_rate ratios sum to 100%.\n * DensityTestSpec is valid and Benchmark.run() can be started in a\n background thread.\n\nFailure conditions:\n * Validation errors in Benchmark._calculate_streams_per_pipeline() or\n TestsManager.test_density() \u2192 400.\n * Any other unhandled exception \u2192 500.\n\nRequest example:\n .. code-block:: json\n\n {\n \"fps_floor\": 30,\n \"pipeline_density_specs\": [\n {\"id\": \"pipeline-a3f5d9e1\", \"stream_rate\": 50},\n {\"id\": \"pipeline-b7c2e114\", \"stream_rate\": 50}\n ],\n \"video_output\": {\n \"enabled\": false\n }\n }\n\nSuccessful response example (202):\n .. code-block:: json\n\n {\n \"job_id\": \"job456\"\n }\n\nError response example (400, bad ratios):\n .. code-block:: json\n\n {\n \"message\": \"Pipeline stream_rate ratios must sum to 100%, got 110%\"\n }",
"operationId": "run_density_test",
"requestBody": {
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/DensityTestSpec-Input"
+ "$ref": "#/components/schemas/DensityTestSpec"
}
}
},
@@ -1568,7 +1568,7 @@
"title": "Id"
},
"request": {
- "$ref": "#/components/schemas/DensityTestSpec-Output"
+ "$ref": "#/components/schemas/DensityTestSpec"
}
},
"type": "object",
@@ -1579,7 +1579,7 @@
"title": "DensityJobSummary",
"description": "Short summary for a density test job.\n\nAttributes:\n id: Job identifier.\n request: Original DensityTestSpec used to start the job."
},
- "DensityTestSpec-Input": {
+ "DensityTestSpec": {
"properties": {
"fps_floor": {
"type": "integer",
@@ -1614,79 +1614,11 @@
"$ref": "#/components/schemas/VideoOutputConfig",
"description": "Video output configuration.",
"default": {
- "enabled": false,
- "encoder_device": {
- "device_name": "GPU",
- "gpu_id": 0
- }
- },
- "examples": [
- {
- "enabled": false,
- "encoder_device": {
- "device_name": "GPU",
- "gpu_id": 0
- }
- }
- ]
- }
- },
- "type": "object",
- "required": [
- "fps_floor",
- "pipeline_density_specs"
- ],
- "title": "DensityTestSpec",
- "description": "Request body for starting a density test.\n\nAttributes:\n fps_floor: Minimum acceptable FPS per stream.\n pipeline_density_specs: List of pipelines with relative stream_rate ratios.\n video_output: Optional configuration for storing encoded video outputs."
- },
- "DensityTestSpec-Output": {
- "properties": {
- "fps_floor": {
- "type": "integer",
- "minimum": 0.0,
- "title": "Fps Floor",
- "description": "Minimum acceptable FPS per stream.",
- "examples": [
- 30
- ]
- },
- "pipeline_density_specs": {
- "items": {
- "$ref": "#/components/schemas/PipelineDensitySpec"
- },
- "type": "array",
- "title": "Pipeline Density Specs",
- "description": "List of pipelines with relative stream_rate percentages that must sum to 100.",
- "examples": [
- [
- {
- "id": "pipeline-1",
- "stream_rate": 50
- },
- {
- "id": "pipeline-2",
- "stream_rate": 50
- }
- ]
- ]
- },
- "video_output": {
- "$ref": "#/components/schemas/VideoOutputConfig",
- "description": "Video output configuration.",
- "default": {
- "enabled": false,
- "encoder_device": {
- "device_name": "GPU",
- "gpu_id": 0
- }
+ "enabled": false
},
"examples": [
{
- "enabled": false,
- "encoder_device": {
- "device_name": "GPU",
- "gpu_id": 0
- }
+ "enabled": false
}
]
}
@@ -1781,40 +1713,6 @@
"title": "Edge",
"description": "Directed connection between two nodes in a generic pipeline graph.\n\nAttributes:\n id: Edge identifier, unique within a single graph.\n source: ID of the source node.\n target: ID of the target node."
},
- "EncoderDeviceConfig": {
- "properties": {
- "device_name": {
- "type": "string",
- "title": "Device Name",
- "description": "Name of the encoder device (e.g., 'GPU', 'CPU', 'NPU')",
- "default": "GPU",
- "examples": [
- "GPU",
- "CPU",
- "NPU"
- ]
- },
- "gpu_id": {
- "anyOf": [
- {
- "type": "integer"
- },
- {
- "type": "null"
- }
- ],
- "title": "Gpu Id",
- "description": "GPU device index (only applicable when device_name indicates a GPU)",
- "examples": [
- 0,
- 1
- ]
- }
- },
- "type": "object",
- "title": "EncoderDeviceConfig",
- "description": "Encoder device configuration used in video output settings.\n\nAttributes:\n device_name: Name of the encoder device (for example ``\"GPU\"``).\n gpu_id: Optional GPU index when applicable.\n\nExample:\n .. code-block:: json\n\n {\n \"device_name\": \"GPU\",\n \"gpu_id\": 0\n }"
- },
"HTTPValidationError": {
"properties": {
"detail": {
@@ -2190,7 +2088,7 @@
"title": "Id"
},
"request": {
- "$ref": "#/components/schemas/PerformanceTestSpec-Output"
+ "$ref": "#/components/schemas/PerformanceTestSpec"
}
},
"type": "object",
@@ -2201,57 +2099,7 @@
"title": "PerformanceJobSummary",
"description": "Short summary for a performance test job.\n\nAttributes:\n id: Job identifier.\n request: Original PerformanceTestSpec used to start the job."
},
- "PerformanceTestSpec-Input": {
- "properties": {
- "pipeline_performance_specs": {
- "items": {
- "$ref": "#/components/schemas/PipelinePerformanceSpec"
- },
- "type": "array",
- "title": "Pipeline Performance Specs",
- "description": "List of pipelines with number of streams for each.",
- "examples": [
- [
- {
- "id": "pipeline-1",
- "streams": 8
- },
- {
- "id": "pipeline-2",
- "streams": 8
- }
- ]
- ]
- },
- "video_output": {
- "$ref": "#/components/schemas/VideoOutputConfig",
- "description": "Video output configuration.",
- "default": {
- "enabled": false,
- "encoder_device": {
- "device_name": "GPU",
- "gpu_id": 0
- }
- },
- "examples": [
- {
- "enabled": false,
- "encoder_device": {
- "device_name": "GPU",
- "gpu_id": 0
- }
- }
- ]
- }
- },
- "type": "object",
- "required": [
- "pipeline_performance_specs"
- ],
- "title": "PerformanceTestSpec",
- "description": "Request body for starting a performance test.\n\nAttributes:\n pipeline_performance_specs: List of pipelines and their stream counts.\n video_output: Optional configuration for storing encoded video outputs."
- },
- "PerformanceTestSpec-Output": {
+ "PerformanceTestSpec": {
"properties": {
"pipeline_performance_specs": {
"items": {
@@ -2277,19 +2125,11 @@
"$ref": "#/components/schemas/VideoOutputConfig",
"description": "Video output configuration.",
"default": {
- "enabled": false,
- "encoder_device": {
- "device_name": "GPU",
- "gpu_id": 0
- }
+ "enabled": false
},
"examples": [
{
- "enabled": false,
- "encoder_device": {
- "device_name": "GPU",
- "gpu_id": 0
- }
+ "enabled": false
}
]
}
@@ -2955,25 +2795,11 @@
"title": "Enabled",
"description": "Flag to enable or disable video output generation.",
"default": false
- },
- "encoder_device": {
- "$ref": "#/components/schemas/EncoderDeviceConfig",
- "description": "Encoder device configuration (only applicable when video output is enabled).",
- "default": {
- "device_name": "GPU",
- "gpu_id": 0
- },
- "examples": [
- {
- "device_name": "GPU",
- "gpu_id": 0
- }
- ]
}
},
"type": "object",
"title": "VideoOutputConfig",
- "description": "Generic configuration of optional encoded video output.\n\nAttributes:\n enabled: Flag to enable or disable video output generation.\n encoder_device: EncoderDeviceConfig used when video output is enabled.\n\nExample:\n .. code-block:: json\n\n {\n \"enabled\": false,\n \"encoder_device\": {\n \"device_name\": \"GPU\",\n \"gpu_id\": 0\n }\n }"
+ "description": "Generic configuration of optional encoded video output.\n\nAttributes:\n enabled: Flag to enable or disable video output generation.\n\nExample:\n .. code-block:: json\n\n {\n \"enabled\": false\n }"
}
}
}
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/api/api.generated.ts b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/api/api.generated.ts
index 7d87cead7a..0e731e2d14 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/api/api.generated.ts
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/api/api.generated.ts
@@ -224,7 +224,7 @@ const injectedRtkApi = api
query: (queryArg) => ({
url: `/tests/performance`,
method: "POST",
- body: queryArg.performanceTestSpecInput,
+ body: queryArg.performanceTestSpec,
}),
invalidatesTags: ["tests"],
}),
@@ -235,7 +235,7 @@ const injectedRtkApi = api
query: (queryArg) => ({
url: `/tests/density`,
method: "POST",
- body: queryArg.densityTestSpecInput,
+ body: queryArg.densityTestSpec,
}),
invalidatesTags: ["tests"],
}),
@@ -365,12 +365,12 @@ export type OptimizePipelineApiArg = {
export type RunPerformanceTestApiResponse =
/** status 202 Performance test job created */ TestJobResponse;
export type RunPerformanceTestApiArg = {
- performanceTestSpecInput: PerformanceTestSpec2;
+ performanceTestSpec: PerformanceTestSpec;
};
export type RunDensityTestApiResponse =
/** status 202 Density test job created */ TestJobResponse;
export type RunDensityTestApiArg = {
- densityTestSpecInput: DensityTestSpec2;
+ densityTestSpec: DensityTestSpec;
};
export type GetVideosApiResponse =
/** status 200 Successful Response */ Video[];
@@ -439,17 +439,9 @@ export type PerformanceJobStatus = {
} | null;
error_message: string | null;
};
-export type EncoderDeviceConfig = {
- /** Name of the encoder device (e.g., 'GPU', 'CPU', 'NPU') */
- device_name?: string;
- /** GPU device index (only applicable when device_name indicates a GPU) */
- gpu_id?: number | null;
-};
export type VideoOutputConfig = {
/** Flag to enable or disable video output generation. */
enabled?: boolean;
- /** Encoder device configuration (only applicable when video output is enabled). */
- encoder_device?: EncoderDeviceConfig;
};
export type PerformanceTestSpec = {
/** List of pipelines with number of streams for each. */
@@ -607,20 +599,6 @@ export type TestJobResponse = {
/** Identifier of the created test job. */
job_id: string;
};
-export type PerformanceTestSpec2 = {
- /** List of pipelines with number of streams for each. */
- pipeline_performance_specs: PipelinePerformanceSpec[];
- /** Video output configuration. */
- video_output?: VideoOutputConfig;
-};
-export type DensityTestSpec2 = {
- /** Minimum acceptable FPS per stream. */
- fps_floor: number;
- /** List of pipelines with relative stream_rate percentages that must sum to 100. */
- pipeline_density_specs: PipelineDensitySpec[];
- /** Video output configuration. */
- video_output?: VideoOutputConfig;
-};
export type Video = {
filename: string;
width: number;
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/features/pipeline-tests/SaveOutputWarning.tsx b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/features/pipeline-tests/SaveOutputWarning.tsx
index 66458eb640..a94830d3e2 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/features/pipeline-tests/SaveOutputWarning.tsx
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/features/pipeline-tests/SaveOutputWarning.tsx
@@ -1,22 +1,8 @@
const SaveOutputWarning = () => {
return (
-
Note 1: The current implementation does not automatically infer the
- best encoding device from the existing pipeline. Select the same device
- that is already used by other blocks in your pipeline. To learn more,
- refer to our documentation:{" "}
-
- link
-
- .
-
-
Note 2: Selecting this option will negatively impact the
- performance results.
+
Note: Selecting this option will negatively impact the performance
+ results.
);
};
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/DensityTests.tsx b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/DensityTests.tsx
index fdb8c3ad01..8acc84b421 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/DensityTests.tsx
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/DensityTests.tsx
@@ -9,7 +9,6 @@ import { PipelineStreamsSummary } from "@/features/pipeline-tests/PipelineStream
import { PipelineName } from "@/features/pipelines/PipelineName.tsx";
import { useAppSelector } from "@/store/hooks";
import { selectPipelines } from "@/store/reducers/pipelines";
-import { selectDevices } from "@/store/reducers/devices";
import { Checkbox } from "@/components/ui/checkbox";
import {
Tooltip,
@@ -18,7 +17,6 @@ import {
} from "@/components/ui/tooltip";
import { Plus, X } from "lucide-react";
import { ParticipationSlider } from "@/features/pipeline-tests/ParticipationSlider.tsx";
-import DeviceSelect from "@/components/shared/DeviceSelect";
import SaveOutputWarning from "@/features/pipeline-tests/SaveOutputWarning.tsx";
interface PipelineSelection {
@@ -30,7 +28,6 @@ interface PipelineSelection {
const DensityTests = () => {
const pipelines = useAppSelector(selectPipelines);
- const devices = useAppSelector(selectDevices);
const [runDensityTest, { isLoading: isRunning }] =
useRunDensityTestMutation();
const [pipelineSelections, setPipelineSelections] = useState<
@@ -46,7 +43,6 @@ const DensityTests = () => {
} | null>(null);
const [videoOutputEnabled, setVideoOutputEnabled] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
- const [encoderDevice, setEncoderDevice] = useState("CPU");
const { data: jobStatus } = useGetDensityJobStatusQuery(
{ jobId: jobId! },
@@ -154,24 +150,10 @@ const DensityTests = () => {
setTestResult(null);
setErrorMessage(null);
try {
- const selectedDevice = devices.find(
- (d) => d.device_name === encoderDevice,
- );
-
const result = await runDensityTest({
- densityTestSpecInput: {
+ densityTestSpec: {
video_output: {
enabled: videoOutputEnabled,
- encoder_device:
- videoOutputEnabled && selectedDevice
- ? {
- device_name: selectedDevice.device_name,
- gpu_id:
- selectedDevice.device_family === "GPU"
- ? (selectedDevice.gpu_id ?? 0)
- : undefined,
- }
- : undefined,
},
fps_floor: fpsFloor,
pipeline_density_specs: pipelineSelections.map((selection) => ({
@@ -319,16 +301,6 @@ const DensityTests = () => {
- {videoOutputEnabled && (
-
- Select device for encoding:
-
-
- )}
{videoOutputEnabled && }
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/PerformanceTests.tsx b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/PerformanceTests.tsx
index 18decba423..dca520d2c5 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/PerformanceTests.tsx
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/PerformanceTests.tsx
@@ -7,7 +7,6 @@ import { TestProgressIndicator } from "@/features/pipeline-tests/TestProgressInd
import { PipelineName } from "@/features/pipelines/PipelineName.tsx";
import { useAppSelector } from "@/store/hooks";
import { selectPipelines } from "@/store/reducers/pipelines";
-import { selectDevices } from "@/store/reducers/devices";
import { Checkbox } from "@/components/ui/checkbox";
import {
Tooltip,
@@ -16,7 +15,6 @@ import {
} from "@/components/ui/tooltip";
import { Plus, X } from "lucide-react";
import { StreamsSlider } from "@/features/pipeline-tests/StreamsSlider.tsx";
-import DeviceSelect from "@/components/shared/DeviceSelect";
import SaveOutputWarning from "@/features/pipeline-tests/SaveOutputWarning.tsx";
interface PipelineSelection {
@@ -28,7 +26,6 @@ interface PipelineSelection {
const PerformanceTests = () => {
const pipelines = useAppSelector(selectPipelines);
- const devices = useAppSelector(selectDevices);
const [runPerformanceTest, { isLoading: isRunning }] =
useRunPerformanceTestMutation();
const [pipelineSelections, setPipelineSelections] = useState<
@@ -44,7 +41,6 @@ const PerformanceTests = () => {
} | null>(null);
const [videoOutputEnabled, setVideoOutputEnabled] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
- const [encoderDevice, setEncoderDevice] = useState("CPU");
const { data: jobStatus } = useGetPerformanceJobStatusQuery(
{ jobId: jobId! },
@@ -149,24 +145,10 @@ const PerformanceTests = () => {
setTestResult(null);
setErrorMessage(null);
try {
- const selectedDevice = devices.find(
- (d) => d.device_name === encoderDevice,
- );
-
const result = await runPerformanceTest({
- performanceTestSpecInput: {
+ performanceTestSpec: {
video_output: {
enabled: videoOutputEnabled,
- encoder_device:
- videoOutputEnabled && selectedDevice
- ? {
- device_name: selectedDevice.device_name,
- gpu_id:
- selectedDevice.device_family === "GPU"
- ? (selectedDevice.gpu_id ?? 0)
- : undefined,
- }
- : undefined,
},
pipeline_performance_specs: pipelineSelections.map((selection) => ({
id: selection.pipelineId,
@@ -297,16 +279,6 @@ const PerformanceTests = () => {
- {videoOutputEnabled && (
-
- Select device for encoding:
-
-
- )}
{videoOutputEnabled && }
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/Pipelines.tsx b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/Pipelines.tsx
index be4d2e2f53..510bb8f72c 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/Pipelines.tsx
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/ui/src/pages/Pipelines.tsx
@@ -24,7 +24,6 @@ import StopPerformanceTestButton from "@/features/pipeline-editor/StopPerformanc
import ExportPipelineButton from "@/features/pipeline-editor/ExportPipelineButton.tsx";
import DeletePipelineButton from "@/features/pipeline-editor/DeletePipelineButton.tsx";
import ImportPipelineButton from "@/features/pipeline-editor/ImportPipelineButton.tsx";
-import DeviceSelect from "@/components/shared/DeviceSelect";
import { Zap } from "lucide-react";
import { isApiError } from "@/lib/apiUtils";
import {
@@ -33,8 +32,6 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Checkbox } from "@/components/ui/checkbox";
-import { useAppSelector } from "@/store/hooks";
-import { selectDevices } from "@/store/reducers/devices";
type UrlParams = {
id: string;
@@ -42,7 +39,6 @@ type UrlParams = {
const Pipelines = () => {
const { id } = useParams();
- const devices = useAppSelector(selectDevices);
const [performanceTestJobId, setPerformanceTestJobId] = useState<
string | null
>(null);
@@ -56,7 +52,6 @@ const Pipelines = () => {
const [editorKey, setEditorKey] = useState(0);
const [shouldFitView, setShouldFitView] = useState(false);
const [videoOutputEnabled, setVideoOutputEnabled] = useState(true);
- const [encoderDevice, setEncoderDevice] = useState("CPU");
const [completedVideoPath, setCompletedVideoPath] = useState(
null,
);
@@ -396,24 +391,10 @@ const Pipelines = () => {
},
}).unwrap();
- const selectedDevice = devices.find(
- (d) => d.device_name === encoderDevice,
- );
-
const response = await runPerformanceTest({
- performanceTestSpecInput: {
+ performanceTestSpec: {
video_output: {
enabled: videoOutputEnabled,
- encoder_device:
- videoOutputEnabled && selectedDevice
- ? {
- device_name: selectedDevice.device_name,
- gpu_id:
- selectedDevice.device_family === "GPU"
- ? (selectedDevice.gpu_id ?? 0)
- : undefined,
- }
- : undefined,
},
pipeline_performance_specs: [
{
@@ -617,31 +598,7 @@ const Pipelines = () => {
- {videoOutputEnabled && (
-
- )}
- {videoOutputEnabled && (
-
-
Note: The current implementation does not automatically
- infer the best encoding device from the existing pipeline. Select
- the same device that is already used by other blocks in your
- pipeline. To learn more, refer to our documentation:{" "}
-
- link
-
- .
-
- )}
);
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/api/api_schemas.py b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/api/api_schemas.py
index f23d282844..aef115927a 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/api/api_schemas.py
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/api/api_schemas.py
@@ -528,63 +528,24 @@ class PipelineRequestOptimize(BaseModel):
parameters: Optional[Dict[str, Any]]
-class EncoderDeviceConfig(BaseModel):
- """
- Encoder device configuration used in video output settings.
-
- Attributes:
- device_name: Name of the encoder device (for example ``"GPU"``).
- gpu_id: Optional GPU index when applicable.
-
- Example:
- .. code-block:: json
-
- {
- "device_name": "GPU",
- "gpu_id": 0
- }
- """
-
- device_name: str = Field(
- default="GPU",
- description="Name of the encoder device (e.g., 'GPU', 'CPU', 'NPU')",
- examples=["GPU", "CPU", "NPU"],
- )
- gpu_id: Optional[int] = Field(
- default=None,
- description="GPU device index (only applicable when device_name indicates a GPU)",
- examples=[0, 1],
- )
-
-
class VideoOutputConfig(BaseModel):
"""
Generic configuration of optional encoded video output.
Attributes:
enabled: Flag to enable or disable video output generation.
- encoder_device: EncoderDeviceConfig used when video output is enabled.
Example:
.. code-block:: json
{
- "enabled": false,
- "encoder_device": {
- "device_name": "GPU",
- "gpu_id": 0
- }
+ "enabled": false
}
"""
enabled: bool = Field(
default=False, description="Flag to enable or disable video output generation."
)
- encoder_device: EncoderDeviceConfig = Field(
- default=EncoderDeviceConfig(device_name="GPU", gpu_id=0),
- description="Encoder device configuration (only applicable when video output is enabled).",
- examples=[{"device_name": "GPU", "gpu_id": 0}],
- )
class PerformanceTestSpec(BaseModel):
@@ -609,12 +570,9 @@ class PerformanceTestSpec(BaseModel):
video_output: VideoOutputConfig = Field(
default=VideoOutputConfig(
enabled=False,
- encoder_device=EncoderDeviceConfig(device_name="GPU", gpu_id=0),
),
description="Video output configuration.",
- examples=[
- {"enabled": False, "encoder_device": {"device_name": "GPU", "gpu_id": 0}}
- ],
+ examples=[{"enabled": False}],
)
@@ -646,12 +604,9 @@ class DensityTestSpec(BaseModel):
video_output: VideoOutputConfig = Field(
default=VideoOutputConfig(
enabled=False,
- encoder_device=EncoderDeviceConfig(device_name="GPU", gpu_id=0),
),
description="Video output configuration.",
- examples=[
- {"enabled": False, "encoder_device": {"device_name": "GPU", "gpu_id": 0}}
- ],
+ examples=[{"enabled": False}],
)
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/api/routes/tests.py b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/api/routes/tests.py
index beebf0b2ea..b616e1741b 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/api/routes/tests.py
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/api/routes/tests.py
@@ -47,7 +47,7 @@ def run_performance_test(body: schemas.PerformanceTestSpec):
* pipeline_performance_specs – list of pipelines and number of
streams per pipeline.
* video_output – configuration for optional encoded video output
- (enabled flag and encoder_device).
+ (enabled flag).
Returns:
202 Accepted:
@@ -78,8 +78,7 @@ def run_performance_test(body: schemas.PerformanceTestSpec):
{"id": "pipeline-b7c2e114", "streams": 4}
],
"video_output": {
- "enabled": false,
- "encoder_device": {"device_name": "GPU", "gpu_id": 0}
+ "enabled": false
}
}
@@ -186,8 +185,7 @@ def run_density_test(body: schemas.DensityTestSpec):
{"id": "pipeline-b7c2e114", "stream_rate": 50}
],
"video_output": {
- "enabled": false,
- "encoder_device": {"device_name": "GPU", "gpu_id": 0}
+ "enabled": false
}
}
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/graph.py b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/graph.py
index d599551843..fbb6c775bb 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/graph.py
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/graph.py
@@ -10,6 +10,7 @@
from utils import generate_unique_filename
from videos import get_videos_manager, OUTPUT_VIDEO_DIR
from models import get_supported_models_manager
+from video_encoder import ENCODER_DEVICE_CPU, ENCODER_DEVICE_GPU
from resources import (
get_labels_manager,
get_scripts_manager,
@@ -392,6 +393,29 @@ def get_input_video_filenames(self) -> list[str]:
return input_filenames
+ def get_recommended_encoder_device(self) -> str:
+ """
+ Iterate backwards through nodes to find the last video/x-raw node
+ and return the recommended encoder device based on memory type.
+
+ Note: NPU variants are not considered because NPUs do not provide dedicated
+ memory accessible for GStreamer pipeline buffering; they operate exclusively
+ on system or shared memory.
+
+ Returns:
+ str: ENCODER_DEVICE_GPU if video/x-raw(memory:VAMemory) is detected,
+ ENCODER_DEVICE_CPU for standard video/x-raw or when no video/x-raw
+ node exists in the pipeline.
+ """
+ for node in reversed(self.nodes):
+ if not node.type.startswith("video/x-raw"):
+ continue
+ if "memory:VAMemory" in node.type:
+ return ENCODER_DEVICE_GPU
+ return ENCODER_DEVICE_CPU
+
+ return ENCODER_DEVICE_CPU
+
def to_simple_view(self) -> "Graph":
"""
Generate a simplified view of the pipeline graph by filtering out technical elements.
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/managers/pipeline_manager.py b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/managers/pipeline_manager.py
index 7294da5b19..9a60d76ee9 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/managers/pipeline_manager.py
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/managers/pipeline_manager.py
@@ -299,11 +299,14 @@ def build_pipeline_command(
# Handle final video output if enabled
if video_config.enabled and stream_index == 0:
+ # Get recommended encoder device from the graph
+ encoder_device = graph.get_recommended_encoder_device()
+ # Replace fakesink with actual video output element
unique_pipeline_str, generated_paths = (
self.video_encoder.replace_fakesink_with_video_output(
pipeline.id,
unique_pipeline_str,
- video_config.encoder_device,
+ encoder_device,
input_video_filenames,
)
)
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/api_tests/tests_test.py b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/api_tests/tests_test.py
index 55b40fd7b9..8c4b3e3db4 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/api_tests/tests_test.py
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/api_tests/tests_test.py
@@ -200,8 +200,6 @@ def test_run_performance_test_with_gpu_encoder(self, mock_test_manager):
# Verify video output configuration
self.assertTrue(call_args.video_output.enabled)
- self.assertEqual(call_args.video_output.encoder_device.device_name, "GPU")
- self.assertEqual(call_args.video_output.encoder_device.gpu_id, 0)
# ------------------------------------------------------------------
# /tests/density
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/graph_test.py b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/graph_test.py
index 8fb141db14..82cf6d90f1 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/graph_test.py
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/graph_test.py
@@ -3,6 +3,7 @@
from dataclasses import dataclass
from unittest.mock import MagicMock, patch
from graph import Graph, Node, Edge
+from video_encoder import ENCODER_DEVICE_GPU, ENCODER_DEVICE_CPU
mock_models_manager = MagicMock()
mock_videos_manager = MagicMock()
@@ -2171,6 +2172,134 @@ def test_empty_graph_raises_error(self):
self.assertIn("Empty graph", str(cm.exception))
+class TestGetRecommendedEncoderDevice(unittest.TestCase):
+ """Test cases for Graph.get_recommended_encoder_device method."""
+
+ def test_gpu_encoder_for_va_memory_caps(self):
+ """Test that GPU encoder is recommended when video/x-raw(memory:VAMemory) is found."""
+ graph = Graph(
+ nodes=[
+ Node(id="0", type="filesrc", data={"location": "test.mp4"}),
+ Node(id="1", type="decodebin3", data={}),
+ Node(
+ id="2",
+ type="video/x-raw(memory:VAMemory)",
+ data={"__node_kind": "caps"},
+ ),
+ Node(id="3", type="fakesink", data={}),
+ ],
+ edges=[
+ Edge(id="0", source="0", target="1"),
+ Edge(id="1", source="1", target="2"),
+ Edge(id="2", source="2", target="3"),
+ ],
+ )
+
+ self.assertEqual(graph.get_recommended_encoder_device(), ENCODER_DEVICE_GPU)
+
+ def test_cpu_encoder_for_standard_video_raw(self):
+ """Test that CPU encoder is recommended for standard video/x-raw caps."""
+ graph = Graph(
+ nodes=[
+ Node(id="0", type="filesrc", data={"location": "test.mp4"}),
+ Node(id="1", type="decodebin3", data={}),
+ Node(
+ id="2",
+ type="video/x-raw",
+ data={"__node_kind": "caps", "width": "640", "height": "480"},
+ ),
+ Node(id="3", type="fakesink", data={}),
+ ],
+ edges=[
+ Edge(id="0", source="0", target="1"),
+ Edge(id="1", source="1", target="2"),
+ Edge(id="2", source="2", target="3"),
+ ],
+ )
+
+ self.assertEqual(graph.get_recommended_encoder_device(), ENCODER_DEVICE_CPU)
+
+ def test_cpu_encoder_when_no_video_raw_caps(self):
+ """Test that CPU encoder is recommended when no video/x-raw caps exist."""
+ graph = Graph(
+ nodes=[
+ Node(id="0", type="filesrc", data={"location": "test.mp4"}),
+ Node(id="1", type="decodebin3", data={}),
+ Node(id="2", type="queue", data={}),
+ Node(id="3", type="fakesink", data={}),
+ ],
+ edges=[
+ Edge(id="0", source="0", target="1"),
+ Edge(id="1", source="1", target="2"),
+ Edge(id="2", source="2", target="3"),
+ ],
+ )
+
+ self.assertEqual(graph.get_recommended_encoder_device(), ENCODER_DEVICE_CPU)
+
+ def test_uses_last_video_raw_caps_when_multiple_exist(self):
+ """Test that the method uses the last video/x-raw caps in the pipeline."""
+ graph = Graph(
+ nodes=[
+ Node(id="0", type="filesrc", data={"location": "test.mp4"}),
+ Node(
+ id="1",
+ type="video/x-raw",
+ data={"__node_kind": "caps", "width": "640"},
+ ),
+ Node(id="2", type="queue", data={}),
+ Node(
+ id="3",
+ type="video/x-raw(memory:VAMemory)",
+ data={"__node_kind": "caps"},
+ ),
+ Node(id="4", type="fakesink", data={}),
+ ],
+ edges=[
+ Edge(id="0", source="0", target="1"),
+ Edge(id="1", source="1", target="2"),
+ Edge(id="2", source="2", target="3"),
+ Edge(id="3", source="3", target="4"),
+ ],
+ )
+
+ # Should return GPU because the last video/x-raw has VAMemory
+ self.assertEqual(graph.get_recommended_encoder_device(), ENCODER_DEVICE_GPU)
+
+ def test_iterates_backwards_through_nodes(self):
+ """Test that the method iterates backwards (uses last occurrence, not first)."""
+ graph = Graph(
+ nodes=[
+ Node(id="0", type="filesrc", data={"location": "test.mp4"}),
+ Node(
+ id="1",
+ type="video/x-raw(memory:VAMemory)",
+ data={"__node_kind": "caps"},
+ ),
+ Node(id="2", type="queue", data={}),
+ Node(
+ id="3", type="video/x-raw", data={"__node_kind": "caps"}
+ ), # Last one, no VAMemory
+ Node(id="4", type="fakesink", data={}),
+ ],
+ edges=[
+ Edge(id="0", source="0", target="1"),
+ Edge(id="1", source="1", target="2"),
+ Edge(id="2", source="2", target="3"),
+ Edge(id="3", source="3", target="4"),
+ ],
+ )
+
+ # Should return CPU because iterating backwards finds node 3 first (no VAMemory)
+ self.assertEqual(graph.get_recommended_encoder_device(), ENCODER_DEVICE_CPU)
+
+ def test_empty_graph(self):
+ """Test that CPU encoder is recommended for an empty graph."""
+ graph = Graph(nodes=[], edges=[])
+
+ self.assertEqual(graph.get_recommended_encoder_device(), ENCODER_DEVICE_CPU)
+
+
class TestToSimpleView(unittest.TestCase):
"""
Test the to_simple_view method which generates simplified graphs
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/managers_tests/pipeline_manager_test.py b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/managers_tests/pipeline_manager_test.py
index dd2371b96e..40d13e64a3 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/managers_tests/pipeline_manager_test.py
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/managers_tests/pipeline_manager_test.py
@@ -5,7 +5,6 @@
from api.api_schemas import (
Node,
Edge,
- EncoderDeviceConfig,
PipelineType,
PipelineSource,
PipelineGraph,
@@ -458,7 +457,6 @@ def test_build_pipeline_command_with_video_output_enabled(self):
pipeline_performance_specs = [PipelinePerformanceSpec(id=added.id, streams=1)]
video_config = VideoOutputConfig(
enabled=True,
- encoder_device=EncoderDeviceConfig(device_name="CPU", gpu_id=None),
)
command, output_paths = manager.build_pipeline_command(
@@ -497,7 +495,6 @@ def test_build_pipeline_command_with_gpu_encoder(self):
pipeline_performance_specs = [PipelinePerformanceSpec(id=added.id, streams=2)]
video_config = VideoOutputConfig(
enabled=True,
- encoder_device=EncoderDeviceConfig(device_name="GPU", gpu_id=0),
)
command, output_paths = manager.build_pipeline_command(
@@ -544,7 +541,6 @@ def test_build_pipeline_command_video_output_multiple_pipelines(self):
]
video_config = VideoOutputConfig(
enabled=True,
- encoder_device=EncoderDeviceConfig(device_name="CPU", gpu_id=None),
)
command, output_paths = manager.build_pipeline_command(
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/video_encoder_test.py b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/video_encoder_test.py
index b1b108b286..e81fe9348d 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/video_encoder_test.py
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/tests/video_encoder_test.py
@@ -3,10 +3,9 @@
from video_encoder import (
VideoEncoder,
- GPU_0,
- OTHER,
+ ENCODER_DEVICE_CPU,
+ ENCODER_DEVICE_GPU,
)
-from api.api_schemas import EncoderDeviceConfig
class TestVideoEncoderClass(unittest.TestCase):
@@ -27,56 +26,19 @@ def test_initialization(self, mock_gst_inspector):
self.assertIn("h264", encoder.encoder_configs)
mock_gst_inspector.assert_called_once()
- def test_select_gpu_single_gpu(self):
- """Test GPU device without index."""
- gpu_id, vaapi_suffix = self.encoder.select_gpu("GPU")
- self.assertEqual(gpu_id, 0)
- self.assertIsNone(vaapi_suffix)
-
- def test_select_gpu_first_with_index(self):
- """Test GPU.0 device."""
- gpu_id, vaapi_suffix = self.encoder.select_gpu("GPU.0")
- self.assertEqual(gpu_id, 0)
- self.assertIsNone(vaapi_suffix)
-
- def test_select_gpu_second_gpu(self):
- """Test GPU.1 device with vaapi suffix."""
- gpu_id, vaapi_suffix = self.encoder.select_gpu("GPU.1")
- self.assertEqual(gpu_id, 1)
- self.assertEqual(vaapi_suffix, "129")
-
- def test_select_gpu_cpu_device(self):
- """Test non-GPU device (CPU)."""
- gpu_id, vaapi_suffix = self.encoder.select_gpu("CPU")
- self.assertEqual(gpu_id, -1)
- self.assertIsNone(vaapi_suffix)
-
def test_select_element_gpu_0(self):
"""Test selecting encoder for GPU 0."""
self.encoder.gst_inspector.elements = [("elem1", "vah264enc")]
- encoder_device = EncoderDeviceConfig(device_name="GPU", gpu_id=0)
+ encoder_device = ENCODER_DEVICE_GPU
encoder_dict = {
- GPU_0: [("vah264enc", "vah264enc")],
- OTHER: [("x264enc", "x264enc")],
+ ENCODER_DEVICE_GPU: [("vah264enc", "vah264enc")],
+ ENCODER_DEVICE_CPU: [("x264enc", "x264enc")],
}
- result = self.encoder.select_element(encoder_dict, encoder_device, None)
+ result = self.encoder.select_element(encoder_dict, encoder_device)
self.assertEqual(result, "vah264enc")
- def test_select_element_fallback_to_cpu(self):
- """Test fallback to CPU encoder when GPU encoder not available."""
- self.encoder.gst_inspector.elements = [("elem1", "x264enc")]
-
- encoder_device = EncoderDeviceConfig(device_name="GPU", gpu_id=0)
- encoder_dict = {
- GPU_0: [("vah264enc", "vah264enc")],
- OTHER: [("x264enc", "x264enc bitrate=16000")],
- }
-
- result = self.encoder.select_element(encoder_dict, encoder_device, None)
- self.assertEqual(result, "x264enc bitrate=16000")
-
@patch("video_encoder.videos_manager")
def test_detect_codec_from_input(self, mock_videos_manager):
"""Test codec detection from input videos."""
@@ -123,7 +85,7 @@ def test_replace_fakesink_with_video_output(self, mock_videos_manager):
mock_videos_manager.get_video = Mock(return_value=mock_video)
pipeline_str = "videotestsrc ! fakesink"
- encoder_device = EncoderDeviceConfig(device_name="GPU", gpu_id=0)
+ encoder_device = ENCODER_DEVICE_GPU
pipeline_id = "test-pipeline-123"
result, output_paths = self.encoder.replace_fakesink_with_video_output(
@@ -148,7 +110,7 @@ def test_replace_fakesink_with_h265_codec(self, mock_videos_manager):
mock_videos_manager.get_video = Mock(return_value=mock_video)
pipeline_str = "videotestsrc ! fakesink"
- encoder_device = EncoderDeviceConfig(device_name="GPU", gpu_id=0)
+ encoder_device = ENCODER_DEVICE_GPU
pipeline_id = "test-pipeline-456"
result, output_paths = self.encoder.replace_fakesink_with_video_output(
@@ -170,7 +132,7 @@ def test_replace_multiple_fakesinks(self, mock_videos_manager):
pipeline_str = (
"videotestsrc ! tee name=t t. ! queue ! fakesink t. ! queue ! fakesink"
)
- encoder_device = EncoderDeviceConfig(device_name="GPU", gpu_id=0)
+ encoder_device = ENCODER_DEVICE_GPU
pipeline_id = "test-pipeline-789"
result, output_paths = self.encoder.replace_fakesink_with_video_output(
@@ -196,7 +158,7 @@ def test_replace_multiple_fakesinks(self, mock_videos_manager):
@patch("video_encoder.videos_manager")
def test_replace_fakesink_unsupported_codec(self, mock_videos_manager):
"""Test that unsupported codec raises ValueError."""
- encoder_device = EncoderDeviceConfig(device_name="GPU", gpu_id=0)
+ encoder_device = ENCODER_DEVICE_GPU
mock_video = Mock()
mock_video.codec = "av1" # Unsupported codec
@@ -221,7 +183,7 @@ def test_replace_fakesink_no_encoder_found(self, mock_videos_manager):
mock_video.codec = "h264"
mock_videos_manager.get_video = Mock(return_value=mock_video)
- encoder_device = EncoderDeviceConfig(device_name="GPU", gpu_id=0)
+ encoder_device = ENCODER_DEVICE_GPU
with self.assertRaises(ValueError) as context:
self.encoder.replace_fakesink_with_video_output(
diff --git a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/video_encoder.py b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/video_encoder.py
index 7381a511b1..45749ac367 100644
--- a/tools/visual-pipeline-and-platform-evaluation-tool/vippet/video_encoder.py
+++ b/tools/visual-pipeline-and-platform-evaluation-tool/vippet/video_encoder.py
@@ -4,14 +4,12 @@
from typing import Dict, List, Optional, Tuple
from explore import GstInspector
-from api.api_schemas import EncoderDeviceConfig
from utils import generate_unique_filename
from videos import get_videos_manager, OUTPUT_VIDEO_DIR
-# Keys for device selection
-GPU_0 = "GPU_0"
-GPU_N = "GPU_N"
-OTHER = "OTHER"
+# Constants for encoder device types
+ENCODER_DEVICE_CPU = "CPU"
+ENCODER_DEVICE_GPU = "GPU"
# Default codec for encoding
DEFAULT_CODEC = "h264"
@@ -60,130 +58,69 @@ def __init__(self):
# Define encoder configurations for different codecs
self.encoder_configs = {
"h264": {
- GPU_0: [
+ ENCODER_DEVICE_GPU: [
("vah264lpenc", "vah264lpenc"),
("vah264enc", "vah264enc"),
],
- GPU_N: [
- (
- f"varenderD{VAAPI_SUFFIX_PLACEHOLDER}h264lpenc",
- f"varenderD{VAAPI_SUFFIX_PLACEHOLDER}h264lpenc",
- ),
- (
- f"varenderD{VAAPI_SUFFIX_PLACEHOLDER}h264enc",
- f"varenderD{VAAPI_SUFFIX_PLACEHOLDER}h264enc",
- ),
- ],
- OTHER: [
+ ENCODER_DEVICE_CPU: [
("x264enc", "x264enc bitrate=16000 speed-preset=superfast"),
],
},
"h265": {
- GPU_0: [
+ ENCODER_DEVICE_GPU: [
("vah265lpenc", "vah265lpenc"),
("vah265enc", "vah265enc"),
],
- GPU_N: [
- (
- f"varenderD{VAAPI_SUFFIX_PLACEHOLDER}h265lpenc",
- f"varenderD{VAAPI_SUFFIX_PLACEHOLDER}h265lpenc",
- ),
- (
- f"varenderD{VAAPI_SUFFIX_PLACEHOLDER}h265enc",
- f"varenderD{VAAPI_SUFFIX_PLACEHOLDER}h265enc",
- ),
- ],
- OTHER: [
+ ENCODER_DEVICE_CPU: [
("x265enc", "x265enc bitrate=16000 speed-preset=superfast"),
],
},
}
- def select_gpu(self, device: str | None) -> Tuple[int, Optional[str]]:
- """
- Parse device name and determine GPU ID and VAAPI suffix.
-
- Args:
- device: Device name (e.g., "GPU", "GPU.0", "GPU.1", "CPU")
-
- Returns:
- Tuple of (gpu_id, vaapi_suffix)
- - gpu_id: 0 for first GPU, >0 for other GPUs, -1 for non-GPU
- - vaapi_suffix: VAAPI device suffix for multi-GPU systems
- """
- gpu_id = -1
- vaapi_suffix = None
-
- # Determine gpu_id and vaapi_suffix
- # If there is only one GPU, device name is just GPU
- # If there is more than one GPU, device names are like GPU.0, GPU.1, ...
- if device == "GPU":
- gpu_id = 0
- elif device is not None and device.startswith("GPU."):
- try:
- gpu_index = int(device.split(".")[1])
- if gpu_index == 0:
- gpu_id = 0
- elif gpu_index > 0:
- vaapi_suffix = str(128 + gpu_index)
- gpu_id = gpu_index
- except (IndexError, ValueError):
- self.logger.warning(f"Failed to parse GPU index from device: {device}")
- gpu_id = -1
- else:
- gpu_id = -1
-
- return gpu_id, vaapi_suffix
-
def select_element(
self,
field_dict: Dict[str, List[Tuple[str, str]]],
- encoder_device: EncoderDeviceConfig,
- vaapi_suffix: Optional[str],
+ encoder_device: str,
) -> Optional[str]:
"""
Select an appropriate encoder element from available GStreamer elements.
Args:
field_dict: Dictionary mapping device types to lists of (search, result) tuples
- encoder_device: Encoder device configuration
- vaapi_suffix: VAAPI device suffix for multi-GPU systems
+ encoder_device: Target encoder device. Must be one of the module constants:
+ - ENCODER_DEVICE_CPU ("CPU"): Use CPU-based encoder
+ - ENCODER_DEVICE_GPU ("GPU"): Use GPU-based encoder (VAAPI)
Returns:
Selected encoder element string with properties, or None if not found
+
+ Raises:
+ ValueError: If encoder_device is not a valid constant value
"""
- key = OTHER
- if encoder_device.device_name.startswith("GPU"):
- if encoder_device.gpu_id == 0:
- key = GPU_0
- elif encoder_device.gpu_id is not None and encoder_device.gpu_id > 0:
- key = GPU_N
-
- pairs = field_dict.get(key, [])
- # Add OTHER pairs as fallback if key is not OTHER
- if key != OTHER:
- pairs = pairs + field_dict.get(OTHER, [])
+ # Validate encoder_device
+ valid_devices = {ENCODER_DEVICE_CPU, ENCODER_DEVICE_GPU}
+ if encoder_device not in valid_devices:
+ raise ValueError(
+ f"Invalid encoder_device: {encoder_device}. "
+ f"Must be one of: {', '.join(valid_devices)}"
+ )
+
+ pairs = field_dict.get(encoder_device, [])
if not pairs:
- self.logger.warning(f"No encoder pairs found for key: {key}")
+ self.logger.warning(
+ f"No encoder pairs found for encoder_device: {encoder_device}"
+ )
return None
for search, result in pairs:
- if search == "": # to support optional parameters
- return result
-
- if VAAPI_SUFFIX_PLACEHOLDER in search or VAAPI_SUFFIX_PLACEHOLDER in result:
- suffix = vaapi_suffix if vaapi_suffix is not None else ""
- search = search.replace(VAAPI_SUFFIX_PLACEHOLDER, suffix)
- result = result.replace(VAAPI_SUFFIX_PLACEHOLDER, suffix)
-
for element in self.gst_inspector.elements:
if element[1] == search:
self.logger.debug(f"Selected encoder element: {result}")
return result
self.logger.warning(
- f"No matching encoder element found for device: {encoder_device.device_name}"
+ f"No matching encoder element found for encoder_device: {encoder_device}"
)
return None
@@ -230,7 +167,7 @@ def replace_fakesink_with_video_output(
self,
pipeline_id: str,
pipeline_str: str,
- encoder_device: EncoderDeviceConfig,
+ encoder_device: str,
input_video_filenames: list[str],
) -> Tuple[str, List[str]]:
"""
@@ -239,33 +176,38 @@ def replace_fakesink_with_video_output(
Args:
pipeline_id: Pipeline ID used to generate unique output filenames
pipeline_str: GStreamer pipeline string containing fakesink(s)
- encoder_device: Encoder device configuration
+ encoder_device: Target encoder device. Must be one of the module constants:
+ - ENCODER_DEVICE_CPU ("CPU"): Use CPU-based encoder
+ - ENCODER_DEVICE_GPU ("GPU"): Use GPU-based encoder (VAAPI)
input_video_filenames: List of input video filenames to detect codec
Returns:
Tuple of (modified pipeline string, list of output paths)
Raises:
- ValueError: If codec is not supported or no suitable encoder is found
+ ValueError: If codec is not supported, encoder_device is invalid,
+ or no suitable encoder is found
"""
+ # Detect codec from input video files (h264, h265, etc.)
codec = self._detect_codec_from_input(input_video_filenames)
self._validate_codec(codec)
+ # Get encoder configuration for the detected codec (GPU/CPU variants)
encoder_config = self.encoder_configs[codec]
- gpu_id, vaapi_suffix = self.select_gpu(encoder_device.device_name)
+ # Select the best available encoder element based on device type and
+ # installed GStreamer plugins (e.g., vah264enc for GPU, x264enc for CPU)
encoder_element = self.select_element(
encoder_config,
encoder_device,
- vaapi_suffix,
)
if encoder_element is None:
self.logger.error(
- f"Failed to select encoder element for device: {encoder_device.device_name}"
+ f"Failed to select encoder element for codec: {codec} and encoder_device: {encoder_device}"
)
raise ValueError(
- f"No suitable encoder found for device: {encoder_device.device_name}"
+ f"No suitable encoder found for codec: {codec} and encoder_device: {encoder_device}"
)
# Count fakesink instances