[Theora-dev] Re: [Theora] Small memory leak...

Mat heavensdoor78 at gmail.com
Thu Oct 27 02:28:14 PDT 2005


Thank you for your reply!

Ralph Giles wrote:

>Right. As the comment says, the caller has to free this to avoid 
>leaking (but not if building against libogg2). 
>
Yep... but how can I enable libogg2 ?
I looked in xiph.org downloads... I suppose there aren't targz packages 
ready... right?
Do I have to get it from svn ? Do you think  libogg2  is very stable... ?

>It's hard to tell without seeing your code, but is the 
>op->packet you free at the end the same one theora_encode_comment() 
>allocated, or have you reused the op struct in other calls since?
>  
>
Mmm... I made some changes to the encoder sample in theora.
But I suppose the leak is in the sample too...
Perhaps I need only to look better where to put the free statement.
I post my code, I have little experience with theora so if you have 
comments/advice they are very appreciated !

=== test.c ===

#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 = 125;

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_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;

        serial1 = rand();
        ogg_stream_init( &to,serial1 );
    }

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

_ogg_free(op.packet);

    fclose( outfile );

    free( yuvframe );

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

    return 0;
}



More information about the Theora-dev mailing list