Jan, Here's a hacky patch to add a few commandline options for setting comment header fields in ffmpeg2theora. It's a bit big because I virtualized the global info struct in theorautils.c. In retrospect that probably wasn't necessary, but I think it's cleaner anyway. I didn't test it because I couldn't compile ffmpeg2theora, but modulo bugs it should support --artist="foo" --title="bar" and so on. FWIW, -r -------------- next part -------------- Index: theorautils.c ==================================================================--- theorautils.c (revision 8208) +++ theorautils.c (working copy) @@ -32,8 +32,6 @@ #include "theorautils.h" -theoraframes_info info; - static double rint(double x) { if (x < 0.0) @@ -42,30 +40,30 @@ return (double)(int)(x + 0.5); } -void theoraframes_init (){ - info.audio_bytesout = 0; - info.video_bytesout = 0; +void theoraframes_init (theoraframes_info *info){ + info->audio_bytesout = 0; + info->video_bytesout = 0; /* yayness. Set up Ogg output stream */ srand (time (NULL)); - ogg_stream_init (&info.vo, rand ()); + ogg_stream_init (&info->vo, rand ()); - if(!info.audio_only){ - ogg_stream_init (&info.to, rand ()); /* oops, add one ot the above */ - theora_encode_init (&info.td, &info.ti); - theora_info_clear (&info.ti); + if(!info->audio_only){ + ogg_stream_init (&info->to, rand ()); /* oops, add one ot the above */ + theora_encode_init (&info->td, &info->ti); + theora_info_clear (&info->ti); } /* init theora done */ /* initialize Vorbis too, if we have audio. */ - if(!info.video_only){ - vorbis_info_init (&info.vi); + if(!info->video_only){ + vorbis_info_init (&info->vi); /* Encoding using a VBR quality mode. */ int ret; - if(info.vorbis_quality>-99) - ret =vorbis_encode_init_vbr (&info.vi, info.channels,info.sample_rate,info.vorbis_quality); + if(info->vorbis_quality>-99) + ret =vorbis_encode_init_vbr (&info->vi, info->channels,info->sample_rate,info->vorbis_quality); else - ret=vorbis_encode_init(&info.vi,info.channels,info.sample_rate,-1,info.vorbis_bitrate,-1); + ret=vorbis_encode_init(&info->vi,info->channels,info->sample_rate,-1,info->vorbis_bitrate,-1); if (ret){ fprintf (stderr, @@ -74,11 +72,11 @@ exit (1); } - vorbis_comment_init (&info.vc); - vorbis_comment_add_tag (&info.vc, "ENCODER",PACKAGE_STRING); + vorbis_comment_init (&info->vc); + vorbis_comment_add_tag (&info->vc, "ENCODER",PACKAGE_STRING); /* set up the analysis state and auxiliary encoding storage */ - vorbis_analysis_init (&info.vd, &info.vi); - vorbis_block_init (&info.vd, &info.vb); + vorbis_analysis_init (&info->vd, &info->vi); + vorbis_block_init (&info->vd, &info->vb); } /* audio init done */ @@ -86,50 +84,50 @@ /* write the bitstream header packets with proper page interleave */ /* first packet will get its own page automatically */ - if(!info.audio_only){ - theora_encode_header (&info.td, &info.op); - ogg_stream_packetin (&info.to, &info.op); - if (ogg_stream_pageout (&info.to, &info.og) != 1){ + if(!info->audio_only){ + theora_encode_header (&info->td, &info->op); + ogg_stream_packetin (&info->to, &info->op); + if (ogg_stream_pageout (&info->to, &info->og) != 1){ fprintf (stderr, "Internal Ogg library error.\n"); exit (1); } - fwrite (info.og.header, 1, info.og.header_len, info.outfile); - fwrite (info.og.body, 1, info.og.body_len, info.outfile); + fwrite (info->og.header, 1, info->og.header_len, info->outfile); + fwrite (info->og.body, 1, info->og.body_len, info->outfile); /* create the remaining theora headers */ - theora_comment_init (&info.tc); - theora_comment_add_tag (&info.tc, "ENCODER",PACKAGE_STRING); - theora_encode_comment (&info.tc, &info.op); - ogg_stream_packetin (&info.to, &info.op); - theora_encode_tables (&info.td, &info.op); - ogg_stream_packetin (&info.to, &info.op); + /* theora_comment_init (&info->tc); is called in main() prior to parsing options */ + theora_comment_add_tag (&info->tc, "ENCODER",PACKAGE_STRING); + theora_encode_comment (&info->tc, &info->op); + ogg_stream_packetin (&info->to, &info->op); + theora_encode_tables (&info->td, &info->op); + ogg_stream_packetin (&info->to, &info->op); } - if(!info.video_only){ + if(!info->video_only){ ogg_packet header; ogg_packet header_comm; ogg_packet header_code; - vorbis_analysis_headerout (&info.vd, &info.vc, &header, + vorbis_analysis_headerout (&info->vd, &info->vc, &header, &header_comm, &header_code); - ogg_stream_packetin (&info.vo, &header); /* automatically placed in its own + ogg_stream_packetin (&info->vo, &header); /* automatically placed in its own * page */ - if (ogg_stream_pageout (&info.vo, &info.og) != 1){ + if (ogg_stream_pageout (&info->vo, &info->og) != 1){ fprintf (stderr, "Internal Ogg library error.\n"); exit (1); } - fwrite (info.og.header, 1, info.og.header_len, info.outfile); - fwrite (info.og.body, 1, info.og.body_len, info.outfile); + fwrite (info->og.header, 1, info->og.header_len, info->outfile); + fwrite (info->og.body, 1, info->og.body_len, info->outfile); /* remaining vorbis header packets */ - ogg_stream_packetin (&info.vo, &header_comm); - ogg_stream_packetin (&info.vo, &header_code); + ogg_stream_packetin (&info->vo, &header_comm); + ogg_stream_packetin (&info->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 && !info.audio_only){ - int result = ogg_stream_flush (&info.to, &info.og); + while (1 && !info->audio_only){ + int result = ogg_stream_flush (&info->to, &info->og); if (result < 0){ /* can't get here */ fprintf (stderr, "Internal Ogg library error.\n"); @@ -137,11 +135,11 @@ } if (result == 0) break; - fwrite (info.og.header, 1, info.og.header_len, info.outfile); - fwrite (info.og.body, 1, info.og.body_len, info.outfile); + fwrite (info->og.header, 1, info->og.header_len, info->outfile); + fwrite (info->og.body, 1, info->og.body_len, info->outfile); } - while (1 && !info.video_only){ - int result = ogg_stream_flush (&info.vo, &info.og); + while (1 && !info->video_only){ + int result = ogg_stream_flush (&info->vo, &info->og); if (result < 0){ /* can't get here */ fprintf (stderr, @@ -150,8 +148,8 @@ } if (result == 0) break; - fwrite (info.og.header, 1, info.og.header_len,info.outfile); - fwrite (info.og.body, 1, info.og.body_len, info.outfile); + fwrite (info->og.header, 1, info->og.header_len,info->outfile); + fwrite (info->og.body, 1, info->og.body_len, info->outfile); } } @@ -166,7 +164,7 @@ * @param linesize of data * @param e_o_s 1 indicates ond of stream */ -int theoraframes_add_video (uint8_t * data, int width, int height, int linesize,int e_o_s){ +int theoraframes_add_video (theoraframes_info *info, uint8_t * data, int width, int height, int linesize,int e_o_s){ /* map some things from info struk to local variables, * just to understand the code better */ /* pysical pages */ @@ -186,10 +184,10 @@ yuv.u = data + width * height; yuv.v = data + width * height * 5 / 4; } - theora_encode_YUVin (&info.td, &yuv); - theora_encode_packetout (&info.td, e_o_s, &info.op); - ogg_stream_packetin (&info.to, &info.op); - info.videoflag=1; + theora_encode_YUVin (&info->td, &yuv); + theora_encode_packetout (&info->td, e_o_s, &info->op); + ogg_stream_packetin (&info->to, &info->op); + info->videoflag=1; return 0; } @@ -200,71 +198,71 @@ * @param samples samples in buffer * @param e_o_s 1 indicates end of stream. */ -int theoraframes_add_audio (int16_t * buffer, int bytes, int samples, int e_o_s){ +int theoraframes_add_audio (theoraframes_info *info, int16_t * buffer, int bytes, int samples, int e_o_s){ int i,j, count = 0; float **vorbis_buffer; if (bytes <= 0 && samples <= 0){ /* end of audio stream */ if(e_o_s) - vorbis_analysis_wrote (&info.vd, 0); + vorbis_analysis_wrote (&info->vd, 0); } else{ - vorbis_buffer = vorbis_analysis_buffer (&info.vd, samples); + vorbis_buffer = vorbis_analysis_buffer (&info->vd, samples); /* uninterleave samples */ for (i = 0; i < samples; i++){ - for(j=0;j<info.channels;j++){ + for(j=0;j<info->channels;j++){ vorbis_buffer[j][i] = buffer[count++] / 32768.f; } } - vorbis_analysis_wrote (&info.vd, samples); + vorbis_analysis_wrote (&info->vd, samples); } - while(vorbis_analysis_blockout (&info.vd, &info.vb) == 1){ + while(vorbis_analysis_blockout (&info->vd, &info->vb) == 1){ /* analysis, assume we want to use bitrate management */ - vorbis_analysis (&info.vb, NULL); - vorbis_bitrate_addblock (&info.vb); + vorbis_analysis (&info->vb, NULL); + vorbis_bitrate_addblock (&info->vb); /* weld packets into the bitstream */ - while (vorbis_bitrate_flushpacket (&info.vd, &info.op)){ - ogg_stream_packetin (&info.vo, &info.op); + while (vorbis_bitrate_flushpacket (&info->vd, &info->op)){ + ogg_stream_packetin (&info->vo, &info->op); } } - info.audioflag=1; + info->audioflag=1; /* - if (ogg_stream_eos (&info.vo)){ - info.audioflag = 0; + if (ogg_stream_eos (&info->vo)){ + info->audioflag = 0; return 0; } */ return 0; } -void print_stats(double timebase){ +static void print_stats(theoraframes_info *info, double timebase){ int hundredths = timebase * 100 - (long) timebase * 100; int seconds = (long) timebase % 60; int minutes = ((long) timebase / 60) % 60; int hours = (long) timebase / 3600; - if(info.vkbps<0) - info.vkbps=0; - if(info.akbps<0) - info.akbps=0; + if(info->vkbps<0) + info->vkbps=0; + if(info->akbps<0) + info->akbps=0; - if(info.debug==1 && !info.video_only && !info.audio_only){ + if(info->debug==1 && !info->video_only && !info->audio_only){ fprintf (stderr,"\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps diff: %.4f ", - hours, minutes, seconds, hundredths,info.akbps, info.vkbps,info.audiotime-info.videotime); + hours, minutes, seconds, hundredths,info->akbps, info->vkbps,info->audiotime-info->videotime); } else{ fprintf (stderr,"\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps ", - hours, minutes, seconds, hundredths,info.akbps, info.vkbps); + hours, minutes, seconds, hundredths,info->akbps, info->vkbps); } } -void theoraframes_flush (int e_o_s){ - /* flush out the ogg pages to info.outfile */ +void theoraframes_flush (theoraframes_info *info, int e_o_s){ + /* flush out the ogg pages to info->outfile */ int flushloop=1; @@ -272,48 +270,48 @@ int video = -1; flushloop=0; //some debuging - //fprintf(stderr,"\ndiff: %f\n",info.audiotime-info.videotime); - while(!info.audio_only && (e_o_s || - ((info.videotime <= info.audiotime || info.video_only) && info.videoflag == 1))){ + //fprintf(stderr,"\ndiff: %f\n",info->audiotime-info->videotime); + while(!info->audio_only && (e_o_s || + ((info->videotime <= info->audiotime || info->video_only) && info->videoflag == 1))){ - info.videoflag = 0; - while(ogg_stream_pageout (&info.to, &info.videopage) > 0){ - info.videotime- theora_granule_time (&info.td,ogg_page_granulepos(&info.videopage)); + info->videoflag = 0; + while(ogg_stream_pageout (&info->to, &info->videopage) > 0){ + info->videotime+ theora_granule_time (&info->td,ogg_page_granulepos(&info->videopage)); /* flush a video page */ - info.video_bytesout +- fwrite (info.videopage.header, 1,info.videopage.header_len, info.outfile); - info.video_bytesout +- fwrite (info.videopage.body, 1,info.videopage.body_len, info.outfile); + info->video_bytesout ++ fwrite (info->videopage.header, 1,info->videopage.header_len, info->outfile); + info->video_bytesout ++ fwrite (info->videopage.body, 1,info->videopage.body_len, info->outfile); - info.vkbps = rint (info.video_bytesout * 8. / info.videotime * .001); + info->vkbps = rint (info->video_bytesout * 8. / info->videotime * .001); - print_stats(info.videotime); + print_stats(info, info->videotime); video=1; - info.videoflag = 1; + info->videoflag = 1; flushloop=1; } if(e_o_s) break; } - while (!info.video_only && (e_o_s || - ((info.audiotime < info.videotime || info.audio_only) && info.audioflag==1))){ + while (!info->video_only && (e_o_s || + ((info->audiotime < info->videotime || info->audio_only) && info->audioflag==1))){ - info.audioflag = 0; - while(ogg_stream_pageout (&info.vo, &info.audiopage) > 0){ + info->audioflag = 0; + while(ogg_stream_pageout (&info->vo, &info->audiopage) > 0){ /* flush an audio page */ - info.audiotime- vorbis_granule_time (&info.vd,ogg_page_granulepos(&info.audiopage)); - info.audio_bytesout +- fwrite (info.audiopage.header, 1,info.audiopage.header_len, info.outfile); - info.audio_bytesout +- fwrite (info.audiopage.body, 1,info.audiopage.body_len, info.outfile); + info->audiotime+ vorbis_granule_time (&info->vd,ogg_page_granulepos(&info->audiopage)); + info->audio_bytesout ++ fwrite (info->audiopage.header, 1,info->audiopage.header_len, info->outfile); + info->audio_bytesout ++ fwrite (info->audiopage.body, 1,info->audiopage.body_len, info->outfile); - info.akbps = rint (info.audio_bytesout * 8. / info.audiotime * .001); - print_stats(info.audiotime); + info->akbps = rint (info->audio_bytesout * 8. / info->audiotime * .001); + print_stats(info, info->audiotime); video=0; - info.audioflag = 1; + info->audioflag = 1; flushloop=1; } if(e_o_s) @@ -322,16 +320,16 @@ } } -void theoraframes_close (){ - ogg_stream_clear (&info.vo); - vorbis_block_clear (&info.vb); - vorbis_dsp_clear (&info.vd); - vorbis_comment_clear (&info.vc); - vorbis_info_clear (&info.vi); +void theoraframes_close (theoraframes_info *info){ + ogg_stream_clear (&info->vo); + vorbis_block_clear (&info->vb); + vorbis_dsp_clear (&info->vd); + vorbis_comment_clear (&info->vc); + vorbis_info_clear (&info->vi); - ogg_stream_clear (&info.to); - theora_clear (&info.td); + ogg_stream_clear (&info->to); + theora_clear (&info->td); - if (info.outfile && info.outfile != stdout) - fclose (info.outfile); + if (info->outfile && info->outfile != stdout) + fclose (info->outfile); } Index: theorautils.h ==================================================================--- theorautils.h (revision 8208) +++ theorautils.h (working copy) @@ -73,11 +73,10 @@ } theoraframes_info; - -extern void theoraframes_init (); -extern int theoraframes_add_video (uint8_t * data, int width, int height, +extern void theoraframes_init (theoraframes_info *info); +extern int theoraframes_add_video (theoraframes_info *info, uint8_t * data, int width, int height, int linesize,int e_o_s); -extern int theoraframes_add_audio (int16_t * readbuffer, int bytesread, +extern int theoraframes_add_audio (theoraframes_info *info, int16_t * readbuffer, int bytesread, int samplesread,int e_o_s); -extern void theoraframes_flush (int e_o_s); -extern void theoraframes_close (); +extern void theoraframes_flush (theoraframes_info *info, int e_o_s); +extern void theoraframes_close (theoraframes_info *info); Index: ffmpeg2theora.c ==================================================================--- ffmpeg2theora.c (revision 8208) +++ ffmpeg2theora.c (working copy) @@ -425,7 +425,7 @@ info.sample_rate = this->sample_rate; info.vorbis_quality = this->audio_quality; info.vorbis_bitrate = this->audio_bitrate; - theoraframes_init (); + theoraframes_init (&info); /* main decoding loop */ do{ @@ -491,7 +491,7 @@ } first=0; //now output_resized - if(theoraframes_add_video(output_resized->data[0], + if(theoraframes_add_video(&info, output_resized->data[0], this->video_x,this->video_y,output_resized->linesize[0],e_o_s)){ //this->output_width,this->output_height,output_resized->linesize[0],e_o_s)){ ret = -1; @@ -529,7 +529,7 @@ resampled=audio_buf; } } - if (theoraframes_add_audio(resampled, + if (theoraframes_add_audio(&info, resampled, samples_out *(this->channels),samples_out,e_o_s)){ ret = -1; fprintf (stderr,"No audio frames available\n"); @@ -541,7 +541,7 @@ } /* flush out the file */ - theoraframes_flush (e_o_s); + theoraframes_flush (&info, e_o_s); av_free_packet (&pkt); } while (ret >= 0); @@ -557,7 +557,7 @@ if (this->audio_resample_ctx) audio_resample_close(this->audio_resample_ctx); - theoraframes_close (); + theoraframes_close (&info); } else{ fprintf (stderr, "No video or audio stream found\n"); @@ -711,7 +711,15 @@ {"cropright",required_argument,&cropright_flag,1}, {"cropleft",required_argument,&cropleft_flag,1}, {"inputfps",required_argument,&inputfps_flag,1}, - + + {"artist",required_argument,NULL,10}, + {"title",required_argument,NULL,11}, + {"date",required_argument,NULL,12}, + {"location",required_argument,NULL,13}, + {"organization",required_argument,NULL,14}, + {"copyright",required_argument,NULL,15}, + {"license",required_argument,NULL,16}, + {"debug",0,NULL,'D'}, {"help",0,NULL,'h'}, {NULL,0,NULL,0} @@ -721,6 +729,7 @@ } // set some variables; info.debug=0; + theora_comment_init (&info.tc); while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){ switch(c) @@ -756,6 +765,27 @@ aspect_flag=0; } break; + case 10: + theora_comment_add_tag(&info.tc, "ARTIST", optarg); + break; + case 11: + theora_comment_add_tag(&info.tc, "TITLE", optarg); + break; + case 12: + theora_comment_add_tag(&info.tc, "DATE", optarg); + break; + case 13: + theora_comment_add_tag(&info.tc, "LOCATION", optarg); + break; + case 14: + theora_comment_add_tag(&info.tc, "ORGANIZATION", optarg); + break; + case 15: + theora_comment_add_tag(&info.tc, "COPYRIGHT", optarg); + break; + case 16: + theora_comment_add_tag(&info.tc, "LICENSE", optarg); + break; case 'o': sprintf(outputfile_name,optarg); outputfile_set=1;