mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-23 19:31:44 +00:00
Added support for Ogg/Theora (not specs compliant because we haven't decided about the specs yet.
This commit is contained in:
parent
0591a72ca1
commit
ccdcebaddf
@ -1,3 +1,7 @@
|
|||||||
|
2005-10-23 Moritz Bunkus <moritz@bunkus.org>
|
||||||
|
|
||||||
|
* mkvmerge: new feature: Added support for Ogg/Theora.
|
||||||
|
|
||||||
2005-10-22 Moritz Bunkus <moritz@bunkus.org>
|
2005-10-22 Moritz Bunkus <moritz@bunkus.org>
|
||||||
|
|
||||||
* mkvmerge: Changed the CodecID for AAC audio tracks to "A_AAC" by
|
* mkvmerge: Changed the CodecID for AAC audio tracks to "A_AAC" by
|
||||||
|
100
src/common/common_memory.cpp
Normal file
100
src/common/common_memory.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
mkvmerge -- utility for splicing together matroska files
|
||||||
|
from component media subtypes
|
||||||
|
|
||||||
|
Distributed under the GPL
|
||||||
|
see the file COPYING for details
|
||||||
|
or visit http://www.gnu.org/copyleft/gpl.html
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
|
||||||
|
class definition for memory handling classes
|
||||||
|
|
||||||
|
Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common_memory.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
memory_cptr
|
||||||
|
lace_memory_xiph(const vector<memory_cptr> &blocks) {
|
||||||
|
unsigned char *buffer;
|
||||||
|
int size, i, offset, n;
|
||||||
|
|
||||||
|
size = 1;
|
||||||
|
for (i = 0; (blocks.size() - 1) > i; ++i)
|
||||||
|
size += blocks[i]->get_size() / 255 + 1 + blocks[i]->get_size();
|
||||||
|
size += blocks.back()->get_size();
|
||||||
|
|
||||||
|
buffer = (unsigned char *)safemalloc(size);
|
||||||
|
|
||||||
|
buffer[0] = blocks.size() - 1;
|
||||||
|
offset = 1;
|
||||||
|
for (i = 0; (blocks.size() - 1) > i; ++i) {
|
||||||
|
for (n = blocks[i]->get_size(); n >= 255; n -= 255) {
|
||||||
|
buffer[offset] = 255;
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
|
buffer[offset] = n;
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
|
for (i = 0; blocks.size() > i; ++i) {
|
||||||
|
memcpy(&buffer[offset], blocks[i]->get(), blocks[i]->get_size());
|
||||||
|
offset += blocks[i]->get_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory_cptr(new memory_c(buffer, size, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<memory_cptr>
|
||||||
|
unlace_memory_xiph(memory_cptr &buffer) {
|
||||||
|
int i, num_blocks, size, last_size;
|
||||||
|
unsigned char *ptr, *end;
|
||||||
|
vector<memory_cptr> blocks;
|
||||||
|
vector<int> sizes;
|
||||||
|
|
||||||
|
if (1 > buffer->get_size())
|
||||||
|
throw error_c("Lacing error: Buffer too small");
|
||||||
|
|
||||||
|
ptr = buffer->get();
|
||||||
|
end = buffer->get() + buffer->get_size();
|
||||||
|
num_blocks = ptr[0] + 1;
|
||||||
|
++ptr;
|
||||||
|
|
||||||
|
last_size = buffer->get_size();
|
||||||
|
for (i = 0; (num_blocks - 1) > i; ++i) {
|
||||||
|
size = 0;
|
||||||
|
while ((ptr < end) && (*ptr == 255)) {
|
||||||
|
size += 255;
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr >= end)
|
||||||
|
throw error_c("Lacing error: End-of-buffer while reading the block "
|
||||||
|
"sizes");
|
||||||
|
|
||||||
|
size += *ptr;
|
||||||
|
++ptr;
|
||||||
|
|
||||||
|
sizes.push_back(size);
|
||||||
|
last_size -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
sizes.push_back(last_size - (ptr - buffer->get()));
|
||||||
|
|
||||||
|
for (i = 0; sizes.size() > i; ++i) {
|
||||||
|
if ((ptr + sizes[i]) > end)
|
||||||
|
throw error_c("Lacing error: End-of-buffer while assigning the blocks");
|
||||||
|
|
||||||
|
blocks.push_back(memory_cptr(new memory_c(ptr, sizes[i], false)));
|
||||||
|
ptr += sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks;
|
||||||
|
}
|
@ -126,4 +126,7 @@ struct buffer_t {
|
|||||||
~buffer_t();
|
~buffer_t();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
memory_cptr MTX_DLL_API lace_memory_xiph(const vector<memory_cptr> &blocks);
|
||||||
|
vector<memory_cptr> MTX_DLL_API unlace_memory_xiph(memory_cptr &buffer);
|
||||||
|
|
||||||
#endif // __COMMON_MEMORY_H
|
#endif // __COMMON_MEMORY_H
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
#define MKV_V_REALV3 "V_REAL/RV30"
|
#define MKV_V_REALV3 "V_REAL/RV30"
|
||||||
#define MKV_V_REALV4 "V_REAL/RV40"
|
#define MKV_V_REALV4 "V_REAL/RV40"
|
||||||
#define MKV_V_QUICKTIME "V_QUICKTIME"
|
#define MKV_V_QUICKTIME "V_QUICKTIME"
|
||||||
|
#define MKV_V_THEORA "V_THEORA"
|
||||||
|
|
||||||
#define MKV_S_TEXTUTF8 "S_TEXT/UTF8"
|
#define MKV_S_TEXTUTF8 "S_TEXT/UTF8"
|
||||||
#define MKV_S_TEXTSSA "S_TEXT/SSA"
|
#define MKV_S_TEXTSSA "S_TEXT/SSA"
|
||||||
|
78
src/common/theora_common.cpp
Normal file
78
src/common/theora_common.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
mkvmerge -- utility for splicing together matroska files
|
||||||
|
from component media subtypes
|
||||||
|
|
||||||
|
Distributed under the GPL
|
||||||
|
see the file COPYING for details
|
||||||
|
or visit http://www.gnu.org/copyleft/gpl.html
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
|
||||||
|
Ogg Theora helper functions
|
||||||
|
|
||||||
|
Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
#include "bit_cursor.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "theora_common.h"
|
||||||
|
|
||||||
|
theora_identification_header_t::theora_identification_header_t() {
|
||||||
|
memset(this, 0, sizeof(theora_identification_header_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
theora_parse_identification_header(unsigned char *buffer,
|
||||||
|
int size,
|
||||||
|
theora_identification_header_t &header)
|
||||||
|
throw(error_c) {
|
||||||
|
|
||||||
|
bit_cursor_c bc(buffer, size);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
header.headertype = bc.get_bits(8);
|
||||||
|
if (THEORA_HEADERTYPE_IDENTIFICATION != header.headertype)
|
||||||
|
throw error_c(mxsprintf("Wrong header type: 0x%02x != 0x%02x",
|
||||||
|
header.headertype,
|
||||||
|
THEORA_HEADERTYPE_IDENTIFICATION));
|
||||||
|
|
||||||
|
for (i = 0; 6 > i; ++i)
|
||||||
|
header.theora_string[i] = bc.get_bits(8);
|
||||||
|
if (strncmp(header.theora_string, "theora", 6))
|
||||||
|
throw error_c(mxsprintf("Wrong identifaction string: '%6s' != 'theora'",
|
||||||
|
header.theora_string));
|
||||||
|
|
||||||
|
header.vmaj = bc.get_bits(8);
|
||||||
|
header.vmin = bc.get_bits(8);
|
||||||
|
header.vrev = bc.get_bits(8);
|
||||||
|
|
||||||
|
if ((3 != header.vmaj) || (2 != header.vmin) || (0 != header.vrev))
|
||||||
|
throw error_c(mxsprintf("Wrong Theora version: %d.%d.%d != 3.2.0",
|
||||||
|
header.vmaj, header.vmin, header.vrev));
|
||||||
|
|
||||||
|
header.fmbw = bc.get_bits(16) * 16;
|
||||||
|
header.fmbh = bc.get_bits(16) * 16;
|
||||||
|
header.picw = bc.get_bits(24);
|
||||||
|
header.pich = bc.get_bits(24);
|
||||||
|
header.picx = bc.get_bits(8);
|
||||||
|
header.picy = bc.get_bits(8);
|
||||||
|
|
||||||
|
header.frn = bc.get_bits(32);
|
||||||
|
header.frd = bc.get_bits(32);
|
||||||
|
|
||||||
|
header.parn = bc.get_bits(24);
|
||||||
|
header.pard = bc.get_bits(24);
|
||||||
|
|
||||||
|
header.cs = bc.get_bits(8);
|
||||||
|
header.nombr = bc.get_bits(24);
|
||||||
|
header.qual = bc.get_bits(6);
|
||||||
|
|
||||||
|
header.kfgshift = bc.get_bits(5);
|
||||||
|
|
||||||
|
header.pf = bc.get_bits(2);
|
||||||
|
|
||||||
|
if (0 != bc.get_bits(3))
|
||||||
|
throw error_c("Reserved bits are not 0");
|
||||||
|
}
|
65
src/common/theora_common.h
Normal file
65
src/common/theora_common.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
mkvmerge -- utility for splicing together matroska files
|
||||||
|
from component media subtypes
|
||||||
|
|
||||||
|
Distributed under the GPL
|
||||||
|
see the file COPYING for details
|
||||||
|
or visit http://www.gnu.org/copyleft/gpl.html
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
|
||||||
|
Ogg Theora helper functions
|
||||||
|
|
||||||
|
Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __THEORA_COMMON_H
|
||||||
|
#define __THEORA_COMMON_H
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
#define THEORA_HEADERTYPE_IDENTIFICATION 0x80
|
||||||
|
#define THEORA_HEADERTYPE_COMMENT 0x81
|
||||||
|
#define THEORA_HEADERTYPE_SETUP 0x82
|
||||||
|
|
||||||
|
struct MTX_DLL_API theora_identification_header_t {
|
||||||
|
uint8_t headertype;
|
||||||
|
char theora_string[6];
|
||||||
|
|
||||||
|
uint8_t vmaj;
|
||||||
|
uint8_t vmin;
|
||||||
|
uint8_t vrev;
|
||||||
|
|
||||||
|
uint16_t fmbw;
|
||||||
|
uint16_t fmbh;
|
||||||
|
|
||||||
|
uint32_t picw;
|
||||||
|
uint32_t pich;
|
||||||
|
uint8_t picx;
|
||||||
|
uint8_t picy;
|
||||||
|
|
||||||
|
uint32_t frn;
|
||||||
|
uint32_t frd;
|
||||||
|
|
||||||
|
uint32_t parn;
|
||||||
|
uint32_t pard;
|
||||||
|
|
||||||
|
uint8_t cs;
|
||||||
|
uint8_t pf;
|
||||||
|
|
||||||
|
uint32_t nombr;
|
||||||
|
uint8_t qual;
|
||||||
|
|
||||||
|
uint8_t kfgshift;
|
||||||
|
|
||||||
|
theora_identification_header_t();
|
||||||
|
};
|
||||||
|
|
||||||
|
void MTX_DLL_API
|
||||||
|
theora_parse_identification_header(unsigned char *buffer, int size,
|
||||||
|
theora_identification_header_t &header)
|
||||||
|
throw(error_c);
|
||||||
|
|
||||||
|
#endif // __THEORA_COMMON_H
|
@ -228,9 +228,7 @@ kax_reader_c::find_track_by_uid(uint64_t uid,
|
|||||||
|
|
||||||
void
|
void
|
||||||
kax_reader_c::verify_tracks() {
|
kax_reader_c::verify_tracks() {
|
||||||
int tnum, i;
|
int tnum, u;
|
||||||
unsigned char *c;
|
|
||||||
uint32_t u, offset, length;
|
|
||||||
kax_track_t *t;
|
kax_track_t *t;
|
||||||
alBITMAPINFOHEADER *bih;
|
alBITMAPINFOHEADER *bih;
|
||||||
alWAVEFORMATEX *wfe;
|
alWAVEFORMATEX *wfe;
|
||||||
@ -294,6 +292,13 @@ kax_reader_c::verify_tracks() {
|
|||||||
|
|
||||||
memcpy(t->v_fourcc, &bih->bi_compression, 4);
|
memcpy(t->v_fourcc, &bih->bi_compression, 4);
|
||||||
}
|
}
|
||||||
|
} else if (t->codec_id == MKV_V_THEORA) {
|
||||||
|
if (NULL == t->private_data) {
|
||||||
|
if (verbose)
|
||||||
|
mxwarn(PFX "CodecID for track " LLU " is '" MKV_V_THEORA
|
||||||
|
"', but there was no codec private headers.\n", t->tnum);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->v_width == 0) {
|
if (t->v_width == 0) {
|
||||||
@ -381,38 +386,26 @@ kax_reader_c::verify_tracks() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = (unsigned char *)t->private_data;
|
try {
|
||||||
if (c[0] != 2) {
|
memory_cptr temp(new memory_c((unsigned char *)t->private_data,
|
||||||
|
t->private_size, false));
|
||||||
|
vector<memory_cptr> blocks = unlace_memory_xiph(temp);
|
||||||
|
if (blocks.size() != 3)
|
||||||
|
throw false;
|
||||||
|
|
||||||
|
t->headers[0] = blocks[0]->get();
|
||||||
|
t->headers[1] = blocks[1]->get();
|
||||||
|
t->headers[2] = blocks[2]->get();
|
||||||
|
t->header_sizes[0] = blocks[0]->get_size();
|
||||||
|
t->header_sizes[1] = blocks[1]->get_size();
|
||||||
|
t->header_sizes[2] = blocks[2]->get_size();
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
mxwarn(PFX "Vorbis track does not contain valid headers.\n");
|
mxwarn(PFX "Vorbis track does not contain valid headers.\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = 1;
|
|
||||||
for (i = 0; i < 2; i++) {
|
|
||||||
length = 0;
|
|
||||||
while ((c[offset] == (unsigned char )255) &&
|
|
||||||
(length < t->private_size)) {
|
|
||||||
length += 255;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
if (offset >= (t->private_size - 1)) {
|
|
||||||
if (verbose)
|
|
||||||
mxwarn(PFX "Vorbis track does not contain valid headers.\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
length += c[offset];
|
|
||||||
offset++;
|
|
||||||
t->header_sizes[i] = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
t->headers[0] = &c[offset];
|
|
||||||
t->headers[1] = &c[offset + t->header_sizes[0]];
|
|
||||||
t->headers[2] = &c[offset + t->header_sizes[0] +
|
|
||||||
t->header_sizes[1]];
|
|
||||||
t->header_sizes[2] = t->private_size - offset -
|
|
||||||
t->header_sizes[0] - t->header_sizes[1];
|
|
||||||
|
|
||||||
t->a_formattag = 0xFFFE;
|
t->a_formattag = 0xFFFE;
|
||||||
|
|
||||||
// mkvmerge around 0.6.x had a bug writing a default duration
|
// mkvmerge around 0.6.x had a bug writing a default duration
|
||||||
@ -1417,7 +1410,8 @@ kax_reader_c::create_packetizer(int64_t tid) {
|
|||||||
starts_with(t->codec_id, "V_REAL", 6) ||
|
starts_with(t->codec_id, "V_REAL", 6) ||
|
||||||
(t->codec_id == MKV_V_QUICKTIME) ||
|
(t->codec_id == MKV_V_QUICKTIME) ||
|
||||||
(t->codec_id == MKV_V_MPEG1) ||
|
(t->codec_id == MKV_V_MPEG1) ||
|
||||||
(t->codec_id == MKV_V_MPEG2)) {
|
(t->codec_id == MKV_V_MPEG2) ||
|
||||||
|
(t->codec_id == MKV_V_THEORA)) {
|
||||||
const char *fourcc;
|
const char *fourcc;
|
||||||
|
|
||||||
if ((t->codec_id == MKV_V_MSCOMP) &&
|
if ((t->codec_id == MKV_V_MSCOMP) &&
|
||||||
|
@ -68,9 +68,8 @@ free_string_array(char **comments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char **
|
static char **
|
||||||
extract_vorbis_comments(unsigned char *buffer,
|
extract_vorbis_comments(const memory_cptr &mem) {
|
||||||
int size) {
|
mm_mem_io_c in(mem->get(), mem->get_size());
|
||||||
mm_mem_io_c in(buffer, size);
|
|
||||||
char **comments;
|
char **comments;
|
||||||
uint32_t i, n, len;
|
uint32_t i, n, len;
|
||||||
|
|
||||||
@ -397,6 +396,7 @@ ogm_reader_c::create_packetizer(int64_t tid) {
|
|||||||
generic_packetizer_c *ptzr;
|
generic_packetizer_c *ptzr;
|
||||||
double fps;
|
double fps;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
memory_cptr codecprivate;
|
||||||
|
|
||||||
if ((tid < 0) || (tid >= sdemuxers.size()))
|
if ((tid < 0) || (tid >= sdemuxers.size()))
|
||||||
return;
|
return;
|
||||||
@ -404,7 +404,7 @@ ogm_reader_c::create_packetizer(int64_t tid) {
|
|||||||
|
|
||||||
if ((dmx->ptzr == -1) && dmx->in_use) {
|
if ((dmx->ptzr == -1) && dmx->in_use) {
|
||||||
memset(&bih, 0, sizeof(alBITMAPINFOHEADER));
|
memset(&bih, 0, sizeof(alBITMAPINFOHEADER));
|
||||||
sth = (stream_header *)&dmx->packet_data[0][1];
|
sth = (stream_header *)&dmx->packet_data[0]->get()[1];
|
||||||
ti.private_data = NULL;
|
ti.private_data = NULL;
|
||||||
ti.private_size = 0;
|
ti.private_size = 0;
|
||||||
ti.id = tid;
|
ti.id = tid;
|
||||||
@ -476,9 +476,11 @@ ogm_reader_c::create_packetizer(int64_t tid) {
|
|||||||
|
|
||||||
case OGM_STREAM_TYPE_AAC:
|
case OGM_STREAM_TYPE_AAC:
|
||||||
aac_info_extracted = false;
|
aac_info_extracted = false;
|
||||||
if (dmx->packet_sizes[0] >= (sizeof(stream_header) + 5)) {
|
if (dmx->packet_data[0]->get_size() >= (sizeof(stream_header) + 5)) {
|
||||||
if (parse_aac_data(&dmx->packet_data[0][sizeof(stream_header) + 5],
|
if (parse_aac_data(dmx->packet_data[0]->get() +
|
||||||
dmx->packet_sizes[0] - sizeof(stream_header) - 5,
|
sizeof(stream_header) + 5,
|
||||||
|
dmx->packet_data[0]->get_size() -
|
||||||
|
sizeof(stream_header) - 5,
|
||||||
profile, channels, sample_rate,
|
profile, channels, sample_rate,
|
||||||
output_sample_rate, sbr)) {
|
output_sample_rate, sbr)) {
|
||||||
aac_info_extracted = true;
|
aac_info_extracted = true;
|
||||||
@ -511,8 +513,8 @@ ogm_reader_c::create_packetizer(int64_t tid) {
|
|||||||
vorbis_info_init(&vi);
|
vorbis_info_init(&vi);
|
||||||
vorbis_comment_init(&vc);
|
vorbis_comment_init(&vc);
|
||||||
memset(&op, 0, sizeof(ogg_packet));
|
memset(&op, 0, sizeof(ogg_packet));
|
||||||
op.packet = dmx->packet_data[0];
|
op.packet = dmx->packet_data[0]->get();
|
||||||
op.bytes = dmx->packet_sizes[0];
|
op.bytes = dmx->packet_data[0]->get_size();
|
||||||
op.b_o_s = 1;
|
op.b_o_s = 1;
|
||||||
vorbis_synthesis_headerin(&vi, &vc, &op);
|
vorbis_synthesis_headerin(&vi, &vc, &op);
|
||||||
dmx->vorbis_rate = vi.rate;
|
dmx->vorbis_rate = vi.rate;
|
||||||
@ -520,9 +522,12 @@ ogm_reader_c::create_packetizer(int64_t tid) {
|
|||||||
vorbis_comment_clear(&vc);
|
vorbis_comment_clear(&vc);
|
||||||
ptzr =
|
ptzr =
|
||||||
new vorbis_packetizer_c(this,
|
new vorbis_packetizer_c(this,
|
||||||
dmx->packet_data[0], dmx->packet_sizes[0],
|
dmx->packet_data[0]->get(),
|
||||||
dmx->packet_data[1], dmx->packet_sizes[1],
|
dmx->packet_data[0]->get_size(),
|
||||||
dmx->packet_data[2], dmx->packet_sizes[2],
|
dmx->packet_data[1]->get(),
|
||||||
|
dmx->packet_data[1]->get_size(),
|
||||||
|
dmx->packet_data[2]->get(),
|
||||||
|
dmx->packet_data[2]->get_size(),
|
||||||
ti);
|
ti);
|
||||||
|
|
||||||
mxinfo(FMT_TID "Using the Vorbis output module.\n", ti.fname.c_str(),
|
mxinfo(FMT_TID "Using the Vorbis output module.\n", ti.fname.c_str(),
|
||||||
@ -544,13 +549,14 @@ ogm_reader_c::create_packetizer(int64_t tid) {
|
|||||||
int size, i;
|
int size, i;
|
||||||
|
|
||||||
size = 0;
|
size = 0;
|
||||||
for (i = 1; i < (int)dmx->packet_sizes.size(); i++)
|
for (i = 1; i < (int)dmx->packet_data.size(); i++)
|
||||||
size += dmx->packet_sizes[i];
|
size += dmx->packet_data[i]->get_size();
|
||||||
buf = (unsigned char *)safemalloc(size);
|
buf = (unsigned char *)safemalloc(size);
|
||||||
size = 0;
|
size = 0;
|
||||||
for (i = 1; i < (int)dmx->packet_sizes.size(); i++) {
|
for (i = 1; i < (int)dmx->packet_data.size(); i++) {
|
||||||
memcpy(&buf[size], dmx->packet_data[i], dmx->packet_sizes[i]);
|
memcpy(&buf[size], dmx->packet_data[i]->get(),
|
||||||
size += dmx->packet_sizes[i];
|
dmx->packet_data[i]->get_size());
|
||||||
|
size += dmx->packet_data[i]->get_size();
|
||||||
}
|
}
|
||||||
ptzr = new flac_packetizer_c(this, buf, size, ti);
|
ptzr = new flac_packetizer_c(this, buf, size, ti);
|
||||||
safefree(buf);
|
safefree(buf);
|
||||||
@ -560,6 +566,21 @@ ogm_reader_c::create_packetizer(int64_t tid) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case OGM_STREAM_TYPE_THEORA:
|
||||||
|
codecprivate = lace_memory_xiph(dmx->packet_data);
|
||||||
|
ti.private_data = codecprivate->get();
|
||||||
|
ti.private_size = codecprivate->get_size();
|
||||||
|
|
||||||
|
fps = (double)dmx->theora.frn / (double)dmx->theora.frd;
|
||||||
|
ptzr = new video_packetizer_c(this, MKV_V_THEORA, fps, dmx->theora.fmbw,
|
||||||
|
dmx->theora.fmbh, ti);
|
||||||
|
mxinfo(FMT_TID "Using the Theora video output module.\n", ti.fname.c_str(),
|
||||||
|
(int64_t)tid);
|
||||||
|
|
||||||
|
ti.private_data = NULL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
die("ogm_reader: Don't know how to create a packetizer for stream "
|
die("ogm_reader: Don't know how to create a packetizer for stream "
|
||||||
"type %d.\n", (int)dmx->stype);
|
"type %d.\n", (int)dmx->stype);
|
||||||
@ -635,8 +656,10 @@ ogm_reader_c::handle_new_stream(ogg_page *og) {
|
|||||||
ogg_stream_pagein(&dmx->os, og);
|
ogg_stream_pagein(&dmx->os, og);
|
||||||
ogg_stream_packetout(&dmx->os, &op);
|
ogg_stream_packetout(&dmx->os, &op);
|
||||||
|
|
||||||
dmx->packet_data.push_back((unsigned char *)safememdup(op.packet, op.bytes));
|
dmx->packet_data.push_back(memory_cptr(new memory_c((unsigned char *)
|
||||||
dmx->packet_sizes.push_back(op.bytes);
|
safememdup(op.packet,
|
||||||
|
op.bytes),
|
||||||
|
op.bytes, true)));
|
||||||
dmx->serialno = ogg_page_serialno(og);
|
dmx->serialno = ogg_page_serialno(og);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -653,6 +676,24 @@ ogm_reader_c::handle_new_stream(ogg_page *og) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((op.bytes >= 7) && !strncmp((char *)&op.packet[1], "theora", 6)) {
|
||||||
|
if (!demuxing_requested('v', sdemuxers.size() - 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
dmx->stype = OGM_STREAM_TYPE_THEORA;
|
||||||
|
dmx->in_use = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
theora_parse_identification_header(op.packet, op.bytes, dmx->theora);
|
||||||
|
} catch (error_c &e) {
|
||||||
|
mxerror(FMT_TID "The Theora identifaction header could not be parsed "
|
||||||
|
"(%s).\n", ti.fname.c_str(), (int64_t)sdemuxers.size() - 1,
|
||||||
|
e.get_error().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// FLAC
|
// FLAC
|
||||||
if ((op.bytes >= 4) && !strncmp((char *)op.packet, "fLaC", 4)) {
|
if ((op.bytes >= 4) && !strncmp((char *)op.packet, "fLaC", 4)) {
|
||||||
if (!demuxing_requested('a', sdemuxers.size() - 1))
|
if (!demuxing_requested('a', sdemuxers.size() - 1))
|
||||||
@ -778,8 +819,7 @@ ogm_reader_c::process_page(ogg_page *og) {
|
|||||||
if (dmx->units_processed <= dmx->flac_header_packets)
|
if (dmx->units_processed <= dmx->flac_header_packets)
|
||||||
continue;
|
continue;
|
||||||
for (i = 0; i < (int)dmx->nh_packet_data.size(); i++) {
|
for (i = 0; i < (int)dmx->nh_packet_data.size(); i++) {
|
||||||
memory_c *mem = new memory_c(dmx->nh_packet_data[i],
|
memory_c *mem = dmx->nh_packet_data[i]->clone();
|
||||||
dmx->nh_packet_sizes[i], true);
|
|
||||||
PTZR(dmx->ptzr)->process(new packet_t(mem, 0));
|
PTZR(dmx->ptzr)->process(new packet_t(mem, 0));
|
||||||
}
|
}
|
||||||
dmx->nh_packet_data.clear();
|
dmx->nh_packet_data.clear();
|
||||||
@ -804,6 +844,42 @@ ogm_reader_c::process_page(ogg_page *og) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (dmx->stype == OGM_STREAM_TYPE_THEORA) {
|
||||||
|
int frame_number, keyframe_number, non_keyframe_number;
|
||||||
|
int64_t timecode, duration, bref;
|
||||||
|
|
||||||
|
if ((0 == op.bytes) || (0 != (op.packet[0] & 0x80)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
keyframe_number = ogg_page_granulepos(og) >> dmx->theora.kfgshift;
|
||||||
|
non_keyframe_number = ogg_page_granulepos(og) & dmx->theora.kfgshift;
|
||||||
|
frame_number = keyframe_number + non_keyframe_number;
|
||||||
|
|
||||||
|
timecode = (int64_t)(1000000000.0 * dmx->last_granulepos *
|
||||||
|
dmx->theora.frd / dmx->theora.frn);
|
||||||
|
duration = (int64_t)(1000000000.0 * dmx->theora.frd / dmx->theora.frn);
|
||||||
|
bref = (keyframe_number != dmx->last_keyframe_number) &&
|
||||||
|
(0 == non_keyframe_number) ? VFT_IFRAME : VFT_PFRAMEAUTOMATIC;
|
||||||
|
PTZR(dmx->ptzr)->process(new packet_t(new memory_c(op.packet, op.bytes,
|
||||||
|
false), timecode,
|
||||||
|
duration, bref, VFT_NOBFRAME));
|
||||||
|
|
||||||
|
if (frame_number > dmx->last_granulepos)
|
||||||
|
dmx->last_granulepos = frame_number;
|
||||||
|
else
|
||||||
|
++dmx->last_granulepos;
|
||||||
|
|
||||||
|
dmx->last_keyframe_number = keyframe_number;
|
||||||
|
|
||||||
|
if (eos) {
|
||||||
|
dmx->eos = 1;
|
||||||
|
debug_leave("ogm_reader_c::process_page");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
duration_len = (*op.packet & PACKET_LEN_BITS01) >> 6;
|
duration_len = (*op.packet & PACKET_LEN_BITS01) >> 6;
|
||||||
duration_len |= (*op.packet & PACKET_LEN_BITS2) << 1;
|
duration_len |= (*op.packet & PACKET_LEN_BITS2) << 1;
|
||||||
if ((duration_len > 0) && (op.bytes >= (duration_len + 1)))
|
if ((duration_len > 0) && (op.bytes >= (duration_len + 1)))
|
||||||
@ -886,16 +962,18 @@ ogm_reader_c::process_header_packets(ogm_demuxer_t *dmx) {
|
|||||||
#if defined HAVE_FLAC_FORMAT_H
|
#if defined HAVE_FLAC_FORMAT_H
|
||||||
while ((dmx->packet_data.size() < dmx->flac_header_packets) &&
|
while ((dmx->packet_data.size() < dmx->flac_header_packets) &&
|
||||||
(ogg_stream_packetout(&dmx->os, &op) == 1)) {
|
(ogg_stream_packetout(&dmx->os, &op) == 1)) {
|
||||||
dmx->packet_data.push_back((unsigned char *)
|
memory_c *mem = new memory_c((unsigned char *)
|
||||||
safememdup(op.packet, op.bytes));
|
safememdup(op.packet, op.bytes),
|
||||||
dmx->packet_sizes.push_back(op.bytes);
|
op.bytes, true);
|
||||||
|
dmx->packet_data.push_back(memory_cptr(mem));
|
||||||
}
|
}
|
||||||
if (dmx->packet_data.size() >= dmx->flac_header_packets)
|
if (dmx->packet_data.size() >= dmx->flac_header_packets)
|
||||||
dmx->headers_read = true;
|
dmx->headers_read = true;
|
||||||
while (ogg_stream_packetout(&dmx->os, &op) == 1) {
|
while (ogg_stream_packetout(&dmx->os, &op) == 1) {
|
||||||
dmx->nh_packet_data.push_back((unsigned char *)
|
memory_c *mem = new memory_c((unsigned char *)
|
||||||
safememdup(op.packet, op.bytes));
|
safememdup(op.packet, op.bytes),
|
||||||
dmx->nh_packet_sizes.push_back(op.bytes);
|
op.bytes, true);
|
||||||
|
dmx->nh_packet_data.push_back(memory_cptr(mem));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
dmx->headers_read = true;
|
dmx->headers_read = true;
|
||||||
@ -914,9 +992,10 @@ ogm_reader_c::process_header_packets(ogm_demuxer_t *dmx) {
|
|||||||
ogg_stream_reset(&dmx->os);
|
ogg_stream_reset(&dmx->os);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dmx->packet_data.push_back((unsigned char *)
|
memory_c *mem = new memory_c((unsigned char *)
|
||||||
safememdup(op.packet, op.bytes));
|
safememdup(op.packet, op.bytes),
|
||||||
dmx->packet_sizes.push_back(op.bytes);
|
op.bytes, true);
|
||||||
|
dmx->packet_data.push_back(memory_cptr(mem));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dmx->stype == OGM_STREAM_TYPE_VORBIS) {
|
if (dmx->stype == OGM_STREAM_TYPE_VORBIS) {
|
||||||
@ -1030,7 +1109,7 @@ ogm_reader_c::identify() {
|
|||||||
mxinfo("File '%s': container: Ogg/OGM%s\n", ti.fname.c_str(), info.c_str());
|
mxinfo("File '%s': container: Ogg/OGM%s\n", ti.fname.c_str(), info.c_str());
|
||||||
for (i = 0; i < sdemuxers.size(); i++) {
|
for (i = 0; i < sdemuxers.size(); i++) {
|
||||||
if (sdemuxers[i]->stype == OGM_STREAM_TYPE_VIDEO) {
|
if (sdemuxers[i]->stype == OGM_STREAM_TYPE_VIDEO) {
|
||||||
sth = (stream_header *)&sdemuxers[i]->packet_data[0][1];
|
sth = (stream_header *)(sdemuxers[i]->packet_data[0]->get() + 1);
|
||||||
memcpy(fourcc, sth->subtype, 4);
|
memcpy(fourcc, sth->subtype, 4);
|
||||||
fourcc[4] = 0;
|
fourcc[4] = 0;
|
||||||
}
|
}
|
||||||
@ -1091,8 +1170,7 @@ ogm_reader_c::handle_stream_comments() {
|
|||||||
if ((dmx->stype == OGM_STREAM_TYPE_FLAC) ||
|
if ((dmx->stype == OGM_STREAM_TYPE_FLAC) ||
|
||||||
(dmx->packet_data.size() < 2))
|
(dmx->packet_data.size() < 2))
|
||||||
continue;
|
continue;
|
||||||
comments = extract_vorbis_comments(dmx->packet_data[1],
|
comments = extract_vorbis_comments(dmx->packet_data[1]);
|
||||||
dmx->packet_sizes[1]);
|
|
||||||
if (comments == NULL)
|
if (comments == NULL)
|
||||||
continue;
|
continue;
|
||||||
chapters.clear();
|
chapters.clear();
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "mm_io.h"
|
#include "mm_io.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "pr_generic.h"
|
#include "pr_generic.h"
|
||||||
|
#include "theora_common.h"
|
||||||
|
|
||||||
#define OGM_STREAM_TYPE_UNKNOWN 0
|
#define OGM_STREAM_TYPE_UNKNOWN 0
|
||||||
#define OGM_STREAM_TYPE_VORBIS 1
|
#define OGM_STREAM_TYPE_VORBIS 1
|
||||||
@ -40,6 +41,7 @@
|
|||||||
#define OGM_STREAM_TYPE_TEXT 6
|
#define OGM_STREAM_TYPE_TEXT 6
|
||||||
#define OGM_STREAM_TYPE_FLAC 7
|
#define OGM_STREAM_TYPE_FLAC 7
|
||||||
#define OGM_STREAM_TYPE_AAC 8
|
#define OGM_STREAM_TYPE_AAC 8
|
||||||
|
#define OGM_STREAM_TYPE_THEORA 9
|
||||||
|
|
||||||
#if defined(HAVE_FLAC_FORMAT_H)
|
#if defined(HAVE_FLAC_FORMAT_H)
|
||||||
class flac_header_extractor_c {
|
class flac_header_extractor_c {
|
||||||
@ -69,26 +71,23 @@ struct ogm_demuxer_t {
|
|||||||
int units_processed, vorbis_rate;
|
int units_processed, vorbis_rate;
|
||||||
bool headers_read, native_mode;
|
bool headers_read, native_mode;
|
||||||
string language, title;
|
string language, title;
|
||||||
vector<unsigned char *> packet_data, nh_packet_data;
|
vector<memory_cptr> packet_data, nh_packet_data;
|
||||||
vector<int> packet_sizes, nh_packet_sizes;
|
|
||||||
#if defined(HAVE_FLAC_FORMAT_H)
|
#if defined(HAVE_FLAC_FORMAT_H)
|
||||||
flac_header_extractor_c *fhe;
|
flac_header_extractor_c *fhe;
|
||||||
int flac_header_packets, channels, bits_per_sample;
|
int flac_header_packets, channels, bits_per_sample;
|
||||||
int64_t last_granulepos;
|
|
||||||
#endif
|
#endif
|
||||||
|
int64_t last_granulepos, last_keyframe_number;
|
||||||
bool in_use;
|
bool in_use;
|
||||||
|
|
||||||
|
theora_identification_header_t theora;
|
||||||
|
|
||||||
ogm_demuxer_t():
|
ogm_demuxer_t():
|
||||||
ptzr(-1), stype(0), serialno(0), eos(0), units_processed(0),
|
ptzr(-1), stype(0), serialno(0), eos(0), units_processed(0),
|
||||||
vorbis_rate(0), headers_read(false), native_mode(true),
|
vorbis_rate(0), headers_read(false), native_mode(true),
|
||||||
|
last_granulepos(0), last_keyframe_number(-1),
|
||||||
in_use(false) {
|
in_use(false) {
|
||||||
memset(&os, 0, sizeof(ogg_stream_state));
|
memset(&os, 0, sizeof(ogg_stream_state));
|
||||||
}
|
}
|
||||||
~ogm_demuxer_t() {
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < packet_data.size(); i++)
|
|
||||||
safefree(packet_data[i]);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ogm_reader_c: public generic_reader_c {
|
class ogm_reader_c: public generic_reader_c {
|
||||||
|
@ -46,21 +46,34 @@ vorbis_packetizer_c::vorbis_packetizer_c(generic_reader_c *_reader,
|
|||||||
timecode_offset(0) {
|
timecode_offset(0) {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
ogg_packet ogg_headers[3];
|
||||||
|
|
||||||
memset(headers, 0, 3 * sizeof(ogg_packet));
|
headers.push_back(memory_cptr(new memory_c((unsigned char *)
|
||||||
headers[0].packet = (unsigned char *)safememdup(d_header, l_header);
|
safememdup(d_header, l_header),
|
||||||
headers[1].packet = (unsigned char *)safememdup(d_comments, l_comments);
|
l_header)));
|
||||||
headers[2].packet = (unsigned char *)safememdup(d_codecsetup, l_codecsetup);
|
headers.push_back(memory_cptr(new memory_c((unsigned char *)
|
||||||
headers[0].bytes = l_header;
|
safememdup(d_comments,
|
||||||
headers[1].bytes = l_comments;
|
l_comments),
|
||||||
headers[2].bytes = l_codecsetup;
|
l_comments)));
|
||||||
headers[0].b_o_s = 1;
|
headers.push_back(memory_cptr(new memory_c((unsigned char *)
|
||||||
headers[1].packetno = 1;
|
safememdup(d_codecsetup,
|
||||||
headers[2].packetno = 2;
|
l_codecsetup),
|
||||||
|
l_codecsetup)));
|
||||||
|
|
||||||
|
memset(ogg_headers, 0, 3 * sizeof(ogg_packet));
|
||||||
|
ogg_headers[0].packet = headers[0]->get();
|
||||||
|
ogg_headers[1].packet = headers[1]->get();
|
||||||
|
ogg_headers[2].packet = headers[2]->get();
|
||||||
|
ogg_headers[0].bytes = l_header;
|
||||||
|
ogg_headers[1].bytes = l_comments;
|
||||||
|
ogg_headers[2].bytes = l_codecsetup;
|
||||||
|
ogg_headers[0].b_o_s = 1;
|
||||||
|
ogg_headers[1].packetno = 1;
|
||||||
|
ogg_headers[2].packetno = 2;
|
||||||
vorbis_info_init(&vi);
|
vorbis_info_init(&vi);
|
||||||
vorbis_comment_init(&vc);
|
vorbis_comment_init(&vc);
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
if (vorbis_synthesis_headerin(&vi, &vc, &headers[i]) < 0)
|
if (vorbis_synthesis_headerin(&vi, &vc, &ogg_headers[i]) < 0)
|
||||||
throw error_c("Error: vorbis_packetizer: Could not extract the "
|
throw error_c("Error: vorbis_packetizer: Could not extract the "
|
||||||
"stream's parameters from the first packets.\n");
|
"stream's parameters from the first packets.\n");
|
||||||
|
|
||||||
@ -72,54 +85,18 @@ vorbis_packetizer_c::vorbis_packetizer_c(generic_reader_c *_reader,
|
|||||||
}
|
}
|
||||||
|
|
||||||
vorbis_packetizer_c::~vorbis_packetizer_c() {
|
vorbis_packetizer_c::~vorbis_packetizer_c() {
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
if (headers[i].packet != NULL)
|
|
||||||
safefree(headers[i].packet);
|
|
||||||
vorbis_info_clear(&vi);
|
vorbis_info_clear(&vi);
|
||||||
vorbis_comment_clear(&vc);
|
vorbis_comment_clear(&vc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
vorbis_packetizer_c::set_headers() {
|
vorbis_packetizer_c::set_headers() {
|
||||||
unsigned char *buffer;
|
memory_cptr codecprivate;
|
||||||
int n, offset, i, lsize;
|
|
||||||
|
|
||||||
set_codec_id(MKV_A_VORBIS);
|
set_codec_id(MKV_A_VORBIS);
|
||||||
|
|
||||||
// We use lacing for the blocks. The first bytes is the number of
|
codecprivate = lace_memory_xiph(headers);
|
||||||
// packets being laced which is one less than the number of blocks that
|
set_codec_private(codecprivate->get(), codecprivate->get_size());
|
||||||
// are actually stored. For each packet in the lace there's the length
|
|
||||||
// coded like this:
|
|
||||||
// length = 0
|
|
||||||
// while (next byte == 255) { length += 255 }
|
|
||||||
// length += this byte which is < 255
|
|
||||||
// The last packet's length can be calculated by the length of
|
|
||||||
// the KaxCodecPrivate and all prior packets, so there's no length for it -
|
|
||||||
// and that's why the first byte is (num_packets - 1).
|
|
||||||
lsize = 1 + (headers[0].bytes / 255) + 1 + (headers[1].bytes / 255) + 1 +
|
|
||||||
headers[0].bytes + headers[1].bytes + headers[2].bytes;
|
|
||||||
buffer = (unsigned char *)safemalloc(lsize);
|
|
||||||
|
|
||||||
buffer[0] = 2; // The number of packets less one.
|
|
||||||
offset = 1;
|
|
||||||
for (i = 0; i < 2; i++) {
|
|
||||||
for (n = headers[i].bytes; n >= 255; n -= 255) {
|
|
||||||
buffer[offset] = 255;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
buffer[offset] = n;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
for (i = 0; i <= 2; i++) {
|
|
||||||
memcpy(&buffer[offset], headers[i].packet, headers[i].bytes);
|
|
||||||
offset += headers[i].bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_codec_private(buffer, lsize);
|
|
||||||
|
|
||||||
safefree(buffer);
|
|
||||||
|
|
||||||
set_audio_sampling_freq((float)vi.rate);
|
set_audio_sampling_freq((float)vi.rate);
|
||||||
set_audio_channels(vi.channels);
|
set_audio_channels(vi.channels);
|
||||||
@ -240,10 +217,9 @@ vorbis_packetizer_c::can_connect_to(generic_packetizer_c *src,
|
|||||||
return CAN_CONNECT_NO_FORMAT;
|
return CAN_CONNECT_NO_FORMAT;
|
||||||
connect_check_a_samplerate(vi.rate, vsrc->vi.rate);
|
connect_check_a_samplerate(vi.rate, vsrc->vi.rate);
|
||||||
connect_check_a_channels(vi.channels, vsrc->vi.channels);
|
connect_check_a_channels(vi.channels, vsrc->vi.channels);
|
||||||
if ((headers[2].bytes != vsrc->headers[2].bytes) ||
|
if ((headers[2]->get_size() != vsrc->headers[2]->get_size()) ||
|
||||||
(headers[2].packet == NULL) ||
|
memcmp(headers[2]->get(), vsrc->headers[2]->get(),
|
||||||
(vsrc->headers[2].packet == NULL) ||
|
headers[2]->get_size())) {
|
||||||
memcmp(headers[2].packet, vsrc->headers[2].packet, headers[2].bytes)) {
|
|
||||||
error_message = "The Vorbis codebooks are different; such tracks cannot "
|
error_message = "The Vorbis codebooks are different; such tracks cannot "
|
||||||
"be concatenated without reencoding";
|
"be concatenated without reencoding";
|
||||||
return CAN_CONNECT_NO_PARAMETERS;
|
return CAN_CONNECT_NO_PARAMETERS;
|
||||||
|
@ -30,9 +30,9 @@
|
|||||||
class vorbis_packetizer_c: public generic_packetizer_c {
|
class vorbis_packetizer_c: public generic_packetizer_c {
|
||||||
private:
|
private:
|
||||||
int64_t last_bs, samples, last_samples_sum, last_timecode, timecode_offset;
|
int64_t last_bs, samples, last_samples_sum, last_timecode, timecode_offset;
|
||||||
|
vector<memory_cptr> headers;
|
||||||
vorbis_info vi;
|
vorbis_info vi;
|
||||||
vorbis_comment vc;
|
vorbis_comment vc;
|
||||||
ogg_packet headers[3];
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
vorbis_packetizer_c(generic_reader_c *_reader,
|
vorbis_packetizer_c(generic_reader_c *_reader,
|
||||||
|
Loading…
Reference in New Issue
Block a user