Video and Vision Processing Suite Intel® FPGA IP User Guide
A newer version of this document is available. Customers should click here to go to the newest version.
Visible to Intel only — GUID: orr1625154557551
Ixiasoft
Visible to Intel only — GUID: orr1625154557551
Ixiasoft
32.5.2. Warp IP Software Code Examples
UHD 60 Hz Workflow example
This example shows the workflow and basic warp software usage of the C++ source code to generate and apply 15 degree rotation warp. The example is for 3840x2160@60Hz video, which requires the processing to be split between two warp engines. The frame buffer and warp coefficient base addresses in the example are arbitrary. Actual values depend on your particular system design.
const uint32_t FRAMEBUF_BASE_ADDR = 0x80000000; const uint32_t COEF_BASE_ADDR = 0xa0000000; intel_vvp_warp_base_t base = INTEL_VVP_WARP_BASE; intel_vvp_warp_instance_t wrp0; // Warp data sizes should be multiples of 256kb auto align_256k = [](const uint32_t addr)->uint32_t { static const uint32_t DATA_SIZE_256KB = (256 * 1024); return ((addr + DATA_SIZE_256KB - 1) & ~(DATA_SIZE_256KB - 1)); }; // Initialize driver instance intel_vvp_warp_init_instance(&wrp0, base); intel_vvp_warp_channel_t* ch0 = intel_vvp_warp_create_double_channel(&wrp0, 0, 0, 1, 0); // Fill in warp channel configuration structure intel_vvp_warp_channel_config_t cfg; cfg.ram_addr = FRAMEBUF_BASE_ADDR; // Frame buffers base address cfg.cs = ERGB_FULL; // Video colourspace cfg.scan = EMEGABLOCK; // Scan pattern cfg.width_input = 3840; // Video dimensions cfg.height_input = 2160; cfg.width_output = 3840; cfg.height_output = 2160; cfg.lfr = 0; // No low frame rate fallback // Configure warp channel using the parameters above intel_vvp_warp_configure_channel(ch0, &cfg); // Instantiate and initialize mesh generator WarpConfigurator configurator; configurator.SetInputResolution(3840, 2160); configurator.SetOutputResolution(3840, 2160); configurator.Reset(); configurator.SetRotate(15.0f); // Generate mesh WarpMeshPtr mesh = configurator.GenerateMeshFromFixed(); WarpMeshSet mesh_set{ mesh }; // Instantiate data generator WarpDataGenerator data_generator; // Obtain required hardware information WarpHwContextPtr hw = WarpDataHelper::GetHwContext(ch0); WarpDataContext ctx{ hw, 3840, 2160, 3840, 2160 }; // Generate warp data using provided hardware configuration and mesh WarpDataPtr user_data = data_generator.GenerateData(ctx, mesh_set); // Allocate and fill in intel_vvp_warp_data_t object for the required number of engines const uint32_t warp_data_size = sizeof(intel_vvp_warp_data_t) + user_data->GetEngines() * sizeof(intel_vvp_warp_engine_data_t); intel_vvp_warp_data_t* warp_data = (intel_vvp_warp_data_t*)malloc(warp_data_size); warp_data->num_engines = user_data->GetEngines(); intel_vvp_warp_engine_data_t* engine_data = warp_data->engine_data; const uint32_t mesh_stride = ctx._engine_mesh_stride / 4 - 1; // Mesh nodes in multiples of 4 less 1 // Processing is split between two engines // 1st engine processes left half of the frame { engine_data[0].start_h = 0; engine_data[0].start_v = 0; engine_data[0].end_h = ctx._engine_hblocks - 1; engine_data[0].end_v = ctx._vblocks_out - 1; engine_data[0].mesh_stride = mesh_stride; const WarpEngineData* ue = user_data->GetEngineData(0); const uint32_t mesh_data_size = ue->GetMeshEntries() * sizeof(mesh_entry_t); const uint32_t filter_data_size = ue->GetFilterEntries() * sizeof(filter_entry_t); const uint32_t fetch_data_size = ue->GetFilterEntries() * sizeof(fetch_entry_t); // Point engine to the location of the mesh, filter and fetch data engine_data[0].mesh_addr = COEF_BASE_ADDR; engine_data[0].filter_addr = engine_data[0].mesh_addr + align_256k(mesh_data_size); engine_data[0].fetch_addr = engine_data[0].filter_addr + align_256k(filter_data_size); // Transfer generated warp data to the calculated destination memcpy((void*)(engine_data[0].mesh_addr), ue->GetMeshData(), mesh_data_size); memcpy((void*)(engine_data[0].filter_addr), ue->GetFilterData(), filter_data_size); memcpy((void*)(engine_data[0].fetch_addr), ue->GetFetchData(), fetch_data_size); } // 2nd engine - right half of the frame { engine_data[1].start_h = ctx._engine_hblocks; engine_data[1].start_v = 0; engine_data[1].end_h = ctx._hblocks_out - 1; engine_data[1].end_v = ctx._vblocks_out - 1; engine_data[1].mesh_stride = mesh_stride; const WarpEngineData* ue = user_data->GetEngineData(1); const uint32_t mesh_data_size = ue->GetMeshEntries() * sizeof(mesh_entry_t); const uint32_t filter_data_size = ue->GetFilterEntries() * sizeof(filter_entry_t); const uint32_t fetch_data_size = ue->GetFetchEntries() * sizeof(fetch_entry_t); // Point engine to the location of the mesh, filter and fetch data engine_data[1].mesh_addr = engine_data[0].fetch_addr + align_256k(user_data->GetEngineData(0)->_fetch_entries * sizeof(fetch_entry_t)); engine_data[1].filter_addr = engine_data[1].mesh_addr + align_256k(mesh_data_size); engine_data[1].fetch_addr = engine_data[1].filter_addr + align_256k(filter_data_size); // Transfer generated warp data to the calculated destination memcpy((void*)(engine_data[1].mesh_addr), ue->GetMeshData(), mesh_data_size); memcpy((void*)(engine_data[1].filter_addr), ue->GetFilterData(), filter_data_size); memcpy((void*)(engine_data[1].fetch_addr), ue->GetFetchData(), fetch_data_size); } warp_data->_skip_megablock_data = user_data->GetSkipMegablockData(); warp_data->_skip_ram_page = 0; // Apply warp by passing new warp data set to the driver intel_vvp_warp_apply_transform(ch0, warp_data); // Release allocated resources free(warp_data); intel_vvp_warp_free_channel(ch0);
Warp mesh usage
Define required warp using the WarpMesh object. The example shows the simplest case of 1:1 (unity) warp for a 3840x2160 video.
intel_vvp_warp::WarpMesh mesh{3840, 2160}; for(uint32_t v = 0; v < mesh.GetVNodes(); ++v) { mesh_node_t* node = mesh.GetRow(v); for(uint32_t h = 0; h < mesh.GetHNodes(); ++h) { node->_x = (h * mesh.GetStep()) << 4; node->_y = (v * mesh.GetStep()) << 4; } }
Mesh coordinates use the least significant four bits as fractional part for subpixel precision. In the example above the fractional part is always 0. Store subpixel positions in the following way:
mesh_node_t* node = mesh.GetRow(v); … float pos_x = 10.6f; node->_x = static_cast<int32_t>(roundf(pos_x * 16.0f));
Easy warp example
When you turn on Easy warp you can rotate the input video to 0, 90, 180 or 270 degrees or mirror the video without the need of transform mesh and associated warp data.
const uint32_t FRAMEBUF_BASE_ADDR = 0x80000000; const uint32_t width = 1920; const uint32_t height = 1080; intel_vvp_warp_base_t base = INTEL_VVP_WARP_BASE; intel_vvp_warp_instance wrp0; // Initialize driver instance intel_vvp_warp_init_instance(&wrp0, base); // Allocate Easy warp channel intel_vvp_warp_channel_t* ch0 = intel_vvp_warp_create_easy_warp_channel(&wrp0, 0, 0); assert(ch0 != NULL); assert(intel_vvp_warp_check_easy_warp_capable(ch0) == 0); // Configure channel intel_vvp_warp_channel_config_t cfg; // Configure in 4K, RGB Full colourspace cfg.ram_addr = FRAMEBUF_BASE_ADDR; cfg.cs = ERGB_FULL; cfg.width_input = width; cfg.height_input = height; cfg.width_output = width; cfg.height_output = height; cfg.lfr = 0; intel_vvp_warp_configure_channel(ch0, &cfg); // Mirror input video // Enable video bypass, keep original resolution intel_vvp_warp_bypass(ch0, 1, 0, width, height); // Configure Easy warp mirror intel_vvp_warp_set_easy_warp(ch0, 0x4); // Rotate input video 90 degrees CCW // Enable video bypass, flip input width and height intel_vvp_warp_bypass(ch0, 1, 0, height, width); // Configure Easy warp rotation intel_vvp_warp_set_easy_warp(ch0, 0x01); // Release warp channel intel_vvp_warp_free_channel(ch0); assert(wrp0.num_engines > 0);
Warp latency parameters generation example
The example shows how to generate recommended minimum latency parameters for a given video transformation. These parameters are necessary to configure video pipeline for low latency operation.
// Example video and system clock static constexpr uint32_t EXAMPLE_CLOCK = 300000000; // UHD video dimensions static constexpr uint32_t WIDTH_UHD = 3840; static constexpr uint32_t HEIGHT_UHD = 2160; static constexpr uint32_t FULL_HEIGHT_UHD = 2250; // Output frame rate x100 static constexpr uint32_t OUTPUT_FRAME_RATE = 6000; // In this example system and video clock are the same const uint32_t system_clock = EXAMPLE_CLOCK; const uint32_t video_clock = EXAMPLE_CLOCK; // Warp channel intel_vvp_warp_channel_t* ch0{nullptr}; // Allocate and initialize a warp channel here // ... ////////////////////////////////////////////// // Generate a 4K mesh for 5 degree CCW rotation WarpConfigurator configurator{WarpDataHelper::GetHwContext(ch0)}; configurator.SetInputResolution(WIDTH_UHD, HEIGHT_UHD); configurator.SetOutputResolution(WIDTH_UHD, HEIGHT_UHD); configurator.Reset(); configurator.SetRotate(5.0f); WarpMeshSet mesh_set{configurator.GenerateMeshFromFixed()}; // Parameters required for warp data generation WarpDataContext ctx{ WarpDataHelper::GetHwContext(ch0), WIDTH_UHD, HEIGHT_UHD, WIDTH_UHD, HEIGHT_UHD }; WarpDataGenerator data_generator; WarpDataPtr user_data = data_generator.GenerateData(ctx, mesh_set); // Obtain latency params for the configured warp WarpLatencyParams latency_params = data_generator.GenerateLatencyParams(ctx, user_data, system_clock, video_clock, FULL_HEIGHT_UHD, OUTPUT_FRAME_RATE); // Upload and apply generated warp data here // … // intel_vvp_warp_apply_transform(ch0, …); // … // Pass on “output_latency” to the driver intel_vvp_warp_set_output_latency(ch0, latency_params._output_latency); // The “total_latency” member represents the recommended minimum offset // between the input and output frames // The value is in axi4s_vid_out_0_clock clock cycles // Use the this parameter to configure the rest of the video pipeline // as appropriate // // latency_params._total_latency; //assert(wrp0.num_engines > 0);