Files
FreeJ/xcode/encoder_example1.c
2010-02-28 14:28:54 +01:00

617 lines
22 KiB
C

#include <encoder_example.h>
// InOut Hi, i'm using globals, not good :
ogg_stream_state myGlob_to; /* take physical pages, weld into a logical stream of packets */
ogg_stream_state myGlob_vo; /* take physical pages, weld into a logical stream of packets */
ogg_page myGlob_og; /* one Ogg bitstream page. Vorbis packets are inside */
ogg_packet myGlob_op; /* one raw packet of data for decode */
theora_state myGlob_td;
theora_info myGlob_ti;
theora_comment myGlob_tc;
vorbis_info myGlob_vi; /* struct that stores all the static vorbis bitstream settings */
vorbis_comment myGlob_vc; /* struct that stores all the user comments */
vorbis_dsp_state myGlob_vd; /* central working state for the packet->PCM decoder */
vorbis_block myGlob_vb; /* local working space for packet->PCM decode */
FILE* outfile ; /// InOut file where im writing for tests
FILE* testOutFile ;
size_t audio_bytesout=0;
size_t video_bytesout=0;
int audioflag=0;
int videoflag=0;
int akbps=0;
int vkbps=0;
int myGlob_state ; // For allocating memory at the beginning
/* You'll go to Hell for using globals. */
FILE *audio=NULL;
FILE *video=NULL;
int audio_ch=0;
int audio_hz=0;
float audio_q=.1;
int audio_r=-1;
int video_x=0;
int video_y=0;
int frame_x=0;
int frame_y=0;
int frame_x_offset=0;
int frame_y_offset=0;
int noise_sensitivity=1;
int sharpness=0;
int keyframe_frequency=1;
/*
int yuv_copy__422_to_420(void *b_2vuy, SInt32 b_2vuy_stride, size_t width, size_t height, size_t offset_x, size_t offset_y, yuv_buffer *dst)
{
UInt8 *base = b_2vuy;
size_t off_x = offset_x & ~0x01, off_y = offset_y & ~0x01;
size_t off_x2 = offset_x >> 1, off_y2 = offset_y >> 1;
UInt8 *y_base = dst->y + off_y * dst->y_stride + off_x;
UInt8 *cb_base = dst->u + off_y2 * dst->uv_stride + off_x2;
UInt8 *cr_base = dst->v + off_y2 * dst->uv_stride + off_x2;
size_t x, y;
for (y = 0; y < height; y += 2) {
UInt8 *b_top = base;
UInt8 *b_bot = base + b_2vuy_stride;
UInt8 *y_top = y_base;
UInt8 *y_bot = y_base + dst->y_stride;
UInt8 *cb = cb_base;
UInt8 *cr = cr_base;
for (x = 0; x < width; x += 2) {
*cb++ = (UInt8) (((UInt16) *b_top++ + (UInt16) *b_bot++) >> 1);
*y_top++ = *b_top++;
*y_bot++ = *b_bot++;
*cr++ = (UInt8) (((UInt16) *b_top++ + (UInt16) *b_bot++) >> 1);
*y_top++ = *b_top++;
*y_bot++ = *b_bot++;
}
base += 2 * b_2vuy_stride;
y_base += 2 * dst->y_stride;
cb_base += dst->uv_stride;
cr_base += dst->uv_stride;
}
return 1;
}
*/
debug_dump(const char *fn, uint8_t *data, size_t len) {
FILE *F = fopen(fn,"w");
fwrite(data,sizeof(uint8_t), len, F);
fclose(F);
}
int yuv_copy__argb_to_420(void *b_rgb, SInt32 b_rgb_stride, size_t width, size_t height, size_t offset_x, size_t offset_y, yuv_buffer *dst)
{
// TODO: offset ! & strides
#define _CR ((float)((bptr[(4*i)+1])&0xff))
#define _CG ((float)((bptr[(4*i)+2])&0xff))
#define _CB ((float)((bptr[(4*i)+3])&0xff))
#define _CRX ((float)( ( ((bptr[(4*i)+1])&0xff) + ((bptr[(4*(i+1))+1])&0xff) + ((bptr[(4*(i+1+width))+1])&0xff) + ((bptr[(4*(i+1+width))+1])&0xff) )>>2))
#define _CGX ((float)( ( ((bptr[(4*i)+2])&0xff) + ((bptr[(4*(i+1))+2])&0xff) + ((bptr[(4*(i+1+width))+2])&0xff) + ((bptr[(4*(i+1+width))+2])&0xff) )>>2))
#define _CBX ((float)( ( ((bptr[(4*i)+3])&0xff) + ((bptr[(4*(i+1))+3])&0xff) + ((bptr[(4*(i+1+width))+3])&0xff) + ((bptr[(4*(i+1+width))+3])&0xff) )>>2))
uint8_t *bptr = (uint8_t*) b_rgb;
int i; int c=0;
for (i=0;i<width*height;i++) {
double Y = (0.299 * _CR) + (0.587 * _CG) + (0.114 * _CB);
if (Y<1) dst->y[i]=(uint8_t)0;
else if (Y>254) dst->y[i]=(uint8_t)255;
else dst->y[i]=(uint8_t) floor(Y+.5);
#if 1
if (i%2==0 && ((i/width)%2)==0 && i < (width-1)*height) {
double V = (0.500 * _CRX) - (0.419 * _CGX) - (0.081 * _CBX) + 128;
double U = -(0.169 * _CRX) - (0.331 * _CGX) + (0.500 * _CBX) + 128;
if (U<1) dst->u[c]=(uint8_t)0;
else if (U>254) dst->u[c]=(uint8_t)255;
else dst->u[c]=(uint8_t) floor(U+.5);
if (V<1) dst->v[c]=(uint8_t)0;
else if (V>254) dst->v[c]=(uint8_t)255;
else dst->v[c]=(uint8_t) floor(V+.5);
c++;
}
#endif
}
return 1;
}
int fetch_and_process_video(CVPixelBufferRef theBuffer,ogg_page *videopage,
ogg_stream_state *to,
theora_state *td,
int localVideoflag){
//printf("fetch_and_process_video()\n") ;
/* You'll go to Hell for using static variables */
static unsigned char *myGlob_yuvframe;
yuv_buffer myGlob_yuv;
ogg_packet op;
if(myGlob_state==-1){
/* initialize the double frame buffer */
//printf("INOUT - initialize the double frame buffer...\n") ;
//myGlob_yuvframe = new unsigned char[video_x*video_y*3/2];
myGlob_yuvframe = malloc(video_x*video_y*3/2);
//myGlob_yuvframe[1]=malloc(video_x*video_y*3/2);
//printf("INOUT - initialize the double frame buffer DONE...\n") ;
/* clear initial frame as it may be larger than actual video data */
/* fill Y plane with 0x10 and UV planes with 0X80, for black data */
memset(myGlob_yuvframe,0x10,video_x*video_y);
memset(myGlob_yuvframe+video_x*video_y,0x80,video_x*video_y/2);
// memset(myGlob_yuvframe[1],0x10,video_x*video_y);
// memset(myGlob_yuvframe[1]+video_x*video_y,0x80,video_x*video_y/2);
myGlob_state=10;
}
//InOut //printf("init AA\n") ;
/* is there a video page flushed? If not, work until there is. */
//printf("Working...\n") ;
while(!localVideoflag) {
//printf("%d\n",workI++) ;
//("encoder_example - INSIDE FETCH VIDEO loop\n", video_x) ;
if(ogg_stream_pageout(to,videopage)>0) return 1;
if(ogg_stream_eos(to)) { printf("boumboumboum (stream EOS)\n") ;return 0;}
{
/* read and process more video */
/* video strategy reads one frame ahead so we know when we're
at end of stream and can mark last video frame as such
(vorbis audio has to flush one frame past last video frame
due to overlap and thus doesn't need this extra work */
/* have two frame buffers full (if possible) before
proceeding. after first pass and until eos, one will
always be full when we get here */
if(myGlob_state<1){
/* can't get here unless YUV4MPEG stream has no video */
fprintf(stderr,"Video input contains no frames.\n");
exit(1);
}
/* Theora is a one-frame-in,one-frame-out system; submit a frame
for compression and pull out the packet */
{
//printf("- (juste pour voir) video_x : %d \n", video_x) ;
myGlob_yuv.y_width= video_x;
myGlob_yuv.y_height= video_y;
myGlob_yuv.y_stride= video_x;
myGlob_yuv.uv_width=video_x/2;
myGlob_yuv.uv_height=video_y/2;
myGlob_yuv.uv_stride=video_x/2;
myGlob_yuv.y= &myGlob_yuvframe[0];
myGlob_yuv.u= &myGlob_yuvframe[0] + video_x*video_y;
myGlob_yuv.v= &myGlob_yuvframe[0] + video_x*video_y*5/4 ;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// InOut myencoding Test
//if(theBuffer==NULL) printf("hum \n") ;
size_t pxwidth = CVPixelBufferGetWidth(theBuffer) ;
size_t pxheight = CVPixelBufferGetHeight(theBuffer) ;
//printf("DIMENSIONS DU CVPIXELBUFFER :%d,%d\n" ,pxwidth,pxheight) ;
CVPixelBufferLockBaseAddress(theBuffer, 0);
// debug_dump("/tmp/test.rgb", CVPixelBufferGetBaseAddress(theBuffer), pxwidth*pxheight*4*sizeof(uint8_t));
// printf("going to yuv CONVERT %ix%i+%i+%i (%i)\n", pxwidth, pxheight,myGlob_ti.offset_x,myGlob_ti.offset_y, CVPixelBufferGetBytesPerRow(theBuffer)) ;
// Transfer the source frame into glob->currentFrame, converting it from chunky YUV422 to planar YUV420.
int err = yuv_copy__argb_to_420(CVPixelBufferGetBaseAddress(theBuffer),
CVPixelBufferGetBytesPerRow(theBuffer),
pxwidth, pxheight,
myGlob_ti.offset_x,myGlob_ti.offset_y,
&myGlob_yuv);
// debug_dump("/tmp/test.yuv", myGlob_yuv.y, pxwidth*pxheight*sizeof(uint8_t)*3/2);
// printf("yuv convert done\n") ;
CVPixelBufferUnlockBaseAddress( theBuffer, 0 );
//printf("cv pixel unlock base adress unlocked\n") ;
///////////////// InOut debug tests yuv :
// printf("YUV_BUFFER : ywidth:%d yheight:%d ystride:%d uvwidth:%d uvheight:%d uvstride:%d\n",myGlob_yuv.y_width,myGlob_yuv.y_height,myGlob_yuv.y_stride,myGlob_yuv.uv_width,myGlob_yuv.uv_height,myGlob_yuv.uv_stride) ;
// //printf("Y : %s\n", myGlob_yuv.y) ;
// printf("size of y : %i\n", strlen(myGlob_yuv.y)) ;
// int outr = fwrite(myGlob_yuv.y,1,strlen(myGlob_yuv.y),testOutFile);
// fclose(testOutFile) ;
// printf("OK file test closed (%d)\n",outr) ;
// //fwrite("\n\n\n",1,3,testOutFile);
// break ;
int result = theora_encode_YUVin(td, &myGlob_yuv);
//printf("pb? encodeYUV O success : %d\n", result);
//printf("theora encode OK\n") ;
result = theora_encode_packetout(td, 0, &op);
//printf("pb? encodePACKETout 1 sucess : %d\n", result);
//printf("theora pachet OUT OK\n") ;
ogg_stream_packetin(to,&op);
{
// unsigned char *temp=myGlob_yuvframe[0];
// myGlob_yuvframe[0]=myGlob_yuvframe[1];
// myGlob_yuvframe[1]=temp;
// state--;
}
}
}
//printf("END of fetch and process VIDEO\n") ;
return localVideoflag;
}
shout_t *myShout;
//FILE *outTestFile ;
int myOggfwd_init( const char* outIceIp, int outIcePort, const char* outPassword, const char* outIceMount,
const char *description, const char *genre, const char *name, const char *url ) {
int res = 0 ;
unsigned short port = outIcePort ;
if ((myShout = shout_new()) == NULL) printf("oggfwd - Error - allocate shouter\n") ;
if (shout_set_host(myShout, outIceIp) != SHOUTERR_SUCCESS) printf("oggfwd - Error - set host pb...%s\n",shout_get_error(myShout)) ;
if (shout_set_port(myShout, port) != SHOUTERR_SUCCESS) printf("oggfwd - Error - look at the code to know...\n") ;
if (shout_set_password(myShout, outPassword) != SHOUTERR_SUCCESS) printf("oggfwd - Error - look at the code to know...\n") ;
if (shout_set_mount(myShout, outIceMount) != SHOUTERR_SUCCESS) printf("oggfwd - Error - look at the code to know...\n") ;
shout_set_format(myShout, SHOUT_FORMAT_VORBIS);
shout_set_public(myShout, 1);
if (description) shout_set_description(myShout, description);
if (genre) shout_set_genre(myShout, genre);
if (name) shout_set_name(myShout, name);
if (url) shout_set_url(myShout, url);
//printf("oggfwd - Trying to connect\n") ;
if (shout_open(myShout) == SHOUTERR_SUCCESS) {
printf("INOUT - oggfwd - Connected to server (%s)\n",outIceIp) ;
res = 1 ;
}
else {
printf("INOUT - oggfwd - Error connecting server (%s)\n",outIceIp) ;
}
//outTestFile = fopen("/OUT_oggFwdOutVideo.ogg", "wb") ;
return res ;
}
void encoder_example_init(int inW, int inH, int inFramerate, int in_video_r, int in_video_q) // int argc,char *const *argv)
{
//printf("encoder_example INIT function\n");
//testOutFile = fopen("OUT_testOutFile.txt","wb") ;
//outfile=fopen("OUT_outVideo.ogg","wb");
printf("INOUT - Encoder Video Size: %dx%d\n",inW,inH) ;
frame_x = inW ;
frame_y = inH ;
myGlob_state = -1 ;
#ifdef _WIN32
# ifdef THEORA_PERF_DATA
LARGE_INTEGER start_time;
LARGE_INTEGER final_time;
LONGLONG elapsed_ticks;
LARGE_INTEGER ticks_per_second;
LONGLONG elapsed_secs;
LONGLONG elapsed_sec_mod;
double elapsed_secs_dbl ;
# endif
/* We need to set stdin/stdout to binary mode. Damn windows. */
/* if we were reading/writing a file, it would also need to in
binary mode, eg, fopen("file.wav","wb"); */
/* Beware the evil ifdef. We avoid these where we can, but this one we
cannot. Don't add any more, you'll probably go to hell if you do. */
_setmode( _fileno( stdin ), _O_BINARY );
_setmode( _fileno( stdout ), _O_BINARY );
#endif
#ifdef THEORA_PERF_DATA
# ifdef WIN32
QueryPerformanceCounter(&start_time);
# endif
#endif
/* yayness. Set up Ogg output stream */
srand(time(NULL));
{
/* need two inequal serial numbers */
int serial1, serial2;
serial1 = rand();
serial2 = rand();
if (serial1 == serial2) serial2++;
ogg_stream_init(&myGlob_to,serial1);
ogg_stream_init(&myGlob_vo,serial2);
}
/* 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;
theora_info_init(&myGlob_ti);
myGlob_ti.width= video_x;
myGlob_ti.height= video_y;
myGlob_ti.frame_width= frame_x;
myGlob_ti.frame_height= frame_y;
myGlob_ti.offset_x= frame_x_offset;
myGlob_ti.offset_y= frame_y_offset;
myGlob_ti.fps_numerator= inFramerate ; //video_hzn;
myGlob_ti.fps_denominator= 1 ; //video_hzd;
myGlob_ti.aspect_numerator= 1 ; //video_an;
myGlob_ti.aspect_denominator= 1 ; //video_ad;
myGlob_ti.colorspace=OC_CS_UNSPECIFIED;
// myGlob_ti.colorspace=OC_CS_ITU_REC_470BG; /// new
myGlob_ti.pixelformat=OC_PF_420;
myGlob_ti.target_bitrate= in_video_r ;
myGlob_ti.quality= in_video_q ;
myGlob_ti.dropframes_p=0;
myGlob_ti.quick_p=1;
myGlob_ti.keyframe_auto_p=1;
myGlob_ti.keyframe_frequency=keyframe_frequency;
myGlob_ti.keyframe_frequency_force=keyframe_frequency;
myGlob_ti.keyframe_data_target_bitrate= myGlob_ti.target_bitrate *1.5;
myGlob_ti.keyframe_data_target_bitrate= myGlob_ti.target_bitrate *4; /// new
myGlob_ti.keyframe_auto_threshold=80;
myGlob_ti.keyframe_mindistance=8;
myGlob_ti.noise_sensitivity= noise_sensitivity ;
myGlob_ti.sharpness= sharpness;
theora_encode_init(&myGlob_td,&myGlob_ti);
theora_info_clear(&myGlob_ti);
//////////////////////////////////////////////////////////
/* write the bitstream header packets with proper page interleave */
/* first packet will get its own page automatically */
theora_encode_header(&myGlob_td,&myGlob_op);
ogg_stream_packetin(&myGlob_to,&myGlob_op);
if(ogg_stream_pageout(&myGlob_to,&myGlob_og)!=1){
fprintf(stderr,"Internal Ogg library error.\n");
exit(1);
}
/////////////////////////////////////////////////////////////
// InOut - writing header in outFile
// int poaResult = fwrite(myGlob_og.header,1,myGlob_og.header_len,outfile);
// poaResult += fwrite(myGlob_og.body,1,myGlob_og.body_len,outfile);
// fprintf(stderr,"HEADER ///////InOut fwrite header length: %d\n",myGlob_og.header_len);
// fprintf(stderr,"HEADER ///////InOut fwrite body length: %d\n",myGlob_og.body_len);
// fprintf(stderr,"HEADER ///////InOut fwrite header: %s\n",myGlob_og.header);
// fprintf(stderr,"HEADER ///////InOut fwrite body: %s\n",myGlob_og.body);
// fprintf(stderr,"HEADER InOut fwrite header result: %d\n",poaResult);
/////////////////////////////////////////////////////////////
// S2 - InOut - sending header to icecast
int fwdResH1 = myOggfwd_process(myGlob_og) ;
//printf("HEADER /////// Forwarded to Icecast : success ? %d\n", fwdResH1) ;
////////////////////////////////////////////////////////////
/* create the remaining theora headers */
theora_comment_init(&myGlob_tc);
theora_encode_comment(&myGlob_tc,&myGlob_op);
ogg_stream_packetin(&myGlob_to,&myGlob_op);
/*theora_encode_comment() doesn't take a theora_state parameter, so it has to
allocate its own buffer to pass back the packet data.
If we don't free it here, we'll leak.
libogg2 makes this much cleaner: the stream owns the buffer after you call
packetin in libogg2, but this is not true in libogg1.*/
free(myGlob_op.packet);
theora_encode_tables(&myGlob_td,&myGlob_op);
ogg_stream_packetin(&myGlob_to,&myGlob_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(&myGlob_to,&myGlob_og);
if(result<0){
/* can't get here */
fprintf(stderr,"Internal Ogg library error.\n");
exit(1);
}
if(result==0) break ;
/////////////////////////////////////////////////////////////
// InOut - writing header in outFile
// fwrite(myGlob_og.header,1,myGlob_og.header_len,outfile);
// fwrite(myGlob_og.body,1,myGlob_og.body_len,outfile);
// fprintf(stderr,"HEADER ////////InOut V lg header: %d\n",myGlob_og.header_len);
// fprintf(stderr,"HEADER ////////InOut V lg body: %d\n",myGlob_og.body_len);
// fprintf(stderr,"HEADER ////////InOut header: %s\n",myGlob_og.header);
// fprintf(stderr,"HEADER ////////InOut body: %s\n",myGlob_og.body);
/////////////////////////////////////////////////////////////
// S3 - InOut - sending to icecast
int fwdResH2 = myOggfwd_process(myGlob_og) ;
//printf("HEADERs /////// Forwarded to Icecast : success ? %d\n", fwdResH2) ;
}
fprintf(stderr,"INOUT (framerate=%d,bitrate=%d,quality=%d)\n",inFramerate,in_video_r,in_video_q);
/* setup complete. Raw processing loop */
//InOut done outside from mycontroller...
}
int encoder_example_loop( CVPixelBufferRef imBuffRef ) {
//fprintf(stderr,"encore F\n") ;
//if(imBuffRef==NULL) printf("AVT copie - de toute facon ca va pas marcher \n") ;
//if(sourcePixelBuffer!=NULL) sourcePixelBuffer=NULL ;
//if(sourcePixelBuffer==NULL) printf("APRES COPIE - de toute facon ca va pas marcher \n") ;
//fprintf(stderr,"ENCODER_EXAMPLE_LOOP : got the buffer from controller, going to Compress....\n");
//fprintf(stderr,"ENCODER_EXAMPLE_LOOP : video : %d audio : %d\n",video, audio);
ogg_page videopage;
double timebase;
/* is there a video page flushed? If not, fetch one if possible */
videoflag=fetch_and_process_video(imBuffRef,&videopage,&myGlob_to,&myGlob_td,videoflag);
/* no pages of either? Must be end of stream. */
if(!videoflag) {
printf("ENCODER_LOOP - Must be end of stream because i don't have any frame !!\n") ;
return 0;
}
{
double videotime=videoflag?theora_granule_time(&myGlob_td,ogg_page_granulepos(&videopage)):-1;
if(videoflag){
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
// InOut - flush page on disk
// //printf("ENCODER_LOOP - going to output frame result (videopage/header+body)\n") ;
// //fprintf(stderr,"Flush Video Page.\n\n");
// /* flush a video page */
// //fprintf(stderr,"LOOP /////// videopage header (%d) : %s\n",videopage.header_len,videopage.header);
// //fprintf(stderr,"LOOP /////// videopage body (%d) : %s\n",videopage.body_len,videopage.body);
// video_bytesout+=fwrite(videopage.header,1,videopage.header_len,outfile);
// video_bytesout+=fwrite(videopage.body,1,videopage.body_len,outfile);
// fprintf(stderr,"LOOP /////// Total written on disk : videobytes : %d\n",video_bytesout);
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
// S1 - InOut - forward page to myOggfwd
int fwdRes = myOggfwd_process(videopage) ;
//printf("LOOP /////// Forwarded to Icecast : success ? %d\n", fwdRes) ;
////////////////////////////////////////////////////////////////////////////////////
videoflag=0;
timebase=videotime;
}
}
return 1 ;
}
int myOggfwd_process(ogg_page inputVideoPage) {
int ret ;
////////////////////////////// TESTING SIMPLE WRITE ON FILE ... /////////////////////
// int video_bytesout = 0 ;
// video_bytesout+=fwrite(inputVideoPage.header,1,inputVideoPage.header_len,outTestFile);
// video_bytesout+=fwrite(inputVideoPage.body,1,inputVideoPage.body_len,outTestFile);
// printf("[TESTFILE out of oggfwd] Written %d bytes on disk \n", video_bytesout) ;
////////////////////////////////////////////////////////////////////////////////////
//printf("going to OGGFWD TO ICECAST\n") ;
if (inputVideoPage.header_len > 0 && inputVideoPage.body_len > 0) {
ret = shout_send(myShout, inputVideoPage.header, inputVideoPage.header_len);
ret = shout_send(myShout, inputVideoPage.body, inputVideoPage.body_len);
//printf("The oggfwd sent process return : %d\n", ret) ;
if(ret != SHOUTERR_SUCCESS) {
printf("!!!!!!! oggfwd - PB (error : %s) \n",shout_get_error(myShout)) ;
return 0 ;
}
//if(shout_queuelen(myShout) > 0) printf("DEBUG: queue length: %d\n", shout_queuelen(myShout));
}
else {
printf("!!!!!!!! oggfwd - PB (buffer empty)\n") ;
return 0 ;
}
shout_sync(myShout); // Sleep until the server will be ready for more data.
return 1 ;
}
void myOggfwd_close() {
//if(outTestFile) fclose(outTestFile) ;
shout_close(myShout);
printf("INOUT - oggfwd - Shout closed - Done\n") ;
}
int encoder_example_end() {
/* clear out state */
if(audio){
ogg_stream_clear(&myGlob_vo);
vorbis_block_clear(&myGlob_vb);
vorbis_dsp_clear(&myGlob_vd);
vorbis_comment_clear(&myGlob_vc);
vorbis_info_clear(&myGlob_vi);
}
if(video){
fprintf(stderr,"Clearing video state\n");
ogg_stream_clear(&myGlob_to);
theora_clear(&myGlob_td);
}
if(outfile && outfile!=stdout) fclose(outfile);
fprintf(stderr,"INOUT - encoder - Done.\n\n");
#ifdef THEORA_PERF_DATA
# ifdef WIN32
QueryPerformanceCounter(&final_time);
elapsed_ticks = final_time.QuadPart - start_time.QuadPart;
ticks_per_second;
QueryPerformanceFrequency(&ticks_per_second);
elapsed_secs = elapsed_ticks / ticks_per_second.QuadPart;
elapsed_sec_mod = elapsed_ticks % ticks_per_second.QuadPart;
elapsed_secs_dbl = elapsed_secs;
elapsed_secs_dbl += ((double)elapsed_sec_mod / (double)ticks_per_second.QuadPart);
printf("Encode time = %lld ticks\n", elapsed_ticks);
printf("~%lld and %lld / %lld seconds\n", elapsed_secs, elapsed_sec_mod, ticks_per_second.QuadPart);
printf("~%Lf seconds\n", elapsed_secs_dbl);
# endif
#endif
return(0);
}