| /* |
| * * Copyright (C) 2018 Intel Corporation. All Rights Reserved. |
| * * |
| ** Permission is hereby granted, free of charge, to any person obtaining a |
| * * copy of this software and associated documentation files (the |
| * * "Software"), to deal in the Software without restriction, including |
| * * without limitation the rights to use, copy, modify, merge, publish, |
| * * distribute, sub license, and/or sell copies of the Software, and to |
| * * permit persons to whom the Software is furnished to do so, subject to |
| * * the following conditions: |
| * * |
| * * The above copyright notice and this permission notice (including the |
| * * next paragraph) shall be included in all copies or substantial portions |
| * * of the Software. |
| * * |
| * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * */ |
| |
| |
| /** |
| * @file VDecAccelVA.cpp |
| * @brief LibVA decode accelerator implementation. |
| */ |
| |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <sys/mman.h> |
| #include <sys/ioctl.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <iostream> |
| #include <assert.h> |
| #include <algorithm> |
| #include <string.h> |
| #include "VDecAccelVA.h" |
| #include <va/va.h> |
| #include <va/va_drm.h> |
| |
| #define VASUCCEEDED(err) (err == VA_STATUS_SUCCESS) |
| #define VAFAILED(err) (err != VA_STATUS_SUCCESS) |
| |
| mvaccel::VDecAccelVAImpl::VDecAccelVAImpl(void* device) |
| : m_vaDisplay(0) |
| , m_vaProfile(VAProfileNone) |
| , m_vaEntrypoint(VAEntrypointVLD) |
| , m_vaConfigID(0) |
| , m_vaContextID(0) |
| , m_surfaceType(VA_RT_FORMAT_YUV420) |
| { |
| if (device) |
| m_vaDisplay = *(reinterpret_cast<VADisplay*>(device)); |
| |
| if (!m_vaDisplay) |
| { |
| printf("Invalid VADisplay\n"); |
| delete this; |
| return; |
| } |
| } |
| |
| mvaccel::VDecAccelVAImpl::VDecAccelVAImpl() |
| : m_vaDisplay(0) |
| , m_vaProfile(VAProfileNone) |
| , m_vaEntrypoint(VAEntrypointVLD) |
| , m_vaConfigID(0) |
| , m_vaContextID(0) |
| , m_surfaceType(VA_RT_FORMAT_YUV420) |
| { |
| } |
| |
| mvaccel::VDecAccelVAImpl::~VDecAccelVAImpl() |
| { |
| if (drm_fd != -1) { |
| close(drm_fd); |
| } |
| } |
| |
| |
| int mvaccel::VDecAccelVAImpl::Open() |
| { |
| VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN; |
| |
| //get display device |
| int MajorVer, MinorVer; |
| |
| if (vaStatus != VA_STATUS_SUCCESS) { |
| drm_fd = open("/dev/dri/renderD128", O_RDWR); |
| if (drm_fd >= 0) { |
| m_vaDisplay = vaGetDisplayDRM(drm_fd); |
| vaStatus = vaInitialize(m_vaDisplay, &MajorVer, &MinorVer); |
| } |
| } |
| |
| //initialize decode description |
| create_decode_desc(); |
| |
| m_vaProfile = VAProfileH264Main; |
| |
| // We only support VLD currently |
| m_vaEntrypoint = VAEntrypointVLD; |
| |
| int count = 0; |
| count = vaMaxNumEntrypoints(m_vaDisplay); |
| assert(count); |
| |
| std::vector<VAEntrypoint> vaEntrypoints(count); |
| vaStatus = vaQueryConfigEntrypoints( |
| m_vaDisplay, |
| m_vaProfile, |
| &vaEntrypoints[0], |
| &count); |
| if(VAFAILED(vaStatus)) |
| printf("vaQueryConfigEntrypoints fail\n"); |
| |
| std::vector<VAEntrypoint>::iterator it = std::find(vaEntrypoints.begin(), vaEntrypoints.end(), m_vaEntrypoint); |
| if (it == vaEntrypoints.end()) |
| { |
| if(VAFAILED(vaStatus)) |
| printf("VAEntrypoint is not found\n"); |
| return 1; |
| } |
| |
| if (!is_config_compatible(m_DecodeDesc)) |
| { |
| if(VAFAILED(vaStatus)) |
| printf("Decode configuration is not compatible\n"); |
| return 1; |
| } |
| |
| // Setup config attributes |
| std::vector<VAConfigAttrib> vaAttribs; |
| prepare_config_attribs(m_DecodeDesc, vaAttribs); |
| // Create config |
| vaStatus = vaCreateConfig( |
| m_vaDisplay, |
| m_vaProfile, |
| m_vaEntrypoint, |
| &vaAttribs.at(0), |
| vaAttribs.size(), |
| &m_vaConfigID |
| ); |
| if(VAFAILED(vaStatus)) |
| printf("vaCreateConfig fail\n"); |
| |
| if (!is_rt_foramt_supported(m_DecodeDesc)) |
| { |
| if(VAFAILED(vaStatus)) |
| printf("Render target is not supported\n"); |
| return 1; |
| } |
| |
| // Calculate aligned width/height for gfx surface |
| uint32_t aligned_width = m_DecodeDesc.width; |
| uint32_t aligned_height = m_DecodeDesc.height; |
| |
| // Setup surface attributes |
| prepare_surface_attribs(m_DecodeDesc, m_vaSurfAttribs, false); |
| // Create surfaces |
| for (uint32_t i=0; i<m_DecodeDesc.surfaces_num; i++) |
| { |
| VASurfaceID vaID = VA_INVALID_SURFACE; |
| vaStatus = vaCreateSurfaces( |
| m_vaDisplay, |
| m_surfaceType, |
| aligned_width, |
| aligned_height, |
| &vaID, |
| 1, |
| &(m_vaSurfAttribs.at(0)), |
| m_vaSurfAttribs.size() |
| ); |
| |
| if (VASUCCEEDED(vaStatus)) |
| m_vaIDs.push_back(vaID); |
| } |
| |
| // Check if surfaces created is equal to requested. |
| if (m_vaIDs.size() != m_DecodeDesc.surfaces_num) |
| { |
| if(VAFAILED(vaStatus)) |
| printf("Create surface fail\n"); |
| return 1; |
| } |
| |
| // Create context |
| vaStatus = vaCreateContext( |
| m_vaDisplay, |
| m_vaConfigID, |
| aligned_width, |
| aligned_height, |
| VA_PROGRESSIVE, |
| &(m_vaIDs.at(0)), |
| m_vaIDs.size(), |
| &m_vaContextID |
| ); |
| if(VAFAILED(vaStatus)) |
| printf("vaCreateContext fail\n"); |
| |
| check_process_pipeline_caps(m_DecodeDesc); |
| |
| return vaStatus; |
| } |
| |
| void mvaccel::VDecAccelVAImpl::Close() |
| { |
| std::vector<VASurfaceID>::iterator it; |
| for (it = m_vaIDs.begin(); it != m_vaIDs.end(); ++it) |
| delete_surface(*it); |
| |
| vaDestroyConfig(m_vaDisplay, m_vaConfigID); |
| vaDestroyContext(m_vaDisplay, m_vaContextID); |
| |
| m_images.clear(); |
| m_vaIDs.clear(); |
| m_vaSurfAttribs.clear(); |
| |
| m_vaConfigID = 0; |
| m_vaContextID = 0; |
| } |
| |
| uint32_t mvaccel::VDecAccelVAImpl::GetSurfaceID(uint32_t index) |
| { |
| assert(index < m_vaIDs.size()); |
| return m_vaIDs[index]; |
| } |
| |
| /** |
| * @brief Check if video decode acceleration description is supported. |
| * @param cc Video decode acceleration description. |
| * @return true if supported, false if not. |
| */ |
| bool mvaccel::VDecAccelVAImpl::is_config_compatible(DecodeDesc& desc) |
| { |
| if (!is_slice_mode_supported(desc)) |
| return false; |
| |
| if (!is_encryption_supported(desc)) |
| return false; |
| |
| if(!is_sfc_config_supported(desc)) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * @brief Check if long or short format is supported not not. |
| * @param cc Video decode acceleration description. |
| * @return true if supported, false if not. |
| */ |
| bool mvaccel::VDecAccelVAImpl::is_slice_mode_supported(DecodeDesc& desc) |
| { |
| VAConfigAttrib vaAttrib; |
| memset(&vaAttrib, 0, sizeof(vaAttrib)); |
| vaAttrib.type = VAConfigAttribDecSliceMode; |
| vaAttrib.value = 0; |
| |
| vaGetConfigAttributes( |
| m_vaDisplay, |
| m_vaProfile, |
| m_vaEntrypoint, |
| &vaAttrib, |
| 1); |
| |
| if(vaAttrib.value & VA_DEC_SLICE_MODE_BASE || vaAttrib.value & VA_DEC_SLICE_MODE_NORMAL) |
| return true; |
| else |
| return false; |
| } |
| |
| /** |
| * @brief Check if encryption is supported or not. |
| * @param cc Video decode acceleration description. |
| * @return true if supported, false if not. |
| */ |
| bool mvaccel::VDecAccelVAImpl::is_encryption_supported(DecodeDesc& desc) |
| { |
| VAConfigAttrib vaAttrib; |
| memset(&vaAttrib, 0, sizeof(vaAttrib)); |
| vaAttrib.type = VAConfigAttribEncryption; |
| vaAttrib.value = 0; |
| |
| vaGetConfigAttributes( |
| m_vaDisplay, |
| m_vaProfile, |
| m_vaEntrypoint, |
| &vaAttrib, |
| 1 |
| ); |
| if(vaAttrib.value & VA_ATTRIB_NOT_SUPPORTED) |
| return true; |
| else |
| return false; |
| } |
| |
| /** |
| * @brief Check if SFC attribute is supported or not. |
| * @param cc Video decode acceleration description. |
| * @return true if supported, false if not. |
| */ |
| bool mvaccel::VDecAccelVAImpl::is_sfc_config_supported(DecodeDesc& desc) |
| { |
| // SFC attribute check |
| VAConfigAttrib vaAttrib; |
| memset(&vaAttrib, 0, sizeof(vaAttrib)); |
| vaAttrib.type = VAConfigAttribDecProcessing; |
| vaAttrib.value = 0; |
| |
| vaGetConfigAttributes( |
| m_vaDisplay, |
| m_vaProfile, |
| m_vaEntrypoint, |
| &vaAttrib, |
| 1); |
| |
| if (vaAttrib.value != VA_DEC_PROCESSING) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * @brief Check if render target format is supported or not. |
| * @param cc Video decode acceleration description. |
| * @return true if supported, false if not. |
| */ |
| bool mvaccel::VDecAccelVAImpl::is_rt_foramt_supported(DecodeDesc& desc) |
| { |
| uint32_t count = VASurfaceAttribCount + vaMaxNumImageFormats(m_vaDisplay); |
| std::vector<VASurfaceAttrib> attribs(count); |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| vaStatus = vaQuerySurfaceAttributes( |
| m_vaDisplay, |
| m_vaConfigID, |
| &attribs.at(0), |
| &count |
| ); |
| if (VAFAILED(vaStatus)) |
| { |
| printf("vaQuerySurfaceAttributes failed\n"); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @brief Prepare config attribs VAContext creation. |
| * @param desc Video decode acceleration description. |
| * @param vaAttribs Array of VASurfaceAttrib which will contains the attrib. |
| */ |
| void mvaccel::VDecAccelVAImpl::prepare_config_attribs( |
| DecodeDesc& desc, |
| VAConfigAttribArray& attribs) |
| { |
| VAConfigAttrib attrib; |
| memset(&attrib, 0, sizeof(attrib)); |
| |
| // RT formats |
| attrib.type = VAConfigAttribRTFormat; |
| attrib.value = VA_RT_FORMAT_YUV420; |
| attribs.push_back(attrib); |
| |
| // Slice Mode |
| attrib.type = VAConfigAttribDecSliceMode; |
| attrib.value = VA_DEC_SLICE_MODE_NORMAL; |
| attribs.push_back(attrib); |
| |
| //dec processing attribs |
| attrib.type = VAConfigAttribDecProcessing; |
| attrib.value = VA_DEC_PROCESSING; |
| attribs.push_back(attrib); |
| } |
| |
| /** |
| * @brief Prepare the VA surface attribs for creation. |
| * @param desc Video decode acceleration description. |
| * @param vaSurfAttribs Array of VASurfaceAttrib which will contains attrib. |
| */ |
| void mvaccel::VDecAccelVAImpl::prepare_surface_attribs( |
| DecodeDesc& desc, |
| VASurfaceAttribArray& attribs, |
| bool bDecodeDownsamplingHinted) |
| { |
| VASurfaceAttrib attrib; |
| memset(&attrib, 0, sizeof(attrib)); |
| |
| attrib.type = VASurfaceAttribPixelFormat; |
| attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; |
| attrib.value.type = VAGenericValueTypeInteger; |
| |
| // VA_FOURCC and MVFOURCC are interchangeable |
| if(bDecodeDownsamplingHinted) |
| attrib.value.value.i = VA_FOURCC_ARGB; |
| else |
| attrib.value.value.i = VA_FOURCC_NV12; |
| |
| attribs.push_back(attrib); |
| } |
| |
| /** |
| * @brief Delete allocated surface |
| * @param surfaceID Index of allocated surface. After delete, the surface |
| * values will be set to invalid value. |
| */ |
| void mvaccel::VDecAccelVAImpl::delete_surface(VASurfaceID& vaID) |
| { |
| // Make sure no others is using this surface |
| if (m_images.count(vaID)) |
| m_images.erase(m_images.find(vaID)); |
| |
| vaDestroySurfaces(m_vaDisplay, &vaID, 1); |
| vaID = VA_INVALID_SURFACE; |
| } |
| |
| uint8_t* mvaccel::VDecAccelVAImpl::lock_surface(VASurfaceID id, bool write) |
| { |
| // Check if decode is completed |
| VAStatus status = vaSyncSurface(m_vaDisplay, id); |
| if (VAFAILED(status)) |
| { |
| printf("vaSyncSurface Error.\n"); |
| return NULL; |
| } |
| |
| //sync decode surface |
| VASurfaceStatus surf_status = VASurfaceSkipped; |
| for(;;) |
| { |
| vaQuerySurfaceStatus(m_vaDisplay, id, &surf_status); |
| if (surf_status != VASurfaceRendering && |
| surf_status != VASurfaceDisplaying) |
| break; |
| } |
| |
| if (surf_status != VASurfaceReady) |
| { |
| printf("Surface is not ready by vaQueryStatusSurface"); |
| return NULL; |
| } |
| |
| uint8_t* buffer = NULL; |
| //map the decoded buffer |
| for(;;) |
| { |
| status = vaDeriveImage(m_vaDisplay, id, &m_images[id]); |
| if (VAFAILED(status)) |
| printf("vaDeriveImage fail. \n"); |
| |
| status = vaMapBuffer(m_vaDisplay, m_images[id].buf, (void**)&buffer); |
| if (VAFAILED(status)) |
| printf("vaDeriveImage fail. \n"); |
| |
| break; |
| } |
| |
| if (VAFAILED(status)) |
| { |
| status = vaUnmapBuffer(m_vaDisplay, m_images[id].buf); |
| status = vaDestroyImage(m_vaDisplay, m_images[id].image_id); |
| } |
| return buffer; |
| } |
| |
| void mvaccel::VDecAccelVAImpl::unlock_surface(VASurfaceID id) |
| { |
| VAStatus status = vaUnmapBuffer(m_vaDisplay, m_images[id].buf); |
| assert(VASUCCEEDED(status)); |
| |
| status = vaDestroyImage(m_vaDisplay, m_images[id].image_id); |
| assert(VASUCCEEDED(status)); |
| } |
| |
| //prepare basic format/resolution parameter |
| void mvaccel::VDecAccelVAImpl::create_decode_desc() |
| { |
| m_DecodeDesc.format = VA_FOURCC_NV12; |
| m_DecodeDesc.sfcformat = VA_FOURCC_ARGB; |
| m_DecodeDesc.width = 352; |
| m_DecodeDesc.height = 288; |
| m_DecodeDesc.sfc_widht = 176; |
| m_DecodeDesc.sfc_height = 144; |
| m_DecodeDesc.surfaces_num = 2; |
| } |
| |
| bool mvaccel::VDecAccelVAImpl::DecodePicture() |
| { |
| // Create addition surfaces for scaled video output |
| if (m_sfcIDs.empty()) |
| { |
| if (create_resources()) |
| return 1; |
| } |
| |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| VAContextID vaContextID = 0; |
| VASurfaceID vaID = 0; |
| |
| //va begin picture |
| vaStatus = vaBeginPicture(m_vaDisplay, m_vaContextID, vaID); |
| if (VAFAILED(vaStatus)) |
| printf("vaBeginPicture fail."); |
| |
| // Set Context ID for End Picture |
| vaContextID = m_vaContextID; |
| |
| std::vector<VABufferID> vaBufferIDs; |
| // Pic parameters buffers |
| VABufferID vaBufferID; |
| vaStatus = vaCreateBuffer( m_vaDisplay, |
| m_vaContextID, |
| VAPictureParameterBufferType, |
| sizeof(g_PicParams_AVC), |
| 1, |
| (uint8_t*)g_PicParams_AVC, |
| &vaBufferID ); |
| assert(VASUCCEEDED(vaStatus)); |
| if (VASUCCEEDED(vaStatus)) |
| vaBufferIDs.push_back(vaBufferID); |
| |
| // IQ matrics |
| vaStatus = vaCreateBuffer( m_vaDisplay, |
| m_vaContextID, |
| VAIQMatrixBufferType, |
| sizeof(g_Qmatrix_AVC), |
| 1, |
| (uint8_t*)g_Qmatrix_AVC, |
| &vaBufferID ); |
| assert(VASUCCEEDED(vaStatus)); |
| if (VASUCCEEDED(vaStatus)) |
| vaBufferIDs.push_back(vaBufferID); |
| |
| //slice parameter buffers |
| vaStatus = vaCreateBuffer(m_vaDisplay, |
| m_vaContextID, |
| VASliceParameterBufferType, |
| sizeof(g_SlcParams_AVC), |
| 1, |
| (uint8_t*)g_SlcParams_AVC, |
| &vaBufferID ); |
| assert(VASUCCEEDED(vaStatus)); |
| if (VASUCCEEDED(vaStatus)) |
| vaBufferIDs.push_back(vaBufferID); |
| |
| //BITSTREAM buffers |
| vaStatus = vaCreateBuffer(m_vaDisplay, |
| m_vaContextID, |
| VASliceDataBufferType, |
| sizeof(g_Bitstream_AVC), |
| 1, |
| (uint8_t*)g_Bitstream_AVC, |
| &vaBufferID ); |
| assert(VASUCCEEDED(vaStatus)); |
| if (VASUCCEEDED(vaStatus)) |
| vaBufferIDs.push_back(vaBufferID); |
| |
| //PROC_PIPELINE buffers |
| vaStatus = vaCreateBuffer(m_vaDisplay, |
| m_vaContextID, |
| VAProcPipelineParameterBufferType, |
| sizeof(m_vaProcBuffer), |
| 1, |
| (uint8_t*)&m_vaProcBuffer, |
| &vaBufferID ); |
| assert(VASUCCEEDED(vaStatus)); |
| if (VASUCCEEDED(vaStatus)) |
| vaBufferIDs.push_back(vaBufferID); |
| |
| if (vaBufferIDs.size()) |
| { |
| vaStatus = vaRenderPicture( |
| m_vaDisplay, |
| m_vaContextID, |
| &(vaBufferIDs.at(0)), |
| vaBufferIDs.size()); |
| } |
| |
| //va end picture |
| vaStatus = vaEndPicture(m_vaDisplay, vaContextID); |
| if (VAFAILED(vaStatus)) |
| printf("vaEndPicture fail."); |
| |
| //lock surface |
| uint8_t* gfx_surface_buf = lock_surface(m_sfcIDs[0], false); |
| if (gfx_surface_buf == NULL) |
| { |
| printf("Fail to lock gfx surface\n"); |
| return 1; |
| } |
| |
| //write to yuv file |
| FILE* sfc_stream = fopen("sfc_sample_176_144_argb.yuv", "wb"); |
| uint32_t file_size = m_DecodeDesc.sfc_widht * m_DecodeDesc.sfc_height * 4; //ARGB format |
| if (sfc_stream) { |
| fwrite(gfx_surface_buf, file_size, 1, sfc_stream); |
| fclose(sfc_stream); |
| } |
| |
| //unlock surface and clear |
| unlock_surface(m_sfcIDs[0]); |
| Close(); |
| |
| return (VASUCCEEDED(vaStatus) ? 0 : 1); |
| } |
| |
| // check vaQueryVideoProcPipelineCaps |
| int mvaccel::VDecAccelVAImpl::check_process_pipeline_caps(DecodeDesc& desc) |
| { |
| VAProcPipelineCaps caps; |
| |
| VAProcColorStandardType inputCST[VAProcColorStandardCount]; |
| VAProcColorStandardType outputCST[VAProcColorStandardCount]; |
| caps.input_color_standards = inputCST; |
| caps.output_color_standards = outputCST; |
| |
| m_in4CC.resize(vaMaxNumImageFormats(m_vaDisplay)); |
| m_out4CC.resize(vaMaxNumImageFormats(m_vaDisplay)); |
| caps.input_pixel_format = &m_in4CC.at(0); |
| caps.output_pixel_format = &m_out4CC.at(0); |
| |
| VABufferID filterIDs[VAProcFilterCount]; |
| uint32_t filterCount = 0; |
| |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| vaStatus = vaQueryVideoProcPipelineCaps( |
| m_vaDisplay, |
| m_vaContextID, |
| filterIDs, |
| filterCount, |
| &caps |
| ); |
| if (VAFAILED(vaStatus)) |
| { |
| printf("vaQueryVideoProcPipelineCaps fail\n"); |
| return 1; |
| } |
| |
| m_in4CC.resize(caps.num_input_pixel_formats); |
| m_out4CC.resize(caps.num_output_pixel_formats); |
| |
| return 0; |
| } |
| |
| int mvaccel::VDecAccelVAImpl::create_resources() |
| { |
| if (m_sfcIDs.empty()) |
| m_sfcIDs.resize(1); |
| |
| // Create addition surfaces for scaled video output |
| uint16_t width = m_DecodeDesc.sfc_widht; |
| uint16_t height = m_DecodeDesc.sfc_height; |
| |
| //prepare sfc surface attribs |
| DecodeDesc SfcDesc; |
| SfcDesc.sfcformat = VA_FOURCC('A','R','G','B'); |
| VASurfaceAttribArray Sfc_vaSurfAttribs; |
| prepare_surface_attribs(SfcDesc, Sfc_vaSurfAttribs, true); |
| |
| uint32_t surfaceType = m_surfaceType; |
| m_surfaceType = (uint32_t)SfcDesc.sfcformat; |
| |
| for(uint32_t i = 0; i < m_sfcIDs.size(); i++) |
| { |
| vaCreateSurfaces( |
| m_vaDisplay, |
| m_surfaceType, |
| width, |
| height, |
| &m_sfcIDs[i], |
| 1, |
| &(Sfc_vaSurfAttribs.at(0)), |
| Sfc_vaSurfAttribs.size() |
| ); |
| } |
| m_surfaceType = surfaceType; |
| m_rectSFC.x = m_rectSFC.y = 0; |
| m_rectSFC.width = width; |
| m_rectSFC.height = height; |
| |
| // Prepare VAProcPipelineParameterBuffer for decode |
| VAProcPipelineParameterBuffer buffer; |
| memset(&buffer, 0, sizeof(buffer)); |
| |
| m_rectSrc.x = m_rectSrc.y = 0; |
| m_rectSrc.width = (uint16_t)m_DecodeDesc.width; |
| m_rectSrc.height = (uint16_t)m_DecodeDesc.height; |
| |
| buffer.surface_region = &m_rectSrc; |
| buffer.output_region = &m_rectSFC; |
| buffer.additional_outputs = (VASurfaceID*)&(m_sfcIDs[0]); |
| buffer.num_additional_outputs = 1; |
| m_vaProcBuffer = buffer; |
| |
| return 0; |
| } |