[Theora] Simple encodig sample...

Mat heavensdoor78 at gmail.com
Wed Oct 5 06:40:58 PDT 2005


Hi all.
I'm Mat & I'm new :)

I'm testing libtheora + libogg perhaps for a commercial product.

I started watching  encoder_example.c  ... I simplified it for testing 
it easier.
It seems ok to me but I have no experience with theora so I would like 
to know if my code is correct.

I tried to debug it with Valgrind and I found 4 possible memory leaks...
but I think they can be found in the original sample too ( 
encoder_example.c ) ... right?
( 1 about theora_encode_comment - row 195 )
( 3 about ogg_stream_init - row 133 )

Sorry for my english. Thanx in advance.
-Mat-

=== CODE ===

#define _GNU_SOURCE
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64

#ifndef _REENTRANT
# define _REENTRANT
#endif

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include "theora/theora.h"

#define STREAM_EOP  1   // End-of-page
#define STREAM_EOD  2   // End-of-data
#define STREAM_EOS  3   // End-of-stream

#define SPIN    "|/-\\"

int video_x         = 0;
int video_y         = 0;
int frame_x         = 352;
int frame_y         = 288;
int frame_x_offset  = 0;
int frame_y_offset  = 0;
int video_hzn       = 25;
int video_hzd       = 1;
int video_an        = 1;
int video_ad        = 1;

int video_r  = 320000;
int video_q  = 16;

int frame_counter = 250;

signed char *yuvframe;

int fetch_video_page( ogg_page *videopage, ogg_stream_state *to, 
theora_state *td )
{
    yuv_buffer  yuv;
    ogg_packet  op;

    yuv.y_width  = video_x;
    yuv.y_height = video_y;
    yuv.y_stride = video_x;

    yuv.uv_width  = video_x / 2;
    yuv.uv_height = video_y / 2;
    yuv.uv_stride = video_x / 2;

    yuv.y = yuvframe;
    yuv.u = yuvframe + video_x * video_y;
    yuv.v = yuvframe + video_x * video_y * 5 / 4;

/* is there a video page flushed?  If not, work until there is. */
    while( 1 )
    {
        frame_counter--;
        fprintf( stderr, "\r%c", SPIN[frame_counter%4] );

    /* fill the frame data */
        memset( yuvframe, frame_counter % 255, video_x * video_y );
        memset( yuvframe + video_x * video_y, frame_counter % 128, 
video_x * video_y / 2 );

    /* encode the frame */
        theora_encode_YUVin( td, &yuv );

        if( frame_counter < 0 )
            theora_encode_packetout( td, 1, &op );
        else
            theora_encode_packetout( td, 0, &op );

        ogg_stream_packetin( to, &op );

        if( ogg_stream_pageout( to, videopage ) > 0 )
        {
            if( frame_counter < 0 )
                return STREAM_EOD;
            else
                return STREAM_EOP;
        }
        if( ogg_stream_eos( to ) )
            return STREAM_EOS;
    }

/* unreachable */
    return 0;
}

int main( int argc,char *argv[] )
{
    ogg_stream_state to;    /* take physical pages, weld into a logical 
stream of packets */
    ogg_stream_state vo;    /* 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;

    int vkbps = 0;
    int ret;

    ogg_int64_t video_bytesout = 0;
    double      timebase;

    FILE* outfile;


    outfile = fopen( "test.ogg","wb" );
    if( outfile == NULL )
    {
        fprintf( stderr, "Unable to open output file '%s'\n", "test.ogg" );
        exit( 1 );
    }

    srand( time( NULL ) );
    {
        /* need two inequal serial numbers */
        int serial1, serial2;

        serial1 = rand();
        serial2 = rand();
        if( serial1 == serial2 )
            serial2++;
        ogg_stream_init( &to,serial1 );
        ogg_stream_init( &vo,serial2 );
    }

/* Set up Theora encoder */

/* Theora has a divisible-by-sixteen restriction for the encoded video 
size */
/* scale the frame size up to the nearest /16 and calculate offsets */
    video_x = ( ( frame_x + 15 ) >> 4 ) << 4;
    video_y = ( ( frame_y + 15 ) >> 4 ) << 4;

