mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2025-01-09 03:31:41 +00:00
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:
parent
855ea1ab1c
commit
8c8c0ade0e
102
src/common/split_arg_parsing.cpp
Normal file
102
src/common/split_arg_parsing.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}}
|
39
src/common/split_arg_parsing.h
Normal file
39
src/common/split_arg_parsing.h
Normal 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
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user