Skip to content

Instantly share code, notes, and snippets.

@cormoran
Last active February 7, 2016 12:35
Show Gist options
  • Save cormoran/7108756075785b5c6fc1 to your computer and use it in GitHub Desktop.
Save cormoran/7108756075785b5c6fc1 to your computer and use it in GitHub Desktop.
c言語のweb socketライブラリで動画をストリーミングする
<!DOCTYPE html>
<html>
<head>
<title>動画ストリーミング サンプル</title>
<meta charset="utf-8">
<style type="text/css">
body {
background: #f7f7f7;
color: #474747;
font-family: arial, sans-serif;
}
</style>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
</head>
<body>
<input type="button" id="button" value="play" onClick="onButtonClicked()">
<canvas id="img" width="640" height="360"> </canvas>
</body>
<script>
var ws = new WebSocket("ws://localhost:7681", "movie");
var button = $("#button");
ws.onmessage = function(evt) {
console.log("received");
var url = window.URL.createObjectURL(evt.data);
var img = new Image;
img.src = url;
img.onload = function () {
$("#img")[0].getContext("2d").drawImage(img,0,0);
};
};
function onButtonClicked(){
console.log("Button Clicked");
ws.send(button.val());
if(button.val() == "play") button.val("stop");
else button.val("play");
}
</script>
</html>
#ifndef LWS_SUB_H
#define LWS_SUB_H
#include <libwebsockets.h>
const char* lws_getReasonString(int reason){
static const char* reason_strings[] = {
"LWS_CALLBACK_ESTABLISHED",
"LWS_CALLBACK_CLIENT_CONNECTION_ERROR",
"LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH",
"LWS_CALLBACK_CLIENT_ESTABLISHED",
"LWS_CALLBACK_CLOSED",
"LWS_CALLBACK_RECEIVE",
"LWS_CALLBACK_CLIENT_RECEIVE",
"LWS_CALLBACK_CLIENT_RECEIVE_PONG",
"LWS_CALLBACK_CLIENT_WRITEABLE",
"LWS_CALLBACK_SERVER_WRITEABLE",
"LWS_CALLBACK_HTTP",
"LWS_CALLBACK_HTTP_FILE_COMPLETION",
"LWS_CALLBACK_FILTER_NETWORK_CONNECTION",
"LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION",
"LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS",
"LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS",
"LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION",
"LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER",
"LWS_CALLBACK_CONFIRM_EXTENSION_OKAY",
"LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED",
"LWS_CALLBACK_PROTOCOL_INIT",
"LWS_CALLBACK_PROTOCOL_DESTROY",
/* external poll() management support */
"LWS_CALLBACK_ADD_POLL_FD",
"LWS_CALLBACK_DEL_POLL_FD",
"LWS_CALLBACK_SET_MODE_POLL_FD",
"LWS_CALLBACK_CLEAR_MODE_POLL_FD",
};
return reason_strings[reason];
}
static void dump_handshake_info(struct lws *wsi){
int n;
static const char *token_names[WSI_TOKEN_COUNT] = {
/*[WSI_TOKEN_GET_URI] =*/ "GET URI",
/*[WSI_TOKEN_HOST] =*/ "Host",
/*[WSI_TOKEN_CONNECTION] =*/ "Connection",
/*[WSI_TOKEN_KEY1] =*/ "key 1",
/*[WSI_TOKEN_KEY2] =*/ "key 2",
/*[WSI_TOKEN_PROTOCOL] =*/ "Protocol",
/*[WSI_TOKEN_UPGRADE] =*/ "Upgrade",
/*[WSI_TOKEN_ORIGIN] =*/ "Origin",
/*[WSI_TOKEN_DRAFT] =*/ "Draft",
/*[WSI_TOKEN_CHALLENGE] =*/ "Challenge",
/* new for 04 */
/*[WSI_TOKEN_KEY] =*/ "Key",
/*[WSI_TOKEN_VERSION] =*/ "Version",
/*[WSI_TOKEN_SWORIGIN] =*/ "Sworigin",
/* new for 05 */
/*[WSI_TOKEN_EXTENSIONS] =*/ "Extensions",
/* client receives these */
/*[WSI_TOKEN_ACCEPT] =*/ "Accept",
/*[WSI_TOKEN_NONCE] =*/ "Nonce",
/*[WSI_TOKEN_HTTP] =*/ "Http",
/*[WSI_TOKEN_MUXURL] =*/ "MuxURL",
};
char buf[256];
for (n = 0; n < WSI_TOKEN_COUNT; n++) {
if (!lws_hdr_total_length(wsi, (lws_token_indexes)n))
continue;
lws_hdr_copy(wsi, buf, sizeof buf, (lws_token_indexes)n);
fprintf(stderr, " %s = %s\n", token_names[n], buf);
}
}
#endif
/*
Websocket Video Streaming Sample
2016/2/7
*/
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <sys/time.h>
#include <assert.h>
#include <syslog.h>
#include <signal.h>
#include <stdarg.h>
#include <opencv2/opencv.hpp>
#include <libwebsockets.h>
#include "lws-sub.h"
using namespace std;
using namespace cv;
int force_exit = 0;
bool start = false;
VideoCapture video;
class LwsSendBuffer{
vector<uchar> buffer;
public:
LwsSendBuffer(){
buffer.resize(LWS_SEND_BUFFER_PRE_PADDING);
}
template<class T>
void set(const vector<T> &src){
if(src.size() == 0) return;
buffer.resize(LWS_SEND_BUFFER_PRE_PADDING + src.size() * sizeof(T));
copy(src.begin(),
src.end(),
buffer.begin() + LWS_SEND_BUFFER_PRE_PADDING);
}
int write(struct lws *wsi, lws_write_protocol protcol){
return lws_write(wsi,
&buffer[0] + LWS_SEND_BUFFER_PRE_PADDING,
buffer.size() - LWS_SEND_BUFFER_PRE_PADDING,
protcol );
}
};
vector<unsigned char> toJpeg(Mat &src){
vector<uchar> buff;
vector<int> param = { CV_IMWRITE_JPEG_QUALITY, 50 };
imencode(".jpg",src,buff,param);
return buff;
}
static int callback_movie(struct lws *wsi,
enum lws_callback_reasons reason, void *user,
void *in, size_t len){
switch (reason){
case LWS_CALLBACK_ESTABLISHED:
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
{
static LwsSendBuffer buffer;
Mat frame;
video >> frame;
if(frame.empty() or video.get(CV_CAP_PROP_POS_AVI_RATIO) == 1) break;
buffer.set( toJpeg(frame) );
buffer.write(wsi, LWS_WRITE_BINARY);
}
break;
case LWS_CALLBACK_RECEIVE: // 受信
{
lwsl_notice("ReceiveMessage=[%s]\n",(const char*)in);
if( string((const char*)in) == "play" ) start = true;
else if( string((const char*)in) == "stop" ) start = false;
}
break;
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
dump_handshake_info(wsi);
break;
default:
break;
}
return 0;
}
static struct lws_protocols protocols[] = {
{
"movie", /* name */
callback_movie, /* callback */
0, /* per_session_data_size */
1000000 /* max frame size / rx buffer */
},
{ NULL, NULL, 0, 0 } /* terminator */
};
void sighandler(int sig){
force_exit = 1;
}
int main(){
video = VideoCapture("video.mp4");
int n = 0;
struct lws_context *context;
struct lws_context_creation_info info;
{ // set info
memset(&info, 0, sizeof info);
info.port = 7681;
info.iface = NULL;
info.protocols = protocols;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
info.gid = -1;
info.uid = -1;
info.options = 0;
}
signal(SIGINT, sighandler);
int syslog_options = LOG_PID | LOG_PERROR;
int debug_level = 7;
{ // log setting
lws_set_log_level(debug_level, lwsl_emit_syslog);
lwsl_notice("lws chat server -\n");
setlogmask(LOG_UPTO (LOG_DEBUG));
openlog("lwsts", syslog_options, LOG_DAEMON);
}
context = lws_create_context(&info);
if (context == NULL) {
lwsl_err("lws init failed\n");
return -1;
}
n = 0;
while (n >= 0 && !force_exit) {
struct timeval tv;
gettimeofday(&tv, NULL);
n = lws_service(context, 50);
if(start) lws_callback_on_writable_all_protocol(context, protocols);
usleep(100000); // about 10fps
}
lws_context_destroy(context);
lwsl_notice("lws-test-server exited cleanly\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment