|
|
|
@ -8,6 +8,14 @@ |
|
|
|
|
#include "common/swaglog.h" |
|
|
|
|
#include "common/util.h" |
|
|
|
|
|
|
|
|
|
// echo "0xFFFF" > /sys/kernel/debug/msm_vidc/debug_level
|
|
|
|
|
|
|
|
|
|
static void copyBuffer(VisionBuf *src_buf, VisionBuf *dst_buf) { |
|
|
|
|
// Copy Y plane
|
|
|
|
|
memcpy(dst_buf->y, src_buf->y, src_buf->height * src_buf->stride); |
|
|
|
|
// Copy UV plane
|
|
|
|
|
memcpy(dst_buf->uv, src_buf->uv, src_buf->height / 2 * src_buf->stride); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void request_buffers(int fd, v4l2_buf_type buf_type, unsigned int count) { |
|
|
|
|
struct v4l2_requestbuffers reqbuf = { |
|
|
|
@ -44,8 +52,7 @@ bool MsmVidc::init(const char* dev, size_t width, size_t height, uint64_t codec) |
|
|
|
|
util::safe_ioctl(fd, VIDIOC_STREAMON, &out_type, "VIDIOC_STREAMON OUTPUT failed"); |
|
|
|
|
restartCapture(); |
|
|
|
|
setupPolling(); |
|
|
|
|
rotator.init(); |
|
|
|
|
rotator.configUBWCtoNV12(width, height); |
|
|
|
|
|
|
|
|
|
this->initialized = true; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
@ -117,25 +124,13 @@ VisionBuf* MsmVidc::handleCapture() { |
|
|
|
|
buf.length = 1; |
|
|
|
|
util::safe_ioctl(this->fd, VIDIOC_DQBUF, &buf, "VIDIOC_DQBUF CAPTURE failed"); |
|
|
|
|
|
|
|
|
|
if (buf.m.planes[0].bytesused) { |
|
|
|
|
static size_t cap_cnt = 0; |
|
|
|
|
cap_cnt++; |
|
|
|
|
if (cap_cnt % 240 == 0) { |
|
|
|
|
LOGD("Dequeued %zu capture buffers", cap_cnt); |
|
|
|
|
} |
|
|
|
|
if (!this->reconfigure_pending) { |
|
|
|
|
rotator.putFrame(&cap_bufs[buf.index]); |
|
|
|
|
VisionBuf *rotated = rotator.getFrame(100); |
|
|
|
|
queueCaptureBuffer(buf.index); |
|
|
|
|
if (rotated) { |
|
|
|
|
rotator.convertStride(rotated, this->current_output_buf); |
|
|
|
|
return this->current_output_buf; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
LOGE("Dequeued empty capture buffer %d", buf.index); |
|
|
|
|
if (this->reconfigure_pending || buf.m.planes[0].bytesused == 0) { |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
return nullptr; |
|
|
|
|
|
|
|
|
|
copyBuffer(&cap_bufs[buf.index], this->current_output_buf); |
|
|
|
|
queueCaptureBuffer(buf.index); |
|
|
|
|
return this->current_output_buf; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool MsmVidc::subscribeEvents() { |
|
|
|
@ -149,12 +144,16 @@ bool MsmVidc::subscribeEvents() { |
|
|
|
|
bool MsmVidc::setPlaneFormat(enum v4l2_buf_type type, uint32_t fourcc) { |
|
|
|
|
struct v4l2_format fmt = {.type = type}; |
|
|
|
|
struct v4l2_pix_format_mplane *pix = &fmt.fmt.pix_mp; |
|
|
|
|
*pix = { .width = (__u32)this->w, .height = (__u32)this->h, .pixelformat = fourcc }; |
|
|
|
|
*pix = { |
|
|
|
|
.width = (__u32)this->w, |
|
|
|
|
.height = (__u32)this->h, |
|
|
|
|
.pixelformat = fourcc |
|
|
|
|
}; |
|
|
|
|
util::safe_ioctl(fd, VIDIOC_S_FMT, &fmt, "VIDIOC_S_FMT failed"); |
|
|
|
|
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
|
|
|
|
this->out_buf_size = pix->plane_fmt[0].sizeimage; |
|
|
|
|
int ion_size = this->out_buf_size * OUTPUT_BUFFER_COUNT; // Output (input) buffers are ION buffer.
|
|
|
|
|
this->out_buf.allocate_no_cache(ion_size); // mmap rw
|
|
|
|
|
this->out_buf.allocate(ion_size); // mmap rw
|
|
|
|
|
for (int i = 0; i < OUTPUT_BUFFER_COUNT; i++) { |
|
|
|
|
this->out_buf_off[i] = i * this->out_buf_size; |
|
|
|
|
this->out_buf_addr[i] = (char *)this->out_buf.addr + this->out_buf_off[i]; |
|
|
|
@ -164,11 +163,15 @@ bool MsmVidc::setPlaneFormat(enum v4l2_buf_type type, uint32_t fourcc) { |
|
|
|
|
} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
|
|
|
|
request_buffers(this->fd, type, CAPTURE_BUFFER_COUNT); |
|
|
|
|
util::safe_ioctl(fd, VIDIOC_G_FMT, &fmt, "VIDIOC_G_FMT failed"); |
|
|
|
|
const __u32 y_size = pix->plane_fmt[0].sizeimage; |
|
|
|
|
const __u32 y_stride = pix->plane_fmt[0].bytesperline; |
|
|
|
|
for (int i = 0; i < CAPTURE_BUFFER_COUNT; i++) { |
|
|
|
|
this->cap_bufs[i].allocate_no_cache(pix->plane_fmt[0].sizeimage); |
|
|
|
|
this->cap_bufs[i].init_yuv(pix->width, pix->height, pix->plane_fmt[0].bytesperline, 0); |
|
|
|
|
size_t uv_offset = (size_t)y_stride * pix->height; |
|
|
|
|
size_t required = uv_offset + (y_stride * pix->height / 2); // enough for Y + UV. For linear NV12, UV plane starts at y_stride * height.
|
|
|
|
|
size_t alloc_size = std::max<size_t>(y_size, required); |
|
|
|
|
this->cap_bufs[i].allocate(alloc_size); |
|
|
|
|
this->cap_bufs[i].init_yuv(pix->width, pix->height, y_stride, uv_offset); |
|
|
|
|
} |
|
|
|
|
this->cap_buf_format = pix->pixelformat; |
|
|
|
|
LOGD("Set capture buffer size to %d, count %d, addr %p, extradata size %d", |
|
|
|
|
pix->plane_fmt[0].sizeimage, CAPTURE_BUFFER_COUNT, this->cap_bufs[0].addr, pix->plane_fmt[1].sizeimage); |
|
|
|
|
} |
|
|
|
@ -201,7 +204,7 @@ bool MsmVidc::restartCapture() { |
|
|
|
|
} |
|
|
|
|
// setup, start and queue capture buffers
|
|
|
|
|
setDBP(); |
|
|
|
|
setPlaneFormat(type, V4L2_PIX_FMT_NV12_UBWC); |
|
|
|
|
setPlaneFormat(type, V4L2_PIX_FMT_NV12); |
|
|
|
|
util::safe_ioctl(this->fd, VIDIOC_STREAMON, &type, "VIDIOC_STREAMON CAPTURE failed"); |
|
|
|
|
for (size_t i = 0; i < CAPTURE_BUFFER_COUNT; ++i) { |
|
|
|
|
queueCaptureBuffer(i); |
|
|
|
@ -259,7 +262,7 @@ bool MsmVidc::setDBP() { |
|
|
|
|
struct v4l2_ext_control control[2] = {0}; |
|
|
|
|
struct v4l2_ext_controls controls = {0}; |
|
|
|
|
control[0].id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE; |
|
|
|
|
control[0].value = 0; // V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY
|
|
|
|
|
control[0].value = 1; // V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY
|
|
|
|
|
control[1].id = V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT; |
|
|
|
|
control[1].value = 0; // V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE
|
|
|
|
|
controls.count = 2; |
|
|
|
|