Esempio n. 1
0
void MatroskaImport::ImportCluster(KaxCluster &cluster, bool addToTrack)
{
	KaxSegment & segment = *static_cast<KaxSegment *>(el_l0);
	KaxClusterTimecode & clusterTime = GetChild<KaxClusterTimecode>(cluster);
	CXXAutoreleasePool pool;
				
	cluster.SetParent(segment);
	cluster.InitTimecode(uint64(clusterTime), timecodeScale);
	
	for (int i = 0; i < cluster.ListSize(); i++) {
		const EbmlId & elementID = EbmlId(*cluster[i]);
		KaxInternalBlock *block = NULL;
		uint32_t duration = 0;		// set to track's default duration in AddBlock if 0
		short flags = 0;
		
		if (elementID == KaxBlockGroup::ClassInfos.GlobalId) {
			KaxBlockGroup & blockGroup = *static_cast<KaxBlockGroup *>(cluster[i]);
			KaxBlockDuration & blkDuration = GetChild<KaxBlockDuration>(blockGroup);
			block = &GetChild<KaxBlock>(blockGroup);
			if (blkDuration.ValueIsSet())
				duration = uint32(blkDuration);
			flags = blockGroup.ReferenceCount() > 0 ? mediaSampleNotSync : 0;
			
		} else if (elementID == KaxSimpleBlock::ClassInfos.GlobalId) {
			KaxSimpleBlock & simpleBlock = *static_cast<KaxSimpleBlock *>(cluster[i]);
			block = &simpleBlock;
			if (!simpleBlock.IsKeyframe())
				flags |= mediaSampleNotSync;
			if (simpleBlock.IsDiscardable() && IsFrameDroppingEnabled())
				flags |= mediaSampleDroppable;
		}
		
		if (block) {
			block->SetParent(cluster);
			
			for (int i = 0; i < tracks.size(); i++) {
				if (tracks[i].number == block->TrackNum()) {
					tracks[i].AddBlock(*block, duration, flags);
					break;
				}
			}
		}
	}
	
	if (addToTrack) {
		for (int i = 0; i < tracks.size(); i++)
			tracks[i].AddSamplesToTrack();
		
		loadState = kMovieLoadStatePlayable;
	}
}
Esempio n. 2
0
void
cues_c::postprocess_cues(KaxCues &cues,
                         KaxCluster &cluster) {
  add(cues);

  if (m_no_cue_duration && m_no_cue_relative_position)
    return;

  auto cluster_data_start_pos = cluster.GetElementPosition() + cluster.HeadSize();
  auto block_positions        = calculate_block_positions(cluster);

  for (auto point = m_points.begin() + m_num_cue_points_postprocessed, end = m_points.end(); point != end; ++point) {
    // Set CueRelativePosition for all cues.
    if (!m_no_cue_relative_position) {
      auto position_itr      = block_positions.find({ point->track_num, point->timecode });
      auto relative_position = block_positions.end() != position_itr ? std::max(position_itr->second, cluster_data_start_pos) - cluster_data_start_pos : 0ull;

      assert(relative_position <= static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()));

      point->relative_position = relative_position;

      mxdebug_if(m_debug_cue_relative_position,
                 boost::format("cue_relative_position: looking for <%1%:%2%>: cluster_data_start_pos %3% position %4%\n")
                 % point->track_num % point->timecode % cluster_data_start_pos % relative_position);
    }

    // Set CueDuration if the packetizer wants them.
    if (m_no_cue_duration)
      continue;

    auto duration_itr = m_id_timecode_duration_map.find({ point->track_num, point->timecode });
    auto ptzr         = g_packetizers_by_track_num[point->track_num];

    if (!ptzr || !ptzr->wants_cue_duration())
      continue;

    if (m_id_timecode_duration_map.end() != duration_itr)
      point->duration = duration_itr->second;

    mxdebug_if(m_debug_cue_duration,
               boost::format("cue_duration: looking for <%1%:%2%>: %3%\n")
               % point->track_num % point->timecode % (duration_itr == m_id_timecode_duration_map.end() ? static_cast<int64_t>(-1) : duration_itr->second));
  }

  m_num_cue_points_postprocessed = m_points.size();

  m_id_timecode_duration_map.clear();
}
Esempio n. 3
0
void
tag_target_c::account_one_cluster(KaxCluster &cluster) {
  for (int idx = 0, num_children = cluster.ListSize(); idx < num_children; ++idx) {
    auto child = cluster[idx];

    if (Is<KaxBlockGroup>(child))
      account_block_group(*static_cast<KaxBlockGroup *>(child), cluster);

    else if (Is<KaxSimpleBlock>(child))
      account_simple_block(*static_cast<KaxSimpleBlock *>(child), cluster);
  }
}
Esempio n. 4
0
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();
    }
}
Esempio n. 5
0
bool
extract_tracks(const std::string &file_name,
               std::vector<track_spec_t> &tspecs,
               kax_analyzer_c::parse_mode_e parse_mode) {
  if (tspecs.empty())
    mxerror(Y("Nothing to do.\n"));

  // open input file
  mm_io_cptr in;
  kax_file_cptr file;
  try {
    in   = mm_file_io_c::open(file_name);
    file = kax_file_cptr(new kax_file_c(in));
  } 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 false;
  }

  int64_t file_size = in->get_size();
  uint64_t tc_scale = TIMECODE_SCALE;
  bool segment_info_found = false, tracks_found = false;

  // open input file
  auto analyzer = open_and_analyze(file_name, parse_mode, false);
  if (analyzer) {
    auto af_master    = ebml_master_cptr{ analyzer->read_all(EBML_INFO(KaxInfo)) };
    auto segment_info = dynamic_cast<KaxInfo *>(af_master.get());
    if (segment_info) {
      segment_info_found = true;
      handle_segment_info(segment_info, file.get(), tc_scale);
    }

    af_master   = ebml_master_cptr{ analyzer->read_all(EBML_INFO(KaxTracks)) };
    auto tracks = dynamic_cast<KaxTracks *>(af_master.get());
    if (tracks) {
      tracks_found = true;
      find_and_verify_track_uids(*tracks, tspecs);
      create_extractors(*tracks, tspecs);
    }
  }

  try {
    in->setFilePointer(0);
    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 false;
    }

    // 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 false;
      }

      if (Is<KaxSegment>(l0)) {
        show_element(l0, 0, Y("Segment"));
        break;
      }

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

    EbmlElement *l1   = nullptr;

    KaxChapters all_chapters;
    KaxTags all_tags;

    while ((l1 = file->read_next_level1_element())) {
      if (Is<KaxInfo>(l1) && !segment_info_found) {
        segment_info_found = true;
        handle_segment_info(static_cast<EbmlMaster *>(l1), file.get(), tc_scale);

      } else if (Is<KaxTracks>(l1) && !tracks_found) {
        tracks_found = true;
        find_and_verify_track_uids(*dynamic_cast<KaxTracks *>(l1), tspecs);
        create_extractors(*dynamic_cast<KaxTracks *>(l1), tspecs);

      } else if (Is<KaxCluster>(l1)) {
        show_element(l1, 1, Y("Cluster"));
        KaxCluster *cluster = static_cast<KaxCluster *>(l1);

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

        KaxClusterTimecode *ctc = FindChild<KaxClusterTimecode>(l1);
        if (ctc) {
          uint64_t cluster_tc = ctc->GetValue();
          show_element(ctc, 2, boost::format(Y("Cluster timecode: %|1$.3f|s")) % ((float)cluster_tc * (float)tc_scale / 1000000000.0));
          cluster->InitTimecode(cluster_tc, tc_scale);
        } else
          cluster->InitTimecode(0, tc_scale);

        size_t i;
        int64_t max_timecode = -1;

        for (i = 0; cluster->ListSize() > i; ++i) {
          int64_t max_bg_timecode = -1;
          EbmlElement *el         = (*cluster)[i];

          if (Is<KaxBlockGroup>(el)) {
            show_element(el, 2, Y("Block group"));
            max_bg_timecode = handle_blockgroup(*static_cast<KaxBlockGroup *>(el), *cluster, tc_scale);

          } else if (Is<KaxSimpleBlock>(el)) {
            show_element(el, 2, Y("SimpleBlock"));
            max_bg_timecode = handle_simpleblock(*static_cast<KaxSimpleBlock *>(el), *cluster);
          }

          max_timecode = std::max(max_timecode, max_bg_timecode);
        }

        if (-1 != max_timecode)
          file->set_last_timecode(max_timecode);

      } else if (Is<KaxChapters>(l1)) {
        KaxChapters &chapters = *static_cast<KaxChapters *>(l1);

        while (chapters.ListSize() > 0) {
          if (Is<KaxEditionEntry>(chapters[0])) {
            KaxEditionEntry &entry = *static_cast<KaxEditionEntry *>(chapters[0]);
            while (entry.ListSize() > 0) {
              if (Is<KaxChapterAtom>(entry[0]))
                all_chapters.PushElement(*entry[0]);
              entry.Remove(0);
            }
          }
          chapters.Remove(0);
        }

      } else if (Is<KaxTags>(l1)) {
        KaxTags &tags = *static_cast<KaxTags *>(l1);

        while (tags.ListSize() > 0) {
          all_tags.PushElement(*tags[0]);
          tags.Remove(0);
        }

      }

      delete l1;

    } // while (l1)

    delete l0;
    delete es;

    write_all_cuesheets(all_chapters, all_tags, tspecs);

    // Now just close the files and go to sleep. Mummy will sing you a
    // lullaby. Just close your eyes, listen to her sweet voice, singing,
    // singing, fading... fad... ing...
    close_extractors();

    return true;
  } catch (...) {
    show_error(Y("Caught exception"));

    return false;
  }
}
Esempio n. 6
0
bool
extract_tracks(const std::string &file_name,
               std::vector<track_spec_t> &tspecs) {
  if (tspecs.empty())
    mxerror(Y("Nothing to do.\n"));

  // open input file
  mm_io_cptr in;
  kax_file_cptr file;
  try {
    in   = mm_file_io_c::open(file_name);
    file = kax_file_cptr(new kax_file_c(in));
  } catch (...) {
    show_error(boost::format(Y("The file '%1%' could not be opened for reading (%2%).\n")) % file_name % strerror(errno));
    return false;
  }

  int64_t file_size = in->get_size();

  try {
    EbmlStream *es = new EbmlStream(*in);

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

      return false;
    }

    // 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 (NULL == l0) {
        show_error(Y("No segment/level 0 element found."));
        return false;
      }

      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;
    EbmlElement *l1   = NULL;
    uint64_t tc_scale = TIMECODE_SCALE;

    KaxChapters all_chapters;
    KaxTags all_tags;

    while (NULL != (l1 = file->read_next_level1_element())) {
      if (EbmlId(*l1) == EBML_ID(KaxInfo)) {
        // General info about this Matroska file
        show_element(l1, 1, Y("Segment information"));

        KaxTimecodeScale *ktc_scale = FINDFIRST(l1, KaxTimecodeScale);
        if (NULL != ktc_scale) {
          tc_scale = uint64(*ktc_scale);
          show_element(ktc_scale, 2, boost::format(Y("Timecode scale: %1%")) % tc_scale);
        }

      } 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;
        find_and_verify_track_uids(*dynamic_cast<KaxTracks *>(l1), tspecs);
        create_extractors(*dynamic_cast<KaxTracks *>(l1), tspecs);

      } else if (EbmlId(*l1) == EBML_ID(KaxCluster)) {
        show_element(l1, 1, Y("Cluster"));
        KaxCluster *cluster = static_cast<KaxCluster *>(l1);

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

        KaxClusterTimecode *ctc = FINDFIRST(l1, KaxClusterTimecode);
        if (NULL != ctc) {
          uint64_t cluster_tc = uint64(*ctc);
          show_element(ctc, 2, boost::format(Y("Cluster timecode: %|1$.3f|s")) % ((float)cluster_tc * (float)tc_scale / 1000000000.0));
          cluster->InitTimecode(cluster_tc, tc_scale);
        } else
          cluster->InitTimecode(0, tc_scale);

        size_t i;
        for (i = 0; cluster->ListSize() > i; ++i) {
          EbmlElement *el = (*cluster)[i];
          if (EbmlId(*el) == EBML_ID(KaxBlockGroup)) {
            show_element(el, 2, Y("Block group"));
            handle_blockgroup(*static_cast<KaxBlockGroup *>(el), *cluster, tc_scale);

          } else if (EbmlId(*el) == EBML_ID(KaxSimpleBlock)) {
            show_element(el, 2, Y("SimpleBlock"));
            handle_simpleblock(*static_cast<KaxSimpleBlock *>(el), *cluster);
          }
        }

      } else if (EbmlId(*l1) == EBML_ID(KaxChapters)) {
        KaxChapters &chapters = *static_cast<KaxChapters *>(l1);

        while (chapters.ListSize() > 0) {
          if (EbmlId(*chapters[0]) == EBML_ID(KaxEditionEntry)) {
            KaxEditionEntry &entry = *static_cast<KaxEditionEntry *>(chapters[0]);
            while (entry.ListSize() > 0) {
              if (EbmlId(*entry[0]) == EBML_ID(KaxChapterAtom))
                all_chapters.PushElement(*entry[0]);
              entry.Remove(0);
            }
          }
          chapters.Remove(0);
        }

      } else if (EbmlId(*l1) == EBML_ID(KaxTags)) {
        KaxTags &tags = *static_cast<KaxTags *>(l1);

        while (tags.ListSize() > 0) {
          all_tags.PushElement(*tags[0]);
          tags.Remove(0);
        }

      }

      delete l1;

    } // while (l1 != NULL)

    delete l0;
    delete es;

    write_all_cuesheets(all_chapters, all_tags, tspecs);

    // Now just close the files and go to sleep. Mummy will sing you a
    // lullaby. Just close your eyes, listen to her sweet voice, singing,
    // singing, fading... fad... ing...
    close_extractors();

    return true;
  } catch (...) {
    show_error(Y("Caught exception"));

    return false;
  }
}