├── multi_src ├── CMakeLists.txt ├── blocking_queue.h ├── main.cpp └── decode_vpp.h ├── single_src ├── CMakeLists.txt └── main.cpp ├── content └── cars_320x240.h265 ├── test.py ├── docker └── Dockerfile ├── CMakeLists.txt ├── README.md └── utils ├── functions.h └── util.h /multi_src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_demo(NAME multi_source 2 | SRC multi_src) 3 | -------------------------------------------------------------------------------- /single_src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_demo(NAME single_source 2 | SRC single_src) -------------------------------------------------------------------------------- /content/cars_320x240.h265: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openvino-dev-samples/decode-infer-on-GPU/HEAD/content/cars_320x240.h265 -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import time 4 | from openvino.runtime import Core 5 | 6 | capture = cv2.VideoCapture('/home/ethan/Downloads/sample_2560x1440.h265') 7 | ie = Core() 8 | model = ie.read_model(model="/home/ethan/oneVPL/examples/interop/advanced-decvpp-infer/intel/vehicle-detection-0200/FP16/vehicle-detection-0200.xml") 9 | compiled_model = ie.compile_model(model=model, device_name="GPU") 10 | input_layer = compiled_model.input(0) 11 | N, C, H, W = input_layer.shape 12 | request = compiled_model.create_infer_request() 13 | start = time.time() 14 | while True: 15 | isTrue, frame = capture.read() 16 | if isTrue: 17 | resized_image = cv2.resize(src=frame, dsize=(W,H)) 18 | input_data = np.expand_dims(np.transpose(resized_image, (2, 0, 1)), 0).astype(np.float32) 19 | request.infer(inputs={input_layer.any_name: input_data}) 20 | else: 21 | break 22 | end = time.time() 23 | time_spend = end - start 24 | print(time_spend) 25 | capture.release() 26 | 27 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openvino/ubuntu20_runtime:latest 2 | USER root 3 | ARG DEBIAN_FRONTEND=noninteractive 4 | ENV TZ=America/Los_Angeles 5 | 6 | # install environment package prerequisites 7 | RUN apt update && \ 8 | apt install --no-install-recommends -q -y software-properties-common gnupg wget sudo unzip libnss3-tools ncurses-term python3-pip 9 | 10 | 11 | 12 | # Install Intel graphics stack packages from Agama 13 | RUN wget https://repositories.intel.com/graphics/intel-graphics.key && \ 14 | apt-key add intel-graphics.key && \ 15 | apt-add-repository 'deb [arch=amd64] https://repositories.intel.com/graphics/ubuntu focal main' && \ 16 | apt update && \ 17 | apt install -y libmfx1 libmfxgen1 vainfo intel-opencl-icd intel-level-zero-gpu level-zero intel-media-va-driver-non-free python3.9 18 | 19 | # Dev packages (optional for run-only environments) 20 | RUN apt install -y cmake build-essential libva-dev libdrm-dev net-tools pkg-config libigc-dev intel-igc-cm libigdfcl-dev libigfxcmrt-dev level-zero-dev opencl-headers build-essential 21 | 22 | #Install oneVPL devkit package from oneAPI 23 | RUN wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB && \ 24 | apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB && \ 25 | echo "deb https://apt.repos.intel.com/oneapi all main" | tee /etc/apt/sources.list.d/oneAPI.list && \ 26 | apt update && apt install -y intel-oneapi-onevpl-devel 27 | -------------------------------------------------------------------------------- /multi_src/blocking_queue.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2022 Intel Corporation 3 | * 4 | * SPDX-License-Identifier: MIT 5 | ******************************************************************************/ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace multi_source { 14 | template 15 | class BlockingQueue { 16 | public: 17 | void push(T const& value, size_t queue_limit = 0) { 18 | std::unique_lock lock(_mutex); 19 | if (queue_limit > 0) { 20 | while (_queue.size() >= queue_limit) { 21 | _pop_condition.wait(lock); 22 | } 23 | } 24 | _queue.push_front(value); 25 | _push_condition.notify_one(); 26 | } 27 | 28 | T pop() { 29 | std::unique_lock lock(_mutex); 30 | _push_condition.wait(lock, [=] { return !_queue.empty(); }); 31 | T value(std::move(_queue.back())); 32 | _queue.pop_back(); 33 | _pop_condition.notify_one(); 34 | return value; 35 | } 36 | 37 | void clear() { 38 | _queue.clear(); 39 | _pop_condition.notify_one(); 40 | } 41 | 42 | size_t size() { 43 | return _queue.size(); 44 | } 45 | 46 | private: 47 | std::deque _queue; 48 | std::mutex _mutex; 49 | std::condition_variable _push_condition; 50 | std::condition_variable _pop_condition; 51 | }; 52 | } // namespace multi_source -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ############################################################################## 2 | # Copyright (C) Intel Corporation 3 | # 4 | # SPDX-License-Identifier: MIT 5 | # ############################################################################## 6 | cmake_minimum_required(VERSION 3.10.2) 7 | project(vpl_demo) 8 | set(CMAKE_CXX_STANDARD 11) 9 | set(CMAKE_CXX_FLAGS -pthread) 10 | # Default install places 64 bit runtimes in the environment, so we want to do a 11 | # 64 bit build by default. 12 | if(WIN32) 13 | message(FATAL_ERROR "Windows not supported by this sample.") 14 | endif() 15 | 16 | find_package(PkgConfig REQUIRED) 17 | include(CMakeParseArguments) 18 | 19 | macro(add_demo) 20 | set(oneValueArgs NAME SRC) 21 | cmake_parse_arguments(VPL_DEMO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 22 | set(SOURCES main.cpp) 23 | message("-- demo name = ${VPL_DEMO_NAME}") 24 | # Set default build type to RelWithDebInfo if not specified 25 | if(NOT CMAKE_BUILD_TYPE) 26 | message( 27 | STATUS "Default CMAKE_BUILD_TYPE not set using Release with Debug Info") 28 | set(CMAKE_BUILD_TYPE 29 | "RelWithDebInfo" 30 | CACHE 31 | STRING 32 | "Choose build type from: None Debug Release RelWithDebInfo MinSizeRel" 33 | FORCE) 34 | endif() 35 | aux_source_directory(${VPL_DEMO_SRC} SRC) 36 | add_executable(${VPL_DEMO_NAME} ${SOURCES} ${SRC}) 37 | find_package(VPL REQUIRED) 38 | target_link_libraries(${VPL_DEMO_NAME} VPL::dispatcher) 39 | include_directories(../) 40 | 41 | if(UNIX) 42 | set(LIBVA_SUPPORT 43 | ON 44 | CACHE BOOL "Enable hardware support.") 45 | if(LIBVA_SUPPORT) 46 | # note: pkg-config version for libva is *API* version 47 | 48 | pkg_check_modules(PKG_LIBVA libva>=1.2) 49 | if(PKG_LIBVA_FOUND) 50 | target_compile_definitions(${VPL_DEMO_NAME} PUBLIC -DLIBVA_SUPPORT) 51 | target_link_libraries(${VPL_DEMO_NAME} ${PKG_LIBVA_LIBRARIES}) 52 | target_include_directories(${VPL_DEMO_NAME} PUBLIC ${PKG_LIBVA_INCLUDEDIR}) 53 | else() 54 | message( 55 | SEND_ERROR 56 | "libva not found: set LIBVA_SUPPORT=OFF to build ${TARGET} without libva support" 57 | ) 58 | endif() 59 | 60 | pkg_check_modules(PKG_LIBVADRM libva-drm>=1.2) 61 | if(PKG_LIBVADRM_FOUND) 62 | target_compile_definitions(${VPL_DEMO_NAME} PUBLIC -DLIBVA_SUPPORT) 63 | target_link_libraries(${VPL_DEMO_NAME} ${PKG_LIBVADRM_LIBRARIES}) 64 | target_include_directories(${VPL_DEMO_NAME} PUBLIC ${PKG_LIBVADRM_INCLUDEDIR}) 65 | else() 66 | message( 67 | SEND_ERROR 68 | "libva-drm not found: set LIBVA_SUPPORT=OFF to build ${TARGET} without libva support" 69 | ) 70 | endif() 71 | else() 72 | message(STATUS "Building ${TARGET} without hardware support") 73 | endif() 74 | endif() 75 | 76 | find_package(OpenVINO REQUIRED) 77 | if(OpenVINO_FOUND) 78 | target_link_libraries(${VPL_DEMO_NAME} openvino::runtime) 79 | else() 80 | message(SEND_ERROR "OpenVINO not found") 81 | endif() 82 | 83 | find_package(OpenCL) 84 | if(OpenCL_FOUND) 85 | target_include_directories(${VPL_DEMO_NAME} PUBLIC ${OpenCL_INCLUDE_DIRS}) 86 | else() 87 | message( 88 | "OpenCL not found with find_package(OpenCL), using backup approach to find OpenCL library." 89 | ) 90 | find_path( 91 | OpenCL_LIBRARY_PATH libOpenCL.so.1 92 | PATHS $ENV{ONEAPI_ROOT}/compiler/latest/linux/lib /usr/lib/x86_64-linux-gnu 93 | NO_DEFAULT_PATH) 94 | if(OpenCL_LIBRARY_PATH) 95 | set(OpenCL_LIBRARIES ${OpenCL_LIBRARY_PATH}/libOpenCL.so.1) 96 | set(OpenCL_FOUND true) 97 | endif() 98 | 99 | endif() 100 | 101 | if(OpenCL_FOUND) 102 | message("using OpenCL library ${OpenCL_LIBRARIES}") 103 | target_link_libraries(${VPL_DEMO_NAME} ${OpenCL_LIBRARIES}) 104 | else() 105 | message(SEND_ERROR "OpenCL not found") 106 | endif() 107 | 108 | find_package(gflags) 109 | if (gflags_FOUND) 110 | message("using gflags library") 111 | target_link_libraries(${VPL_DEMO_NAME} gflags) 112 | else() 113 | message(SEND_ERROR "gflags not found") 114 | endif() 115 | 116 | endmacro() 117 | 118 | add_subdirectory(single_src) 119 | add_subdirectory(multi_src) 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # decode-infer-on-GPU 2 | This sample shows how to use the oneAPI Video Processing Library (oneVPL) to perform a ***single and mulit-source*** video decode and preprocess and inference using OpenVINO to show the device surface sharing (zero copy), modified from the example in (oneVPL)[https://github.com/oneapi-src/oneVPL/tree/master/examples]. 3 | 4 | ![vpl_ov](https://user-images.githubusercontent.com/91237924/201594545-16a056c0-8724-4562-a697-9d6eb46ab72b.png) 5 | 6 | ## System requirements 7 | 8 | | Optimized for | Description 9 | |----------------- | ---------------------------------------- 10 | | OS | Ubuntu* 20.04 11 | | Hardware | Compatible with Intel® oneAPI Video Processing Library(oneVPL) GPU implementation, which can be found at https://github.com/oneapi-src/oneVPL-intel-gpu 12 | | Software | Intel® oneAPI Video Processing Library(oneVPL) CPU implementation and Intel® - OpenVINO 2022.2 13 | 14 | ## How to build the sample 15 | 16 | ### Install OpenVINO toolkits 2022.2 from achieved package 17 | 1) Download and install OpenVINO C++ runtime: 18 | https://docs.openvino.ai/latest/openvino_docs_install_guides_installing_openvino_from_archive_linux.html 19 | 2) Configurations for Intel® Processor Graphics (GPU): 20 | https://docs.openvino.ai/latest/openvino_docs_install_guides_configurations_for_intel_gpu.html#gpu-guide 21 | 3) Install the OpenVINO Developtment tools: 22 | ```shell 23 | pip install openvino-dev[tensorflow2,onnx] 24 | ``` 25 | 26 | ### Install environment package prerequisites (optional) 27 | ```shell 28 | apt update && \ 29 | apt install --no-install-recommends -q -y software-properties-common gnupg wget sudo unzip libnss3-tools ncurses-term python3-pip 30 | ``` 31 | 32 | ### Install Intel graphics stack packages from Agama 33 | ```shell 34 | wget https://repositories.intel.com/graphics/intel-graphics.key && \ 35 | apt-key add intel-graphics.key && \ 36 | apt-add-repository 'deb [arch=amd64] https://repositories.intel.com/graphics/ubuntu focal main' && \ 37 | apt update && \ 38 | apt install -y libmfx1 libmfxgen1 vainfo intel-opencl-icd intel-level-zero-gpu level-zero intel-media-va-driver-non-free python3.9 39 | ``` 40 | 41 | ### Install Dev package 42 | ```shell 43 | apt install -y cmake build-essential libva-dev libdrm-dev net-tools pkg-config libigc-dev intel-igc-cm libigdfcl-dev libigfxcmrt-dev level-zero-dev opencl-headers build-essential 44 | ``` 45 | 46 | Or you can follow this instruction to install the driver package for a discrete GPU device. 47 | https://dgpu-docs.intel.com/index.html 48 | 49 | ### Install oneVPL devkit package from oneAPI 50 | ```shell 51 | wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB && \ 52 | apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB && \ 53 | echo "deb https://apt.repos.intel.com/oneapi all main" | tee /etc/apt/sources.list.d/oneAPI.list && \ 54 | apt update && apt install -y intel-oneapi-onevpl-devel 55 | ``` 56 | 57 | ### Configure the Environment 58 | 1) OpenVINO: 59 | ```shell 60 | source /setupvars.sh 61 | ``` 62 | 2) oneAPI: 63 | ```shell 64 | source /opt/intel/oneapi/setvars.sh 65 | ``` 66 | 67 | 3) Build the source code 68 | ``` 69 | mkdir build 70 | cd build 71 | cmake -DCMAKE_BUILD_TYPE=Release .. 72 | cmake --build . 73 | ``` 74 | 75 | Tips: To trigger dGPU, you have to switch the code as below: 76 | https://github.com/OpenVINO-dev-contest/decode-infer-on-GPU/blob/main/multi_src/decode_vpp.h#L252 77 | 78 | from 79 | ``` 80 | fd = open("/dev/dri/renderD128", O_RDWR); 81 | ``` 82 | to 83 | ``` 84 | fd = open("/dev/dri/renderD129", O_RDWR); 85 | ``` 86 | 87 | ### Download test model 88 | Download the vehicle detection model from OpenVINO model zoo 89 | ``` 90 | omz_downloader --name vehicle-detection-0200 91 | ``` 92 | 93 | ### Run the program 94 | - For single source 95 | ``` 96 | ./single_src/single_source -i ../content/cars_320x240.h265 -m ~/vehicle-detection-0200/FP32/vehicle-detection-0200.xml 97 | ``` 98 | - For multiple source 99 | ``` 100 | ./multi_src/multi_source -i ../content/cars_320x240.h265,../content/cars_320x240.h265,../content/cars_320x240.h265 -m ~/vehicle-detection-0200/FP32/vehicle-detection-0200.xml -bs 2 -nr 4 101 | ``` 102 | 103 | - -i = Path to one or multiple input video files, separated by comma; 104 | - -m = Path to IR .xml file; 105 | - -bs = Batch size; 106 | - -nr = Number of inference requests; 107 | - -ns = Number of GPU streams; 108 | - -fr = Number of frame to be decoded for each input source; 109 | 110 | Tips: Since the sample has been set the number of stream as 1, the number of infer request should be larger than 1. 111 | 112 | ## Example of Output 113 | In this sample, you will get the inference result according to stream id of input source. 114 | ``` 115 | libva info: VA-API version 1.12.0 116 | libva info: Trying to open /opt/intel/mediasdk/lib64/iHD_drv_video.so 117 | libva info: Found init function __vaDriverInit_1_12 118 | libva info: va_openDriver() returns 0 119 | Implementation details: 120 | ApiVersion: 2.7 121 | Implementation type: HW 122 | AccelerationMode via: VAAPI 123 | Path: /usr/lib/x86_64-linux-gnu/libmfx-gen.so.1.2.7 124 | 125 | Frames [stream_id=1] [stream_id=0] 126 | image0: bbox 204.99, 49.43, 296.43, 144.56, confidence = 0.99805 127 | image0: bbox 91.26, 115.56, 198.41, 221.69, confidence = 0.99609 128 | image0: bbox 36.50, 44.75, 111.34, 134.57, confidence = 0.98535 129 | image0: bbox 77.92, 72.38, 155.06, 164.30, confidence = 0.97510 130 | image1: bbox 204.99, 49.43, 296.43, 144.56, confidence = 0.99805 131 | image1: bbox 91.26, 115.56, 198.41, 221.69, confidence = 0.99609 132 | image1: bbox 36.50, 44.75, 111.34, 134.57, confidence = 0.98535 133 | image1: bbox 77.92, 72.38, 155.06, 164.30, confidence = 0.97510 134 | Frames [stream_id=1] [stream_id=0] 135 | image0: bbox 206.96, 50.41, 299.54, 146.23, confidence = 0.99805 136 | image0: bbox 93.81, 115.29, 200.86, 222.94, confidence = 0.99414 137 | image0: bbox 84.15, 92.91, 178.14, 191.82, confidence = 0.99316 138 | image0: bbox 37.78, 45.82, 113.29, 132.28, confidence = 0.98193 139 | image0: bbox 75.96, 71.88, 154.31, 164.54, confidence = 0.96582 140 | image1: bbox 206.96, 50.41, 299.54, 146.23, confidence = 0.99805 141 | image1: bbox 93.81, 115.29, 200.86, 222.94, confidence = 0.99414 142 | image1: bbox 84.15, 92.91, 178.14, 191.82, confidence = 0.99316 143 | image1: bbox 37.78, 45.82, 113.29, 132.28, confidence = 0.98193 144 | image1: bbox 75.96, 71.88, 154.31, 164.54, confidence = 0.96582 145 | ... 146 | decoded and infered 60 frames 147 | Time = 0.328556s 148 | ``` 149 | -------------------------------------------------------------------------------- /multi_src/main.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // Copyright Intel Corporation 3 | // 4 | // SPDX-License-Identifier: MIT 5 | //============================================================================== 6 | 7 | /// 8 | /// A minimal oneAPI Video Processing Library (oneVPL) decode, vpp and infer application, 9 | /// using 2.x API with internal memory management, 10 | /// showing zerocopy with remoteblob 11 | /// 12 | /// @file 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "blocking_queue.h" 22 | #include "decode_vpp.h" 23 | #include "utils/functions.h" 24 | #include "utils/util.h" 25 | 26 | using namespace multi_source; 27 | DEFINE_string(i, "", 28 | "Required. Path to one or multiple input video files " 29 | "(separated by comma or delimeter specified in -delimeter option"); 30 | DEFINE_string(m, "", "Required. Path to IR .xml file"); 31 | // DEFINE_string(device, "GPU", "Device for decode and inference, 'CPU' or 'GPU'"); 32 | DEFINE_int32(bs, 2, "Batch size"); 33 | DEFINE_int32(nr, 4, "Number of inference requests"); 34 | DEFINE_int32(ns, 1, "Number of GPU streams"); 35 | DEFINE_int32(fr, 30, "Number of frame to be decoded for each input source"); 36 | 37 | int main(int argc, char* argv[]) { 38 | gflags::ParseCommandLineFlags(&argc, &argv, true); 39 | int frameNum = 0; 40 | 41 | // setup OpenVINO Inference Engine 42 | ov::Core core; 43 | 44 | // configuration for Multiple streams on GPU 45 | std::string key = "GPU_THROUGHPUT_STREAMS"; 46 | ov::AnyMap config; 47 | config[key] = FLAGS_ns; 48 | core.set_property("GPU", config); 49 | 50 | // read network model 51 | std::shared_ptr model = core.read_model(FLAGS_m); 52 | 53 | // get the input shape 54 | auto input0 = model->get_parameters().at(0); 55 | auto shape = input0->get_shape(); 56 | auto inputs = split_string(FLAGS_i); 57 | int num_source = inputs.size(); 58 | 59 | // setup VPL 60 | Decode_vpp decode_vpp(inputs, shape); 61 | auto lvaDisplay = decode_vpp.get_context(); 62 | auto input_shape = decode_vpp.get_input_shape(); 63 | 64 | // integrate preprocessing steps into the execution graph with Preprocessing API 65 | openvino_preprocess(model); 66 | 67 | if (FLAGS_bs > 1) 68 | ov::set_batch(model, FLAGS_bs); 69 | // zero-copy conversion from VAAPI surface to OpenVINO toolkit tensors (one for Y plane, another for UV) 70 | auto shared_va_context = ov::intel_gpu::ocl::VAContext(core, lvaDisplay); 71 | ov::CompiledModel compiled_model = core.compile_model(model, shared_va_context); 72 | 73 | // create the queue for free infer request 74 | BlockingQueue free_requests; 75 | for (int i = 0; i < FLAGS_nr; i++) 76 | free_requests.push(compiled_model.create_infer_request()); 77 | 78 | auto t1 = std::chrono::high_resolution_clock::now(); 79 | 80 | // reading the input data and start decoding 81 | decode_vpp.decoding(inputs); 82 | BlockingQueue>, ov::InferRequest>> busy_requests; 83 | 84 | // async thread waiting for inference completion and printing inference results 85 | std::thread thread([&] { 86 | for (;;) { 87 | auto res = busy_requests.pop(); 88 | auto batched_frames = res.first; 89 | auto infer_request = res.second; 90 | if (!infer_request) 91 | break; 92 | infer_request.wait(); 93 | ov::Tensor output_tensor = infer_request.get_output_tensor(0); 94 | PrintMultiResults(output_tensor, batched_frames, input_shape); 95 | // When application completes the work with frame surface, it must call release to avoid memory leaks 96 | for (auto frame : batched_frames) 97 | { 98 | frame.first->FrameInterface->Release(frame.first); 99 | } 100 | free_requests.push(infer_request); 101 | } 102 | printf("print_tensor() thread completed\n"); }); 103 | 104 | int inferedNum = 0; 105 | // frame loop 106 | std::vector> batched_frames; 107 | 108 | for (;;) { 109 | inferedNum++; 110 | if (inferedNum > FLAGS_fr * num_source) // End-Of-Stream or error 111 | break; 112 | // video input, decode, resize 113 | auto frame = decode_vpp.read(); 114 | 115 | // fill full batch 116 | batched_frames.push_back(frame); 117 | if (batched_frames.size() < FLAGS_bs) 118 | continue; 119 | 120 | // zero-copy conversion from VASurfaceID to OpenVINO VASurfaceTensor (one tensor for Y plane, another for UV) 121 | std::vector y_tensors; 122 | std::vector uv_tensors; 123 | for (auto va_surface : batched_frames) { 124 | mfxResourceType lresourceType; 125 | mfxHDL lresource; 126 | va_surface.first->FrameInterface->GetNativeHandle(va_surface.first, 127 | &lresource, 128 | &lresourceType); 129 | VASurfaceID lvaSurfaceID = *(VASurfaceID*)(lresource); 130 | auto nv12_tensor = shared_va_context.create_tensor_nv12(shape[2], shape[3], lvaSurfaceID); 131 | y_tensors.push_back(nv12_tensor.first); 132 | uv_tensors.push_back(nv12_tensor.second); 133 | } 134 | 135 | // get inference request and start asynchronously 136 | ov::InferRequest infer_request = free_requests.pop(); 137 | infer_request.set_input_tensors(0, y_tensors); // first input is batch of Y planes 138 | infer_request.set_input_tensors(1, uv_tensors); // second input is batch of UV planes 139 | infer_request.start_async(); 140 | busy_requests.push({batched_frames, infer_request}); 141 | 142 | batched_frames.clear(); 143 | } 144 | 145 | // wait for all inference requests in queue 146 | busy_requests.push({}); 147 | thread.join(); 148 | printf("decoded and infered %d frames\n", inferedNum - 1); 149 | auto t2 = std::chrono::high_resolution_clock::now(); 150 | std::chrono::duration fp_ms = t2 - t1; 151 | std::cout << "Time = " << fp_ms.count() << "ms" << std::endl; 152 | return 0; 153 | } 154 | -------------------------------------------------------------------------------- /utils/functions.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "utils/util.h" 6 | 7 | using namespace ov::preprocess; 8 | 9 | mfxStatus sts = MFX_ERR_NONE; 10 | #define MAJOR_API_VERSION_REQUIRED 2 11 | #define MINOR_API_VERSION_REQUIRED 2 12 | 13 | bool openvino_preprocess(std::shared_ptr model) 14 | { 15 | auto p = PrePostProcessor(model); 16 | p.input().tensor().set_element_type(ov::element::u8) 17 | // YUV images can be split into separate planes 18 | .set_color_format(ov::preprocess::ColorFormat::NV12_TWO_PLANES, {"y", "uv"}) 19 | .set_memory_type(ov::intel_gpu::memory_type::surface); 20 | // Change color format 21 | p.input().preprocess().convert_color(ov::preprocess::ColorFormat::BGR); 22 | // Change layout 23 | p.input().model().set_layout("NCHW"); 24 | model = p.build(); 25 | return true; 26 | } 27 | 28 | ov::Tensor openvino_infer(std::pair nv12_blob, std::shared_ptr &model, ov::InferRequest infer_request) 29 | { 30 | // get the new inputs, one for Y and another for UV 31 | auto new_input0 = model->get_parameters().at(0); 32 | auto new_input1 = model->get_parameters().at(1); 33 | 34 | // set remoteblobs as inference input 35 | infer_request.set_tensor(new_input0->get_friendly_name(), nv12_blob.first); 36 | infer_request.set_tensor(new_input1->get_friendly_name(), nv12_blob.second); 37 | 38 | // start inference on GPU 39 | infer_request.start_async(); 40 | infer_request.wait(); 41 | // Process output 42 | auto output_tensor = infer_request.get_output_tensor(0); 43 | return output_tensor; 44 | } 45 | 46 | void PrintSingleResults(ov::Tensor output_tensor, mfxU16 width, mfxU16 height) 47 | { 48 | float *output = (float *)output_tensor.data(); 49 | /* Each detection has image_id that denotes processed image */ 50 | size_t last_dim = output_tensor.get_shape().back(); 51 | if (last_dim == 7) 52 | { 53 | // suppose object detection model with output [image_id, label_id, confidence, bbox coordinates] 54 | float *output = (float *)output_tensor.data(); 55 | for (size_t i = 0; i < output_tensor.get_size() / last_dim; i++) 56 | { 57 | int image_id = static_cast(output[i * last_dim + 0]); 58 | if (image_id < 0) 59 | break; 60 | 61 | float confidence = output[i * last_dim + 2]; 62 | 63 | if (confidence < 0.5) 64 | { 65 | continue; 66 | } 67 | 68 | float x_min = output[i * last_dim + 3] * width; 69 | float y_min = output[i * last_dim + 4] * height; 70 | float x_max = output[i * last_dim + 5] * width; 71 | float y_max = output[i * last_dim + 6] * height; 72 | printf(" image%d: bbox %.2f, %.2f, %.2f, %.2f, confidence = %.5f\n", image_id, x_min, y_min, x_max, y_max, 73 | confidence); 74 | } 75 | } 76 | else 77 | { 78 | std::cout << " output shape=" << output_tensor.get_shape() << std::endl; 79 | } 80 | } 81 | 82 | void PrintMultiResults(ov::Tensor output_tensor, std::vector> batched_frames, std::vector> shape) 83 | { 84 | printf("Frames"); 85 | for (auto frame : batched_frames) 86 | { 87 | printf(" [stream_id=%ld]", frame.second); 88 | } 89 | printf("\n"); 90 | // If object detection model, print bounding box coordinates and confidence. Otherwise, print output shape 91 | size_t last_dim = output_tensor.get_shape().back(); 92 | if (last_dim == 7) 93 | { 94 | // suppose object detection model with output [image_id, label_id, confidence, bbox coordinates] 95 | float *output = (float *)output_tensor.data(); 96 | for (size_t i = 0; i < output_tensor.get_size() / last_dim; i++) 97 | { 98 | int image_id = static_cast(output[i * last_dim + 0]); 99 | int batch_id = batched_frames[image_id].second; 100 | if (image_id < 0) 101 | break; 102 | 103 | float confidence = output[i * last_dim + 2]; 104 | 105 | if (confidence < 0.5) 106 | { 107 | continue; 108 | } 109 | 110 | float x_min = output[i * last_dim + 3] * shape[batch_id].second; 111 | float y_min = output[i * last_dim + 4] * shape[batch_id].first; 112 | float x_max = output[i * last_dim + 5] * shape[batch_id].second; 113 | float y_max = output[i * last_dim + 6] * shape[batch_id].first; 114 | printf("image%d: bbox %.2f, %.2f, %.2f, %.2f, confidence = %.5f\n", image_id, x_min, y_min, x_max, y_max, 115 | confidence); 116 | } 117 | } 118 | else 119 | { 120 | std::cout << " output shape=" << output_tensor.get_shape() << std::endl; 121 | } 122 | } 123 | 124 | 125 | mfxSession CreateVPLSession(mfxLoader *loader) 126 | { 127 | 128 | // variables used only in 2.x version 129 | mfxConfig cfg[4]; 130 | mfxVariant cfgVal; 131 | mfxSession session = NULL; 132 | 133 | //-- Create session 134 | *loader = MFXLoad(); 135 | VERIFY2(NULL != *loader, "MFXLoad failed -- is implementation in path?\n"); 136 | 137 | // Implementation used must be the hardware implementation 138 | cfg[0] = MFXCreateConfig(*loader); 139 | VERIFY2(NULL != cfg[0], "MFXCreateConfig failed") 140 | cfgVal.Type = MFX_VARIANT_TYPE_U32; 141 | cfgVal.Data.U32 = MFX_IMPL_TYPE_HARDWARE; 142 | sts = MFXSetConfigFilterProperty(cfg[0], (mfxU8 *)"mfxImplDescription.Impl", cfgVal); 143 | VERIFY2(MFX_ERR_NONE == sts, "MFXSetConfigFilterProperty failed for Impl"); 144 | 145 | // Implementation must provide an HEVC decoder 146 | cfg[1] = MFXCreateConfig(*loader); 147 | VERIFY2(NULL != cfg[1], "MFXCreateConfig failed") 148 | cfgVal.Type = MFX_VARIANT_TYPE_U32; 149 | cfgVal.Data.U32 = MFX_CODEC_HEVC; 150 | sts = MFXSetConfigFilterProperty( 151 | cfg[1], 152 | (mfxU8 *)"mfxImplDescription.mfxDecoderDescription.decoder.CodecID", 153 | cfgVal); 154 | VERIFY2(MFX_ERR_NONE == sts, "MFXSetConfigFilterProperty failed for decoder CodecID"); 155 | 156 | // Implementation used must have VPP scaling capability 157 | cfg[2] = MFXCreateConfig(*loader); 158 | VERIFY2(NULL != cfg[2], "MFXCreateConfig failed") 159 | cfgVal.Type = MFX_VARIANT_TYPE_U32; 160 | cfgVal.Data.U32 = MFX_EXTBUFF_VPP_SCALING; 161 | sts = MFXSetConfigFilterProperty( 162 | cfg[2], 163 | (mfxU8 *)"mfxImplDescription.mfxVPPDescription.filter.FilterFourCC", 164 | cfgVal); 165 | VERIFY2(MFX_ERR_NONE == sts, "MFXSetConfigFilterProperty failed for VPP scale"); 166 | 167 | // Implementation used must provide API version 2.2 or newer 168 | cfg[3] = MFXCreateConfig(*loader); 169 | VERIFY2(NULL != cfg[3], "MFXCreateConfig failed") 170 | cfgVal.Type = MFX_VARIANT_TYPE_U32; 171 | cfgVal.Data.U32 = VPLVERSION(MAJOR_API_VERSION_REQUIRED, MINOR_API_VERSION_REQUIRED); 172 | sts = MFXSetConfigFilterProperty(cfg[3], 173 | (mfxU8 *)"mfxImplDescription.ApiVersion.Version", 174 | cfgVal); 175 | VERIFY2(MFX_ERR_NONE == sts, "MFXSetConfigFilterProperty failed for API version"); 176 | 177 | sts = MFXCreateSession(*loader, 0, &session); 178 | VERIFY2(MFX_ERR_NONE == sts, 179 | "Cannot create session -- no implementations meet selection criteria"); 180 | 181 | // Print info about implementation loaded 182 | ShowImplementationInfo(*loader, 0); 183 | return session; 184 | } 185 | -------------------------------------------------------------------------------- /single_src/main.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // Copyright Intel Corporation 3 | // 4 | // SPDX-License-Identifier: MIT 5 | //============================================================================== 6 | 7 | /// 8 | /// A minimal oneAPI Video Processing Library (oneVPL) decode, vpp and infer application, 9 | /// using 2.x API with internal memory management, 10 | /// showing zerocopy with remoteblob 11 | /// 12 | /// @file 13 | 14 | #include 15 | #include 16 | #include 17 | #include "utils/functions.h" 18 | #include "utils/util.h" 19 | 20 | #define BITSTREAM_BUFFER_SIZE 2000000 21 | #define MAX_RESULTS 5 22 | #define SYNC_TIMEOUT 60000 23 | #define onevpl_decode MFXVideoDECODE_DecodeFrameAsync 24 | #define onevpl_vpp MFXVideoVPP_ProcessFrameAsync 25 | 26 | DEFINE_string(i, "", "Required. Path to one input video files "); 27 | DEFINE_string(m, "", "Required. Path to IR .xml file"); 28 | 29 | mfxSession CreateVPLSession(mfxLoader* loader); 30 | void PrintTopResults(const float* output, mfxU16 width, mfxU16 height, ov::Shape output_shape); 31 | 32 | int main(int argc, char** argv) { 33 | gflags::ParseCommandLineFlags(&argc, &argv, true); 34 | 35 | FILE* source = NULL; 36 | mfxLoader loader = NULL; 37 | mfxSession session = NULL; 38 | mfxFrameSurface1* decSurfaceOut = NULL; 39 | mfxBitstream bitstream = {}; 40 | mfxSyncPoint syncp = {}; 41 | mfxVideoParam mfxDecParams = {}; 42 | mfxVideoParam mfxVPPParams = {}; 43 | mfxFrameSurface1* pmfxDecOutSurface = NULL; 44 | mfxFrameSurface1* pmfxVPPSurfacesOut = NULL; 45 | mfxU32 frameNum = 0; 46 | bool isStillGoing = true; 47 | bool isDrainingDec = false; 48 | bool isDrainingVPP = false; 49 | mfxStatus sts = MFX_ERR_NONE; 50 | Params cliParams = {}; 51 | 52 | ov::Core core; 53 | std::shared_ptr model; 54 | ov::CompiledModel compiled_model; 55 | ov::InferRequest infer_request; 56 | ov::Shape output_shape; 57 | 58 | VADisplay lvaDisplay; 59 | VASurfaceID lvaSurfaceID; 60 | mfxHandleType ldeviceType; 61 | mfxHDL lresource; 62 | mfxResourceType lresourceType; 63 | mfxStatus lsts; 64 | bool isNetworkLoaded = false; 65 | 66 | mfxU16 oriImgWidth, oriImgHeight; 67 | mfxU16 inputDimWidth, inputDimHeight; 68 | mfxU16 vppInImgWidth, vppInImgHeight; 69 | mfxU16 vppOutImgWidth, vppOutImgHeight; 70 | 71 | source = fopen(FLAGS_i.data(), "rb"); 72 | VERIFY(source, "Could not open input file"); 73 | 74 | //--- Setup OpenVINO Inference Engine 75 | // Read network model 76 | model = core.read_model(FLAGS_m); 77 | 78 | // Get the input shape 79 | auto input0 = model->get_parameters().at(0); 80 | auto shape = input0->get_shape(); 81 | auto width = shape[3]; 82 | auto height = shape[2]; 83 | inputDimWidth = (mfxU16)width; 84 | inputDimHeight = (mfxU16)height; 85 | 86 | // Get the ouput shape 87 | output_shape = model->output().get_shape(); 88 | 89 | //---- Setup VPL 90 | // Create VPL session 91 | session = CreateVPLSession(&loader); 92 | VERIFY(session != NULL, "Not able to create VPL session"); 93 | 94 | //-- Initialize Decode 95 | // Prepare input bitstream 96 | bitstream.MaxLength = BITSTREAM_BUFFER_SIZE; 97 | bitstream.Data = (mfxU8*)calloc(bitstream.MaxLength, sizeof(mfxU8)); 98 | VERIFY(bitstream.Data, "Not able to allocate input buffer"); 99 | bitstream.CodecId = MFX_CODEC_HEVC; 100 | 101 | sts = ReadEncodedStream(bitstream, source); 102 | VERIFY(MFX_ERR_NONE == sts, "Error reading bitstream"); 103 | 104 | // Retrieve the frame information from input stream 105 | mfxDecParams.mfx.CodecId = MFX_CODEC_HEVC; 106 | mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY; 107 | sts = MFXVideoDECODE_DecodeHeader(session, &bitstream, &mfxDecParams); 108 | VERIFY(MFX_ERR_NONE == sts, "Error decoding header"); 109 | 110 | // Original image size 111 | oriImgWidth = mfxDecParams.mfx.FrameInfo.Width; 112 | oriImgHeight = mfxDecParams.mfx.FrameInfo.Height; 113 | 114 | // Input parameters finished, now initialize decode 115 | sts = MFXVideoDECODE_Init(session, &mfxDecParams); 116 | VERIFY(MFX_ERR_NONE == sts, "Error initializing Decode"); 117 | 118 | //-- Initialize VPP 119 | // Prepare vpp in/out params 120 | // vpp in: decode output image size 121 | // vpp out: network model input size 122 | vppInImgWidth = mfxDecParams.mfx.FrameInfo.Width; 123 | vppInImgHeight = mfxDecParams.mfx.FrameInfo.Height; 124 | vppOutImgWidth = inputDimWidth; 125 | vppOutImgHeight = inputDimHeight; 126 | 127 | mfxVPPParams.vpp.In.FourCC = mfxDecParams.mfx.FrameInfo.FourCC; 128 | mfxVPPParams.vpp.In.ChromaFormat = mfxDecParams.mfx.FrameInfo.ChromaFormat; 129 | mfxVPPParams.vpp.In.Width = vppInImgWidth; 130 | mfxVPPParams.vpp.In.Height = vppInImgHeight; 131 | mfxVPPParams.vpp.In.CropW = vppInImgWidth; 132 | mfxVPPParams.vpp.In.CropH = vppInImgHeight; 133 | mfxVPPParams.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; 134 | mfxVPPParams.vpp.In.FrameRateExtN = 30; 135 | mfxVPPParams.vpp.In.FrameRateExtD = 1; 136 | 137 | mfxVPPParams.vpp.Out.FourCC = MFX_FOURCC_NV12; 138 | mfxVPPParams.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420; 139 | mfxVPPParams.vpp.Out.Width = ALIGN16(vppOutImgWidth); 140 | mfxVPPParams.vpp.Out.Height = ALIGN16(vppOutImgHeight); 141 | mfxVPPParams.vpp.Out.CropW = vppOutImgWidth; 142 | mfxVPPParams.vpp.Out.CropH = vppOutImgHeight; 143 | mfxVPPParams.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; 144 | mfxVPPParams.vpp.Out.FrameRateExtN = 30; 145 | mfxVPPParams.vpp.Out.FrameRateExtD = 1; 146 | 147 | mfxVPPParams.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY; 148 | 149 | // Initialize the VPP 150 | sts = MFXVideoVPP_Init(session, &mfxVPPParams); 151 | VERIFY(MFX_ERR_NONE == sts, "Error initializing VPP"); 152 | 153 | // Get the vaapi device handle 154 | sts = MFXVideoCORE_GetHandle(session, MFX_HANDLE_VA_DISPLAY, &lvaDisplay); 155 | VERIFY(MFX_ERR_NONE == sts, "MFXVideoCore_GetHandle error"); 156 | 157 | // Integrate preprocessing steps into the execution graph with Preprocessing API 158 | openvino_preprocess(model); 159 | auto shared_va_context = ov::intel_gpu::ocl::VAContext(core, lvaDisplay); 160 | compiled_model = core.compile_model(model, shared_va_context); 161 | 162 | // Create infer request 163 | infer_request = compiled_model.create_infer_request(); 164 | auto t1 = std::chrono::high_resolution_clock::now(); 165 | printf("Decoding VPP, and infering %s with %s\n", cliParams.infileName, cliParams.inmodelName); 166 | while (isStillGoing == true) { 167 | if (isDrainingDec == false) { 168 | sts = ReadEncodedStream(bitstream, source); 169 | if (sts != MFX_ERR_NONE) 170 | isDrainingDec = true; 171 | } 172 | 173 | if (!isDrainingVPP) { 174 | // Run decode with onevpl 175 | sts = onevpl_decode(session, 176 | (isDrainingDec) ? NULL : &bitstream, 177 | NULL, 178 | &pmfxDecOutSurface, 179 | &syncp); 180 | } else { 181 | sts = MFX_ERR_NONE; 182 | } 183 | 184 | switch (sts) { 185 | case MFX_ERR_NONE: 186 | // Run vpp with onevpl 187 | sts = 188 | onevpl_vpp(session, pmfxDecOutSurface, &pmfxVPPSurfacesOut); 189 | if (sts == MFX_ERR_NONE) { 190 | sts = pmfxVPPSurfacesOut->FrameInterface->Synchronize(pmfxVPPSurfacesOut, 191 | SYNC_TIMEOUT); 192 | VERIFY(MFX_ERR_NONE == sts, "MFXVideoCORE_SyncOperation error"); 193 | 194 | sts = pmfxVPPSurfacesOut->FrameInterface->GetNativeHandle(pmfxVPPSurfacesOut, 195 | &lresource, 196 | &lresourceType); 197 | VERIFY(MFX_ERR_NONE == sts, "FrameInterface->GetNativeHandle error"); 198 | VERIFY(MFX_RESOURCE_VA_SURFACE == lresourceType, 199 | "Display device is not MFX_HANDLE_VA_DISPLAY"); 200 | 201 | lvaSurfaceID = *(VASurfaceID*)lresource; 202 | 203 | // Wrap VPP output into remoteblobs 204 | auto nv12_blob = shared_va_context.create_tensor_nv12(height, width, lvaSurfaceID); 205 | 206 | // Run inference with openvino 207 | ov::Tensor result = openvino_infer(nv12_blob, model, infer_request); 208 | frameNum++; 209 | // Release surface 210 | sts = pmfxVPPSurfacesOut->FrameInterface->Release(pmfxVPPSurfacesOut); 211 | VERIFY(MFX_ERR_NONE == sts, "ERROR - mfxFrameSurfaceInterface->Release failed"); 212 | 213 | PrintSingleResults(result, oriImgWidth, oriImgHeight); 214 | } else if (sts == MFX_ERR_MORE_DATA) { 215 | if (isDrainingVPP == true) 216 | isStillGoing = false; 217 | } else { 218 | if (sts < 0) 219 | isStillGoing = false; 220 | } 221 | break; 222 | case MFX_ERR_MORE_DATA: 223 | // The function requires more bitstream at input before decoding can proceed 224 | if (isDrainingDec) 225 | isDrainingVPP = true; 226 | break; 227 | default: 228 | isStillGoing = false; 229 | break; 230 | } 231 | } 232 | auto t2 = std::chrono::high_resolution_clock::now(); 233 | std::chrono::duration fp_ms = t2 - t1; 234 | std::cout << "Time = " << fp_ms.count() << "ms" << std::endl; 235 | printf("Decoded %d frames\n", frameNum); 236 | 237 | if (bitstream.Data) 238 | free(bitstream.Data); 239 | 240 | if (source) 241 | fclose(source); 242 | 243 | if (loader) 244 | MFXUnload(loader); 245 | 246 | return 0; 247 | } 248 | -------------------------------------------------------------------------------- /multi_src/decode_vpp.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "blocking_queue.h" 4 | #include "utils/util.h" 5 | #define MAX_QUEUE_SIZE 16 6 | #define BITSTREAM_BUFFER_SIZE 2000000 7 | #define SYNC_TIMEOUT 600000 8 | #define MAJOR_API_VERSION_REQUIRED 2 9 | #define MINOR_API_VERSION_REQUIRED 2 10 | 11 | namespace multi_source { 12 | class Decode_vpp { 13 | public: 14 | Decode_vpp(std::vector inputs, const ov::Shape& shape) { 15 | width = shape[3]; 16 | height = shape[2]; 17 | inputDimWidth = (mfxU16)width; 18 | inputDimHeight = (mfxU16)height; 19 | 20 | // Initialize the VPL session for each input source instance 21 | for (int i = 0; i < inputs.size(); i++) { 22 | FILE* source = NULL; 23 | mfxSession session = NULL; 24 | mfxLoader loader = NULL; 25 | mfxBitstream bitstream = {}; 26 | 27 | const char* files = inputs[i].c_str(); 28 | source = fopen(files, "rb"); 29 | VERIFY(source, "Could not open input file"); 30 | 31 | // Create VPL session 32 | session = CreateVPLSession(&loader, i); 33 | VERIFY(session != NULL, "Not able to create VPL session"); 34 | //-- Initialize Decode 35 | // Prepare input bitstream 36 | bitstream.MaxLength = BITSTREAM_BUFFER_SIZE; 37 | bitstream.Data = (mfxU8*)calloc(bitstream.MaxLength, sizeof(mfxU8)); 38 | VERIFY(bitstream.Data, "Not able to allocate input buffer"); 39 | bitstream.CodecId = MFX_CODEC_HEVC; 40 | 41 | sts = ReadEncodedStream(bitstream, source); 42 | VERIFY(MFX_ERR_NONE == sts, "Error reading bitstream"); 43 | 44 | // Retrieve the frame information from input stream 45 | mfxDecParams.mfx.CodecId = MFX_CODEC_HEVC; 46 | mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY; 47 | sts = MFXVideoDECODE_DecodeHeader(session, &bitstream, &mfxDecParams); 48 | VERIFY(MFX_ERR_NONE == sts, "Error decoding header"); 49 | 50 | // Original image size 51 | mfxU16 oriImgWidth = mfxDecParams.mfx.FrameInfo.Width; 52 | mfxU16 oriImgHeight = mfxDecParams.mfx.FrameInfo.Height; 53 | _oriImgShape.push_back(std::make_pair(oriImgHeight, oriImgWidth)); 54 | 55 | // Input parameters finished, now initialize decode 56 | sts = MFXVideoDECODE_Init(session, &mfxDecParams); 57 | VERIFY(MFX_ERR_NONE == sts, "Error initializing Decode"); 58 | 59 | //-- Initialize VPP 60 | // Prepare vpp in/out params 61 | // vpp in: decode output image size 62 | // vpp out: network model input size 63 | vppInImgWidth = mfxDecParams.mfx.FrameInfo.Width; 64 | vppInImgHeight = mfxDecParams.mfx.FrameInfo.Height; 65 | vppOutImgWidth = inputDimWidth; 66 | vppOutImgHeight = inputDimHeight; 67 | 68 | mfxVPPParams.vpp.In.FourCC = mfxDecParams.mfx.FrameInfo.FourCC; 69 | mfxVPPParams.vpp.In.ChromaFormat = mfxDecParams.mfx.FrameInfo.ChromaFormat; 70 | mfxVPPParams.vpp.In.Width = vppInImgWidth; 71 | mfxVPPParams.vpp.In.Height = vppInImgHeight; 72 | mfxVPPParams.vpp.In.CropW = vppInImgWidth; 73 | mfxVPPParams.vpp.In.CropH = vppInImgHeight; 74 | mfxVPPParams.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; 75 | mfxVPPParams.vpp.In.FrameRateExtN = 30; 76 | mfxVPPParams.vpp.In.FrameRateExtD = 1; 77 | 78 | mfxVPPParams.vpp.Out.FourCC = MFX_FOURCC_NV12; 79 | mfxVPPParams.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420; 80 | mfxVPPParams.vpp.Out.Width = ALIGN16(vppOutImgWidth); 81 | mfxVPPParams.vpp.Out.Height = ALIGN16(vppOutImgHeight); 82 | mfxVPPParams.vpp.Out.CropW = vppOutImgWidth; 83 | mfxVPPParams.vpp.Out.CropH = vppOutImgHeight; 84 | mfxVPPParams.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; 85 | mfxVPPParams.vpp.Out.FrameRateExtN = 30; 86 | mfxVPPParams.vpp.Out.FrameRateExtD = 1; 87 | 88 | mfxVPPParams.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY; 89 | 90 | // Initialize the VPP 91 | sts = MFXVideoVPP_Init(session, &mfxVPPParams); 92 | VERIFY(MFX_ERR_NONE == sts, "Error initializing VPP"); 93 | 94 | // Get the vaapi device handle 95 | sts = MFXVideoCORE_GetHandle(session, MFX_HANDLE_VA_DISPLAY, &lvaDisplay); 96 | VERIFY(MFX_ERR_NONE == sts, "MFXVideoCore_GetHandle error"); 97 | 98 | _sessions.push_back(session); 99 | _bitstreams.push_back(bitstream); 100 | _sources.push_back(source); 101 | } 102 | } 103 | 104 | VADisplay get_context() { 105 | return lvaDisplay; 106 | } 107 | 108 | std::vector> get_input_shape() { 109 | return _oriImgShape; 110 | } 111 | 112 | ~Decode_vpp() { 113 | for (auto& stream : _streams) { 114 | stream.isStillGoing = false; 115 | stream.thread.join(); 116 | } 117 | } 118 | 119 | void decoding(std::vector inputs) { 120 | for (auto& input : inputs) { 121 | add_input(input); 122 | } 123 | } 124 | 125 | void add_input(std::string url) { 126 | // Create thread with frame reading loop 127 | size_t stream_id = _streams.size(); 128 | _streams.push_back({}); 129 | _streams.back().thread = std::thread([=] { 130 | mfxFrameSurface1 *pmfxDecOutSurface = NULL; 131 | mfxFrameSurface1 *pmfxVPPSurfacesOut = NULL; 132 | mfxSyncPoint syncp = {}; 133 | 134 | while (_streams[stream_id].isStillGoing){ 135 | if (_streams[stream_id].isDrainingDec == false){ 136 | _streams[stream_id].status = ReadEncodedStream(_bitstreams[stream_id], _sources[stream_id]); 137 | VERIFY(MFX_ERR_NONE == _streams[stream_id].status, "Error reading bitstream"); 138 | if (_streams[stream_id].status != MFX_ERR_NONE) 139 | _streams[stream_id].isDrainingDec = true; 140 | } 141 | 142 | if (!_streams[stream_id].isDrainingVPP){ 143 | _streams[stream_id].status = MFXVideoDECODE_DecodeFrameAsync(_sessions[stream_id], 144 | (_streams[stream_id].isDrainingDec) ? NULL : &_bitstreams[stream_id], 145 | NULL, 146 | &pmfxDecOutSurface, 147 | &syncp); 148 | } 149 | else{ 150 | _streams[stream_id].status = MFX_ERR_NONE; 151 | } 152 | 153 | switch (_streams[stream_id].status){ 154 | case MFX_ERR_NONE: 155 | _streams[stream_id].status = 156 | MFXVideoVPP_ProcessFrameAsync(_sessions[stream_id], pmfxDecOutSurface, &pmfxVPPSurfacesOut); 157 | if (_streams[stream_id].status == MFX_ERR_NONE) 158 | { 159 | _streams[stream_id].status = pmfxVPPSurfacesOut->FrameInterface->Synchronize(pmfxVPPSurfacesOut, 160 | SYNC_TIMEOUT); 161 | VERIFY(MFX_ERR_NONE == _streams[stream_id].status, "MFXVideoCORE_SyncOperation error"); 162 | 163 | // wrap the VPP output and stream id into a shared surface queue 164 | _queue.push(std::make_pair(pmfxVPPSurfacesOut, stream_id), MAX_QUEUE_SIZE); 165 | } 166 | else if (_streams[stream_id].status == MFX_ERR_MORE_DATA) 167 | { 168 | if (_streams[stream_id].isDrainingVPP == true) 169 | _streams[stream_id].isStillGoing = false; 170 | } 171 | else 172 | { 173 | if (_streams[stream_id].status < 0) 174 | _streams[stream_id].isStillGoing = false; 175 | } 176 | break; 177 | case MFX_ERR_MORE_DATA: 178 | // The function requires more bitstream at input before decoding can proceed 179 | if (_streams[stream_id].isDrainingDec) 180 | _streams[stream_id].isDrainingVPP = true; 181 | break; 182 | } 183 | } 184 | _streams[stream_id].isStillGoing = false; }); 185 | } 186 | 187 | std::pair read() { 188 | return _queue.pop(); 189 | } 190 | 191 | mfxSession CreateVPLSession(mfxLoader* loader, int counter) { 192 | mfxStatus sts = MFX_ERR_NONE; 193 | 194 | // variables used only in 2.x version 195 | mfxConfig cfg[4]; 196 | mfxVariant cfgVal; 197 | mfxSession session = NULL; 198 | 199 | //-- Create session 200 | *loader = MFXLoad(); 201 | VERIFY2(NULL != *loader, "MFXLoad failed -- is implementation in path?\n"); 202 | 203 | // Implementation used must be the hardware implementation 204 | cfg[0] = MFXCreateConfig(*loader); 205 | VERIFY2(NULL != cfg[0], "MFXCreateConfig failed") 206 | cfgVal.Type = MFX_VARIANT_TYPE_U32; 207 | cfgVal.Data.U32 = MFX_IMPL_TYPE_HARDWARE; 208 | sts = MFXSetConfigFilterProperty(cfg[0], (mfxU8*)"mfxImplDescription.Impl", cfgVal); 209 | VERIFY2(MFX_ERR_NONE == sts, "MFXSetConfigFilterProperty failed for Impl"); 210 | 211 | // Implementation must provide an HEVC decoder 212 | cfg[1] = MFXCreateConfig(*loader); 213 | VERIFY2(NULL != cfg[1], "MFXCreateConfig failed") 214 | cfgVal.Type = MFX_VARIANT_TYPE_U32; 215 | cfgVal.Data.U32 = MFX_CODEC_HEVC; 216 | sts = MFXSetConfigFilterProperty( 217 | cfg[1], 218 | (mfxU8*)"mfxImplDescription.mfxDecoderDescription.decoder.CodecID", 219 | cfgVal); 220 | VERIFY2(MFX_ERR_NONE == sts, "MFXSetConfigFilterProperty failed for decoder CodecID"); 221 | 222 | // Implementation used must have VPP scaling capability 223 | cfg[2] = MFXCreateConfig(*loader); 224 | VERIFY2(NULL != cfg[2], "MFXCreateConfig failed") 225 | cfgVal.Type = MFX_VARIANT_TYPE_U32; 226 | cfgVal.Data.U32 = MFX_EXTBUFF_VPP_SCALING; 227 | sts = MFXSetConfigFilterProperty( 228 | cfg[2], 229 | (mfxU8*)"mfxImplDescription.mfxVPPDescription.filter.FilterFourCC", 230 | cfgVal); 231 | VERIFY2(MFX_ERR_NONE == sts, "MFXSetConfigFilterProperty failed for VPP scale"); 232 | 233 | // Implementation used must provide API version 2.2 or newer 234 | cfg[3] = MFXCreateConfig(*loader); 235 | VERIFY2(NULL != cfg[3], "MFXCreateConfig failed") 236 | cfgVal.Type = MFX_VARIANT_TYPE_U32; 237 | cfgVal.Data.U32 = VPLVERSION(MAJOR_API_VERSION_REQUIRED, MINOR_API_VERSION_REQUIRED); 238 | sts = MFXSetConfigFilterProperty(cfg[3], 239 | (mfxU8*)"mfxImplDescription.ApiVersion.Version", 240 | cfgVal); 241 | VERIFY2(MFX_ERR_NONE == sts, "MFXSetConfigFilterProperty failed for API version"); 242 | 243 | sts = MFXCreateSession(*loader, 0, &session); 244 | VERIFY2(MFX_ERR_NONE == sts, 245 | "Cannot create session -- no implementations meet selection criteria"); 246 | 247 | // share one vaapi device handle amonge different input source 248 | if (counter == 0) { 249 | VADisplay va_dpy = NULL; 250 | int fd; 251 | // initialize VAAPI context and set session handle (req in Linux) 252 | fd = open("/dev/dri/renderD128", O_RDWR); 253 | if (fd >= 0) { 254 | va_dpy = vaGetDisplayDRM(fd); 255 | if (va_dpy) { 256 | int major_version = 0, minor_version = 0; 257 | if (VA_STATUS_SUCCESS == vaInitialize(va_dpy, &major_version, &minor_version)) { 258 | sts = MFXVideoCORE_SetHandle(session, 259 | static_cast(MFX_HANDLE_VA_DISPLAY), 260 | va_dpy); 261 | VERIFY(MFX_ERR_NONE == sts, "SetHandle error"); 262 | } 263 | } 264 | } 265 | } else { 266 | sts = MFXVideoCORE_SetHandle(session, 267 | static_cast(MFX_HANDLE_VA_DISPLAY), 268 | lvaDisplay); 269 | VERIFY(MFX_ERR_NONE == sts, "SetHandle error"); 270 | } 271 | 272 | // Print info about implementation loaded 273 | ShowImplementationInfo(*loader, 0); 274 | return session; 275 | } 276 | 277 | private: 278 | BlockingQueue> _queue; 279 | struct StreamState { 280 | bool isStillGoing = true; 281 | bool isDrainingDec = false; 282 | bool isDrainingVPP = false; 283 | mfxStatus status = MFX_ERR_NONE; 284 | std::thread thread; 285 | }; 286 | std::vector _streams; 287 | std::vector _sessions; 288 | std::vector _bitstreams; 289 | std::vector _sources; 290 | std::vector> _oriImgShape; 291 | size_t width; 292 | size_t height; 293 | 294 | mfxStatus sts = MFX_ERR_NONE; 295 | bool isNetworkLoaded = false; 296 | mfxU16 inputDimWidth, inputDimHeight; 297 | mfxU16 vppInImgWidth, vppInImgHeight; 298 | mfxU16 vppOutImgWidth, vppOutImgHeight; 299 | mfxVideoParam mfxDecParams = {}; 300 | mfxVideoParam mfxVPPParams = {}; 301 | VADisplay lvaDisplay; 302 | }; 303 | } // namespace multi_source 304 | -------------------------------------------------------------------------------- /utils/util.h: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // Copyright Intel Corporation 3 | // 4 | // SPDX-License-Identifier: MIT 5 | //============================================================================== 6 | 7 | /// 8 | /// Utility library header file for sample code 9 | /// 10 | /// @file 11 | 12 | #ifndef EXAMPLES_UTIL_H_ 13 | #define EXAMPLES_UTIL_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #ifdef USE_MEDIASDK1 20 | #include "mfxvideo.h" 21 | enum { 22 | MFX_FOURCC_I420 = MFX_FOURCC_IYUV /*!< Alias for the IYUV color format. */ 23 | }; 24 | #else 25 | #include "vpl/mfxjpeg.h" 26 | #include "vpl/mfxvideo.h" 27 | #endif 28 | 29 | #if (MFX_VERSION >= 2000) 30 | #include "vpl/mfxdispatcher.h" 31 | #endif 32 | 33 | #ifdef __linux__ 34 | #include 35 | #include 36 | #endif 37 | 38 | #ifdef LIBVA_SUPPORT 39 | #include "va/va.h" 40 | #include "va/va_drm.h" 41 | #endif 42 | 43 | #define WAIT_100_MILLISECONDS 100 44 | #define MAX_PATH 260 45 | #define MAX_WIDTH 3840 46 | #define MAX_HEIGHT 2160 47 | #define IS_ARG_EQ(a, b) (!strcmp((a), (b))) 48 | 49 | #define VERIFY(x, y) \ 50 | if (!(x)) { \ 51 | printf("%s\n", y); \ 52 | } 53 | 54 | #define VERIFY2(x, y) \ 55 | if (!(x)) { \ 56 | printf("%s\n", y); \ 57 | } 58 | 59 | #define ALIGN16(value) (((value + 15) >> 4) << 4) 60 | #define ALIGN32(X) (((mfxU32)((X) + 31)) & (~(mfxU32)31)) 61 | #define VPLVERSION(major, minor) (major << 16 | minor) 62 | 63 | enum ExampleParams { PARAM_IMPL = 0, PARAM_INFILE, PARAM_INRES, PARAM_COUNT }; 64 | enum ParamGroup { 65 | PARAMS_CREATESESSION = 0, 66 | PARAMS_DECODE, 67 | PARAMS_ENCODE, 68 | PARAMS_VPP, 69 | PARAMS_TRANSCODE, 70 | PARAMS_DECVPP 71 | }; 72 | 73 | typedef struct _Params { 74 | mfxIMPL impl; 75 | #if (MFX_VERSION >= 2000) 76 | mfxVariant implValue; 77 | #endif 78 | 79 | char *infileName; 80 | char *inmodelName; 81 | int inBatchsize; 82 | int inRequest; 83 | 84 | mfxU16 srcWidth; 85 | mfxU16 srcHeight; 86 | } Params; 87 | 88 | static inline std::vector split_string(const std::string &input, char delimiter = ',') { 89 | std::vector tokens; 90 | std::string token; 91 | std::istringstream token_stream(input); 92 | while (std::getline(token_stream, token, delimiter)) { 93 | tokens.push_back(token); 94 | } 95 | return tokens; 96 | } 97 | 98 | char *ValidateFileName(char *in) { 99 | if (in) { 100 | if (strnlen(in, MAX_PATH) > MAX_PATH) 101 | return NULL; 102 | } 103 | 104 | return in; 105 | } 106 | 107 | bool ValidateSize(char *in, mfxU16 *vsize, mfxU32 vmax) { 108 | if (in) { 109 | *vsize = static_cast(strtol(in, NULL, 10)); 110 | if (*vsize <= vmax) 111 | return true; 112 | } 113 | 114 | *vsize = 0; 115 | return false; 116 | } 117 | 118 | bool ParseArgsAndValidate(int argc, char *argv[], Params *params, ParamGroup group) { 119 | int idx; 120 | char *s; 121 | 122 | // init all params to 0 123 | *params = {}; 124 | params->impl = MFX_IMPL_SOFTWARE; 125 | #if (MFX_VERSION >= 2000) 126 | params->implValue.Type = MFX_VARIANT_TYPE_U32; 127 | params->implValue.Data.U32 = MFX_IMPL_TYPE_SOFTWARE; 128 | #endif 129 | 130 | for (idx = 1; idx < argc;) { 131 | // all switches must start with '-' 132 | if (argv[idx][0] != '-') { 133 | printf("ERROR - invalid argument: %s\n", argv[idx]); 134 | return false; 135 | } 136 | 137 | // switch string, starting after the '-' 138 | s = &argv[idx][1]; 139 | idx++; 140 | 141 | // search for match 142 | if (IS_ARG_EQ(s, "i")) { 143 | params->infileName = ValidateFileName(argv[idx++]); 144 | if (!params->infileName) { 145 | return false; 146 | } 147 | } 148 | else if (IS_ARG_EQ(s, "m")) { 149 | params->inmodelName = ValidateFileName(argv[idx++]); 150 | if (!params->inmodelName) { 151 | return false; 152 | } 153 | } 154 | else if (IS_ARG_EQ(s, "bs")) { 155 | params->inBatchsize = int(*ValidateFileName(argv[idx++])); 156 | if (!params->inBatchsize) { 157 | return false; 158 | } 159 | } 160 | else if (IS_ARG_EQ(s, "nr")) { 161 | params->inRequest = int(*ValidateFileName(argv[idx++])); 162 | if (!params->inRequest) { 163 | return false; 164 | } 165 | } 166 | else if (IS_ARG_EQ(s, "w")) { 167 | if (!ValidateSize(argv[idx++], ¶ms->srcWidth, MAX_WIDTH)) 168 | return false; 169 | } 170 | else if (IS_ARG_EQ(s, "h")) { 171 | if (!ValidateSize(argv[idx++], ¶ms->srcHeight, MAX_HEIGHT)) 172 | return false; 173 | } 174 | else if (IS_ARG_EQ(s, "hw")) { 175 | params->impl = MFX_IMPL_HARDWARE; 176 | #if (MFX_VERSION >= 2000) 177 | params->implValue.Data.U32 = MFX_IMPL_TYPE_HARDWARE; 178 | #endif 179 | } 180 | else if (IS_ARG_EQ(s, "sw")) { 181 | params->impl = MFX_IMPL_SOFTWARE; 182 | #if (MFX_VERSION >= 2000) 183 | params->implValue.Data.U32 = MFX_IMPL_TYPE_SOFTWARE; 184 | #endif 185 | } 186 | } 187 | 188 | // input file required by all except createsession 189 | if ((group != PARAMS_CREATESESSION) && (!params->infileName)) { 190 | printf("ERROR - input file name (-i) is required\n"); 191 | return false; 192 | } 193 | 194 | // VPP and encode samples require an input resolution 195 | if ((PARAMS_VPP == group) || (PARAMS_ENCODE == group)) { 196 | if ((!params->srcWidth) || (!params->srcHeight)) { 197 | printf("ERROR - source width/height required\n"); 198 | return false; 199 | } 200 | } 201 | 202 | return true; 203 | } 204 | 205 | //Shows implementation info for Media SDK or oneVPL 206 | mfxVersion ShowImplInfo(mfxSession session) { 207 | mfxIMPL impl; 208 | mfxVersion version = { 0, 1 }; 209 | 210 | mfxStatus sts = MFXQueryIMPL(session, &impl); 211 | if (sts != MFX_ERR_NONE) 212 | return version; 213 | 214 | sts = MFXQueryVersion(session, &version); 215 | if (sts != MFX_ERR_NONE) 216 | return version; 217 | 218 | printf("Session loaded: ApiVersion = %d.%d \timpl= ", version.Major, version.Minor); 219 | 220 | switch (impl) { 221 | case MFX_IMPL_SOFTWARE: 222 | puts("Software"); 223 | break; 224 | case MFX_IMPL_HARDWARE | MFX_IMPL_VIA_VAAPI: 225 | puts("Hardware:VAAPI"); 226 | break; 227 | case MFX_IMPL_HARDWARE | MFX_IMPL_VIA_D3D11: 228 | puts("Hardware:D3D11"); 229 | break; 230 | case MFX_IMPL_HARDWARE | MFX_IMPL_VIA_D3D9: 231 | puts("Hardware:D3D9"); 232 | break; 233 | default: 234 | puts("Unknown"); 235 | break; 236 | } 237 | 238 | return version; 239 | } 240 | 241 | // Shows implementation info with oneVPL 242 | void ShowImplementationInfo(mfxLoader loader, mfxU32 implnum) { 243 | mfxImplDescription *idesc = nullptr; 244 | mfxStatus sts; 245 | //Loads info about implementation at specified list location 246 | sts = MFXEnumImplementations(loader, implnum, MFX_IMPLCAPS_IMPLDESCSTRUCTURE, (mfxHDL *)&idesc); 247 | if (!idesc || (sts != MFX_ERR_NONE)) 248 | return; 249 | 250 | printf("Implementation details:\n"); 251 | printf(" ApiVersion: %hu.%hu \n", idesc->ApiVersion.Major, idesc->ApiVersion.Minor); 252 | printf(" Implementation type: %s\n", (idesc->Impl == MFX_IMPL_TYPE_SOFTWARE) ? "SW" : "HW"); 253 | printf(" AccelerationMode via: "); 254 | switch (idesc->AccelerationMode) { 255 | case MFX_ACCEL_MODE_NA: 256 | printf("NA \n"); 257 | break; 258 | case MFX_ACCEL_MODE_VIA_D3D9: 259 | printf("D3D9\n"); 260 | break; 261 | case MFX_ACCEL_MODE_VIA_D3D11: 262 | printf("D3D11\n"); 263 | break; 264 | case MFX_ACCEL_MODE_VIA_VAAPI: 265 | printf("VAAPI\n"); 266 | break; 267 | case MFX_ACCEL_MODE_VIA_VAAPI_DRM_MODESET: 268 | printf("VAAPI_DRM_MODESET\n"); 269 | break; 270 | case MFX_ACCEL_MODE_VIA_VAAPI_GLX: 271 | printf("VAAPI_GLX\n"); 272 | break; 273 | case MFX_ACCEL_MODE_VIA_VAAPI_X11: 274 | printf("VAAPI_X11\n"); 275 | break; 276 | case MFX_ACCEL_MODE_VIA_VAAPI_WAYLAND: 277 | printf("VAAPI_WAYLAND\n"); 278 | break; 279 | case MFX_ACCEL_MODE_VIA_HDDLUNITE: 280 | printf("HDDLUNITE\n"); 281 | break; 282 | default: 283 | printf("unknown\n"); 284 | break; 285 | } 286 | MFXDispReleaseImplDescription(loader, idesc); 287 | 288 | #if (MFX_VERSION >= 2004) 289 | //Show implementation path, added in 2.4 API 290 | mfxHDL implPath = nullptr; 291 | sts = MFXEnumImplementations(loader, implnum, MFX_IMPLCAPS_IMPLPATH, &implPath); 292 | if (!implPath || (sts != MFX_ERR_NONE)) 293 | return; 294 | 295 | printf(" Path: %s\n\n", reinterpret_cast(implPath)); 296 | MFXDispReleaseImplDescription(loader, implPath); 297 | #endif 298 | } 299 | 300 | void PrepareFrameInfo(mfxFrameInfo *fi, mfxU32 format, mfxU16 w, mfxU16 h) { 301 | // Video processing input data format 302 | fi->FourCC = format; 303 | fi->ChromaFormat = MFX_CHROMAFORMAT_YUV420; 304 | fi->CropX = 0; 305 | fi->CropY = 0; 306 | fi->CropW = w; 307 | fi->CropH = h; 308 | fi->PicStruct = MFX_PICSTRUCT_PROGRESSIVE; 309 | fi->FrameRateExtN = 30; 310 | fi->FrameRateExtD = 1; 311 | // width must be a multiple of 16 312 | // height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture 313 | fi->Width = ALIGN16(fi->CropW); 314 | fi->Height = 315 | (MFX_PICSTRUCT_PROGRESSIVE == fi->PicStruct) ? ALIGN16(fi->CropH) : ALIGN32(fi->CropH); 316 | } 317 | 318 | mfxU32 GetSurfaceSize(mfxU32 FourCC, mfxU32 width, mfxU32 height) { 319 | mfxU32 nbytes = 0; 320 | 321 | switch (FourCC) { 322 | case MFX_FOURCC_I420: 323 | case MFX_FOURCC_NV12: 324 | nbytes = width * height + (width >> 1) * (height >> 1) + (width >> 1) * (height >> 1); 325 | break; 326 | case MFX_FOURCC_I010: 327 | case MFX_FOURCC_P010: 328 | nbytes = width * height + (width >> 1) * (height >> 1) + (width >> 1) * (height >> 1); 329 | nbytes *= 2; 330 | break; 331 | case MFX_FOURCC_RGB4: 332 | nbytes = width * height * 4; 333 | break; 334 | default: 335 | break; 336 | } 337 | 338 | return nbytes; 339 | } 340 | 341 | int GetFreeSurfaceIndex(mfxFrameSurface1 *SurfacesPool, mfxU16 nPoolSize) { 342 | for (mfxU16 i = 0; i < nPoolSize; i++) { 343 | if (0 == SurfacesPool[i].Data.Locked) 344 | return i; 345 | } 346 | return MFX_ERR_NOT_FOUND; 347 | } 348 | 349 | mfxStatus AllocateExternalSystemMemorySurfacePool(mfxU8 **buf, 350 | mfxFrameSurface1 *surfpool, 351 | mfxFrameInfo frame_info, 352 | mfxU16 surfnum) { 353 | // initialize surface pool (I420, RGB4 format) 354 | mfxU32 surfaceSize = GetSurfaceSize(frame_info.FourCC, frame_info.Width, frame_info.Height); 355 | if (!surfaceSize) 356 | return MFX_ERR_MEMORY_ALLOC; 357 | 358 | size_t framePoolBufSize = static_cast(surfaceSize) * surfnum; 359 | *buf = reinterpret_cast(calloc(framePoolBufSize, 1)); 360 | 361 | mfxU16 surfW; 362 | mfxU16 surfH = frame_info.Height; 363 | 364 | if (frame_info.FourCC == MFX_FOURCC_RGB4) { 365 | surfW = frame_info.Width * 4; 366 | 367 | for (mfxU32 i = 0; i < surfnum; i++) { 368 | surfpool[i] = { 0 }; 369 | surfpool[i].Info = frame_info; 370 | size_t buf_offset = static_cast(i) * surfaceSize; 371 | surfpool[i].Data.B = *buf + buf_offset; 372 | surfpool[i].Data.G = surfpool[i].Data.B + 1; 373 | surfpool[i].Data.R = surfpool[i].Data.B + 2; 374 | surfpool[i].Data.A = surfpool[i].Data.B + 3; 375 | surfpool[i].Data.Pitch = surfW; 376 | } 377 | } 378 | else { 379 | surfW = (frame_info.FourCC == MFX_FOURCC_P010) ? frame_info.Width * 2 : frame_info.Width; 380 | 381 | for (mfxU32 i = 0; i < surfnum; i++) { 382 | surfpool[i] = { 0 }; 383 | surfpool[i].Info = frame_info; 384 | size_t buf_offset = static_cast(i) * surfaceSize; 385 | surfpool[i].Data.Y = *buf + buf_offset; 386 | surfpool[i].Data.U = *buf + buf_offset + (surfW * surfH); 387 | surfpool[i].Data.V = surfpool[i].Data.U + ((surfW / 2) * (surfH / 2)); 388 | surfpool[i].Data.Pitch = surfW; 389 | } 390 | } 391 | 392 | return MFX_ERR_NONE; 393 | } 394 | 395 | 396 | // Read encoded stream from file 397 | mfxStatus ReadEncodedStream(mfxBitstream &bs, FILE *f) { 398 | mfxU8 *p0 = bs.Data; 399 | mfxU8 *p1 = bs.Data + bs.DataOffset; 400 | if (bs.DataOffset > bs.MaxLength - 1) { 401 | return MFX_ERR_NOT_ENOUGH_BUFFER; 402 | } 403 | if (bs.DataLength + bs.DataOffset > bs.MaxLength) { 404 | return MFX_ERR_NOT_ENOUGH_BUFFER; 405 | } 406 | for (mfxU32 i = 0; i < bs.DataLength; i++) { 407 | *(p0++) = *(p1++); 408 | } 409 | bs.DataOffset = 0; 410 | bs.DataLength += (mfxU32)fread(bs.Data + bs.DataLength, 1, bs.MaxLength - bs.DataLength, f); 411 | if (bs.DataLength == 0) 412 | return MFX_ERR_MORE_DATA; 413 | 414 | return MFX_ERR_NONE; 415 | } 416 | 417 | // Write encoded stream to file 418 | void WriteEncodedStream(mfxBitstream &bs, FILE *f) { 419 | fwrite(bs.Data + bs.DataOffset, 1, bs.DataLength, f); 420 | bs.DataLength = 0; 421 | return; 422 | } 423 | 424 | // Load raw I420 frames to mfxFrameSurface 425 | mfxStatus ReadRawFrame(mfxFrameSurface1 *surface, FILE *f) { 426 | mfxU16 w, h, i, pitch; 427 | size_t bytes_read; 428 | mfxU8 *ptr; 429 | mfxFrameInfo *info = &surface->Info; 430 | mfxFrameData *data = &surface->Data; 431 | 432 | w = info->Width; 433 | h = info->Height; 434 | 435 | switch (info->FourCC) { 436 | case MFX_FOURCC_I420: 437 | // read luminance plane (Y) 438 | pitch = data->Pitch; 439 | ptr = data->Y; 440 | for (i = 0; i < h; i++) { 441 | bytes_read = (mfxU32)fread(ptr + i * pitch, 1, w, f); 442 | if (w != bytes_read) 443 | return MFX_ERR_MORE_DATA; 444 | } 445 | 446 | // read chrominance (U, V) 447 | pitch /= 2; 448 | h /= 2; 449 | w /= 2; 450 | ptr = data->U; 451 | for (i = 0; i < h; i++) { 452 | bytes_read = (mfxU32)fread(ptr + i * pitch, 1, w, f); 453 | if (w != bytes_read) 454 | return MFX_ERR_MORE_DATA; 455 | } 456 | 457 | ptr = data->V; 458 | for (i = 0; i < h; i++) { 459 | bytes_read = (mfxU32)fread(ptr + i * pitch, 1, w, f); 460 | if (w != bytes_read) 461 | return MFX_ERR_MORE_DATA; 462 | } 463 | break; 464 | case MFX_FOURCC_NV12: 465 | // Y 466 | pitch = data->Pitch; 467 | for (i = 0; i < h; i++) { 468 | bytes_read = fread(data->Y + i * pitch, 1, w, f); 469 | if (w != bytes_read) 470 | return MFX_ERR_MORE_DATA; 471 | } 472 | // UV 473 | h /= 2; 474 | for (i = 0; i < h; i++) { 475 | bytes_read = fread(data->UV + i * pitch, 1, w, f); 476 | if (w != bytes_read) 477 | return MFX_ERR_MORE_DATA; 478 | } 479 | break; 480 | case MFX_FOURCC_RGB4: 481 | // Y 482 | pitch = data->Pitch; 483 | for (i = 0; i < h; i++) { 484 | bytes_read = fread(data->B + i * pitch, 1, pitch, f); 485 | if (pitch != bytes_read) 486 | return MFX_ERR_MORE_DATA; 487 | } 488 | break; 489 | default: 490 | printf("Unsupported FourCC code, skip LoadRawFrame\n"); 491 | break; 492 | } 493 | 494 | return MFX_ERR_NONE; 495 | } 496 | 497 | #if (MFX_VERSION >= 2000) 498 | mfxStatus ReadRawFrame_InternalMem(mfxFrameSurface1 *surface, FILE *f) { 499 | bool is_more_data = false; 500 | 501 | // Map makes surface writable by CPU for all implementations 502 | mfxStatus sts = surface->FrameInterface->Map(surface, MFX_MAP_WRITE); 503 | if (sts != MFX_ERR_NONE) { 504 | printf("mfxFrameSurfaceInterface->Map failed (%d)\n", sts); 505 | return sts; 506 | } 507 | 508 | sts = ReadRawFrame(surface, f); 509 | if (sts != MFX_ERR_NONE) { 510 | if (sts == MFX_ERR_MORE_DATA) 511 | is_more_data = true; 512 | else 513 | return sts; 514 | } 515 | 516 | // Unmap/release returns local device access for all implementations 517 | sts = surface->FrameInterface->Unmap(surface); 518 | if (sts != MFX_ERR_NONE) { 519 | printf("mfxFrameSurfaceInterface->Unmap failed (%d)\n", sts); 520 | return sts; 521 | } 522 | 523 | return (is_more_data == true) ? MFX_ERR_MORE_DATA : MFX_ERR_NONE; 524 | } 525 | #endif 526 | 527 | // Write raw I420 frame to file 528 | mfxStatus WriteRawFrame(mfxFrameSurface1 *surface, FILE *f) { 529 | mfxU16 w, h, i, pitch; 530 | mfxFrameInfo *info = &surface->Info; 531 | mfxFrameData *data = &surface->Data; 532 | 533 | w = info->Width; 534 | h = info->Height; 535 | 536 | // write the output to disk 537 | switch (info->FourCC) { 538 | case MFX_FOURCC_I420: 539 | // Y 540 | pitch = data->Pitch; 541 | for (i = 0; i < h; i++) { 542 | fwrite(data->Y + i * pitch, 1, w, f); 543 | } 544 | // U 545 | pitch /= 2; 546 | h /= 2; 547 | w /= 2; 548 | for (i = 0; i < h; i++) { 549 | fwrite(data->U + i * pitch, 1, w, f); 550 | } 551 | // V 552 | for (i = 0; i < h; i++) { 553 | fwrite(data->V + i * pitch, 1, w, f); 554 | } 555 | break; 556 | case MFX_FOURCC_NV12: 557 | // Y 558 | pitch = data->Pitch; 559 | for (i = 0; i < h; i++) { 560 | fwrite(data->Y + i * pitch, 1, w, f); 561 | } 562 | // UV 563 | h /= 2; 564 | for (i = 0; i < h; i++) { 565 | fwrite(data->UV + i * pitch, 1, w, f); 566 | } 567 | break; 568 | case MFX_FOURCC_RGB4: 569 | // Y 570 | pitch = data->Pitch; 571 | for (i = 0; i < h; i++) { 572 | fwrite(data->B + i * pitch, 1, pitch, f); 573 | } 574 | break; 575 | default: 576 | return MFX_ERR_UNSUPPORTED; 577 | break; 578 | } 579 | 580 | return MFX_ERR_NONE; 581 | } 582 | 583 | #if (MFX_VERSION >= 2000) 584 | // Write raw frame to file 585 | mfxStatus WriteRawFrame_InternalMem(mfxFrameSurface1 *surface, FILE *f) { 586 | mfxStatus sts = surface->FrameInterface->Map(surface, MFX_MAP_READ); 587 | if (sts != MFX_ERR_NONE) { 588 | printf("mfxFrameSurfaceInterface->Map failed (%d)\n", sts); 589 | return sts; 590 | } 591 | 592 | sts = WriteRawFrame(surface, f); 593 | if (sts != MFX_ERR_NONE) { 594 | printf("Error in WriteRawFrame\n"); 595 | return sts; 596 | } 597 | 598 | sts = surface->FrameInterface->Unmap(surface); 599 | if (sts != MFX_ERR_NONE) { 600 | printf("mfxFrameSurfaceInterface->Unmap failed (%d)\n", sts); 601 | return sts; 602 | } 603 | 604 | sts = surface->FrameInterface->Release(surface); 605 | if (sts != MFX_ERR_NONE) { 606 | printf("mfxFrameSurfaceInterface->Release failed (%d)\n", sts); 607 | return sts; 608 | } 609 | 610 | return sts; 611 | } 612 | #endif 613 | 614 | #endif //EXAMPLES_UTIL_H_ --------------------------------------------------------------------------------