Months passed, my computer exploded and it looked like everything was dead... until the other night I decided it was time to do something and this got my attention once again.
Now, when my computer died due to a few mistakes I lost all the conversion code I wrote; this is a good thing.
As good as my SSE was it was being spanked by a lookup table version, heh.. although that was lost as well [sad]
So, I started from the top tuesday night and spec'd out some ideas about how I wanted it to work and wrote a basic interface;
A library to allow drop in encoding of RGB data (framebuffer) to a
compressed ogg stream via Theora
- Initalise with a filename/stream to save to
-- version 1.0 just has a filename for now
- start encoder
-- encoder pre-allocates a series of buffers
-- spawns a worker thread to do the encoding work
- request a buffer from encoder lib
-- this can block if the encoder is too far behind
- use supplied buffer to pass RGB/RGBA data to encoder
- Performs colour space conversion from RGB=>YUV via lookup table
-- this frees RGB buffer to be reused as it's copied into an internal buffer
-- UV data needs to be 1/4 that of Y data; need to resample
--- ? simple drop or do a proper filter on the image ?
- YUV is passed to lib Theora for encoding
- when completed write frame data out
- system must request end of encoding
-- lib writes special frame data out and shuts down as required
* no sound support as yet...
* might want to cue a frame in advance before we being encoding, last frame
is flushed on shutdown request
basic API ideas;
void initialiseEncoder(std::string &filename); // setup stream + internals
void beginEncoding(int width, int height); // preallocate buffers
char * requestRGBBuffer(); // pass a pointer to a RGB buffer out (handle type maybe?)
void processRGBBuffer(char * buffer); // process the buffer back again
void endEncodering(); // flush all buffers and close stream
void shutdownEncoder(); // or maybe this name?
Initialise becomes the constructor, the rest member functions...
That was where I started tuesday night... I then distracted myself for 24h to give my brain a chance to process the ideas.
Tonight, about 2:30am I picked it up again, the net result is the following interface (and code behind it, you'll have to trust me on that, heh)
TheoraEncoder(std::string const& filename, int width, int height);
unsigned char * requestBuffer();
void processBuffer(unsigned char * buffer);
void Process(); // TEMP!!!! this will be a threaded section!
void Process(bool lastframe);
std::queue<unsigned char *> rgbfreebuffers;
std::queue<unsigned char *> rgbusedbuffers;
unsigned char * ybuffer;
unsigned char * vbuffer;
unsigned char * ubuffer;
int height, width, video_height, video_width, frame_x_offset, frame_y_offset;
ogg_stream_state to; /* take physical pages, weld into a logical
stream of packets */
ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
ogg_packet op; /* one raw packet of data for decode */
FILE * outfile;
Not overly comment and no support for encoding in a second thread yet (thus teh big 'TEMP!' comment [grin]
The code might need some refining, however the process is pretty simple;
- Construct a TheoraEncoder object, giving it the filename and sizes
This will do all the Theora/Ogg setup and open the output file.
- Request a start to encoding
Memory is reserved for a number of buffers (right now 2xRGB and 1xYUV, the RGB might be made variable)
- Per-frame you want to encode;
- Request a pointer to a buffer (in MT mode this will block until a buffer is free)
- Fill the buffer with RGB data
- Send it back for processing
- when you are done, tell it to enencoding and the final frames are flushed and memory buffers released
- On destruction the file is closed
The file stuff and maybe some of the init and final frame flushing might require some more thought (mostly todo with when these things should happen), however the basic theory is sound.
I'd be testing it about now, indeed it's mostly intergrated into an FBO example I've got which uses GLUT, however due to a mild library incompatiblity I can't be bothered to solve right now it's not linking [sad]
I'm a bit tired now so I plan on fixing it tomorrow... of course I also plan to go down the pub, so I'll have to do it before I pickle my brain, heh