diff --git a/src/input/r_matroska.cpp b/src/input/r_matroska.cpp index 85b4cdf78..01ecbe50a 100644 --- a/src/input/r_matroska.cpp +++ b/src/input/r_matroska.cpp @@ -86,17 +86,18 @@ using namespace std; using namespace libmatroska; #define PFX "matroska_reader: " -#define MAP_TRACK_TYPE(c) ((c) == 'a' ? track_audio : \ - (c) == 'b' ? track_buttons : \ - (c) == 'v' ? track_video : track_subtitle) -#define MAP_TRACK_TYPE_STRING(c) ((c) == 'a' ? "audio" : \ - (c) == 'b' ? "buttons" : \ - (c) == 'v' ? "video" : "subtitle") +#define MAP_TRACK_TYPE(c) ( (c) == 'a' ? track_audio \ + : (c) == 'b' ? track_buttons \ + : (c) == 'v' ? track_video \ + : track_subtitle) +#define MAP_TRACK_TYPE_STRING(c) ( (c) == '?' ? "unknown" \ + : (c) == 'a' ? "audio" \ + : (c) == 'b' ? "buttons" \ + : (c) == 'v' ? "video" \ + : "subtitle") #define in_parent(p) \ - (!p->IsFiniteSize() || \ - (in->getFilePointer() < \ - (p->GetElementPosition() + p->HeadSize() + p->GetSize()))) + (!p->IsFiniteSize() || (in->getFilePointer() < (p->GetElementPosition() + p->HeadSize() + p->GetSize()))) // }}} @@ -104,6 +105,8 @@ using namespace libmatroska; // {{{ FUNCTION kax_reader::probe_file() +#define MAGIC_MKV 0x1a45dfa3 + /* Probes a file by simply comparing the first four bytes to the EBML head signature. @@ -113,7 +116,7 @@ kax_reader_c::probe_file(mm_io_c *io, int64_t size) { unsigned char data[4]; - if (size < 4) + if (4 > size) return 0; try { io->setFilePointer(0, seek_beginning); @@ -123,8 +126,7 @@ kax_reader_c::probe_file(mm_io_c *io, } catch (...) { return 0; } - if ((data[0] != 0x1A) || (data[1] != 0x45) || - (data[2] != 0xDF) || (data[3] != 0xA3)) + if (get_uint32_be(data) != MAGIC_MKV) return 0; return 1; } @@ -135,11 +137,10 @@ kax_reader_c::probe_file(mm_io_c *io, kax_reader_c::kax_reader_c(track_info_c &_ti) throw (error_c): - generic_reader_c(_ti) { - - segment_duration = 0; - first_timecode = -1; - writing_app_ver = -1; + generic_reader_c(_ti), + segment_duration(0), + first_timecode(-1), + writing_app_ver(-1) { if (!read_headers()) throw error_c(PFX "Failed to read the headers."); @@ -155,17 +156,12 @@ kax_reader_c::~kax_reader_c() { int i; for (i = 0; i < tracks.size(); i++) - if (tracks[i] != NULL) - delete tracks[i]; + delete tracks[i]; - if (saved_l1 != NULL) - delete saved_l1; - if (in != NULL) - delete in; - if (es != NULL) - delete es; - if (segment != NULL) - delete segment; + delete saved_l1; + delete in; + delete es; + delete segment; } // }}} @@ -180,7 +176,7 @@ kax_reader_c::packets_available() { if ((-1 != tracks[i]->ptzr) && !PTZR(tracks[i]->ptzr)->packet_available()) return 0; - if (tracks.size() == 0) + if (tracks.empty()) return 0; return 1; @@ -188,14 +184,12 @@ kax_reader_c::packets_available() { kax_track_t * kax_reader_c::new_kax_track() { - kax_track_t *t; - - t = new kax_track_t; - tracks.push_back(t); - // Set some default values. + kax_track_t *t = new kax_track_t; t->default_track = true; - t->ptzr = -1; + t->ptzr = -1; + + tracks.push_back(t); return t; } @@ -206,8 +200,7 @@ kax_reader_c::find_track_by_num(uint64_t n, int i; for (i = 0; i < tracks.size(); i++) - if ((tracks[i] != NULL) && (tracks[i]->tnum == n) && - (tracks[i] != c)) + if ((NULL != tracks[i]) && (tracks[i]->tnum == n) && (tracks[i] != c)) return tracks[i]; return NULL; @@ -219,8 +212,7 @@ kax_reader_c::find_track_by_uid(uint64_t uid, int i; for (i = 0; i < tracks.size(); i++) - if ((tracks[i] != NULL) && (tracks[i]->tuid == uid) && - (tracks[i] != c)) + if ((NULL != tracks[i]) && (tracks[i]->tuid == uid) && (tracks[i] != c)) return tracks[i]; return NULL; @@ -234,8 +226,6 @@ void kax_reader_c::verify_tracks() { int tnum, u; kax_track_t *t; - alBITMAPINFOHEADER *bih; - alWAVEFORMATEX *wfe; for (tnum = 0; tnum < tracks.size(); tnum++) { t = tracks[tnum]; @@ -246,11 +236,9 @@ kax_reader_c::verify_tracks() { continue; t->ok = 0; - if (t->private_data != NULL) { - memory_cptr private_data(new memory_c((unsigned char *)t->private_data, - t->private_size, true)); - t->content_decoder.reverse(private_data, - CONTENT_ENCODING_SCOPE_CODECPRIVATE); + if (NULL != t->private_data) { + memory_cptr private_data(new memory_c((unsigned char *)t->private_data, t->private_size, true)); + t->content_decoder.reverse(private_data, CONTENT_ENCODING_SCOPE_CODECPRIVATE); private_data->lock(); t->private_data = private_data->get(); t->private_size = private_data->get_size(); @@ -261,56 +249,50 @@ kax_reader_c::verify_tracks() { if (t->codec_id == "") continue; if (t->codec_id == MKV_V_MSCOMP) { - if ((t->private_data == NULL) || - (t->private_size < sizeof(alBITMAPINFOHEADER))) { + if ((NULL == t->private_data) || (sizeof(alBITMAPINFOHEADER) > t->private_size)) { if (verbose) - mxwarn(PFX "CodecID for track " LLU " is '" MKV_V_MSCOMP - "', but there was no BITMAPINFOHEADER struct present. " - "Therefore we don't have a FourCC to identify the video " - "codec used.\n", t->tnum); + mxwarn(PFX "CodecID for track " LLU " is '" MKV_V_MSCOMP "', but there was no BITMAPINFOHEADER struct present. " + "Therefore we don't have a FourCC to identify the video codec used.\n", t->tnum); continue; + } else { - t->ms_compat = 1; + t->ms_compat = 1; + alBITMAPINFOHEADER *bih = (alBITMAPINFOHEADER *)t->private_data; + u = get_uint32_le(&bih->bi_width); - bih = (alBITMAPINFOHEADER *)t->private_data; - - u = get_uint32_le(&bih->bi_width); if (t->v_width != u) { if (verbose) - mxwarn(PFX "(MS compatibility mode, track " LLU ") Matrosa " - "says video width is " LLU ", but the BITMAPINFOHEADER " - "says %u.\n", t->tnum, t->v_width, u); - if (t->v_width == 0) + mxwarn(PFX "(MS compatibility mode, track " LLU ") Matrosa says video width is " LLU ", but the BITMAPINFOHEADER says %u.\n", t->tnum, t->v_width, u); + if (0 == t->v_width) t->v_width = u; } u = get_uint32_le(&bih->bi_height); if (t->v_height != u) { if (verbose) - mxwarn(PFX "(MS compatibility mode, track " LLU ") Matrosa " - "video height is " LLU ", but the BITMAPINFOHEADER " - "says %u.\n", t->tnum, t->v_height, u); - if (t->v_height == 0) + mxwarn(PFX "(MS compatibility mode, track " LLU ") Matrosa video height is " LLU ", but the BITMAPINFOHEADER says %u.\n", t->tnum, t->v_height, u); + if (0 == t->v_height) t->v_height = u; } 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); + 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 (0 == t->v_width) { if (verbose) mxwarn(PFX "The width for track " LLU " was not set.\n", t->tnum); continue; } - if (t->v_height == 0) { + + if (0 == t->v_height) { if (verbose) mxwarn(PFX "The height for track " LLU " was not set.\n", t->tnum); continue; @@ -324,59 +306,51 @@ kax_reader_c::verify_tracks() { case 'a': // audio track if (t->codec_id == "") continue; + if (t->codec_id == MKV_A_ACM) { - if ((t->private_data == NULL) || - (t->private_size < sizeof(alWAVEFORMATEX))) { + if ((NULL == t->private_data) || (sizeof(alWAVEFORMATEX) > t->private_size)) { if (verbose) - mxwarn(PFX "CodecID for track " LLU " is '" - MKV_A_ACM "', but there was no WAVEFORMATEX struct " - "present. Therefore we don't have a format ID to " - "identify the audio codec used.\n", t->tnum); + mxwarn(PFX "CodecID for track " LLU " is '" MKV_A_ACM "', but there was no WAVEFORMATEX struct present. " + "Therefore we don't have a format ID to identify the audio codec used.\n", t->tnum); continue; } else { - t->ms_compat = 1; + t->ms_compat = 1; + alWAVEFORMATEX *wfe = (alWAVEFORMATEX *)t->private_data; + t->a_formattag = get_uint16_le(&wfe->w_format_tag); + u = get_uint32_le(&wfe->n_samples_per_sec); - wfe = (alWAVEFORMATEX *)t->private_data; - t->a_formattag = get_uint16_le(&wfe->w_format_tag); - u = get_uint32_le(&wfe->n_samples_per_sec); if (((uint32_t)t->a_sfreq) != u) { if (verbose) - mxwarn(PFX "(MS compatibility mode for track " LLU - ") Matroska says that there are %u samples " - "per second, but WAVEFORMATEX says that there are " - "%u.\n", t->tnum, (uint32_t)t->a_sfreq, u); - if (t->a_sfreq == 0.0) + mxwarn(PFX "(MS compatibility mode for track " LLU ") Matroska says that there are %u samples per second, but WAVEFORMATEX says that there are %u.\n", + t->tnum, (uint32_t)t->a_sfreq, u); + if (0.0 == t->a_sfreq) t->a_sfreq = (float)u; } u = get_uint16_le(&wfe->n_channels); if (t->a_channels != u) { if (verbose) - mxwarn(PFX "(MS compatibility mode for " - "track " LLU ") Matroska says that there are " LLU " " - "channels, but the WAVEFORMATEX says that there are " - "%u.\n", t->tnum, t->a_channels, u); - if (t->a_channels == 0) + mxwarn(PFX "(MS compatibility mode for track " LLU ") Matroska says that there are " LLU "channels, but the WAVEFORMATEX says that there are %u.\n", + t->tnum, t->a_channels, u); + if (0 == t->a_channels) t->a_channels = u; } u = get_uint16_le(&wfe->w_bits_per_sample); if (t->a_bps != u) { - if (verbose && (t->a_formattag == 0x0001 || t->a_formattag == 0x0003)) - mxwarn(PFX "(MS compatibility mode for track " LLU - ") Matroska says that there are " LLU " bits per" - " sample, but the WAVEFORMATEX says that there are %u." - "\n", t->tnum, t->a_bps, u); - if (t->a_bps == 0) + if (verbose && ((0x0001 == t->a_formattag) || (0x0003 == t->a_formattag))) + mxwarn(PFX "(MS compatibility mode for track " LLU ") Matroska says that there are " LLU " bits per sample, " + "but the WAVEFORMATEX says that there are %u.\n", t->tnum, t->a_bps, u); + if (0 == t->a_bps) t->a_bps = u; } } + } else { if (starts_with(t->codec_id, MKV_A_MP3, strlen(MKV_A_MP3) - 1)) t->a_formattag = 0x0055; - else if (starts_with(t->codec_id, MKV_A_AC3, strlen(MKV_A_AC3)) || - (t->codec_id == MKV_A_EAC3)) + else if (starts_with(t->codec_id, MKV_A_AC3, strlen(MKV_A_AC3)) || (t->codec_id == MKV_A_EAC3)) t->a_formattag = 0x2000; else if (t->codec_id == MKV_A_DTS) t->a_formattag = 0x2001; @@ -385,24 +359,21 @@ kax_reader_c::verify_tracks() { else if (t->codec_id == MKV_A_PCM_FLOAT) t->a_formattag = 0x0003; else if (t->codec_id == MKV_A_VORBIS) { - if (t->private_data == NULL) { + if (NULL == t->private_data) { if (verbose) - mxwarn(PFX "CodecID for track " LLU " is " - "'A_VORBIS', but there are no header packets present.", - t->tnum); + mxwarn(PFX "CodecID for track " LLU " is 'A_VORBIS', but there are no header packets present.", t->tnum); continue; } try { - memory_cptr temp(new memory_c((unsigned char *)t->private_data, - t->private_size, false)); + memory_cptr temp(new memory_c((unsigned char *)t->private_data, t->private_size, false)); vector 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->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(); @@ -422,30 +393,27 @@ kax_reader_c::verify_tracks() { // are used and add up to too large a value. The result is the // usual "timecode < last_timecode" message. // Workaround: do not use durations for such tracks. - if ((writing_app == "mkvmerge") && (writing_app_ver != -1) && - (writing_app_ver < 0x07000000)) + if ((writing_app == "mkvmerge") && (-1 != writing_app_ver) && (0x07000000 > writing_app_ver)) t->ignore_duration_hack = true; - } else if ((t->codec_id == MKV_A_AAC_2MAIN) || - (t->codec_id == MKV_A_AAC_2LC) || - (t->codec_id == MKV_A_AAC_2SSR) || - (t->codec_id == MKV_A_AAC_4MAIN) || - (t->codec_id == MKV_A_AAC_4LC) || - (t->codec_id == MKV_A_AAC_4SSR) || - (t->codec_id == MKV_A_AAC_4LTP) || - (t->codec_id == MKV_A_AAC_2SBR) || - (t->codec_id == MKV_A_AAC_4SBR) || - (t->codec_id == MKV_A_AAC)) + } else if ( (t->codec_id == MKV_A_AAC_2MAIN) + || (t->codec_id == MKV_A_AAC_2LC) + || (t->codec_id == MKV_A_AAC_2SSR) + || (t->codec_id == MKV_A_AAC_4MAIN) + || (t->codec_id == MKV_A_AAC_4LC) + || (t->codec_id == MKV_A_AAC_4SSR) + || (t->codec_id == MKV_A_AAC_4LTP) + || (t->codec_id == MKV_A_AAC_2SBR) + || (t->codec_id == MKV_A_AAC_4SBR) + || (t->codec_id == MKV_A_AAC)) t->a_formattag = FOURCC('M', 'P', '4', 'A'); - else if (starts_with(t->codec_id, MKV_A_REAL_COOK, - strlen("A_REAL/"))) + else if (starts_with(t->codec_id, MKV_A_REAL_COOK, strlen("A_REAL/"))) t->a_formattag = FOURCC('r', 'e', 'a', 'l'); else if (t->codec_id == MKV_A_FLAC) { #if defined(HAVE_FLAC_FORMAT_H) t->a_formattag = FOURCC('f', 'L', 'a', 'C'); #else - mxwarn(PFX "mkvmerge was not compiled with FLAC support. " - "Ignoring track " LLU ".\n", t->tnum); + mxwarn(PFX "mkvmerge was not compiled with FLAC support. Ignoring track " LLU ".\n", t->tnum); continue; #endif } else if (t->codec_id == MKV_A_TTA) @@ -454,10 +422,10 @@ kax_reader_c::verify_tracks() { t->a_formattag = FOURCC('W', 'V', 'P', '4'); } - if (t->a_sfreq == 0.0) + if (0.0 == t->a_sfreq) t->a_sfreq = 8000.0; - if (t->a_channels == 0) + if (0 == t->a_channels) t->a_channels = 1; // This track seems to be ok. @@ -467,15 +435,14 @@ kax_reader_c::verify_tracks() { case 's': if (t->codec_id == MKV_S_VOBSUB) { - if (t->private_data == NULL) { + if (NULL == t->private_data) { if (verbose) - mxwarn(PFX "CodecID for track " LLU " is '%s', but there was no " - "private data found.\n", t->tnum, t->codec_id.c_str()); + mxwarn(PFX "CodecID for track " LLU " is '%s', but there was no private data found.\n", t->tnum, t->codec_id.c_str()); continue; } - } - else if (t->codec_id == MKV_S_KATE) { - if (t->private_data == NULL) { + + } else if (t->codec_id == MKV_S_KATE) { + if (NULL == t->private_data) { if (verbose) mxwarn(PFX "CodecID for track " LLU " is '%s', but there was no private data found.\n", t->tnum, t->codec_id.c_str()); continue; @@ -487,8 +454,7 @@ kax_reader_c::verify_tracks() { case 'b': if (t->codec_id != MKV_B_VOBBTN) { if (verbose) - mxwarn(PFX "CodecID '%s' for track " LLU " is unknown.\n", - t->codec_id.c_str(), t->tnum); + mxwarn(PFX "CodecID '%s' for track " LLU " is unknown.\n", t->codec_id.c_str(), t->tnum); continue; } t->ok = 1; @@ -496,12 +462,11 @@ kax_reader_c::verify_tracks() { default: // unknown track type!? error in demuxer... if (verbose) - mxwarn(PFX "matroska_reader: unknown " - "demuxer type for track " LLU ": '%c'\n", t->tnum, t->type); + mxwarn(PFX "matroska_reader: unknown demuxer type for track " LLU ": '%c'\n", t->tnum, t->type); continue; } - if (t->ok && (verbose > 1)) + if (t->ok && (1 < verbose)) mxinfo(PFX "Track " LLU " seems to be ok.\n", t->tnum); } } @@ -514,91 +479,87 @@ void kax_reader_c::handle_attachments(mm_io_c *io, EbmlElement *l0, int64_t pos) { - KaxAttachments *atts; - KaxAttached *att; - EbmlElement *l1, *l2; - UTFstring description, name; - int upper_lvl_el, i, k; - string mime_type; - int64_t size, id; - unsigned char *data; - bool found; + bool found = false; - found = false; + int i; for (i = 0; i < handled_attachments.size(); i++) if (handled_attachments[i] == pos) { found = true; break; } + if (found) return; + handled_attachments.push_back(pos); - data = NULL; io->save_pos(pos); - l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, - true); + int upper_lvl_el; + EbmlElement *l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true); + + if ((NULL != l1) && (EbmlId(*l1) == KaxAttachments::ClassInfos.GlobalId)) { + KaxAttachments *atts = (KaxAttachments *)l1; + EbmlElement *l2 = NULL; + upper_lvl_el = 0; + + atts->Read(*es, KaxAttachments::ClassInfos.Context, upper_lvl_el, l2, true); - if ((l1 != NULL) && (EbmlId(*l1) == KaxAttachments::ClassInfos.GlobalId)) { - atts = (KaxAttachments *)l1; - l2 = NULL; - upper_lvl_el = 0; - atts->Read(*es, KaxAttachments::ClassInfos.Context, upper_lvl_el, l2, - true); for (i = 0; i < atts->ListSize(); i++) { - att = (KaxAttached *)(*atts)[i]; + KaxAttached *att = (KaxAttached *)(*atts)[i]; + if (EbmlId(*att) == KaxAttached::ClassInfos.GlobalId) { - name = L""; - mime_type = ""; - description = L""; - size = -1; - id = -1; + UTFstring name = L""; + UTFstring description = L""; + string mime_type = ""; + int64_t size = -1; + int64_t id = -1; + unsigned char *data = NULL; + int k; for (k = 0; k < att->ListSize(); k++) { l2 = (*att)[k]; if (EbmlId(*l2) == KaxFileName::ClassInfos.GlobalId) { KaxFileName &fname = *static_cast(l2); - name = UTFstring(fname); + name = UTFstring(fname); } else if (EbmlId(*l2) == KaxFileDescription::ClassInfos.GlobalId) { KaxFileDescription &fdesc = *static_cast(l2); - description = UTFstring(fdesc); + description = UTFstring(fdesc); } else if (EbmlId(*l2) == KaxMimeType::ClassInfos.GlobalId) { KaxMimeType &mtype = *static_cast(l2); - mime_type = string(mtype); + mime_type = string(mtype); } else if (EbmlId(*l2) == KaxFileUID::ClassInfos.GlobalId) { KaxFileUID &fuid = *static_cast(l2); - id = uint64(fuid); + id = uint64(fuid); } else if (EbmlId(*l2) == KaxFileData::ClassInfos.GlobalId) { KaxFileData &fdata = *static_cast(l2); - size = fdata.GetSize(); - data = (unsigned char *)fdata.GetBuffer(); + size = fdata.GetSize(); + data = (unsigned char *)fdata.GetBuffer(); } } - if ((id != -1) && (size != -1) && (mime_type.length() > 0) && - (name.length() > 0)) { + if ((-1 != id) && (-1 != size) && !mime_type.empty() && (0 < name.length())) { attachment_t matt; - matt.name = UTFstring_to_cstrutf8(name); - matt.mime_type = mime_type; - matt.description = UTFstring_to_cstrutf8(description); - matt.id = id; - matt.data = counted_ptr(new buffer_t); - matt.data->m_size = size; + matt.name = UTFstring_to_cstrutf8(name); + matt.mime_type = mime_type; + matt.description = UTFstring_to_cstrutf8(description); + matt.id = id; + matt.data = counted_ptr(new buffer_t); + matt.data->m_size = size; matt.data->m_buffer = (unsigned char *)safememdup(data, size); + add_attachment(matt); } } } + } - delete l1; - } else if (l1 != NULL) - delete l1; + delete l1; io->restore_pos(); } @@ -607,44 +568,43 @@ void kax_reader_c::handle_chapters(mm_io_c *io, EbmlElement *l0, int64_t pos) { - KaxChapters *tmp_chapters; - EbmlElement *l1, *l2; - int upper_lvl_el, i; - bool found; - if (ti.no_chapters) return; - found = false; + bool found = false; + int i; for (i = 0; i < handled_chapters.size(); i++) if (handled_chapters[i] == pos) { found = true; break; } + if (found) return; + handled_chapters.push_back(pos); + int upper_lvl_el = 0; io->save_pos(pos); - l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, - true); + EbmlElement *l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true); if ((l1 != NULL) && is_id(l1, KaxChapters)) { - tmp_chapters = static_cast(l1); - l2 = NULL; - upper_lvl_el = 0; - tmp_chapters->Read(*es, KaxChapters::ClassInfos.Context, upper_lvl_el, - l2, true); + KaxChapters *tmp_chapters = static_cast(l1); + EbmlElement *l2 = NULL; + upper_lvl_el = 0; - if (chapters == NULL) + tmp_chapters->Read(*es, KaxChapters::ClassInfos.Context, upper_lvl_el, l2, true); + + if (NULL == chapters) chapters = new KaxChapters; + for (i = 0; i < tmp_chapters->ListSize(); i++) chapters->PushElement(*(*tmp_chapters)[i]); tmp_chapters->RemoveAll(); - delete l1; - } else if (l1 != NULL) - delete l1; + } + + delete l1; io->restore_pos(); } @@ -653,36 +613,31 @@ void kax_reader_c::handle_tags(mm_io_c *io, EbmlElement *l0, int64_t pos) { - KaxTags *tags; - KaxTag *tag; - KaxTagTargets *target; - KaxTagTrackUID *tuid; - EbmlElement *l1, *l2; - int upper_lvl_el, tid, i; - bool is_global, found, contains_tag; - kax_track_t *track; - if (ti.no_tags) return; - found = false; + bool found = false; + int i; for (i = 0; i < handled_tags.size(); i++) if (handled_tags[i] == pos) { found = true; break; } + if (found) return; + handled_tags.push_back(pos); + int upper_lvl_el = 0; io->save_pos(pos); - l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, - true); + EbmlElement *l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true); + + if ((NULL != l1) && (EbmlId(*l1) == KaxTags::ClassInfos.GlobalId)) { + KaxTags *tags = (KaxTags *)l1; + EbmlElement *l2 = NULL; + upper_lvl_el = 0; - if ((l1 != NULL) && (EbmlId(*l1) == KaxTags::ClassInfos.GlobalId)) { - tags = (KaxTags *)l1; - l2 = NULL; - upper_lvl_el = 0; tags->Read(*es, KaxTags::ClassInfos.Context, upper_lvl_el, l2, true); while (tags->ListSize() > 0) { @@ -692,27 +647,31 @@ kax_reader_c::handle_tags(mm_io_c *io, continue; } - is_global = false; - tid = -1; - tag = static_cast((*tags)[0]); - target = FINDFIRST(tag, KaxTagTargets); - if (target != NULL) { - tuid = FINDFIRST(target, KaxTagTrackUID); - if (tuid == NULL) + bool is_global = false; + KaxTag *tag = static_cast((*tags)[0]); + KaxTagTargets *target = FINDFIRST(tag, KaxTagTargets); + + if (NULL != target) { + KaxTagTrackUID *tuid = FINDFIRST(target, KaxTagTrackUID); + + if (NULL == tuid) is_global = true; else { - found = false; - track = find_track_by_uid(uint64(*tuid)); - if (track != NULL) { - found = true; - contains_tag = false; + found = false; + kax_track_t *track = find_track_by_uid(uint64(*tuid)); + + if (NULL != track) { + found = true; + bool contains_tag = false; + for (i = 0; i < tag->ListSize(); i++) if (dynamic_cast((*tag)[i]) != NULL) { contains_tag = true; break; } + if (contains_tag) { - if (track->tags == NULL) + if (NULL == track->tags) track->tags = new KaxTags; track->tags->PushElement(*tag); } @@ -725,10 +684,11 @@ kax_reader_c::handle_tags(mm_io_c *io, add_tags(tag); else if (!found) delete tag; + tags->Remove(0); } - } else if (l1 != NULL) + } else delete l1; io->restore_pos(); @@ -736,26 +696,417 @@ kax_reader_c::handle_tags(mm_io_c *io, // }}} +void +kax_reader_c::read_headers_info(EbmlElement *&l1, + EbmlElement *&l2, + int &upper_lvl_el) { + // General info about this Matroska file + mxverb(2, PFX "|+ segment information...\n"); + + l1->Read(*es, KaxInfo::ClassInfos.Context, upper_lvl_el, l2, true); + + KaxTimecodeScale *ktc_scale = FINDFIRST(l1, KaxTimecodeScale); + if (NULL != ktc_scale) { + tc_scale = uint64(*ktc_scale); + mxverb(2, PFX "| + timecode scale: " LLU "\n", tc_scale); + + } else + tc_scale = 1000000; + + KaxDuration *kduration = FINDFIRST(l1, KaxDuration); + if (NULL != kduration) { + segment_duration = irnd(double(*kduration) * tc_scale); + mxverb(2, PFX "| + duration: %.3fs\n", segment_duration / 1000000000.0); + } + + KaxTitle *ktitle = FINDFIRST(l1, KaxTitle); + if (NULL != ktitle) { + title = UTFstring_to_cstrutf8(UTFstring(*ktitle)); + mxverb(2, PFX "| + title: %s\n", title.c_str()); + } + + // Let's try to parse the "writing application" string. This usually + // contains the name and version number of the application used for + // creating this Matroska file. Examples are: + // + // mkvmerge v0.6.6 + // mkvmerge v0.9.6 ('Every Little Kiss') built on Oct 7 2004 18:37:49 + // VirtualDubMod 1.5.4.1 (build 2178/release) + // AVI-Mux GUI 1.16.8 MPEG test build 1, Aug 24 2004 12:42:57 + // + // The idea is to first replace known application names that contain + // spaces with one that doesn't. Then split the whole string up on + // spaces into at most three parts. If the result is at least two parts + // long then try to parse the version number from the second and + // store a lower case version of the first as the application's name. + KaxWritingApp *kwriting_app = FINDFIRST(l1, KaxWritingApp); + if (NULL != kwriting_app) + read_headers_info_writing_app(kwriting_app); + + KaxMuxingApp *kmuxing_app = FINDFIRST(l1, KaxMuxingApp); + if (NULL != kmuxing_app) { + muxing_app = UTFstring_to_cstrutf8(UTFstring(*kmuxing_app)); + mxverb(3, PFX "| (muxing_app '%s')\n", muxing_app.c_str()); + + // DirectShow Muxer workaround: Gabest's DirectShow muxer + // writes wrong references (off by 1ms). So let the cluster + // helper be a bit more imprecise in what it accepts when + // looking for referenced packets. + if (muxing_app == "DirectShow Matroska Muxer") + reference_timecode_tolerance = 1000000; + } +} + +void +kax_reader_c::read_headers_info_writing_app(KaxWritingApp *&kwriting_app) { + int idx; + + string s = UTFstring_to_cstrutf8(UTFstring(*kwriting_app)); + strip(s); + mxverb(2, PFX "| + writing app: %s\n", s.c_str()); + + if (starts_with_case(s, "avi-mux gui")) + s.replace(0, strlen("avi-mux gui"), "avimuxgui"); + + vector parts = split(s.c_str(), " ", 3); + if (parts.size() < 2) { + writing_app = ""; + for (idx = 0; idx < s.size(); idx++) + writing_app += tolower(s[idx]); + writing_app_ver = -1; + + } else { + + writing_app = ""; + for (idx = 0; idx < parts[0].size(); idx++) + writing_app += tolower(parts[0][idx]); + s = ""; + + for (idx = 0; idx < parts[1].size(); idx++) + if (isdigit(parts[1][idx]) || (parts[1][idx] == '.')) + s += parts[1][idx]; + + vector ver_parts = split(s.c_str(), "."); + for (idx = ver_parts.size(); idx < 4; idx++) + ver_parts.push_back("0"); + + bool failed = false; + writing_app_ver = 0; + + for (idx = 0; idx < 4; idx++) { + int num; + + if (!parse_int(ver_parts[idx], num) || (0 > num) || (255 < num)) { + failed = true; + break; + } + writing_app_ver <<= 8; + writing_app_ver |= num; + } + if (failed) + writing_app_ver = -1; + } + + mxverb(3, PFX "| (writing_app '%s', writing_app_ver 0x%08x)\n", writing_app.c_str(), (uint32_t)writing_app_ver); +} + +void +kax_reader_c::read_headers_track_audio(kax_track_t *&track, + KaxTrackAudio *&ktaudio) { + mxverb(2, PFX "| + Audio track\n"); + + KaxAudioSamplingFreq *ka_sfreq = FINDFIRST(ktaudio, KaxAudioSamplingFreq); + if (NULL != ka_sfreq) { + track->a_sfreq = float(*ka_sfreq); + mxverb(2, PFX "| + Sampling frequency: %f\n", track->a_sfreq); + } else + track->a_sfreq = 8000.0; + + KaxAudioOutputSamplingFreq *ka_osfreq = FINDFIRST(ktaudio, KaxAudioOutputSamplingFreq); + if (NULL != ka_osfreq) { + track->a_osfreq = float(*ka_osfreq); + mxverb(2, PFX "| + Output sampling frequency: %f\n", track->a_osfreq); + } + + KaxAudioChannels *ka_channels = FINDFIRST(ktaudio, KaxAudioChannels); + if (NULL != ka_channels) { + track->a_channels = uint8(*ka_channels); + mxverb(2, PFX "| + Channels: " LLU "\n", track->a_channels); + } else + track->a_channels = 1; + + + KaxAudioBitDepth *ka_bitdepth = FINDFIRST(ktaudio, KaxAudioBitDepth); + if (NULL != ka_bitdepth) { + track->a_bps = uint8(*ka_bitdepth); + mxverb(2, PFX "| + Bit depth: " LLU "\n", track->a_bps); + } +} + +void +kax_reader_c::read_headers_track_video(kax_track_t *&track, + KaxTrackVideo *&ktvideo) { + KaxVideoPixelWidth *kv_pwidth = FINDFIRST(ktvideo, KaxVideoPixelWidth); + if (NULL != kv_pwidth) { + track->v_width = uint64(*kv_pwidth); + mxverb(2, PFX "| + Pixel width: " LLU "\n", track->v_width); + } else + mxerror(PFX "Pixel width is missing.\n"); + + KaxVideoPixelHeight *kv_pheight = FINDFIRST(ktvideo, KaxVideoPixelHeight); + if (NULL != kv_pheight) { + track->v_height = uint64(*kv_pheight); + mxverb(2, PFX "| + Pixel height: " LLU "\n", track->v_height); + } else + mxerror(PFX "Pixel height is missing.\n"); + + KaxVideoDisplayWidth *kv_dwidth = FINDFIRST(ktvideo, KaxVideoDisplayWidth); + if (NULL != kv_dwidth) { + track->v_dwidth = uint64(*kv_dwidth); + mxverb(2, PFX "| + Display width: " LLU "\n", track->v_dwidth); + } else + track->v_dwidth = track->v_width; + + KaxVideoDisplayHeight *kv_dheight = FINDFIRST(ktvideo, KaxVideoDisplayHeight); + if (NULL != kv_dheight) { + track->v_dheight = uint64(*kv_dheight); + mxverb(2, PFX "| + Display height: " LLU "\n", track->v_dheight); + } else + track->v_dheight = track->v_height; + + // For older files. + KaxVideoFrameRate *kv_frate = FINDFIRST(ktvideo, KaxVideoFrameRate); + if (NULL != kv_frate) { + track->v_frate = float(*kv_frate); + mxverb(2, PFX "| + Frame rate: %f\n", track->v_frate); + } + + KaxVideoPixelCropLeft *kv_pcleft = FINDFIRST(ktvideo, KaxVideoPixelCropLeft); + if (NULL != kv_pcleft) { + track->v_pcleft = uint64(*kv_pcleft); + mxverb(2, PFX "| + Pixel crop left: " LLU "\n", track->v_pcleft); + } + + KaxVideoPixelCropTop *kv_pctop = FINDFIRST(ktvideo, KaxVideoPixelCropTop); + if (NULL != kv_pctop) { + track->v_pctop = uint64(*kv_pctop); + mxverb(2, PFX "| + Pixel crop top: " LLU "\n", track->v_pctop); + } + + KaxVideoPixelCropRight *kv_pcright = FINDFIRST(ktvideo, KaxVideoPixelCropRight); + if (NULL != kv_pcright) { + track->v_pcright = uint64(*kv_pcright); + mxverb(2, PFX "| + Pixel crop right: " LLU "\n", track->v_pcright); + } + + KaxVideoPixelCropBottom *kv_pcbottom = FINDFIRST(ktvideo, KaxVideoPixelCropBottom); + if (NULL != kv_pcbottom) { + track->v_pcbottom = uint64(*kv_pcbottom); + mxverb(2, PFX "| + Pixel crop bottom: " LLU "\n", track->v_pcbottom); + } + + KaxVideoStereoMode *kv_stereo_mode = FINDFIRST(ktvideo, KaxVideoStereoMode); + if (NULL != kv_stereo_mode) { + track->v_stereo_mode = (stereo_mode_e)uint64(*kv_stereo_mode); + mxverb(2, PFX "| + Stereo mode: %d\n", (int)track->v_stereo_mode); + } +} + +void +kax_reader_c::read_headers_tracks(EbmlElement *&l1, + EbmlElement *&l2, + int &upper_lvl_el) { + // Yep, we've found our KaxTracks element. Now find all tracks + // contained in this segment. + mxverb(2, PFX "|+ segment tracks...\n"); + + l1->Read(*es, KaxTracks::ClassInfos.Context, upper_lvl_el, l2, true); + + KaxTrackEntry *ktentry = FINDFIRST(l1, KaxTrackEntry); + while (ktentry != NULL) { + // We actually found a track entry :) We're happy now. + mxverb(2, PFX "| + a track...\n"); + + kax_track_t *track = new_kax_track(); + if (NULL == track) + return; + + KaxTrackNumber *ktnum = FINDFIRST(ktentry, KaxTrackNumber); + if (NULL == ktnum) + mxerror(PFX "A track is missing its track number.\n"); + mxverb(2, PFX "| + Track number: %d\n", uint8(*ktnum)); + + track->tnum = uint8(*ktnum); + if (find_track_by_num(track->tnum, track) != NULL) + mxwarn(PFX "| + There's more than one track with the number " LLU ".\n", track->tnum); + + KaxTrackUID *ktuid = FINDFIRST(ktentry, KaxTrackUID); + if (NULL == ktuid) + mxerror(PFX "A track is missing its track UID.\n"); + mxverb(2, PFX "| + Track UID: " LLU "\n", uint64(*ktuid)); + track->tuid = uint64(*ktuid); + if ((find_track_by_uid(track->tuid, track) != NULL) && (verbose > 1)) + mxwarn(PFX "| + There's more than one track with the UID " LLU ".\n", track->tnum); + + KaxTrackDefaultDuration *kdefdur = FINDFIRST(ktentry, KaxTrackDefaultDuration); + if (NULL != kdefdur) { + track->v_frate = 1000000000.0 / (float)uint64(*kdefdur); + track->default_duration = uint64(*kdefdur); + mxverb(2, PFX "| + Default duration: %.3fms ( = %.3f fps)\n", (float)uint64(*kdefdur) / 1000000.0, track->v_frate); + } + + KaxTrackType *kttype = FINDFIRST(ktentry, KaxTrackType); + if (NULL == kttype) + mxerror(PFX "Track type was not found.\n"); + unsigned char track_type = uint8(*kttype); + track->type = track_type == track_audio ? 'a' + : track_type == track_video ? 'v' + : track_type == track_subtitle ? 's' + : '?'; + mxverb(2, PFX "| + Track type: %s\n", MAP_TRACK_TYPE_STRING(track->type)); + + KaxTrackAudio *ktaudio = FINDFIRST(ktentry, KaxTrackAudio); + if (NULL != ktaudio) + read_headers_track_audio(track, ktaudio); + + KaxTrackVideo *ktvideo = FINDFIRST(ktentry, KaxTrackVideo); + if (NULL != ktvideo) + read_headers_track_video(track, ktvideo); + + KaxCodecID *kcodecid = FINDFIRST(ktentry, KaxCodecID); + if (NULL != kcodecid) { + mxverb(2, PFX "| + Codec ID: %s\n", string(*kcodecid).c_str()); + track->codec_id = string(*kcodecid); + } else + mxerror(PFX "CodecID is missing.\n"); + + KaxCodecPrivate *kcodecpriv = FINDFIRST(ktentry, KaxCodecPrivate); + if (NULL != kcodecpriv) { + mxverb(2, PFX "| + CodecPrivate, length " LLU "\n", kcodecpriv->GetSize()); + track->private_size = kcodecpriv->GetSize(); + if (0 < track->private_size) + track->private_data = safememdup(kcodecpriv->GetBuffer(), track->private_size); + } + + KaxTrackMinCache *ktmincache = FINDFIRST(ktentry, KaxTrackMinCache); + if (NULL != ktmincache) { + mxverb(2, PFX "| + MinCache: " LLU "\n", uint64(*ktmincache)); + if (1 < uint64(*ktmincache)) + track->v_bframes = true; + track->min_cache = uint64(*ktmincache); + } + + KaxTrackMaxCache *ktmaxcache = FINDFIRST(ktentry, KaxTrackMaxCache); + if (NULL != ktmaxcache) { + mxverb(2, PFX "| + MaxCache: " LLU "\n", uint64(*ktmaxcache)); + track->max_cache = uint64(*ktmaxcache); + } + + KaxTrackFlagDefault *ktfdefault = FINDFIRST(ktentry, KaxTrackFlagDefault); + if (NULL != ktfdefault) { + mxverb(2, PFX "| + Default flag: " LLU "\n", uint64(*ktfdefault)); + track->default_track = uint64(*ktfdefault); + } + + KaxTrackFlagLacing *ktflacing = FINDFIRST(ktentry, KaxTrackFlagLacing); + if (NULL != ktflacing) { + mxverb(2, PFX "| + Lacing flag: " LLU "\n", uint64(*ktflacing)); + track->lacing_flag = uint64(*ktflacing); + } else + track->lacing_flag = true; + + KaxMaxBlockAdditionID *ktmax_blockadd_id = FINDFIRST(ktentry, KaxMaxBlockAdditionID); + if (NULL != ktmax_blockadd_id) { + mxverb(2, PFX "| + Max Block Addition ID: " LLU "\n", uint64(*ktmax_blockadd_id)); + track->max_blockadd_id = uint64(*ktmax_blockadd_id); + } else + track->max_blockadd_id = 0; + + KaxTrackLanguage *ktlanguage = FINDFIRST(ktentry, KaxTrackLanguage); + if (NULL != ktlanguage) { + mxverb(2, PFX "| + Language: %s\n", string(*ktlanguage).c_str()); + track->language = string(*ktlanguage); + } + + KaxTrackName *ktname = FINDFIRST(ktentry, KaxTrackName); + if (NULL != ktname) { + track->track_name = UTFstring_to_cstrutf8(UTFstring(*ktname)); + mxverb(2, PFX "| + Name: %s\n", track->track_name.c_str()); + } + + track->content_decoder.initialize(*ktentry); + ktentry = FINDNEXT(l1, KaxTrackEntry, ktentry); + } // while (ktentry != NULL) + + l1->SkipData(*es, l1->Generic().Context); +} + +void +kax_reader_c::read_headers_seek_head(EbmlElement *&l0, + EbmlElement *&l1, + vector &deferred_tags, + vector &deferred_chapters, + vector &deferred_attachments) { + EbmlElement *el; + + KaxSeekHead &seek_head = *static_cast(l1); + + int i = 0; + seek_head.Read(*es, KaxSeekHead::ClassInfos.Context, i, el, true); + + for (i = 0; i < seek_head.ListSize(); i++) { + if (EbmlId(*seek_head[i]) != KaxSeek::ClassInfos.GlobalId) + continue; + + KaxSeek &seek = *static_cast(seek_head[i]); + int64_t pos = -1; + bool is_attachments = false; + bool is_chapters = false; + bool is_tags = false; + int k; + + for (k = 0; k < seek.ListSize(); k++) + if (EbmlId(*seek[k]) == KaxSeekID::ClassInfos.GlobalId) { + KaxSeekID &sid = *static_cast(seek[k]); + EbmlId id(sid.GetBuffer(), sid.GetSize()); + if (id == KaxAttachments::ClassInfos.GlobalId) + is_attachments = true; + else if (id == KaxChapters::ClassInfos.GlobalId) + is_chapters = true; + else if (id == KaxTags::ClassInfos.GlobalId) + is_tags = true; + + } else if (EbmlId(*seek[k]) == KaxSeekPosition::ClassInfos.GlobalId) + pos = uint64(*static_cast(seek[k])); + + if (-1 != pos) { + pos = ((KaxSegment *)l0)->GetGlobalPosition(pos); + if (is_attachments) + deferred_attachments.push_back(pos); + else if (is_chapters) + deferred_chapters.push_back(pos); + else if (is_tags) + deferred_tags.push_back(pos); + } + } +} + // {{{ FUNCTION kax_reader_c::read_headers() int kax_reader_c::read_headers() { - int upper_lvl_el, i; // Elements for different levels - EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL; - kax_track_t *track; - bool exit_loop; vector deferred_tags, deferred_chapters, deferred_attachments; - exit_loop = false; + bool exit_loop = false; try { - in = new mm_file_io_c(ti.fname); + in = new mm_file_io_c(ti.fname); file_size = in->get_size(); - es = new EbmlStream(*in); + es = new EbmlStream(*in); // Find the EbmlHead element. Must be the first one. - l0 = es->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFFFFFFFFFLL); - if (l0 == NULL) { + EbmlElement *l0 = es->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFFFFFFFFFLL); + if (NULL == l0) { mxwarn(PFX "no EBML head found.\n"); return 0; } @@ -763,12 +1114,11 @@ kax_reader_c::read_headers() { // Don't verify its data for now. l0->SkipData(*es, l0->Generic().Context); delete l0; - if (verbose > 1) - mxinfo(PFX "Found the head...\n"); + mxverb(2, PFX "Found the head...\n"); // Next element must be a segment l0 = es->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFFFFFFFFFLL); - if (l0 == NULL) { + if (NULL == l0) { if (verbose) mxwarn(PFX "No segment found.\n"); return 0; @@ -778,446 +1128,26 @@ kax_reader_c::read_headers() { mxwarn(PFX "No segment found.\n"); return 0; } - if (verbose > 1) - mxinfo(PFX "+ a segment...\n"); + mxverb(2, PFX "+ a segment...\n"); segment = l0; - upper_lvl_el = 0; - exit_loop = false; - tc_scale = TIMECODE_SCALE; // We've got our segment, so let's find the tracks - l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, - true, 1); - while ((l1 != NULL) && (upper_lvl_el <= 0)) { + int upper_lvl_el = 0; + exit_loop = false; + tc_scale = TIMECODE_SCALE; + EbmlElement *l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true, 1); - if (EbmlId(*l1) == KaxInfo::ClassInfos.GlobalId) { - KaxTimecodeScale *ktc_scale; - KaxDuration *kduration; - KaxTitle *ktitle; - KaxWritingApp *kwriting_app; - KaxMuxingApp *kmuxing_app; + while ((NULL != l1) && (0 >= upper_lvl_el)) { + EbmlElement *l2; - // General info about this Matroska file - if (verbose > 1) - mxinfo(PFX "|+ segment information...\n"); + if (EbmlId(*l1) == KaxInfo::ClassInfos.GlobalId) + read_headers_info(l1, l2, upper_lvl_el); - l1->Read(*es, KaxInfo::ClassInfos.Context, upper_lvl_el, l2, true); + else if (EbmlId(*l1) == KaxTracks::ClassInfos.GlobalId) + read_headers_tracks(l1, l2, upper_lvl_el); - ktc_scale = FINDFIRST(l1, KaxTimecodeScale); - if (ktc_scale != NULL) { - tc_scale = uint64(*ktc_scale); - if (verbose > 1) - mxinfo(PFX "| + timecode scale: " LLU "\n", tc_scale); - - } else - tc_scale = 1000000; - - kduration = FINDFIRST(l1, KaxDuration); - if (kduration != NULL) { - segment_duration = irnd(double(*kduration) * tc_scale); - if (verbose > 1) - mxinfo(PFX "| + duration: %.3fs\n", segment_duration / - 1000000000.0); - } - - ktitle = FINDFIRST(l1, KaxTitle); - if (ktitle != NULL) { - title = UTFstring_to_cstrutf8(UTFstring(*ktitle)); - if (verbose > 1) - mxinfo(PFX "| + title: %s\n", title.c_str()); - } - - // Let's try to parse the "writing application" string. This usually - // contains the name and version number of the application used for - // creating this Matroska file. Examples are: - // - // mkvmerge v0.6.6 - // mkvmerge v0.9.6 ('Every Little Kiss') built on Oct 7 2004 18:37:49 - // VirtualDubMod 1.5.4.1 (build 2178/release) - // AVI-Mux GUI 1.16.8 MPEG test build 1, Aug 24 2004 12:42:57 - // - // The idea is to first replace known application names that contain - // spaces with one that doesn't. Then split the whole string up on - // spaces into at most three parts. If the result is at least two parts - // long then try to parse the version number from the second and - // store a lower case version of the first as the application's name. - kwriting_app = FINDFIRST(l1, KaxWritingApp); - if (kwriting_app != NULL) { - int idx; - vector parts, ver_parts; - string s; - - s = UTFstring_to_cstrutf8(UTFstring(*kwriting_app)); - strip(s); - if (verbose > 1) - mxinfo(PFX "| + writing app: %s\n", s.c_str()); - if (starts_with_case(s, "avi-mux gui")) - s.replace(0, strlen("avi-mux gui"), "avimuxgui"); - - parts = split(s.c_str(), " ", 3); - if (parts.size() < 2) { - writing_app = ""; - for (idx = 0; idx < s.size(); idx++) - writing_app += tolower(s[idx]); - writing_app_ver = -1; - - } else { - bool failed; - - writing_app = ""; - for (idx = 0; idx < parts[0].size(); idx++) - writing_app += tolower(parts[0][idx]); - s = ""; - for (idx = 0; idx < parts[1].size(); idx++) - if (isdigit(parts[1][idx]) || (parts[1][idx] == '.')) - s += parts[1][idx]; - ver_parts = split(s.c_str(), "."); - for (idx = ver_parts.size(); idx < 4; idx++) - ver_parts.push_back("0"); - - failed = false; - writing_app_ver = 0; - for (idx = 0; idx < 4; idx++) { - int num; - - if (!parse_int(ver_parts[idx], num) || (num < 0) || - (num > 255)) { - failed = true; - break; - } - writing_app_ver <<= 8; - writing_app_ver |= num; - } - if (failed) - writing_app_ver = -1; - } - - mxverb(3, PFX "| (writing_app '%s', writing_app_ver 0x%08x)\n", - writing_app.c_str(), (uint32_t)writing_app_ver); - } - - kmuxing_app = FINDFIRST(l1, KaxMuxingApp); - if (kmuxing_app != NULL) { - muxing_app = UTFstring_to_cstrutf8(UTFstring(*kmuxing_app)); - mxverb(3, PFX "| (muxing_app '%s')\n", muxing_app.c_str()); - - // DirectShow Muxer workaround: Gabest's DirectShow muxer - // writes wrong references (off by 1ms). So let the cluster - // helper be a bit more imprecise in what it accepts when - // looking for referenced packets. - if (muxing_app == "DirectShow Matroska Muxer") - reference_timecode_tolerance = 1000000; - } - - } else if (EbmlId(*l1) == KaxTracks::ClassInfos.GlobalId) { - KaxTrackEntry *ktentry; - - // Yep, we've found our KaxTracks element. Now find all tracks - // contained in this segment. - if (verbose > 1) - mxinfo(PFX "|+ segment tracks...\n"); - - l1->Read(*es, KaxTracks::ClassInfos.Context, upper_lvl_el, l2, true); - - ktentry = FINDFIRST(l1, KaxTrackEntry); - while (ktentry != NULL) { - // We actually found a track entry :) We're happy now. - - KaxTrackNumber *ktnum; - KaxTrackUID *ktuid; - KaxTrackDefaultDuration *kdefdur; - KaxTrackType *kttype; - KaxTrackAudio *ktaudio; - KaxTrackVideo *ktvideo; - KaxCodecID *kcodecid; - KaxCodecPrivate *kcodecpriv; - KaxTrackFlagDefault *ktfdefault; - KaxTrackFlagLacing *ktflacing; - KaxMaxBlockAdditionID *ktmax_blockadd_id; - KaxTrackLanguage *ktlanguage; - KaxTrackMinCache *ktmincache; - KaxTrackMaxCache *ktmaxcache; - KaxTrackName *ktname; - - if (verbose > 1) - mxinfo(PFX "| + a track...\n"); - - track = new_kax_track(); - if (track == NULL) - return 0; - - ktnum = FINDFIRST(ktentry, KaxTrackNumber); - if (ktnum == NULL) - mxerror(PFX "A track is missing its track number.\n"); - if (verbose > 1) - mxinfo(PFX "| + Track number: %d\n", uint8(*ktnum)); - track->tnum = uint8(*ktnum); - if ((find_track_by_num(track->tnum, track) != NULL) && (verbose > 1)) - mxwarn(PFX "| + There's more than one track with " - "the number " LLU ".\n", track->tnum); - - ktuid = FINDFIRST(ktentry, KaxTrackUID); - if (ktuid == NULL) - mxerror(PFX "A track is missing its track UID.\n"); - if (verbose > 1) - mxinfo(PFX "| + Track UID: " LLU "\n", uint64(*ktuid)); - track->tuid = uint64(*ktuid); - if ((find_track_by_uid(track->tuid, track) != NULL) && (verbose > 1)) - mxwarn(PFX "| + There's more than one track with the UID " LLU - ".\n", track->tnum); - - kdefdur = FINDFIRST(ktentry, KaxTrackDefaultDuration); - if (kdefdur != NULL) { - track->v_frate = 1000000000.0 / (float)uint64(*kdefdur); - track->default_duration = uint64(*kdefdur); - if (verbose > 1) - mxinfo(PFX "| + Default duration: %.3fms ( = %.3f fps)\n", - (float)uint64(*kdefdur) / 1000000.0, track->v_frate); - } - - kttype = FINDFIRST(ktentry, KaxTrackType); - if (kttype == NULL) - mxerror(PFX "Track type was not found.\n"); - if (verbose > 1) - mxinfo(PFX "| + Track type: "); - switch (uint8(*kttype)) { - case track_audio: - if (verbose > 1) - mxinfo("Audio\n"); - track->type = 'a'; - break; - case track_video: - if (verbose > 1) - mxinfo("Video\n"); - track->type = 'v'; - break; - case track_subtitle: - if (verbose > 1) - mxinfo("Subtitle\n"); - track->type = 's'; - break; - default: - if (verbose > 1) - mxinfo("unknown\n"); - track->type = '?'; - break; - } - - ktaudio = FINDFIRST(ktentry, KaxTrackAudio); - if (ktaudio != NULL) { - KaxAudioSamplingFreq *ka_sfreq; - KaxAudioOutputSamplingFreq *ka_osfreq; - KaxAudioChannels *ka_channels; - KaxAudioBitDepth *ka_bitdepth; - - if (verbose > 1) - mxinfo(PFX "| + Audio track\n"); - - ka_sfreq = FINDFIRST(ktaudio, KaxAudioSamplingFreq); - if (ka_sfreq != NULL) { - track->a_sfreq = float(*ka_sfreq); - if (verbose > 1) - mxinfo(PFX "| + Sampling frequency: %f\n", track->a_sfreq); - } else - track->a_sfreq = 8000.0; - - ka_osfreq = FINDFIRST(ktaudio, KaxAudioOutputSamplingFreq); - if (ka_osfreq != NULL) { - track->a_osfreq = float(*ka_osfreq); - if (verbose > 1) - mxinfo(PFX "| + Output sampling frequency: %f\n", - track->a_osfreq); - } - - ka_channels = FINDFIRST(ktaudio, KaxAudioChannels); - if (ka_channels != NULL) { - track->a_channels = uint8(*ka_channels); - if (verbose > 1) - mxinfo(PFX "| + Channels: " LLU "\n", track->a_channels); - } else - track->a_channels = 1; - - - ka_bitdepth = FINDFIRST(ktaudio, KaxAudioBitDepth); - if (ka_bitdepth != NULL) { - track->a_bps = uint8(*ka_bitdepth); - if (verbose > 1) - mxinfo(PFX "| + Bit depth: " LLU "\n", track->a_bps); - } - } - - ktvideo = FINDFIRST(ktentry, KaxTrackVideo); - if (ktvideo != NULL) { - KaxVideoPixelWidth *kv_pwidth; - KaxVideoPixelHeight *kv_pheight; - KaxVideoDisplayWidth *kv_dwidth; - KaxVideoDisplayHeight *kv_dheight; - KaxVideoFrameRate *kv_frate; - KaxVideoPixelCropLeft *kv_pcleft; - KaxVideoPixelCropTop *kv_pctop; - KaxVideoPixelCropRight *kv_pcright; - KaxVideoPixelCropBottom *kv_pcbottom; - KaxVideoStereoMode *kv_stereo_mode; - - kv_pwidth = FINDFIRST(ktvideo, KaxVideoPixelWidth); - if (kv_pwidth != NULL) { - track->v_width = uint64(*kv_pwidth); - if (verbose > 1) - mxinfo(PFX "| + Pixel width: " LLU "\n", track->v_width); - } else - mxerror(PFX "Pixel width is missing.\n"); - - kv_pheight = FINDFIRST(ktvideo, KaxVideoPixelHeight); - if (kv_pheight != NULL) { - track->v_height = uint64(*kv_pheight); - if (verbose > 1) - mxinfo(PFX "| + Pixel height: " LLU "\n", track->v_height); - } else - mxerror(PFX "Pixel height is missing.\n"); - - kv_dwidth = FINDFIRST(ktvideo, KaxVideoDisplayWidth); - if (kv_dwidth != NULL) { - track->v_dwidth = uint64(*kv_dwidth); - if (verbose > 1) - mxinfo(PFX "| + Display width: " LLU "\n", track->v_dwidth); - } else - track->v_dwidth = track->v_width; - - kv_dheight = FINDFIRST(ktvideo, KaxVideoDisplayHeight); - if (kv_dheight != NULL) { - track->v_dheight = uint64(*kv_dheight); - if (verbose > 1) - mxinfo(PFX "| + Display height: " LLU "\n", - track->v_dheight); - } else - track->v_dheight = track->v_height; - - // For older files. - kv_frate = FINDFIRST(ktvideo, KaxVideoFrameRate); - if (kv_frate != NULL) { - track->v_frate = float(*kv_frate); - if (verbose > 1) - mxinfo(PFX "| + Frame rate: %f\n", track->v_frate); - } - - kv_pcleft = FINDFIRST(ktvideo, KaxVideoPixelCropLeft); - if (kv_pcleft != NULL) { - track->v_pcleft = uint64(*kv_pcleft); - if (verbose > 1) - mxinfo(PFX "| + Pixel crop left: " LLU "\n", - track->v_pcleft); - } - - kv_pctop = FINDFIRST(ktvideo, KaxVideoPixelCropTop); - if (kv_pctop != NULL) { - track->v_pctop = uint64(*kv_pctop); - if (verbose > 1) - mxinfo(PFX "| + Pixel crop top: " LLU "\n", track->v_pctop); - } - - kv_pcright = FINDFIRST(ktvideo, KaxVideoPixelCropRight); - if (kv_pcright != NULL) { - track->v_pcright = uint64(*kv_pcright); - if (verbose > 1) - mxinfo(PFX "| + Pixel crop right: " LLU "\n", - track->v_pcright); - } - - kv_pcbottom = FINDFIRST(ktvideo, KaxVideoPixelCropBottom); - if (kv_pcbottom != NULL) { - track->v_pcbottom = uint64(*kv_pcbottom); - if (verbose > 1) - mxinfo(PFX "| + Pixel crop bottom: " LLU "\n", - track->v_pcbottom); - } - - kv_stereo_mode = FINDFIRST(ktvideo, KaxVideoStereoMode); - if (NULL != kv_stereo_mode) { - track->v_stereo_mode = (stereo_mode_e)uint64(*kv_stereo_mode); - mxverb(2, PFX "| + Stereo mode: %d\n", - (int)track->v_stereo_mode); - } - - } - - kcodecid = FINDFIRST(ktentry, KaxCodecID); - if (kcodecid != NULL) { - if (verbose > 1) - mxinfo(PFX "| + Codec ID: %s\n", string(*kcodecid).c_str()); - track->codec_id = string(*kcodecid); - } else - mxerror(PFX "CodecID is missing.\n"); - - kcodecpriv = FINDFIRST(ktentry, KaxCodecPrivate); - if (kcodecpriv != NULL) { - if (verbose > 1) - mxinfo(PFX "| + CodecPrivate, length " LLU "\n", - kcodecpriv->GetSize()); - track->private_size = kcodecpriv->GetSize(); - if (track->private_size > 0) - track->private_data = safememdup(kcodecpriv->GetBuffer(), - track->private_size); - } - - ktmincache = FINDFIRST(ktentry, KaxTrackMinCache); - if (ktmincache != NULL) { - if (verbose > 1) - mxinfo(PFX "| + MinCache: " LLU "\n", uint64(*ktmincache)); - if (uint64(*ktmincache) > 1) - track->v_bframes = true; - track->min_cache = uint64(*ktmincache); - } - - ktmaxcache = FINDFIRST(ktentry, KaxTrackMaxCache); - if (ktmaxcache != NULL) { - mxverb(2, PFX "| + MaxCache: " LLU "\n", uint64(*ktmaxcache)); - track->max_cache = uint64(*ktmaxcache); - } - - ktfdefault = FINDFIRST(ktentry, KaxTrackFlagDefault); - if (ktfdefault != NULL) { - if (verbose > 1) - mxinfo(PFX "| + Default flag: " LLU "\n", uint64(*ktfdefault)); - track->default_track = uint64(*ktfdefault); - } - - ktflacing = FINDFIRST(ktentry, KaxTrackFlagLacing); - if (ktflacing != NULL) { - mxverb(2, PFX "| + Lacing flag: " LLU "\n", uint64(*ktflacing)); - track->lacing_flag = uint64(*ktflacing); - } else - track->lacing_flag = true; - - ktmax_blockadd_id = FINDFIRST(ktentry, KaxMaxBlockAdditionID); - if (ktmax_blockadd_id != NULL) { - mxverb(2, PFX "| + Max Block Addition ID: " LLU "\n", - uint64(*ktmax_blockadd_id)); - track->max_blockadd_id = uint64(*ktmax_blockadd_id); - } else - track->max_blockadd_id = 0; - - ktlanguage = FINDFIRST(ktentry, KaxTrackLanguage); - if (ktlanguage != NULL) { - if (verbose > 1) - mxinfo(PFX "| + Language: %s\n", string(*ktlanguage).c_str()); - track->language = string(*ktlanguage); - } - - ktname = FINDFIRST(ktentry, KaxTrackName); - if (ktname != NULL) { - track->track_name = UTFstring_to_cstrutf8(UTFstring(*ktname)); - if (verbose > 1) - mxinfo(PFX "| + Name: %s\n", track->track_name.c_str()); - } - - track->content_decoder.initialize(*ktentry); - ktentry = FINDNEXT(l1, KaxTrackEntry, ktentry); - } // while (ktentry != NULL) - - l1->SkipData(*es, l1->Generic().Context); - - } else if (EbmlId(*l1) == KaxAttachments::ClassInfos.GlobalId) + else if (EbmlId(*l1) == KaxAttachments::ClassInfos.GlobalId) deferred_attachments.push_back(l1->GetElementPosition()); else if (EbmlId(*l1) == KaxChapters::ClassInfos.GlobalId) @@ -1226,52 +1156,12 @@ kax_reader_c::read_headers() { else if (EbmlId(*l1) == KaxTags::ClassInfos.GlobalId) deferred_tags.push_back(l1->GetElementPosition()); - else if (EbmlId(*l1) == KaxSeekHead::ClassInfos.GlobalId) { - int k; - EbmlElement *el; - KaxSeekHead &seek_head = *static_cast(l1); - int64_t pos; - bool is_attachments, is_chapters, is_tags; + else if (EbmlId(*l1) == KaxSeekHead::ClassInfos.GlobalId) + read_headers_seek_head(l0, l1, deferred_tags, deferred_chapters, deferred_attachments); - i = 0; - seek_head.Read(*es, KaxSeekHead::ClassInfos.Context, i, el, true); - for (i = 0; i < seek_head.ListSize(); i++) - if (EbmlId(*seek_head[i]) == KaxSeek::ClassInfos.GlobalId) { - KaxSeek &seek = *static_cast(seek_head[i]); - pos = -1; - is_attachments = false; - is_chapters = false; - is_tags = false; - - for (k = 0; k < seek.ListSize(); k++) - if (EbmlId(*seek[k]) == KaxSeekID::ClassInfos.GlobalId) { - KaxSeekID &sid = *static_cast(seek[k]); - EbmlId id(sid.GetBuffer(), sid.GetSize()); - if (id == KaxAttachments::ClassInfos.GlobalId) - is_attachments = true; - else if (id == KaxChapters::ClassInfos.GlobalId) - is_chapters = true; - else if (id == KaxTags::ClassInfos.GlobalId) - is_tags = true; - - } else if (EbmlId(*seek[k]) == - KaxSeekPosition::ClassInfos.GlobalId) - pos = uint64(*static_cast(seek[k])); - - if (pos != -1) { - pos = ((KaxSegment *)l0)->GetGlobalPosition(pos); - if (is_attachments) - deferred_attachments.push_back(pos); - else if (is_chapters) - deferred_chapters.push_back(pos); - else if (is_tags) - deferred_tags.push_back(pos); - } - } - - } else if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) { + else if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) { mxverb(2, PFX "|+ found cluster, headers are parsed completely :)\n"); - saved_l1 = l1; + saved_l1 = l1; exit_loop = true; } else @@ -1302,11 +1192,11 @@ kax_reader_c::read_headers() { l1->SkipData(*es, l1->Generic().Context); delete l1; - l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true); + l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true); } // while (l1 != NULL) + int i; if (!ti.no_attachments) for (i = 0; i < deferred_attachments.size(); i++) handle_attachments(in, l0, deferred_attachments[i]); @@ -1337,13 +1227,11 @@ kax_reader_c::init_passthrough_packetizer(kax_track_t *t) { passthrough_packetizer_c *ptzr; track_info_c nti(ti); - mxinfo(FMT_TID "Using the passthrough output module for this %s " - "track.\n", ti.fname.c_str(), (int64_t)t->tnum, - MAP_TRACK_TYPE_STRING(t->type)); + mxinfo(FMT_TID "Using the passthrough output module for this %s track.\n", ti.fname.c_str(), (int64_t)t->tnum, MAP_TRACK_TYPE_STRING(t->type)); - nti.id = t->tnum; - nti.language = t->language; - nti.track_name = t->track_name; + nti.id = t->tnum; + nti.language = t->language; + nti.track_name = t->track_name; ptzr = new passthrough_packetizer_c(this, nti); t->ptzr = add_packetizer(ptzr); @@ -1352,40 +1240,37 @@ kax_reader_c::init_passthrough_packetizer(kax_track_t *t) { ptzr->set_track_type(MAP_TRACK_TYPE(t->type)); ptzr->set_codec_id(t->codec_id); - ptzr->set_codec_private((unsigned char *)t->private_data, - t->private_size); - if (t->v_frate > 0.0) + ptzr->set_codec_private((unsigned char *)t->private_data, t->private_size); + + if (0.0 < t->v_frate) ptzr->set_track_default_duration((int64_t)(1000000000.0 / t->v_frate)); - if (t->min_cache > 0) + if (0 < t->min_cache) ptzr->set_track_min_cache(t->min_cache); - if (t->max_cache > 0) + if (0 < t->max_cache) ptzr->set_track_max_cache(t->max_cache); - if (t->type == 'v') { + if ('v' == t->type) { ptzr->set_video_pixel_width(t->v_width); ptzr->set_video_pixel_height(t->v_height); if (!ptzr->ti.aspect_ratio_given) { // The user hasn't set it. - if (t->v_dwidth != 0) + if (0 != t->v_dwidth) ptzr->set_video_display_width(t->v_dwidth); - if (t->v_dheight != 0) + if (0 != t->v_dheight) ptzr->set_video_display_height(t->v_dheight); } - if (!ptzr->ti.pixel_cropping_specified && - ((t->v_pcleft > 0) || (t->v_pctop > 0) || - (t->v_pcright > 0) || (t->v_pcbottom > 0))) - ptzr->set_video_pixel_cropping(t->v_pcleft, t->v_pctop, - t->v_pcright, t->v_pcbottom); + if (!ptzr->ti.pixel_cropping_specified && ((t->v_pcleft > 0) || (t->v_pctop > 0) || (t->v_pcright > 0) || (t->v_pcbottom > 0))) + ptzr->set_video_pixel_cropping(t->v_pcleft, t->v_pctop, t->v_pcright, t->v_pcbottom); if (STEREO_MODE_UNSPECIFIED == ptzr->ti.stereo_mode) ptzr->set_stereo_mode(t->v_stereo_mode); - if (ptzr->get_cue_creation() == CUE_STRATEGY_UNSPECIFIED) - ptzr->set_cue_creation( CUE_STRATEGY_IFRAMES); + if (CUE_STRATEGY_UNSPECIFIED == ptzr->get_cue_creation()) + ptzr->set_cue_creation(CUE_STRATEGY_IFRAMES); - } else if (t->type == 'a') { + } else if ('a' == t->type) { ptzr->set_audio_sampling_freq(t->a_sfreq); ptzr->set_audio_channels(t->a_channels); - if (t->a_bps != 0) + if (0 != t->a_bps) ptzr->set_audio_bit_depth(t->a_bps); - if (t->a_osfreq != 0.0) + if (0.0 != t->a_osfreq) ptzr->set_audio_output_sampling_freq(t->a_osfreq); } else { @@ -1399,376 +1284,292 @@ kax_reader_c::set_packetizer_headers(kax_track_t *t) { if (appending) return; if (t->default_track) - PTZR(t->ptzr)->set_as_default_track(t->type == 'v' ? DEFTRACK_TYPE_VIDEO : - t->type == 'a' ? DEFTRACK_TYPE_AUDIO : - DEFTRACK_TYPE_SUBS, + PTZR(t->ptzr)->set_as_default_track(t->type == 'v' ? DEFTRACK_TYPE_VIDEO : t->type == 'a' ? DEFTRACK_TYPE_AUDIO : DEFTRACK_TYPE_SUBS, DEFAULT_TRACK_PRIORITY_FROM_SOURCE); - if (t->tuid != 0) - if (!PTZR(t->ptzr)->set_uid(t->tuid)) - mxwarn(PFX "Could not keep the track UID " LLU " because it is already " - "allocated for the new file.\n", t->tuid); + if ((0 != t->tuid != 0) && !PTZR(t->ptzr)->set_uid(t->tuid)) + mxwarn(PFX "Could not keep the track UID " LLU " because it is already allocated for the new file.\n", t->tuid); +} + +void +kax_reader_c::create_video_packetizer(kax_track_t *t, + track_info_c &nti) { + if ((t->codec_id == MKV_V_MSCOMP) && mpeg4::p10::is_avc_fourcc(t->v_fourcc) && !hack_engaged(ENGAGE_ALLOW_AVC_IN_VFW_MODE)) + create_mpeg4_p10_es_video_packetizer(t, nti); + + else if ( starts_with(t->codec_id, "V_MPEG4", 7) + || (t->codec_id == MKV_V_MSCOMP) + || starts_with(t->codec_id, "V_REAL", 6) + || (t->codec_id == MKV_V_QUICKTIME) + || (t->codec_id == MKV_V_MPEG1) + || (t->codec_id == MKV_V_MPEG2) + || (t->codec_id == MKV_V_THEORA)) { + if ((t->codec_id == MKV_V_MPEG1) || (t->codec_id == MKV_V_MPEG2)) { + int version = t->codec_id[6] - '0'; + mxinfo(FMT_TID "Using the MPEG-%d video output module.\n", ti.fname.c_str(), (int64_t)t->tnum, version); + + t->ptzr = add_packetizer(new mpeg1_2_video_packetizer_c(this, version, t->v_frate, t->v_width, t->v_height, t->v_dwidth, t->v_dheight, true, nti)); + + } else if (IS_MPEG4_L2_CODECID(t->codec_id) || IS_MPEG4_L2_FOURCC(t->v_fourcc)) { + mxinfo(FMT_TID "Using the MPEG-4 part 2 video output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + bool is_native = IS_MPEG4_L2_CODECID(t->codec_id); + t->ptzr = add_packetizer(new mpeg4_p2_video_packetizer_c(this, t->v_frate, t->v_width, t->v_height, is_native, nti)); + + } else if (t->codec_id == MKV_V_MPEG4_AVC) { + mxinfo(FMT_TID "Using the MPEG-4 part 10 (AVC) video output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + t->ptzr = add_packetizer(new mpeg4_p10_video_packetizer_c(this, t->v_frate, t->v_width, t->v_height, nti)); + + } else { + mxinfo(FMT_TID "Using the video output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + t->ptzr = add_packetizer(new video_packetizer_c(this, t->codec_id.c_str(), t->v_frate, t->v_width, t->v_height, nti)); + } + + if (!PTZR(t->ptzr)->ti.aspect_ratio_given) { + // The user hasn't set it. + if (0 != t->v_dwidth) + PTZR(t->ptzr)->set_video_display_width(t->v_dwidth); + if (0 != t->v_dheight) + PTZR(t->ptzr)->set_video_display_height(t->v_dheight); + } + + if (!PTZR(t->ptzr)->ti.pixel_cropping_specified && ((t->v_pcleft > 0) || (t->v_pctop > 0) || (t->v_pcright > 0) || (t->v_pcbottom > 0))) + PTZR(t->ptzr)->set_video_pixel_cropping(t->v_pcleft, t->v_pctop, t->v_pcright, t->v_pcbottom); + if (STEREO_MODE_UNSPECIFIED == PTZR(t->ptzr)->ti.stereo_mode) + PTZR(t->ptzr)->set_stereo_mode(t->v_stereo_mode); + + } else + init_passthrough_packetizer(t); +} + +void +kax_reader_c::create_audio_packetizer(kax_track_t *t, + track_info_c &nti) { + if ((0x0001 == t->a_formattag) || (0x0003 == t->a_formattag)) { + t->ptzr = add_packetizer(new pcm_packetizer_c(this, (int32_t)t->a_sfreq, t->a_channels, t->a_bps, nti, false, t->a_formattag==0x0003)); + mxinfo(FMT_TID "Using the PCM output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + } else if (0x0055 == t->a_formattag) { + t->ptzr = add_packetizer(new mp3_packetizer_c(this, (int32_t)t->a_sfreq, t->a_channels, true, nti)); + mxinfo(FMT_TID "Using the MPEG audio output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + } else if (0x2000 == t->a_formattag) { + int bsid = t->codec_id == "A_AC3/BSID9" ? 9 + : t->codec_id == "A_AC3/BSID10" ? 10 + : t->codec_id == MKV_A_EAC3 ? 16 + : 0; + + t->ptzr = add_packetizer(new ac3_packetizer_c(this, (int32_t)t->a_sfreq, t->a_channels, bsid, nti)); + mxinfo(FMT_TID "Using the %sAC3 output module.\n", ti.fname.c_str(), (int64_t)t->tnum, 16 == bsid ? "E" : ""); + + } else if (0x2001 == t->a_formattag) { + dts_header_t dtsheader; + + dtsheader.core_sampling_frequency = (unsigned int)t->a_sfreq; + dtsheader.audio_channels = t->a_channels; + + t->ptzr = add_packetizer(new dts_packetizer_c(this, dtsheader, nti, true)); + mxinfo(FMT_TID "Using the DTS output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + } else if (0xFFFE == t->a_formattag) { + t->ptzr = add_packetizer(new vorbis_packetizer_c(this, t->headers[0], t->header_sizes[0], t->headers[1], t->header_sizes[1], t->headers[2], t->header_sizes[2], nti)); + mxinfo(FMT_TID "Using the Vorbis output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + } else if ((FOURCC('M', 'P', '4', 'A') == t->a_formattag) || (0x00ff == t->a_formattag)) { + // A_AAC/MPEG2/MAIN + // 0123456789012345 + int id = 0; + int profile = 0; + int detected_profile = AAC_PROFILE_MAIN; + + if (FOURCC('M', 'P', '4', 'A') == t->a_formattag) { + if ((NULL != t->private_data) && (2 <= t->private_size)) { + int channels, sfreq, osfreq; + bool sbr; + + if (!parse_aac_data((unsigned char *)t->private_data, t->private_size, profile, channels, sfreq, osfreq, sbr)) + mxerror(FMT_TID "Malformed AAC codec initialization data " "found.\n", ti.fname.c_str(), (int64_t)t->tnum); + + detected_profile = profile; + id = AAC_ID_MPEG4; + if (sbr) + profile = AAC_PROFILE_SBR; + + } else if (!parse_aac_codec_id(string(t->codec_id), id, profile)) + mxerror(FMT_TID "Malformed codec id '%s'.\n", ti.fname.c_str(), (int64_t)t->tnum, t->codec_id.c_str()); + + } else { + int channels, sfreq, osfreq; + bool sbr; + + if (!parse_aac_data(((unsigned char *)t->private_data) + sizeof(alWAVEFORMATEX), t->private_size - sizeof(alWAVEFORMATEX), profile, channels, sfreq, osfreq, sbr)) + mxerror(FMT_TID "Malformed AAC codec initialization data " "found.\n", ti.fname.c_str(), (int64_t)t->tnum); + + detected_profile = profile; + id = AAC_ID_MPEG4; + if (sbr) + profile = AAC_PROFILE_SBR; + } + + if ((map_has_key(ti.all_aac_is_sbr, t->tnum) && ti.all_aac_is_sbr[t->tnum]) || (map_has_key(ti.all_aac_is_sbr, -1) && ti.all_aac_is_sbr[-1])) + profile = AAC_PROFILE_SBR; + + if ((map_has_key(ti.all_aac_is_sbr, t->tnum) && !ti.all_aac_is_sbr[t->tnum]) || (map_has_key(ti.all_aac_is_sbr, -1) && !ti.all_aac_is_sbr[-1])) + profile = detected_profile; + + t->ptzr = add_packetizer(new aac_packetizer_c(this, id, profile, (int32_t)t->a_sfreq, t->a_channels, nti, false, true)); + mxinfo(FMT_TID "Using the AAC output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + #if defined(HAVE_FLAC_FORMAT_H) + } else if ((FOURCC('f', 'L', 'a', 'C') == t->a_formattag) || (0xf1ac == t->a_formattag)) { + safefree(nti.private_data); + nti.private_data = NULL; + nti.private_size = 0; + + if (FOURCC('f', 'L', 'a', 'C') == t->a_formattag) + t->ptzr = add_packetizer(new flac_packetizer_c(this, (unsigned char *) t->private_data, t->private_size, nti)); + else { + flac_packetizer_c * p= new flac_packetizer_c(this, ((unsigned char *)t->private_data) + sizeof(alWAVEFORMATEX), t->private_size - sizeof(alWAVEFORMATEX), nti); + t->ptzr = add_packetizer(p); + } + + mxinfo(FMT_TID "Using the FLAC output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + #endif + + } else if (FOURCC('T', 'T', 'A', '1') == t->a_formattag) { + safefree(nti.private_data); + nti.private_data = NULL; + nti.private_size = 0; + + t->ptzr = add_packetizer(new tta_packetizer_c(this, t->a_channels, t->a_bps, (int32_t)t->a_sfreq, nti)); + mxinfo(FMT_TID "Using the TTA output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + } else if (FOURCC('W', 'V', 'P', '4') == t->a_formattag) { + wavpack_meta_t meta; + + nti.private_data = (unsigned char *)t->private_data; + nti.private_size = t->private_size; + + meta.bits_per_sample = t->a_bps; + meta.channel_count = t->a_channels; + meta.sample_rate = (uint32_t)t->a_sfreq; + meta.has_correction = t->max_blockadd_id != 0; + + if (0.0 < t->v_frate) + meta.samples_per_block = (uint32_t)(t->a_sfreq / t->v_frate); + + t->ptzr = add_packetizer(new wavpack_packetizer_c(this, meta, nti)); + nti.private_data = NULL; + nti.private_size = 0; + + mxinfo(FMT_TID "Using the WAVPACK output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + } else + init_passthrough_packetizer(t); + + if (0.0 != t->a_osfreq) + PTZR(t->ptzr)->set_audio_output_sampling_freq(t->a_osfreq); +} + +void +kax_reader_c::create_subtitle_packetizer(kax_track_t *t, + track_info_c &nti) { + if (t->codec_id == MKV_S_VOBSUB) { + t->ptzr = add_packetizer(new vobsub_packetizer_c(this, t->private_data, t->private_size, nti)); + mxinfo(FMT_TID "Using the VobSub output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + t->sub_type = 'v'; + + } else if (starts_with(t->codec_id, "S_TEXT", 6) || (t->codec_id == "S_SSA") || (t->codec_id == "S_ASS")) { + string new_codec_id = ((t->codec_id == "S_SSA") || (t->codec_id == "S_ASS")) ? string("S_TEXT/") + string(&t->codec_id[2]) : t->codec_id; + + t->ptzr = add_packetizer(new textsubs_packetizer_c(this, new_codec_id.c_str(), t->private_data, t->private_size, false, true, nti)); + mxinfo(FMT_TID "Using the text subtitle output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + t->sub_type = 't'; + + } else if (t->codec_id == MKV_S_KATE) { + t->ptzr = add_packetizer(new kate_packetizer_c(this, t->private_data, t->private_size, nti)); + t->sub_type = 'k'; + + mxinfo(FMT_TID "Using the Kate output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + } else + init_passthrough_packetizer(t); + +} + +void +kax_reader_c::create_button_packetizer(kax_track_t *t, + track_info_c &nti) { + if (t->codec_id == MKV_B_VOBBTN) { + mxinfo(FMT_TID "Using the VobBtn output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + safefree(nti.private_data); + nti.private_data = NULL; + nti.private_size = 0; + + t->ptzr = add_packetizer(new vobbtn_packetizer_c(this, t->v_width, t->v_height, nti)); + t->sub_type = 'b'; + + } else + init_passthrough_packetizer(t); } void kax_reader_c::create_packetizer(int64_t tid) { uint32_t i; - kax_track_t *t; - - t = NULL; + kax_track_t *t = NULL; for (i = 0; i < tracks.size(); i++) if (tracks[i]->tnum == tid) { t = tracks[i]; break; } - if (t == NULL) + + if ((NULL == t) || (-1 != t->ptzr) || !t->ok || !demuxing_requested(t->type, t->tnum)) return; - if ((t->ptzr == -1) && t->ok && demuxing_requested(t->type, t->tnum)) { - track_info_c nti(ti); - nti.private_data = - (unsigned char *)safememdup(t->private_data, t->private_size); - nti.private_size = t->private_size; - if (nti.language == "") - nti.language = t->language; - if (nti.track_name == "") - nti.track_name = t->track_name; - nti.id = t->tnum; // ID for this track. - if (t->tags != NULL) - nti.tags = dynamic_cast(t->tags->Clone()); + track_info_c nti(ti); + nti.private_data = (unsigned char *)safememdup(t->private_data, t->private_size); + nti.private_size = t->private_size; + nti.id = t->tnum; // ID for this track. - if (hack_engaged(ENGAGE_FORCE_PASSTHROUGH_PACKETIZER)) { - init_passthrough_packetizer(t); - set_packetizer_headers(t); + if (nti.language == "") + nti.language = t->language; + if (nti.track_name == "") + nti.track_name = t->track_name; + if (NULL != t->tags) + nti.tags = dynamic_cast(t->tags->Clone()); - return; - } - - switch (t->type) { - case 'v': - if ((t->codec_id == MKV_V_MSCOMP) && - mpeg4::p10::is_avc_fourcc(t->v_fourcc) && - !hack_engaged(ENGAGE_ALLOW_AVC_IN_VFW_MODE)) - create_mpeg4_p10_es_video_packetizer(t, nti); - - else if (starts_with(t->codec_id, "V_MPEG4", 7) || - (t->codec_id == MKV_V_MSCOMP) || - starts_with(t->codec_id, "V_REAL", 6) || - (t->codec_id == MKV_V_QUICKTIME) || - (t->codec_id == MKV_V_MPEG1) || - (t->codec_id == MKV_V_MPEG2) || - (t->codec_id == MKV_V_THEORA)) { - if ((t->codec_id == MKV_V_MPEG1) || (t->codec_id == MKV_V_MPEG2)) { - int version; - - version = t->codec_id[6] - '0'; - mxinfo(FMT_TID "Using the MPEG-%d video output module.\n", - ti.fname.c_str(), (int64_t)t->tnum, version); - t->ptzr = - add_packetizer(new mpeg1_2_video_packetizer_c(this, - version, - t->v_frate, - t->v_width, - t->v_height, - t->v_dwidth, - t->v_dheight, - true, nti)); - - } else if (IS_MPEG4_L2_CODECID(t->codec_id) || - IS_MPEG4_L2_FOURCC(t->v_fourcc)) { - bool is_native; - - mxinfo(FMT_TID "Using the MPEG-4 part 2 video output module.\n", - ti.fname.c_str(), (int64_t)t->tnum); - is_native = IS_MPEG4_L2_CODECID(t->codec_id); - t->ptzr = - add_packetizer(new mpeg4_p2_video_packetizer_c(this, - t->v_frate, - t->v_width, - t->v_height, - is_native, - nti)); - - } else if (t->codec_id == MKV_V_MPEG4_AVC) { - mxinfo(FMT_TID "Using the MPEG-4 part 10 (AVC) video output " - "module.\n", ti.fname.c_str(), (int64_t)t->tnum); - t->ptzr = - add_packetizer(new mpeg4_p10_video_packetizer_c(this, - t->v_frate, - t->v_width, - t->v_height, - nti)); - - } else { - mxinfo(FMT_TID "Using the video output module.\n", - ti.fname.c_str(), (int64_t)t->tnum); - t->ptzr = - add_packetizer(new video_packetizer_c(this, - t->codec_id.c_str(), - t->v_frate, - t->v_width, - t->v_height, - nti)); - } - - if (!PTZR(t->ptzr)->ti.aspect_ratio_given) { - // The user hasn't set it. - if (t->v_dwidth != 0) - PTZR(t->ptzr)->set_video_display_width(t->v_dwidth); - if (t->v_dheight != 0) - PTZR(t->ptzr)->set_video_display_height(t->v_dheight); - } - if (!PTZR(t->ptzr)->ti.pixel_cropping_specified && - ((t->v_pcleft > 0) || (t->v_pctop > 0) || - (t->v_pcright > 0) || (t->v_pcbottom > 0))) - PTZR(t->ptzr)->set_video_pixel_cropping(t->v_pcleft, t->v_pctop, - t->v_pcright, - t->v_pcbottom); - if (STEREO_MODE_UNSPECIFIED == PTZR(t->ptzr)->ti.stereo_mode) - PTZR(t->ptzr)->set_stereo_mode(t->v_stereo_mode); - } else - init_passthrough_packetizer(t); - - break; - - case 'a': - if (t->a_formattag == 0x0001 || t->a_formattag == 0x0003) { - t->ptzr = - add_packetizer(new pcm_packetizer_c(this, (int32_t)t->a_sfreq, - t->a_channels, t->a_bps, nti, - false, t->a_formattag==0x0003)); - mxinfo(FMT_TID "Using the PCM output module.\n", ti.fname.c_str(), - (int64_t)t->tnum); - - } else if (t->a_formattag == 0x0055) { - t->ptzr = - add_packetizer(new mp3_packetizer_c(this, (int32_t)t->a_sfreq, - t->a_channels, true, nti)); - mxinfo(FMT_TID "Using the MPEG audio output module.\n", - ti.fname.c_str(), (int64_t)t->tnum); - - } else if (t->a_formattag == 0x2000) { - int bsid; - - if (t->codec_id == "A_AC3/BSID9") - bsid = 9; - else if (t->codec_id == "A_AC3/BSID10") - bsid = 10; - else if (t->codec_id == MKV_A_EAC3) - bsid = 16; - else - bsid = 0; - t->ptzr = - add_packetizer(new ac3_packetizer_c(this, (int32_t)t->a_sfreq, - t->a_channels, bsid, nti)); - mxinfo(FMT_TID "Using the %sAC3 output module.\n", ti.fname.c_str(), - (int64_t)t->tnum, 16 == bsid ? "E" : ""); - - } else if (t->a_formattag == 0x2001) { - dts_header_t dtsheader; - - dtsheader.core_sampling_frequency = (unsigned int)t->a_sfreq; - dtsheader.audio_channels = t->a_channels; - t->ptzr = - add_packetizer(new dts_packetizer_c(this, dtsheader, nti, true)); - mxinfo(FMT_TID "Using the DTS output module.\n", ti.fname.c_str(), - (int64_t)t->tnum); - - } else if (t->a_formattag == 0xFFFE) { - t->ptzr = - add_packetizer(new vorbis_packetizer_c(this, - t->headers[0], - t->header_sizes[0], - t->headers[1], - t->header_sizes[1], - t->headers[2], - t->header_sizes[2], nti)); - mxinfo(FMT_TID "Using the Vorbis output module.\n", - ti.fname.c_str(), (int64_t)t->tnum); - } else if ((t->a_formattag == FOURCC('M', 'P', '4', 'A')) || - (t->a_formattag == 0x00ff)) { - // A_AAC/MPEG2/MAIN - // 0123456789012345 - int id, profile, detected_profile = AAC_PROFILE_MAIN; - - id = 0; - profile = 0; - if (t->a_formattag == FOURCC('M', 'P', '4', 'A')) { - int channels, sfreq, osfreq; - bool sbr; - - if ((t->private_data != NULL) && (t->private_size >= 2)) { - id = AAC_ID_MPEG4; - if (!parse_aac_data((unsigned char *)t->private_data, - t->private_size, profile, channels, sfreq, - osfreq, sbr)) - mxerror(FMT_TID "Malformed AAC codec initialization data " - "found.\n", ti.fname.c_str(), (int64_t)t->tnum); - detected_profile = profile; - if (sbr) - profile = AAC_PROFILE_SBR; - } else if (!parse_aac_codec_id(string(t->codec_id), id, profile)) - mxerror(FMT_TID "Malformed codec id '%s'.\n", ti.fname.c_str(), - (int64_t)t->tnum, t->codec_id.c_str()); - } else { - int channels, sfreq, osfreq; - bool sbr; - - id = AAC_ID_MPEG4; - if (!parse_aac_data(((unsigned char *)t->private_data) + - sizeof(alWAVEFORMATEX), - t->private_size - sizeof(alWAVEFORMATEX), - profile, channels, sfreq, osfreq, sbr)) - mxerror(FMT_TID "Malformed AAC codec initialization data " - "found.\n", ti.fname.c_str(), (int64_t)t->tnum); - detected_profile = profile; - if (sbr) - profile = AAC_PROFILE_SBR; - } - - if ((map_has_key(ti.all_aac_is_sbr, t->tnum) && - ti.all_aac_is_sbr[t->tnum]) || - (map_has_key(ti.all_aac_is_sbr, -1) && ti.all_aac_is_sbr[-1])) - profile = AAC_PROFILE_SBR; - - if ((map_has_key(ti.all_aac_is_sbr, t->tnum) && - !ti.all_aac_is_sbr[t->tnum]) || - (map_has_key(ti.all_aac_is_sbr, -1) && !ti.all_aac_is_sbr[-1])) - profile = detected_profile; - - t->ptzr = - add_packetizer(new aac_packetizer_c(this, id, profile, - (int32_t)t->a_sfreq, - t->a_channels, nti, - false, true)); - mxinfo(FMT_TID "Using the AAC output module.\n", ti.fname.c_str(), - (int64_t)t->tnum); - -#if defined(HAVE_FLAC_FORMAT_H) - } else if ((t->a_formattag == FOURCC('f', 'L', 'a', 'C')) || - (t->a_formattag == 0xf1ac)) { - safefree(nti.private_data); - nti.private_data = NULL; - nti.private_size = 0; - if (t->a_formattag == FOURCC('f', 'L', 'a', 'C')) - t->ptzr = - add_packetizer(new flac_packetizer_c(this, (unsigned char *) - t->private_data, - t->private_size, nti)); - else { - flac_packetizer_c *p; - p = new flac_packetizer_c(this, - ((unsigned char *)t->private_data) + - sizeof(alWAVEFORMATEX), - t->private_size - sizeof(alWAVEFORMATEX), - nti); - t->ptzr = add_packetizer(p); - } - mxinfo(FMT_TID "Using the FLAC output module.\n", ti.fname.c_str(), - (int64_t)t->tnum); - -#endif - } else if (t->a_formattag == FOURCC('T', 'T', 'A', '1')) { - safefree(nti.private_data); - nti.private_data = NULL; - nti.private_size = 0; - t->ptzr = - add_packetizer(new tta_packetizer_c(this, t->a_channels, - t->a_bps, (int32_t)t->a_sfreq, - nti)); - mxinfo(FMT_TID "Using the TTA output module.\n", ti.fname.c_str(), - (int64_t)t->tnum); - - } else if (t->a_formattag == FOURCC('W', 'V', 'P', '4')) { - wavpack_meta_t meta; - - nti.private_data = (unsigned char *)t->private_data; - nti.private_size = t->private_size; - meta.bits_per_sample = t->a_bps; - meta.channel_count = t->a_channels; - meta.sample_rate = (uint32_t)t->a_sfreq; - meta.has_correction = t->max_blockadd_id != 0; - if (t->v_frate > 0.0) - meta.samples_per_block = (uint32_t)(t->a_sfreq / t->v_frate); - t->ptzr = add_packetizer(new wavpack_packetizer_c(this, meta, nti)); - nti.private_data = NULL; - nti.private_size = 0; - mxinfo(FMT_TID "Using the WAVPACK output module.\n", - ti.fname.c_str(), (int64_t)t->tnum); - - } else - init_passthrough_packetizer(t); - - if (t->a_osfreq != 0.0) - PTZR(t->ptzr)->set_audio_output_sampling_freq(t->a_osfreq); - - break; - - case 's': - if (t->codec_id == MKV_S_VOBSUB) { - t->ptzr = - add_packetizer(new vobsub_packetizer_c(this, t->private_data, - t->private_size, nti)); - mxinfo(FMT_TID "Using the VobSub output module.\n", - ti.fname.c_str(), (int64_t)t->tnum); - - t->sub_type = 'v'; - - } else if (starts_with(t->codec_id, "S_TEXT", 6) || - (t->codec_id == "S_SSA") || (t->codec_id == "S_ASS")) { - string new_codec_id; - - if ((t->codec_id == "S_SSA") || (t->codec_id == "S_ASS")) - new_codec_id = string("S_TEXT/") + string(&t->codec_id[2]); - else - new_codec_id = t->codec_id; - t->ptzr = - add_packetizer(new textsubs_packetizer_c(this, - new_codec_id.c_str(), - t->private_data, - t->private_size, false, - true, nti)); - mxinfo(FMT_TID "Using the text subtitle output module.\n", - ti.fname.c_str(), (int64_t)t->tnum); - - t->sub_type = 't'; - - } else if (t->codec_id == MKV_S_KATE) { - t->ptzr = add_packetizer(new kate_packetizer_c(this, t->private_data, t->private_size, nti)); - t->sub_type = 'k'; - - mxinfo(FMT_TID "Using the Kate output module.\n", ti.fname.c_str(), (int64_t)t->tnum); - - } else - init_passthrough_packetizer(t); - - break; - - case 'b': - if (t->codec_id == MKV_B_VOBBTN) { - safefree(nti.private_data); - nti.private_data = NULL; - nti.private_size = 0; - t->ptzr = - add_packetizer(new vobbtn_packetizer_c(this, t->v_width, - t->v_height, nti)); - mxinfo(FMT_TID "Using the VobBtn output module.\n", - ti.fname.c_str(), (int64_t)t->tnum); - - t->sub_type = 'b'; - - } else - init_passthrough_packetizer(t); - - break; - - default: - mxerror(FMT_TID "Unsupported track type for this track.\n", - ti.fname.c_str(), (int64_t)t->tnum); - break; - } + if (hack_engaged(ENGAGE_FORCE_PASSTHROUGH_PACKETIZER)) { + init_passthrough_packetizer(t); set_packetizer_headers(t); - ptzr_to_track_map[reader_packetizers[t->ptzr]] = t; + + return; } + + switch (t->type) { + case 'v': + create_video_packetizer(t, nti); + break; + + case 'a': + create_audio_packetizer(t, nti); + break; + + case 's': + create_subtitle_packetizer(t, nti); + break; + + case 'b': + create_button_packetizer(t, nti); + break; + + default: + mxerror(FMT_TID "Unsupported track type for this track.\n", ti.fname.c_str(), (int64_t)t->tnum); + break; + } + + set_packetizer_headers(t); + ptzr_to_track_map[reader_packetizers[t->ptzr]] = t; } void @@ -1799,33 +1600,26 @@ kax_reader_c::create_mpeg4_p10_es_video_packetizer(kax_track_t *t, parser.set_nalu_size_length(ti.nalu_size_lengths[-1]); if (sizeof(alBITMAPINFOHEADER) < t->private_size) - parser.add_bytes((unsigned char *)t->private_data + - sizeof(alBITMAPINFOHEADER), - t->private_size - sizeof(alBITMAPINFOHEADER)); - parser.add_bytes(t->first_frame_data->get(), - t->first_frame_data->get_size()); + parser.add_bytes((unsigned char *)t->private_data + sizeof(alBITMAPINFOHEADER), t->private_size - sizeof(alBITMAPINFOHEADER)); + parser.add_bytes(t->first_frame_data->get(), t->first_frame_data->get_size()); parser.flush(); if (!parser.headers_parsed()) throw false; - memory_cptr avcc = parser.get_avcc(); + if (verbose) + mxinfo(FMT_TID "Using the MPEG-4 part 10 ES video output module.\n", ti.fname.c_str(), (int64_t)t->tnum); + + memory_cptr avcc = parser.get_avcc(); + mpeg4_p10_es_video_packetizer_c *ptzr = new mpeg4_p10_es_video_packetizer_c(this, avcc, t->v_width, t->v_height, nti); + t->ptzr = add_packetizer(ptzr); - mpeg4_p10_es_video_packetizer_c *ptzr = - new mpeg4_p10_es_video_packetizer_c(this, avcc, t->v_width, t->v_height, - nti); - t->ptzr = add_packetizer(ptzr); ptzr->enable_timecode_generation(false); if (t->default_duration) ptzr->set_track_default_duration(t->default_duration); - if (verbose) - mxinfo(FMT_TID "Using the MPEG-4 part 10 ES video output module.\n", - ti.fname.c_str(), (int64_t)t->tnum); } catch (...) { - mxerror(FMT_TID "Could not extract the decoder specific config data " - "(AVCC) from this AVC/h.264 track.\n", - ti.fname.c_str(), (int64_t)t->tnum); + mxerror(FMT_TID "Could not extract the decoder specific config data (AVCC) from this AVC/h.264 track.\n", ti.fname.c_str(), (int64_t)t->tnum); } } @@ -1833,60 +1627,42 @@ kax_reader_c::create_mpeg4_p10_es_video_packetizer(kax_track_t *t, void kax_reader_c::read_first_frame(kax_track_t *t) { - if ((NULL != t->first_frame_data.get()) || - (NULL == saved_l1)) + if ((NULL != t->first_frame_data.get()) || (NULL == saved_l1)) return; - int upper_lvl_el, bgidx; - // Elements for different levels - EbmlElement *l1 = NULL, *l2 = NULL; - KaxSimpleBlock *block_simple; - KaxBlockGroup *block_group; - KaxBlock *block; - KaxClusterTimecode *ctc; - kax_track_t *block_track; - in->save_pos(saved_l1->GetElementPosition()); - upper_lvl_el = 0; - try { - l1 = es->FindNextElement(segment->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true); + int upper_lvl_el = 0; + EbmlElement *l1 = es->FindNextElement(segment->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true); + EbmlElement *l2 = NULL; while ((l1 != NULL) && (upper_lvl_el <= 0)) { if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) { cluster = (KaxCluster *)l1; - cluster->Read(*es, KaxCluster::ClassInfos.Context, upper_lvl_el, l2, - true); + cluster->Read(*es, KaxCluster::ClassInfos.Context, upper_lvl_el, l2, true); - ctc = static_cast - (cluster->FindFirstElt(KaxClusterTimecode::ClassInfos, false)); + KaxClusterTimecode *ctc = static_cast (cluster->FindFirstElt(KaxClusterTimecode::ClassInfos, false)); if (NULL != ctc) { cluster_tc = uint64(*ctc); cluster->InitTimecode(cluster_tc, tc_scale); } + int bgidx; for (bgidx = 0; bgidx < cluster->ListSize(); bgidx++) { - if ((EbmlId(*(*cluster)[bgidx]) == - KaxSimpleBlock::ClassInfos.GlobalId)) { - block_simple = static_cast((*cluster)[bgidx]); + if ((EbmlId(*(*cluster)[bgidx]) == KaxSimpleBlock::ClassInfos.GlobalId)) { + KaxSimpleBlock *block_simple = static_cast((*cluster)[bgidx]); block_simple->SetParent(*cluster); - block_track = find_track_by_num(block_simple->TrackNum()); + kax_track_t *block_track = find_track_by_num(block_simple->TrackNum()); - if ((NULL == block_track) || - (0 == block_simple->NumberFrames())) + if ((NULL == block_track) || (0 == block_simple->NumberFrames())) continue; if (NULL == block_track->first_frame_data.get()) { DataBuffer &data_buffer = block_simple->GetBuffer(0); - block_track->first_frame_data = - memory_cptr(new memory_c(data_buffer.Buffer(), - data_buffer.Size())); - block_track->content_decoder. - reverse(block_track->first_frame_data, - CONTENT_ENCODING_SCOPE_BLOCK); + block_track->first_frame_data = memory_cptr(new memory_c(data_buffer.Buffer(), data_buffer.Size())); + block_track->content_decoder.reverse(block_track->first_frame_data, CONTENT_ENCODING_SCOPE_BLOCK); block_track->first_frame_data->grab(); if (t == block_track) { @@ -1896,29 +1672,23 @@ kax_reader_c::read_first_frame(kax_track_t *t) { } } - } else if ((EbmlId(*(*cluster)[bgidx]) == - KaxBlockGroup::ClassInfos.GlobalId)) { - block_group = static_cast((*cluster)[bgidx]); - block = static_cast - (block_group->FindFirstElt(KaxBlock::ClassInfos, false)); + } else if ((EbmlId(*(*cluster)[bgidx]) == KaxBlockGroup::ClassInfos.GlobalId)) { + KaxBlockGroup *block_group = static_cast((*cluster)[bgidx]); + KaxBlock *block = static_cast(block_group->FindFirstElt(KaxBlock::ClassInfos, false)); + if (NULL == block) continue; block->SetParent(*cluster); - block_track = find_track_by_num(block->TrackNum()); + kax_track_t *block_track = find_track_by_num(block->TrackNum()); - if ((NULL == block_track) || - (0 == block->NumberFrames())) + if ((NULL == block_track) || (0 == block->NumberFrames())) continue; if (NULL == block_track->first_frame_data.get()) { - DataBuffer &data_buffer = block->GetBuffer(0); - block_track->first_frame_data = - memory_cptr(new memory_c(data_buffer.Buffer(), - data_buffer.Size())); - block_track->content_decoder. - reverse(block_track->first_frame_data, - CONTENT_ENCODING_SCOPE_BLOCK); + DataBuffer &data_buffer = block->GetBuffer(0); + block_track->first_frame_data = memory_cptr(new memory_c(data_buffer.Buffer(), data_buffer.Size())); + block_track->content_decoder.reverse(block_track->first_frame_data, CONTENT_ENCODING_SCOPE_BLOCK); block_track->first_frame_data->grab(); if (t == block_track) { @@ -1938,25 +1708,21 @@ kax_reader_c::read_first_frame(kax_track_t *t) { break; } - if (upper_lvl_el > 0) { + if (0 < upper_lvl_el) { upper_lvl_el--; - if (upper_lvl_el > 0) + if (0 < upper_lvl_el) break; delete l1; l1 = l2; break; - } else if (upper_lvl_el < 0) { + } else if (0 > upper_lvl_el) upper_lvl_el++; - } - delete l1; - l1 = es->FindNextElement(segment->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true); + l1 = es->FindNextElement(segment->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true); } // while (l1 != NULL) - } catch (...) { } @@ -1969,30 +1735,10 @@ kax_reader_c::read_first_frame(kax_track_t *t) { file_status_e kax_reader_c::read(generic_packetizer_c *requested_ptzr, bool force) { - int upper_lvl_el, i, bgidx; - // Elements for different levels - EbmlElement *l0 = NULL, *l1 = NULL, *l2 = NULL; - KaxSimpleBlock *block_simple; - KaxBlockGroup *block_group; - KaxBlock *block; - KaxBlockAdditions *blockadd; - KaxBlockMore *blockmore; - KaxBlockAdditional *blockadd_data; - KaxReferenceBlock *ref_block; - KaxBlockDuration *duration; - KaxClusterTimecode *ctc; - KaxCodecState *codec_state; - int64_t block_fref, block_bref, block_duration, frame_duration; - uint64_t blockadd_id; - kax_track_t *block_track; - bool found_cluster, bref_found, fref_found; - if (tracks.size() == 0) return FILE_STATUS_DONE; - l0 = segment; - - if (saved_l1 == NULL) { // We're done. + if (NULL == saved_l1) { // We're done. flush_packetizers(); return FILE_STATUS_DONE; } @@ -2004,72 +1750,65 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, return FILE_STATUS_HOLDING; } - found_cluster = false; - upper_lvl_el = 0; - l1 = saved_l1; - saved_l1 = NULL; - duration = NULL; + bool found_cluster = false; + int upper_lvl_el = 0; + EbmlElement *l0 = segment; + EbmlElement *l1 = saved_l1; + EbmlElement *l2 = NULL; + saved_l1 = NULL; try { - while ((l1 != NULL) && (upper_lvl_el <= 0)) { - + while ((NULL != l1) && (0 >= upper_lvl_el)) { if (EbmlId(*l1) == KaxCluster::ClassInfos.GlobalId) { found_cluster = true; - cluster = (KaxCluster *)l1; - cluster->Read(*es, KaxCluster::ClassInfos.Context, upper_lvl_el, l2, - true); + cluster = (KaxCluster *)l1; + cluster->Read(*es, KaxCluster::ClassInfos.Context, upper_lvl_el, l2, true); - ctc = static_cast - (cluster->FindFirstElt(KaxClusterTimecode::ClassInfos, false)); - if (ctc == NULL) - die("r_matroska: Cluster does not contain a cluster timecode. " - "File is broken. Aborting."); + KaxClusterTimecode *ctc = static_cast(cluster->FindFirstElt(KaxClusterTimecode::ClassInfos, false)); + if (NULL == ctc) + die("r_matroska: Cluster does not contain a cluster timecode. File is broken. Aborting."); cluster_tc = uint64(*ctc); cluster->InitTimecode(cluster_tc, tc_scale); - if (first_timecode == -1) { + if (-1 == first_timecode) { first_timecode = cluster_tc * tc_scale; // If we're appending this file to another one then the core // needs the timecodes shifted to zero. - if (appending && (chapters != NULL) && (first_timecode > 0)) + if (appending && (NULL != chapters) && (0 < first_timecode)) adjust_chapter_timecodes(*chapters, -first_timecode); } + int bgidx; for (bgidx = 0; bgidx < cluster->ListSize(); bgidx++) { - block_duration = -1; - block_bref = VFT_IFRAME; - block_fref = VFT_NOBFRAME; - block_track = NULL; - bref_found = false; - fref_found = false; - if ((EbmlId(*(*cluster)[bgidx]) == - KaxSimpleBlock::ClassInfos.GlobalId)) { - block_simple = static_cast((*cluster)[bgidx]); + int64_t block_duration = -1; + int64_t block_bref = VFT_IFRAME; + int64_t block_fref = VFT_NOBFRAME; + bool bref_found = false; + bool fref_found = false; + + if ((EbmlId(*(*cluster)[bgidx]) == KaxSimpleBlock::ClassInfos.GlobalId)) { + KaxSimpleBlock *block_simple = static_cast((*cluster)[bgidx]); block_simple->SetParent(*cluster); - block_track = find_track_by_num(block_simple->TrackNum()); + kax_track_t *block_track = find_track_by_num(block_simple->TrackNum()); if (NULL == block_track) { - mxwarn(FMT_FN "A block was found at timestamp " FMT_TIMECODE - "for track number %u. However, no headers where found for" - " that track number. The block will be skipped.\n", - ti.fname.c_str(), - ARG_TIMECODE_NS(block_simple->GlobalTimecode()), - (unsigned int)block_simple->TrackNum()); + mxwarn(FMT_FN "A block was found at timestamp " FMT_TIMECODE "for track number %u. However, no headers where found for that track number. " + "The block will be skipped.\n", ti.fname.c_str(), ARG_TIMECODE_NS(block_simple->GlobalTimecode()), (unsigned int)block_simple->TrackNum()); continue; } - if (block_track->v_frate != 0) + if (0 != block_track->v_frate) block_duration = (int64_t)(1000000000.0 / block_track->v_frate); - frame_duration = (block_duration == -1) ? 0 : block_duration; + int64_t frame_duration = (block_duration == -1) ? 0 : block_duration; - if ((block_track->type == 's') && (block_duration == -1)) + if (('s' == block_track->type) && (-1 == block_duration)) block_duration = 0; if (block_track->ignore_duration_hack) { frame_duration = 0; - if (block_duration > 0) + if (0 < block_duration) block_duration = 0; } @@ -2090,71 +1829,51 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, if (appending) last_timecode -= first_timecode; - if ((block_track->ptzr != -1) && block_track->passthrough) { + if ((-1 != block_track->ptzr) && block_track->passthrough) { // The handling for passthrough is a bit different. We don't have // any special cases, e.g. 0 terminating a string for the subs // and stuff. Just pass everything through as it is. + int i; for (i = 0; i < (int)block_simple->NumberFrames(); i++) { DataBuffer &data = block_simple->GetBuffer(i); - packet_t *packet = - new packet_t(new memory_c((unsigned char *)data.Buffer(), - data.Size(), false), - last_timecode + i * frame_duration, - block_duration, block_bref, block_fref); - packet->duration_mandatory = duration != NULL; - ((passthrough_packetizer_c *)PTZR(block_track->ptzr))-> - process(packet_cptr(packet)); + packet_t *packet = new packet_t(new memory_c((unsigned char *)data.Buffer(), data.Size(), false), + last_timecode + i * frame_duration, block_duration, block_bref, block_fref); + + ((passthrough_packetizer_c *)PTZR(block_track->ptzr))->process(packet_cptr(packet)); } - } else if (block_track->ptzr != -1) { - + } else if (-1 != block_track->ptzr) { + int i; for (i = 0; i < (int)block_simple->NumberFrames(); i++) { DataBuffer &data_buffer = block_simple->GetBuffer(i); - memory_cptr data(new memory_c(data_buffer.Buffer(), - data_buffer.Size(), false)); - block_track->content_decoder. - reverse(data, CONTENT_ENCODING_SCOPE_BLOCK); + memory_cptr data(new memory_c(data_buffer.Buffer(), data_buffer.Size(), false)); + block_track->content_decoder.reverse(data, CONTENT_ENCODING_SCOPE_BLOCK); - if ((block_track->type == 's') && - (block_track->sub_type == 't')) { - if ((data->get_size() > 2) || - ((data->get_size() > 0) && (*data->get() != ' ') && - (*data->get() != 0) && !iscr(*data->get()))) { - char *lines; - - lines = (char *)safemalloc(data->get_size() + 1); + if (('s' == block_track->type) && ('t' == block_track->sub_type)) { + if ((2 < data->get_size()) || ((0 < data->get_size()) && (' ' != *data->get()) && (0 != *data->get()) && !iscr(*data->get()))) { + char *lines = (char *)safemalloc(data->get_size() + 1); lines[data->get_size()] = 0; memcpy(lines, data->get(), data->get_size()); - PTZR(block_track->ptzr)-> - process(new packet_t(new memory_c((unsigned char *)lines, - 0, true), - last_timecode, block_duration, - block_bref, block_fref)); - } - } else { - packet_cptr packet(new packet_t(data, last_timecode + i * - frame_duration, - block_duration, block_bref, - block_fref)); + PTZR(block_track->ptzr)-> process(new packet_t(new memory_c((unsigned char *)lines, 0, true), last_timecode, block_duration, block_bref, block_fref)); + } + + } else { + packet_cptr packet(new packet_t(data, last_timecode + i * frame_duration, block_duration, block_bref, block_fref)); PTZR(block_track->ptzr)->process(packet); } } } - block_track->previous_timecode = (int64_t)last_timecode; - block_track->units_processed += block_simple->NumberFrames(); + block_track->previous_timecode = (int64_t)last_timecode; + block_track->units_processed += block_simple->NumberFrames(); - } else if ((EbmlId(*(*cluster)[bgidx]) == - KaxBlockGroup::ClassInfos.GlobalId)) { - block_group = static_cast((*cluster)[bgidx]); - block = NULL; + } else if ((EbmlId(*(*cluster)[bgidx]) == KaxBlockGroup::ClassInfos.GlobalId)) { + KaxBlockGroup *block_group = static_cast((*cluster)[bgidx]); + KaxReferenceBlock *ref_block = static_cast(block_group->FindFirstElt(KaxReferenceBlock::ClassInfos, false)); - ref_block = static_cast - (block_group->FindFirstElt(KaxReferenceBlock::ClassInfos, - false)); - while (ref_block != NULL) { - if (int64(*ref_block) <= 0) { + while (NULL != ref_block) { + if (0 >= int64(*ref_block)) { block_bref = int64(*ref_block) * tc_scale; bref_found = true; } else { @@ -2162,52 +1881,40 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, fref_found = true; } - ref_block = static_cast - (block_group->FindNextElt(*ref_block, false)); + ref_block = static_cast(block_group->FindNextElt(*ref_block, false)); } - block = static_cast - (block_group->FindFirstElt(KaxBlock::ClassInfos, false)); + KaxBlock *block = static_cast(block_group->FindFirstElt(KaxBlock::ClassInfos, false)); if (NULL == block) { - mxwarn(FMT_FN "A block group was found at position " LLD ", but " - "no block element was found inside it. This might make " - "mkvmerge crash.\n", ti.fname.c_str(), - block_group->GetElementPosition()); + mxwarn(FMT_FN "A block group was found at position " LLD ", but no block element was found inside it. This might make mkvmerge crash.\n", + ti.fname.c_str(), block_group->GetElementPosition()); continue; } block->SetParent(*cluster); - block_track = find_track_by_num(block->TrackNum()); + kax_track_t *block_track = find_track_by_num(block->TrackNum()); if (NULL == block_track) { - mxwarn(FMT_FN "A block was found at timestamp " FMT_TIMECODE - "for track number %u. However, no headers where found for" - " that track number. The block will be skipped.\n", - ti.fname.c_str(), - ARG_TIMECODE_NS(block->GlobalTimecode()), - (unsigned int)block->TrackNum()); + mxwarn(FMT_FN "A block was found at timestamp " FMT_TIMECODE "for track number %u. However, no headers where found for that track number. " + "The block will be skipped.\n", ti.fname.c_str(), ARG_TIMECODE_NS(block->GlobalTimecode()), (unsigned int)block->TrackNum()); continue; } - blockadd = static_cast - (block_group->FindFirstElt(KaxBlockAdditions::ClassInfos, - false)); + KaxBlockAdditions *blockadd = static_cast(block_group->FindFirstElt(KaxBlockAdditions::ClassInfos, false)); + KaxBlockDuration *duration = static_cast(block_group->FindFirstElt(KaxBlockDuration::ClassInfos, false)); - duration = static_cast - (block_group->FindFirstElt(KaxBlockDuration::ClassInfos, false)); - if (duration != NULL) - block_duration = (int64_t)uint64(*duration) * tc_scale / - block->NumberFrames(); - else if (block_track->v_frate != 0) + if (NULL != duration) + block_duration = (int64_t)uint64(*duration) * tc_scale / block->NumberFrames(); + else if (0 != block_track->v_frate) block_duration = (int64_t)(1000000000.0 / block_track->v_frate); - frame_duration = (block_duration == -1) ? 0 : block_duration; + int64_t frame_duration = (block_duration == -1) ? 0 : block_duration; - if ((block_track->type == 's') && (block_duration == -1)) + if (('s' == block_track->type) && (-1 == block_duration)) block_duration = 0; if (block_track->ignore_duration_hack) { frame_duration = 0; - if (block_duration > 0) + if (0 < block_duration) block_duration = 0; } @@ -2217,16 +1924,13 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, if (appending) last_timecode -= first_timecode; - codec_state = static_cast - (block_group->FindFirstElt(KaxCodecState::ClassInfos)); + KaxCodecState *codec_state = static_cast(block_group->FindFirstElt(KaxCodecState::ClassInfos)); if ((NULL != codec_state) && !hack_engaged(ENGAGE_USE_CODEC_STATE)) - mxerror(FMT_TID "This track uses a Matroska feature called " - "'Codec state elements'. mkvmerge supports these but " - "this feature has not been turned on with the option " - "'--engage use_codec_state'.\n", ti.fname.c_str(), - (int64_t)block_track->tnum); + mxerror(FMT_TID "This track uses a Matroska feature called 'Codec state elements'. mkvmerge supports these but " + "this feature has not been turned on with the option '--engage use_codec_state'.\n", + ti.fname.c_str(), (int64_t)block_track->tnum); - if ((block_track->ptzr != -1) && block_track->passthrough) { + if ((-1 != block_track->ptzr) && block_track->passthrough) { // The handling for passthrough is a bit different. We don't have // any special cases, e.g. 0 terminating a string for the subs // and stuff. Just pass everything through as it is. @@ -2235,24 +1939,22 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, if (fref_found) block_fref += last_timecode; + int i; for (i = 0; i < (int)block->NumberFrames(); i++) { - DataBuffer &data = block->GetBuffer(i); - packet_t *packet = - new packet_t(new memory_c((unsigned char *)data.Buffer(), - data.Size(), false), - last_timecode + i * frame_duration, - block_duration, block_bref, block_fref); + DataBuffer &data = block->GetBuffer(i); + packet_t *packet = new packet_t(new memory_c((unsigned char *)data.Buffer(), data.Size(), false), + last_timecode + i * frame_duration, block_duration, block_bref, block_fref); packet->duration_mandatory = duration != NULL; + if (NULL != codec_state) - packet->codec_state = clone_memory(codec_state->GetBuffer(), - codec_state->GetSize()); - ((passthrough_packetizer_c *)PTZR(block_track->ptzr))-> - process(packet_cptr(packet)); + packet->codec_state = clone_memory(codec_state->GetBuffer(), codec_state->GetSize()); + + ((passthrough_packetizer_c *)PTZR(block_track->ptzr))->process(packet_cptr(packet)); } - } else if (block_track->ptzr != -1) { + } else if (-1 != block_track->ptzr) { if (bref_found) { - if (block_track->a_formattag == FOURCC('r', 'e', 'a', 'l')) + if (FOURCC('r', 'e', 'a', 'l') == block_track->a_formattag) block_bref = block_track->previous_timecode; else block_bref += (int64_t)last_timecode; @@ -2260,61 +1962,43 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, if (fref_found) block_fref += (int64_t)last_timecode; + int i; for (i = 0; i < (int)block->NumberFrames(); i++) { DataBuffer &data_buffer = block->GetBuffer(i); - memory_cptr data(new memory_c(data_buffer.Buffer(), - data_buffer.Size(), false)); - block_track->content_decoder. - reverse(data, CONTENT_ENCODING_SCOPE_BLOCK); + memory_cptr data(new memory_c(data_buffer.Buffer(), data_buffer.Size(), false)); + block_track->content_decoder.reverse(data, CONTENT_ENCODING_SCOPE_BLOCK); - if ((block_track->type == 's') && - (block_track->sub_type == 't')) { - if ((data->get_size() > 2) || - ((data->get_size() > 0) && (*data->get() != ' ') && - (*data->get() != 0) && !iscr(*data->get()))) { - char *lines; - - lines = (char *)safemalloc(data->get_size() + 1); + if (('s' == block_track->type) && ('t' == block_track->sub_type)) { + if ((2 < data->get_size()) || ((0 < data->get_size()) && (' ' != *data->get()) && (0 != *data->get()) && !iscr(*data->get()))) { + char *lines = (char *)safemalloc(data->get_size() + 1); lines[data->get_size()] = 0; memcpy(lines, data->get(), data->get_size()); - packet_t *packet = - new packet_t(new memory_c((unsigned char *)lines, 0, - true), - last_timecode, block_duration, - block_bref, block_fref); + packet_t *packet = new packet_t(new memory_c((unsigned char *)lines, 0, true), last_timecode, block_duration, block_bref, block_fref); if (NULL != codec_state) - packet->codec_state = - clone_memory(codec_state->GetBuffer(), - codec_state->GetSize()); + packet->codec_state = clone_memory(codec_state->GetBuffer(), codec_state->GetSize()); + PTZR(block_track->ptzr)->process(packet); } + } else { - packet_cptr packet(new packet_t(data, last_timecode + i * - frame_duration, - block_duration, block_bref, - block_fref)); + packet_cptr packet(new packet_t(data, last_timecode + i * frame_duration, block_duration, block_bref, block_fref)); if (NULL != codec_state) - packet->codec_state = - clone_memory(codec_state->GetBuffer(), - codec_state->GetSize()); + packet->codec_state = clone_memory(codec_state->GetBuffer(), codec_state->GetSize()); + if (blockadd) { - for (i = 0; i < blockadd->ListSize(); i++) { - if (!(is_id((*blockadd)[i], KaxBlockMore))) + int k; + for (k = 0; k < blockadd->ListSize(); k++) { + if (!(is_id((*blockadd)[k], KaxBlockMore))) continue; - blockmore = static_cast((*blockadd)[i]); - blockadd_id = - uint64(*static_cast - (&GetChild(*blockmore))); - blockadd_data = - &GetChild(*blockmore); - memory_cptr - blockadded(new memory_c(blockadd_data->GetBuffer(), - blockadd_data->GetSize(), - false)); - block_track->content_decoder. - reverse(blockadded, CONTENT_ENCODING_SCOPE_BLOCK); + + KaxBlockMore *blockmore = static_cast((*blockadd)[k]); + KaxBlockAdditional *blockadd_data = &GetChild(*blockmore); + + memory_cptr blockadded(new memory_c(blockadd_data->GetBuffer(), blockadd_data->GetSize(), false)); + block_track->content_decoder.reverse(blockadded, CONTENT_ENCODING_SCOPE_BLOCK); + packet->data_adds.push_back(blockadded); } } @@ -2323,8 +2007,8 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, } } - block_track->previous_timecode = (int64_t)last_timecode; - block_track->units_processed += block->NumberFrames(); + block_track->previous_timecode = (int64_t)last_timecode; + block_track->units_processed += block->NumberFrames(); } } } @@ -2337,22 +2021,19 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, break; } - if (upper_lvl_el > 0) { + if (0 < upper_lvl_el) { upper_lvl_el--; - if (upper_lvl_el > 0) + if (0 < upper_lvl_el) break; delete l1; saved_l1 = l2; break; - } else if (upper_lvl_el < 0) { + } else if (0 > upper_lvl_el) upper_lvl_el++; - } - delete l1; - l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, - 0xFFFFFFFFL, true); + l1 = es->FindNextElement(l0->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, true); if (found_cluster) { saved_l1 = l1; break; @@ -2369,10 +2050,9 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, if (found_cluster) return FILE_STATUS_MOREDATA; - else { - flush_packetizers(); - return FILE_STATUS_DONE; - } + + flush_packetizers(); + return FILE_STATUS_DONE; } // }}} @@ -2381,7 +2061,7 @@ kax_reader_c::read(generic_packetizer_c *requested_ptzr, int kax_reader_c::get_progress() { - if (segment_duration != 0) + if (0 != segment_duration) return (last_timecode - first_timecode) * 100 / segment_duration; return 100 * in->getFilePointer() / file_size; @@ -2389,14 +2069,12 @@ kax_reader_c::get_progress() { void kax_reader_c::set_headers() { - uint32_t i; - generic_reader_c::set_headers(); + int i; for (i = 0; i < tracks.size(); i++) - if ((tracks[i]->ptzr != -1) && tracks[i]->passthrough) - PTZR(tracks[i]->ptzr)->get_track_entry()-> - EnableLacing(tracks[i]->lacing_flag); + if ((-1 != tracks[i]->ptzr) && tracks[i]->passthrough) + PTZR(tracks[i]->ptzr)->get_track_entry()->EnableLacing(tracks[i]->lacing_flag); } // }}} @@ -2406,8 +2084,6 @@ kax_reader_c::set_headers() { void kax_reader_c::identify() { vector verbose_info; - int i; - string info; if (!title.empty()) verbose_info.push_back(mxsprintf("title:%s", escape(title).c_str())); @@ -2416,6 +2092,7 @@ kax_reader_c::identify() { id_result_container("Matroska", verbose_info); + int i; for (i = 0; i < tracks.size(); i++) { if (!tracks[i]->ok) continue; @@ -2441,21 +2118,23 @@ kax_reader_c::identify() { else if (tracks[i]->codec_id == MKV_V_MPEG4_AVC) verbose_info.push_back("packetizer:mpeg4_p10_video"); - info = tracks[i]->codec_id; + string info = tracks[i]->codec_id; if (tracks[i]->ms_compat) info += string(", ") + - (tracks[i]->type == 'v' ? tracks[i]->v_fourcc : - tracks[i]->a_formattag == 0x0001 ? "PCM" : - tracks[i]->a_formattag == 0x0003 ? "PCM" : - tracks[i]->a_formattag == 0x0055 ? "MP3" : - tracks[i]->a_formattag == 0x2000 ? "AC3" : "unknown"); + ( tracks[i]->type == 'v' ? tracks[i]->v_fourcc + : tracks[i]->a_formattag == 0x0001 ? "PCM" + : tracks[i]->a_formattag == 0x0003 ? "PCM" + : tracks[i]->a_formattag == 0x0055 ? "MP3" + : tracks[i]->a_formattag == 0x2000 ? "AC3" + : "unknown"); id_result_track(tracks[i]->tnum, - tracks[i]->type == 'v' ? ID_RESULT_TRACK_VIDEO : - tracks[i]->type == 'a' ? ID_RESULT_TRACK_AUDIO : - tracks[i]->type == 'b' ? ID_RESULT_TRACK_BUTTONS : - tracks[i]->type == 's' ? ID_RESULT_TRACK_SUBTITLES : "unknown", + tracks[i]->type == 'v' ? ID_RESULT_TRACK_VIDEO + : tracks[i]->type == 'a' ? ID_RESULT_TRACK_AUDIO + : tracks[i]->type == 'b' ? ID_RESULT_TRACK_BUTTONS + : tracks[i]->type == 's' ? ID_RESULT_TRACK_SUBTITLES + : "unknown", info, verbose_info); } diff --git a/src/input/r_matroska.h b/src/input/r_matroska.h index 99755b9c7..b45103941 100644 --- a/src/input/r_matroska.h +++ b/src/input/r_matroska.h @@ -47,7 +47,7 @@ struct kax_track_t { bool ms_compat; char type; // 'v' = video, 'a' = audio, 't' = text subs, 'b' = buttons - char sub_type; // 't' = text, 'v' = VobSub + char sub_type; // 't' = text, 'v' = VobSub bool passthrough; // No special packetizer available. uint32_t min_cache, max_cache, max_blockadd_id; @@ -124,7 +124,7 @@ struct kax_track_t { } ~kax_track_t() { safefree(private_data); - if (tags != NULL) + if (NULL != tags) delete tags; } }; @@ -171,7 +171,6 @@ public: static int probe_file(mm_io_c *io, int64_t size); protected: - virtual int read_headers(); virtual void init_passthrough_packetizer(kax_track_t *t); virtual void set_packetizer_headers(kax_track_t *t); virtual void read_first_frame(kax_track_t *t); @@ -184,8 +183,20 @@ protected: virtual void handle_chapters(mm_io_c *io, EbmlElement *l0, int64_t pos); virtual void handle_tags(mm_io_c *io, EbmlElement *l0, int64_t pos); - virtual void create_mpeg4_p10_es_video_packetizer(kax_track_t *t, - track_info_c &nti); + virtual void create_video_packetizer(kax_track_t *t, track_info_c &nti); + virtual void create_audio_packetizer(kax_track_t *t, track_info_c &nti); + virtual void create_subtitle_packetizer(kax_track_t *t, track_info_c &nti); + virtual void create_button_packetizer(kax_track_t *t, track_info_c &nti); + virtual void create_mpeg4_p10_es_video_packetizer(kax_track_t *t, track_info_c &nti); + + virtual void read_headers_info(EbmlElement *&l1, EbmlElement *&l2, int &upper_lvl_el); + virtual void read_headers_info_writing_app(KaxWritingApp *&kwriting_app); + virtual void read_headers_track_audio(kax_track_t *&track, KaxTrackAudio *&ktaudio); + virtual void read_headers_track_video(kax_track_t *&track, KaxTrackVideo *&ktvideo); + virtual void read_headers_tracks(EbmlElement *&l1, EbmlElement *&l2, int &upper_lvl_el); + virtual void read_headers_seek_head(EbmlElement *&l0, EbmlElement *&l1, + vector &deferred_tags, vector &deferred_chapters, vector &deferred_attachments); + virtual int read_headers(); };