コード例 #1
0
ファイル: timecodes_v2.cpp プロジェクト: MIKULINK/mkvtoolnix
void
extract_timecodes(const std::string &file_name,
                  std::vector<track_spec_t> &tspecs,
                  int version) {
    if (tspecs.empty())
        mxerror(Y("Nothing to do.\n"));

    // open input file
    mm_io_c *in;
    try {
        in = new mm_file_io_c(file_name, MODE_READ);
    } catch (mtx::mm_io::exception &ex) {
        show_error(boost::format(Y("The file '%1%' could not be opened for reading: %2%.\n")) % file_name % ex);
        return;
    }

    try {
        int64_t file_size = in->get_size();
        EbmlStream *es    = new EbmlStream(*in);

        // Find the EbmlHead element. Must be the first one.
        EbmlElement *l0 = es->FindNextID(EBML_INFO(EbmlHead), 0xFFFFFFFFL);
        if (!l0) {
            show_error(Y("Error: No EBML head found."));
            delete es;

            return;
        }

        // Don't verify its data for now.
        l0->SkipData(*es, EBML_CONTEXT(l0));
        delete l0;

        while (1) {
            // Next element must be a segment
            l0 = es->FindNextID(EBML_INFO(KaxSegment), 0xFFFFFFFFFFFFFFFFLL);
            if (!l0) {
                show_error(Y("No segment/level 0 element found."));
                return;
            }
            if (EbmlId(*l0) == EBML_ID(KaxSegment)) {
                show_element(l0, 0, Y("Segment"));
                break;
            }

            l0->SkipData(*es, EBML_CONTEXT(l0));
            delete l0;
        }

        bool tracks_found = false;
        int upper_lvl_el  = 0;
        uint64_t tc_scale = TIMECODE_SCALE;

        // We've got our segment, so let's find the tracks
        EbmlElement *l1   = es->FindNextElement(EBML_CONTEXT(l0), upper_lvl_el, 0xFFFFFFFFL, true, 1);
        EbmlElement *l2   = nullptr;
        EbmlElement *l3   = nullptr;

        while (l1 && (0 >= upper_lvl_el)) {
            if (EbmlId(*l1) == EBML_ID(KaxInfo)) {
                // General info about this Matroska file
                show_element(l1, 1, Y("Segment information"));

                upper_lvl_el = 0;
                l2           = es->FindNextElement(EBML_CONTEXT(l1), upper_lvl_el, 0xFFFFFFFFL, true, 1);
                while (l2 && (0 >= upper_lvl_el)) {
                    if (EbmlId(*l2) == EBML_ID(KaxTimecodeScale)) {
                        KaxTimecodeScale &ktc_scale = *static_cast<KaxTimecodeScale *>(l2);
                        ktc_scale.ReadData(es->I_O());
                        tc_scale = ktc_scale.GetValue();
                        show_element(l2, 2, boost::format(Y("Timecode scale: %1%")) % tc_scale);
                    } else
                        l2->SkipData(*es, EBML_CONTEXT(l2));

                    if (!in_parent(l1)) {
                        delete l2;
                        break;
                    }

                    if (0 > upper_lvl_el) {
                        upper_lvl_el++;
                        if (0 > upper_lvl_el)
                            break;

                    }

                    l2->SkipData(*es, EBML_CONTEXT(l2));
                    delete l2;
                    l2 = es->FindNextElement(EBML_CONTEXT(l1), upper_lvl_el, 0xFFFFFFFFL, true);
                }

            } else if ((EbmlId(*l1) == EBML_ID(KaxTracks)) && !tracks_found) {

                // Yep, we've found our KaxTracks element. Now find all tracks
                // contained in this segment.
                show_element(l1, 1, Y("Segment tracks"));

                tracks_found = true;
                l1->Read(*es, EBML_CLASS_CONTEXT(KaxTracks), upper_lvl_el, l2, true);
                find_and_verify_track_uids(*dynamic_cast<KaxTracks *>(l1), tspecs);
                create_timecode_files(*dynamic_cast<KaxTracks *>(l1), tspecs, version);

            } else if (EbmlId(*l1) == EBML_ID(KaxCluster)) {
                show_element(l1, 1, Y("Cluster"));
                KaxCluster *cluster = (KaxCluster *)l1;
                uint64_t cluster_tc = 0;

                if (0 == verbose)
                    mxinfo(boost::format(Y("Progress: %1%%%%2%")) % (int)(in->getFilePointer() * 100 / file_size) % "\r");

                upper_lvl_el = 0;
                l2           = es->FindNextElement(EBML_CONTEXT(l1), upper_lvl_el, 0xFFFFFFFFL, true, 1);
                while (l2 && (0 >= upper_lvl_el)) {

                    if (EbmlId(*l2) == EBML_ID(KaxClusterTimecode)) {
                        KaxClusterTimecode &ctc = *static_cast<KaxClusterTimecode *>(l2);
                        ctc.ReadData(es->I_O());
                        cluster_tc = ctc.GetValue();
                        show_element(l2, 2, boost::format(Y("Cluster timecode: %|1$.3f|s")) % ((float)cluster_tc * (float)tc_scale / 1000000000.0));
                        cluster->InitTimecode(cluster_tc, tc_scale);

                    } else if (EbmlId(*l2) == EBML_ID(KaxBlockGroup)) {
                        show_element(l2, 2, Y("Block group"));

                        l2->Read(*es, EBML_CLASS_CONTEXT(KaxBlockGroup), upper_lvl_el, l3, true);
                        handle_blockgroup(*static_cast<KaxBlockGroup *>(l2), *cluster, tc_scale);

                    } else if (EbmlId(*l2) == EBML_ID(KaxSimpleBlock)) {
                        show_element(l2, 2, Y("Simple block"));

                        l2->Read(*es, EBML_CLASS_CONTEXT(KaxSimpleBlock), upper_lvl_el, l3, true);
                        handle_simpleblock(*static_cast<KaxSimpleBlock *>(l2), *cluster);

                    } else
                        l2->SkipData(*es, EBML_CONTEXT(l2));

                    if (!in_parent(l1)) {
                        delete l2;
                        break;
                    }

                    if (0 < upper_lvl_el) {
                        upper_lvl_el--;
                        if (0 < upper_lvl_el)
                            break;
                        delete l2;
                        l2 = l3;
                        continue;

                    } else if (0 > upper_lvl_el) {
                        upper_lvl_el++;
                        if (0 > upper_lvl_el)
                            break;

                    }

                    l2->SkipData(*es, EBML_CONTEXT(l2));
                    delete l2;
                    l2 = es->FindNextElement(EBML_CONTEXT(l1), upper_lvl_el, 0xFFFFFFFFL, true);

                } // while (l2)

            } else
                l1->SkipData(*es, EBML_CONTEXT(l1));

            if (!in_parent(l0)) {
                delete l1;
                break;
            }

            if (0 < upper_lvl_el) {
                upper_lvl_el--;
                if (0 < upper_lvl_el)
                    break;
                delete l1;
                l1 = l2;
                continue;

            } else if (0 > upper_lvl_el) {
                upper_lvl_el++;
                if (0 > upper_lvl_el)
                    break;

            }

            l1->SkipData(*es, EBML_CONTEXT(l1));
            delete l1;
            l1 = es->FindNextElement(EBML_CONTEXT(l0), upper_lvl_el, 0xFFFFFFFFL, true);

        } // while (l1)

        delete l0;
        delete es;
        delete in;

        close_timecode_files();

        if (0 == verbose)
            mxinfo(Y("Progress: 100%\n"));

    } catch (...) {
        show_error(Y("Caught exception"));
        delete in;

        close_timecode_files();
    }
}
コード例 #2
0
ファイル: EbmlMaster.cpp プロジェクト: ares89/vlc
/*!
	\brief Method to help reading a Master element and all subsequent children quickly
	\todo add an option to discard even unknown elements
	\todo handle when a mandatory element is not found
*/
void EbmlMaster::Read(EbmlStream & inDataStream, const EbmlSemanticContext & sContext, int & UpperEltFound, EbmlElement * & FoundElt, bool AllowDummyElt, ScopeMode ReadFully)
{
	if (ReadFully != SCOPE_NO_DATA)
	{
		EbmlElement * ElementLevelA;
		// remove all existing elements, including the mandatory ones...
		size_t Index;
		for (Index=0; Index<ElementList.size(); Index++) {
			if (!(*ElementList[Index]).IsLocked()) {
				delete ElementList[Index];
			}
		}
		ElementList.clear();
		uint64 MaxSizeToRead;

		if (IsFiniteSize())
			MaxSizeToRead = GetSize();
		else
			MaxSizeToRead = 0x7FFFFFFF;

		// read blocks and discard the ones we don't care about
		if (MaxSizeToRead > 0)
		{
			inDataStream.I_O().setFilePointer(GetSizePosition() + GetSizeLength(), seek_beginning);
			ElementLevelA = inDataStream.FindNextElement(sContext, UpperEltFound, MaxSizeToRead, AllowDummyElt);
			while (ElementLevelA != NULL && UpperEltFound <= 0 && MaxSizeToRead > 0) {
				if (IsFiniteSize())
					MaxSizeToRead = GetEndPosition() - ElementLevelA->GetEndPosition(); // even if it's the default value
				if (!AllowDummyElt && ElementLevelA->IsDummy()) {
					ElementLevelA->SkipData(inDataStream, sContext);
					delete ElementLevelA; // forget this unknown element
				} else {
					// more logical to do it afterward
					ElementList.push_back(ElementLevelA);

					ElementLevelA->Read(inDataStream, EBML_CONTEXT(ElementLevelA), UpperEltFound, FoundElt, AllowDummyElt, ReadFully);

					// just in case
					ElementLevelA->SkipData(inDataStream, EBML_CONTEXT(ElementLevelA));
				}

				if (UpperEltFound > 0) {
					UpperEltFound--;
					if (UpperEltFound > 0 || MaxSizeToRead <= 0)
						goto processCrc;
					ElementLevelA = FoundElt;
					continue;
				} 
				
				if (UpperEltFound < 0) {
					UpperEltFound++;
					if (UpperEltFound < 0)
						goto processCrc;
				}

				if (MaxSizeToRead <= 0)
					goto processCrc;// this level is finished
				
				ElementLevelA = inDataStream.FindNextElement(sContext, UpperEltFound, MaxSizeToRead, AllowDummyElt);
			}
			if (UpperEltFound > 0) {
				FoundElt = ElementLevelA;
			}
		}
	processCrc:
        EBML_MASTER_ITERATOR Itr, CrcItr;
        for (Itr = ElementList.begin(); Itr != ElementList.end();) {
			if ((EbmlId)(*(*Itr)) == EBML_ID(EbmlCrc32)) {
				bChecksumUsed = true;
				// remove the element
				Checksum = *(static_cast<EbmlCrc32*>(*Itr));
                CrcItr = Itr;
                break;
			}
            ++Itr;
		}
        if (bChecksumUsed)
        {
		    delete *CrcItr;
		    Remove(CrcItr);
        }
		SetValueIsSet();
	}
}