mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2025-02-12 12:10:03 +00:00
Merge branch 'master' into mkvtoolnix-gui
This commit is contained in:
commit
108e5dbe71
1
.gitignore
vendored
1
.gitignore
vendored
@ -67,3 +67,4 @@ BROWSE
|
||||
Makefile
|
||||
TAGS
|
||||
lib*.a
|
||||
/src/tools/mpls_dump
|
||||
|
12
ChangeLog
12
ChangeLog
@ -1,3 +1,15 @@
|
||||
2014-02-05 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mkvmerge: enhancements: AVI reader: audio chunks with obvious
|
||||
wrong size information (bigger than 10 MB) will be skipped.
|
||||
|
||||
2014-02-03 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mkvmerge: bug fix: When reading M2TS files belonging to an MPLS
|
||||
playlist mkvmerge will now only copy packets whose timestamps lie
|
||||
between the »in time« and »out time« restrictions from the
|
||||
playlist's entry corresponding to that M2TS file. Fixes #985.
|
||||
|
||||
2014-01-22 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* all: Windows 64bit: fixed return value checks for opening
|
||||
|
12
Rakefile
12
Rakefile
@ -43,7 +43,7 @@ def setup_globals
|
||||
$programs = %w{mkvmerge mkvinfo mkvextract mkvpropedit}
|
||||
$programs << "mmg" if c?(:USE_WXWIDGETS)
|
||||
$programs << "mkvtoolnix-gui" if $build_mkvtoolnix_gui
|
||||
$tools = %w{ac3parser base64tool diracparser ebml_validator vc1parser}
|
||||
$tools = %w{ac3parser base64tool diracparser ebml_validator mpls_dump vc1parser}
|
||||
$mmg_bin = c(:MMG_BIN)
|
||||
$mmg_bin = "mmg" if $mmg_bin.empty?
|
||||
|
||||
@ -824,6 +824,16 @@ if $build_tools
|
||||
libraries($common_libs).
|
||||
create
|
||||
|
||||
#
|
||||
# tools: mpls_dump
|
||||
#
|
||||
Application.new("src/tools/mpls_dump").
|
||||
description("Build the mpls_dump executable").
|
||||
aliases("tools:mpls_dump").
|
||||
sources("src/tools/mpls_dump.cpp").
|
||||
libraries($common_libs).
|
||||
create
|
||||
|
||||
#
|
||||
# tools: vc1parser
|
||||
#
|
||||
|
@ -17,5 +17,5 @@ PKG_PROG_PKG_CONFIG
|
||||
|
||||
dnl Check for headers
|
||||
AC_HEADER_STDC()
|
||||
AC_CHECK_HEADERS([inttypes.h stdint.h sys/types.h sys/syscall.h])
|
||||
AC_CHECK_HEADERS([inttypes.h stdint.h sys/types.h sys/syscall.h stropts.h])
|
||||
AC_CHECK_FUNCS([vsscanf syscall],,)
|
||||
|
@ -45,5 +45,5 @@ double
|
||||
int_to_double(int64_t value) {
|
||||
if (static_cast<uint64_t>(value + value) > (0xffeull << 52))
|
||||
return NAN;
|
||||
return ldexp(((value & ((1ll << 52) - 1)) + (1ll << 52)) * (value >> 63 | 1), (value >> 52 & 0x7ff) - 1075);
|
||||
return std::ldexp(((value & ((1ll << 52) - 1)) + (1ll << 52)) * (value >> 63 | 1), (value >> 52 & 0x7ff) - 1075);
|
||||
}
|
||||
|
@ -77,17 +77,13 @@ mm_mpls_multi_file_io_c::open_multi(mm_io_c *in) {
|
||||
};
|
||||
|
||||
std::vector<bfs::path> file_names;
|
||||
std::unordered_map<std::string, bool> file_names_seen;
|
||||
|
||||
for (auto const &item : mpls_parser->get_playlist().items) {
|
||||
auto file = find_file(item);
|
||||
|
||||
mxdebug_if(ms_debug, boost::format("Item clip ID: %1% codec ID: %2%: have file? %3% file: %4%\n") % item.clip_id % item.codec_id % !file.empty() % file.string());
|
||||
if (file.empty() || file_names_seen[file.string()])
|
||||
continue;
|
||||
|
||||
file_names.push_back(file);
|
||||
file_names_seen[file.string()] = true;
|
||||
if (!file.empty())
|
||||
file_names.push_back(file);
|
||||
}
|
||||
|
||||
mxdebug_if(ms_debug, boost::format("Number of files left: %1%\n") % file_names.size());
|
||||
|
@ -41,6 +41,10 @@ public:
|
||||
return m_files;
|
||||
}
|
||||
|
||||
mtx::mpls::parser_c const &get_mpls_parser() const {
|
||||
return *m_mpls_parser;
|
||||
}
|
||||
|
||||
std::vector<timecode_c> const &get_chapters() const;
|
||||
virtual void create_verbose_identification_info(std::vector<std::string> &verbose_info);
|
||||
|
||||
|
@ -1559,6 +1559,8 @@ mpeg4::p10::avc_es_parser_c::get_most_often_used_duration()
|
||||
|
||||
void
|
||||
mpeg4::p10::avc_es_parser_c::cleanup() {
|
||||
auto s_debug_force_simple_picture_order = debugging_option_c{"avc_parser_force_simple_picture_order"};
|
||||
|
||||
if (m_frames.empty())
|
||||
return;
|
||||
|
||||
@ -1632,7 +1634,7 @@ mpeg4::p10::avc_es_parser_c::cleanup() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!simple_picture_order)
|
||||
if (!simple_picture_order && !s_debug_force_simple_picture_order)
|
||||
brng::sort(m_frames, [](const avc_frame_t &f1, const avc_frame_t &f2) { return f1.m_presentation_order < f2.m_presentation_order; });
|
||||
|
||||
brng::sort(m_provided_timecodes);
|
||||
|
@ -18,6 +18,12 @@
|
||||
# if defined(HAVE_SYS_IOCTL_H) || defined(GWINSZ_IN_SYS_IOCTL)
|
||||
# include <sys/ioctl.h>
|
||||
# endif // HAVE_SYS_IOCTL_H || GWINSZ_IN_SYS_IOCTL
|
||||
# if defined(HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
# endif // HAVE_UNISTD_H
|
||||
# if defined(HAVE_STROPTS_H)
|
||||
# include <stropts.h>
|
||||
# endif // HAVE_STROPTS_H
|
||||
#endif // HAVE_TIOCGWINSZ
|
||||
|
||||
#include "common/terminal.h"
|
||||
@ -37,4 +43,3 @@ get_terminal_columns() {
|
||||
return DEFAULT_TERMINAL_COLUMNS;
|
||||
#endif // HAVE_TIOCGWINSZ
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,8 @@
|
||||
#include "output/p_vorbis.h"
|
||||
#include "output/p_vpx.h"
|
||||
|
||||
#define AVI_MAX_AUDIO_CHUNK_SIZE (10 * 1024 * 1024)
|
||||
|
||||
#define GAB2_TAG FOURCC('G', 'A', 'B', '2')
|
||||
#define GAB2_ID_LANGUAGE 0x0000
|
||||
#define GAB2_ID_LANGUAGE_UNICODE 0x0002
|
||||
@ -509,8 +511,11 @@ avi_reader_c::add_audio_demuxer(int aid) {
|
||||
m_audio_demuxers.push_back(demuxer);
|
||||
|
||||
int i, maxchunks = AVI_audio_chunks(m_avi);
|
||||
for (i = 0; i < maxchunks; i++)
|
||||
m_bytes_to_process += AVI_audio_size(m_avi, i);
|
||||
for (i = 0; i < maxchunks; i++) {
|
||||
auto size = AVI_audio_size(m_avi, i);
|
||||
if (size < AVI_MAX_AUDIO_CHUNK_SIZE)
|
||||
m_bytes_to_process += size;
|
||||
}
|
||||
}
|
||||
|
||||
generic_packetizer_c *
|
||||
@ -762,10 +767,14 @@ avi_reader_c::read_audio(avi_demuxer_t &demuxer) {
|
||||
while (true) {
|
||||
int size = AVI_audio_size(m_avi, AVI_get_audio_position_index(m_avi));
|
||||
|
||||
// -1 indicates the last chunk.
|
||||
if (-1 == size)
|
||||
return flush_packetizer(demuxer.m_ptzr);
|
||||
|
||||
if (!size) {
|
||||
// Sanity check. Ignore chunks with obvious wrong size information
|
||||
// (> 10 MB). Also skip 0-sized blocks. Those are officially
|
||||
// skipped.
|
||||
if (!size || (size > AVI_MAX_AUDIO_CHUNK_SIZE)) {
|
||||
AVI_set_audio_position_index(m_avi, AVI_get_audio_position_index(m_avi) + 1);
|
||||
continue;
|
||||
}
|
||||
@ -934,6 +943,11 @@ avi_reader_c::debug_dump_video_index() {
|
||||
int num_video_frames = AVI_video_frames(m_avi), i;
|
||||
|
||||
mxinfo(boost::format("AVI video index dump: %1% entries; frame rate: %2%\n") % num_video_frames % m_fps);
|
||||
for (i = 0; num_video_frames > i; ++i)
|
||||
mxinfo(boost::format(" %1%: %2% bytes\n") % i % AVI_frame_size(m_avi, i));
|
||||
for (i = 0; num_video_frames > i; ++i) {
|
||||
int key = 0;
|
||||
AVI_read_frame(m_avi, nullptr, &key);
|
||||
mxinfo(boost::format(" %1%: %2% bytes; key: %3%\n") % i % AVI_frame_size(m_avi, i) % key);
|
||||
}
|
||||
|
||||
AVI_set_video_position(m_avi, 0);
|
||||
}
|
||||
|
@ -54,13 +54,26 @@ mpeg_ts_track_c::send_to_packetizer() {
|
||||
auto timecode_to_use = !m_timecode.valid() ? timecode_c{}
|
||||
: reader.m_dont_use_audio_pts && (ES_AUDIO_TYPE == type) ? timecode_c{}
|
||||
: m_apply_dts_timecode_fix && (m_previous_timecode == m_timecode) ? timecode_c{}
|
||||
: (m_timecode < reader.m_global_timecode_offset) ? timecode_c::ns(0)
|
||||
: m_timecode - reader.m_global_timecode_offset;
|
||||
: std::max(m_timecode, reader.m_global_timecode_offset);
|
||||
|
||||
auto timecode_to_check = timecode_to_use.valid() ? timecode_to_use : reader.m_stream_timecode;
|
||||
auto const &min = reader.get_timecode_restriction_min();
|
||||
auto const &max = reader.get_timecode_restriction_max();
|
||||
auto use_packet = ptzr != -1;
|
||||
|
||||
if ( (min.valid() && (timecode_to_check < min))
|
||||
|| (max.valid() && (timecode_to_check > max)))
|
||||
use_packet = false;
|
||||
|
||||
if (timecode_to_use.valid()) {
|
||||
reader.m_stream_timecode = timecode_to_use;
|
||||
timecode_to_use -= std::max(reader.m_global_timecode_offset, min.valid() ? min : timecode_c::ns(0));
|
||||
}
|
||||
|
||||
mxdebug_if(m_debug_delivery, boost::format("send_to_packetizer() PID %1% expected %2% actual %3% timecode_to_use %4% m_previous_timecode %5%\n")
|
||||
% pid % pes_payload_size % pes_payload->get_size() % timecode_to_use % m_previous_timecode);
|
||||
|
||||
if (ptzr != -1)
|
||||
if (use_packet)
|
||||
reader.m_reader_packetizers[ptzr]->process(new packet_t(memory_c::clone(pes_payload->get_buffer(), pes_payload->get_size()), timecode_to_use.to_ns(-1)));
|
||||
|
||||
pes_payload->remove(pes_payload->get_size());
|
||||
@ -387,6 +400,7 @@ mpeg_ts_reader_c::mpeg_ts_reader_c(const track_info_c &ti,
|
||||
, PMT_pid(-1)
|
||||
, es_to_process{}
|
||||
, m_global_timecode_offset{}
|
||||
, m_stream_timecode{timecode_c::ns(0)}
|
||||
, input_status(INPUT_PROBE)
|
||||
, track_buffer_ready(-1)
|
||||
, file_done{}
|
||||
|
@ -362,7 +362,7 @@ protected:
|
||||
bool PAT_found, PMT_found;
|
||||
int16_t PMT_pid;
|
||||
int es_to_process;
|
||||
timecode_c m_global_timecode_offset;
|
||||
timecode_c m_global_timecode_offset, m_stream_timecode;
|
||||
|
||||
mpeg_ts_input_type_e input_status; // can be INPUT_PROBE, INPUT_READ
|
||||
int track_buffer_ready;
|
||||
|
@ -2391,10 +2391,19 @@ add_filelists_for_playlists() {
|
||||
|
||||
auto &file_names = filelist->playlist_mpls_in->get_file_names();
|
||||
auto previous_filelist_id = filelist->id;
|
||||
auto const &play_items = filelist->playlist_mpls_in->get_mpls_parser().get_playlist().items;
|
||||
|
||||
assert(file_names.size() == play_items.size());
|
||||
|
||||
filelist->restricted_timecode_min = play_items[0].in_time;
|
||||
filelist->restricted_timecode_max = play_items[0].out_time;
|
||||
|
||||
for (size_t idx = 1, idx_end = file_names.size(); idx < idx_end; ++idx) {
|
||||
auto current_filelist_id = g_files.size() + new_filelists.size();
|
||||
auto new_filelist = create_filelist_for_playlist(file_names[idx], previous_filelist_id, current_filelist_id, idx, *filelist->ti);
|
||||
auto current_filelist_id = g_files.size() + new_filelists.size();
|
||||
auto new_filelist = create_filelist_for_playlist(file_names[idx], previous_filelist_id, current_filelist_id, idx, *filelist->ti);
|
||||
new_filelist.restricted_timecode_min = play_items[idx].in_time;
|
||||
new_filelist.restricted_timecode_max = play_items[idx].out_time;
|
||||
|
||||
new_filelists.push_back(new_filelist);
|
||||
|
||||
previous_filelist_id = new_filelist.id;
|
||||
|
@ -1301,6 +1301,8 @@ calc_attachment_sizes() {
|
||||
*/
|
||||
void
|
||||
create_readers() {
|
||||
static auto s_debug_timecode_restrictions = debugging_option_c{"timecode_restrictions"};
|
||||
|
||||
for (auto &file : g_files) {
|
||||
try {
|
||||
mm_io_cptr input_file = file.playlist_mpls_in ? std::static_pointer_cast<mm_io_c>(file.playlist_mpls_in) : open_input_file(file);
|
||||
@ -1401,11 +1403,15 @@ create_readers() {
|
||||
}
|
||||
|
||||
file.reader->read_headers();
|
||||
file.reader->set_timecode_restrictions(file.restricted_timecode_min, file.restricted_timecode_max);
|
||||
|
||||
// Re-calculate file size because the reader might switch to a
|
||||
// multi I/O reader in read_headers().
|
||||
file.size = file.reader->get_file_size();
|
||||
|
||||
mxdebug_if(s_debug_timecode_restrictions,
|
||||
boost::format("Timecode restrictions for %3%: min %1% max %2%\n") % file.restricted_timecode_min % file.restricted_timecode_max % file.ti->m_fname);
|
||||
|
||||
} catch (mtx::mm_io::open_x &error) {
|
||||
mxerror(boost::format(Y("The demultiplexer for the file '%1%' failed to initialize:\n%2%\n")) % file.ti->m_fname % Y("The file could not be opened for reading, or there was not enough data to parse its headers."));
|
||||
|
||||
|
@ -119,6 +119,8 @@ struct filelist_t {
|
||||
size_t playlist_index, playlist_previous_filelist_id;
|
||||
mm_mpls_multi_file_io_cptr playlist_mpls_in;
|
||||
|
||||
timecode_c restricted_timecode_min, restricted_timecode_max;
|
||||
|
||||
filelist_t()
|
||||
: size{}
|
||||
, id{}
|
||||
|
@ -1255,6 +1255,25 @@ generic_reader_c::~generic_reader_c() {
|
||||
delete m_reader_packetizers[i];
|
||||
}
|
||||
|
||||
void
|
||||
generic_reader_c::set_timecode_restrictions(timecode_c const &min,
|
||||
timecode_c const &max) {
|
||||
m_restricted_timecodes_min = min;
|
||||
m_restricted_timecodes_max = max;
|
||||
}
|
||||
|
||||
timecode_c const &
|
||||
generic_reader_c::get_timecode_restriction_min()
|
||||
const {
|
||||
return m_restricted_timecodes_min;
|
||||
}
|
||||
|
||||
timecode_c const &
|
||||
generic_reader_c::get_timecode_restriction_max()
|
||||
const {
|
||||
return m_restricted_timecodes_max;
|
||||
}
|
||||
|
||||
void
|
||||
generic_reader_c::read_all() {
|
||||
for (auto &packetizer : m_reader_packetizers)
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "common/stereo_mode.h"
|
||||
#include "common/strings/editing.h"
|
||||
#include "common/tags/tags.h"
|
||||
#include "common/timecode.h"
|
||||
#include "common/translation.h"
|
||||
#include "merge/item_selector.h"
|
||||
#include "merge/packet.h"
|
||||
@ -353,10 +354,12 @@ public:
|
||||
|
||||
int64_t m_reference_timecode_tolerance;
|
||||
|
||||
private:
|
||||
protected:
|
||||
id_result_t m_id_results_container;
|
||||
std::vector<id_result_t> m_id_results_tracks, m_id_results_attachments, m_id_results_chapters, m_id_results_tags;
|
||||
|
||||
timecode_c m_restricted_timecodes_min, m_restricted_timecodes_max;
|
||||
|
||||
public:
|
||||
generic_reader_c(const track_info_c &ti, const mm_io_cptr &in);
|
||||
virtual ~generic_reader_c();
|
||||
@ -366,6 +369,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void set_timecode_restrictions(timecode_c const &min, timecode_c const &max);
|
||||
virtual timecode_c const &get_timecode_restriction_min() const;
|
||||
virtual timecode_c const &get_timecode_restriction_max() const;
|
||||
|
||||
virtual void read_headers() = 0;
|
||||
virtual file_status_e read(generic_packetizer_c *ptzr, bool force = false) = 0;
|
||||
virtual void read_all();
|
||||
|
86
src/tools/mpls_dump.cpp
Normal file
86
src/tools/mpls_dump.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
mpls_dump - A tool dumping MPLS structures
|
||||
|
||||
Distributed under the GPL
|
||||
see the file COPYING for details
|
||||
or visit http://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#include "common/common_pch.h"
|
||||
|
||||
#include "common/command_line.h"
|
||||
#include "common/mpls.h"
|
||||
|
||||
static void
|
||||
show_help() {
|
||||
mxinfo("mpls_dump [options] input_file_name\n"
|
||||
"\n"
|
||||
"General options:\n"
|
||||
"\n"
|
||||
" -h, --help This help text\n"
|
||||
" -V, --version Print version information\n");
|
||||
mxexit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
show_version() {
|
||||
mxinfo("mpls_dump v" VERSION "\n");
|
||||
mxexit(0);
|
||||
}
|
||||
|
||||
static std::string
|
||||
parse_args(std::vector<std::string> &args) {
|
||||
std::string file_name;
|
||||
|
||||
for (auto & arg: args) {
|
||||
if ((arg == "-h") || (arg == "--help"))
|
||||
show_help();
|
||||
|
||||
else if ((arg == "-V") || (arg == "--version"))
|
||||
show_version();
|
||||
|
||||
else if (!file_name.empty())
|
||||
mxerror(Y("More than one input file given\n"));
|
||||
|
||||
else
|
||||
file_name = arg;
|
||||
}
|
||||
|
||||
if (file_name.empty())
|
||||
mxerror(Y("No file name given\n"));
|
||||
|
||||
return file_name;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_file(const std::string &file_name) {
|
||||
auto in = mm_file_io_c{file_name};
|
||||
auto parser = mtx::mpls::parser_c{};
|
||||
|
||||
if (!parser.parse(&in))
|
||||
mxerror("MPLS file could not be parsed.\n");
|
||||
|
||||
parser.dump();
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc,
|
||||
char **argv) {
|
||||
mtx_common_init("mpls_dump");
|
||||
|
||||
auto args = command_line_utf8(argc, argv);
|
||||
while (handle_common_cli_args(args, "-r"))
|
||||
;
|
||||
|
||||
auto file_name = parse_args(args);
|
||||
|
||||
try {
|
||||
parse_file(file_name);
|
||||
} catch (mtx::mm_io::exception &) {
|
||||
mxerror(Y("File not found\n"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user