[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