Skip to content

Instantly share code, notes, and snippets.

@roxlu

roxlu/Webm.cpp Secret

Created February 1, 2013 23:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roxlu/62e8a92beff6845eed92 to your computer and use it in GitHub Desktop.
Save roxlu/62e8a92beff6845eed92 to your computer and use it in GitHub Desktop.
#include "Webm.h"
void webm_vpx_write_cb(const vpx_codec_cx_pkt_t* pkt, void* user) {
printf("Got encoded frame!\n");
}
void webm_encoder_thread(void* user) {
Webm& webm = *(static_cast<Webm*>(user));
std::vector<WebmPacket*> work_packets;
WebmPacket* pkt = NULL;
bool stop = false;
while(true) {
uv_mutex_lock(&webm.packets_mutex);
std::copy(webm.packets.begin(), webm.packets.end(), std::back_inserter(work_packets));
webm.packets.clear();
uv_mutex_unlock(&webm.packets_mutex);
for(std::vector<WebmPacket*>::iterator it = work_packets.begin(); it != work_packets.end(); ++it) {
pkt = *it;
webm.vid_enc.encode(pkt->buf, pkt->timestamp);
delete[] pkt->buf;
delete pkt;
// pkt = NULL;
}
work_packets.clear();
printf("??\n");
uv_mutex_lock(&webm.stop_mutex);
stop = webm.must_stop;
uv_mutex_unlock(&webm.stop_mutex);
if(stop) {
printf("STOPPPING.\n");
break;
}
}
}
Webm::Webm()
:ebml(NULL)
,vid_in_w(0)
,vid_in_h(0)
,vid_out_w(0)
,vid_out_h(0)
,vid_fps(0)
,vid_fmt(VPX_IMG_FMT_NONE)
,vid_num_frames(0)
,must_stop(false)
{
}
Webm::~Webm() {
shutdown();
}
bool Webm::setupVideo(int inW,
int inH,
int outW,
int outH,
int fps,
vpx_img_fmt fmt)
{
vid_in_w = inW;
vid_in_h = inH;
vid_out_w = outW;
vid_out_h = outH;
vid_fps = fps;
vid_fmt = fmt;
bool is_setup = vid_enc.setup(vid_in_w, vid_in_h, vid_out_w,
vid_out_h, vid_fps, vid_fmt,
webm_vpx_write_cb, this);
if(!is_setup) {
return false;
}
return true;
}
bool Webm::setupAudio() {
return true;
}
bool Webm::initialize() {
if(!initializeThread()) {
return false;
}
if(!vid_enc.initialize()) {
return false;
}
return true;
}
bool Webm::open() {
if(!openEBML()) {
return false;
}
return true;
}
bool Webm::openEBML() {
assert(ebml != NULL);
EBMLHeader h;
h.ebml_version = 1;
h.ebml_read_version = 1;
h.ebml_max_id_length = 4;
h.ebml_max_size_length = 8;
h.doctype = "webm";
h.doctype_version = 2;
h.doctype_read_version = 2;
return ebml->open(h);
}
bool Webm::shutdown() {
stopThread();
return true;
}
bool Webm::close() {
ebml->close();
vid_num_frames = 0;
return true;
}
bool Webm::startThread() {
uv_thread_create(&thread, webm_encoder_thread, this);
return true;
}
bool Webm::stopThread() {
uv_mutex_lock(&stop_mutex);
must_stop = true;
uv_mutex_unlock(&stop_mutex);
uv_thread_join(&thread);
return true;
}
bool Webm::initializeThread() {
if(uv_mutex_init(&stop_mutex) != 0) {
return false;
}
if(uv_mutex_init(&packets_mutex) != 0) {
return false;
}
return true;
}
void Webm::addVideoFrame(unsigned char* data, int nbytes) {
WebmPacket* p = new WebmPacket();
if(!p) {
printf("ERROR: out of mem\n");
return;
}
p->buf = new unsigned char[nbytes];
if(!p->buf) {
printf("ERROR: out of mem\n");
return;
}
memcpy(p->buf, data, nbytes);
p->timestamp = vid_num_frames;
p->type = WPT_VIDEO;
uv_mutex_lock(&packets_mutex);
packets.push_back(p);
uv_mutex_unlock(&packets_mutex);
vid_num_frames++;
}
#ifndef ROXLU_WEBM_H
#define ROXLU_WEBM_H
#include <assert.h>
#include <inttypes.h>
#include <vector>
#include <algorithm>
extern "C" {
# include <uv.h>
}
#include "EBML.h"
#include "VPX.h"
enum WebmPacketTypes {
WPT_VIDEO,
WPT_AUDIO
};
struct WebmPacket {
unsigned char* buf;
int nbytes;
char type;
int64_t timestamp;
};
void webm_vpx_write_cb(const vpx_codec_cx_pkt_t* pkt, void* user);
void webm_encoder_thread(void* user);
class Webm {
public:
Webm();
~Webm();
void setEBML(EBML* ebml);
bool setupVideo(int inW, /* video in width */
int inH, /* video in height */
int outW, /* video out width */
int outH, /* video out height */
int fps, /* video fps */
vpx_img_fmt fmt); /* video pixel format */
bool setupAudio(); // todo
bool initialize();
bool shutdown();
bool open();
bool close();
bool startThread();
bool stopThread();
void addVideoFrame(unsigned char* data, int nbytes);
private:
bool openEBML(); /* open the EBML stream */
bool initializeThread(); /* initialize thread related members */
public:
EBML* ebml;
/* video */
int vid_in_w; /* video input width */
int vid_in_h; /* video input height */
int vid_out_w; /* video output width */
int vid_out_h; /* video output height */
int vid_fps; /* video frames per second */
int64_t vid_num_frames; /* number of encoded/added frames */
vpx_img_fmt vid_fmt; /* video input pixel format */
VPX vid_enc; /* video encoder; wrapper around libvpx */
std::vector<WebmPacket*> packets; /* contains video/audio packets that needs to be encoded */
public:
/* threading */
bool must_stop;
uv_thread_t thread;
uv_mutex_t stop_mutex;
uv_mutex_t packets_mutex;
};
inline void Webm::setEBML(EBML* ebml) {
this->ebml = ebml;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment