diff --git a/api/rocdecode.h b/api/rocdecode.h index ecff11567d..04ebf9f730 100644 --- a/api/rocdecode.h +++ b/api/rocdecode.h @@ -513,6 +513,7 @@ typedef struct _RocdecHevcIQMatrix { */ uint8_t ScalingListDC32x32[2]; + uint32_t reserved[4]; } RocdecHevcIQMatrix; /***********************************************************/ @@ -631,6 +632,8 @@ typedef struct _RocdecHevcPicParams { * short_term_ref_pic_set( num_short_term_ref_pic_sets ) structure. */ uint32_t st_rps_bits; + + uint32_t reserved[8]; } RocdecHevcPicParams; /***********************************************************/ @@ -724,6 +727,8 @@ typedef struct _RocdecHevcSliceParams { uint16_t entry_offset_to_subset_array; /** \brief Number of emulation prevention bytes in slice header. */ uint16_t slice_data_num_emu_prevn_bytes; + + uint32_t reserved[2]; } RocdecHevcSliceParams; /******************************************************************************************/ diff --git a/src/rocdecode/vaapi/vaapi_videodecoder.cpp b/src/rocdecode/vaapi/vaapi_videodecoder.cpp index 9d4d038873..140bd9ded3 100644 --- a/src/rocdecode/vaapi/vaapi_videodecoder.cpp +++ b/src/rocdecode/vaapi/vaapi_videodecoder.cpp @@ -30,6 +30,7 @@ VaapiVideoDecoder::~VaapiVideoDecoder() { close(drm_fd_); } if (va_display_) { + DestroyDataBuffers(); vaDestroySurfaces(va_display_, va_surface_ids_.data(), va_surface_ids_.size()); if (va_context_id_) vaDestroyContext(va_display_, va_context_id_); @@ -73,6 +74,11 @@ rocDecStatus VaapiVideoDecoder::InitializeDecoder(std::string gcn_arch_name) { ERR("ERROR: Failed to create a VAAPI context " + TOSTR(rocdec_status)); return rocdec_status; } + rocdec_status = CreateDataBuffers(); + if (rocdec_status != ROCDEC_SUCCESS) { + ERR("ERROR: Failed to create VAAPI data buffers " + TOSTR(rocdec_status)); + return rocdec_status; + } return rocdec_status; } @@ -148,8 +154,116 @@ rocDecStatus VaapiVideoDecoder::CreateContext() { return ROCDEC_SUCCESS; } +rocDecStatus VaapiVideoDecoder::CreateDataBuffers() { + switch (decoder_create_info_.CodecType) { + case rocDecVideoCodec_HEVC: { + // Create picture parameter buffer + CHECK_VAAPI(vaCreateBuffer(va_display_, va_context_id_, VAPictureParameterBufferType, sizeof(VAPictureParameterBufferHEVC), 1, NULL, &pic_params_buf_id_)); + // Create inverse quantization matrix buffer + CHECK_VAAPI(vaCreateBuffer(va_display_, va_context_id_, VAIQMatrixBufferType, sizeof(VAIQMatrixBufferHEVC), 1, NULL, &iq_matrix_buf_id_)); + // Create slice parameter buffer + CHECK_VAAPI(vaCreateBuffer(va_display_, va_context_id_, VASliceParameterBufferType, sizeof(VASliceParameterBufferHEVC), 1, NULL, &slice_params_buf_id_)); + // Creat slice data buffer with the default size (2MB) + slice_data_buf_size_ = DEFAULT_SLICE_DATA_BUF_SIZE; + CHECK_VAAPI(vaCreateBuffer(va_display_, va_context_id_, VASliceDataBufferType, slice_data_buf_size_, 1, NULL, &slice_data_buf_id_)); + break; + } + + default: { + ERR("ERROR: the codec type is not supported!"); + return ROCDEC_NOT_SUPPORTED; + } + } + + return ROCDEC_SUCCESS; +} + +rocDecStatus VaapiVideoDecoder::DestroyDataBuffers() { + CHECK_VAAPI(vaDestroyBuffer(va_display_, pic_params_buf_id_)); + CHECK_VAAPI(vaDestroyBuffer(va_display_, iq_matrix_buf_id_)); + CHECK_VAAPI(vaDestroyBuffer(va_display_, slice_params_buf_id_)); + CHECK_VAAPI(vaDestroyBuffer(va_display_, slice_data_buf_id_)); + return ROCDEC_SUCCESS; +} + rocDecStatus VaapiVideoDecoder::SubmitDecode(RocdecPicParams *pPicParams) { - // Todo copy pic param, slice param, IQ matrix and slice data from RocdecPicParams to VAAPI struct buffers, then submit to VAAPI driver. + uint8_t *pic_params_ptr, *iq_matrix_ptr, *slice_params_ptr; + uint32_t pic_params_size, iq_matrix_size, slice_params_size; + bool scaling_list_enabled = true; + uint8_t *data_buf_ptr; + VASurfaceID curr_surface_id; + + // Get the surface id for the current picture, assuming 1:1 mapping between DPB and VAAPI decoded surfaces. + if (pPicParams->CurrPicIdx >= va_surface_ids_.size()) { + ERR("CurrPicIdx exceeded the VAAPI surface pool limit."); + return ROCDEC_INVALID_PARAMETER; + } + curr_surface_id = va_surface_ids_[pPicParams->CurrPicIdx]; + + // Upload data buffers + switch (decoder_create_info_.CodecType) { + case rocDecVideoCodec_HEVC: { + pPicParams->pic_params.hevc.cur_pic.PicIdx = curr_surface_id; + pic_params_ptr = (uint8_t*)&pPicParams->pic_params.hevc; + pic_params_size = sizeof(RocdecHevcPicParams); + + if (pPicParams->pic_params.hevc.pic_fields.bits.scaling_list_enabled_flag) { + scaling_list_enabled = true; + iq_matrix_ptr = (uint8_t*)&pPicParams->iq_matrix.hevc; + iq_matrix_size = sizeof(RocdecHevcIQMatrix); + } + else { + scaling_list_enabled = false; + } + + slice_params_ptr = (uint8_t*)&pPicParams->slice_params.hevc; + slice_params_size = sizeof(RocdecHevcSliceParams); + break; + } + + default: { + ERR("ERROR: the codec type is not supported!"); + return ROCDEC_NOT_SUPPORTED; + } + } + + /****************************************************************************** + * Note: make sure the structs in RocdecPicParams match VA-API structs, or we + * have to assign fields one by one. + ******************************************************************************/ + CHECK_VAAPI(vaMapBuffer(va_display_, pic_params_buf_id_, (void**)&data_buf_ptr)); + memcpy(data_buf_ptr, pic_params_ptr, pic_params_size); + CHECK_VAAPI(vaUnmapBuffer(va_display_, pic_params_buf_id_)); + + if (scaling_list_enabled) { + CHECK_VAAPI(vaMapBuffer(va_display_, iq_matrix_buf_id_, (void**)&data_buf_ptr)); + memcpy(data_buf_ptr, iq_matrix_ptr, iq_matrix_size); + CHECK_VAAPI(vaUnmapBuffer(va_display_, iq_matrix_buf_id_)); + } + + CHECK_VAAPI(vaMapBuffer(va_display_, slice_params_buf_id_, (void**)&data_buf_ptr)); + memcpy(data_buf_ptr, slice_params_ptr, slice_params_size); + CHECK_VAAPI(vaUnmapBuffer(va_display_, slice_params_buf_id_)); + + if ( pPicParams->nBitstreamDataLen > slice_data_buf_size_) { + CHECK_VAAPI(vaDestroyBuffer(va_display_, slice_data_buf_id_)); + slice_data_buf_size_ = pPicParams->nBitstreamDataLen * 3 / 2; // to reduce the chance to re-allocate again. + CHECK_VAAPI(vaCreateBuffer(va_display_, va_context_id_, VASliceDataBufferType, slice_data_buf_size_, 1, NULL, &slice_data_buf_id_)); + } + CHECK_VAAPI(vaMapBuffer(va_display_, slice_data_buf_id_, (void**)&data_buf_ptr)); + memcpy(data_buf_ptr, pPicParams->pBitstreamData, pPicParams->nBitstreamDataLen); + CHECK_VAAPI(vaUnmapBuffer(va_display_, slice_data_buf_id_)); + + // Sumbmit buffers to VAAPI driver + CHECK_VAAPI(vaBeginPicture(va_display_, va_context_id_, curr_surface_id)); + CHECK_VAAPI(vaRenderPicture(va_display_, va_context_id_, &pic_params_buf_id_, 1)); + if (scaling_list_enabled) { + CHECK_VAAPI(vaRenderPicture(va_display_, va_context_id_, &iq_matrix_buf_id_, 1)); + } + CHECK_VAAPI(vaRenderPicture(va_display_, va_context_id_, &slice_params_buf_id_, 1)); + CHECK_VAAPI(vaRenderPicture(va_display_, va_context_id_, &slice_data_buf_id_, 1)); + CHECK_VAAPI(vaEndPicture(va_display_, va_context_id_)); + return ROCDEC_SUCCESS; } diff --git a/src/rocdecode/vaapi/vaapi_videodecoder.h b/src/rocdecode/vaapi/vaapi_videodecoder.h index e8da580bb3..d7aa5bd2e0 100644 --- a/src/rocdecode/vaapi/vaapi_videodecoder.h +++ b/src/rocdecode/vaapi/vaapi_videodecoder.h @@ -34,6 +34,7 @@ THE SOFTWARE. #include "../../commons.h" #include "../../../api/rocdecode.h" +#define DEFAULT_SLICE_DATA_BUF_SIZE 2 * 1024 * 1024 // 2 MB #define CHECK_VAAPI(call) { \ VAStatus va_status = (call); \ @@ -61,8 +62,17 @@ private: VAProfile va_profile_; VAContextID va_context_id_; std::vector va_surface_ids_; + + VABufferID pic_params_buf_id_; + VABufferID iq_matrix_buf_id_; + VABufferID slice_params_buf_id_; + VABufferID slice_data_buf_id_; + uint32_t slice_data_buf_size_; + rocDecStatus InitVAAPI(std::string drm_node); rocDecStatus CreateDecoderConfig(); rocDecStatus CreateSurfaces(); rocDecStatus CreateContext(); + rocDecStatus CreateDataBuffers(); + rocDecStatus DestroyDataBuffers(); }; \ No newline at end of file