mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2025-01-04 09:15:05 +00:00
Rewrite of the OGM reader code.
This commit is contained in:
parent
507c2593c6
commit
ccd91ab84f
1606
src/input/r_ogm.cpp
1606
src/input/r_ogm.cpp
File diff suppressed because it is too large
Load Diff
@ -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
306
src/input/r_ogm_flac.cpp
Normal 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
72
src/input/r_ogm_flac.h
Normal 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
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user