Refactoring: move parse_arg_split_parts() to common library

Goal: mmg should be able to use it for split arg validation.
This commit is contained in:
Moritz Bunkus 2013-01-21 13:26:16 +01:00
parent 855ea1ab1c
commit 8c8c0ade0e
7 changed files with 173 additions and 96 deletions

View File

@ -0,0 +1,102 @@
/** \brief command line parsing
mkvmerge -- utility for splicing together matroska files
from component media subtypes
Distributed under the GPL
see the file COPYING for details
or visit http://www.gnu.org/copyleft/gpl.html
\author Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#include "common/common_pch.h"
#include "common/split_arg_parsing.h"
#include "common/strings/editing.h"
#include "common/strings/parsing.h"
namespace mtx { namespace args {
std::vector<split_point_c>
parse_split_parts(const std::string &arg,
bool frames_fields) {
std::string s = arg;
if (balg::istarts_with(s, "parts:"))
s.erase(0, 6);
else if (balg::istarts_with(s, "parts-frames:"))
s.erase(0, 13);
if (s.empty())
throw format_x{boost::format(Y("Missing start/end specifications for '--split' in '--split %1%'.\n")) % arg};
std::vector<std::tuple<int64_t, int64_t, bool> > requested_split_points;
for (auto const &part_spec : split(s, ",")) {
auto pair = split(part_spec, "-");
if (pair.size() != 2)
throw format_x{boost::format(Y("Invalid start/end specification for '--split' in '--split %1%' (curent part: %2%).\n")) % arg % part_spec};
bool create_new_file = true;
if (pair[0].substr(0, 1) == "+") {
if (!requested_split_points.empty())
create_new_file = false;
pair[0].erase(0, 1);
}
int64_t start;
if (pair[0].empty())
start = requested_split_points.empty() ? 0 : std::get<1>(requested_split_points.back());
else if (!frames_fields && !parse_timecode(pair[0], start))
throw format_x{boost::format(Y("Invalid start time for '--split' in '--split %1%' (current part: %2%). Additional error message: %3%.\n")) % arg % part_spec % timecode_parser_error};
else if (frames_fields && (!parse_number(pair[0], start) || (0 > start)))
throw format_x{boost::format(Y("Invalid start frame/field number for '--split' in '--split %1%' (current part: %2%).\n")) % arg % part_spec};
int64_t end;
if (pair[1].empty())
end = std::numeric_limits<int64_t>::max();
else if (!frames_fields && !parse_timecode(pair[1], end))
throw format_x{boost::format(Y("Invalid end time for '--split' in '--split %1%' (current part: %2%). Additional error message: %3%.\n")) % arg % part_spec % timecode_parser_error};
else if (frames_fields && (!parse_number(pair[1], end) || (0 > end)))
throw format_x{boost::format(Y("Invalid end frame/field number for '--split' in '--split %1%' (current part: %2%).\n")) % arg % part_spec};
if (end <= start) {
if (frames_fields)
throw format_x{boost::format(Y("Invalid end frame/field number for '--split' in '--split %1%' (current part: %2%). The end number must be bigger than the start number.\n")) % arg % part_spec};
else
throw format_x{boost::format(Y("Invalid end time for '--split' in '--split %1%' (current part: %2%). The end time must be bigger than the start time.\n")) % arg % part_spec};
}
if (!requested_split_points.empty() && (start < std::get<1>(requested_split_points.back()))) {
if (frames_fields)
throw format_x{boost::format(Y("Invalid start frame/field number for '--split' in '--split %1%' (current part: %2%). The start number must be bigger than or equal to the previous part's end number.\n")) % arg % part_spec};
else
throw format_x{boost::format(Y("Invalid start time for '--split' in '--split %1%' (current part: %2%). The start time must be bigger than or equal to the previous part's end time.\n")) % arg % part_spec};
}
requested_split_points.push_back(std::make_tuple(start, end, create_new_file));
}
std::vector<split_point_c> split_points;
auto sp_type = frames_fields ? split_point_c::parts_frame_field : split_point_c::parts;
int64_t previous_end = 0;
for (auto &split_point : requested_split_points) {
if (previous_end < std::get<0>(split_point))
split_points.push_back(split_point_c{ previous_end, sp_type, true, true, std::get<2>(split_point) });
split_points.push_back(split_point_c{ std::get<0>(split_point), sp_type, true, false, std::get<2>(split_point) });
previous_end = std::get<1>(split_point);
}
if (std::get<1>(requested_split_points.back()) < std::numeric_limits<int64_t>::max())
split_points.push_back(split_point_c{ std::get<1>(requested_split_points.back()), sp_type, true, true });
return split_points;
}
}}

View File

@ -0,0 +1,39 @@
/** \brief command line parsing
mkvmerge -- utility for splicing together matroska files
from component media subtypes
Distributed under the GPL
see the file COPYING for details
or visit http://www.gnu.org/copyleft/gpl.html
\author Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#ifndef MTX_COMMON_SPLIT_ARG_PARSING_H
#define MTX_COMMON_SPLIT_ARG_PARSING_H
#include "common/common_pch.h"
#include "common/split_point.h"
namespace mtx { namespace args {
class format_x: public exception {
protected:
std::string m_message;
public:
explicit format_x(std::string const &message) : m_message(message) { }
explicit format_x(boost::format const &message): m_message(message.str()) { }
virtual ~format_x() throw() { }
virtual char const *what() const throw() {
return m_message.c_str();
}
};
std::vector<split_point_c> parse_split_parts(const std::string &arg, bool frames_fields);
}}
#endif // MTX_COMMON_SPLIT_ARG_PARSING_H

View File

@ -17,7 +17,7 @@
#include "common/strings/formatting.h"
std::string
split_point_t::str()
split_point_c::str()
const {
return (boost::format("<%1% %2% once:%3% discard:%4% create_file:%5%>")
% format_timecode(m_point)

View File

@ -16,7 +16,7 @@
#include "common/common_pch.h"
class split_point_t {
class split_point_c {
public:
enum type_e {
duration,
@ -33,7 +33,7 @@ public:
bool m_use_once, m_discard, m_create_new_file;
public:
split_point_t(int64_t point,
split_point_c(int64_t point,
type_e type,
bool use_once,
bool discard = false,
@ -47,7 +47,7 @@ public:
}
bool
operator <(split_point_t const &rhs)
operator <(split_point_c const &rhs)
const {
return m_point < rhs.m_point;
}

View File

@ -131,7 +131,7 @@ cluster_helper_c::split_if_necessary(packet_cptr &packet) {
bool split_now = false;
// Maybe we want to start a new file now.
if (split_point_t::size == m_current_split_point->m_type) {
if (split_point_c::size == m_current_split_point->m_type) {
int64_t additional_size = 0;
if (!m_packets.empty())
@ -146,18 +146,18 @@ cluster_helper_c::split_if_necessary(packet_cptr &packet) {
if ((m_header_overhead + additional_size + m_bytes_in_file) >= m_current_split_point->m_point)
split_now = true;
} else if ( (split_point_t::duration == m_current_split_point->m_type)
} else if ( (split_point_c::duration == m_current_split_point->m_type)
&& (0 <= m_first_timecode_in_file)
&& (packet->assigned_timecode - m_first_timecode_in_file) >= m_current_split_point->m_point)
split_now = true;
else if ( ( (split_point_t::timecode == m_current_split_point->m_type)
|| (split_point_t::parts == m_current_split_point->m_type))
else if ( ( (split_point_c::timecode == m_current_split_point->m_type)
|| (split_point_c::parts == m_current_split_point->m_type))
&& (packet->assigned_timecode >= m_current_split_point->m_point))
split_now = true;
else if ( ( (split_point_t::frame_field == m_current_split_point->m_type)
|| (split_point_t::parts_frame_field == m_current_split_point->m_type))
else if ( ( (split_point_c::frame_field == m_current_split_point->m_type)
|| (split_point_c::parts_frame_field == m_current_split_point->m_type))
&& (m_frame_field_number >= m_current_split_point->m_point))
split_now = true;
@ -183,8 +183,8 @@ cluster_helper_c::split(packet_cptr &packet) {
if (m_current_split_point->m_use_once) {
if ( m_current_split_point->m_discard
&& ( (split_point_t::parts == m_current_split_point->m_type)
|| (split_point_t::parts_frame_field == m_current_split_point->m_type))
&& ( (split_point_c::parts == m_current_split_point->m_type)
|| (split_point_c::parts_frame_field == m_current_split_point->m_type))
&& (m_split_points.end() == (m_current_split_point + 1))) {
mxdebug_if(m_debug_splitting, boost::format("Splitting: Last part in 'parts:' splitting mode finished\n"));
m_splitting_and_processed_fully = true;
@ -658,7 +658,7 @@ cluster_helper_c::handle_discarded_duration(bool create_new_file,
}
void
cluster_helper_c::add_split_point(const split_point_t &split_point) {
cluster_helper_c::add_split_point(const split_point_c &split_point) {
m_split_points.push_back(split_point);
m_current_split_point = m_split_points.begin();
m_discarding = m_current_split_point->m_discard;
@ -673,8 +673,8 @@ cluster_helper_c::split_mode_produces_many_files()
if (!splitting())
return false;
if ( (split_point_t::parts != m_split_points.front().m_type)
&& (split_point_t::parts_frame_field != m_split_points.front().m_type))
if ( (split_point_c::parts != m_split_points.front().m_type)
&& (split_point_c::parts_frame_field != m_split_points.front().m_type))
return true;
bool first = true;
@ -698,7 +698,7 @@ cluster_helper_c::dump_split_points()
const {
mxdebug_if(m_debug_splitting,
boost::format("Split points:%1%\n")
% boost::accumulate(m_split_points, std::string(""), [](std::string const &accu, split_point_t const &point) { return accu + " " + point.str(); }));
% boost::accumulate(m_split_points, std::string(""), [](std::string const &accu, split_point_c const &point) { return accu + " " + point.str(); }));
}
cluster_helper_c *g_cluster_helper = nullptr;

View File

@ -57,8 +57,8 @@ private:
bool m_first_video_keyframe_seen;
mm_io_c *m_out;
std::vector<split_point_t> m_split_points;
std::vector<split_point_t>::iterator m_current_split_point;
std::vector<split_point_c> m_split_points;
std::vector<split_point_c>::iterator m_current_split_point;
std::map<id_timecode_t, int64_t> m_id_timecode_duration_map;
size_t m_num_cue_points_postprocessed;
@ -92,7 +92,7 @@ public:
int64_t get_discarded_duration() const;
void handle_discarded_duration(bool create_new_file, bool previously_discarding);
void add_split_point(const split_point_t &split_point);
void add_split_point(split_point_c const &split_point);
void dump_split_points() const;
bool splitting() const {
return !m_split_points.empty();

View File

@ -52,6 +52,7 @@
#include "common/iso639.h"
#include "common/mm_io.h"
#include "common/segmentinfo.h"
#include "common/split_arg_parsing.h"
#include "common/strings/formatting.h"
#include "common/strings/parsing.h"
#include "common/unique_numbers.h"
@ -793,7 +794,7 @@ parse_arg_split_duration(const std::string &arg) {
if (!parse_timecode(s, split_after))
mxerror(boost::format(Y("Invalid time for '--split' in '--split %1%'. Additional error message: %2%\n")) % arg % timecode_parser_error);
g_cluster_helper->add_split_point(split_point_t(split_after, split_point_t::duration, false));
g_cluster_helper->add_split_point(split_point_c(split_after, split_point_c::duration, false));
}
/** \brief Parse the timecode format to \c --split
@ -813,7 +814,7 @@ parse_arg_split_timecodes(const std::string &arg) {
int64_t split_after;
if (!parse_timecode(timecode, split_after))
mxerror(boost::format(Y("Invalid time for '--split' in '--split %1%'. Additional error message: %2%.\n")) % arg % timecode_parser_error);
g_cluster_helper->add_split_point(split_point_t(split_after, split_point_t::timecode, true));
g_cluster_helper->add_split_point(split_point_c(split_after, split_point_c::timecode, true));
}
}
@ -834,7 +835,7 @@ parse_arg_split_frames(std::string const &arg) {
uint64_t split_after = 0;
if (!parse_number(frame, split_after) || (0 == split_after))
mxerror(boost::format(Y("Invalid frame for '--split' in '--split %1%'.\n")) % arg);
g_cluster_helper->add_split_point(split_point_t(split_after, split_point_t::frame_field, true));
g_cluster_helper->add_split_point(split_point_c(split_after, split_point_c::frame_field, true));
}
}
@ -864,7 +865,7 @@ parse_arg_split_chapters(std::string const &arg) {
if (!g_kax_chapters)
mxerror(boost::format(Y("No chapters in source files or chapter files found to split by.\n")));
std::vector<split_point_t> new_split_points;
std::vector<split_point_c> new_split_points;
auto current_number = 0u;
for (auto element : *g_kax_chapters) {
auto edition = dynamic_cast<KaxEditionEntry *>(element);
@ -883,7 +884,7 @@ parse_arg_split_chapters(std::string const &arg) {
int64_t split_after = FindChildValue<KaxChapterTimeStart, uint64_t>(atom, 0);
if (split_after)
new_split_points.push_back(split_point_t{split_after, split_point_t::timecode, true});
new_split_points.push_back(split_point_c{split_after, split_point_c::timecode, true});
}
}
@ -905,79 +906,14 @@ parse_arg_split_chapters(std::string const &arg) {
static void
parse_arg_split_parts(const std::string &arg,
bool frames_fields) {
std::string s = arg;
try {
auto split_points = mtx::args::parse_split_parts(arg, frames_fields);
for (auto &point : split_points)
g_cluster_helper->add_split_point(point);
if (balg::istarts_with(s, "parts:"))
s.erase(0, 6);
else if (balg::istarts_with(s, "parts-frames:"))
s.erase(0, 13);
if (s.empty())
mxerror(boost::format(Y("Missing start/end specifications for '--split' in '--split %1%'.\n")) % arg);
std::vector<std::tuple<int64_t, int64_t, bool> > split_points;
for (auto const &part_spec : split(s, ",")) {
auto pair = split(part_spec, "-");
if (pair.size() != 2)
mxerror(boost::format(Y("Invalid start/end specification for '--split' in '--split %1%' (curent part: %2%).\n")) % arg % part_spec);
bool create_new_file = true;
if (pair[0].substr(0, 1) == "+") {
if (!split_points.empty())
create_new_file = false;
pair[0].erase(0, 1);
}
int64_t start;
if (pair[0].empty())
start = split_points.empty() ? 0 : std::get<1>(split_points.back());
else if (!frames_fields && !parse_timecode(pair[0], start))
mxerror(boost::format(Y("Invalid start time for '--split' in '--split %1%' (current part: %2%). Additional error message: %3%.\n")) % arg % part_spec % timecode_parser_error);
else if (frames_fields && (!parse_number(pair[0], start) || (0 > start)))
mxerror(boost::format(Y("Invalid start frame/field number for '--split' in '--split %1%' (current part: %2%).\n")) % arg % part_spec);
int64_t end;
if (pair[1].empty())
end = std::numeric_limits<int64_t>::max();
else if (!frames_fields && !parse_timecode(pair[1], end))
mxerror(boost::format(Y("Invalid end time for '--split' in '--split %1%' (current part: %2%). Additional error message: %3%.\n")) % arg % part_spec % timecode_parser_error);
else if (frames_fields && (!parse_number(pair[1], end) || (0 > end)))
mxerror(boost::format(Y("Invalid end frame/field number for '--split' in '--split %1%' (current part: %2%).\n")) % arg % part_spec);
if (end <= start) {
if (frames_fields)
mxerror(boost::format(Y("Invalid end frame/field number for '--split' in '--split %1%' (current part: %2%). The end number must be bigger than the start number.\n")) % arg % part_spec);
else
mxerror(boost::format(Y("Invalid end time for '--split' in '--split %1%' (current part: %2%). The end time must be bigger than the start time.\n")) % arg % part_spec);
}
if (!split_points.empty() && (start < std::get<1>(split_points.back()))) {
if (frames_fields)
mxerror(boost::format(Y("Invalid start frame/field number for '--split' in '--split %1%' (current part: %2%). The start number must be bigger than or equal to the previous part's end number.\n")) % arg % part_spec);
else
mxerror(boost::format(Y("Invalid start time for '--split' in '--split %1%' (current part: %2%). The start time must be bigger than or equal to the previous part's end time.\n")) % arg % part_spec);
}
split_points.push_back(std::make_tuple(start, end, create_new_file));
} catch (mtx::args::format_x &ex) {
mxerror(ex.what());
}
auto sp_type = frames_fields ? split_point_t::parts_frame_field : split_point_t::parts;
int64_t previous_end = 0;
for (auto &split_point : split_points) {
if (previous_end < std::get<0>(split_point))
g_cluster_helper->add_split_point(split_point_t{ previous_end, sp_type, true, true, std::get<2>(split_point) });
g_cluster_helper->add_split_point(split_point_t{ std::get<0>(split_point), sp_type, true, false, std::get<2>(split_point) });
previous_end = std::get<1>(split_point);
}
if (std::get<1>(split_points.back()) < std::numeric_limits<int64_t>::max())
g_cluster_helper->add_split_point(split_point_t{ std::get<1>(split_points.back()), sp_type, true, true });
}
/** \brief Parse the size format to \c --split
@ -1015,7 +951,7 @@ parse_arg_split_size(const std::string &arg) {
if (!parse_number(s, split_after))
mxerror(boost::format(err_msg) % arg);
g_cluster_helper->add_split_point(split_point_t(split_after * modifier, split_point_t::size, false));
g_cluster_helper->add_split_point(split_point_c(split_after * modifier, split_point_c::size, false));
}
/** \brief Parse the \c --split argument