diff --git a/mkvmerge.cpp b/mkvmerge.cpp index dc4a93438..069a4ac02 100644 --- a/mkvmerge.cpp +++ b/mkvmerge.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: mkvmerge.cpp,v 1.16 2003/02/26 08:59:54 mosu Exp $ + \version \$Id: mkvmerge.cpp,v 1.17 2003/02/27 09:35:55 mosu Exp $ \brief command line parameter parsing, looping, output handling \author Moritz Bunkus */ @@ -85,17 +85,18 @@ typedef struct filelist_tag { char *outfile = NULL; filelist_t *input= NULL; int max_blocks_per_cluster = 65535; -int max_ms_per_cluster = 5000; +int max_ms_per_cluster = 1000; float video_fps = -1.0; packet_t **packet_queue = NULL; int num_packets_in_packetq = 0; -KaxSegment kax_segment; -KaxTracks *kax_tracks; -KaxTrackEntry *kax_last_entry; -int track_number = 1; +cluster_helper_c *cluster_helper = NULL; +KaxSegment kax_segment; +KaxTracks *kax_tracks; +KaxTrackEntry *kax_last_entry; +int track_number = 1; StdIOCallback *out; @@ -409,7 +410,6 @@ static void parse_args(int argc, char **argv) { audio_sync_t async; range_t range; char *fourcc, *s; -// vorbis_comment *chapters; noaudio = 0; novideo = 0; @@ -421,7 +421,6 @@ static void parse_args(int argc, char **argv) { async.displacement = 0; async.linear = 1.0; fourcc = NULL; -// chapters = NULL; for (i = 1; i < argc; i++) if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) { @@ -736,70 +735,52 @@ static void parse_args(int argc, char **argv) { }*/ } -static void add_packet_to_packetq(packet_t *pack) { - packet_queue = (packet_t **)realloc(packet_queue, sizeof(packet_t *) * - (num_packets_in_packetq + 1)); - if (packet_queue == NULL) - die("realloc"); - packet_queue[num_packets_in_packetq] = pack; - num_packets_in_packetq++; -} - -static void clear_packetq() { - int i; - packet_t *p; - - for (i = 0; i < num_packets_in_packetq; i++) { - p = packet_queue[i]; - if (p != NULL) { - free(p->data); - delete p->data_buffer; - free(p); - } - } - - num_packets_in_packetq = 0; - free(packet_queue); - packet_queue = NULL; -} - static void write_packetq() { KaxCues dummy_cues; - KaxCluster cluster; KaxBlockGroup *last_group = NULL; - int i; + KaxCluster *cluster; + int i, num_packets; + u_int64_t cluster_timecode; - KaxClusterTimecode &timecode = GetChild(cluster); - *(static_cast(&timecode)) = packet_queue[0]->timestamp; + cluster = cluster_helper->get_cluster(); + cluster_timecode = cluster_helper->get_timecode(); + num_packets = cluster_helper->get_packet_count(); - for (i = 0; i < num_packets_in_packetq; i++) { + for (i = 0; i < num_packets; i++) { packet_t *pack; - pack = packet_queue[i]; + pack = cluster_helper->get_packet(i); if (last_group == NULL) - pack->group = &GetChild(cluster); + pack->group = &GetChild(*cluster); else - pack->group = &GetNextChild(cluster, *last_group); + pack->group = &GetNextChild(*cluster, *last_group); last_group = pack->group; pack->block = &GetChild(*pack->group); pack->data_buffer = new DataBuffer((binary *)pack->data, pack->length); KaxTrackEntry &track_entry = static_cast(*pack->source->track_entry); - pack->block->AddFrame(track_entry, - pack->timestamp - packet_queue[0]->timestamp, + pack->block->AddFrame(track_entry, pack->timestamp - cluster_timecode, *pack->data_buffer); + pack->source->added_packet_to_cluster(pack, cluster_helper); } - cluster.Render(static_cast(*out), dummy_cues); - clear_packetq(); + cluster->Render(static_cast(*out), dummy_cues); + + cluster_helper->release(); } static int write_packet(packet_t *pack) { - add_packet_to_packetq(pack); + u_int64_t timecode; - if (((pack->timestamp - packet_queue[0]->timestamp) > max_ms_per_cluster) || + if (cluster_helper == NULL) + cluster_helper = new cluster_helper_c(); + + cluster_helper->add_packet(pack); + timecode = cluster_helper->get_timecode(); + + if (((pack->timestamp - timecode) > max_ms_per_cluster) || (num_packets_in_packetq > max_blocks_per_cluster)) write_packetq(); diff --git a/p_ac3.cpp b/p_ac3.cpp index e19577dae..c194017b9 100644 --- a/p_ac3.cpp +++ b/p_ac3.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: p_ac3.cpp,v 1.2 2003/02/23 23:23:10 mosu Exp $ + \version \$Id: p_ac3.cpp,v 1.3 2003/02/27 09:35:55 mosu Exp $ \brief AC3 output module \author Moritz Bunkus */ @@ -183,7 +183,8 @@ void ac3_packetizer_c::set_header() { static_cast(*kax_last_entry)); kax_last_entry = track_entry; - serialno = track_number++; + if (serialno == -1) + serialno = track_number++; KaxTrackNumber &tnumber = GetChild(static_cast(*track_entry)); *(static_cast(&tnumber)) = serialno; diff --git a/p_mp3.cpp b/p_mp3.cpp index 1ef6bc99b..3b9d32502 100644 --- a/p_mp3.cpp +++ b/p_mp3.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: p_mp3.cpp,v 1.3 2003/02/19 09:31:24 mosu Exp $ + \version \$Id: p_mp3.cpp,v 1.4 2003/02/27 09:35:55 mosu Exp $ \brief MP3 output module \author Moritz Bunkus */ @@ -172,7 +172,8 @@ void mp3_packetizer_c::set_header() { static_cast(*kax_last_entry)); kax_last_entry = track_entry; - serialno = track_number++; + if (serialno == -1) + serialno = track_number++; KaxTrackNumber &tnumber = GetChild(static_cast(*track_entry)); *(static_cast(&tnumber)) = serialno; diff --git a/p_video.cpp b/p_video.cpp index d898adc9e..991cb37ec 100644 --- a/p_video.cpp +++ b/p_video.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: p_video.cpp,v 1.3 2003/02/25 14:24:43 mosu Exp $ + \version \$Id: p_video.cpp,v 1.4 2003/02/27 09:35:55 mosu Exp $ \brief video output module \author Moritz Bunkus */ @@ -58,9 +58,10 @@ video_packetizer_c::video_packetizer_c(void *pr_data, int pd_size, avi_compat_mode = navi_compat_mode; frames_output = 0; avi_compat_mode = 1; + last_id = 1; + last_keyframe = NULL; set_private_data(pr_data, pd_size); set_header(); -// add_index(serialno); } void video_packetizer_c::set_header() { @@ -77,7 +78,8 @@ void video_packetizer_c::set_header() { static_cast(*kax_last_entry)); kax_last_entry = track_entry; - serialno = track_number++; + if (serialno == -1) + serialno = track_number++; KaxTrackNumber &tnumber = GetChild(static_cast(*track_entry)); *(static_cast(&tnumber)) = serialno; @@ -123,7 +125,12 @@ int video_packetizer_c::process(char *buf, int size, int num_frames, if ((packetno >= range.start) && ((range.end == 0) || (packetno < range.end))) { - add_packet(buf, size, (u_int64_t)(1000.0 * frames_output / fps), key); + if (key) + last_id = add_packet(buf, size, + (u_int64_t)(1000.0 * frames_output / fps)); + else + add_packet(buf, size, (u_int64_t)(1000.0 * frames_output / fps), + last_id); frames_output += num_frames; } packetno++; @@ -135,3 +142,14 @@ video_packetizer_c::~video_packetizer_c() { if (tempbuf != NULL) free(tempbuf); } + +void video_packetizer_c::added_packet_to_cluster(packet_t *packet, + cluster_helper_c *helper) { + if (packet->ref == 0) { // this is a keyframe + if (last_helper) + last_helper->release(); + last_helper = helper; + last_keyframe = packet; + last_helper->add_ref(); + } +} diff --git a/p_video.h b/p_video.h index 754b62328..10b675cb5 100644 --- a/p_video.h +++ b/p_video.h @@ -13,7 +13,7 @@ /*! \file - \version \$Id: p_video.h,v 1.3 2003/02/26 19:20:26 mosu Exp $ + \version \$Id: p_video.h,v 1.4 2003/02/27 09:35:55 mosu Exp $ \brief class definition for the video output module \author Moritz Bunkus */ @@ -25,17 +25,18 @@ #include "queue.h" class video_packetizer_c: public q_c { - private: - char codec[5]; - double fps; - int width, height; - int bpp; - int max_frame_size; - int packetno, frames_output; - char *tempbuf; - int avi_compat_mode; - range_t range; - public: +private: + char codec[5]; + double fps; + int width, height, bpp, max_frame_size, packetno; + int frames_output; + char *tempbuf; + int avi_compat_mode; + range_t range; + u_int64_t last_id; + packet_t *last_keyframe; + cluster_helper_c *last_helper; +public: video_packetizer_c(void *, int, char *, double, int, int, int, int, audio_sync_t *, range_t *nrange, int) throw (error_c); virtual ~video_packetizer_c(); @@ -43,6 +44,8 @@ class video_packetizer_c: public q_c { virtual int process(char *buf, int size, int num_frames, int key, int last_frame); virtual void set_header(); + virtual void added_packet_to_cluster(packet_t *packet, + cluster_helper_c *helper); }; #endif diff --git a/pr_generic.cpp b/pr_generic.cpp index 2f25cd627..fa277dded 100644 --- a/pr_generic.cpp +++ b/pr_generic.cpp @@ -13,13 +13,16 @@ /*! \file - \version \$Id: pr_generic.cpp,v 1.2 2003/02/24 12:31:17 mosu Exp $ + \version \$Id: pr_generic.cpp,v 1.3 2003/02/27 09:35:55 mosu Exp $ \brief functions common for all readers/packetizers \author Moritz Bunkus */ #include +#include "KaxCluster.h" +#include "KaxClusterData.h" + #include "pr_generic.h" generic_packetizer_c::generic_packetizer_c() { @@ -44,6 +47,10 @@ void generic_packetizer_c::set_private_data(void *data, int size) { private_data_size = size; } +void generic_packetizer_c::added_packet_to_cluster(packet_t *, + cluster_helper_c *) { +} + //-------------------------------------------------------------------- generic_reader_c::generic_reader_c() { @@ -51,3 +58,83 @@ generic_reader_c::generic_reader_c() { generic_reader_c::~generic_reader_c() { } + +//-------------------------------------------------------------------- + +cluster_helper_c::cluster_helper_c(KaxCluster *ncluster) { + num_packets = 0; + packet_q = NULL; + refcount = 1; + if (ncluster == NULL) + cluster = new KaxCluster(); + else + cluster = ncluster; +} + +cluster_helper_c::~cluster_helper_c() { + int i; + + if (packet_q) { + for (i = 0; i < num_packets; i++) { + free(packet_q[i]->data); + delete packet_q[i]->data_buffer; + free(packet_q[i]); + } + free(packet_q); + } + if (cluster) + delete cluster; +} + +KaxCluster *cluster_helper_c::get_cluster() { + return cluster; +} + +KaxCluster &cluster_helper_c::operator *() { + return *cluster; +} + +int cluster_helper_c::add_ref() { + refcount++; + return refcount; +} + +int cluster_helper_c::release() { + int ref; + refcount--; + ref = refcount; + if (refcount == 0) + delete this; + return ref; +} + +void cluster_helper_c::add_packet(packet_t *packet) { + packet_q = (packet_t **)realloc(packet_q, sizeof(packet_t *) * + (num_packets + 1)); + if (packet_q == NULL) + die("realloc"); + packet_q[num_packets] = packet; + if (num_packets == 0) { + KaxClusterTimecode &timecode = GetChild(*cluster); + *(static_cast(&timecode)) = packet->timestamp; + } + num_packets++; +} + +u_int64_t cluster_helper_c::get_timecode() { + if (packet_q == NULL) + return 0; + return packet_q[0]->timestamp; +} + +packet_t *cluster_helper_c::get_packet(int num) { + if (packet_q == NULL) + return NULL; + if ((num < 0) || (num > num_packets)) + return NULL; + return packet_q[num]; +} + +int cluster_helper_c::get_packet_count() { + return num_packets; +} diff --git a/pr_generic.h b/pr_generic.h index 5b2e19d2b..eec5c16bc 100644 --- a/pr_generic.h +++ b/pr_generic.h @@ -13,7 +13,7 @@ /*! \file - \version \$Id: pr_generic.h,v 1.4 2003/02/26 19:20:26 mosu Exp $ + \version \$Id: pr_generic.h,v 1.5 2003/02/27 09:35:55 mosu Exp $ \brief class definition for the generic reader and packetizer \author Moritz Bunkus */ @@ -25,21 +25,44 @@ #include "common.h" #include "KaxBlock.h" +#include "KaxCluster.h" #include "KaxTracks.h" -extern LIBMATROSKA_NAMESPACE::KaxTracks *kax_tracks; -extern LIBMATROSKA_NAMESPACE::KaxTrackEntry *kax_last_entry; +using namespace LIBMATROSKA_NAMESPACE; + +extern KaxTracks *kax_tracks; +extern KaxTrackEntry *kax_last_entry; extern int track_number; struct packet_t; +typedef class cluster_helper_c { +private: + int refcount; + KaxCluster *cluster; + packet_t **packet_q; + int num_packets; +public: + cluster_helper_c(KaxCluster *ncluster = NULL); + virtual ~cluster_helper_c(); + + KaxCluster *get_cluster(); + int add_ref(); + void add_packet(packet_t *packet); + u_int64_t get_timecode(); + packet_t *get_packet(int num); + int get_packet_count(); + int release(); + KaxCluster &operator *(); +} cluster_helper_c; + typedef class generic_packetizer_c { - protected: +protected: int serialno; void *private_data; int private_data_size; - public: - LIBMATROSKA_NAMESPACE::KaxTrackEntry *track_entry; +public: + KaxTrackEntry *track_entry; generic_packetizer_c(); virtual ~generic_packetizer_c(); @@ -48,10 +71,12 @@ typedef class generic_packetizer_c { virtual void set_header() = 0; virtual stamp_t get_smallest_timestamp() = 0; virtual void set_private_data(void *data, int size); + virtual void added_packet_to_cluster(packet_t *packet, + cluster_helper_c *helper); } generic_packetizer_c; typedef class generic_reader_c { - public: +public: generic_reader_c(); virtual ~generic_reader_c(); virtual int read() = 0; @@ -61,15 +86,14 @@ typedef class generic_reader_c { } generic_reader_c; typedef struct packet_t { - LIBMATROSKA_NAMESPACE::DataBuffer *data_buffer; - LIBMATROSKA_NAMESPACE::KaxBlockGroup *group; - LIBMATROSKA_NAMESPACE::KaxBlock *block; - LIBMATROSKA_NAMESPACE::KaxCluster *cluster; - char *data; - int length; - u_int64_t timestamp; - u_int64_t id, ref; - generic_packetizer_c *source; + DataBuffer *data_buffer; + KaxBlockGroup *group; + KaxBlock *block; + KaxCluster *cluster; + char *data; + int length; + u_int64_t timestamp, id, ref; + generic_packetizer_c *source; } packet_t; #endif // __PR_GENERIC_H diff --git a/queue.cpp b/queue.cpp index 62d6e6c92..95162ca1b 100644 --- a/queue.cpp +++ b/queue.cpp @@ -13,7 +13,7 @@ /*! \file - \version \$Id: queue.cpp,v 1.4 2003/02/26 19:20:26 mosu Exp $ + \version \$Id: queue.cpp,v 1.5 2003/02/27 09:35:55 mosu Exp $ \brief packet queueing class used by every packetizer \author Moritz Bunkus */ @@ -58,7 +58,7 @@ u_int64_t q_c::add_packet(char *data, int length, u_int64_t timestamp, q_page_t *qpage; if (data == NULL) - return -1; + return 0; qpage = (q_page_t *)malloc(sizeof(q_page_t)); if (qpage == NULL) die("malloc");