[Theora-dev] metadata switches for ffmpeg2theora

Ralph Giles giles at xiph.org
Tue Nov 16 22:04:43 PST 2004


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;


More information about the Theora-dev mailing list