[xiph-commits] r11698 - trunk/ffmpeg2theora

j at svn.xiph.org j at svn.xiph.org
Sat Jul 8 01:25:55 PDT 2006


Author: j
Date: 2006-07-08 01:25:52 -0700 (Sat, 08 Jul 2006)
New Revision: 11698

Modified:
   trunk/ffmpeg2theora/ffmpeg2theora.c
   trunk/ffmpeg2theora/theorautils.c
   trunk/ffmpeg2theora/theorautils.h
Log:
patch by tahseen adding ogg skeleton support.
Fixes #939



Modified: trunk/ffmpeg2theora/ffmpeg2theora.c
===================================================================
--- trunk/ffmpeg2theora/ffmpeg2theora.c	2006-07-06 23:09:49 UTC (rev 11697)
+++ trunk/ffmpeg2theora/ffmpeg2theora.c	2006-07-08 08:25:52 UTC (rev 11698)
@@ -790,6 +790,7 @@
         "\n"
         "General output options:\n"
         "  -o, --output           alternative output filename\n"
+	"  -k, --skeleton         outputs ogg skeleton metadata\n"
         "  -s, --starttime        start encoding at this time (in sec.)\n"
         "  -e, --endtime          end encoding at this time (in sec.)\n"
         "  -p, --v2v-preset       encode file with v2v preset.\n"
@@ -886,10 +887,11 @@
     AVFormatParameters *formatParams = NULL;
     
     int c,long_option_index;
-    const char *optstring = "P:o:f:x:y:v:V:a:A:S:K:d:H:c:p:N:s:e:D:h::";
+    const char *optstring = "P:o:k:f:x:y:v:V:a:A:S:K:d:H:c:p:N:s:e:D:h::";
     struct option options [] = {
       {"pid",required_argument,NULL, 'P'},
       {"output",required_argument,NULL,'o'},
+      {"skeleton",no_argument,NULL,'k'},
       {"format",required_argument,NULL,'f'},
       {"width",required_argument,NULL,'x'},
       {"height",required_argument,NULL,'y'},
@@ -1052,6 +1054,9 @@
                 sprintf(outputfile_name,optarg);
                 outputfile_set=1;
                 break;
+	    case 'k':
+		info.with_skeleton=1;
+		break;
             case 'P':
                 sprintf(pidfile_name,optarg);
                 break;

Modified: trunk/ffmpeg2theora/theorautils.c
===================================================================
--- trunk/ffmpeg2theora/theorautils.c	2006-07-06 23:09:49 UTC (rev 11697)
+++ trunk/ffmpeg2theora/theorautils.c	2006-07-08 08:25:52 UTC (rev 11698)
@@ -41,6 +41,7 @@
 }
 
 void init_info(oggmux_info *info) {
+    info->with_skeleton = 0; /* skeleton is disabled by default	*/
     info->videotime =  0;
     info->audiotime = 0;
     info->audio_bytesout = 0;
@@ -60,6 +61,88 @@
 #endif
 }
 
+void add_fishead_packet (oggmux_info *info) {
+    ogg_packet op;
+
+    memset (&op, 0, sizeof (op));
+    
+    op.packet = _ogg_calloc (64, sizeof(unsigned char));
+    memset (op.packet, 0, 64);
+    memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */
+    *((ogg_uint16_t*)(op.packet+8)) = SKELETON_VERSION_MAJOR; /* version major */
+    *((ogg_uint16_t*)(op.packet+10)) = SKELETON_VERSION_MINOR; /* version minor */
+    *((ogg_int64_t*)(op.packet+12)) = (ogg_int64_t)0; /* presentationtime numerator */
+    *((ogg_int64_t*)(op.packet+20)) = (ogg_int64_t)1000; /* presentationtime denominator */
+    *((ogg_int64_t*)(op.packet+28)) = (ogg_int64_t)0; /* basetime numerator */
+    *((ogg_int64_t*)(op.packet+36)) = (ogg_int64_t)1000; /* basetime denominator */
+    /* both the numerator are zero hence handled by the memset */
+    *((ogg_uint32_t*)(op.packet+44)) = 0; /* UTC time, set to zero for now */
+    
+    op.b_o_s = 1; /* its the first packet of the stream */
+    op.e_o_s = 0; /* its not the last packet of the stream */
+    op.bytes = 64; /* length of the packet in bytes */
+
+    ogg_stream_packetin (&info->so, &op); /* adding the packet to the skeleton stream */
+    _ogg_free (op.packet);
+}
+
+/*
+ * Adds the fishead packets in the skeleton output stream along with the e_o_s packet
+ */
+void add_fisbone_packet (oggmux_info *info) {
+    ogg_packet op;
+
+    if (!info->audio_only) {
+	memset (&op, 0, sizeof (op));	    
+        op.packet = _ogg_calloc (80, sizeof(unsigned char));
+        memset (op.packet, 0, 80);
+	/* it will be the fisbone packet for the theora video */
+        memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
+	*((ogg_uint32_t*)(op.packet+8)) = FISBONE_MESSAGE_HEADER_OFFSET; /* offset of the message header fields */
+        *((ogg_uint32_t*)(op.packet+12)) = info->to.serialno; /* serialno of the theora stream */
+	*((ogg_uint32_t*)(op.packet+16)) = 3; /* number of header packets */
+	/* granulerate, temporal resolution of the bitstream in samples/microsecond */
+        *((ogg_int64_t*)(op.packet+20)) = info->ti.fps_numerator; /* granulrate numerator */
+	*((ogg_int64_t*)(op.packet+28)) = info->ti.fps_denominator; /* granulrate denominator */
+        *((ogg_int64_t*)(op.packet+36)) = 0; /* start granule */
+	*((ogg_uint32_t*)(op.packet+44)) = 0; /* preroll, for theora its 0 */
+        *(op.packet+48) = theora_granule_shift (&info->ti); /* granule shift */
+        memcpy(op.packet+FISBONE_SIZE, "Content-Type: video/x-theora", 28); /* message header field, Content-Type */
+		
+	op.b_o_s = 0; 
+	op.e_o_s = 0;
+	op.bytes = 80; /* size of the packet in bytes */
+	
+        ogg_stream_packetin (&info->so, &op);
+	_ogg_free (op.packet);
+    }
+
+    if (!info->video_only) {
+	memset (&op, 0, sizeof (op));
+	op.packet = _ogg_calloc (80, sizeof(unsigned char));
+	memset (op.packet, 0, 80);
+        /* it will be the fisbone packet for the vorbis audio */
+	memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
+        *((ogg_uint32_t*)(op.packet+8)) = FISBONE_MESSAGE_HEADER_OFFSET; /* offset of the message header fields */
+	*((ogg_uint32_t*)(op.packet+12)) = info->vo.serialno; /* serialno of the vorbis stream */
+        *((ogg_uint32_t*)(op.packet+16)) = 3; /* number of header packet */
+	/* granulerate, temporal resolution of the bitstream in samples/microsecond */
+	*((ogg_int64_t*)(op.packet+20)) = info->sample_rate; /* granulerate numerator */
+        *((ogg_int64_t*)(op.packet+28)) = (ogg_int64_t)1000; /* granulerate denominator */
+	*((ogg_int64_t*)(op.packet+36)) = 0; /* start granule */
+        *((ogg_uint32_t*)(op.packet+44)) = 2; /* preroll, for vorbis its 2 */
+	*(op.packet+48) = 0; /* granule shift, always 0 for vorbis */
+        memcpy (op.packet+FISBONE_SIZE, "Content-Type: audio/x-vorbis", 28);
+	
+	op.b_o_s = 0;
+	op.e_o_s = 0;
+	op.bytes = 80;
+	
+        ogg_stream_packetin (&info->so, &op);
+	_ogg_free (op.packet);
+    }
+}
+
 void oggmux_init (oggmux_info *info){
     ogg_page og;
     ogg_packet op;
@@ -101,6 +184,19 @@
     }
     /* audio init done */
 
