Rewrite of the OGM reader code.

This commit is contained in:
Moritz Bunkus 2008-02-19 16:29:34 +00:00
parent 507c2593c6
commit ccd91ab84f
6 changed files with 1191 additions and 869 deletions

File diff suppressed because it is too large Load Diff

View File

@ -21,9 +21,6 @@
#include <stdio.h>
#include <ogg/ogg.h>
#if defined(HAVE_FLAC_FORMAT_H)
#include <FLAC/stream_decoder.h>
#endif
#include <vector>
@ -47,62 +44,59 @@ enum ogm_stream_type_e {
OGM_STREAM_TYPE_V_THEORA,
};
#if defined(HAVE_FLAC_FORMAT_H)
class flac_header_extractor_c {
public:
FLAC__StreamDecoder *decoder;
bool metadata_parsed;
int channels, sample_rate, bits_per_sample;
mm_io_c *file;
ogg_stream_state os;
ogg_sync_state oy;
ogg_page og;
int64_t sid, num_packets, num_header_packets;
bool done;
class ogm_reader_c;
class ogm_demuxer_c {
public:
flac_header_extractor_c(const string &file_name, int64_t _sid);
~flac_header_extractor_c();
bool extract();
bool read_page();
};
#endif
ogm_reader_c *reader;
struct ogm_demuxer_t {
ogg_stream_state os;
int ptzr;
int64_t track_id;
ogm_stream_type_e stype;
int serialno, eos;
int units_processed, vorbis_rate;
int units_processed;
int num_header_packets, num_non_header_packets;
bool headers_read;
string language, title;
vector<memory_cptr> packet_data, nh_packet_data;
#if defined(HAVE_FLAC_FORMAT_H)
flac_header_extractor_c *fhe;
int flac_header_packets, channels, bits_per_sample;
#endif
int64_t first_granulepos, last_granulepos, last_keyframe_number, default_duration;
bool in_use;
theora_identification_header_t theora;
public:
ogm_demuxer_c(ogm_reader_c *p_reader);
bool is_avc;
virtual ~ogm_demuxer_c();
ogm_demuxer_t():
ptzr(-1), stype(OGM_STREAM_TYPE_UNKNOWN), serialno(0), eos(0), units_processed(0),
vorbis_rate(0), num_header_packets(2), num_non_header_packets(0), headers_read(false),
first_granulepos(0), last_granulepos(0), last_keyframe_number(-1), default_duration(0),
in_use(false), is_avc(false) {
memset(&os, 0, sizeof(ogg_stream_state));
}
virtual const char *get_type() {
return "unknown";
};
virtual string get_codec() {
return "unknown";
};
virtual void initialize() {
};
virtual generic_packetizer_c *create_packetizer(track_info_c &ti) {
return NULL;
};
virtual void process_page(int64_t granulepos);
virtual void process_header_page();
virtual void get_duration_and_len(ogg_packet &op, int64_t &duration, int &duration_len);
virtual bool is_header_packet(ogg_packet &op) {
return op.packet[0] & 1;
};
};
typedef counted_ptr<ogm_demuxer_c> ogm_demuxer_cptr;
class ogm_reader_c: public generic_reader_c {
private:
ogg_sync_state oy;
mm_io_c *io;
vector<ogm_demuxer_t *> sdemuxers;
vector<ogm_demuxer_cptr> sdemuxers;
int bos_pages_read;
int64_t file_size;
@ -121,7 +115,7 @@ public:
static int probe_file(mm_io_c *io, int64_t size);
private:
virtual ogm_demuxer_t *find_demuxer(int serialno);
virtual ogm_demuxer_cptr find_demuxer(int serialno);
virtual int read_page(ogg_page *);
virtual void handle_new_stream(ogg_page *);
virtual void handle_new_stream_and_packets(ogg_page *);
@ -129,9 +123,8 @@ private:
virtual int packet_available();
virtual int read_headers();
virtual void process_header_page(ogg_page *pg);
virtual void process_header_packets(ogm_demuxer_t *dmx);
virtual void process_header_packets(ogm_demuxer_cptr dmx);
virtual void handle_stream_comments();
virtual memory_cptr extract_avcc(ogm_demuxer_t *dmx, int64_t tid);
};

306
src/input/r_ogm_flac.cpp Normal file
View File

@ -0,0 +1,306 @@
/*
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: r_ogm.cpp 3743 2008-01-02 12:09:14Z mosu $
OGG media stream reader -- FLAC support
Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#include "os.h"
#if defined(HAVE_FLAC_FORMAT_H)
#if defined(HAVE_FLAC_FORMAT_H)
# include <FLAC/stream_decoder.h>
# if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8
# define LEGACY_FLAC
# else
# undef LEGACY_FLAC
# endif
#endif
#include "p_flac.h"
#include "r_ogm.h"
#include "r_ogm_flac.h"
#define FPFX "flac_header_extraction: "
#define BUFFER_SIZE 4096
static FLAC__StreamDecoderReadStatus
fhe_read_cb(const FLAC__StreamDecoder *decoder,
FLAC__byte buffer[],
#ifdef LEGACY_FLAC
unsigned *bytes,
#else
size_t *bytes,
#endif
void *client_data) {
flac_header_extractor_c *fhe;
ogg_packet op;
fhe = (flac_header_extractor_c *)client_data;
if (fhe->done)
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
if (ogg_stream_packetout(&fhe->os, &op) != 1) {
if (!fhe->read_page() || (ogg_stream_packetout(&fhe->os, &op) != 1))
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
if (*bytes < op.bytes)
mxerror(FPFX "bytes (%u) < op.bytes (%ld). Could not read the FLAC "
"headers.\n", *bytes, op.bytes);
memcpy(buffer, op.packet, op.bytes);
*bytes = op.bytes;
fhe->num_packets++;
mxverb(2, FPFX "read packet number " LLD " with %ld bytes\n",
fhe->num_packets, op.bytes);
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
static FLAC__StreamDecoderWriteStatus
fhe_write_cb(const FLAC__StreamDecoder *,
const FLAC__Frame *,
const FLAC__int32 * const [],
void *client_data) {
mxverb(2, FPFX "write cb\n");
((flac_header_extractor_c *)client_data)->done = true;
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static void
fhe_metadata_cb(const FLAC__StreamDecoder *decoder,
const FLAC__StreamMetadata *metadata,
void *client_data) {
flac_header_extractor_c *fhe;
fhe = (flac_header_extractor_c *)client_data;
fhe->num_header_packets = fhe->num_packets;
mxverb(2, FPFX "metadata cb\n");
switch (metadata->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
mxverb(2, FPFX "STREAMINFO block (%u bytes):\n", metadata->length);
mxverb(2, FPFX " sample_rate: %u Hz\n",
metadata->data.stream_info.sample_rate);
fhe->sample_rate = metadata->data.stream_info.sample_rate;
mxverb(2, FPFX " channels: %u\n", metadata->data.stream_info.channels);
fhe->channels = metadata->data.stream_info.channels;
mxverb(2, FPFX " bits_per_sample: %u\n",
metadata->data.stream_info.bits_per_sample);
fhe->bits_per_sample = metadata->data.stream_info.bits_per_sample;
fhe->metadata_parsed = true;
break;
default:
mxverb(2, "%s (%u) block (%u bytes)\n",
metadata->type == FLAC__METADATA_TYPE_PADDING ? "PADDING" :
metadata->type == FLAC__METADATA_TYPE_APPLICATION ?
"APPLICATION" :
metadata->type == FLAC__METADATA_TYPE_SEEKTABLE ? "SEEKTABLE" :
metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT ?
"VORBIS COMMENT" :
metadata->type == FLAC__METADATA_TYPE_CUESHEET ? "CUESHEET" :
"UNDEFINED", metadata->type, metadata->length);
break;
}
}
static void
fhe_error_cb(const FLAC__StreamDecoder *,
FLAC__StreamDecoderErrorStatus status,
void *client_data) {
((flac_header_extractor_c *)client_data)->done = true;
mxverb(2, FPFX "error (%d)\n", (int)status);
}
flac_header_extractor_c::flac_header_extractor_c(const string &file_name,
int64_t _sid):
metadata_parsed(false),
sid(_sid),
num_packets(0),
num_header_packets(0),
done(false) {
file = new mm_file_io_c(file_name);
decoder = FLAC__stream_decoder_new();
if (decoder == NULL)
mxerror(FPFX "FLAC__stream_decoder_new() failed.\n");
#ifdef LEGACY_FLAC
FLAC__stream_decoder_set_client_data(decoder, this);
if (!FLAC__stream_decoder_set_read_callback(decoder, fhe_read_cb))
mxerror(FPFX "Could not set the read callback.\n");
if (!FLAC__stream_decoder_set_write_callback(decoder, fhe_write_cb))
mxerror(FPFX "Could not set the write callback.\n");
if (!FLAC__stream_decoder_set_metadata_callback(decoder, fhe_metadata_cb))
mxerror(FPFX "Could not set the metadata callback.\n");
if (!FLAC__stream_decoder_set_error_callback(decoder, fhe_error_cb))
mxerror(FPFX "Could not set the error callback.\n");
#endif
if (!FLAC__stream_decoder_set_metadata_respond_all(decoder))
mxerror(FPFX "Could not set metadata_respond_all.\n");
#ifdef LEGACY_FLAC
if (FLAC__stream_decoder_init(decoder) !=
FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
#else
if (FLAC__stream_decoder_init_stream(decoder, fhe_read_cb, NULL, NULL, NULL, NULL, fhe_write_cb, fhe_metadata_cb, fhe_error_cb, this) !=
FLAC__STREAM_DECODER_INIT_STATUS_OK)
#endif
mxerror(FPFX "Could not initialize the FLAC decoder.\n");
ogg_sync_init(&oy);
}
flac_header_extractor_c::~flac_header_extractor_c() {
FLAC__stream_decoder_reset(decoder);
FLAC__stream_decoder_delete(decoder);
ogg_sync_clear(&oy);
ogg_stream_clear(&os);
delete file;
}
bool
flac_header_extractor_c::extract() {
int result;
mxverb(2, FPFX "extract\n");
if (!read_page()) {
mxverb(2, FPFX "read_page() failed.\n");
return false;
}
result = (int)FLAC__stream_decoder_process_until_end_of_stream(decoder);
mxverb(2, FPFX "extract, result: %d, mdp: %d, num_header_packets: " LLD "\n",
result, metadata_parsed, num_header_packets);
return metadata_parsed;
}
bool
flac_header_extractor_c::read_page() {
int np, nread;
unsigned char *buf;
while (1) {
np = ogg_sync_pageseek(&oy, &og);
if (np <= 0) {
if (np < 0)
return false;
buf = (unsigned char *)ogg_sync_buffer(&oy, BUFFER_SIZE);
if (!buf)
return false;
if ((nread = file->read(buf, BUFFER_SIZE)) <= 0)
return false;
ogg_sync_wrote(&oy, nread);
} else if (ogg_page_serialno(&og) == sid)
break;
}
if (ogg_page_bos(&og))
ogg_stream_init(&os, sid);
ogg_stream_pagein(&os, &og);
return true;
}
// ------------------------------------------
ogm_a_flac_demuxer_c::ogm_a_flac_demuxer_c(ogm_reader_c *p_reader):
ogm_demuxer_c(p_reader),
flac_header_packets(0), sample_rate(0), channels(0), bits_per_sample(0) {
stype = OGM_STREAM_TYPE_A_FLAC;
}
void
ogm_a_flac_demuxer_c::process_page(int64_t granulepos) {
ogg_packet op;
int i;
while (ogg_stream_packetout(&os, &op) == 1) {
eos |= op.e_o_s;
units_processed++;
if (units_processed <= flac_header_packets)
continue;
for (i = 0; i < (int)nh_packet_data.size(); i++) {
memory_c *mem = nh_packet_data[i]->clone();
reader->reader_packetizers[ptzr]->process(new packet_t(mem, 0));
}
nh_packet_data.clear();
if (-1 == last_granulepos)
reader->reader_packetizers[ptzr]->process(new packet_t(new memory_c(op.packet, op.bytes, false), -1));
else {
reader->reader_packetizers[ptzr]->process(new packet_t(new memory_c(op.packet, op.bytes, false), last_granulepos * 1000000000 / sample_rate));
last_granulepos = granulepos;
}
}
}
void
ogm_a_flac_demuxer_c::process_header_page() {
ogg_packet op;
while ((packet_data.size() < flac_header_packets) && (ogg_stream_packetout(&os, &op) == 1)) {
eos |= op.e_o_s;
packet_data.push_back(clone_memory(op.packet, op.bytes));
}
if (packet_data.size() >= flac_header_packets)
headers_read = true;
while (ogg_stream_packetout(&os, &op) == 1) {
nh_packet_data.push_back(clone_memory(op.packet, op.bytes));
}
}
void
ogm_a_flac_demuxer_c::initialize() {
flac_header_extractor_c fhe(reader->ti.fname, serialno);
if (!fhe.extract())
mxerror("ogm_reader: Could not read the FLAC header packets for stream id " LLD ".\n", (int64_t)track_id);
flac_header_packets = fhe.num_header_packets;
sample_rate = fhe.sample_rate;
channels = fhe.channels;
bits_per_sample = fhe.bits_per_sample;
last_granulepos = 0;
units_processed = 1;
}
generic_packetizer_c *
ogm_a_flac_demuxer_c::create_packetizer(track_info_c &ti) {
unsigned char *buf;
int size, i;
size = 0;
for (i = 1; i < (int)packet_data.size(); i++)
size += packet_data[i]->get_size();
buf = (unsigned char *)safemalloc(size);
size = 0;
for (i = 1; i < (int)packet_data.size(); i++) {
memcpy(&buf[size], packet_data[i]->get(), packet_data[i]->get_size());
size += packet_data[i]->get_size();
}
generic_packetizer_c *ptzr = new flac_packetizer_c(reader, buf, size, ti);
safefree(buf);
mxinfo(FMT_TID "Using the FLAC output module.\n", ti.fname.c_str(), (int64_t)ti.id);
return ptzr;
}
#endif // HAVE_FLAC_FORMAT_H

72
src/input/r_ogm_flac.h Normal file
View File

@ -0,0 +1,72 @@
/*
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: r_ogm.h 3578 2007-08-16 16:30:05Z mosu $
class definitions for the OGG media stream reader
Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#ifndef __R_OGM_FLAC_H
#define __R_OGM_FLAC_H
#include "os.h"
#if defined(HAVE_FLAC_FORMAT_H)
#include <ogg/ogg.h>
#include <FLAC/stream_decoder.h>
#include "mm_io.h"
class flac_header_extractor_c {
public:
FLAC__StreamDecoder *decoder;
bool metadata_parsed;
int channels, sample_rate, bits_per_sample;
mm_io_c *file;
ogg_stream_state os;
ogg_sync_state oy;
ogg_page og;
int64_t sid, num_packets, num_header_packets;
bool done;
public:
flac_header_extractor_c(const string &file_name, int64_t _sid);
~flac_header_extractor_c();
bool extract();
bool read_page();
};
class ogm_a_flac_demuxer_c: public ogm_demuxer_c {
public:
int flac_header_packets, sample_rate, channels, bits_per_sample;
public:
ogm_a_flac_demuxer_c(ogm_reader_c *p_reader);
virtual const char *get_type() {
return "audio";
};
virtual string get_codec() {
return "FLAC";
};
virtual void initialize();
virtual generic_packetizer_c *create_packetizer(track_info_c &ti);
virtual void process_page(int64_t granulepos);
virtual void process_header_page();
};
#endif // HAVE_FLAC_FORMAT_H
#endif // __R_OGM_FLAC_H

View File

@ -32,6 +32,7 @@
#include "p_flac.h"
#include "matroska.h"
#include "checksums.h"
using namespace libmatroska;
flac_packetizer_c::flac_packetizer_c(generic_reader_c *_reader,

View File

@ -46,7 +46,7 @@ T_047X_tags:3f151ff52e43ed1df3c173e5b0c78ee2:passed:20040920-192348
T_048X_chapters_ogmstyle:5ecb42d20d78b4f73fc2340a2e4f0803:passed:20040920-192349
T_049ass:b50e8bc1d9acbe0a5a940e18e4b33cde:passed:20040929-113852
T_050X_ass:6aeb4aef55511282630e9f0e69777c46-d65638e96a393b01deb6d5e132d35552:passed:20040929-113852
T_051ogm:1bbfae553dced1b1fd3578a48ff8d783:passed:20071223-112225
T_051ogm:f76b769f07129431c46c6ce6a759b429:passed:20071223-112225
T_200mp2_from_mp4:4e8078c1fbe5ec97a3a74e1f5aeb255a:passed:20040917-185156
T_201avc_from_mp4_with_par:6c7940e2a22ceeb41599880a8499ab8a:passed:20050125-224528
T_202avc_from_mp4_with_par_bframes:646322197912c18bbeeaec2b6bcdb781:passed:20050125-224635