[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