1b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph/* 2b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * Copyright (C) 2016 The Android Open Source Project 3b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * 4b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * Licensed under the Apache License, Version 2.0 (the "License"); 5b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * you may not use this file except in compliance with the License. 6b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * You may obtain a copy of the License at 7b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * 8b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * http://www.apache.org/licenses/LICENSE-2.0 9b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * 10b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * Unless required by applicable law or agreed to in writing, software 11b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * distributed under the License is distributed on an "AS IS" BASIS, 12b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * See the License for the specific language governing permissions and 14b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph * limitations under the License. 15b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph */ 16b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <stdio.h> 17b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <stdlib.h> 18b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <error.h> 19b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <errno.h> 20b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <memory.h> 21b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <fcntl.h> 22b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <unistd.h> 23b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <sys/ioctl.h> 24b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <sys/mman.h> 25b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include <cutils/log.h> 26b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 27b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include "assert.h" 28b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 29b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph#include "VideoCapture.h" 30b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 31b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 32b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// NOTE: This developmental code does not properly clean up resources in case of failure 33b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// during the resource setup phase. Of particular note is the potential to leak 34b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// the file descriptor. This must be fixed before using this code for anything but 35b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// experimentation. 36b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphbool VideoCapture::open(const char* deviceName) { 37b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // If we want a polling interface for getting frames, we would use O_NONBLOCK 38b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// int mDeviceFd = open(deviceName, O_RDWR | O_NONBLOCK, 0); 39b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mDeviceFd = ::open(deviceName, O_RDWR, 0); 40b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (mDeviceFd < 0) { 41b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("failed to open device %s (%d = %s)", deviceName, errno, strerror(errno)); 42b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 43b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 44b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 45b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph v4l2_capability caps; 46b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph { 47b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph int result = ioctl(mDeviceFd, VIDIOC_QUERYCAP, &caps); 48b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (result < 0) { 49b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("failed to get device caps for %s (%d = %s)", deviceName, errno, strerror(errno)); 50b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 51b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 52b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 53b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 54b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Report device properties 55b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI("Open Device: %s (fd=%d)", deviceName, mDeviceFd); 56b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI(" Driver: %s", caps.driver); 57b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI(" Card: %s", caps.card); 58b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI(" Version: %u.%u.%u", 59b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph (caps.version >> 16) & 0xFF, 60b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph (caps.version >> 8) & 0xFF, 61b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph (caps.version) & 0xFF); 62b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI(" All Caps: %08X", caps.capabilities); 63b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI(" Dev Caps: %08X", caps.device_caps); 64b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 65b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Enumerate the available capture formats (if any) 66b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI("Supported capture formats:"); 67b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph v4l2_fmtdesc formatDescriptions; 68b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph formatDescriptions.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 69b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph for (int i=0; true; i++) { 70b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph formatDescriptions.index = i; 71b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_ENUM_FMT, &formatDescriptions) == 0) { 72b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI(" %2d: %s 0x%08X 0x%X", 73b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph i, 74b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph formatDescriptions.description, 75b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph formatDescriptions.pixelformat, 76b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph formatDescriptions.flags 77b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ); 78b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } else { 79b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // No more formats available 80b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph break; 81b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 82b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 83b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 84b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Verify we can use this device for video capture 85b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) || 86b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph !(caps.capabilities & V4L2_CAP_STREAMING)) { 87b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Can't do streaming capture. 88b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("Streaming capture not supported by %s.", deviceName); 89b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 90b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 91b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 92b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Set our desired output format 93b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph v4l2_format format; 94b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 95f91b3fccfe62a0361f64c89218d3a7a2443f8d0aScott Randolph format.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; // Could/should we request V4L2_PIX_FMT_NV21? 96b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph format.fmt.pix.width = 720; // TODO: Can we avoid hard coding dimensions? 97b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph format.fmt.pix.height = 240; // For now, this works with available hardware 98f91b3fccfe62a0361f64c89218d3a7a2443f8d0aScott Randolph format.fmt.pix.field = V4L2_FIELD_ALTERNATE; // TODO: Do we need to specify this? 99b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI("Requesting format %c%c%c%c (0x%08X)", 100b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ((char*)&format.fmt.pix.pixelformat)[0], 101b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ((char*)&format.fmt.pix.pixelformat)[1], 102b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ((char*)&format.fmt.pix.pixelformat)[2], 103b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ((char*)&format.fmt.pix.pixelformat)[3], 104b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph format.fmt.pix.pixelformat); 105b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_S_FMT, &format) < 0) { 106b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("VIDIOC_S_FMT: %s", strerror(errno)); 107b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 108b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 109b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Report the current output format 110b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 111b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_G_FMT, &format) == 0) { 112b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 113b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mFormat = format.fmt.pix.pixelformat; 114b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mWidth = format.fmt.pix.width; 115b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mHeight = format.fmt.pix.height; 116b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mStride = format.fmt.pix.bytesperline; 117b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 118b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI("Current output format: fmt=0x%X, %dx%d, pitch=%d", 119b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph format.fmt.pix.pixelformat, 120b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph format.fmt.pix.width, 121b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph format.fmt.pix.height, 122b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph format.fmt.pix.bytesperline 123b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ); 124b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } else { 125b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("VIDIOC_G_FMT: %s", strerror(errno)); 126b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 127b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 128b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 129b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Make sure we're initialized to the STOPPED state 130b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mRunMode = STOPPED; 131b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mFrameReady = false; 132b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 133b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Ready to go! 134b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return true; 135b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph} 136b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 137b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 138b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphvoid VideoCapture::close() { 139b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGD("VideoCapture::close"); 140b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Stream should be stopped first! 141b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph assert(mRunMode == STOPPED); 142b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 143b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (isOpen()) { 144b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGD("closing video device file handled %d", mDeviceFd); 145b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ::close(mDeviceFd); 146b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mDeviceFd = -1; 147b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 148b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph} 149b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 150b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 151b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphbool VideoCapture::startStream(std::function<void(VideoCapture*, imageBuffer*, void*)> callback) { 152b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Set the state of our background thread 153b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph int prevRunMode = mRunMode.fetch_or(RUN); 154b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (prevRunMode & RUN) { 155b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // The background thread is already running, so we can't start a new stream 156b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("Already in RUN state, so we can't start a new streaming thread"); 157b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 158b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 159b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 160b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Tell the L4V2 driver to prepare our streaming buffers 161b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph v4l2_requestbuffers bufrequest; 162b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 163b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph bufrequest.memory = V4L2_MEMORY_MMAP; 164b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph bufrequest.count = 1; 165b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_REQBUFS, &bufrequest) < 0) { 166b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("VIDIOC_REQBUFS: %s", strerror(errno)); 167b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 168b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 169b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 170b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Get the information on the buffer that was created for us 171b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph memset(&mBufferInfo, 0, sizeof(mBufferInfo)); 172b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mBufferInfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 173b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mBufferInfo.memory = V4L2_MEMORY_MMAP; 174b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mBufferInfo.index = 0; 175b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_QUERYBUF, &mBufferInfo) < 0) { 176b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("VIDIOC_QUERYBUF: %s", strerror(errno)); 177b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 178b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 179b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 180b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI("Buffer description:"); 181b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI(" offset: %d", mBufferInfo.m.offset); 182b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI(" length: %d", mBufferInfo.length); 183b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 184b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Get a pointer to the buffer contents by mapping into our address space 185b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mPixelBuffer = mmap( 186b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph NULL, 187b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mBufferInfo.length, 188b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph PROT_READ | PROT_WRITE, 189b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph MAP_SHARED, 190b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mDeviceFd, 191b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mBufferInfo.m.offset 192b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ); 193b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if( mPixelBuffer == MAP_FAILED) { 194b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("mmap: %s", strerror(errno)); 195b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 196b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 197b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph memset(mPixelBuffer, 0, mBufferInfo.length); 198b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGI("Buffer mapped at %p", mPixelBuffer); 199b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 200b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Queue the first capture buffer 201b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_QBUF, &mBufferInfo) < 0) { 202b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("VIDIOC_QBUF: %s", strerror(errno)); 203b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 204b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 205b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 206b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Start the video stream 207b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph int type = mBufferInfo.type; 208b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_STREAMON, &type) < 0) { 209b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("VIDIOC_STREAMON: %s", strerror(errno)); 210b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 211b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 212b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 213b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Remember who to tell about new frames as they arrive 214b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mCallback = callback; 215b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 216b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Fire up a thread to receive and dispatch the video frames 217b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mCaptureThread = std::thread([this](){ collectFrames(); }); 218b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 219b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGD("Stream started."); 220b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return true; 221b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph} 222b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 223b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 224b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphvoid VideoCapture::stopStream() { 225b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Tell the background thread to stop 226b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph int prevRunMode = mRunMode.fetch_or(STOPPING); 227b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (prevRunMode == STOPPED) { 228b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // The background thread wasn't running, so set the flag back to STOPPED 229b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mRunMode = STOPPED; 230b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } else if (prevRunMode & STOPPING) { 231b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("stopStream called while stream is already stopping. Reentrancy is not supported!"); 232b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return; 233b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } else { 234b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Block until the background thread is stopped 235b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (mCaptureThread.joinable()) { 236b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mCaptureThread.join(); 237b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 238b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 239b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Stop the underlying video stream (automatically empties the buffer queue) 240b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph int type = mBufferInfo.type; 241b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_STREAMOFF, &type) < 0) { 242b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("VIDIOC_STREAMOFF: %s", strerror(errno)); 243b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 244b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 245b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGD("Capture thread stopped."); 246b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 247b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 248b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Unmap the buffers we allocated 249b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph munmap(mPixelBuffer, mBufferInfo.length); 250b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 251b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Tell the L4V2 driver to release our streaming buffers 252b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph v4l2_requestbuffers bufrequest; 253b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 254b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph bufrequest.memory = V4L2_MEMORY_MMAP; 255b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph bufrequest.count = 0; 256b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ioctl(mDeviceFd, VIDIOC_REQBUFS, &bufrequest); 257b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 258b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Drop our reference to the frame delivery callback interface 259b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mCallback = nullptr; 260b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph} 261b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 262b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 263b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphvoid VideoCapture::markFrameReady() { 264b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mFrameReady = true; 265b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph}; 266b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 267b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 268b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphbool VideoCapture::returnFrame() { 269b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // We're giving the frame back to the system, so clear the "ready" flag 270b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mFrameReady = false; 271b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 272b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Requeue the buffer to capture the next available frame 273b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_QBUF, &mBufferInfo) < 0) { 274b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("VIDIOC_QBUF: %s", strerror(errno)); 275b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return false; 276b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 277b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 278b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph return true; 279b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph} 280b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 281b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 282b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph// This runs on a background thread to receive and dispatch video frames 283b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolphvoid VideoCapture::collectFrames() { 284b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Run until our atomic signal is cleared 285b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph while (mRunMode == RUN) { 286b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Wait for a buffer to be ready 287b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (ioctl(mDeviceFd, VIDIOC_DQBUF, &mBufferInfo) < 0) { 288b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGE("VIDIOC_DQBUF: %s", strerror(errno)); 289b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph break; 290b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 291b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 292b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph markFrameReady(); 293b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 294b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // If a callback was requested per frame, do that now 295b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph if (mCallback) { 296b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mCallback(this, &mBufferInfo, mPixelBuffer); 297b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 298b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph } 299b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph 300b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph // Mark ourselves stopped 301b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph ALOGD("VideoCapture thread ending"); 302b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph mRunMode = STOPPED; 303b342cb163393317d8af77339ff8ff5e921bd4a8fScott Randolph} 304