diff --git a/src/rocdecode/roc_decoder.cpp b/src/rocdecode/roc_decoder.cpp index cee07324a8..4d853cb80d 100644 --- a/src/rocdecode/roc_decoder.cpp +++ b/src/rocdecode/roc_decoder.cpp @@ -77,11 +77,15 @@ rocDecStatus RocDecoder::GetDecodeStatus(int pic_idx, RocdecDecodeStatus* decode } rocDecStatus RocDecoder::ReconfigureDecoder(RocdecReconfigureDecoderInfo *reconfig_params) { - // todo:: return appropriate decStatus - // this will be called when the current configuration is changed during decoding - // release the current va-api decoder instance and create a new one with the new parameters (or reinit if available) - // return status - return ROCDEC_NOT_IMPLEMENTED; + if (reconfig_params == nullptr) { + return ROCDEC_INVALID_PARAMETER; + } + rocDecStatus rocdec_status = va_video_decoder_.ReconfigureDecoder(reconfig_params); + if (rocdec_status != ROCDEC_SUCCESS) { + ERR("ERROR: Reconfiguration of the decoder failed with rocDecStatus# " + TOSTR(rocdec_status)); + return rocdec_status; + } + return rocdec_status; } rocDecStatus RocDecoder::MapVideoFrame(int pic_idx, void *dev_mem_ptr[3], uint32_t horizontal_pitch[3], RocdecProcParams *vid_postproc_params) { diff --git a/src/rocdecode/rocdecode_api.cpp b/src/rocdecode/rocdecode_api.cpp index c127a6d2ff..f6939e7c57 100644 --- a/src/rocdecode/rocdecode_api.cpp +++ b/src/rocdecode/rocdecode_api.cpp @@ -143,6 +143,9 @@ rocDecGetDecodeStatus(rocDecDecoderHandle decoder_handle, int pic_idx, RocdecDec /*********************************************************************************************************/ rocDecStatus ROCDECAPI rocDecReconfigureDecoder(rocDecDecoderHandle decoder_handle, RocdecReconfigureDecoderInfo *reconfig_params) { + if (decoder_handle == nullptr || reconfig_params == nullptr) { + return ROCDEC_INVALID_PARAMETER; + } auto handle = static_cast (decoder_handle); rocDecStatus ret; try { diff --git a/src/rocdecode/vaapi/vaapi_videodecoder.cpp b/src/rocdecode/vaapi/vaapi_videodecoder.cpp index 70f0260944..a9ae347ed4 100644 --- a/src/rocdecode/vaapi/vaapi_videodecoder.cpp +++ b/src/rocdecode/vaapi/vaapi_videodecoder.cpp @@ -323,3 +323,44 @@ rocDecStatus VaapiVideoDecoder::ExportSurface(int pic_idx, VADRMPRIMESurfaceDesc return ROCDEC_SUCCESS; } + +rocDecStatus VaapiVideoDecoder::ReconfigureDecoder(RocdecReconfigureDecoderInfo *reconfig_params) { + if (reconfig_params == nullptr) { + return ROCDEC_INVALID_PARAMETER; + } + if (va_display_ == 0) { + ERR("ERROR: VAAPI decoder has not been initialized but reconfiguration of the decoder has been requested!"); + return ROCDEC_NOT_SUPPORTED; + } + rocDecStatus rocdec_status = DestroyDataBuffers(); + if (rocdec_status != ROCDEC_SUCCESS) { + ERR("ERROR: Failed to destroy VAAPI buffers during the reconfiguration, with rocDecStatus# " + TOSTR(rocdec_status)); + return rocdec_status; + } + CHECK_VAAPI(vaDestroySurfaces(va_display_, va_surface_ids_.data(), va_surface_ids_.size())); + CHECK_VAAPI(vaDestroyContext(va_display_, va_context_id_)); + + va_surface_ids_.clear(); + decoder_create_info_.ulWidth = reconfig_params->ulWidth; + decoder_create_info_.ulHeight = reconfig_params->ulHeight; + decoder_create_info_.ulNumDecodeSurfaces = reconfig_params->ulNumDecodeSurfaces; + decoder_create_info_.ulTargetHeight = reconfig_params->ulTargetHeight; + decoder_create_info_.ulTargetWidth = reconfig_params->ulTargetWidth; + + rocdec_status = CreateSurfaces(); + if (rocdec_status != ROCDEC_SUCCESS) { + ERR("ERROR: Failed to create VAAPI surfaces during the decoder reconfiguration " + TOSTR(rocdec_status)); + return rocdec_status; + } + rocdec_status = CreateContext(); + if (rocdec_status != ROCDEC_SUCCESS) { + ERR("ERROR: Failed to create a VAAPI context during the decoder reconfiguration " + TOSTR(rocdec_status)); + return rocdec_status; + } + rocdec_status = CreateDataBuffers(); + if (rocdec_status != ROCDEC_SUCCESS) { + ERR("ERROR: Failed to create VAAPI buffers during the decoder reconfiguration " + TOSTR(rocdec_status)); + return rocdec_status; + } + return rocdec_status; +} \ No newline at end of file diff --git a/src/rocdecode/vaapi/vaapi_videodecoder.h b/src/rocdecode/vaapi/vaapi_videodecoder.h index d924a3c9f7..7f23a21ef3 100644 --- a/src/rocdecode/vaapi/vaapi_videodecoder.h +++ b/src/rocdecode/vaapi/vaapi_videodecoder.h @@ -52,7 +52,7 @@ public: rocDecStatus SubmitDecode(RocdecPicParams *pPicParams); rocDecStatus GetDecodeStatus(int pic_idx, RocdecDecodeStatus* decode_status); rocDecStatus ExportSurface(int pic_idx, VADRMPRIMESurfaceDescriptor &va_drm_prime_surface_desc); - + rocDecStatus ReconfigureDecoder(RocdecReconfigureDecoderInfo *reconfig_params); private: RocDecoderCreateInfo decoder_create_info_; int drm_fd_; diff --git a/utils/rocvideodecode/roc_video_dec.cpp b/utils/rocvideodecode/roc_video_dec.cpp index 98b285875a..844b66b286 100644 --- a/utils/rocvideodecode/roc_video_dec.cpp +++ b/utils/rocvideodecode/roc_video_dec.cpp @@ -270,10 +270,8 @@ int RocVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) { } if (width_ && height_ && chroma_height_) { - // rocdecCreateDecoder() has been called before, and now there's possible config change - // todo:: support reconfigure - //return ReconfigureDecoder(p_video_format); + return ReconfigureDecoder(p_video_format); } // e_codec has been set in the constructor (for parser). Here it's set again for potential correction @@ -395,10 +393,108 @@ int RocVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) { return nDecodeSurface; } - +/** + * @brief function to reconfigure decoder if there is a change in sequence params. + * + * @param p_video_format + * @return int 1: success 0: fail + */ int RocVideoDecoder::ReconfigureDecoder(RocdecVideoFormat *p_video_format) { - ROCDEC_THROW("ReconfigureDecoder is not supported in this version: ", ROCDEC_NOT_SUPPORTED); - return ROCDEC_NOT_SUPPORTED; + if (p_video_format->codec != codec_id_) { + ROCDEC_THROW("Reconfigure Not supported for codec change", ROCDEC_NOT_SUPPORTED); + return 0; + } + if (p_video_format->chroma_format != video_chroma_format_) { + ROCDEC_THROW("Reconfigure Not supported for chroma format change", ROCDEC_NOT_SUPPORTED); + return 0; + } + if (p_video_format->bit_depth_luma_minus8 != bitdepth_minus_8_){ + ROCDEC_THROW("Reconfigure Not supported for bit depth change", ROCDEC_NOT_SUPPORTED); + return 0; + } + + bool is_decode_res_changed = !(p_video_format->coded_width == width_ && p_video_format->coded_height == height_); + bool is_display_rect_changed = !(p_video_format->display_area.bottom == disp_rect_.b && + p_video_format->display_area.top == disp_rect_.t && + p_video_format->display_area.left == disp_rect_.l && + p_video_format->display_area.right == disp_rect_.r); + if (!is_decode_res_changed) { + // if the coded_width and coded_height hasn't changed but display resolution has changed, then need to update width and height for + // correct output without cropping. There is no need to reconfigure the decoder. + if (is_display_rect_changed) { + width_ = p_video_format->display_area.right - p_video_format->display_area.left; + height_ = p_video_format->display_area.bottom - p_video_format->display_area.top; + chroma_height_ = static_cast(std::ceil(height_ * GetChromaHeightFactor(video_surface_format_))); + num_chroma_planes_ = GetChromaPlaneCount(video_surface_format_); + } + return 1; + } + + width_ = p_video_format->coded_width; + height_ = p_video_format->coded_height; + + RocdecReconfigureDecoderInfo reconfig_params = {0}; + reconfig_params.ulWidth = width_; + reconfig_params.ulHeight = height_; + reconfig_params.ulTargetWidth = (width_ + 1) & ~1; + reconfig_params.ulTargetHeight = (height_ + 1) & ~1; + reconfig_params.ulNumDecodeSurfaces = p_video_format->min_num_decode_surfaces; + reconfig_params.roi_area.left = crop_rect_.l; + reconfig_params.roi_area.top = crop_rect_.t; + reconfig_params.roi_area.right = crop_rect_.r; + reconfig_params.roi_area.bottom = crop_rect_.b; + reconfig_params.target_rect.left = p_video_format->display_area.left; + reconfig_params.target_rect.top = p_video_format->display_area.top; + reconfig_params.target_rect.right = p_video_format->display_area.right; + reconfig_params.target_rect.bottom = p_video_format->display_area.bottom; + + if (out_mem_type_ == OUT_SURFACE_MEM_DEV_INTERNAL) { + GetSurfaceStrideInternal(video_surface_format_, p_video_format->coded_width, p_video_format->coded_height, &surface_stride_, &surface_vstride_); + } else { + surface_stride_ = reconfig_params.ulTargetWidth * byte_per_pixel_; + } + chroma_vstride_ = static_cast(std::ceil(surface_vstride_ * GetChromaHeightFactor(video_surface_format_))); + // fill output_surface_info_ + output_surface_info_.output_width = width_; + output_surface_info_.output_height = height_; + output_surface_info_.output_pitch = surface_stride_; + output_surface_info_.output_vstride = (out_mem_type_ == OUT_SURFACE_MEM_DEV_INTERNAL) ? surface_vstride_ : reconfig_params.ulTargetHeight; + output_surface_info_.bit_depth = bitdepth_minus_8_ + 8; + output_surface_info_.bytes_per_pixel = byte_per_pixel_; + output_surface_info_.surface_format = video_surface_format_; + output_surface_info_.num_chroma_planes = num_chroma_planes_; + if (out_mem_type_ == OUT_SURFACE_MEM_DEV_INTERNAL) { + output_surface_info_.output_surface_size_in_bytes = surface_stride_ * (surface_vstride_ + (chroma_vstride_ * num_chroma_planes_)); + output_surface_info_.mem_type = OUT_SURFACE_MEM_DEV_INTERNAL; + } else if (out_mem_type_ == OUT_SURFACE_MEM_DEV_COPIED) { + output_surface_info_.output_surface_size_in_bytes = GetFrameSizePitched(); + output_surface_info_.mem_type = OUT_SURFACE_MEM_DEV_COPIED; + } else { + output_surface_info_.output_surface_size_in_bytes = GetFrameSize(); + output_surface_info_.mem_type = OUT_SURFACE_MEM_HOST_COPIED; + } + + if (roc_decoder_ == nullptr) { + ROCDEC_THROW("Reconfigurition of the decoder detected but the decoder was not initialized previoulsy!", ROCDEC_NOT_SUPPORTED); + return 0; + } + ROCDEC_API_CALL(rocDecReconfigureDecoder(roc_decoder_, &reconfig_params)); + + input_video_info_str_.str(""); + input_video_info_str_.clear(); + input_video_info_str_ << "Input Video Resolution Changed:" << std::endl + << "\tCoded size : [" << p_video_format->coded_width << ", " << p_video_format->coded_height << "]" << std::endl + << "\tDisplay area : [" << p_video_format->display_area.left << ", " << p_video_format->display_area.top << ", " + << p_video_format->display_area.right << ", " << p_video_format->display_area.bottom << "]" << std::endl; + input_video_info_str_ << std::endl; + input_video_info_str_ << "Video Decoding Params:" << std::endl + << "\tNum Surfaces : " << reconfig_params.ulNumDecodeSurfaces << std::endl + << "\tResize : " << reconfig_params.ulTargetWidth << "x" << reconfig_params.ulTargetHeight << std::endl + ; + input_video_info_str_ << std::endl; + std::cout << input_video_info_str_.str(); + + return 1; } /** @@ -650,7 +746,6 @@ bool RocVideoDecoder::ReleaseFrame(int64_t pTimestamp) { return true; } - void RocVideoDecoder::SaveFrameToFile(std::string output_file_name, void *surf_mem, OutputSurfaceInfo *surf_info) { uint8_t *hst_ptr = nullptr; uint64_t output_image_size = surf_info->output_surface_size_in_bytes; diff --git a/utils/rocvideodecode/roc_video_dec.h b/utils/rocvideodecode/roc_video_dec.h index ecb9353273..a3acc571f2 100644 --- a/utils/rocvideodecode/roc_video_dec.h +++ b/utils/rocvideodecode/roc_video_dec.h @@ -384,16 +384,16 @@ class RocVideoDecoder { std::ostringstream input_video_info_str_; int bitdepth_minus_8_ = 0; uint32_t byte_per_pixel_ = 1; - uint32_t width_; - uint32_t height_; - int max_width_, max_height_; - uint32_t chroma_height_; - uint32_t num_chroma_planes_; - uint32_t num_components_; - uint32_t surface_stride_; - uint32_t surface_vstride_, chroma_vstride_; // vertical stride between planes: used when using internal dev memory - size_t surface_size_; - OutputSurfaceInfo output_surface_info_; + uint32_t width_ = 0; + uint32_t height_ = 0; + int max_width_ = 0, max_height_ = 0; + uint32_t chroma_height_ = 0; + uint32_t num_chroma_planes_ = 0; + uint32_t num_components_ = 0; + uint32_t surface_stride_ = 0; + uint32_t surface_vstride_ = 0, chroma_vstride_ = 0; // vertical stride between planes: used when using internal dev memory + size_t surface_size_ = 0; + OutputSurfaceInfo output_surface_info_ = {}; std::mutex mtx_vp_frame_; std::vector vp_frames_; // vector of decoded frames std::queue vp_frames_q_;