mpp
mpp copied to clipboard
mpi_->decode_put_packet(mpp_ctx_, mpp_pkt_); Failed to put packet into MPP, error code: -1012
想实现的功能:使用mmp代替cv::Mat image = cv::imdecode(cv::Mat(1, buf.bytesused, CV_8UC1, buffers_[buf.index].start), cv::IMREAD_COLOR); 减少cpu使用率
代码:
#include <ros/ros.h>
#include <sensor_msgs/Image.h>
#include <linux/videodev2.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#include
#define HEIGHT 480 #define WIDTH 640 #define FPS 30
class V4L2CameraNode { public: V4L2CameraNode() : mpp_ctx_(nullptr), mpp_pkt_(nullptr), mpp_frm_(nullptr), mpp_buf_grp_(nullptr) { fd_ = open("/dev/video0", O_RDWR); if (fd_ == -1) { ROS_ERROR("Failed to open V4L2 device"); return; }
if (initializeMPP() != MPP_OK)
{
ROS_ERROR("Failed to initialize MPP");
close(fd_);
return;
}
struct v4l2_capability cap;
if (ioctl(fd_, VIDIOC_QUERYCAP, &cap) == -1)
{
ROS_ERROR("Failed to query V4L2 capabilities");
close(fd_);
return;
}
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = WIDTH;
fmt.fmt.pix.height = HEIGHT;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (ioctl(fd_, VIDIOC_S_FMT, &fmt) == -1)
{
ROS_ERROR("Failed to set V4L2 format");
close(fd_);
return;
}
struct v4l2_requestbuffers req;
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd_, VIDIOC_REQBUFS, &req) == -1)
{
ROS_ERROR("Failed to request buffers");
close(fd_);
return;
}
buffers_.resize(req.count);
for (unsigned int i = 0; i < req.count; ++i)
{
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (ioctl(fd_, VIDIOC_QUERYBUF, &buf) == -1)
{
ROS_ERROR("Failed to query buffer");
close(fd_);
return;
}
buffers_[i].length = buf.length;
buffers_[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, buf.m.offset);
ROS_INFO("BUffer[%d] mapped at address: %p, length: %zu", i, buffers_[i].start, buffers_[i].length);
if (buffers_[i].start == MAP_FAILED)
{
ROS_ERROR("Failed to map buffer");
close(fd_);
return;
}
if (ioctl(fd_, VIDIOC_QBUF, &buf) == -1)
{
ROS_ERROR("Failed to queue buffer");
close(fd_);
return;
}
}
v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd_, VIDIOC_STREAMON, &type) == -1)
{
ROS_ERROR("Failed to start streaming");
close(fd_);
return;
}
image_pub_ = nh_.advertise<sensor_msgs::Image>("camera/image_raw", 1);
ros_timer_ = nh_.createTimer(ros::Duration(1.0 / FPS), &V4L2CameraNode::captureImage, this);
}
~V4L2CameraNode()
{
ros_timer_.stop();
v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd_, VIDIOC_STREAMOFF, &type);
for (auto& buffer : buffers_)
{
if (buffer.start != MAP_FAILED)
{
munmap(buffer.start, buffer.length);
}
}
close(fd_);
deinitializeMPP();
}
private: MPP_RET initializeMPP() { MPP_RET ret = mpp_create(&mpp_ctx_, &mpi_); ROS_INFO("mpp create ret: %d", ret); if (ret != MPP_OK) return ret;
ret = mpp_init(mpp_ctx_, MPP_CTX_DEC, MPP_VIDEO_CodingMJPEG);
ROS_INFO("mpp init ret: %d", ret);
if (ret != MPP_OK)
return ret;
return MPP_OK;
}
void deinitializeMPP()
{
if (mpp_ctx_)
{
mpp_destroy(mpp_ctx_);
mpp_ctx_ = nullptr;
}
}
void captureImage(const ros::TimerEvent&)
{
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd_, VIDIOC_DQBUF, &buf) == -1)
{
ROS_ERROR("Failed to dequeue buffer");
return;
}
ROS_INFO("buf.bytesused: %d", buf.bytesused);
// 保存捕获的 JPEG 数据以供验证
std::ofstream outfile("captured_frame.jpg", std::ios::binary);
outfile.write(static_cast<char*>(buffers_[buf.index].start), buf.bytesused);
outfile.close();
// 验证 MJPEG 数据的格式
const uint8_t* data = static_cast<const uint8_t*>(buffers_[buf.index].start);
if (buf.bytesused < 2 || data[0] != 0xFF || data[1] != 0xD8)
{
ROS_ERROR("Captured data is not valid MJPEG format");
if (ioctl(fd_, VIDIOC_QBUF, &buf) == -1)
{
ROS_ERROR("Failed to requeue buffer");
}
return;
}
// 创建 MPP 包
// 增加调试信息:打印缓冲区的字节大小和起始地址
ROS_INFO("Dequeued buffer: index=%d, bytesused=%d, start address=%p", buf.index, buf.bytesused, buffers_[buf.index].start);
MPP_RET ret = mpp_packet_init(&mpp_pkt_, buffers_[buf.index].start, buf.bytesused);
if (ret != MPP_OK)
{
ROS_ERROR("Failed to initialize MPP packet, error code: %d", ret);
return;
}
ROS_INFO("MPP packet initialized successfully");
// 将包传递给解码器前增加调试信息
ROS_INFO("Putting packet into MPP for decoding with size:%d", buf.bytesused);
std::cout << "mpp_ctx_" << mpp_ctx_ << std::endl;
std::cout << "mpp_pkt_" << mpp_pkt_ << std::endl;
ret = mpi_->decode_put_packet(mpp_ctx_, mpp_pkt_);
if (ret != MPP_OK)
{
ROS_ERROR("MPP packet data ptr: %p, size: %d", buffers_[buf.index].start, buf.bytesused);
ROS_ERROR("Failed to put packet into MPP, error code: %d", ret);
return;
}
ROS_INFO("Packet successfully put into MPP");
// 解码输出
ROS_INFO("decode get frame");
ret = mpi_->decode_get_frame(mpp_ctx_, &mpp_frm_);
if (ret != MPP_OK || mpp_frm_ == NULL)
{
ROS_ERROR("Failed to decode MJPEG frame");
return;
}
ROS_INFO("Frame successfully decoded");
if (mpp_frame_get_info_change(mpp_frm_))
{
ROS_WARN("Detected MPP frame info change");
}
// 获取解码后的图像
MppBuffer mpp_buf = mpp_frame_get_buffer(mpp_frm_);
if (mpp_buf)
{
void* ptr = mpp_buffer_get_ptr(mpp_buf);
cv::Mat image(HEIGHT, WIDTH, CV_8UC3, ptr); // 这里直接使用解码后的数据
// 创建 ROS 图像消息并设置其属性
sensor_msgs::ImagePtr image_msg = boost::make_shared<sensor_msgs::Image>();
image_msg->header.stamp = ros::Time::now();
image_msg->height = image.rows;
image_msg->width = image.cols;
image_msg->encoding = "bgr8"; // 设置为 BGR8 编码
image_msg->step = image.step[0];
image_msg->data.assign(image.data, image.data + image.total() * image.elemSize());
// 发布图像消息
image_pub_.publish(image_msg);
}
// 释放 MPP 资源
mpp_packet_deinit(&mpp_pkt_);
mpp_frame_deinit(&mpp_frm_);
// 重新将缓冲区放回捕获队列
if (ioctl(fd_, VIDIOC_QBUF, &buf) == -1)
{
ROS_ERROR("Failed to requeue buffer");
}
}
ros::NodeHandle nh_;
ros::Timer ros_timer_;
int fd_;
MppCtx mpp_ctx_;
MppApi* mpi_;
MppPacket mpp_pkt_;
MppFrame mpp_frm_;
MppBufferGroup mpp_buf_grp_;
struct buffer
{
void* start;
size_t length;
};
std::vector<struct buffer> buffers_;
ros::Publisher image_pub_;
};
int main(int argc, char** argv) { ros::init(argc, argv, "v4l2_camera_node"); V4L2CameraNode node; ros::spin(); return 0; }
报错: (base) orangepi@orangepi5plus:~/hk/code/v4l2$ rosrun v4l2 publisher [ INFO] [1728982422.451431991]: mpp create ret: 0 [ INFO] [1728982422.459096268]: mpp init ret: 0 [ INFO] [1728982422.470774681]: BUffer[0] mapped at address: 0x7f89ec0000, length: 614400 [ INFO] [1728982422.724946479]: buf.bytesused: 63660 [ INFO] [1728982422.727768302]: Dequeued buffer: index=0, bytesused=63660, start address=0x7f89ec0000 [ INFO] [1728982422.728311668]: MPP packet initialized successfully [ INFO] [1728982422.730474920]: Putting packet into MPP for decoding with size:63660 mpp_ctx_0x5571f6c2c0 mpp_pkt_0x5571f7b4a8 [ INFO] [1728982422.731062034]: MPP packet data ptr: 0x7f89ec0000, size: 63660 [ERROR] [1728982422.731212823]: Failed to put packet into MPP, error code: -1012 有大佬知道怎么回事吗?