2023-09-08 08:55:16 +08:00
|
|
|
/*******************************************************************************
|
2026-06-10 15:17:15 +08:00
|
|
|
* Copyright (c) 2023 Orbbec 3D Technology, Inc
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*******************************************************************************/
|
2023-09-08 08:55:16 +08:00
|
|
|
|
2023-08-25 21:47:13 +08:00
|
|
|
#include "orbbec_camera/rk_mpp_decoder.h"
|
|
|
|
|
#include <rclcpp/rclcpp.hpp>
|
|
|
|
|
|
|
|
|
|
namespace orbbec_camera {
|
|
|
|
|
|
2023-09-07 16:46:59 +08:00
|
|
|
RKJPEGDecoder::RKJPEGDecoder(int width, int height) : JPEGDecoder(width, height) {
|
2023-08-27 16:14:34 +08:00
|
|
|
rgb_buffer_ = new uint8_t[width_ * height_ * 3];
|
2023-08-25 21:47:13 +08:00
|
|
|
MPP_RET ret = mpp_create(&mpp_ctx_, &mpp_api_);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"), "mpp_create failed, ret = " << ret);
|
|
|
|
|
throw std::runtime_error("mpp_create failed");
|
|
|
|
|
}
|
|
|
|
|
MpiCmd mpi_cmd = MPP_CMD_BASE;
|
|
|
|
|
MppParam mpp_param = nullptr;
|
|
|
|
|
|
|
|
|
|
mpi_cmd = MPP_DEC_SET_PARSER_SPLIT_MODE;
|
|
|
|
|
mpp_param = &need_split_;
|
|
|
|
|
ret = mpp_api_->control(mpp_ctx_, mpi_cmd, mpp_param);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"),
|
|
|
|
|
"mpp_api_->control failed, ret = " << ret);
|
|
|
|
|
throw std::runtime_error("mpp_api_->control failed");
|
|
|
|
|
}
|
|
|
|
|
ret = mpp_init(mpp_ctx_, MPP_CTX_DEC, MPP_VIDEO_CodingMJPEG);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"), "mpp_init failed, ret = " << ret);
|
|
|
|
|
throw std::runtime_error("mpp_init failed");
|
|
|
|
|
}
|
|
|
|
|
MppFrameFormat fmt = MPP_FMT_YUV420SP_VU;
|
|
|
|
|
mpp_param = &fmt;
|
|
|
|
|
ret = mpp_api_->control(mpp_ctx_, MPP_DEC_SET_OUTPUT_FORMAT, mpp_param);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"),
|
|
|
|
|
"mpp_api_->control failed, ret = " << ret);
|
|
|
|
|
throw std::runtime_error("mpp_api_->control failed");
|
|
|
|
|
}
|
|
|
|
|
ret = mpp_frame_init(&mpp_frame_);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"),
|
|
|
|
|
"mpp_frame_init failed, ret = " << ret);
|
|
|
|
|
throw std::runtime_error("mpp_frame_init failed");
|
|
|
|
|
}
|
|
|
|
|
ret = mpp_buffer_group_get_internal(&mpp_frame_group_, MPP_BUFFER_TYPE_ION);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"),
|
|
|
|
|
"mpp_buffer_group_get_internal failed, ret = " << ret);
|
|
|
|
|
throw std::runtime_error("mpp_buffer_group_get_internal failed");
|
|
|
|
|
}
|
|
|
|
|
ret = mpp_buffer_group_get_internal(&mpp_packet_group_, MPP_BUFFER_TYPE_ION);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"),
|
|
|
|
|
"mpp_buffer_group_get_internal failed, ret = " << ret);
|
|
|
|
|
throw std::runtime_error("mpp_buffer_group_get_internal failed");
|
|
|
|
|
}
|
|
|
|
|
RK_U32 hor_stride = MPP_ALIGN(width_, 16);
|
|
|
|
|
RK_U32 ver_stride = MPP_ALIGN(height_, 16);
|
|
|
|
|
ret = mpp_buffer_get(mpp_frame_group_, &mpp_frame_buffer_, hor_stride * ver_stride * 4);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"),
|
|
|
|
|
"mpp_buffer_get failed, ret = " << ret);
|
|
|
|
|
throw std::runtime_error("mpp_buffer_get failed");
|
|
|
|
|
}
|
|
|
|
|
mpp_frame_set_buffer(mpp_frame_, mpp_frame_buffer_);
|
|
|
|
|
ret = mpp_buffer_get(mpp_packet_group_, &mpp_packet_buffer_, width_ * height_ * 3);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"),
|
|
|
|
|
"mpp_buffer_get failed, ret = " << ret);
|
|
|
|
|
throw std::runtime_error("mpp_buffer_get failed");
|
|
|
|
|
}
|
|
|
|
|
mpp_packet_init_with_buffer(&mpp_packet_, mpp_packet_buffer_);
|
|
|
|
|
data_buffer_ = (uint8_t *)mpp_buffer_get_ptr(mpp_packet_buffer_);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-07 16:46:59 +08:00
|
|
|
RKJPEGDecoder::~RKJPEGDecoder() {
|
2023-08-25 21:47:13 +08:00
|
|
|
if (mpp_frame_buffer_) {
|
|
|
|
|
mpp_buffer_put(mpp_frame_buffer_);
|
|
|
|
|
mpp_frame_buffer_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (mpp_packet_buffer_) {
|
|
|
|
|
mpp_buffer_put(mpp_packet_buffer_);
|
|
|
|
|
mpp_packet_buffer_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (mpp_frame_group_) {
|
|
|
|
|
mpp_buffer_group_put(mpp_frame_group_);
|
|
|
|
|
mpp_frame_group_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (mpp_packet_group_) {
|
|
|
|
|
mpp_buffer_group_put(mpp_packet_group_);
|
|
|
|
|
mpp_packet_group_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (mpp_frame_) {
|
|
|
|
|
mpp_frame_deinit(&mpp_frame_);
|
|
|
|
|
mpp_frame_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (mpp_packet_) {
|
|
|
|
|
mpp_packet_deinit(&mpp_packet_);
|
|
|
|
|
mpp_packet_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (mpp_ctx_) {
|
|
|
|
|
mpp_destroy(mpp_ctx_);
|
|
|
|
|
mpp_ctx_ = nullptr;
|
|
|
|
|
}
|
2023-09-05 17:59:19 +08:00
|
|
|
if (rgb_buffer_) {
|
2023-08-27 16:14:34 +08:00
|
|
|
delete[] rgb_buffer_;
|
|
|
|
|
}
|
2023-08-25 21:47:13 +08:00
|
|
|
}
|
|
|
|
|
|
2023-09-07 16:46:59 +08:00
|
|
|
bool RKJPEGDecoder::mppFrame2RGB(const MppFrame frame, uint8_t *data) {
|
2023-08-25 21:47:13 +08:00
|
|
|
int width = mpp_frame_get_width(frame);
|
|
|
|
|
int height = mpp_frame_get_height(frame);
|
|
|
|
|
MppBuffer buffer = mpp_frame_get_buffer(frame);
|
|
|
|
|
CHECK_EQ(width, width_);
|
|
|
|
|
CHECK_EQ(height, height_);
|
|
|
|
|
CHECK_NOTNULL(data);
|
|
|
|
|
CHECK_EQ(width, width_);
|
|
|
|
|
CHECK_EQ(height, height_);
|
|
|
|
|
memset(data, 0, width * height * 3);
|
|
|
|
|
auto buffer_ptr = mpp_buffer_get_ptr(buffer);
|
2023-09-05 17:59:19 +08:00
|
|
|
#if defined(USE_LIBYUV)
|
2023-09-06 15:30:31 +08:00
|
|
|
auto *y = (const uint8_t *)buffer_ptr;
|
|
|
|
|
auto *uv = y + width * height;
|
|
|
|
|
int ret = libyuv::NV12ToRGB24(y, width, uv, width, data, width * 3, width, height);
|
|
|
|
|
if (ret) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"), "libyuv error " << ret);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-09-05 17:59:19 +08:00
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
rga_info_t src_info;
|
|
|
|
|
rga_info_t dst_info;
|
|
|
|
|
// NOTE: memset to zero is MUST
|
|
|
|
|
memset(&src_info, 0, sizeof(rga_info_t));
|
|
|
|
|
memset(&dst_info, 0, sizeof(rga_info_t));
|
2023-08-25 21:47:13 +08:00
|
|
|
src_info.fd = -1;
|
|
|
|
|
src_info.mmuFlag = 1;
|
|
|
|
|
src_info.virAddr = buffer_ptr;
|
|
|
|
|
src_info.format = RK_FORMAT_YCbCr_420_SP;
|
|
|
|
|
dst_info.fd = -1;
|
|
|
|
|
dst_info.mmuFlag = 1;
|
|
|
|
|
dst_info.virAddr = data;
|
2023-09-06 17:02:30 +08:00
|
|
|
dst_info.format = RK_FORMAT_BGR_888;
|
2023-08-25 21:47:13 +08:00
|
|
|
rga_set_rect(&src_info.rect, 0, 0, width, height, width, height, RK_FORMAT_YCbCr_420_SP);
|
2023-09-06 17:02:30 +08:00
|
|
|
rga_set_rect(&dst_info.rect, 0, 0, width, height, width, height, RK_FORMAT_BGR_888);
|
2023-08-25 21:47:13 +08:00
|
|
|
int ret = c_RkRgaBlit(&src_info, &dst_info, nullptr);
|
|
|
|
|
if (ret) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"),
|
|
|
|
|
"c_RkRgaBlit error " << ret << " errno " << strerror(errno));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2023-09-05 17:59:19 +08:00
|
|
|
#endif
|
2023-08-25 21:47:13 +08:00
|
|
|
}
|
|
|
|
|
|
2023-09-07 16:46:59 +08:00
|
|
|
bool RKJPEGDecoder::decode(const std::shared_ptr<ob::ColorFrame> &frame, uint8_t *dest) {
|
2023-08-25 21:47:13 +08:00
|
|
|
MPP_RET ret = MPP_OK;
|
|
|
|
|
memset(data_buffer_, 0, width_ * height_ * 3);
|
|
|
|
|
memcpy(data_buffer_, frame->data(), frame->dataSize());
|
|
|
|
|
mpp_packet_set_pos(mpp_packet_, data_buffer_);
|
|
|
|
|
mpp_packet_set_length(mpp_packet_, frame->dataSize());
|
|
|
|
|
mpp_packet_set_eos(mpp_packet_);
|
|
|
|
|
CHECK_NOTNULL(mpp_ctx_);
|
|
|
|
|
ret = mpp_api_->poll(mpp_ctx_, MPP_PORT_INPUT, MPP_POLL_BLOCK);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR(rclcpp::get_logger("rk_mpp_decoder"), "mpp poll failed %d", ret);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
ret = mpp_api_->dequeue(mpp_ctx_, MPP_PORT_INPUT, &mpp_task_);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR(rclcpp::get_logger("rk_mpp_decoder"), "mpp dequeue failed %d", ret);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
mpp_task_meta_set_packet(mpp_task_, KEY_INPUT_PACKET, mpp_packet_);
|
|
|
|
|
mpp_task_meta_set_frame(mpp_task_, KEY_OUTPUT_FRAME, mpp_frame_);
|
|
|
|
|
ret = mpp_api_->enqueue(mpp_ctx_, MPP_PORT_INPUT, mpp_task_);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR(rclcpp::get_logger("rk_mpp_decoder"), "mpp enqueue failed %d", ret);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
ret = mpp_api_->poll(mpp_ctx_, MPP_PORT_OUTPUT, MPP_POLL_BLOCK);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR(rclcpp::get_logger("rk_mpp_decoder"), "mpp poll failed %d", ret);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
ret = mpp_api_->dequeue(mpp_ctx_, MPP_PORT_OUTPUT, &mpp_task_);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR(rclcpp::get_logger("rk_mpp_decoder"), "mpp dequeue failed %d", ret);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (mpp_task_) {
|
|
|
|
|
MppFrame output_frame = nullptr;
|
|
|
|
|
mpp_task_meta_get_frame(mpp_task_, KEY_OUTPUT_FRAME, &output_frame);
|
|
|
|
|
if (mpp_frame_) {
|
|
|
|
|
int width = mpp_frame_get_width(mpp_frame_);
|
|
|
|
|
int height = mpp_frame_get_height(mpp_frame_);
|
|
|
|
|
if (width != width_ || height != height_) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"),
|
|
|
|
|
"mpp frame size error " << width << " " << height);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!mppFrame2RGB(mpp_frame_, rgb_buffer_)) {
|
|
|
|
|
RCLCPP_ERROR_STREAM(rclcpp::get_logger("rk_mpp_decoder"), "mpp frame to rgb error");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (mpp_frame_get_eos(output_frame)) {
|
|
|
|
|
RCLCPP_INFO_STREAM(rclcpp::get_logger("rk_mpp_decoder"), "mpp frame get eos");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ret = mpp_api_->enqueue(mpp_ctx_, MPP_PORT_OUTPUT, mpp_task_);
|
|
|
|
|
if (ret != MPP_OK) {
|
|
|
|
|
RCLCPP_ERROR(rclcpp::get_logger("rk_mpp_decoder"), "mpp enqueue failed %d", ret);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
CHECK_NOTNULL(dest);
|
|
|
|
|
memcpy(dest, rgb_buffer_, width_ * height_ * 3);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace orbbec_camera
|