+    /* first packet should be skeleton fishead packet, if skeleton is used */
+
+    if (info->with_skeleton) {
+	ogg_stream_init (&info->so, rand());
+	add_fishead_packet (info);
+	if (ogg_stream_pageout (&info->so, &og) != 1){
+            fprintf (stderr, "Internal Ogg library error.\n");
+            exit (1);
+        }
+        fwrite (og.header, 1, og.header_len, info->outfile);
+        fwrite (og.body, 1, og.body_len, info->outfile);
+    }
+
     /* write the bitstream header packets with proper page interleave */
 
     /* first packet will get its own page automatically */
@@ -143,6 +239,23 @@
         ogg_stream_packetin (&info->vo, &header_code);
     }
 
+    /* output the appropriate fisbone packets */
+    if (info->with_skeleton) {
+	add_fisbone_packet (info);
+	while (1) {
+	    int result = ogg_stream_flush (&info->so, &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, info->outfile);
+	    fwrite (og.body, 1, og.body_len, info->outfile);
+	}
+    }
+
     /* Flush the rest of our headers. This ensures
      * the actual data in each stream will start
      * on a new page, as per spec. */
@@ -170,6 +283,25 @@
         fwrite (og.header, 1, og.header_len,info->outfile);
         fwrite (og.body, 1, og.body_len, info->outfile);
     }
+
+    if (info->with_skeleton) {
+        /* build and add the e_o_s packet */
+	memset (&op, 0, sizeof (op));
+        op.b_o_s = 0;
+	op.e_o_s = 1; /* its the e_o_s packet */
+        op.granulepos = 0;
+	op.bytes = 0; /* e_o_s packet is an empty packet */
+        ogg_stream_packetin (&info->so, &op);
+
+	int result = ogg_stream_flush (&info->so, &og);
+        if (result < 0){
+            /* can't get here */
+            fprintf (stderr, "Internal Ogg library error.\n");
+            exit (1);
+        }
+        fwrite (og.header, 1, og.header_len,info->outfile);
+        fwrite (og.body, 1, og.body_len, info->outfile);
+    }
 }
 
 /**    

Modified: trunk/ffmpeg2theora/theorautils.h
===================================================================
--- trunk/ffmpeg2theora/theorautils.h	2006-07-06 23:09:49 UTC (rev 11697)
+++ trunk/ffmpeg2theora/theorautils.h	2006-07-08 08:25:52 UTC (rev 11698)
@@ -26,6 +26,13 @@
 
 // #define OGGMUX_DEBUG
 
+#define SKELETON_VERSION_MAJOR 3
+#define SKELETON_VERSION_MINOR 0
+#define FISHEAD_IDENTIFIER "fishead\0"
+#define FISBONE_IDENTIFIER "fisbone\0"
+#define FISBONE_SIZE 52
+#define FISBONE_MESSAGE_HEADER_OFFSET 44
+
 typedef struct
 {
     /* the file the mixed ogg stream is written to */
@@ -33,6 +40,7 @@
 
     int audio_only;
     int video_only;
+    int with_skeleton;
 
     /* vorbis settings */
     int sample_rate;
@@ -57,6 +65,8 @@
                              * stream of packets */
     ogg_stream_state vo;    /* take physical pages, weld into a logical
                              * stream of packets */
+    ogg_stream_state so;    /* take physical pages, weld into a logical
+			     * stream of packets, used for skeleton stream */
 
     int audiopage_valid;
     int videopage_valid;



More information about the commits mailing list