static int noop_test_encode () { theora_info ti; theora_state th; INFO ("+ Initializing theora_info struct"); theora_info_init (&ti); INFO ("+ Setting a 16x16 frame"); ti.width = 16; ti.height = 16; INFO ("+ Setting a 1:1 frame rate"); ti.fps_numerator = 1; ti.fps_denominator = 1; INFO ("+ Initializing theora_state for encoding"); if (theora_encode_init (&th, &ti) != OC_DISABLED) { INFO ("+ Clearing theora_state"); theora_clear (&th); } INFO ("+ Clearing theora_info struct"); theora_info_clear (&ti); return 0; }
static void enc_preprocess(MSFilter *f){ EncState *s=(EncState*)f->data; int err; if ((err=theora_encode_init(&s->tstate,&s->tinfo))!=0){ ms_error("error in theora_encode_init() : %i !",err); } s->yuv.y_width=s->tinfo.width; s->yuv.y_height=s->tinfo.height; s->yuv.y_stride=s->tinfo.width; s->yuv.uv_width=s->tinfo.width/2; s->yuv.uv_height=s->tinfo.height/2; s->yuv.uv_stride=s->tinfo.width/2; create_packed_conf(s); s->conf_time=0; s->nframes=0; }
static int noop_test_encode () { theora_info ti; theora_state th; INFO ("+ Initializing theora_info struct"); theora_info_init (&ti); INFO ("+ Initializing theora_state for encoding"); if (theora_encode_init (&th, &ti) != OC_DISABLED) { INFO ("+ Clearing theora_state"); theora_clear (&th); } INFO ("+ Clearing theora_info struct"); theora_info_clear (&ti); return 0; }
static void theora_enc_reset (GstTheoraEnc * enc) { theora_clear (&enc->state); theora_encode_init (&enc->state, &enc->info); }
static int granulepos_test_encode (int frequency, int auto_p) { theora_info ti; theora_state th; int result; int frame, tframe, keyframe, keydist; int shift; double rate, ttime; yuv_buffer yuv; unsigned char *framedata; ogg_packet op; long long int last_granule = -1; /* INFO ("+ Initializing theora_info struct"); */ theora_info_init (&ti); ti.width = 32; ti.height = 32; ti.frame_width = ti.width; ti.frame_height = ti.frame_height; ti.offset_x = 0; ti.offset_y = 0; ti.fps_numerator = 16; ti.fps_denominator = 1; ti.aspect_numerator = 1; ti.aspect_denominator = 1; ti.colorspace = OC_CS_UNSPECIFIED; ti.pixelformat = OC_PF_420; ti.target_bitrate = 0; ti.quality = 16; ti.dropframes_p = 0; ti.quick_p = 1; /* check variations of automatic or forced keyframe choice */ ti.keyframe_auto_p = auto_p; /* check with variations of the maximum gap */ ti.keyframe_frequency = frequency; ti.keyframe_frequency_force = frequency; ti.keyframe_data_target_bitrate = ti.target_bitrate * 1.5; ti.keyframe_auto_threshold = 80; ti.keyframe_mindistance = MIN(8, frequency); ti.noise_sensitivity = 1; /* INFO ("+ Initializing theora_state for encoding"); */ result = theora_encode_init (&th, &ti); if (result == OC_DISABLED) { INFO ("+ Clearing theora_state"); theora_clear (&th); } else if (result < 0) { FAIL ("negative return code initializing encoder"); } /* INFO ("+ Setting up dummy 4:2:0 frame data"); */ framedata = calloc(ti.height, ti.width); yuv.y_width = ti.width; yuv.y_height = ti.height; yuv.y_stride = ti.width; yuv.y = framedata; yuv.uv_width = ti.width / 2; yuv.uv_height = ti.width / 2; yuv.uv_stride = ti.width; yuv.u = framedata; yuv.v = framedata; INFO ("+ Checking granulepos generation"); shift = theora_granule_shift(&ti); rate = (double)ti.fps_denominator/ti.fps_numerator; for (frame = 0; frame < frequency * 2 + 1; frame++) { result = theora_encode_YUVin (&th, &yuv); if (result < 0) { printf("theora_encode_YUVin() returned %d\n", result); FAIL ("negative error code submitting frame for compression"); } theora_encode_packetout (&th, frame >= frequency * 2, &op); if ((long long int)op.granulepos < last_granule) FAIL ("encoder returned a decreasing granulepos value"); last_granule = op.granulepos; keyframe = op.granulepos >> shift; keydist = op.granulepos - (keyframe << shift); tframe = theora_granule_frame (&th, op.granulepos); ttime = theora_granule_time(&th, op.granulepos); #if DEBUG printf("++ frame %d granulepos %lld %d:%d %d %.3lfs\n", frame, (long long int)op.granulepos, keyframe, keydist, tframe, theora_granule_time (&th, op.granulepos)); #endif if ((keyframe + keydist) != frame + 1) FAIL ("encoder granulepos does not map to the correct frame number"); if (tframe != frame) FAIL ("theora_granule_frame returned incorrect results"); if (fabs(rate*(frame+1) - ttime) > 1.0e-6) FAIL ("theora_granule_time returned incorrect results"); } /* clean up */ /* INFO ("+ Freeing dummy frame data"); */ free (framedata); /* INFO ("+ Clearing theora_info struct"); */ theora_info_clear (&ti); /* INFO ("+ Clearing theora_state"); */ theora_clear (&th); return 0; }
static int encode_init(AVCodecContext* avc_context) { theora_info t_info; theora_comment t_comment; ogg_packet o_packet; unsigned int offset; TheoraContext *h = avc_context->priv_data; /* Set up the theora_info struct */ theora_info_init( &t_info ); t_info.width = avc_context->width; t_info.height = avc_context->height; t_info.frame_width = avc_context->width; t_info.frame_height = avc_context->height; t_info.offset_x = 0; t_info.offset_y = 0; /* Swap numerator and denominator as time_base in AVCodecContext gives the * time period between frames, but theora_info needs the framerate. */ t_info.fps_numerator = avc_context->time_base.den; t_info.fps_denominator = avc_context->time_base.num; if (avc_context->sample_aspect_ratio.num != 0) { t_info.aspect_numerator = avc_context->sample_aspect_ratio.num; t_info.aspect_denominator = avc_context->sample_aspect_ratio.den; } else { t_info.aspect_numerator = 1; t_info.aspect_denominator = 1; } t_info.colorspace = OC_CS_UNSPECIFIED; t_info.pixelformat = OC_PF_420; t_info.target_bitrate = avc_context->bit_rate; t_info.keyframe_frequency = avc_context->gop_size; t_info.keyframe_frequency_force = avc_context->gop_size; t_info.keyframe_mindistance = avc_context->keyint_min; t_info.quality = 0; t_info.quick_p = 1; t_info.dropframes_p = 0; t_info.keyframe_auto_p = 1; t_info.keyframe_data_target_bitrate = t_info.target_bitrate * 1.5; t_info.keyframe_auto_threshold = 80; t_info.noise_sensitivity = 1; t_info.sharpness = 0; /* Now initialise libtheora */ if (theora_encode_init( &(h->t_state), &t_info ) != 0) { av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n"); return -1; } /* Clear up theora_info struct */ theora_info_clear( &t_info ); /* Output first header packet consisting of theora header, comment, and tables. Each one is prefixed with a 16bit size, then they are concatenated together into ffmpeg's extradata. */ offset = 0; /* Header */ theora_encode_header( &(h->t_state), &o_packet ); if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { return -1; } /* Comment */ theora_comment_init( &t_comment ); theora_encode_comment( &t_comment, &o_packet ); if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { return -1; } /* Tables */ theora_encode_tables( &(h->t_state), &o_packet ); if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { return -1; } /* Clear up theora_comment struct */ theora_comment_clear( &t_comment ); /* Set up the output AVFrame */ avc_context->coded_frame= avcodec_alloc_frame(); return 0; }
void rmdInitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready){ int y0, y1, y2, fname_length; ogg_stream_state m_ogg_skel; ogg_page skel_og_pg; fisbone_packet skel_fbv, //video fisbone packet skel_fba ; //audio fisbone packet (pdata)->enc_data=enc_data_t; fname_length=strlen(pdata->args.filename); if(!(fname_length>4 && pdata->args.filename[fname_length-4] == '.' && (pdata->args.filename[fname_length-3] == 'o' || pdata->args.filename[fname_length-3] == 'O') && (pdata->args.filename[fname_length-2] == 'g' || pdata->args.filename[fname_length-2] == 'G') && (pdata->args.filename[fname_length-1] == 'v' || pdata->args.filename[fname_length-1] == 'V'))){ char *new_name=malloc(fname_length+5); strcpy(new_name,pdata->args.filename); strcat(new_name,".ogv"); free(pdata->args.filename); pdata->args.filename=new_name; } if (!pdata->args.overwrite) { rmdIncrementalNaming(&(pdata)->args.filename); fprintf(stderr, "Output file: %s\n", pdata->args.filename); } enc_data_t->fp=fopen((pdata)->args.filename,"w"); if(enc_data_t->fp==NULL){ fprintf(stderr,"Cannot open file %s for writting!\n", (pdata)->args.filename); exit(13); } //each stream must have a unique srand(time(NULL)); y0=rand()+1; y1=rand()+1; y2=rand()+1; y2+=(y1==y2); y0=(((y0==y1)||(y0==y2))?(y1+y2):y0); //init ogg streams //skeleton first ogg_stream_init(&m_ogg_skel,y0); m_add_fishead_packet(&m_ogg_skel); if(ogg_stream_pageout(&m_ogg_skel,&skel_og_pg)!= 1){ fprintf (stderr, "Internal Ogg library error.\n"); exit (2); } fwrite(skel_og_pg.header,1,skel_og_pg.header_len,enc_data_t->fp); fwrite(skel_og_pg.body,1,skel_og_pg.body_len,enc_data_t->fp); ogg_stream_init(&enc_data_t->m_ogg_ts,y1); if(!pdata->args.nosound) ogg_stream_init(&enc_data_t->m_ogg_vs,y2); theora_info_init(&enc_data_t->m_th_inf); enc_data_t->m_th_inf.frame_width = pdata->brwin.rrect.width; enc_data_t->m_th_inf.frame_height = pdata->brwin.rrect.height; enc_data_t->m_th_inf.width = ((enc_data_t->m_th_inf.frame_width + 15) >> 4) << 4; enc_data_t->m_th_inf.height = ((enc_data_t->m_th_inf.frame_height + 15) >> 4) << 4; enc_data_t->m_th_inf.offset_x = 0; enc_data_t->m_th_inf.offset_y = 0; enc_data_t->m_th_inf.fps_numerator = pdata->args.fps * 100.0; enc_data_t->m_th_inf.fps_denominator = 100; enc_data_t->m_th_inf.aspect_numerator = 1; enc_data_t->m_th_inf.aspect_denominator = 1; enc_data_t->m_th_inf.colorspace = OC_CS_UNSPECIFIED; enc_data_t->m_th_inf.pixelformat = OC_PF_420; enc_data_t->m_th_inf.target_bitrate = pdata->args.v_bitrate; enc_data_t->m_th_inf.quality = pdata->args.v_quality; enc_data_t->m_th_inf.dropframes_p = 0; enc_data_t->m_th_inf.quick_p = 1; enc_data_t->m_th_inf.keyframe_auto_p = 1; enc_data_t->m_th_inf.keyframe_frequency = 64; enc_data_t->m_th_inf.keyframe_frequency_force = 64; enc_data_t->m_th_inf.keyframe_data_target_bitrate = enc_data_t->m_th_inf.quality * 1.5; enc_data_t->m_th_inf.keyframe_auto_threshold = 80; enc_data_t->m_th_inf.keyframe_mindistance = 8; enc_data_t->m_th_inf.noise_sensitivity = 1; enc_data_t->m_th_inf.sharpness = 2; theora_encode_init(&enc_data_t->m_th_st,&enc_data_t->m_th_inf); if(!pdata->args.nosound){ int ret; vorbis_info_init(&enc_data_t->m_vo_inf); ret = vorbis_encode_init_vbr(&enc_data_t->m_vo_inf, pdata->args.channels, pdata->args.frequency, (float)pdata->args.s_quality*0.1); if(ret){ fprintf(stderr,"Error while setting up vorbis stream quality!\n"); exit(2); } vorbis_comment_init(&enc_data_t->m_vo_cmmnt); vorbis_analysis_init(&enc_data_t->m_vo_dsp,&enc_data_t->m_vo_inf); vorbis_block_init(&enc_data_t->m_vo_dsp,&enc_data_t->m_vo_block); } theora_encode_header(&enc_data_t->m_th_st,&enc_data_t->m_ogg_pckt1); ogg_stream_packetin(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pckt1); if(ogg_stream_pageout(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pg)!=1){ fprintf(stderr,"Internal Ogg library error.\n"); exit(2); } fwrite(enc_data_t->m_ogg_pg.header,1, enc_data_t->m_ogg_pg.header_len, enc_data_t->fp); fwrite(enc_data_t->m_ogg_pg.body,1, enc_data_t->m_ogg_pg.body_len, enc_data_t->fp); theora_comment_init(&enc_data_t->m_th_cmmnt); theora_comment_add_tag(&enc_data_t->m_th_cmmnt,"recordMyDesktop",VERSION); theora_encode_comment(&enc_data_t->m_th_cmmnt,&enc_data_t->m_ogg_pckt1); ogg_stream_packetin(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pckt1); theora_encode_tables(&enc_data_t->m_th_st,&enc_data_t->m_ogg_pckt1); ogg_stream_packetin(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pckt1); if(!pdata->args.nosound){ ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout(&enc_data_t->m_vo_dsp, &enc_data_t->m_vo_cmmnt, &header,&header_comm, &header_code); ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header); if(ogg_stream_pageout(&enc_data_t->m_ogg_vs,&enc_data_t->m_ogg_pg)!=1){ fprintf(stderr,"Internal Ogg library error.\n"); exit(2); } fwrite(enc_data_t->m_ogg_pg.header,1, enc_data_t->m_ogg_pg.header_len, enc_data_t->fp); fwrite(enc_data_t->m_ogg_pg.body,1, enc_data_t->m_ogg_pg.body_len, enc_data_t->fp); ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header_comm); ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header_code); } //fishbone packets go here memset(&skel_fbv,0,sizeof(skel_fbv)); skel_fbv.serial_no=enc_data_t->m_ogg_ts.serialno; skel_fbv.nr_header_packet=3; skel_fbv.granule_rate_n=enc_data_t->m_th_inf.fps_numerator; skel_fbv.granule_rate_d=enc_data_t->m_th_inf.fps_denominator; skel_fbv.start_granule=0; skel_fbv.preroll=0; skel_fbv.granule_shift=theora_granule_shift(&enc_data_t->m_th_inf); add_message_header_field(&skel_fbv, "Content-Type", "video/theora"); add_fisbone_to_stream(&m_ogg_skel,&skel_fbv); if(!pdata->args.nosound){ memset(&skel_fba,0,sizeof(skel_fba)); skel_fba.serial_no=enc_data_t->m_ogg_vs.serialno; skel_fba.nr_header_packet=3; skel_fba.granule_rate_n=pdata->args.frequency; skel_fba.granule_rate_d=(ogg_int64_t)1; skel_fba.start_granule=0; skel_fba.preroll=2; skel_fba.granule_shift=0; add_message_header_field(&skel_fba, "Content-Type", "audio/vorbis"); add_fisbone_to_stream(&m_ogg_skel,&skel_fba); } while(1){ int result = ogg_stream_flush(&m_ogg_skel, &skel_og_pg); if(result<0){ fprintf (stderr, "Internal Ogg library error.\n"); exit(2); } if(result==0) break; fwrite(skel_og_pg.header,1,skel_og_pg.header_len,enc_data_t->fp); fwrite(skel_og_pg.body,1,skel_og_pg.body_len,enc_data_t->fp); } while(1){ int result = ogg_stream_flush(&enc_data_t->m_ogg_ts, &enc_data_t->m_ogg_pg); if(result<0){ fprintf(stderr,"Internal Ogg library error.\n"); exit(2); } if(result==0)break; fwrite(enc_data_t->m_ogg_pg.header,1, enc_data_t->m_ogg_pg.header_len, enc_data_t->fp); fwrite(enc_data_t->m_ogg_pg.body,1, enc_data_t->m_ogg_pg.body_len, enc_data_t->fp); } if(!pdata->args.nosound){ while(1){ int result=ogg_stream_flush(&enc_data_t->m_ogg_vs, &enc_data_t->m_ogg_pg); if(result<0){ fprintf(stderr,"Internal Ogg library error.\n"); exit(2); } if(result==0)break; fwrite(enc_data_t->m_ogg_pg.header,1, enc_data_t->m_ogg_pg.header_len, enc_data_t->fp); fwrite(enc_data_t->m_ogg_pg.body,1, enc_data_t->m_ogg_pg.body_len, enc_data_t->fp); } } //skeleton eos add_eos_packet_to_stream(&m_ogg_skel); if(ogg_stream_flush(&m_ogg_skel,&skel_og_pg)<0){ fprintf(stderr,"Internal Ogg library error.\n"); exit(2); } fwrite(skel_og_pg.header,1,skel_og_pg.header_len,enc_data_t->fp); fwrite(skel_og_pg.body,1,skel_og_pg.body_len,enc_data_t->fp); //theora buffer allocation, if any if(!buffer_ready){ enc_data_t->yuv.y=(unsigned char *)malloc(enc_data_t->m_th_inf.height* enc_data_t->m_th_inf.width); enc_data_t->yuv.u=(unsigned char *)malloc(enc_data_t->m_th_inf.height* enc_data_t->m_th_inf.width/4); enc_data_t->yuv.v=(unsigned char *)malloc(enc_data_t->m_th_inf.height* enc_data_t->m_th_inf.width/4); enc_data_t->yuv.y_width=enc_data_t->m_th_inf.width; enc_data_t->yuv.y_height=enc_data_t->m_th_inf.height; enc_data_t->yuv.y_stride=enc_data_t->m_th_inf.width; enc_data_t->yuv.uv_width=enc_data_t->m_th_inf.width/2; enc_data_t->yuv.uv_height=enc_data_t->m_th_inf.height/2; enc_data_t->yuv.uv_stride=enc_data_t->m_th_inf.width/2; enc_data_t->x_offset=enc_data_t->m_th_inf.offset_x; enc_data_t->y_offset=enc_data_t->m_th_inf.offset_y; } theora_info_clear(&enc_data_t->m_th_inf); }
static BGBBTJ_VidCodecCTX *theo_begin_compress(int fcc, BGBBTJ_BMPInfoHeader *in, BGBBTJ_BMPInfoHeader *out) { byte tbuf[16384]; ogg_packet op; BGBBTJ_VidCodecCTX *ctx; vfw_ctxinfo *info; byte *ct; int err, sz, xs, ys, xs1, ys1, px, py; if((fcc!=RIFF_TAG_THEO) && (fcc!=RIFF_TAG_theo) && (fcc!=RIFF_TAG_ther)) return(NULL); ctx=BGBBTJ_VidCodecCTX_New(); info=gcalloc(sizeof(vfw_ctxinfo)); ctx->data=info; info->ihead=gcalloc(sizeof(BGBBTJ_BMPInfoHeader)); memset(info->ihead, 0, sizeof(BGBBTJ_BMPInfoHeader)); info->ihead->biSize = sizeof(BGBBTJ_BMPInfoHeader); info->ihead->biWidth = in->biWidth; info->ihead->biHeight = in->biHeight; info->ihead->biPlanes = in->biPlanes; info->ihead->biBitCount = in->biBitCount; info->ihead->biCompression = in->biCompression; info->ihead->biSizeImage = in->biWidth*in->biHeight*in->biBitCount/8; // out->biCompression=RIFF_TAG_ther; out->biCompression=RIFF_TAG_theo; info->ohead=gcalloc(sizeof(BGBBTJ_BMPInfoHeader)); memset(info->ohead, 0, sizeof(BGBBTJ_BMPInfoHeader)); info->ohead->biSize = sizeof(BGBBTJ_BMPInfoHeader); info->ohead->biWidth = out->biWidth; // info->ohead->biHeight = -out->biHeight; info->ohead->biHeight = out->biHeight; info->ohead->biPlanes = out->biPlanes; info->ohead->biBitCount = out->biBitCount; info->ohead->biCompression = out->biCompression; info->ihead->biSizeImage = out->biWidth*out->biHeight*out->biBitCount/8; // info->buffer=malloc(out->width*out->height*out->bpp/8); theora_info_init(&(info->ti)); // if(err<0)printf("theo_begin_compress: A Err=%d\n"); xs=(out->biWidth+15)&(~15); ys=(out->biHeight+15)&(~15); xs1=xs>>1; ys1=ys>>1; px=((xs-out->biWidth)>>1)&(~1); py=((ys-out->biHeight)>>1)&(~1); info->ti.width = out->biWidth; info->ti.height = out->biHeight; info->ti.frame_width = xs; info->ti.frame_height = ys; info->ti.offset_x=px; info->ti.offset_y=py; // info->ti.pixel_fmt=TH_PF_420; info->ti.pixelformat=TH_PF_420; // info->ti.quality=56; info->ti.quality=63; info->ti.colorspace=TH_CS_UNSPECIFIED; info->ti.fps_numerator=24; info->ti.fps_denominator=1; info->ti.aspect_numerator=1; info->ti.aspect_denominator=1; th_info_init(&(info->thi)); // if(err<0)printf("theo_begin_compress: B Err=%d\n"); info->thi.pic_width = out->biWidth; info->thi.pic_height = out->biHeight; info->thi.frame_width = xs; info->thi.frame_height = ys; info->thi.pic_x=px; info->thi.pic_y=py; info->thi.fps_numerator=24; info->thi.fps_denominator=1; info->thi.aspect_numerator=1; info->thi.aspect_denominator=1; info->thi.colorspace=TH_CS_UNSPECIFIED; info->thi.pixel_fmt=TH_PF_420; // info->thi.pixelformat=TH_PF_420; // info->thi.quality=48; info->thi.quality=63; if(theora_encode_init(&(info->th), &(info->ti)) != OC_DISABLED) { theora_clear(&(info->th)); } info->td=th_encode_alloc(&(info->thi)); th_info_clear(&(info->thi)); // if(err<0)printf("theo_begin_compress: C Err=%d\n"); th_comment_init(&(info->tc)); // if(err<0)printf("theo_begin_compress: D Err=%d\n"); ct=tbuf; err=th_encode_flushheader(info->td, &(info->tc), &op); if(err<0)printf("theo_begin_compress: E Err=%d\n"); ct[0]=(op.bytes>>8)&255; ct[1]=op.bytes&255; ct+=2; memcpy(ct, op.packet, op.bytes); ct+=op.bytes; while(1) { err=th_encode_flushheader(info->td, &(info->tc), &op); if(err<=0)break; ct[0]=(op.bytes>>8)&255; ct[1]=op.bytes&255; ct+=2; memcpy(ct, op.packet, op.bytes); ct+=op.bytes; } if(err<0)printf("theo_begin_compress: F Err=%d\n"); sz=ct-tbuf; ctx->vidStrd=gcalloc(sz); ctx->sz_vidStrd=sz; memcpy(ctx->vidStrd, tbuf, sz); info->ycbbuf[0].width=xs; info->ycbbuf[0].height=ys; info->ycbbuf[0].stride=xs; info->ycbbuf[0].data=malloc(xs*ys); info->ycbbuf[1].width=xs1; info->ycbbuf[1].height=ys1; info->ycbbuf[1].stride=xs1; info->ycbbuf[1].data=malloc(xs1*ys1); info->ycbbuf[2].width=xs1; info->ycbbuf[2].height=ys1; info->ycbbuf[2].stride=xs1; info->ycbbuf[2].data=malloc(xs1*ys1); ctx->compress_frame=&theo_compress_frame; return(ctx); }
int main(int argc,char *argv[]){ int c,long_option_index,ret; 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; vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the user comments */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_block vb; /* local working space for packet->PCM decode */ int audioflag=0; int videoflag=0; int akbps=0; int vkbps=0; ogg_int64_t audio_bytesout=0; ogg_int64_t video_bytesout=0; double timebase; FILE* outfile = stdout; #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 while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){ switch(c){ case 'o': outfile=fopen(optarg,"wb"); if(outfile==NULL){ fprintf(stderr,"Unable to open output file '%s'\n", optarg); exit(1); } break;; case 'a': audio_q=atof(optarg)*.099; if(audio_q<-.1 || audio_q>1){ fprintf(stderr,"Illegal audio quality (choose -1 through 10)\n"); exit(1); } audio_r=-1; break; case 'v': video_q=rint(atof(optarg)*6.3); if(video_q<0 || video_q>63){ fprintf(stderr,"Illegal video quality (choose 0 through 10)\n"); exit(1); } video_r=0; break; case 'A': audio_r=atof(optarg)*1000; if(audio_q<0){ fprintf(stderr,"Illegal audio quality (choose > 0 please)\n"); exit(1); } audio_q=-99; break; case 'V': video_r=rint(atof(optarg)*1000); if(video_r<45000 || video_r>2000000){ fprintf(stderr,"Illegal video bitrate (choose 45kbps through 2000kbps)\n"); exit(1); } video_q=0; break; case 's': video_an=rint(atof(optarg)); break; case 'S': video_ad=rint(atof(optarg)); break; case 'f': video_hzn=rint(atof(optarg)); break; case 'F': video_hzd=rint(atof(optarg)); break; default: usage(); } } while(optind<argc){ /* assume that anything following the options must be a filename */ id_file(argv[optind]); optind++; } #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(&to,serial1); ogg_stream_init(&vo,serial2); } /* Set up Theora encoder */ if(!video){ fprintf(stderr,"No video files submitted for compression?\n"); exit(1); } /* 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(&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); /* initialize Vorbis too, assuming we have audio to compress. */ if(audio){ vorbis_info_init(&vi); if(audio_q>-99) ret = vorbis_encode_init_vbr(&vi,audio_ch,audio_hz,audio_q); else ret = vorbis_encode_init(&vi,audio_ch,audio_hz,-1,audio_r,-1); if(ret){ fprintf(stderr,"The Vorbis encoder could not set up a mode according to\n" "the requested quality or bitrate.\n\n"); exit(1); } vorbis_comment_init(&vc); vorbis_analysis_init(&vd,&vi); vorbis_block_init(&vd,&vb); } /* 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_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(op.packet); theora_encode_tables(&td,&op); ogg_stream_packetin(&to,&op); if(audio){ ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); ogg_stream_packetin(&vo,&header); /* automatically placed in its own page */ if(ogg_stream_pageout(&vo,&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); /* remaining vorbis header packets */ ogg_stream_packetin(&vo,&header_comm); ogg_stream_packetin(&vo,&header_code); } /* 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){ /* can't get here */ 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); } if(audio){ while(1){ int result=ogg_stream_flush(&vo,&og); if(result<0){ /* can't get here */ 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){ ogg_page audiopage; ogg_page videopage; /* is there an audio page flushed? If not, fetch one if possible */ audioflag=fetch_and_process_audio(audio,&audiopage,&vo,&vd,&vb,audioflag); /* is there a video page flushed? If not, fetch one if possible */ videoflag=fetch_and_process_video(video,&videopage,&to,&td,videoflag); /* no pages of either? Must be end of stream. */ if(!audioflag && !videoflag)break; /* which is earlier; the end of the audio page or the end of the video page? Flush the earlier to stream */ { int audio_or_video=-1; double audiotime= audioflag?vorbis_granule_time(&vd,ogg_page_granulepos(&audiopage)):-1; double videotime= videoflag?theora_granule_time(&td,ogg_page_granulepos(&videopage)):-1; if(!audioflag){ audio_or_video=1; } else if(!videoflag) { audio_or_video=0; } else { if(audiotime<videotime) audio_or_video=0; else audio_or_video=1; } if(audio_or_video==1){ /* flush a video page */ video_bytesout+=fwrite(videopage.header,1,videopage.header_len,outfile); video_bytesout+=fwrite(videopage.body,1,videopage.body_len,outfile); videoflag=0; timebase=videotime; }else{ /* flush an audio page */ audio_bytesout+=fwrite(audiopage.header,1,audiopage.header_len,outfile); audio_bytesout+=fwrite(audiopage.body,1,audiopage.body_len,outfile); audioflag=0; timebase=audiotime; } { int hundredths=timebase*100-(long)timebase*100; int seconds=(long)timebase%60; int minutes=((long)timebase/60)%60; int hours=(long)timebase/3600; if(audio_or_video) vkbps=rint(video_bytesout*8./timebase*.001); else akbps=rint(audio_bytesout*8./timebase*.001); fprintf(stderr, "\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps ", hours,minutes,seconds,hundredths,akbps,vkbps); } } } /* clear out state */ if(audio){ ogg_stream_clear(&vo); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); } if(video){ ogg_stream_clear(&to); theora_clear(&td); } if(outfile && outfile!=stdout)fclose(outfile); fprintf(stderr,"\r \ndone.\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); }