kinect 無法在我的android開發板上顯示的分析

來源:互聯網
上載者:User

之前在網上發現駭客已經將kinect移植到android上,使用的beagleboard平台。公司想在kinect上深耕一下,所以需要將kinect在公司的android開發板上實現。記錄以備忘。

 

一,按照駭客的教程,將之移植到beagleboard C4平台上。挺順利。但深度映像只能維持幾秒鐘,因beagleboard不是我的最終目的,此問題擱置,beagleboard作為參考。駭客的教程如下:

http://www.noritsuna.com/archives/2011/01/openframeworks_kinect_android.html

順便說一下,配置開發工具很麻煩,尤其是有些需要翻牆出去下,所以建議下載上面網頁結尾處作者提供的完整軟體包。解壓後修改一下環境變數即可用。可以更懶一下:建立一個跟作者相同的使用者名稱,將包解壓到相應的檔案夾,整個工程及其軟體就可以用了。

 

二、將之移植到自己的android開發板。硬體平台就不具體說了,不是國際大廠的。

出錯:加速度計顯示正常,但深度映像沒有顯示,全黑。

到此為止,我一直沒有仔細看代碼。呵呵。沒辦法了,看代碼吧。

 

架構:openframework

流程:openframework->ofxAndroid->ofxKinect->freenect->libusb之後就是linux核心?

前面不說了,可以藉助列印log進行分析。沒有顯示的原因是ofxKinect::threadedFunction()函數中,

 

void ofxKinect::threadedFunction(){</p><p> freenect_set_led(kinectDevice, LED_GREEN);<br /> freenect_set_depth_format(kinectDevice, FREENECT_DEPTH_11BIT);<br /> freenect_set_depth_callback(kinectDevice, &grabDepthFrame);</p><p> ofLog(OF_LOG_VERBOSE, "leon ofxKinect: Connection opened");</p><p> freenect_start_depth(kinectDevice);<br /> ...............<br />}  


最後一條語句設定回呼函數,具體實現如下void freenect_set_depth_callback(freenect_device *dev, freenect_depth_cb cb)<br />{<br /> dev->depth_cb = cb;<br />}將回呼函數賦值給dev->depth-cb, 之後調用freenect_start_depth(kinectDevice);int freenect_start_depth(freenect_device *dev)<br />{<br /> freenect_context *ctx = dev->parent;<br /> int res;</p><p> ..........................<br /> dev->depth.pkt_size = DEPTH_PKTDSIZE;<br /> dev->depth.synced = 0;<br /> dev->depth.flag = 0x70;<br /> dev->depth.valid_frames = 0;<br /> res = fnusb_start_iso(&dev->usb_cam, &dev->depth_isoc, depth_process, 0x82, NUM_XFERS, PKTS_PER_XFER, DEPTH_PKTBUF);<br /> ................<br />}函數fnusb_start_iso()將參數depth_process設為回呼函數,fnusb_start_iso(){<br /> strm->cb = cb;<br /> libusb_fill_iso_transfer(strm->xfers[i], dev->dev, ep, bufp, pkts * len, pkts, iso_callback, strm, 0);<br />} //在此函數中將iso_callback函數設為回呼函數static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer,<br /> libusb_device_handle *dev_handle, unsigned char endpoint,<br /> unsigned char *buffer, int length, int num_iso_packets,<br /> libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)<br />{<br /> transfer->dev_handle = dev_handle;<br /> transfer->endpoint = endpoint;<br /> transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;<br /> transfer->timeout = timeout;<br /> transfer->buffer = buffer;<br /> transfer->length = length;<br /> transfer->num_iso_packets = num_iso_packets;<br /> transfer->user_data = user_data;<br /> transfer->callback = callback;<br />} 而iso_callback函數又會調用strm->cb,depth_process。static void iso_callback(struct libusb_transfer *xfer)<br />{<br /> int i;<br /> fnusb_isoc_stream *strm = xfer->user_data;<br /> if (strm->dead) {<br /> freenect_context *ctx = strm->parent->parent->parent;<br /> strm->dead_xfers++;<br /> FN_SPEW("EP %02x transfer complete, %d left/n", xfer->endpoint, strm->num_xfers - strm->dead_xfers);<br /> return;<br /> }<br /> if(xfer->status == LIBUSB_TRANSFER_COMPLETED) {<br /> uint8_t *buf = (void*)xfer->buffer;<br /> for (i=0; i<strm->pkts; i++) {<br /> strm->cb(strm->parent->parent, buf, xfer->iso_packet_desc[i].actual_length);<br /> buf += strm->len;<br /> }<br /> libusb_submit_transfer(xfer);<br /> } else {<br /> freenect_context *ctx = strm->parent->parent->parent;<br /> FN_WARNING("Isochronous transfer error: %d/n", xfer->status);<br /> strm->dead_xfers++;<br /> }<br />}  depth_process中會執行dev->depth-cb。調來調去的真的很麻煩。

 

