[xiph-commits] r14147 - trunk/vorbis-tools/oggenc
ivo at svn.xiph.org
ivo at svn.xiph.org
Thu Nov 15 00:33:07 PST 2007
Author: ivo
Date: 2007-11-15 00:33:06 -0800 (Thu, 15 Nov 2007)
New Revision: 14147
Added:
trunk/vorbis-tools/oggenc/skeleton.c
trunk/vorbis-tools/oggenc/skeleton.h
Modified:
trunk/vorbis-tools/oggenc/Makefile.am
trunk/vorbis-tools/oggenc/encode.c
trunk/vorbis-tools/oggenc/encode.h
trunk/vorbis-tools/oggenc/oggenc.c
Log:
applied skeleton patch by Tahseen; ticket #1008
Modified: trunk/vorbis-tools/oggenc/Makefile.am
===================================================================
--- trunk/vorbis-tools/oggenc/Makefile.am 2007-11-15 07:45:07 UTC (rev 14146)
+++ trunk/vorbis-tools/oggenc/Makefile.am 2007-11-15 08:33:06 UTC (rev 14147)
@@ -23,7 +23,7 @@
oggenc_SOURCES = $(flac_sources) \
oggenc.c audio.c encode.c platform.c \
- audio.h encode.h platform.h resample.c resample.h
+ audio.h encode.h platform.h resample.c resample.h skeleton.c skeleton.h
debug:
Modified: trunk/vorbis-tools/oggenc/encode.c
===================================================================
--- trunk/vorbis-tools/oggenc/encode.c 2007-11-15 07:45:07 UTC (rev 14146)
+++ trunk/vorbis-tools/oggenc/encode.c 2007-11-15 08:33:06 UTC (rev 14147)
@@ -17,11 +17,13 @@
#include <stdio.h>
#include <math.h>
#include <string.h>
+#include <time.h>
#include "platform.h"
#include <vorbis/vorbisenc.h>
#include "encode.h"
#include "i18n.h"
+#include "skeleton.h"
#define READSIZE 1024
@@ -110,12 +112,47 @@
}
}
+void add_fishead_packet (ogg_stream_state *os) {
+
+ fishead_packet fp;
+
+ memset(&fp, 0, sizeof(fp));
+ fp.ptime_n = 0;
+ fp.ptime_d = 1000;
+ fp.btime_n = 0;
+ fp.btime_d = 1000;
+
+ add_fishead_to_stream(os, &fp);
+}
+
+/*
+ * Adds the fishead packets in the skeleton output stream along with the e_o_s packet
+ */
+void add_fisbone_packet (ogg_stream_state *os, oe_enc_opt *opt) {
+
+ fisbone_packet fp;
+
+ memset(&fp, 0, sizeof(fp));
+ fp.serial_no = opt->serialno;
+ fp.nr_header_packet = 3;
+ fp.granule_rate_n = opt->rate;
+ fp.granule_rate_d = 1;
+ fp.start_granule = 0;
+ fp.preroll = 2;
+ fp.granule_shift = 0;
+
+ add_message_header_field(&fp, "Content-Type", "audio/vorbis");
+
+ add_fisbone_to_stream(os, &fp);
+}
+
int oe_encode(oe_enc_opt *opt)
{
ogg_stream_state os;
- ogg_page og;
- ogg_packet op;
+ ogg_stream_state so; /* stream for skeleton bitstream */
+ ogg_page og;
+ ogg_packet op;
vorbis_dsp_state vd;
vorbis_block vb;
@@ -127,9 +164,10 @@
double time_elapsed;
int ret=0;
TIMER *timer;
+ int result;
if(opt->channels > 255) {
- fprintf(stderr, _("255 channels should be enough for anyone. (Sorry, vorbis doesn't support more)\n"));
+ fprintf(stderr, _("255 channels should be enough for anyone. (Sorry, but Vorbis doesn't support more)\n"));
return 1;
}
@@ -152,7 +190,7 @@
/* Have vorbisenc choose a mode for us */
vorbis_info_init(&vi);
-
+
if(opt->quality_set > 0){
if(vorbis_encode_setup_vbr(&vi, opt->channels, opt->rate, opt->quality)){
fprintf(stderr, _("Mode initialisation failed: invalid parameters for quality\n"));
@@ -192,7 +230,7 @@
ai.bitrate_average_damping = 1.5;
ai.bitrate_limit_reservoir_bits = bitrate * 2;
ai.bitrate_limit_reservoir_bias = .1;
-
+
/* And now the ones we actually wanted to set */
ai.bitrate_limit_min_kbps=opt->min_bitrate;
ai.bitrate_limit_max_kbps=opt->max_bitrate;
@@ -218,7 +256,7 @@
return 1;
}
}
-
+
if(opt->managed && opt->bitrate < 0)
{
struct ovectl_ratemanage2_arg ai;
@@ -231,9 +269,9 @@
/* Turn off management entirely (if it was turned on). */
vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE2_SET, NULL);
}
-
+
set_advanced_encoder_options(opt->advopt, opt->advopt_count, &vi);
-
+
vorbis_encode_setup_init(&vi);
@@ -245,6 +283,17 @@
vorbis_block_init(&vd,&vb);
ogg_stream_init(&os, opt->serialno);
+ if (opt->with_skeleton)
+ ogg_stream_init(&so, opt->skeleton_serialno);
+
+ /* create the skeleton fishead packet and output it */
+ if (opt->with_skeleton) {
+ add_fishead_packet(&so);
+ if ((ret = flush_ogg_stream_to_file(&so, opt->out))) {
+ opt->error("Failed writing fishead packet to output stream\n");
+ goto cleanup;
+ }
+ }
/* Now, build the three header packets and send through to the stream
output stage (but defer actual file output until the main encode loop) */
@@ -253,14 +302,33 @@
ogg_packet header_main;
ogg_packet header_comments;
ogg_packet header_codebooks;
- int result;
/* Build the packets */
vorbis_analysis_headerout(&vd,opt->comments,
&header_main,&header_comments,&header_codebooks);
/* And stream them out */
+ /* output the vorbis bos first, then the fisbone packets */
ogg_stream_packetin(&os,&header_main);
+ while((result = ogg_stream_flush(&os, &og)))
+ {
+ if(!result) break;
+ ret = oe_write_page(&og, opt->out);
+ if(ret != og.header_len + og.body_len)
+ {
+ opt->error(_("Failed writing header to output stream\n"));
+ ret = 1;
+ goto cleanup; /* Bail and try to clean up stuff */
+ }
+ }
+
+ if (opt->with_skeleton) {
+ add_fisbone_packet(&so, opt);
+ if ((ret = flush_ogg_stream_to_file(&so, opt->out))) {
+ opt->error("Failed writing fisbone header packet to output stream\n");
+ goto cleanup;
+ }
+ }
ogg_stream_packetin(&os,&header_comments);
ogg_stream_packetin(&os,&header_codebooks);
@@ -277,6 +345,14 @@
}
}
+ if (opt->with_skeleton) {
+ add_eos_packet_to_stream(&so);
+ if ((ret = flush_ogg_stream_to_file(&so, opt->out))) {
+ opt->error("Failed writing skeleton eos packet to output stream\n");
+ goto cleanup;
+ }
+ }
+
eos = 0;
/* Main encode loop - continue until end of file */
@@ -342,7 +418,7 @@
}
else
bytes_written += ret;
-
+
if(ogg_page_eos(&og))
eos = 1;
}
@@ -376,7 +452,7 @@
static int spinpoint = 0;
double remain_time;
int minutes=0,seconds=0;
-
+
remain_time = time/((double)done/(double)total) - time;
minutes = ((int)remain_time)/60;
seconds = (int)(remain_time - (double)((int)remain_time/60)*60);
@@ -390,7 +466,7 @@
{
static char *spinner="|/-\\";
static int spinpoint =0;
-
+
fprintf(stderr, "\r");
fprintf(stderr, _("\tEncoding [%2dm%.2ds so far] %c "),
((int)time)/60, (int)(time - (double)((int)time/60)*60),
@@ -415,7 +491,7 @@
fprintf(stderr, _("\n\nDone encoding.\n"));
speed_ratio = (double)samples / (double)rate / time;
-
+
fprintf(stderr, _("\n\tFile length: %dm %04.1fs\n"),
(int)(samples/rate/60),
samples/rate -
Modified: trunk/vorbis-tools/oggenc/encode.h
===================================================================
--- trunk/vorbis-tools/oggenc/encode.h 2007-11-15 07:45:07 UTC (rev 14146)
+++ trunk/vorbis-tools/oggenc/encode.h 2007-11-15 08:33:06 UTC (rev 14147)
@@ -57,6 +57,7 @@
adv_opt *advopt;
int advopt_count;
int copy_comments;
+ int with_skeleton;
int quiet;
@@ -86,6 +87,7 @@
float scale;
unsigned int serial;
+ unsigned int skeleton_serial;
int fixedserial;
} oe_options;
@@ -93,13 +95,14 @@
{
vorbis_comment *comments;
unsigned int serialno;
+ unsigned int skeleton_serialno;
audio_read_func read_samples;
progress_func progress_update;
enc_end_func end_encode;
enc_start_func start_encode;
error_func error;
-
+
void *readdata;
long total_samples_per_channel;
@@ -109,6 +112,7 @@
int endianness;
int resamplefreq;
int copy_comments;
+ int with_skeleton;
/* Various bitrate/quality options */
int managed;
Modified: trunk/vorbis-tools/oggenc/oggenc.c
===================================================================
--- trunk/vorbis-tools/oggenc/oggenc.c 2007-11-15 07:45:07 UTC (rev 14146)
+++ trunk/vorbis-tools/oggenc/oggenc.c 2007-11-15 08:33:06 UTC (rev 14147)
@@ -37,6 +37,7 @@
struct option long_options[] = {
{"quiet",0,0,'Q'},
{"help",0,0,'h'},
+ {"skeleton",no_argument,NULL, 'k'},
{"comment",1,0,'c'},
{"artist",1,0,'a'},
{"album",1,0,'l'},
@@ -67,7 +68,7 @@
{"discard-comments", 0, 0, 0},
{NULL,0,0,0}
};
-
+
static char *generate_name_string(char *format, char *remove_list,
char *replace_list, char *artist, char *title, char *album,
char *track, char *date, char *genre);
@@ -81,7 +82,7 @@
{
/* Default values */
oe_options opt = {NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL,
- 0, NULL, 0, NULL, 0, NULL, 0, 1, 0, 0,16,44100,2, 0, NULL,
+ 0, NULL, 0, NULL, 0, NULL, 0, 1, 0, 0, 0,16,44100,2, 0, NULL,
DEFAULT_NAMEFMT_REMOVE, DEFAULT_NAMEFMT_REPLACE,
NULL, 0, -1,-1,-1,.3,-1,0, 0,0.f, 0, 0};
@@ -130,6 +131,7 @@
/* We randomly pick a serial number. This is then incremented for each file */
srand(time(NULL));
opt.serial = rand();
+ opt.skeleton_serial = opt.serial + numfiles;
}
for(i = 0; i < numfiles; i++)
@@ -149,12 +151,14 @@
/* Set various encoding defaults */
enc_opts.serialno = opt.serial++;
+ enc_opts.skeleton_serialno = opt.skeleton_serial++;
enc_opts.progress_update = update_statistics_full;
enc_opts.start_encode = start_encode_full;
enc_opts.end_encode = final_statistics;
enc_opts.error = encode_error;
enc_opts.comments = &vc;
enc_opts.copy_comments = opt.copy_comments;
+ enc_opts.with_skeleton = opt.with_skeleton;
/* OK, let's build the vorbis_comments structure */
build_comments(&vc, &opt, i, &artist, &album, &title, &track,
@@ -262,11 +266,12 @@
start = infiles[i];
end = strrchr(infiles[i], '.');
end = end?end:(start + strlen(infiles[i])+1);
-
+
+ char *extension = (opt.with_skeleton) ? ".ogg" : ".oga";
out_fn = malloc(end - start + 5);
strncpy(out_fn, start, end-start);
out_fn[end-start] = 0;
- strcat(out_fn, ".ogg");
+ strcat(out_fn, extension);
}
else {
fprintf(stderr, _("WARNING: No filename, defaulting to \"default.ogg\"\n"));
@@ -394,6 +399,7 @@
" -Q, --quiet Produce no output to stderr\n"
" -h, --help Print this help text\n"
" -v, --version Print the version number\n"
+ " -k, --skeleton Outputs ogg skeleton metadata\n"
" -r, --raw Raw mode. Input files are read directly as PCM data\n"
" -B, --raw-bits=n Set bits/sample for raw input. Default is 16\n"
" -C, --raw-chan=n Set number of channels for raw input. Default is 2\n"
@@ -591,13 +597,16 @@
int ret;
int option_index = 1;
- while((ret = getopt_long(argc, argv, "A:a:b:B:c:C:d:G:hl:m:M:n:N:o:P:q:QrR:s:t:vX:",
+ while((ret = getopt_long(argc, argv, "A:a:b:B:c:C:d:G:hl:m:M:n:N:o:P:q:QrR:s:t:vX:k",
long_options, &option_index)) != -1)
{
switch(ret)
{
case 0:
- if(!strcmp(long_options[option_index].name, "managed")) {
+ if(!strcmp(long_options[option_index].name, "skleton")) {
+ opt->with_skeleton = 1;
+ }
+ else if(!strcmp(long_options[option_index].name, "managed")) {
if(!opt->managed){
if(!opt->quiet)
fprintf(stderr,
@@ -841,6 +850,8 @@
fprintf(stderr, _("WARNING: Invalid sample rate specified, assuming 44100.\n"));
}
break;
+ case 'k':
+ opt->with_skeleton = 1;
case '?':
fprintf(stderr, _("WARNING: Unknown option specified, ignoring->\n"));
break;
Added: trunk/vorbis-tools/oggenc/skeleton.c
===================================================================
--- trunk/vorbis-tools/oggenc/skeleton.c (rev 0)
+++ trunk/vorbis-tools/oggenc/skeleton.c 2007-11-15 08:33:06 UTC (rev 14147)
@@ -0,0 +1,134 @@
+/*
+ * skeleton.c
+ * author: Tahseen Mohammad
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <ogg/ogg.h>
+
+#include "skeleton.h"
+
+int add_message_header_field(fisbone_packet *fp,
+ char *header_key,
+ char *header_value) {
+
+ /* size of both key and value + ': ' + CRLF */
+ int this_message_size = strlen(header_key) + strlen(header_value) + 4;
+ if (fp->message_header_fields == NULL) {
+ fp->message_header_fields = _ogg_calloc(this_message_size, sizeof(char));
+ } else {
+ int new_size = (fp->current_header_size + this_message_size) * sizeof(char);
+ fp->message_header_fields = _ogg_realloc(fp->message_header_fields, new_size);
+ }
+ snprintf(fp->message_header_fields + fp->current_header_size,
+ this_message_size+1,
+ "%s: %s\r\n",
+ header_key,
+ header_value);
+ fp->current_header_size += this_message_size;
+
+ return 0;
+}
+
+/* create a ogg_packet from a fishead_packet structure */
+ogg_packet ogg_from_fishead(fishead_packet *fp) {
+
+ ogg_packet op;
+
+ memset(&op, 0, sizeof(op));
+ op.packet = _ogg_calloc(FISHEAD_SIZE, sizeof(unsigned char));
+ memset(op.packet, 0, FISHEAD_SIZE);
+
+ 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)fp->ptime_n; /* presentationtime numerator */
+ *((ogg_int64_t*)(op.packet+20)) = (ogg_int64_t)fp->ptime_d; /* presentationtime denominator */
+ *((ogg_int64_t*)(op.packet+28)) = (ogg_int64_t)fp->btime_n; /* basetime numerator */
+ *((ogg_int64_t*)(op.packet+36)) = (ogg_int64_t)fp->btime_d; /* basetime denominator */
+ /* TODO: 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 = FISHEAD_SIZE; /* length of the packet in bytes */
+
+ return op;
+}
+
+/* create a ogg_packet from a fisbone_packet structure.
+ * call this method after the fisbone_packet is filled and all message header fields are added
+ * by calling add_message_header_field method.
+ */
+ogg_packet ogg_from_fisbone(fisbone_packet *fp) {
+
+ ogg_packet op;
+ int packet_size = FISBONE_SIZE + fp->current_header_size;
+
+ memset (&op, 0, sizeof (op));
+ op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
+ memset (op.packet, 0, packet_size);
+ 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)) = fp->serial_no; /* serialno of the respective stream */
+ *((ogg_uint32_t*)(op.packet+16)) = fp->nr_header_packet; /* number of header packets */
+ *((ogg_int64_t*)(op.packet+20)) = fp->granule_rate_n; /* granulrate numerator */
+ *((ogg_int64_t*)(op.packet+28)) = fp->granule_rate_d; /* granulrate denominator */
+ *((ogg_int64_t*)(op.packet+36)) = fp->start_granule; /* start granule */
+ *((ogg_uint32_t*)(op.packet+44)) = fp->preroll; /* preroll, for theora its 0 */
+ *(op.packet+48) = fp->granule_shift; /* granule shift */
+ memcpy((op.packet+FISBONE_SIZE), fp->message_header_fields, fp->current_header_size);
+
+ op.b_o_s = 0;
+ op.e_o_s = 0;
+ op.bytes = packet_size; /* size of the packet in bytes */
+
+ return op;
+}
+
+int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp) {
+
+ ogg_packet op;
+
+ op = ogg_from_fishead(fp);
+ ogg_stream_packetin(os, &op);
+ _ogg_free(op.packet);
+
+ return 0;
+}
+
+int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp) {
+
+ ogg_packet op;
+
+ op = ogg_from_fisbone(fp);
+ ogg_stream_packetin(os, &op);
+ _ogg_free(op.packet);
+
+ return 0;
+}
+
+int add_eos_packet_to_stream(ogg_stream_state *os) {
+
+ ogg_packet op;
+
+ memset (&op, 0, sizeof(op));
+ op.e_o_s = 1;
+ ogg_stream_packetin(os, &op);
+}
+
+int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) {
+
+ ogg_page og;
+ int result, ret;
+
+ while((result = ogg_stream_flush(os, &og)))
+ {
+ if(!result) break;
+ result = oe_write_page(&og, out);
+ if(result != og.header_len + og.body_len)
+ return 1;
+ }
+}
\ No newline at end of file
Added: trunk/vorbis-tools/oggenc/skeleton.h
===================================================================
--- trunk/vorbis-tools/oggenc/skeleton.h (rev 0)
+++ trunk/vorbis-tools/oggenc/skeleton.h 2007-11-15 08:33:06 UTC (rev 14147)
@@ -0,0 +1,63 @@
+/*
+ * skeleton.h
+ * author: Tahseen Mohammad
+ */
+
+#ifndef _SKELETON_H
+#define _SKELETON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ogg/ogg.h>
+
+#define SKELETON_VERSION_MAJOR 3
+#define SKELETON_VERSION_MINOR 0
+#define FISHEAD_IDENTIFIER "fishead\0"
+#define FISBONE_IDENTIFIER "fisbone\0"
+#define FISHEAD_SIZE 64
+#define FISBONE_SIZE 52
+#define FISBONE_MESSAGE_HEADER_OFFSET 44
+
+/* fishead_packet holds a fishead header packet. */
+typedef struct {
+ /* Start time of the presentation.
+ * For a new stream presentationtime & basetime is same. */
+ ogg_int64_t ptime_n; /* presentation time numerator */
+ ogg_int64_t ptime_d; /* presentation time denominator */
+ ogg_int64_t btime_n; /* basetime numerator */
+ ogg_int64_t btime_d; /* basetime denominator */
+ /* will holds the time of origin of the stream, a 20 bit field. */
+ unsigned char UTC[20];
+} fishead_packet;
+
+/* fisbone_packet holds a fisbone header packet. */
+typedef struct {
+ ogg_uint32_t serial_no; /* serial no of the corresponding stream */
+ ogg_uint32_t nr_header_packet; /* number of header packets */
+ /* granule rate is the temporal resolution of the logical bitstream */
+ ogg_int64_t granule_rate_n; /* granule rate numerator */
+ ogg_int64_t granule_rate_d; /* granule rate denominator */
+ ogg_int64_t start_granule; /* start granule value */
+ ogg_uint32_t preroll; /* preroll */
+ unsigned char granule_shift; // a 8-bit field /* 1 byte value holding the granule shift */
+ char *message_header_fields; /* holds all the message header fields */
+ /* current total size of the message header fields, for realloc purpose, initially zero */
+ ogg_uint32_t current_header_size;
+} fisbone_packet;
+
+extern int add_message_header_field(fisbone_packet *fp, char *header_key, char *header_value);
+/* remember to deallocate the returned ogg_packet properly */
+extern ogg_packet ogg_from_fishead(fishead_packet *fp);
+extern ogg_packet ogg_from_fisbone(fisbone_packet *fp);
+extern int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp);
+extern int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp);
+extern int add_eos_packet_to_stream(ogg_stream_state *os);
+extern int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SKELETON_H */
\ No newline at end of file
More information about the commits
mailing list