Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    455
  • comments
    639
  • views
    424152

A Mildly Productive Phantom : Video Enc Part 3

Sign in to follow this  
_the_phantom_

70 views

Now, you may or may not remember but back in June of this year I was firstly swearing about the GPL and XVid and then muttering about using Theora to encode video with some shiny SSE goodness etc etc

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

Useage process:
- Initalise with a filename/stream to save to
-- version 1.0 just has a filename for now

Encoding:
- start encoder
-- encoder pre-allocates a series of buffers
-- spawns a worker thread to do the encoding work

per frame:
- 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

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

End :
- system must request end of encoding
-- lib writes special frame data out and shuts down as required

Notes:

* 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?

class maybe?
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)

namespace FrameEncoder
{

class TheoraEncoder
{
public:
TheoraEncoder(std::string const& filename, int width, int height);
~TheoraEncoder();

void beginEncoding();
unsigned char * requestBuffer();
void processBuffer(unsigned char * buffer);
void endEncoding();

void Process(); // TEMP!!!! this will be a threaded section!

protected:
private:
void Process(bool lastframe);
void WriteData();

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_page videopage;

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 */

theora_state td;
theora_info ti;
theora_comment tc;

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
Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!