[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