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