video streaming using websocket. but,streaming is very slower than 0.1fps.

Dependencies:   BaseUsbHost EthernetInterface WebSocketClient mbed-rtos mbed

Fork of BaseUsbHost_example by Norimasa Okamoto

viewer

Revision:
6:420a86583681
Parent:
5:495f7536897b
--- a/main.cpp	Fri Jan 25 14:55:08 2013 +0000
+++ b/main.cpp	Tue Feb 19 15:49:33 2013 +0000
@@ -1,27 +1,25 @@
-// BaseUsbHost_example/main.cpp 2013/1/25
-#include "mbed.h"
-#include "rtos.h"
+// VideoStreaming/main.cpp 2013/2/20
+#include "EthernetInterface.h"
+#include "Websocket.h"
 #include "BaseUsbHost.h"
-#include "LogitechC270.h"
-#include "LifeCamVX700.h"
 #include "UvcCam.h"
-#include "UsbFlashDrive.h"
 #include "decodeMJPEG.h"
 #include "MyThread.h"
-#include <string>
 
-#define IMAGE_BUF_SIZE (1024*7)
-#define INTERVAL_S 30
+#define CHANNEL "public-ch"
+#define URL "ws://sockets.mbed.org/ws/"CHANNEL"/rw"
+#define VIEWER "http://va009039-mbed.appspot.com/VideoStreaming/"CHANNEL"/viewer"
+#define FRAME_LIMIT 4
+#define IMAGE_BUFFER_SIZE (1024*3)
 