/* We force the offset to be even. This ensures that the chroma samples 
align
   properly with the luma samples. */
    frame_x_offset = ( ( video_x - frame_x ) / 2 ) & ~1;
    frame_y_offset = ( ( video_y - frame_y ) / 2 ) & ~1;

    yuvframe = malloc( video_x * video_y * 3 / 2 );

    theora_info_init( &ti );

    ti.width                = video_x;
    ti.height               = video_y;
    ti.frame_width          = frame_x;
    ti.frame_height         = frame_y;
    ti.offset_x             = frame_x_offset;
    ti.offset_y             = frame_y_offset;
    ti.fps_numerator        = video_hzn;
    ti.fps_denominator      = video_hzd;
    ti.aspect_numerator     = video_an;
    ti.aspect_denominator   = video_ad;
    ti.colorspace           = OC_CS_UNSPECIFIED;
    ti.pixelformat          = OC_PF_420;
    ti.target_bitrate       = video_r;
    ti.quality              = video_q;

    ti.dropframes_p                 = 0;
    ti.quick_p                      = 1;
    ti.keyframe_auto_p              = 1;
    ti.keyframe_frequency           = 64;
    ti.keyframe_frequency_force     = 64;
    ti.keyframe_data_target_bitrate = video_r * 1.5;
    ti.keyframe_auto_threshold      = 80;
    ti.keyframe_mindistance         = 8;
    ti.noise_sensitivity            = 1;

    theora_encode_init( &td, &ti );
    theora_info_clear( &ti );

/* write the bitstream header packets with proper page interleave */

/* first packet will get its own page automatically */
    theora_encode_header( &td, &op );
    ogg_stream_packetin( &to, &op );
    if( ogg_stream_pageout( &to, &og ) != 1 )
    {
        fprintf( stderr, "Internal Ogg library error.\n" );
        exit( 1 );
    }
    fwrite( og.header, 1, og.header_len, outfile );
    fwrite( og.body, 1, og.body_len, outfile );

/* create the remaining theora headers */
    theora_comment_init( &tc );
    theora_encode_comment( &tc, &op );
    ogg_stream_packetin( &to, &op );
    theora_encode_tables( &td, &op );
    ogg_stream_packetin( &to, &op );

/* Flush the rest of our headers. This ensures the actual data in each 
stream
   will start on a new page, as per spec. */
    while( 1 )
    {
        int result = ogg_stream_flush( &to, &og );

        if( result < 0 )
        {
            fprintf( stderr, "Internal Ogg library error.\n" );
            exit( 1 );
        }
        if( result == 0 )
            break;

        fwrite( og.header, 1, og.header_len, outfile );
        fwrite( og.body, 1, og.body_len, outfile );
    }

/* setup complete.  Raw processing loop */
    fprintf( stderr, "Compressing....\n" );
    while( 1 )
    {
        double videotime;
        ogg_page videopage;

    /* is there a video page flushed?  If not, fetch one if possible */
        ret = fetch_video_page( &videopage, &to, &td );

    /* no pages of either?  Must be end of stream. */
        if( ret == STREAM_EOS )
            break;

    /* Flush to stream */
        videotime = theora_granule_time( &td,ogg_page_granulepos( 
&videopage ) );

        /* flush a video page */
        video_bytesout += fwrite( videopage.header, 1, 
videopage.header_len, outfile );
        video_bytesout += fwrite( videopage.body, 1, videopage.body_len, 
outfile );
        timebase = videotime;
        {
            int hundredths = timebase * 100 - (long) timebase * 100;
            int seconds = ( long) timebase % 60;
            int minutes = ( (long) timebase / 60 ) % 60;
            int hours = (long) timebase / 3600;

            vkbps = rint( video_bytesout * 8. / timebase * .001 );
            fprintf( stderr, "\r      %d:%02d:%02d.%02d video: 
%dkbps                 ", hours, minutes, seconds, hundredths, vkbps );
        }
 
        if( ret == STREAM_EOD )
            break;
    }

/* clear out state */
    ogg_stream_clear( &to );
    theora_clear( &td );

    fclose( outfile );

    free( yuvframe );

    fprintf( stderr, "\r   \ndone.\n\n" );

    return 0;
}



More information about the Theora mailing list