diff --git a/ChangeLog b/ChangeLog index 209630bbd..4fe330773 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2003-05-11 Moritz Bunkus + * Fixed a bug with the AC3 timecode calculation (patch by Peter + Niemayer ). + + * Support for reading DTS files & putting them into Matroska + (main patch by Peter Niemayer , a few things + by me). + * Released v0.3.2. * Fixed the huge memory need if reading from AVI files (introduced diff --git a/Makefile.am b/Makefile.am index 5130c216e..708c30e16 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,11 +8,13 @@ bin_PROGRAMS = mkvmerge mkvinfo mkvmerge_SOURCES = mkvmerge.cpp mkvmerge.h \ ac3_common.cpp ac3_common.h \ + dts_common.cpp dts_common.h \ cluster_helper.cpp cluster_helper.h \ common.cpp common.h \ iso639.cpp iso639.h \ mp3_common.cpp mp3_common.h \ p_ac3.cpp p_ac3.h \ + p_dts.cpp p_dts.h \ p_mp3.cpp p_mp3.h \ p_pcm.cpp p_pcm.h \ p_textsubs.cpp p_textsubs.h \ @@ -21,6 +23,7 @@ mkvmerge_SOURCES = mkvmerge.cpp mkvmerge.h \ pr_generic.h pr_generic.cpp \ r_ac3.cpp r_ac3.h \ r_avi.cpp r_avi.h \ + r_dts.cpp r_dts.h \ r_matroska.cpp r_matroska.h \ r_mp3.cpp r_mp3.h \ r_srt.cpp r_srt.h \ diff --git a/common.h b/common.h index 23a9e0e56..f42453e89 100644 --- a/common.h +++ b/common.h @@ -13,7 +13,7 @@ /*! \file - \version \$Id: common.h,v 1.21 2003/05/11 15:52:54 mosu Exp $ + \version \$Id: common.h,v 1.22 2003/05/15 08:58:52 mosu Exp $ \brief definitions used in all programs, helper functions \author Moritz Bunkus */ @@ -63,6 +63,7 @@ #define TYPEMICRODVD 8 #define TYPEVOBSUB 9 #define TYPEMATROSKA 10 +#define TYPEDTS 11 #define FOURCC(a, b, c, d) (unsigned long)((((unsigned char)a) << 24) + \ (((unsigned char)b) << 16) + \ diff --git a/dts_common.cpp b/dts_common.cpp new file mode 100644 index 000000000..d9f4ba103 --- /dev/null +++ b/dts_common.cpp @@ -0,0 +1,115 @@ +/* + mkvmerge -- utility for splicing together matroska files + from component media subtypes + + dts_common.cpp + + Written by Moritz Bunkus + + Distributed under the GPL + see the file COPYING for details + or visit http://www.gnu.org/copyleft/gpl.html +*/ + +/*! + \file + \version \$Id: dts_common.cpp,v 1.1 2003/05/15 08:58:52 mosu Exp $ + \brief helper function for DTS data + \author Moritz Bunkus +*/ + +#include +#include + +#include "dts_common.h" + +static int DTS_SAMPLEFREQS[16] = +{ + 0, 8000, 16000, 32000, 64000, 128000, 11025, 22050, + 44100, 88200, 176400, 12000, 24000, 48000, 96000, 192000 +}; + +static int DTS_BITRATES[30] = +{ + 32000, 56000, 64000, 96000, 112000, 128000, 192000, + 224000, 256000, 320000, 384000, 448000, 512000, 576000, + 640000, 768000, 896000, 1024000, 1152000, 1280000, 1344000, + 1408000, 1411200, 1472000, 1536000, 1920000, 2048000, 3072000, + 3840000, 4096000 +}; + + +int find_dts_header(unsigned char *buf, int size, dts_header_t *dts_header) { + // dts_header_t header; + int i; + unsigned char * indata_ptr; + int ftype; + int surp; + int unknown_bit; + int fsize; + int amode; + int nblks; + int sfreq; + int rate; + + for (i = 0; i < (size - 9); i++) { + if ((buf[i] != 0x7f) || (buf[i + 1] != 0xfe) || (buf[i + 2] != 0x80) || + (buf[i + 3] != 0x01)) + continue; + + indata_ptr = buf + i; + + ftype = indata_ptr[4] >> 7; + + surp = (indata_ptr[4] >> 2) & 0x1f; + surp = (surp + 1) % 32; + //fprintf(stderr,"surp = %d\n", surp); + + unknown_bit = (indata_ptr[4] >> 1) & 0x01; + + nblks = (indata_ptr[4] & 0x01) << 6 | (indata_ptr[5] >> 2); + nblks = nblks + 1; + + fsize = (indata_ptr[5] & 0x03) << 12 | (indata_ptr[6] << 4) | + (indata_ptr[7] >> 4); + fsize = fsize + 1; + + amode = (indata_ptr[7] & 0x0f) << 2 | (indata_ptr[8] >> 6); + sfreq = (indata_ptr[8] >> 2) & 0x0f; + rate = (indata_ptr[8] & 0x03) << 3 | ((indata_ptr[9] >> 5) & 0x07); + + if (ftype != 1) { + // "DTS: Termination frames not handled, REPORT BUG\n"; + return -1; + } + + if (sfreq != 13) { + // "DTS: Only 48kHz supported, REPORT BUG\n"; + return -1; + } + + if ((fsize > 8192) || (fsize < 96)) { + // "DTS: fsize: %d invalid, REPORT BUG\n", fsize; + return -1; + } + + if ((nblks != 8) && + (nblks != 16) && + (nblks != 32) && + (nblks != 64) && + (nblks != 128) && + (ftype == 1)) { + // "DTS: nblks %d not valid for normal frame, REPORT BUG\n", nblks; + return -1; + } + + // header ok + dts_header->sample_rate = DTS_SAMPLEFREQS[sfreq]; + dts_header->bit_rate = DTS_BITRATES[rate]; + dts_header->bytes = fsize; + + return i; + } + + return -1; +} diff --git a/dts_common.h b/dts_common.h new file mode 100644 index 000000000..5c8fdc81c --- /dev/null +++ b/dts_common.h @@ -0,0 +1,50 @@ +/* + mkvmerge -- utility for splicing together matroska files + from component media subtypes + + dts_common.h + + Written by Moritz Bunkus + + Distributed under the GPL + see the file COPYING for details + or visit http://www.gnu.org/copyleft/gpl.html +*/ + +/*! + \file + \version \$Id: dts_common.h,v 1.1 2003/05/15 08:58:52 mosu Exp $ + \brief definitions and helper functions for DTS data + \author Moritz Bunkus +*/ + +#ifndef __DTSCOMMON_H +#define __DTSCOMMON_H + +#define A52_CHANNEL 0 +#define A52_MONO 1 +#define A52_STEREO 2 +#define A52_3F 3 +#define A52_2F1R 4 +#define A52_3F1R 5 +#define A52_2F2R 6 +#define A52_3F2R 7 +#define A52_CHANNEL1 8 +#define A52_CHANNEL2 9 +#define A52_DOLBY 10 +#define A52_CHANNEL_MASK 15 + +#define A52_LFE 16 + +typedef struct { + int sample_rate; + int bit_rate; + // int channels; + int flags; + int bytes; +} dts_header_t; + +int find_dts_header(unsigned char *buf, int size, dts_header_t *dts_header); + +#endif // __DTSCOMMON_H + diff --git a/matroska.h b/matroska.h index 5be42289d..55e00b8b9 100644 --- a/matroska.h +++ b/matroska.h @@ -13,7 +13,7 @@ /*! \file - \version \$Id: matroska.h,v 1.9 2003/04/30 11:31:47 mosu Exp $ + \version \$Id: matroska.h,v 1.10 2003/05/15 08:58:52 mosu Exp $ \brief Definitions for the various Codec IDs \author Moritz Bunkus */ @@ -25,6 +25,7 @@ #define MKV_A_MP3 "A_MPEG/L3" #define MKV_A_AC3 "A_AC3" +#define MKV_A_DTS "A_DTS" #define MKV_A_PCM "A_PCM/INT/LIT" #define MKV_A_VORBIS "A_VORBIS" #define MKV_A_ACM "A_MS/ACM" diff --git a/mkvmerge.cpp b/mkvmerge.cpp index 8ed6cff04..c22c979f2 100644 --- a/mkvmerge.cpp +++ b/mkvmerge.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: mkvmerge.cpp,v 1.62 2003/05/11 15:48:57 mosu Exp $ + \version \$Id: mkvmerge.cpp,v 1.63 2003/05/15 08:58:52 mosu Exp $ \brief command line parameter parsing, looping, output handling \author Moritz Bunkus */ @@ -64,6 +64,7 @@ #include "common.h" #include "iso639.h" #include "r_ac3.h" +#include "r_dts.h" #include "r_avi.h" #include "r_mp3.h" #include "r_wav.h" @@ -146,6 +147,7 @@ file_type_t file_types[] = // {"idx", TYPEVOBSUB, "VobSub subtitles"}, {"mp3", TYPEMP3, "MPEG1 layer III audio (CBR and VBR/ABR)"}, {"ac3", TYPEAC3, "A/52 (aka AC3)"}, + {"dts", TYPEDTS, "DTS (Digital Theater System)"}, {"output modules:", -1, ""}, #ifdef HAVE_OGGVORBIS {" ", -1, "Vorbis audio"}, @@ -156,6 +158,7 @@ file_type_t file_types[] = // {" ", -1, "VobSub subtitles"}, {" ", -1, "MP3 audio"}, {" ", -1, "AC3 audio"}, + {" ", -1, "DTS audio"}, {NULL, -1, NULL}}; static void usage(void) { @@ -249,6 +252,8 @@ static int get_type(char *filename) { type = TYPEMP3; else if (ac3_reader_c::probe_file(f, size)) type = TYPEAC3; + else if (dts_reader_c::probe_file(f, size)) + type = TYPEDTS; // else if (microdvd_reader_c::probe_file(f, size)) // type = TYPEMICRODVD; // else if (vobsub_reader_c::probe_file(f, size)) @@ -818,6 +823,13 @@ static void parse_args(int argc, char **argv) { "AC3 files.\n"); file->reader = new ac3_reader_c(&ti); break; + case TYPEDTS: + if ((ti.atracks != NULL) || (ti.vtracks != NULL) || + (ti.stracks != NULL)) + fprintf(stderr, "Warning: -a/-A/-d/-D/-t/-T are ignored for " \ + "DTS files.\n"); + file->reader = new dts_reader_c(&ti); + break; // case TYPECHAPTERS: // if (chapters != NULL) { // fprintf(stderr, "Error: only one chapter file allowed.\n"); diff --git a/p_ac3.cpp b/p_ac3.cpp index 520911bb4..51375ceb6 100644 --- a/p_ac3.cpp +++ b/p_ac3.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: p_ac3.cpp,v 1.22 2003/05/11 12:41:53 mosu Exp $ + \version \$Id: p_ac3.cpp,v 1.23 2003/05/15 08:58:52 mosu Exp $ \brief AC3 output module \author Moritz Bunkus */ @@ -165,7 +165,7 @@ int ac3_packetizer_c::process(unsigned char *buf, int size, add_to_buffer(buf, size); while ((packet = get_ac3_packet(&header, &ac3header)) != NULL) { - if (timecode != -1) + if (timecode == -1) my_timecode = (int64_t)(1000.0 * packetno * 1536 * ti->async.linear / samples_per_sec); diff --git a/p_dts.cpp b/p_dts.cpp new file mode 100644 index 000000000..fd53265a1 --- /dev/null +++ b/p_dts.cpp @@ -0,0 +1,180 @@ +/* + mkvmerge -- utility for splicing together matroska files + from component media subtypes + + p_dts.h + + Written by Moritz Bunkus + + Distributed under the GPL + see the file COPYING for details + or visit http://www.gnu.org/copyleft/gpl.html +*/ + +/*! + \file + \version \$Id: p_dts.cpp,v 1.1 2003/05/15 08:58:52 mosu Exp $ + \brief DTS output module + \author Moritz Bunkus +*/ + +#include +#include +#include +#include + +#include "pr_generic.h" +#include "dts_common.h" +#include "p_dts.h" +#include "matroska.h" + +using namespace LIBMATROSKA_NAMESPACE; + +dts_packetizer_c::dts_packetizer_c(generic_reader_c *nreader, + unsigned long nsamples_per_sec, + track_info_t *nti) + throw (error_c): generic_packetizer_c(nreader, nti) { + packetno = 0; + bytes_output = 0; + packet_buffer = NULL; + buffer_size = 0; + samples_per_sec = nsamples_per_sec; + + set_track_type(track_audio); + duplicate_data_on_add(false); +} + +dts_packetizer_c::~dts_packetizer_c() { + safefree(packet_buffer); +} + +void dts_packetizer_c::add_to_buffer(unsigned char *buf, int size) { + unsigned char *new_buffer; + + new_buffer = (unsigned char *)saferealloc(packet_buffer, buffer_size + size); + + memcpy(new_buffer + buffer_size, buf, size); + packet_buffer = new_buffer; + buffer_size += size; +} + +int dts_packetizer_c::dts_packet_available() { + int pos; + dts_header_t dtsheader; + + if (packet_buffer == NULL) + return 0; + pos = find_dts_header(packet_buffer, buffer_size, &dtsheader); + if (pos < 0) + return 0; + + return 1; +} + +void dts_packetizer_c::remove_dts_packet(int pos, int framesize) { + int new_size; + unsigned char *temp_buf; + + new_size = buffer_size - (pos + framesize); + if (new_size != 0) + temp_buf = (unsigned char *)safememdup(&packet_buffer[pos + framesize], + new_size); + else + temp_buf = NULL; + safefree(packet_buffer); + packet_buffer = temp_buf; + buffer_size = new_size; +} + +unsigned char *dts_packetizer_c::get_dts_packet(unsigned long *header, + dts_header_t *dtsheader) { + int pos; + unsigned char *buf; + double pims; + + if (packet_buffer == NULL) + return 0; + pos = find_dts_header(packet_buffer, buffer_size, dtsheader); + if (pos < 0) + return 0; + if ((pos + dtsheader->bytes) > buffer_size) + return 0; + + pims = ((double)((dtsheader->bytes + 511) & (~511))) * 1000.0 / + ((double)dtsheader->bit_rate / 8.0); + + if (ti->async.displacement < 0) { + /* + * DTS audio synchronization. displacement < 0 means skipping an + * appropriate number of packets at the beginning. + */ + ti->async.displacement += (int)pims; + if (ti->async.displacement > -(pims / 2)) + ti->async.displacement = 0; + + remove_dts_packet(pos, dtsheader->bytes); + + return 0; + } + + if (verbose && (pos > 1)) + fprintf(stdout, "dts_packetizer: skipping %d bytes (no valid DTS header " + "found). This might make audio/video go out of sync, but this " + "stream is damaged.\n", pos); + buf = (unsigned char *)safememdup(packet_buffer + pos, dtsheader->bytes); + + if (ti->async.displacement > 0) { + /* + * DTS audio synchronization. displacement > 0 is solved by duplicating + * the very first DTS packet as often as necessary. I cannot create + * a packet with total silence because I don't know how, and simply + * settings the packet's values to 0 does not work as the DTS header + * contains a CRC of its data. + */ + ti->async.displacement -= (int)pims; + if (ti->async.displacement < (pims / 2)) + ti->async.displacement = 0; + + return buf; + } + + remove_dts_packet(pos, dtsheader->bytes); + + return buf; +} + +void dts_packetizer_c::set_headers() { + set_codec_id(MKV_A_DTS); + set_audio_sampling_freq((float)samples_per_sec); + set_audio_channels(6); + + generic_packetizer_c::set_headers(); +} + +int dts_packetizer_c::process(unsigned char *buf, int size, + int64_t timecode, int64_t, int64_t, int64_t) { + unsigned char *packet; + unsigned long header; + dts_header_t dtsheader; + int64_t my_timecode; + double pims; + + if (timecode != -1) + my_timecode = timecode; + + add_to_buffer(buf, size); + while ((packet = get_dts_packet(&header, &dtsheader)) != NULL) { + + if (timecode == -1) { + pims = ((double)((dtsheader.bytes + 511) & (~511))) * 1000.0 / + ((double)dtsheader.bit_rate / 8.0); + my_timecode = (int64_t)(pims * (double)packetno); + } + + add_packet(packet, dtsheader.bytes, my_timecode, (int64_t)pims); + packetno++; + } + + return EMOREDATA; +} + diff --git a/p_dts.h b/p_dts.h new file mode 100644 index 000000000..4db6aefc2 --- /dev/null +++ b/p_dts.h @@ -0,0 +1,53 @@ +/* + mkvmerge -- utility for splicing together matroska files + from component media subtypes + + p_dts.h + + Written by Moritz Bunkus + + Distributed under the GPL + see the file COPYING for details + or visit http://www.gnu.org/copyleft/gpl.html +*/ + +/*! + \file + \version \$Id: p_dts.h,v 1.1 2003/05/15 08:58:52 mosu Exp $ + \brief class definition for the DTS output module + \author Moritz Bunkus +*/ + +#ifndef __P_DTS_H +#define __P_DTS_H + +#include "common.h" +#include "pr_generic.h" +#include "dts_common.h" + +class dts_packetizer_c: public generic_packetizer_c { +private: + int64_t bytes_output, packetno; + unsigned long samples_per_sec; + int buffer_size; + unsigned char *packet_buffer; + +public: + dts_packetizer_c(generic_reader_c *nreader, unsigned long nsamples_per_sec, + track_info_t *nti) throw (error_c); + virtual ~dts_packetizer_c(); + + virtual int process(unsigned char *buf, int size, int64_t timecode = -1, + int64_t length = -1, int64_t bref = -1, + int64_t fref = -1); + virtual void set_headers(); + +private: + virtual void add_to_buffer(unsigned char *buf, int size); + virtual unsigned char *get_dts_packet(unsigned long *header, + dts_header_t *dtsheader); + virtual int dts_packet_available(); + virtual void remove_dts_packet(int pos, int framesize); +}; + +#endif // __P_DTS_H diff --git a/r_dts.cpp b/r_dts.cpp new file mode 100644 index 000000000..a2aeec378 --- /dev/null +++ b/r_dts.cpp @@ -0,0 +1,124 @@ +/* + mkvmerge -- utility for splicing together matroska files + from component media subtypes + + r_dts.h + + Written by Moritz Bunkus + + Distributed under the GPL + see the file COPYING for details + or visit http://www.gnu.org/copyleft/gpl.html +*/ + +/*! + \file + \version \$Id: r_dts.cpp,v 1.1 2003/05/15 08:58:52 mosu Exp $ + \brief DTS demultiplexer module + \author Moritz Bunkus +*/ + +#include +#include +#include +#include + +// extern "C" { +// #include +// } + +#include "mkvmerge.h" +#include "common.h" +#include "error.h" +#include "r_dts.h" +#include "p_dts.h" + +int dts_reader_c::probe_file(FILE *file, int64_t size) { + char buf[4096]; + int pos; + dts_header_t dtsheader; + + if (size < 4096) + return 0; + if (fseek(file, 0, SEEK_SET) != 0) + return 0; + if (fread(buf, 1, 4096, file) != 4096) { + fseek(file, 0, SEEK_SET); + return 0; + } + fseek(file, 0, SEEK_SET); + + pos = find_dts_header((unsigned char *)buf, 4096, &dtsheader); + if (pos < 0) + return 0; + + return 1; +} + +dts_reader_c::dts_reader_c(track_info_t *nti) throw (error_c): + generic_reader_c(nti) { + int pos; + dts_header_t dtsheader; + + if ((file = fopen(ti->fname, "rb")) == NULL) + throw error_c("dts_reader: Could not open source file."); + if (fseek(file, 0, SEEK_END) != 0) + throw error_c("dts_reader: Could not seek to end of file."); + size = ftell(file); + if (fseek(file, 0, SEEK_SET) != 0) + throw error_c("dts_reader: Could not seek to beginning of file."); + chunk = (unsigned char *)safemalloc(4096); + if (fread(chunk, 1, 4096, file) != 4096) + throw error_c("dts_reader: Could not read 4096 bytes."); + if (fseek(file, 0, SEEK_SET) != 0) + throw error_c("dts_reader: Could not seek to beginning of file."); + pos = find_dts_header(chunk, 4096, &dtsheader); + if (pos < 0) + throw error_c("dts_reader: No valid DTS packet found in the first " \ + "4096 bytes.\n"); + bytes_processed = 0; + dtspacketizer = new dts_packetizer_c(this, dtsheader.sample_rate, ti); + if (verbose) + fprintf(stdout, "Using DTS demultiplexer for %s.\n+-> Using " \ + "DTS output module for audio stream.\n", ti->fname); +} + +dts_reader_c::~dts_reader_c() { + if (file != NULL) + fclose(file); + safefree(chunk); + if (dtspacketizer != NULL) + delete dtspacketizer; +} + +int dts_reader_c::read() { + int nread; + + nread = fread(chunk, 1, 4096, file); + if (nread <= 0) + return 0; + + dtspacketizer->process(chunk, nread); + bytes_processed += nread; + + return EMOREDATA; +} + +packet_t *dts_reader_c::get_packet() { + return dtspacketizer->get_packet(); +} + +int dts_reader_c::display_priority() { + return DISPLAYPRIORITY_HIGH - 1; +} + +void dts_reader_c::display_progress() { + fprintf(stdout, "progress: %lld/%lld bytes (%d%%)\r", + bytes_processed, size, + (int)(bytes_processed * 100L / size)); + fflush(stdout); +} + +void dts_reader_c::set_headers() { + dtspacketizer->set_headers(); +} diff --git a/r_dts.h b/r_dts.h new file mode 100644 index 000000000..d592152a4 --- /dev/null +++ b/r_dts.h @@ -0,0 +1,52 @@ +/* + mkvmerge -- utility for splicing together matroska files + from component media subtypes + + r_avi.h + + Written by Moritz Bunkus + + Distributed under the GPL + see the file COPYING for details + or visit http://www.gnu.org/copyleft/gpl.html +*/ + +/*! + \file r_avi.h + \version \$Id: r_dts.h,v 1.1 2003/05/15 08:58:52 mosu Exp $ + \brief class definitions for the AVI demultiplexer module + \author Moritz Bunkus +*/ + +#ifndef __R_DTS_H +#define __R_DTS_H + +#include + +#include "pr_generic.h" +#include "common.h" +#include "error.h" +#include "p_dts.h" +#include "dts_common.h" + +class dts_reader_c: public generic_reader_c { +private: + unsigned char *chunk; + FILE *file; + class dts_packetizer_c *dtspacketizer; + int64_t bytes_processed, size; + +public: + dts_reader_c(track_info_t *nti) throw (error_c); + virtual ~dts_reader_c(); + + virtual int read(); + virtual packet_t *get_packet(); + virtual int display_priority(); + virtual void display_progress(); + virtual void set_headers(); + + static int probe_file(FILE *file, int64_t size); +}; + +#endif // __R_DTS_H diff --git a/r_matroska.cpp b/r_matroska.cpp index 3036a8017..8af6f8b9c 100644 --- a/r_matroska.cpp +++ b/r_matroska.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: r_matroska.cpp,v 1.30 2003/05/11 09:24:02 mosu Exp $ + \version \$Id: r_matroska.cpp,v 1.31 2003/05/15 08:58:52 mosu Exp $ \brief Matroska reader \author Moritz Bunkus */ @@ -40,6 +40,7 @@ extern "C" { // for BITMAPINFOHEADER #include "p_textsubs.h" #include "p_mp3.h" #include "p_ac3.h" +#include "p_dts.h" #include "EbmlContexts.h" #include "EbmlHead.h" @@ -304,6 +305,8 @@ void mkv_reader_c::verify_tracks() { t->a_formattag = 0x0055; else if (!strcmp(t->codec_id, MKV_A_AC3)) t->a_formattag = 0x2000; + else if (!strcmp(t->codec_id, MKV_A_DTS)) + t->a_formattag = 0x2001; else if (!strcmp(t->codec_id, MKV_A_PCM)) t->a_formattag = 0x0001; else if (!strcmp(t->codec_id, MKV_A_VORBIS)) { @@ -856,6 +859,10 @@ void mkv_reader_c::create_packetizers() { t->packetizer = new ac3_packetizer_c(this, (unsigned long)t->a_sfreq, t->a_channels, &nti); + else if (t->a_formattag == 0x2001) + t->packetizer = new dts_packetizer_c(this, + (unsigned long)t->a_sfreq, + &nti); else if (t->a_formattag == 0xFFFE) t->packetizer = new vorbis_packetizer_c(this, t->headers[0],