This is an example of how to use the wcWebCamClient library. A simple test program to demonstrate input streaming.
#include <iostream>
#include <fstream>
#include <string.h>
#include <chrono>
#include <thread>
#include <math.h>
#include <wcJSON.h>
#include <png.h>
#include <ogg/ogg.h>
#include "theora/theoraenc.h"
#include "../../commline_tools.h"
using namespace std;
static const uint32_t TIME_OUT = 60;
static const size_t MAX_INPUT_BUFFER = 0x7D000;
static uint8_t running = 0;
static ofstream outfile;
static char * mem_frame_buffer = NULL;
static size_t frame_size = 0;
static std::string input_device;
static bool theora_initialized = false;
static th_ycbcr_buffer ycbcr;
static uint32_t video_fps_numerator = 24;
static uint32_t video_fps_denominator = 1;
static uint32_t video_aspect_numerator = 0;
static uint32_t video_aspect_denominator = 0;
static uint32_t discrete_delta = 300;
static bool soft_target = false;
static uint32_t video_rate = 0;
static uint32_t video_quality = 25;
ogg_uint32_t keyframe_frequency=64;
static th_pixel_fmt chroma_format = TH_PF_420;
static ogg_stream_state ogg_os;
static ogg_packet op;
static ogg_page og;
static th_enc_ctx *td = NULL;
static th_info ti;
static uint8_t clamp(int d)
{
if(d < 0)
return 0;
if(d > 255)
return 255;
return d;
}
static int ilog(unsigned _v)
{
int ret;
for(ret=0; _v; ret++)
_v>>=1;
return ret;
}
static void rgb_to_yuv(png_bytep *png,
th_ycbcr_buffer ycbcr,
uint32_t w, uint32_t h)
{
uint32_t x;
uint32_t y;
uint32_t x1;
uint32_t y1;
uint64_t yuv_w;
uint8_t *yuv_y;
uint8_t *yuv_u;
uint8_t *yuv_v;
yuv_w = ycbcr[0].width;
yuv_y = ycbcr[0].data;
yuv_u = ycbcr[1].data;
yuv_v = ycbcr[2].data;
if (chroma_format == TH_PF_420)
{
for(y = 0; y < h; y += 2)
{
y1=y+(y+1<h);
for(x = 0; x < w; x += 2)
{
x1=x+(x+1<w);
png_byte r0 = png[y][3 * x + 0];
png_byte g0 = png[y][3 * x + 1];
png_byte b0 = png[y][3 * x + 2];
png_byte r1 = png[y][3 * x1 + 0];
png_byte g1 = png[y][3 * x1 + 1];
png_byte b1 = png[y][3 * x1 + 2];
png_byte r2 = png[y1][3 * x + 0];
png_byte g2 = png[y1][3 * x + 1];
png_byte b2 = png[y1][3 * x + 2];
png_byte r3 = png[y1][3 * x1 + 0];
png_byte g3 = png[y1][3 * x1 + 1];
png_byte b3 = png[y1][3 * x1 + 2];
yuv_y[x + y * yuv_w] = clamp((65481*r0+128553*g0+24966*b0+4207500)/255000);
yuv_y[x1 + y * yuv_w] = clamp((65481*r1+128553*g1+24966*b1+4207500)/255000);
yuv_y[x + y1 * yuv_w] = clamp((65481*r2+128553*g2+24966*b2+4207500)/255000);
yuv_y[x1 + y1 * yuv_w] = clamp((65481*r3+128553*g3+24966*b3+4207500)/255000);
yuv_u[(x >> 1) + (y >> 1) * ycbcr[1].stride] =
clamp( ((-33488*r0-65744*g0+99232*b0+29032005)/4 +
(-33488*r1-65744*g1+99232*b1+29032005)/4 +
(-33488*r2-65744*g2+99232*b2+29032005)/4 +
(-33488*r3-65744*g3+99232*b3+29032005)/4)/225930);
yuv_v[(x >> 1) + (y >> 1) * ycbcr[2].stride] =
clamp( ((157024*r0-131488*g0-25536*b0+45940035)/4 +
(157024*r1-131488*g1-25536*b1+45940035)/4 +
(157024*r2-131488*g2-25536*b2+45940035)/4 +
(157024*r3-131488*g3-25536*b3+45940035)/4)/357510);
}
}
}
else if (chroma_format == TH_PF_444)
{
for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
png_byte r = png[y][3 * x + 0];
png_byte g = png[y][3 * x + 1];
png_byte b = png[y][3 * x + 2];
yuv_y[x + y * yuv_w] = clamp((65481*r+128553*g+24966*b+4207500)/255000);
yuv_u[x + y * yuv_w] = clamp((-33488*r-65744*g+99232*b+29032005)/225930);
yuv_v[x + y * yuv_w] = clamp((157024*r-131488*g-25536*b+45940035)/357510);
}
}
}
else
{
for(y = 0; y < h; y += 1)
{
for(x = 0; x < w; x += 2)
{
x1=x+(x+1<w);
png_byte r0 = png[y][3 * x + 0];
png_byte g0 = png[y][3 * x + 1];
png_byte b0 = png[y][3 * x + 2];
png_byte r1 = png[y][3 * x1 + 0];
png_byte g1 = png[y][3 * x1 + 1];
png_byte b1 = png[y][3 * x1 + 2];
yuv_y[x + y * yuv_w] = clamp((65481*r0+128553*g0+24966*b0+4207500)/255000);
yuv_y[x1 + y * yuv_w] = clamp((65481*r1+128553*g1+24966*b1+4207500)/255000);
yuv_u[(x >> 1) + y * ycbcr[1].stride] =
clamp( ((-33488*r0-65744*g0+99232*b0+29032005)/2 +
(-33488*r1-65744*g1+99232*b1+29032005)/2)/225930);
yuv_v[(x >> 1) + y * ycbcr[2].stride] =
clamp( ((157024*r0-131488*g0-25536*b0+45940035)/2 +
(157024*r1-131488*g1-25536*b1+45940035)/2)/357510);
}
}
}
}
struct mem_file
{
char *buf;
size_t size;
size_t cur;
};
void mem_read(png_structp png_ptr, png_bytep buf, png_size_t sz)
{
mem_file * stream = (mem_file*)png_get_io_ptr(png_ptr);
size_t cp = sz;
if ((cp + stream->cur) > stream->size)
{
cp = stream->size - stream->cur;
}
memcpy(buf, &(stream->buf[stream->cur]), cp);
stream->cur += cp;
if (cp != sz)
png_error(png_ptr, "Read Error");
}
static int png_read(const void * buffer,
size_t buflen,
uint32_t *w, uint32_t *h,
th_ycbcr_buffer ycbcr)
{
uint8_t header[8];
png_structp png_ptr;
png_infop info_ptr;
png_infop end_ptr;
png_bytep row_data;
png_bytep *row_pointers;
png_color_16p bkgd;
png_uint_32 width;
png_uint_32 height;
uint64_t yuv_w;
uint64_t yuv_h;
int bit_depth;
int color_type;
int interlace_type;
int compression_type;
int filter_method;
png_uint_32 y;
memcpy(header, fp, 8);
if(png_sig_cmp(header, 0, 8))
{
cerr << "error:not a PNG" << endl;
return 1;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if(!png_ptr)
{
cerr << "error: couldn't create png read structure" << endl;
return 1;
}
info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
{
cerr << "error: couldn't create png info structure" << endl;
png_destroy_read_struct(&png_ptr, NULL, NULL);
return 1;
}
end_ptr = png_create_info_struct(png_ptr);
if(!end_ptr)
{
cerr << "error: couldn't create png info structure" << endl;
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return 1;
}
struct mem_file f = { .buf = fp, .size = buflen, .cur = 8 };
png_set_read_fn(png_ptr, &f, mem_read);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_method);
png_set_expand(png_ptr);
if(bit_depth<8)
png_set_packing(png_ptr);
if(bit_depth==16)
png_set_strip_16(png_ptr);
if(!(color_type&PNG_COLOR_MASK_COLOR))
png_set_gray_to_rgb(png_ptr);
if(png_get_bKGD(png_ptr, info_ptr, &bkgd))
{
png_set_background(png_ptr, bkgd, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
}
png_set_strip_alpha(png_ptr);
row_data = (png_bytep)png_malloc(png_ptr,
3*height*width*sizeof(*row_data));
row_pointers = (png_bytep *)png_malloc(png_ptr,
height*sizeof(*row_pointers));
for(y = 0; y < height; y++)
{
row_pointers[y] = row_data + y*(3*width);
}
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, end_ptr);
*w = width;
*h = height;
yuv_w = (*w + 15) & ~15;
yuv_h = (*h + 15) & ~15;
if (!ycbcr[0].data)
{
ycbcr[0].width = yuv_w;
ycbcr[0].height = yuv_h;
ycbcr[0].stride = yuv_w;
ycbcr[1].width = (chroma_format == TH_PF_444) ? yuv_w : (yuv_w >> 1);
ycbcr[1].stride = ycbcr[1].width;
ycbcr[1].height = (chroma_format == TH_PF_420) ? (yuv_h >> 1) : yuv_h;
ycbcr[2].width = ycbcr[1].width;
ycbcr[2].stride = ycbcr[1].stride;
ycbcr[2].height = ycbcr[1].height;
ycbcr[0].data = (uint8_t*) malloc(ycbcr[0].stride * ycbcr[0].height);
ycbcr[1].data = (uint8_t*) malloc(ycbcr[1].stride * ycbcr[1].height);
ycbcr[2].data = (uint8_t*) malloc(ycbcr[2].stride * ycbcr[2].height);
}
else
{
if ((ycbcr[0].width != (int64_t)yuv_w) || (ycbcr[0].height != (int64_t)yuv_h))
{
cerr << "Input size " << yuv_w << "x" << yuv_h <<
" does not match " << ycbcr[0].width << "x" << ycbcr[0].height << endl;
return 1;
}
}
rgb_to_yuv(row_pointers, ycbcr, *w, *h);
png_free(png_ptr, row_pointers);
png_free(png_ptr, row_data);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_ptr);
return 0;
}
static int theora_init(uint32_t w, uint32_t h)
{
srand(time(NULL));
if (ogg_stream_init(&ogg_os, rand()))
{
cerr << "error: couldn't create ogg stream state" << endl;
return 1;
}
if (discrete_delta > 0) {
video_fps_numerator = 1000 / discrete_delta;
keyframe_frequency = video_fps_numerator * 2 + 1;
}
th_info_init(&ti);
ti.frame_width = ((w + 15) >>4)<<4;
ti.frame_height = ((h + 15)>>4)<<4;
ti.pic_width = w;
ti.pic_height = h;
ti.pic_x = 0;
ti.pic_y = 0;
ti.fps_numerator = video_fps_numerator;
ti.fps_denominator = video_fps_denominator;
ti.aspect_numerator = video_aspect_numerator;
ti.aspect_denominator = video_aspect_denominator;
ti.colorspace = TH_CS_UNSPECIFIED;
ti.pixel_fmt = chroma_format;
ti.target_bitrate = video_rate;
ti.quality = video_quality;
ti.keyframe_granule_shift=ilog(keyframe_frequency-1);
td=th_encode_alloc(&ti);
th_info_clear(&ti);
int ret = th_encode_ctl(td,TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
&keyframe_frequency,
sizeof(keyframe_frequency - 1));
if (ret < 0)
cerr << "Could not set keyframe interval to " << (int)keyframe_frequency << endl;
if (soft_target) {
int arg = TH_RATECTL_CAP_UNDERFLOW;
ret=th_encode_ctl(td,TH_ENCCTL_SET_RATE_FLAGS,&arg,sizeof(arg));
if (ret < 0)
cerr << "Could not set encoder flags for --soft-target" << endl;
if((keyframe_frequency*7>>1) > 5*video_fps_numerator/video_fps_denominator)
arg = keyframe_frequency * 7 >> 1;
else
arg = 5 * video_fps_numerator/video_fps_denominator;
ret = th_encode_ctl(td,TH_ENCCTL_SET_RATE_BUFFER,&arg,sizeof(arg));
if (ret < 0)
cerr << "Could not set rate control buffer for --soft-target" << endl;
}
th_comment tc;
th_comment_init(&tc);
if (th_encode_flushheader(td,&tc,&op) <= 0) {
cerr << "Internal Theora library error" << endl;
return 1;
}
th_comment_clear(&tc);
ogg_stream_packetin(&ogg_os,&op);
if(ogg_stream_pageout(&ogg_os,&og)!=1) {
cerr << "Internal Ogg library error" << endl;
return 1;
}
outfile.write((const char *)og.header,og.header_len);
outfile.write((const char *)og.body,og.body_len);
for(;;)
{
ret=th_encode_flushheader(td,&tc,&op);
if(ret<0)
{
cerr << "Internal Theora library error" << endl;
return 1;
}
else if(!ret)
break;
ogg_stream_packetin(&ogg_os,&op);
}
for(;;)
{
int result = ogg_stream_flush(&ogg_os,&og);
if (result < 0) {
cerr << "Internal Ogg library error" << endl;
return 1;
}
if (result == 0)
break;
outfile.write((const char *)og.header,og.header_len);
outfile.write((const char *)og.body,og.body_len);
}
theora_initialized = true;
return 0;
}
static int theora_write_frame(th_ycbcr_buffer ycbcr, int last)
{
ogg_packet op;
ogg_page og;
if(th_encode_ycbcr_in(td, ycbcr))
{
cerr << "error: could not encode frame" << endl;
return 1;
}
if(!th_encode_packetout(td, last, &op))
{
cerr << "error: could not read packets" << endl;
return 1;
}
ogg_stream_packetin(&ogg_os, &op);
while (ogg_stream_pageout(&ogg_os, &og))
{
outfile.write((const char *)og.header, og.header_len);
outfile.write((const char *)og.body, og.body_len);
}
return 0;
}
{
cout << "CURL initialized" << endl;
}
{
char * res = NULL;
{
if (res)
{
cout << res << endl;
free(res);
}
}
running = 2;
}
{
cout << "Client disconnected" << endl;
running = 10;
}
void onConnChanged(
wcHandle self,
int state)
{
cout << "Client connection changed " << state << endl;
}
void onLog(
wcHandle self,
const char * str)
{
cout << str << endl;
}
static const string cDEVICE("device");
static const string cSUBPROTO("subproto");
static const string cDELTA("delta");
static const string RAW_PNG_PROTO("RAW_PNG");
static bool device_online = false;
static bool device_streaming = false;
{
wcJSON jarr(json);
if (jarr.isArray()) {
for (int i = 0; i < jarr.length(); i++) {
wcJSON obj = jarr.getArrayItem(i);
if (obj.isObject()) {
wcJSON name = obj.getObjItem(cDEVICE.c_str());
if (name.isString() && (input_device.compare(name.valueString()) == 0)) {
device_online = true;
break;
}
}
}
}
if (device_online && device_streaming)
running = 4;
else
running = 2;
}
{
wcJSON jarr(json);
if (jarr.isArray()) {
for (int i = 0; i < jarr.length(); i++) {
wcJSON obj = jarr.getArrayItem(i);
if (obj.isObject()) {
wcJSON name = obj.getObjItem(cDEVICE.c_str());
if (name.isString() && (input_device.compare(name.valueString()) == 0)) {
wcJSON subproto = obj.getObjItem(cSUBPROTO.c_str());
if (subproto.isString() && (RAW_PNG_PROTO.compare(subproto.valueString())== 0)) {
device_streaming = true;
wcJSON delta = obj.getObjItem(cDELTA.c_str());
if (delta.isNumber()) {
discrete_delta = delta.valueInt();
if (discrete_delta < 200) discrete_delta = 200;
}
break;
}
}
}
}
}
if (device_online && device_streaming)
running = 4;
else
running = 2;
}
{
cout << "Input stream closed" << endl;
running = 10;
}
{
cout << "Input stream started" << endl;
}
{
frame_size = MAX_INPUT_BUFFER;
uint32_t w, h;
if (png_read(mem_frame_buffer, frame_size, &w, &h, ycbcr)) {
cerr << "Could not read frame" << endl;
running = 10;
return;
}
if (!theora_initialized) {
if (theora_init(w, h)) {
cerr << "Could not init theora encoder" << endl;
running = 10;
return;
}
}
if (theora_write_frame(ycbcr, 0)) {
cerr << "Encoding error" << endl;
running = 10;
return;
}
}
}
}
class MyInputParser : public InputParser
{
public:
using InputParser::InputParser;
const std::string& getInput()
{
static const std::string CMD_INPUT("--input");
static const std::string CMD_INPUT_SYN("-i");
const std::string & res = getCmdOption(CMD_INPUT);
if (res.empty())
{
return getCmdOption(CMD_INPUT_SYN);
}
else
return res;
}
const std::string& getOutput()
{
static const std::string CMD_OUTPUT("--output");
static const std::string CMD_OUTPUT_SYN("-o");
const std::string & res = getCmdOption(CMD_OUTPUT);
if (res.empty())
{
return getCmdOption(CMD_OUTPUT_SYN);
}
else
return res;
}
const int getVideoQuality()
{
static const std::string CMD_VIDEOQ("--video-quality");
static const std::string CMD_VIDEOQ_SYN("-v");
std::string res = getCmdOption(CMD_VIDEOQ);
if (res.empty())
res = getCmdOption(CMD_VIDEOQ_SYN);
int vq;
if (!res.empty()) {
vq = rint(atof(res.c_str())*6.3);
if (vq<0 || vq>63){
cerr << "Illegal video quality (choose 0 through 10)" << endl;
return 0;
}
} else vq = 25;
return vq;
}
const int getVideoRate()
{
static const std::string CMD_VIDEOR("--video-rate");
static const std::string CMD_VIDEOR_SYN("-V");
std::string res = getCmdOption(CMD_VIDEOR);
if (res.empty())
res = getCmdOption(CMD_VIDEOR_SYN);
int vq;
if (!res.empty()) {
vq = atoi(res.c_str()) * 1024;
} else vq = 0;
return vq;
}
const th_pixel_fmt getChroma()
{
static const std::string CMD_CHROMA("--chroma");
const std::string & res = getCmdOption(CMD_CHROMA);
th_pixel_fmt vq;
if (!res.empty()) {
int vqv = atoi(res.c_str());
switch (vqv) {
case 444 : vq = TH_PF_444;
break;
case 422 : vq = TH_PF_422;
break;
case 420 : vq = TH_PF_420;
break;
default:
cerr << "Illegal chroma subsampling: " << vqv << endl;
vq = TH_PF_420;
break;
}
} else vq = TH_PF_420;
return vq;
}
virtual void printCommonHelp() override
{
InputParser::printCommonHelp();
cout << " -i --input <devicename> the device name to get data stream from (required);" << endl;
cout << " -o --output <filename.ogv> file name for encoded output (required);" << endl;
cout << " -v --video-quality <n> Theora quality selector from 0 to 10" << endl;
cout << " (0 yields smallest files but lowest" << endl;
cout << " video quality. 10 yields highest" << endl;
cout << " fidelity but large files)" << endl;
cout << " -V --video-rate <n> bitrate target for Theora video in kbits per second" << endl;
cout << " Use a large reservoir and treat the rate" << endl;
cout << " as a soft target; rate control is less" << endl;
cout << " strict but resulting quality is usually" << endl;
cout << " higher/smoother overall. Soft target also" << endl;
cout << " allows an optional -v setting to specify" << endl;
cout << " a minimum allowed quality." << endl;
cout << " --chroma {444|422|420} Use 4:4:4 chroma subsampling" << endl;
cout << " Use 4:2:2 chroma subsampling" << endl;
cout << " (4:2:0 is default)" << endl;
}
};
int main(int argc, char * argv[])
{
MyInputParser input(argc, argv);
const std::string &host = input.getHost();
const std::string &proxy = input.getProxy();
const std::string &user = input.getUserName();
const std::string &pwrd = input.getUserPassword();
std::string device = input.getDevice();
if (device.empty())
device = "device_test001_input";
input_device = input.getInput();
if (input_device.empty())
input_device = "device_test001_output";
std::string output_file = input.getOutput();
if (output_file.empty())
output_file = "output.ogv";
if (input.showHelp())
{
input.printCommonHelp();
return 0;
}
outfile = ofstream(output_file, ios::out | ios::trunc | ios::binary);
if (!outfile.is_open())
{
cerr << "Can't open output file. Wrong file name or the file is blocked: " << output_file << endl;
return 1;
}
chroma_format = input.getChroma();
video_quality = input.getVideoQuality();
video_rate = input.getVideoRate();
if (video_rate > 0) { soft_target = true; }
if (!host.empty())
{
if (input.ignoreTLSCert())
if (!proxy.empty())
auto start_timestamp = std::chrono::system_clock::now();
while (running < 8)
{
switch (running)
{
case 0:
{
running = 1;
break;
}
case 2:
{
running = 3;
break;
}
case 4:
{
mem_frame_buffer = (char*)malloc(MAX_INPUT_BUFFER);
ycbcr[0].data = 0;
running = 5;
break;
}
default:
{
break;
}
}
if (running < 5)
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
else
std::this_thread::sleep_for(std::chrono::milliseconds(50));
auto current_timestamp = std::chrono::system_clock::now();
auto int_s = chrono::duration_cast<chrono::seconds>(current_timestamp - start_timestamp);
if (int_s.count() >= TIME_OUT) {
cout << "timeout" << endl;
break;
}
}
if (mem_frame_buffer)
free(mem_frame_buffer);
if (theora_initialized)
{
th_encode_free(td);
free(ycbcr[0].data);
free(ycbcr[1].data);
free(ycbcr[2].data);
if(ogg_stream_flush(&ogg_os, &og))
{
outfile.write((const char *)og.header, og.header_len);
outfile.write((const char *)og.body, og.body_len);
}
outfile.flush();
ogg_stream_clear(&ogg_os);
}
outfile.close();
return 0;
}
else
{
cout << "should contain at least --host (host-name) option";
}
}
wcRCode DLLEXPORT wcSetTaskCallback(wcHandle client, wcCallback callbackId, TaskNotifyLibFunc func)
Set specified task notify callback for client.
wcRCode DLLEXPORT wcSetNotifyCallback(wcHandle client, wcCallback callbackId, NotifyEventLibFunc func)
Set specified notify callback for client.
wcRCode DLLEXPORT wcSetCStringCallback(wcHandle client, wcCallback callbackId, CStringNotifyLibFunc func)
Set specified notify callback for client to handling the C-style string values.
wcRCode DLLEXPORT wcSetJSONStrCallback(wcHandle client, wcCallback callbackId, JSONStrNotifyEventLibFunc func)
Set specified notify callback for client to process the JSON-formatted response results represented a...
wcRCode DLLEXPORT wcSetConnCallback(wcHandle client, ConnNotifyEventLibFunc func)
Set specified connection notify callback for client.
@ wccbkAddLog
Added new log entry.
Definition: wcwebcamclient.h:140
@ wccbkSynchroUpdateTask
The IO streaming task signals that a change has occurred.
Definition: wcwebcamclient.h:141
@ wccbkAfterLaunchInStream
Incoming stream started.
Definition: wcwebcamclient.h:144
@ wccbkInitCURL
Successful initialization of the multiCURL handle.
Definition: wcwebcamclient.h:135
@ wccbkSuccessAuth
Successful authorization.
Definition: wcwebcamclient.h:136
@ wccbkSuccessUpdateDevices
The request to update list of online devices has been completed.
Definition: wcwebcamclient.h:154
@ wccbkSuccessIOStream
IO stream terminated for some reason.
Definition: wcwebcamclient.h:146
@ wccbkDisconnect
Client has been disconnected.
Definition: wcwebcamclient.h:138
@ wccbkSuccessUpdateStreams
The request to update list of streaming devices has been completed.
Definition: wcwebcamclient.h:155
wcRCode DLLEXPORT wcClientGetStrValue(wcHandle client, wcStateId aStateId, char **aStateVal)
Get a C-style string value for the selected client state.
wcRCode DLLEXPORT wcClientInvalidateState(wcHandle client, wcStateId aStateId)
Reset the selected client state.
wcRCode DLLEXPORT wcClientSetStrValue(wcHandle client, wcStateId aStateId, const char *aStateVal)
Set a C-style string value to the selected client state.
wcRCode DLLEXPORT wcClientSetBoolState(wcHandle client, wcStateId aStateId, wcStateVal aStateVal)
Set the boolean value to the selected client state.
@ wcstDevices
Definition: wcwebcamclient.h:180
@ wcstStreams
Definition: wcwebcamclient.h:179
@ wcstDeviceName
Definition: wcwebcamclient.h:187
@ wcstSID
Definition: wcwebcamclient.h:188
@ wcstProxy
Definition: wcwebcamclient.h:190
@ wcstHostName
Definition: wcwebcamclient.h:189
@ wcstVerifyTLS
Definition: wcwebcamclient.h:175
wcHandle DLLEXPORT wcClientCreate()
Create client.
wcRCode DLLEXPORT wcClientTasksProceed(wcHandle client)
Call the synchronous client update stage.
wcRCode DLLEXPORT wcClientDisconnect(wcHandle client)
Disconnect client from the server host.
wcRCode DLLEXPORT wcClientProceed(wcHandle client)
Call the asynchronous client update stage.
wcRCode DLLEXPORT wcClientAuth(wcHandle client, const char *aLogin, const char *aPwrd)
Authorize client on the server host.
wcRCode DLLEXPORT wcClientDestroy(wcHandle client)
Destroy client.
wcRCode DLLEXPORT wcClientStart(wcHandle client)
Launch client.
wcRCode DLLEXPORT wcLaunchInStream(wcHandle client, const char *deviceName, void *data)
Launch task to consume incoming stream from the specified device for authorized client.
wcRCode DLLEXPORT wcInTaskPopFrame(wcTask task, void **data, size_t *len)
Get access to the first frame in the incoming data stack.
const wcRCode WC_OK
Definition: wcwebcamclient.h:74
const wcRCode WC_FALSE
Definition: wcwebcamclient.h:71
wcRCode DLLEXPORT wcTaskGetClass(wcTask task, wcTaskClass *id)
Get the class of the task.
const wcTaskClass WC_BASE_TASK
The Base task class.
Definition: wcwebcamclient.h:108
const wcTaskClass WC_IN_STREAM_TASK
The Input-stream task class (for GET requests)
Definition: wcwebcamclient.h:112
int wcHandle
Client handle.
Definition: wcwebcamclient.h:99
wcCallbackTask wcTask
Pointer to task.
Definition: wcwebcamclient.h:102
const uint16_t WC_STREAM_FRAME_HEADER_SIZE
The size of frame header (6 bytes)
Definition: wcwebcamclient.h:119
uint32_t wcTaskClass
Task class.
Definition: wcwebcamclient.h:105