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

main.cpp

Committer:
va009039
Date:
2013-02-19
Revision:
7:5dc595bbff58
Parent:
6:420a86583681

File content as of revision 7:5dc595bbff58:

// VideoStreaming/main.cpp 2013/2/20
#include "EthernetInterface.h"
#include "Websocket.h"
#include "BaseUsbHost.h"
#include "UvcCam.h"
#include "decodeMJPEG.h"
#include "MyThread.h"

#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 term(USBTX, USBRX);
DigitalOut led1(LED1), led2(LED2), led3(LED3), led4(LED4);

struct ImageBuffer {
    uint16_t pos;
    uint8_t buf[IMAGE_BUFFER_SIZE];
    void clear() { pos = 0; }
    int size() { return pos; }
    void put(uint8_t c) {
        if (pos < sizeof(buf)) {
            buf[pos++] = c;
        }
    }
};

Mail<ImageBuffer, 1> mail_box;

class Capture : public MyThread, public decodeMJPEG {
public:
    Capture(BaseUvc* cam) : m_cam(cam) {
        m_cam->setOnResult(this, &Capture::callback_motion_jpeg);
        m_buf = NULL;
    }
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();
            if (m_buf) {
                m_buf->clear();
            }
        }
        if (m_buf) {
            m_buf->put(c);
            if (status == JPEG_END) {
                mail_box.put(m_buf);
                m_buf = NULL;
            }
        }
    }

    void callback_motion_jpeg(uint16_t frame, uint8_t* buf, int len) {
        inputPacket(buf, len); // to decodeMJPEG
    }

    virtual void run() {
        while(1) {
            m_cam->poll();
        }
    }
};

// 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() {
    term.baud(921600);
    term.printf("%s\n", __FILE__);
    set_new_handler(no_memory);

    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)) {
        UsbHub* hub = new UsbHub(ctlEp);
        ctlEp = hub->search<UvcCam>(0);
        if (ctlEp == NULL) {
            error("UVC Camera is not connected in USB hub.\n");
        }
    } else if (!UvcCam::check(ctlEp)) {
        error("UVC Camera 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");
    
    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);
            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;
        }
        led1 = ws->is_connected();
    }
}