[xiph-commits] r11759 - trunk/speex/src
jm at svn.xiph.org
jm at svn.xiph.org
Thu Aug 10 22:55:26 PDT 2006
Author: jm
Date: 2006-08-10 22:55:22 -0700 (Thu, 10 Aug 2006)
New Revision: 11759
Added:
trunk/speex/src/skeleton.c
trunk/speex/src/skeleton.h
Modified:
trunk/speex/src/Makefile.am
trunk/speex/src/speexenc.c
Log:
Skeleton support for Speexenc (by Tahseen Mohammad)
Modified: trunk/speex/src/Makefile.am
===================================================================
--- trunk/speex/src/Makefile.am 2006-08-10 15:03:56 UTC (rev 11758)
+++ trunk/speex/src/Makefile.am 2006-08-11 05:55:22 UTC (rev 11759)
@@ -10,14 +10,14 @@
mandir = $(prefix)/share/man
man_MANS = speexenc.1 speexdec.1
-EXTRA_DIST = $(man_MANS) getopt_win.h getopt.c getopt1.c wave_out.c wave_out.h
+EXTRA_DIST = $(man_MANS) getopt_win.h getopt.c getopt1.c wave_out.c wave_out.h skeleton.h
include_HEADERS =
noinst_HEADERS = wav_io.h
bin_PROGRAMS = speexenc speexdec
-speexenc_SOURCES = speexenc.c wav_io.c
+speexenc_SOURCES = speexenc.c wav_io.c skeleton.c
speexenc_LDADD = $(top_builddir)/libspeex/libspeex.la \
$(OGG_LIBS)
Added: trunk/speex/src/skeleton.c
===================================================================
--- trunk/speex/src/skeleton.c 2006-08-10 15:03:56 UTC (rev 11758)
+++ trunk/speex/src/skeleton.c 2006-08-11 05:55:22 UTC (rev 11759)
@@ -0,0 +1,188 @@
+/*
+ * skeleton.c
+ * author: Tahseen Mohammad
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <ogg/ogg.h>
+
+#include "skeleton.h"
+
+/* write an ogg_page to a file pointer */
+int write_ogg_page_to_file(ogg_page *og, FILE *out) {
+ int written;
+
+ written = fwrite(og->header,1, og->header_len, out);
+ written += fwrite(og->body,1, og->body_len, out);
+
+ return written;
+}
+
+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;
+}
+
+/* fills up a fishead_packet from a fishead ogg_packet of a skeleton bistream */
+fishead_packet fishead_from_ogg(ogg_packet *op) {
+
+ fishead_packet fp;
+
+ if (memcmp(op->packet, FISHEAD_IDENTIFIER, 8))
+ ; /* invalid packet what do we do? */
+
+ fp.version_major = *((ogg_uint16_t*)(op->packet+8)); /* version major */
+ fp.version_minor = *((ogg_uint16_t*)(op->packet+10)); /* version minor */
+ fp.ptime_n = *((ogg_int64_t*)(op->packet+12)); /* presentationtime numerator */
+ fp.ptime_d = *((ogg_int64_t*)(op->packet+20)); /* presentationtime denominator */
+ fp.btime_n = *((ogg_int64_t*)(op->packet+28)); /* basetime numerator */
+ fp.btime_d = *((ogg_int64_t*)(op->packet+36)); /* basetime denominator */
+ memcpy(fp.UTC, op->packet+44, 20);
+
+ return fp;
+}
+
+/* fills up a fisbone_packet from a fisbone ogg_packet of a skeleton bitstream */
+fisbone_packet fisbone_from_ogg(ogg_packet *op) {
+
+ fisbone_packet fp;
+
+ if (memcmp(op->packet, FISBONE_IDENTIFIER, 8))
+ ; /* invalid value, what do we do? */
+ fp.serial_no = *((ogg_uint32_t*)(op->packet+12)); /* serialno of the stream represented by this fisbone packet */
+ fp.nr_header_packet = *((ogg_uint32_t*)(op->packet+16)); /* number of header packets */
+ fp.granule_rate_n = *((ogg_int64_t*)(op->packet+20)); /* granulrate numerator */
+ fp.granule_rate_d = *((ogg_int64_t*)(op->packet+28)); /* granulrate denominator */
+ fp.start_granule = *((ogg_int64_t*)(op->packet+36)); /* start granule */
+ fp.preroll = *((ogg_uint32_t*)(op->packet+44)); /* preroll, for theora its 0 */
+ fp.granule_shift = *(op->packet+48); /* granule shift */
+ fp.current_header_size = op->bytes - FISBONE_SIZE;
+ fp.message_header_fields = _ogg_calloc(fp.current_header_size+1, sizeof(char));
+ memcpy(fp.message_header_fields, op->packet+FISBONE_SIZE, fp.current_header_size);
+
+ return fp;
+}
+
+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);
+
+ return 0;
+}
+
+int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) {
+
+ ogg_page og;
+ int result;
+
+ while((result = ogg_stream_flush(os, &og)))
+ {
+ if(!result) break;
+ result = write_ogg_page_to_file(&og, out);
+ if(result != og.header_len + og.body_len)
+ return 1;
+ }
+
+ return 0;
+}
Added: trunk/speex/src/skeleton.h
===================================================================
--- trunk/speex/src/skeleton.h 2006-08-10 15:03:56 UTC (rev 11758)
+++ trunk/speex/src/skeleton.h 2006-08-11 05:55:22 UTC (rev 11759)
@@ -0,0 +1,74 @@
+/*
+ * 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 {
+ ogg_uint16_t version_major; /* skeleton version major */
+ ogg_uint16_t version_minor; /* skeleton version minor */
+ /* 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; /* 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 write_ogg_page_to_file(ogg_page *og, FILE *out);
+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 fishead_packet fishead_from_ogg(ogg_packet *op);
+extern fisbone_packet fisbone_from_ogg(ogg_packet *op);
+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 */
+
+
+
+
+
+
Modified: trunk/speex/src/speexenc.c
===================================================================
--- trunk/speex/src/speexenc.c 2006-08-10 15:03:56 UTC (rev 11758)
+++ trunk/speex/src/speexenc.c 2006-08-11 05:55:22 UTC (rev 11759)
@@ -59,7 +59,9 @@
#include <fcntl.h>
#endif
+#include "skeleton.h"
+
void comment_init(char **comments, int* length, char *vendor_string);
void comment_add(char **comments, int* length, char *tag, char *val);
@@ -144,6 +146,40 @@
return nb_read;
}
+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, spx_int32_t serialno, SpeexHeader *header) {
+
+ fisbone_packet fp;
+
+ memset(&fp, 0, sizeof(fp));
+ fp.serial_no = serialno;
+ fp.nr_header_packet = 2 + header->extra_headers;
+ fp.granule_rate_n = header->rate;
+ fp.granule_rate_d = 1;
+ fp.start_granule = 0;
+ fp.preroll = 3;
+ fp.granule_shift = 0;
+
+ add_message_header_field(&fp, "Content-Type", "audio/x-speex");
+
+ add_fisbone_to_stream(os, &fp);
+}
+
void version()
{
printf ("speexenc (Speex encoder) version " SPEEX_VERSION " (compiled " __DATE__ ")\n");
@@ -186,6 +222,7 @@
printf (" --nframes n Number of frames per Ogg packet (1-10), default 1\n");
printf (" --denoise Denoise the input before encoding\n");
printf (" --agc Apply adaptive gain control (AGC) before encoding\n");
+ printf (" --skeleton Outputs ogg skeleton metadata (may cause incompatibilities)\n");
printf (" --comment Add the given string as an extra comment. This may be\n");
printf (" used multiple times\n");
printf (" --author Author of this track\n");
@@ -229,6 +266,7 @@
void *st;
SpeexBits bits;
char cbits[MAX_FRAME_BYTES];
+ int with_skeleton = 0;
struct option long_options[] =
{
{"wideband", no_argument, NULL, 0},
@@ -245,6 +283,7 @@
{"comp", required_argument, NULL, 0},
{"denoise", no_argument, NULL, 0},
{"agc", no_argument, NULL, 0},
+ {"skeleton",no_argument,NULL, 0},
{"help", no_argument, NULL, 0},
{"quiet", no_argument, NULL, 0},
{"le", no_argument, NULL, 0},
@@ -268,6 +307,7 @@
float vbr_quality=-1;
int lsb=1;
ogg_stream_state os;
+ ogg_stream_state so; /* ogg stream for skeleton bitstream */
ogg_page og;
ogg_packet op;
int bytes_written=0, ret, result;
@@ -359,6 +399,9 @@
} else if (strcmp(long_options[option_index].name,"agc")==0)
{
agc_enabled=1;
+ } else if (strcmp(long_options[option_index].name,"skeleton")==0)
+ {
+ with_skeleton=1;
} else if (strcmp(long_options[option_index].name,"help")==0)
{
usage();
@@ -451,6 +494,11 @@
fprintf(stderr,"Error: stream init failed\n");
exit(1);
}
+ if (with_skeleton && ogg_stream_init(&so, rand())==-1)
+ {
+ fprintf(stderr,"Error: stream init failed\n");
+ exit(1);
+ }
if (strcmp(inFile, "-")==0)
{
@@ -627,6 +675,9 @@
{
fprintf (stderr, "Warning: --vad is already implied by --vbr or --abr\n");
}
+ if (with_skeleton) {
+ fprintf (stderr, "Warning: Enabling skeleton output may cause some decoders to fail.\n");
+ }
if (abr_enabled)
{
@@ -643,6 +694,17 @@
lookahead += frame_size;
}
+ /* first packet should be the skeleton header. */
+
+ if (with_skeleton) {
+ add_fishead_packet(&so);
+ if ((ret = flush_ogg_stream_to_file(&so, fout))) {
+ fprintf (stderr,"Error: failed skeleton (fishead) header to output stream\n");
+ exit(1);
+ } else
+ bytes_written += ret;
+ }
+
/*Write header*/
{
int packet_size;
@@ -655,14 +717,6 @@
ogg_stream_packetin(&os, &op);
free(op.packet);
- op.packet = (unsigned char *)comments;
- op.bytes = comments_length;
- op.b_o_s = 0;
- op.e_o_s = 0;
- op.granulepos = 0;
- op.packetno = 1;
- ogg_stream_packetin(&os, &op);
-
while((result = ogg_stream_flush(&os, &og)))
{
if(!result) break;
@@ -675,10 +729,53 @@
else
bytes_written += ret;
}
+
+ op.packet = (unsigned char *)comments;
+ op.bytes = comments_length;
+ op.b_o_s = 0;
+ op.e_o_s = 0;
+ op.granulepos = 0;
+ op.packetno = 1;
+ ogg_stream_packetin(&os, &op);
}
+ /* fisbone packet should be write after all bos pages */
+ if (with_skeleton) {
+ add_fisbone_packet(&so, os.serialno, &header);
+ if ((ret = flush_ogg_stream_to_file(&so, fout))) {
+ fprintf (stderr,"Error: failed writing skeleton (fisbone )header to output stream\n");
+ exit(1);
+ } else
+ bytes_written += ret;
+ }
+
+ /* writing the rest of the speex header packets */
+ while((result = ogg_stream_flush(&os, &og)))
+ {
+ if(!result) break;
+ ret = oe_write_page(&og, fout);
+ if(ret != og.header_len + og.body_len)
+ {
+ fprintf (stderr,"Error: failed writing header to output stream\n");
+ exit(1);
+ }
+ else
+ bytes_written += ret;
+ }
+
free(comments);
+ /* write the skeleton eos packet */
+ if (with_skeleton) {
+ add_eos_packet_to_stream(&so);
+ if ((ret = flush_ogg_stream_to_file(&so, fout))) {
+ fprintf (stderr,"Error: failed writing skeleton header to output stream\n");
+ exit(1);
+ } else
+ bytes_written += ret;
+ }
+
+
speex_bits_init(&bits);
if (!wave_input)
More information about the commits
mailing list