Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android UVC backend - Out of memory error fix #4678

Merged
merged 2 commits into from
Aug 20, 2019
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
23 changes: 23 additions & 0 deletions src/android/jni/frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,29 @@ Java_com_intel_realsense_librealsense_Frame_nGetData(JNIEnv *env, jclass type, j
handle_error(env, e);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_intel_realsense_librealsense_Points_nGetData(JNIEnv *env, jclass type, jlong handle,
jfloatArray data_) {
jsize length = env->GetArrayLength(data_);
rs2_error *e = NULL;
env->SetFloatArrayRegion(data_, 0, length, static_cast<const jfloat *>(rs2_get_frame_data(
reinterpret_cast<const rs2_frame *>(handle), &e)));
handle_error(env, e);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_intel_realsense_librealsense_Points_nGetTextureCoordinates(JNIEnv *env, jclass type,
jlong handle,
jfloatArray data_) {
jsize length = env->GetArrayLength(data_);
rs2_error *e = NULL;
env->SetFloatArrayRegion(data_, 0, length, reinterpret_cast<const jfloat *>(rs2_get_frame_texture_coordinates(
reinterpret_cast<const rs2_frame *>(handle), &e)));
handle_error(env, e);
}

extern "C" JNIEXPORT jboolean JNICALL
Java_com_intel_realsense_librealsense_Frame_nIsFrameExtendableTo(JNIEnv *env, jclass type,
jlong handle, jint extension) {
Expand Down
161 changes: 155 additions & 6 deletions src/android/usb_host/android_uvc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,20 @@
#include "../../libuvc/utlist.h"
#include "../../usb/usb-types.h"
#include "../../usb/usb-device.h"
#include "../../usbhost/messenger-usbhost.h"

#include <vector>
#include <thread>
#include <atomic>
#include <zconf.h>

#define USE_URB true
#define DEQUEUE_TIMEOUT 50
#define STREAMING_WATCHER_TIMEOUT 1000
#define STREAMING_BULK_TRANSFER_TIMEOUT 1000
#define UVC_PAYLOAD_HEADER_LENGTH 256
#define UVC_PAYLOAD_MAX_HEADER_LENGTH 256

using namespace librealsense;

// Data structures for Backend-Frontend queue:
struct frame;
Expand Down Expand Up @@ -831,7 +836,7 @@ void usbhost_uvc_process_bulk_payload(frame_ptr fp, size_t payload_len, frames_q
queue.enqueue(std::move(fp));
}

void stream_thread(usbhost_uvc_stream_context *strctx) {
void stream_thread_bulk(usbhost_uvc_stream_context *strctx) {
auto inf = strctx->stream->stream_if->interface;
auto dev = strctx->stream->devh->device;
auto messenger = dev->open();
Expand All @@ -844,7 +849,7 @@ void stream_thread(usbhost_uvc_stream_context *strctx) {
std::atomic_bool keep_sending_callbacks(true);
frames_queue queue;

uint32_t read_buff_length = UVC_PAYLOAD_HEADER_LENGTH + strctx->stream->cur_ctrl.dwMaxVideoFrameSize;
uint32_t read_buff_length = UVC_PAYLOAD_MAX_HEADER_LENGTH + strctx->stream->cur_ctrl.dwMaxVideoFrameSize;
LOG_INFO("endpoint " << (int)read_ep->get_address() << " read buffer size: " << read_buff_length);

// Get all pointers from archive and initialize their content
Expand Down Expand Up @@ -918,6 +923,152 @@ void stream_thread(usbhost_uvc_stream_context *strctx) {
LOG_DEBUG("Transfer thread stopped for endpoint address: " << ep);
};

void stream_thread_urb(usbhost_uvc_stream_context *strctx) {
auto inf = strctx->stream->stream_if->interface;
auto dev = strctx->stream->devh->device;
auto messenger = std::static_pointer_cast<platform::usb_messenger_usbhost>(dev->open());

auto read_ep = std::static_pointer_cast<platform::usb_endpoint_usbhost>
(inf->first_endpoint(platform::RS2_USB_ENDPOINT_DIRECTION_READ));

uint32_t reset_ep_timeout = 100;
messenger->reset_endpoint(read_ep, reset_ep_timeout);

frames_archive archive;
std::atomic_bool keep_sending_callbacks(true);
frames_queue queue;

uint32_t read_buff_length = UVC_PAYLOAD_MAX_HEADER_LENGTH + strctx->stream->cur_ctrl.dwMaxVideoFrameSize;
LOG_INFO("endpoint " << (int)read_ep->get_address() << " read buffer size: " << read_buff_length);

// Get all pointers from archive and initialize their content
std::vector<frame *> frames;
for (auto i = 0; i < frames_archive::CAPACITY; i++) {
auto ptr = archive.allocate();
ptr->pixels.resize(read_buff_length, 0);
ptr->owner = &archive;
frames.push_back(ptr);
}

for (auto ptr : frames) {
archive.deallocate(ptr);
}

std::thread t([&]() {
while (keep_sending_callbacks) {
frame_ptr fp(nullptr, [](frame *) {});
if (queue.dequeue(&fp, DEQUEUE_TIMEOUT)) {
strctx->stream->user_cb(&fp->fo, strctx->stream->user_ptr);
}
}
});

frame_ptr fp = frame_ptr(archive.allocate(), &cleanup_frame);

auto desc = read_ep->get_descriptor();
std::shared_ptr<usb_request> request = std::shared_ptr<usb_request>(usb_request_new(dev->get_handle(),
&desc), [](usb_request* req) {usb_request_free(req);});
if(!request)
{
LOG_ERROR("invalid USB request");
return;
}

bool fatal_error = false;
uint32_t frame_count = 0;
int active_request_count = 0;
uint32_t zero_response = 0;
auto callback = std::make_shared<platform::usb_request_callback>([&](usb_request* r)
{
if(r)
{
active_request_count--;
if(r->actual_length == 0){
LOG_WARNING("read_ep: " << r->endpoint << ", zero response");
zero_response++;
if(zero_response > 10)
{
messenger->reset_endpoint(read_ep, reset_ep_timeout);
zero_response = 0;
}
}
if(r->actual_length >= strctx->stream->cur_ctrl.dwMaxVideoFrameSize){
zero_response = 0;
frame_count++;
usbhost_uvc_process_bulk_payload(std::move(fp), r->actual_length, queue);
}
}

if(!strctx->stream->running){
return;
}

fp = frame_ptr(archive.allocate(), &cleanup_frame);
if(!fp)
return;
request->buffer = fp->pixels.data();
request->buffer_length = fp->pixels.size();

auto sts = messenger->submit_request(request);
switch(sts)
{
case platform::RS2_USB_STATUS_SUCCESS:
active_request_count++;
return;
case platform::RS2_USB_STATUS_OVERFLOW:
case platform::RS2_USB_STATUS_NO_DEVICE:
case platform::RS2_USB_STATUS_NO_MEM:
fatal_error = true;
return;
default:
messenger->reset_endpoint(read_ep, reset_ep_timeout);
break;
}
});

request->client_data = callback.get();

while(!fatal_error && strctx->stream->running)
{
if(frame_count == 0){
if(active_request_count > 0)
{
messenger->cancel_request(request);
active_request_count--;
}
callback->callback(nullptr);
}
frame_count = 0;
std::this_thread::sleep_for(std::chrono::milliseconds(STREAMING_WATCHER_TIMEOUT));
}

if(active_request_count > 0)
{
messenger->cancel_request(request);
active_request_count--;
}
LOG_INFO("read endpoint: " << (int)read_ep->get_address() <<", active requests count: " << active_request_count);

callback->cancel();
messenger->reset_endpoint(read_ep, reset_ep_timeout);
free(strctx);
queue.clear();
archive.stop_allocation();
fp.reset();
archive.wait_until_empty();
keep_sending_callbacks = false;

LOG_INFO("start join stream_thread");
t.join();
LOG_INFO("Transfer thread stopped for endpoint address: " << (int)read_ep->get_address());
};

void stream_thread(usbhost_uvc_stream_context *strctx){
if(USE_URB)
stream_thread_urb(strctx);
else
stream_thread_bulk(strctx);
}
uvc_error_t usbhost_uvc_stream_start(
usbhost_uvc_stream_handle_t *strmh,
usbhost_uvc_frame_callback_t *cb,
Expand Down Expand Up @@ -959,8 +1110,6 @@ uvc_error_t usbhost_uvc_stream_start(

usbhost_uvc_stream_context *streamctx = new usbhost_uvc_stream_context;

//printf("Starting stream on EP = 0x%X, interface 0x%X\n", format_desc->parent->bEndpointAddress, iface);

streamctx->stream = strmh;
streamctx->endpoint = format_desc->parent->bEndpointAddress;
streamctx->iface = iface;
Expand Down Expand Up @@ -1001,7 +1150,7 @@ void usbhost_uvc_stream_close(usbhost_uvc_stream_handle_t *strmh) {
}

uvc_error_t usbhost_uvc_stream_open_ctrl(usbhost_uvc_device *devh, usbhost_uvc_stream_handle_t **strmhp,
uvc_stream_ctrl_t *ctrl);
uvc_stream_ctrl_t *ctrl);

uvc_error_t usbhost_start_streaming(usbhost_uvc_device *devh, uvc_stream_ctrl_t *ctrl,
usbhost_uvc_frame_callback_t *cb, void *user_ptr,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ protected static void setViewport(Rect r) {
GLES10.glMatrixMode(GLES10.GL_PROJECTION);
GLES10.glOrthof(0, r.width(), r.height(), 0, -1, +1);
}

public String getLabel() {
if(mFrame == null)
return "";
try(StreamProfile sp = mFrame.getProfile()){
return sp.getType() + " - " + sp.getFormat();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,18 @@ public synchronized void draw(Rect rect)
GLES10.glPopMatrix();
}

@Override
public synchronized String getLabel() {
MotionFrame mf = mFrame.as(Extension.MOTION_FRAME);
Float3 d = mf.getMotionData();
try(StreamProfile sp = mFrame.getProfile()){
return sp.getType().name() +
" [ X: " + String.format("%+.2f", d.x) +
", Y: " + String.format("%+.2f", d.y) +
", Z: " + String.format("%+.2f", d.z) + " ]";
}
}

@Override
public synchronized void close() {
if(mFrame != null)
Expand Down
Loading