mkvtoolnix/src/merge/pr_generic.h

501 lines
15 KiB
C++

/*
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 the generic reader and packetizer
Written by Moritz Bunkus <moritz@bunkus.org>.
Modified by Steve Lhomme <steve.lhomme@free.fr>.
*/
#ifndef __PR_GENERIC_H
#define __PR_GENERIC_H
#include "os.h"
#include <deque>
#include <map>
#include <vector>
#include <matroska/KaxAttachments.h>
#include <matroska/KaxBlock.h>
#include <matroska/KaxChapters.h>
#include <matroska/KaxCluster.h>
#include <matroska/KaxTracks.h>
#include <matroska/KaxTags.h>
#include "common_memory.h"
#include "compression.h"
#include "error.h"
#include "mm_io.h"
#include "packet.h"
#include "smart_pointers.h"
#include "timecode_factory.h"
using namespace libmatroska;
using namespace std;
// CUE_STRATEGY_* control the creation of cue entries for a track.
// UNSPECIFIED: is used for command line parsing.
// NONE: don't create any cue entries.
// IFRAMES: Create cue entries for all I frames.
// ALL: Create cue entries for all frames (not really useful).
// SPARSE: Create cue entries for I frames if no video track exists, but
// create at most one cue entries every two seconds. Used for
// audio only files.
enum cue_strategy_e {
CUE_STRATEGY_UNSPECIFIED = -1,
CUE_STRATEGY_NONE,
CUE_STRATEGY_IFRAMES,
CUE_STRATEGY_ALL,
CUE_STRATEGY_SPARSE
};
#define DEFTRACK_TYPE_AUDIO 0
#define DEFTRACK_TYPE_VIDEO 1
#define DEFTRACK_TYPE_SUBS 2
class generic_packetizer_c;
class generic_reader_c;
enum file_status_e {
FILE_STATUS_DONE = 0,
FILE_STATUS_DONE_AND_DRY,
FILE_STATUS_HOLDING,
FILE_STATUS_MOREDATA
};
struct audio_sync_t {
int64_t displacement;
double linear;
audio_sync_t(): displacement(0), linear(0.0) {}
};
enum default_track_priority_e {
DEFAULT_TRACK_PRIOIRTY_NONE = 0,
DEFAULT_TRACK_PRIORITY_FROM_TYPE = 10,
DEFAULT_TRACK_PRIORITY_FROM_SOURCE = 50,
DEFAULT_TRACK_PRIORITY_CMDLINE = 255
};
#define FMT_FN "'%s': "
#define FMT_TID "'%s' track " LLD ": "
struct display_properties_t {
float aspect_ratio;
bool ar_factor;
int width, height;
display_properties_t(): aspect_ratio(0), ar_factor(false), width(0),
height(0) {}
};
struct pixel_crop_t {
int left, top, right, bottom;
pixel_crop_t(): left(0), top(0), right(0), bottom(0) {}
};
class track_info_c {
protected:
bool initialized;
public:
// The track ID.
int64_t id;
// Options used by the readers.
string fname;
bool no_audio, no_video, no_subs, no_buttons;
vector<int64_t> atracks, vtracks, stracks, btracks;
// Options used by the packetizers.
unsigned char *private_data;
int private_size;
map<int64_t, string> all_fourccs;
string fourcc;
map<int64_t, display_properties_t> display_properties;
float aspect_ratio;
int display_width, display_height;
bool aspect_ratio_given, aspect_ratio_is_factor, display_dimensions_given;
map<int64_t, audio_sync_t> audio_syncs; // As given on the command line
audio_sync_t async; // For this very track
map<int64_t, cue_strategy_e> cue_creations; // As given on the command line
cue_strategy_e cues; // For this very track
vector<int64_t> default_track_flags; // As given on the command line
bool default_track; // For this very track
map<int64_t, string> languages; // As given on the command line
string language; // For this very track
map<int64_t, string> sub_charsets; // As given on the command line
string sub_charset; // For this very track
map<int64_t, string> all_tags; // As given on the command line
string tags_file_name; // For this very track
KaxTags *tags; // For this very track
vector<int64_t> aac_is_sbr; // For AAC+/HE-AAC/SBR
map<int64_t, int64_t> packet_delays; // As given on the command line
int64_t packet_delay; // For this very track
map<int64_t, compression_method_e> compression_list; // As given on the cmd line
compression_method_e compression; // For this very track
map<int64_t, string> track_names; // As given on the command line
string track_name; // For this very track
map<int64_t, string> all_ext_timecodes; // As given on the command line
string ext_timecodes; // For this very track
map<int64_t, pixel_crop_t> pixel_crop_list; // As given on the command line
pixel_crop_t pixel_cropping; // For this very track
bool pixel_cropping_specified;
map<int64_t, int64_t> default_durations; // As given on the command line
map<int64_t, int> max_blockadd_ids; // As given on the command line
bool no_chapters, no_attachments, no_tags;
// Some file formats can contain chapters, but for some the charset
// cannot be identified unambiguously (*cough* OGM *cough*).
string chapter_charset;
// The following variables are needed for the broken way of
// syncing audio in AVIs: by prepending it with trash. Thanks to
// the nandub author for this really, really sucky implementation.
uint16_t avi_block_align;
uint32_t avi_samples_per_sec;
uint32_t avi_avg_bytes_per_sec;
uint32_t avi_samples_per_chunk;
vector<int64_t> avi_block_sizes;
bool avi_audio_sync_enabled;
public:
track_info_c();
track_info_c(const track_info_c &src):
initialized(false) {
*this = src;
}
virtual ~track_info_c() {
free_contents();
}
track_info_c &operator =(const track_info_c &src);
virtual void free_contents();
};
#define PTZR(i) reader_packetizers[i]
#define PTZR0 PTZR(0)
#define NPTZR() reader_packetizers.size()
class generic_reader_c {
public:
track_info_c ti;
vector<generic_packetizer_c *> reader_packetizers;
generic_packetizer_c *ptzr_first_packet;
vector<int64_t> requested_track_ids, available_track_ids, used_track_ids;
int64_t max_timecode_seen;
KaxChapters *chapters;
bool appending;
int num_video_tracks, num_audio_tracks, num_subtitle_tracks;
public:
generic_reader_c(track_info_c &_ti);
virtual ~generic_reader_c();
virtual file_status_e read(generic_packetizer_c *ptzr, bool force = false)
= 0;
virtual void read_all();
virtual int get_progress() = 0;
virtual void set_headers();
virtual void set_headers_for_track(int64_t tid);
virtual void identify() = 0;
virtual void create_packetizer(int64_t tid) = 0;
virtual void create_packetizers() {
create_packetizer(0);
}
virtual int add_packetizer(generic_packetizer_c *ptzr);
virtual void set_timecode_offset(int64_t offset);
virtual void check_track_ids_and_packetizers();
virtual void add_requested_track_id(int64_t id);
virtual void add_available_track_ids() {
available_track_ids.push_back(0);
}
virtual int64_t get_queued_bytes();
virtual void flush_packetizers();
protected:
virtual bool demuxing_requested(char type, int64_t id);
};
enum connection_result_e {
CAN_CONNECT_YES,
CAN_CONNECT_NO_FORMAT,
CAN_CONNECT_NO_PARAMETERS
};
#define connect_check_a_samplerate(a, b) \
if ((a) != (b)) { \
error_message = mxsprintf("The sample rate of the two audio tracks is " \
"different: %d and %d", (int)(a), (int)(b)); \
return CAN_CONNECT_NO_PARAMETERS; \
}
#define connect_check_a_channels(a, b) \
if ((a) != (b)) { \
error_message = mxsprintf("The number of channels of the two audio " \
"tracks is different: %d and %d", (int)(a), \
(int)(b)); \
return CAN_CONNECT_NO_PARAMETERS; \
}
#define connect_check_a_bitdepth(a, b) \
if ((a) != (b)) { \
error_message = mxsprintf("The number of bits per sample of the two " \
"audio tracks is different: %d and %d", \
(int)(a), (int)(b)); \
return CAN_CONNECT_NO_PARAMETERS; \
}
#define connect_check_v_width(a, b) \
if ((a) != (b)) { \
error_message = mxsprintf("The width of the two tracks is " \
"different: %d and %d", (int)(a), (int)(b)); \
return CAN_CONNECT_NO_PARAMETERS; \
}
#define connect_check_v_height(a, b) \
if ((a) != (b)) { \
error_message = mxsprintf("The height of the two tracks is " \
"different: %d and %d", (int)(a), (int)(b)); \
return CAN_CONNECT_NO_PARAMETERS; \
}
#define connect_check_codec_id(a, b) \
if ((a) != (b)) { \
error_message = mxsprintf("The CodecID of the two tracks is different: " \
"%s and %s", (a).c_str(), (b).c_str()); \
return CAN_CONNECT_NO_PARAMETERS; \
}
typedef deque<packet_cptr>::iterator packet_cptr_di;
class generic_packetizer_c {
protected:
deque<packet_cptr> packet_queue, deferred_packets;
int64_t initial_displacement;
int64_t m_free_refs, m_next_free_refs, enqueued_bytes;
int64_t safety_last_timecode, safety_last_duration;
KaxTrackEntry *track_entry;
// Header entries. Can be set via set_XXX and will be 'rendered'
// by set_headers().
int hserialno, htrack_type, htrack_min_cache, htrack_max_cache;
int64_t htrack_default_duration;
bool default_duration_forced;
bool default_track_warning_printed;
uint32_t huid;
int htrack_max_add_block_ids;
string hcodec_id;
unsigned char *hcodec_private;
int hcodec_private_length;
float haudio_sampling_freq, haudio_output_sampling_freq;
int haudio_channels, haudio_bit_depth;
int hvideo_pixel_width, hvideo_pixel_height;
int hvideo_display_width, hvideo_display_height;
compression_method_e hcompression;
compressor_ptr compressor;
timecode_factory_c *timecode_factory;
timecode_factory_application_e timecode_factory_application_mode;
int64_t last_cue_timecode;
bool has_been_flushed;
public:
track_info_c ti;
generic_reader_c *reader;
int connected_to;
int64_t correction_timecode_offset;
int64_t append_timecode_offset, max_timecode_seen;
bool relaxed_timecode_checking;
public:
generic_packetizer_c(generic_reader_c *nreader, track_info_c &_ti)
throw (error_c);
virtual ~generic_packetizer_c();
virtual bool contains_gap();
virtual file_status_e read() {
return reader->read(this);
}
inline void add_packet(packet_t *packet) {
add_packet(packet_cptr(packet));
}
virtual void add_packet(packet_cptr packet);
virtual void add_packet2(packet_cptr pack);
virtual void process_deferred_packets();
virtual packet_cptr get_packet();
inline bool packet_available() {
return !packet_queue.empty() && packet_queue.front()->factory_applied;
}
virtual void flush();
virtual int64_t get_smallest_timecode() {
return packet_queue.empty() ? 0x0FFFFFFF : packet_queue.front()->timecode;
}
inline int64_t get_queued_bytes() {
return enqueued_bytes;
}
inline void set_free_refs(int64_t free_refs) {
m_free_refs = m_next_free_refs;
m_next_free_refs = free_refs;
}
inline int64_t get_free_refs() {
return m_free_refs;
}
virtual void set_headers();
virtual void fix_headers();
inline int process(packet_t *packet) {
return process(packet_cptr(packet));
}
virtual int process(packet_cptr packet) = 0;
virtual void dump_debug_info() = 0;
virtual void set_cue_creation(cue_strategy_e create_cue_data) {
ti.cues = create_cue_data;
}
virtual cue_strategy_e get_cue_creation() {
return ti.cues;
}
virtual int64_t get_last_cue_timecode() {
return last_cue_timecode;
}
virtual void set_last_cue_timecode(int64_t timecode) {
last_cue_timecode = timecode;
}
virtual KaxTrackEntry *get_track_entry() {
return track_entry;
}
virtual int get_track_num() {
return hserialno;
}
virtual int64_t get_source_track_num() {
return ti.id;
}
virtual int set_uid(uint32_t uid);
virtual int get_uid() {
return huid;
}
virtual void set_track_type(int type,
timecode_factory_application_e tfa_mode =
TFA_AUTOMATIC);
virtual int get_track_type() {
return htrack_type;
}
virtual void set_language(const string &language);
virtual void set_codec_id(const string &id);
virtual void set_codec_private(const unsigned char *cp, int length);
virtual void set_track_min_cache(int min_cache);
virtual void set_track_max_cache(int max_cache);
virtual void set_track_default_duration(int64_t default_duration);
virtual void set_track_max_additionals(int max_add_block_ids);
virtual int64_t get_track_default_duration();
virtual void set_audio_sampling_freq(float freq);
virtual float get_audio_sampling_freq() {
return haudio_sampling_freq;
}
virtual void set_audio_output_sampling_freq(float freq);
virtual void set_audio_channels(int channels);
virtual void set_audio_bit_depth(int bit_depth);
virtual void set_video_pixel_width(int width);
virtual void set_video_pixel_height(int height);
virtual void set_video_display_width(int width);
virtual void set_video_display_height(int height);
virtual void set_video_aspect_ratio(float ar) {
ti.aspect_ratio = ar;
}
virtual void set_video_pixel_cropping(int left, int top, int right,
int bottom);
virtual void set_as_default_track(int type, int priority);
virtual void set_tag_track_uid();
virtual void set_track_name(const string &name);
virtual void set_default_compression_method(compression_method_e method) {
hcompression = method;
}
inline bool needs_negative_displacement(float) {
return ((initial_displacement < 0) &&
(ti.async.displacement > initial_displacement));
}
inline bool needs_positive_displacement(float duration) {
return ((initial_displacement > 0) &&
(iabs(ti.async.displacement - initial_displacement) >
(duration / 2)));
}
virtual void displace(float by_ns);
virtual void force_duration_on_last_packet();
virtual const char *get_format_name() = 0;
virtual connection_result_e can_connect_to(generic_packetizer_c *src,
string &error_message) = 0;
virtual void connect(generic_packetizer_c *src,
int64_t _append_timecode_offset = -1);
virtual void enable_avi_audio_sync(bool enable) {
ti.avi_audio_sync_enabled = enable;
}
virtual int64_t handle_avi_audio_sync(int64_t num_bytes, bool vbr);
virtual void add_avi_block_size(int64_t block_size) {
if (ti.avi_audio_sync_enabled)
ti.avi_block_sizes.push_back(block_size);
}
virtual void set_displacement_maybe(int64_t displacement);
virtual void apply_factory();
virtual void apply_factory_once(packet_cptr &packet);
virtual void apply_factory_short_queueing(packet_cptr_di &p_start);
virtual void apply_factory_full_queueing(packet_cptr_di &p_start);
protected:
inline bool has_enough_packets() const;
};
extern vector<generic_packetizer_c *> ptzrs_in_header_order;
#endif // __PR_GENERIC_H