-Serial pc(USBTX, USBRX);
+Serial term(USBTX, USBRX);
 DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4);
 
 struct ImageBuffer {
-    int pos;
-    uint8_t buf[IMAGE_BUF_SIZE];
+    uint16_t pos;
+    uint8_t buf[IMAGE_BUFFER_SIZE];
     void clear() { pos = 0; }
     int size() { return pos; }
-    uint8_t get(int pos) { return buf[pos]; } 
     void put(uint8_t c) {
         if (pos < sizeof(buf)) {
             buf[pos++] = c;
@@ -31,13 +29,17 @@
 
 Mail<ImageBuffer, 1> mail_box;
 
-class captureJPEG : public MyThread, public decodeMJPEG {
+class Capture : public MyThread, public decodeMJPEG {
 public:
-    captureJPEG(BaseUvc* cam) : m_cam(cam) {
+    Capture(BaseUvc* cam) : m_cam(cam) {
+        m_cam->setOnResult(this, &Capture::callback_motion_jpeg);
         m_buf = NULL;
-        m_cam->setOnResult(this, &captureJPEG::callback_motion_jpeg);
     }
-private:    
+private:
+    ImageBuffer* m_buf;
+    BaseUvc* m_cam;
+
+    // from decodeMJPEG
     virtual void outputJPEG(uint8_t c, int status) {
         if (m_buf == NULL && status == JPEG_START) {
             m_buf = mail_box.alloc();
@@ -50,112 +52,126 @@
             if (status == JPEG_END) {
                 mail_box.put(m_buf);
                 m_buf = NULL;
-                led3 = !led3;
             }
         }
     }
 
     void callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len) {
-        inputPacket(buf, len);
-        led1 = buf[1]&1;    // FID
-        if (buf[1]&2) {     // EOF
-            led2 = !led2;
-        }
+        inputPacket(buf, len); // to decodeMJPEG
     }
 
     virtual void run() {
-        while(true) {
-            if (m_cam) {
-                m_cam->poll();
-            }
+        while(1) {
+            m_cam->poll();
         }
     }
-    ImageBuffer* m_buf;
-    BaseUvc* m_cam;
 };
 
+// Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+int base64enc(const char *input, unsigned int length, char *output, int outputlen) {
+  static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  unsigned int c, c1, c2, c3;
+
+  if (outputlen < (((length-1)/3)+1)<<2) return -1;
+
+  for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) {
+    c1 = ((((unsigned char)*((unsigned char *)&input[i]))));
+    c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0;
+    c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0;
+
+    c = ((c1 & 0xFC) >> 2);
+    output[j+0] = base64[c];
+    c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4);
+    output[j+1] = base64[c];
+    c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
+    output[j+2] = (length>i+1)?base64[c]:'=';
+    c = (c3 & 0x3F);
+    output[j+3] = (length>i+2)?base64[c]:'=';
+  }
+  output[(((length-1)/3)+1)<<2] = '\0';
+  return 0;
+}
+
+#define CHUNK (3*20)
+
+void buf_to_websocket(Websocket*ws, ImageBuffer* buf) {
+    Timer t;
+    int send_bytes = 0;
+    t.reset();
+    t.start();
+    char output[CHUNK/3*4+1];
+    for(int i = 0; i < buf->size(); i += CHUNK) {
+        int len = buf->size() - i;
+        if (len > CHUNK) {
+            len = CHUNK;
+        }
+        base64enc(reinterpret_cast<const char*>(buf->buf+i), len, output, sizeof(output));
+        term.printf("%s\n", output);
+        send_bytes += ws->send(output);
+    }
+    strcpy(output, ".");
+    term.printf("%s\n", output);
+    send_bytes += ws->send(output);
+    term.printf("websocket: send %d bytes %d ms\n", send_bytes, t.read_ms());
+}
+
 void no_memory () {
   error("Failed to allocate memory!\n");
 }
 
 int main() {
-    pc.baud(921600);
-    printf("%s\n", __FILE__);
+    term.baud(921600);
+    term.printf("%s\n", __FILE__);
     set_new_handler(no_memory);
 
-    BaseUvc* cam = NULL;
-    UsbFlashDrive* drive = NULL;
+    EthernetInterface eth;
+    eth.init(); //Use DHCP
+    int r = eth.connect();
+    if (r != 0) {
+        error("mbed is not connected to the Internet. %d\n", r);
+    }
+    term.printf("IP Address is %s\n\r", eth.getIPAddress());
+    Websocket* ws = new Websocket(URL);
+    if (!ws->connect()) {
+        error("mbed is not connected to websocket "URL);
+    }
+    
     BaseUsbHost* usbHost = new BaseUsbHost();
     ControlEp* ctlEp = new ControlEp; // root hub
-    if (!UsbHub::check(ctlEp)) {
-        error("USB Hub is not connected.\n");
-    }
-    UsbHub* hub = new UsbHub(ctlEp);
-    ctlEp = hub->search<UsbFlashDrive>();
-    if (ctlEp) {
-        drive = new UsbFlashDrive("usb", ctlEp);
-    }
-    ctlEp = hub->search<LogitechC270>();
-    if (ctlEp) {
-        //cam = new LogitechC270(C270_MJPEG, C270_160x120, _5FPS, ctlEp); 
-        cam = new LogitechC270(C270_MJPEG, C270_320x176, _5FPS, ctlEp); 
-    }
-    if (cam == NULL) {
-        ctlEp = hub->search<LifeCamVX700>();
-        if (ctlEp) {
-            cam = new LifeCamVX700(VX700_160x120, _5FPS, ctlEp); 
+    if (UsbHub::check(ctlEp)) {
+        UsbHub* hub = new UsbHub(ctlEp);
+        ctlEp = hub->search<UvcCam>(0);
+        if (ctlEp == NULL) {
+            error("UVC Camera is not connected in USB hub.\n");
         }
-    }
-    if (cam == NULL) {
-        ctlEp = hub->search<UvcCam>();
-        if (ctlEp) {
-            cam = new UvcCam(UVC_MJPEG, UVC_160x120, _5FPS, ctlEp); 
-        }
-    }
-    if (cam == NULL) {
+    } else if (!UvcCam::check(ctlEp)) {
         error("UVC Camera is not connected.\n");
     }
-    if (drive == NULL) {
-        error("USB flash drive is not connected.\n");
-    }
+    UvcCam* cam = new UvcCam(UVC_MJPEG, UVC_160x120, _5FPS, ctlEp);
+
+    Capture* capture_th = new Capture(cam);
+    capture_th->set_stack(512);
+    capture_th->start();
+
+    term.printf("\n\n"VIEWER"\n\n");
     
-    captureJPEG* capture = new captureJPEG(cam);
-    capture->set_stack(DEFAULT_STACK_SIZE-128*8);
-    capture->start();
-
-    for(int n = 0; ; n++) {
-        printf("%d captureJPEG stack used: %d/%d bytes\n", n, capture->stack_used(), capture->stack_size());
-        osEvent evt = mail_box.get();
+    int frame = 0;
+    for(int n = 0;; n++) {
+        osEvent evt = mail_box.get(200);
         if (evt.status == osEventMail) {
             ImageBuffer *buf = reinterpret_cast<ImageBuffer*>(evt.value.p);
-            time_t timestamp = time(NULL);
-            struct tm* tminfo = localtime(&timestamp);
-            char tmbuf[32];
-            strftime(tmbuf, sizeof(tmbuf), "/usb/img%M%S.jpg", tminfo);
-            string path = tmbuf;
-            printf("%s %d bytes\n", path.c_str(), buf->size());
-            FILE* fp = fopen(path.c_str(), "wb");
-            if (fp) {
-               for(int i = 0; i < buf->size(); i++) {
-                   fputc(buf->get(i), fp);
-                   //Thread::yield();
-               }
-               fclose(fp);
+            if (frame < 10) {
+                term.printf("Capture stack used: %d/%d bytes\n", capture_th->stack_used(), capture_th->stack_size());
+                term.printf("image size: %d bytes\n", buf->size());
+            }
+            if (frame++ < FRAME_LIMIT || FRAME_LIMIT==(-1)) {
+                led2 = 1;
+                buf_to_websocket(ws, buf);
+                led2 = 0;
             }
             mail_box.free(buf);
             led4 = !led4;
         }
-        
-        printf("CC:");
-        for(int i = 0; i < 16; i++) {
-            printf(" %u", cam->report_cc_count[i]); 
-        }
-        printf("\nPS:"); 
-        for(int i = 0; i < 16; i++) {
-            printf(" %u", cam->report_ps_cc_count[i]); 
-        }
-        printf("\n");
-        
-        Thread::wait(INTERVAL_S*1000);
+        led1 = ws->is_connected();
     }
 }