至此,整個流程結束。那回呼函數會在何時調用?也就是libusb_fill_iso_transfer函數中的  transfer->callback會在哪裡被調用執行?在ofxKinect用cscope搜一下callback,只有usbi_handle_transfer_completion回調用到transfer->callback,那usbi_handle_transfer_completion會在哪裡被調用?再搜

 

 

有八九條,我們只關註標志為 LIBUSB_TRANSFER_COMPLETED的,只有一條,handle_iso_completion函數。搜handle_iso_completion

 

reap_for_handle   ---  op_handle_events  ,此函數被設定在const struct usbi_os_backend linux_usbfs_backend 結構體中,指派陳述式:.handle_events = op_handle_events,const struct usbi_os_backend linux_usbfs_backend = {<br /> .name = "Linux usbfs",<br /> .init = op_init,<br /> .exit = NULL,<br /> .get_device_list = op_get_device_list,<br /> .get_device_descriptor = op_get_device_descriptor,<br /> .get_active_config_descriptor = op_get_active_config_descriptor,<br /> .get_config_descriptor = op_get_config_descriptor,<br /> .open = op_open,<br /> .close = op_close,<br /> .get_configuration = op_get_configuration,<br /> .set_configuration = op_set_configuration,<br /> .claim_interface = op_claim_interface,<br /> .release_interface = op_release_interface,<br /> .set_interface_altsetting = op_set_interface,<br /> .clear_halt = op_clear_halt,<br /> .reset_device = op_reset_device,<br /> .kernel_driver_active = op_kernel_driver_active,<br /> .detach_kernel_driver = op_detach_kernel_driver,<br /> .attach_kernel_driver = op_attach_kernel_driver,<br /> .destroy_device = op_destroy_device,<br /> .submit_transfer = op_submit_transfer,<br /> .cancel_transfer = op_cancel_transfer,<br /> .clear_transfer_priv = op_clear_transfer_priv,<br /> .handle_events = op_handle_events,<br /> .clock_gettime = op_clock_gettime,<br />#ifdef USBI_TIMERFD_AVAILABLE<br /> .get_timerfd_clockid = op_get_timerfd_clockid,<br />#endif<br /> .device_priv_size = sizeof(struct linux_device_priv),<br /> .device_handle_priv_size = sizeof(struct linux_device_handle_priv),<br /> .transfer_priv_size = sizeof(struct linux_transfer_priv),<br /> .add_iso_packet_size = 0,<br />}; 看看linux_usbfs_backend 是不是引用,還有.handle_events在哪裡被調用?在libs/libusb/core.c中const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend; 

 

在libs/libusb/io.c中函數handle_events(){   usbi_backend->handle_events}io.c中有兩處調用到handle_events()函數4 io.c          libusb_handle_events_timeout 1946 r = handle_events(ctx, &poll_timeout);5 io.c          libusb_handle_events_locked  2022 return handle_events(ctx, &poll_timeout);正確的調用應該是第二個,libusb_handle_events_locked,搜libusb_handle_events_locked,除了函數定義只有一處標頭檔的聲明。看起來上面分析不對,那是libusb_handle_events_timeout是正確調用?libusb_handle_events_timeout被API_EXPORTED int libusb_handle_events(libusb_context *ctx)<br />{<br /> struct timeval tv;<br /> tv.tv_sec = 60;<br /> tv.tv_usec = 0;<br /> return libusb_handle_events_timeout(ctx, &tv);<br />} 調用,搜libusb_handle_events,排除被bulk及control介面調用,只有在libusb10.c的兩處1 usb_libusb10.c fnusb_process_events      66 return libusb_handle_events(ctx->ctx);2 usb_libusb10.c fnusb_stop_iso           245 libusb_handle_events(ctx->usb.ctx);2是usb停止時的調用,1應為我們的目標,int fnusb_process_events(fnusb_ctx *ctx)<br />{<br /> return libusb_handle_events(ctx->ctx);<br />} 看到fn了,呵呵,我們的路應該是正確的。int freenect_process_events(freenect_context *ctx)<br />{<br /> return fnusb_process_events(&ctx->usb);<br />} 搜freenect_process_events,libs/libfreenect/libfreenect.hpp中template <class T>class Freenect : Noncopyable {<br /> ...<br /> // Do not call directly, thread runs here<br /> void operator()() {<br /> while(!m_stop) {<br /> if(freenect_process_events(m_ctx) != 0) throw std::runtime_error("Cannot process freenect events");<br /> }<br /> }<br /> ...<br />}      // Do not call directly, thread runs here呵呵,終於到頭了。

 

 

 

整個流程就是這樣,但對無法顯示的問題還是無解。需要log。先這樣,將libusb的log列印出來再說。沒有log就像瞎子一樣。

 

 

 

 


4.15日編輯今天把libusb的log輸出出來了,寫下以備忘。libusb的log部分實在libusb.h中定義的enum usbi_log_level {<br /> LOG_LEVEL_DEBUG,<br /> LOG_LEVEL_INFO,<br /> LOG_LEVEL_WARNING,<br /> LOG_LEVEL_ERROR,<br />};<br />void usbi_log(struct libusb_context *ctx, enum usbi_log_level,<br /> const char *function, const char *format, ...);<br />void usb_ofLog(int logLevel, const char* format, ...);<br />#ifdef ENABLE_LOGGING<br />#define _usbi_log(ctx, level, fmt...) usbi_log(ctx, level, __FUNCTION__, fmt)<br />#else<br />#define _usbi_log(ctx, level, fmt...)<br />#endif</p><p>#ifdef ENABLE_DEBUG_LOGGING<br />#define usbi_dbg(fmt...) _usbi_log(NULL, LOG_LEVEL_DEBUG, fmt)<br />#else<br />#define usbi_dbg(fmt...)<br />#endif<br />#define usbi_info(ctx, fmt...) _usbi_log(ctx, LOG_LEVEL_INFO, fmt)<br />#define usbi_warn(ctx, fmt...) _usbi_log(ctx, LOG_LEVEL_WARNING, fmt)<br />#define usbi_err(ctx, fmt...) _usbi_log(ctx, LOG_LEVEL_ERROR, fmt)<br />最終所有的log輸出都定位到usb_ofLog(level, fmt)函數,在core.c中void usbi_log(struct libusb_context *ctx, enum usbi_log_level level,<br /> const char *function, const char *format, ...)<br />{<br /> va_list args;<br /> FILE *stream = stdout;<br /> const char *prefix;<br />#ifndef ENABLE_DEBUG_LOGGING<br /> USBI_GET_CONTEXT(ctx);<br /> if (!ctx->debug)<br /> return;<br /> if (level == LOG_LEVEL_WARNING && ctx->debug < 2)<br /> return;<br /> if (level == LOG_LEVEL_INFO && ctx->debug < 3)<br /> return;<br />#endif<br /> switch (level) {<br /> case LOG_LEVEL_INFO:<br /> prefix = "info";<br /> break;<br /> case LOG_LEVEL_WARNING:<br /> stream = stderr;<br /> prefix = "warning";<br /> break;<br /> case LOG_LEVEL_ERROR:<br /> stream = stderr;<br /> prefix = "error";<br /> break;<br /> case LOG_LEVEL_DEBUG:<br /> stream = stderr;<br /> prefix = "debug";<br /> break;<br /> default:<br /> stream = stderr;<br /> prefix = "unknown";<br /> break;<br /> }<br /> fprintf(stream, "libusb:%s [%s] ", prefix, function);<br /> va_start (args, format);<br /> vfprintf(stream, format, args);<br /> va_end (args);<br /> fprintf(stream, "/n");<br />}<br />libusb的日誌輸出是標準的輸入輸出。有個方案,可以在上面的函數中將日誌儲存到一個檔案中。我用的是另一條路:採用android的記錄模式1、修改libusb.h,修改成這樣enum usbi_log_level {<br /> LOG_LEVEL_DEBUG = 3,<br /> LOG_LEVEL_INFO,<br /> LOG_LEVEL_WARNING,<br /> LOG_LEVEL_ERROR,<br />}; </p><p>void usbi_log(struct libusb_context *ctx, enum usbi_log_level,<br /> const char *function, const char *format, ...);<br />void usb_ofLog(int logLevel, const char* format, ...);<br />#ifdef ENABLE_LOGGING<br />#define _usbi_log(ctx, level, fmt...) usb_ofLog(level, fmt)<br />#else<br />#define _usbi_log(ctx, level, fmt...)</p><p>#endif </p><p>#ifdef ENABLE_DEBUG_LOGGING<br />#define usbi_dbg(fmt...) _usbi_log(NULL, LOG_LEVEL_DEBUG, fmt)<br />#else<br />#define usbi_dbg(fmt...)<br />#endif<br />#define usbi_info(ctx, fmt...) _usbi_log(ctx, LOG_LEVEL_INFO, fmt)<br />#define usbi_warn(ctx, fmt...) _usbi_log(ctx, LOG_LEVEL_WARNING, fmt)<br />#define usbi_err(ctx, fmt...) _usbi_log(ctx, LOG_LEVEL_ERROR, fmt)<br /> 主要是上面的enum,將第一個賦值為3,另外將幾個宏定義重定位到另一個函數usb_ofLog,這個函數需要我們自己改。在core.c 最後添加如下:#include <android/log.h><br />#define LOG_TAG "OF"<br />#define LOGNOTICE(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)<br />#define LOGWARNING(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)<br />#define LOGERROR(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)<br />#define LOGFATAL(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)<br />#define LOGVERBOSE(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)<br />//#define vLOGNOTICE(...) __android_log_vprint(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)<br />//#define vLOGWARNING(...) __android_log_vprint(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)<br />//#define vLOGERROR(...) __android_log_vprint(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)<br />//#define vLOGFATAL(...) __android_log_vprint(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)<br />//#define vLOGVERBOSE(...) __android_log_vprint(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)<br />void usb_ofLog(int logLevel, const char* format, ...){<br /> //thanks stefan!<br /> //http://www.ozzu.com/cpp-tutorials/tutorial-writing-custom-printf-wrapper-function-t89166.html<br />// if(logLevel > LOG_LEVEL_INFO){<br /> if(1){<br /> va_list args;<br /> va_start( args, format );<br /> if(logLevel == LOG_LEVEL_INFO){<br /> LOGVERBOSE( format );<br /> }<br /> else if(logLevel == LOG_LEVEL_DEBUG){<br /> LOGNOTICE( format );<br /> }<br /> else if(logLevel == LOG_LEVEL_WARNING){<br /> LOGWARNING( format );<br /> }<br /> else if(logLevel == LOG_LEVEL_ERROR){<br /> LOGERROR( format );<br /> }<br /> va_end( args );<br /> }<br />}<br /> 見android的日誌規則引用進來。之後重編譯,就可以看到可愛的日誌啦。

 

 

4.26日更新

 

已經在自己的開發板上跑起來了。有映像輸出,但只是二值圖,這個應該是上層畫圖的時候的問題。先記錄一下解決的過程。

libusb日誌列印成功後,分析得知libusb得到的資料為全0,libusb的底層支援是usbfs,所以跟蹤到kernel的usbfs部分,usb/core/devio.c中,有函數processcompl(),

將語句

if (as->userbuffer && urb->actual_length) {

修改成 if(as->userbuffer){之後映像能夠正常輸出,跟板子的供應商聯絡,urb->actual_length在usb core中沒有被賦值。bug他提供的解決方案,在driver/xxx/usb/dwc_otg/dwc_otg_hcd_intr.c中if (++_qtd->isoc_frame_index == urb->number_of_packets) {前加下面的語句urb->actual_length += frame_desc->actual_length;最後的結果是:default:DWC_ERROR("%s: Unhandled _halt_status (%d)/n", __func__, _halt_status);BUG();break;}urb->actual_length += frame_desc->actual_length;if (++_qtd->isoc_frame_index == urb->number_of_packets) {

 

如果只是按照他提供的方案改,幀率很低,原因待分析。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.