[xiph-commits] r17292 - in trunk/ffmpeg2theora: . src
j at svn.xiph.org
j at svn.xiph.org
Wed Jun 16 06:32:35 PDT 2010
Author: j
Date: 2010-06-16 06:32:35 -0700 (Wed, 16 Jun 2010)
New Revision: 17292
Modified:
trunk/ffmpeg2theora/ChangeLog
trunk/ffmpeg2theora/src/ffmpeg2theora.c
trunk/ffmpeg2theora/src/theorautils.c
trunk/ffmpeg2theora/src/theorautils.h
Log:
Update Skeleton/OggIndex support to Skeleton 4.0.
ffmpeg2theora now writes Skeleton 4.0 with index by default.
Patch by Chris Pearce
Modified: trunk/ffmpeg2theora/ChangeLog
===================================================================
--- trunk/ffmpeg2theora/ChangeLog 2010-06-15 21:42:01 UTC (rev 17291)
+++ trunk/ffmpeg2theora/ChangeLog 2010-06-16 13:32:35 UTC (rev 17292)
@@ -1,5 +1,10 @@
-svn
+0.27 soon
- aspect ratio fix in twopass mode
+ - update to fmpeg 0.6 branch
+ - update documentation
+ - use ogv/oga/ogx depending on input if no output name is specified
+ - Skeleton 4.0 support(including index), can be disabled with
+ --skeleton-3 or --no-skeleton
0.26 2010-02-05
- use a/v sync from input container
Modified: trunk/ffmpeg2theora/src/ffmpeg2theora.c
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.c 2010-06-15 21:42:01 UTC (rev 17291)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.c 2010-06-16 13:32:35 UTC (rev 17292)
@@ -85,7 +85,7 @@
SPEEDLEVEL_FLAG,
PP_FLAG,
NOSKELETON,
- SEEK_INDEX,
+ SKELETON_3,
INDEX_INTERVAL,
THEORA_INDEX_RESERVE,
VORBIS_INDEX_RESERVE,
@@ -1677,7 +1677,7 @@
}
/* Write the index out to disk. */
- if (info.passno != 1 && info.with_seek_index) {
+ if (info.passno != 1 && !info.skeleton_3 && info.with_skeleton) {
write_seek_index (&info);
}
@@ -1869,7 +1869,7 @@
"General output options:\n"
" -o, --output alternative output filename\n"
" --no-skeleton disables ogg skeleton metadata output\n"
- " --seek-index enables keyframe index in skeleton track\n"
+ " --skeleton-3 outputs Skeleton Version 3, without keyframe indexes\n"
" -s, --starttime start encoding at this time (in sec.)\n"
" -e, --endtime end encoding at this time (in sec.)\n"
" -p, --preset encode file with preset.\n"
@@ -2058,7 +2058,7 @@
{"output",required_argument,NULL,'o'},
{"skeleton",no_argument,NULL,'k'},
{"no-skeleton",no_argument,&flag,NOSKELETON},
- {"seek-index",no_argument,&flag,SEEK_INDEX},
+ {"skeleton-3",no_argument,&flag,SKELETON_3},
{"index-interval",required_argument,&flag,INDEX_INTERVAL},
{"theora-index-reserve",required_argument,&flag,THEORA_INDEX_RESERVE},
{"vorbis-index-reserve",required_argument,&flag,VORBIS_INDEX_RESERVE},
@@ -2321,8 +2321,8 @@
case NOSKELETON:
info.with_skeleton=0;
break;
- case SEEK_INDEX:
- info.with_seek_index = 1;
+ case SKELETON_3:
+ info.skeleton_3 = 1;
break;
case INDEX_INTERVAL:
info.index_interval = atoi(optarg);
@@ -2566,7 +2566,7 @@
}
}
- if (info.with_seek_index && !info.with_skeleton) {
+ if (info.skeleton_3 && !info.with_skeleton) {
fprintf(stderr, "ERROR: Cannot use --no-skeleton and --seek-index options together!\n");
exit(1);
}
Modified: trunk/ffmpeg2theora/src/theorautils.c
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.c 2010-06-15 21:42:01 UTC (rev 17291)
+++ trunk/ffmpeg2theora/src/theorautils.c 2010-06-16 13:32:35 UTC (rev 17292)
@@ -64,7 +64,7 @@
void init_info(oggmux_info *info) {
info->output_seekable = MAYBE_SEEKABLE;
info->with_skeleton = 1; /* skeleton is enabled by default */
- info->with_seek_index = 0; /* keyframe index disabled by default. */
+ info->skeleton_3 = 0; /* by default, output skeleton 4 with keyframe indexes. */
info->index_interval = 2000;
info->theora_index_reserve = -1;
info->vorbis_index_reserve = -1;
@@ -126,14 +126,6 @@
}
}
-static ogg_uint32_t read_uint32(unsigned const char* p) {
- ogg_uint32_t i = p[0] +
- (p[1] << 8) +
- (p[2] << 16) +
- (p[3] << 24);
- return i;
-}
-
static void write16le(unsigned char *ptr,ogg_uint16_t v)
{
ptr[0]=v&0xff;
@@ -200,48 +192,10 @@
assert(info->output_seekable != MAYBE_SEEKABLE);
}
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-
-static ogg_int64_t index_start_time(oggmux_info* info)
-{
- ogg_int64_t start_time;
- int n;
-
- if (!info->with_seek_index || !info->indexing_complete) {
- return -1;
- }
-
- start_time = MIN(info->theora_index.start_time, info->vorbis_index.start_time);
- for (n=0; n<info->n_kate_streams; ++n) {
- oggmux_kate_stream *ks=info->kate_streams+n;
- if (ks->index.start_time < start_time)
- start_time = ks->index.start_time;
- }
- return start_time;
-}
-
-static ogg_int64_t index_end_time(oggmux_info* info)
-{
- ogg_int64_t end_time;
- int n;
-
- if (!info->with_seek_index || !info->indexing_complete) {
- return -1;
- }
- end_time = MAX(info->theora_index.end_time, info->vorbis_index.end_time);
- for (n=0; n<info->n_kate_streams; ++n) {
- oggmux_kate_stream *ks=info->kate_streams+n;
- if (ks->index.end_time > end_time)
- end_time = ks->index.end_time;
- }
- return end_time;
-}
-
static ogg_int64_t output_file_length(oggmux_info* info)
{
ogg_int64_t offset, length;
- if (!info->with_seek_index || !info->indexing_complete) {
+ if (info->skeleton_3 || !info->indexing_complete) {
return -1;
}
offset = ftello(info->outfile);
@@ -267,19 +221,9 @@
ogg_uint32_t version = SKELETON_VERSION(ver_maj, ver_min);
assert(version >= SKELETON_VERSION(3,0) ||
- version <= SKELETON_VERSION(3,3));
+ version == SKELETON_VERSION(4,0));
- switch (version) {
- case SKELETON_VERSION(3,0):
- packet_size = 64;
- break;
- case SKELETON_VERSION(3,3):
- packet_size = 112;
- break;
- default:
- fprintf (stderr, "ERROR: Unknown skeleton version\n");
- exit (1);
- };
+ packet_size = (version == SKELETON_VERSION(4,0)) ? 80 : 64;
memset (&op, 0, sizeof (op));
@@ -298,13 +242,9 @@
write32le(op.packet+44, 0); /* UTC time, set to zero for now */
/* Index start/end time, if unknown or non-indexed, will be -1. */
- if (version >= SKELETON_VERSION(3,2)) {
- write64le(op.packet+64, index_start_time(info));
- write64le(op.packet+72, (ogg_int64_t)1000);
- write64le(op.packet+80, index_end_time(info));
- write64le(op.packet+88, (ogg_int64_t)1000);
- write64le(op.packet+96, output_file_length(info));
- write64le(op.packet+104, info->content_offset);
+ if (version == SKELETON_VERSION(4,0)) {
+ write64le(op.packet+64, output_file_length(info));
+ write64le(op.packet+72, info->content_offset);
}
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 */
@@ -314,18 +254,32 @@
_ogg_free (op.packet);
}
+const char* theora_message_headers = "Content-Type: video/theora\r\n"
+ "Role: video/main\r\n"
+ "Name: video_1\r\n";
+
+const char* vorbis_message_headers = "Content-Type: audio/vorbis\r\n"
+ "Role: audio/main\r\n"
+ "Name: audio_1\r\n";
+#ifdef HAVE_KATE
+const char* kate_message_headers = "Content-Type: application/x-kate\r\n\r\n"
+ "Role: text/subtitle\r\n";
+ /* Dynamically add name header... */
+#endif
+
/*
* 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;
-
+ size_t packet_size = 0;
if (!info->audio_only) {
memset (&op, 0, sizeof (op));
- op.packet = _ogg_calloc (80, sizeof(unsigned char));
+ packet_size = FISBONE_SIZE + strlen(theora_message_headers);
+ op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
if (op.packet == NULL) return;
- memset (op.packet, 0, 80);
+ memset (op.packet, 0, packet_size);
/* it will be the fisbone packet for the theora video */
memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
@@ -337,11 +291,12 @@
write64le(op.packet+36, 0); /* start granule */
write32le(op.packet+44, 0); /* preroll, for theora its 0 */
*(op.packet+48) = info->ti.keyframe_granule_shift; /* granule shift */
- memcpy(op.packet+FISBONE_SIZE, "Content-Type: video/theora\r\n", 28); /* message header field, Content-Type */
+ /* message header fields */
+ memcpy(op.packet+FISBONE_SIZE, theora_message_headers, strlen(theora_message_headers));
op.b_o_s = 0;
op.e_o_s = 0;
- op.bytes = 80; /* size of the packet in bytes */
+ op.bytes = packet_size; /* size of the packet in bytes */
ogg_stream_packetin (&info->so, &op);
_ogg_free (op.packet);
@@ -349,10 +304,11 @@
if (!info->video_only) {
memset (&op, 0, sizeof (op));
- op.packet = _ogg_calloc (80, sizeof(unsigned char));
+ packet_size = FISBONE_SIZE + strlen(vorbis_message_headers);
+ op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
if (op.packet == NULL) return;
- memset (op.packet, 0, 80);
+ memset (op.packet, 0, packet_size);
/* it will be the fisbone packet for the vorbis audio */
memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
@@ -364,12 +320,13 @@
write64le(op.packet+36, 0); /* start granule */
write32le(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/vorbis\r\n", 28);
+ memcpy(op.packet+FISBONE_SIZE, vorbis_message_headers, strlen(vorbis_message_headers));
+
/* Important: Check the case of Content-Type for correctness */
op.b_o_s = 0;
op.e_o_s = 0;
- op.bytes = 80;
+ op.bytes = packet_size;
ogg_stream_packetin (&info->so, &op);
_ogg_free (op.packet);
@@ -378,31 +335,39 @@
#ifdef HAVE_KATE
if (info->with_kate) {
int n;
+ char name[32];
for (n=0; n<info->n_kate_streams; ++n) {
+ size_t packet_size = 0;
+ int message_headers_len = strlen(kate_message_headers);
+ int name_len = 0;
oggmux_kate_stream *ks=info->kate_streams+n;
- memset (&op, 0, sizeof (op));
- op.packet = _ogg_calloc (86, sizeof(unsigned char));
- memset (op.packet, 0, 86);
+ memset (&op, 0, sizeof (op));
+ sprintf(name, "Name: %d\r\n", (n+1));
+ name_len = strlen(name);
+ packet_size = FISBONE_SIZE + message_headers_len + name_len;
+ op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
+ memset (op.packet, 0, packet_size);
/* it will be the fisbone packet for the kate stream */
- memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
+ memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
- write32le(op.packet+12, ks->ko.serialno); /* serialno of the vorbis stream */
+ write32le(op.packet+12, ks->ko.serialno); /* serialno of the vorbis stream */
write32le(op.packet+16, ks->ki.num_headers); /* number of header packet */
- /* granulerate, temporal resolution of the bitstream in Hz */
- write64le(op.packet+20, ks->ki.gps_numerator); /* granulerate numerator */
+ /* granulerate, temporal resolution of the bitstream in Hz */
+ write64le(op.packet+20, ks->ki.gps_numerator); /* granulerate numerator */
write64le(op.packet+28, ks->ki.gps_denominator); /* granulerate denominator */
- write64le(op.packet+36, 0); /* start granule */
+ write64le(op.packet+36, 0); /* start granule */
write32le(op.packet+44, 0); /* preroll, for kate it's 0 */
- *(op.packet+48) = ks->ki.granule_shift; /* granule shift */
- memcpy (op.packet+FISBONE_SIZE, "Content-Type: application/x-kate\r\n", 34);
- /* Important: Check the case of Content-Type for correctness */
+ *(op.packet+48) = ks->ki.granule_shift; /* granule shift */
+ memcpy (op.packet+FISBONE_SIZE, kate_message_headers, message_headers_len);
+ memcpy (op.packet+FISBONE_SIZE+message_headers_len, name, name_len);
+ /* Important: Check the case of Content-Type for correctness */
- op.b_o_s = 0;
- op.e_o_s = 0;
- op.bytes = 86;
+ op.b_o_s = 0;
+ op.e_o_s = 0;
+ op.bytes = packet_size;
ogg_stream_packetin (&info->so, &op);
- _ogg_free (op.packet);
+ _ogg_free (op.packet);
}
}
#endif
@@ -420,7 +385,7 @@
ogg_uint32_t serialno,
ogg_int64_t num_used_keypoints)
{
- size_t size = 26 + bytes;
+ size_t size = 42 + bytes;
memset (op, 0, sizeof(*op));
op->packet = malloc(size);
if (op->packet == NULL)
@@ -442,6 +407,12 @@
/* Write timestamp denominator, times are in milliseconds, so 1000. */
write64le(op->packet+18, (ogg_int64_t)1000);
+ /* Write first sample time numerator. */
+ write64le(op->packet+26, (ogg_int64_t)0);
+
+ /* Write last sample time numerator. */
+ write64le(op->packet+34, (ogg_int64_t)0);
+
return 0;
}
@@ -628,11 +599,16 @@
"only part of the file may be indexed. Rerun with --%s-index-reserve %d to "
"ensure a complete index, or use OggIndex to re-index.\n",
name, (k - keypoints_cutoff), name, index_bytes);
- } else if (index_bytes < index->packet_size) {
+ } else if (index_bytes < index->packet_size &&
+ index->packet_size - index_bytes > 10000)
+ {
+ /* We over estimated the index size by 10,000 bytes or more. */
printf("Allocated %d bytes for %s keyframe index, %d are unused. "
+ "Index contains %d keyframes. "
"Rerun with '--%s-index-reserve %d' to encode with the optimal sized %s index,"
" or use OggIndex to re-index.\n",
index->packet_size, name, (index->packet_size - index_bytes),
+ keypoints_cutoff,
name, index_bytes, name);
}
num_keypoints = keypoints_cutoff;
@@ -645,9 +621,15 @@
free(keypoints);
return -1;
}
+
+ /* Write first sample time numerator. */
+ write64le(op.packet+26, index->start_time);
+
+ /* Write last sample time numerator. */
+ write64le(op.packet+34, index->end_time);
/* Write keypoint data into packet. */
- p = op.packet + 26;
+ p = op.packet + 42;
limit = op.packet + op.bytes;
prev_offset = 0;
prev_time = 0;
@@ -697,8 +679,8 @@
ogg_uint32_t serialno;
ogg_page og;
- /* If the index is disabled, we shouldn't be doing this! */
- assert(info->with_seek_index);
+ /* We shouldn't write indexes for skeleton 3, it's a skeleton 4 feature. */
+ assert(!info->skeleton_3);
/* Mark that we're done indexing. This causes the header packets' fields
to be filled with valid, non-unknown values. */
@@ -710,7 +692,7 @@
ogg_stream_clear(&info->so);
ogg_stream_init(&info->so, serialno);
- add_fishead_packet (info, 3, 3);
+ add_fishead_packet (info, 4, 0);
if (ogg_stream_flush(&info->so, &og) != 1) {
fprintf (stderr, "Internal Ogg library error.\n");
exit (1);
@@ -897,26 +879,24 @@
}
/* kate init done */
- if (info->with_seek_index &&
+ if (!info->skeleton_3 &&
info->duration == -1)
{
/* We've not got a duration, we can't index the keyframes. */
- fprintf(stderr, "WARNING: Can't get duration of media, not indexing.\n");
- info->with_seek_index = 0;
+ fprintf(stderr, "WARNING: Can't get duration of media, not indexing, writing Skeleton 3 track.\n");
+ info->skeleton_3 = 1;
}
- /* We must only index keyframes when the skeleton track is also present. */
- assert (!info->with_seek_index || info->with_skeleton);
/* first packet should be skeleton fishead packet, if skeleton is used */
if (info->with_skeleton && info->passno!=1) {
/* Sometimes the output file is not seekable. We can't write the seek
index if the output is not seekable. So write a Skeleton3.0 header
- packet, which will in turn determines if the file is seekable. If it
+ packet, which will in turn determine if the file is seekable. If it
is, we can safely construct an index, so then overwrite the header
- page with a Skeleton3.1 header page. */
- int with_seek_index = info->with_seek_index;
- info->with_seek_index = 0;
+ page with a Skeleton4.0 header page. */
+ int skeleton_3 = info->skeleton_3;
+ info->skeleton_3 = 1;
ogg_stream_init (&info->so, rand());
add_fishead_packet (info, 3, 0);
if (ogg_stream_pageout (&info->so, &og) != 1) {
@@ -926,24 +906,23 @@
write_page (info, &og);
assert(info->output_seekable != MAYBE_SEEKABLE);
- if (info->output_seekable == NOT_SEEKABLE && with_seek_index) {
+ if (info->output_seekable == NOT_SEEKABLE && !skeleton_3) {
fprintf(stderr, "WARNING: Can't write keyframe-seek-index into "
- "non-seekable output stream!\n");
+ "non-seekable output stream! Writing Skeleton3 track.\n");
}
- info->with_seek_index = with_seek_index &&
- info->output_seekable == SEEKABLE;
+ info->skeleton_3 = skeleton_3 || info->output_seekable == NOT_SEEKABLE;
- if (info->with_seek_index) {
+ if (!info->skeleton_3) {
/* Output is seekable and we're indexing. Overwrite the
- Skeleton3.0 BOS page with a Skeleton3.1 BOS page. */
+ Skeleton3.0 BOS page with a Skeleton4.0 BOS page. */
if (fseeko (info->outfile, 0, SEEK_SET) < 0) {
fprintf (stderr, "ERROR: failed to seek in seekable output file!?!\n");
exit (1);
}
ogg_stream_clear (&info->so);
ogg_stream_init (&info->so, rand());
- add_fishead_packet (info, 3, 3);
+ add_fishead_packet (info, 4, 0);
if (ogg_stream_pageout (&info->so, &og) != 1) {
fprintf (stderr, "Internal Ogg library error.\n");
exit (1);
@@ -1094,7 +1073,7 @@
if (info->with_skeleton && info->passno!=1) {
int result;
- if (info->with_seek_index) {
+ if (!info->skeleton_3) {
/* Add placeholder packets to reserve space for the index
* at the start of file. */
write_placeholder_index_pages (info);
@@ -1184,7 +1163,7 @@
}
while (th_encode_packetout (info->td, e_o_s, &op) > 0) {
- if (info->with_seek_index &&
+ if (!info->skeleton_3 &&
info->passno != 1)
{
ogg_int64_t frameno = th_granule_frame(info->td, op.granulepos);
@@ -1283,7 +1262,7 @@
ogg_int64_t start_time = vorbis_time (&info->vd, start_granule);
if (op.granulepos != -1 &&
- info->with_seek_index &&
+ !info->skeleton_3 &&
info->passno != 1)
{
ogg_int64_t end_time = vorbis_time (&info->vd, op.granulepos);
@@ -1329,7 +1308,7 @@
int ret;
ret = kate_ogg_encode_text(&ks->k, t0, t1, text, len, &op);
if (ret>=0) {
- if (info->with_seek_index && info->passno != 1) {
+ if (!info->skeleton_3 && info->passno != 1) {
ogg_int64_t start_time = (int)(t0 * 1000.0f + 0.5f);
ogg_int64_t end_time = (int)(t1 * 1000.0f + 0.5f);
oggmux_record_kate_index(info, ks, &op, start_time, end_time);
@@ -1359,7 +1338,7 @@
int ret;
ret = kate_ogg_encode_finish(&ks->k, t, &op);
if (ret>=0) {
- if (info->with_seek_index && info->passno != 1) {
+ if (!info->skeleton_3 && info->passno != 1) {
ogg_int64_t start_time = floorf(t * 1000.0f + 0.5f);
ogg_int64_t end_time = start_time;
oggmux_record_kate_index(info, ks, &op, start_time, end_time);
@@ -1485,7 +1464,6 @@
ogg_int64_t page_offset = ftello(info->outfile);
int packets = ogg_page_packets((ogg_page *)&info->audiopage);
int packet_start_num = ogg_page_start_packets(info->audiopage);
- ogg_uint32_t checksum = read_uint32(info->audiopage + 22);
ret = fwrite(info->audiopage, 1, info->audiopage_len, info->outfile);
if (ret < info->audiopage_len) {
@@ -1519,7 +1497,6 @@
ogg_int64_t page_offset = ftello(info->outfile);
int packets = ogg_page_packets((ogg_page *)&info->videopage);
int packet_start_num = ogg_page_start_packets(info->videopage);
- ogg_uint32_t checksum = read_uint32(info->videopage + 22);
ret = fwrite(info->videopage, 1, info->videopage_len, info->outfile);
if (ret < info->videopage_len) {
Modified: trunk/ffmpeg2theora/src/theorautils.h
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.h 2010-06-15 21:42:01 UTC (rev 17291)
+++ trunk/ffmpeg2theora/src/theorautils.h 2010-06-16 13:32:35 UTC (rev 17292)
@@ -77,7 +77,7 @@
int audio_only;
int video_only;
int with_skeleton;
- int with_seek_index;
+ int skeleton_3;
int index_interval;
int theora_index_reserve;
int vorbis_index_reserve;
More information about the commits
mailing list