Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 32 additions & 43 deletions cpp/uvc/src/uvc_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ extern "C" {
std::atomic<bool> quitEvent(false);

std::shared_ptr<dai::InputQueue> inputQueue{nullptr};
std::shared_ptr<dai::MessageQueue> outputQueue;
std::shared_ptr<dai::MessageQueue> videoBitstreamQueue{nullptr};
std::shared_ptr<dai::MessageQueue> stillBitstreamQueue{nullptr};

/* Necessary for and only used by signal handler. */
static struct events *sigint_events;
Expand All @@ -48,49 +49,30 @@ void signalHandler(int signum) {
events_stop(sigint_events);
}

// Custom host node for saving video data
class VideoSaver : public dai::node::CustomNode<VideoSaver> {
public:
VideoSaver() : fileHandle("video.encoded", std::ios::binary) {
if(!fileHandle.is_open()) {
throw std::runtime_error("Could not open video.encoded for writing");
}
}

~VideoSaver() {
if(fileHandle.is_open()) {
fileHandle.close();
}
}

std::shared_ptr<dai::Buffer> processGroup(std::shared_ptr<dai::MessageGroup> message) override {
if(!fileHandle.is_open()) return nullptr;

// Get raw data and write to file
auto frame = message->get<dai::EncodedFrame>("data");
unsigned char* frameData = frame->getData().data();
size_t frameSize = frame->getData().size();
std::cout << "Storing frame of size: " << frameSize << std::endl;
fileHandle.write(reinterpret_cast<const char*>(frameData), frameSize);
extern "C" void depthai_uvc_get_buffer(struct video_source *s, struct video_buffer *buf, bool still) {
unsigned int frame_size, size;
uint8_t *f;

// Don't send anything back
return nullptr;
if(quitEvent) {
std::cout << "depthai_uvc_get_buffer(): Stopping capture due to quit event." << std::endl;
return;
}

private:
std::ofstream fileHandle;
};
if(still) {
std::cout << "depthai_uvc_get_buffer(): Sending latest full-resolution frame as still image." << std::endl;

extern "C" void depthai_uvc_get_buffer(struct video_source *s, struct video_buffer *buf) {
unsigned int frame_size, size;
uint8_t *f;
auto frame = stillBitstreamQueue->get<dai::ImgFrame>();

if(quitEvent) {
std::cout << "depthai_uvc_get_buffer(): Stopping capture due to quit event." << std::endl;
f = frame->getData().data();
frame_size = frame->getData().size();
size = std::min(frame_size, buf->size);
memcpy(buf->mem, f, size);
buf->bytesused = size;
return;
}
}

auto frame = outputQueue->get<dai::ImgFrame>();
auto frame = videoBitstreamQueue->get<dai::ImgFrame>();
if(frame == nullptr) {
std::cerr << "depthai_uvc_get_buffer(): No frame available." << std::endl;
return;
Expand Down Expand Up @@ -176,13 +158,20 @@ int main() {
// Create nodes
auto camRgb = pipeline.create<dai::node::Camera>()->build(socket);
inputQueue = camRgb->inputControl.createInputQueue();
auto output = camRgb->requestOutput(std::make_pair(1920, 1080), dai::ImgFrame::Type::NV12);

// Create video encoder node
auto encoded = pipeline.create<dai::node::VideoEncoder>();
encoded->setDefaultProfilePreset(30, dai::VideoEncoderProperties::Profile::MJPEG);
output->link(encoded->input);
outputQueue = encoded->bitstream.createOutputQueue(1, false);
auto videoSource = camRgb->requestOutput(std::make_pair(1920, 1080), dai::ImgFrame::Type::NV12);

// Encode the center-cropped HD stream for continuous UVC video.
auto videoEncoder = pipeline.create<dai::node::VideoEncoder>();
videoEncoder->setDefaultProfilePreset(30, dai::VideoEncoderProperties::Profile::MJPEG);
videoSource->link(videoEncoder->input);
videoBitstreamQueue = videoEncoder->bitstream.createOutputQueue(1, false);

auto stillSource = camRgb->requestOutput(std::make_pair(3840, 2160), dai::ImgFrame::Type::NV12);
// Encode full-resolution frames for UVC still-image requests.
auto stillEncoder = pipeline.create<dai::node::VideoEncoder>();
stillEncoder->setDefaultProfilePreset(4, dai::VideoEncoderProperties::Profile::MJPEG);
stillSource->link(stillEncoder->input);
stillBitstreamQueue = stillEncoder->bitstream.createOutputQueue(1, false);

// Start pipeline
pipeline.start();
Expand Down
17 changes: 16 additions & 1 deletion cpp/uvc/uvc-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ fi
MANUF="Luxonis"
PRODUCT="Luxonis UVC Camera"
UDC=$(ls /sys/class/udc | head -n1) # will identify the 'first' UDC
STILL_WIDTH="3840"
STILL_HEIGHT="2160"

log "=== Detecting platform:"
log " product : $PRODUCT"
Expand Down Expand Up @@ -66,6 +68,8 @@ remove_uvc_gadget() {
rm functions/uvc.0/control/class/ss/* 2>/dev/null
rmdir functions/uvc.0/control/header/* 2>/dev/null

rmdir functions/uvc.0/control/extensions/* 2>/dev/null

rmdir functions/uvc.0 2>/dev/null

popd >/dev/null
Expand Down Expand Up @@ -95,7 +99,7 @@ create_frame() {
mkdir -p "$wdir"
echo "$WIDTH" > "$wdir/wWidth"
echo "$HEIGHT" > "$wdir/wHeight"
echo $(( WIDTH * HEIGHT * 2 )) > "$wdir/dwMaxVideoFrameBufferSize"
echo $(( STILL_WIDTH * STILL_HEIGHT * 2 )) > "$wdir/dwMaxVideoFrameBufferSize"
cat <<EOF > "$wdir/dwFrameInterval"
333333
EOF
Expand All @@ -113,6 +117,9 @@ create_uvc() {
pushd "$GADGET/g1" >/dev/null
mkdir "functions/$FUNCTION"

# write to fule function_name PRODUCT var
echo "Luxonis UVC Camera" > "functions/$FUNCTION/function_name"

# create_frame "$FUNCTION" 640 360 uncompressed u
# create_frame "$FUNCTION" 1280 720 uncompressed u
# create_frame "$FUNCTION" 320 180 uncompressed u
Expand All @@ -121,6 +128,14 @@ create_uvc() {
# create_frame "$FUNCTION" 640 360 mjpeg m

mkdir "functions/$FUNCTION/streaming/header/h"
if [ -w "functions/$FUNCTION/streaming/header/h/still_width" ] && \
[ -w "functions/$FUNCTION/streaming/header/h/still_height" ]; then
echo "$STILL_WIDTH" > "functions/$FUNCTION/streaming/header/h/still_width"
echo "$STILL_HEIGHT" > "functions/$FUNCTION/streaming/header/h/still_height"
else
log " Still frame configfs attributes not present, using kernel defaults"
fi

cd "functions/$FUNCTION/streaming/header/h"
# ln -s ../../uncompressed/u
ln -s ../../mjpeg/m
Expand Down
Loading