Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d8118684f | |||
| bb464b2c03 |
+17
-2
@@ -200,15 +200,24 @@ Result scan_mp4(const Window& file, std::size_t max_bytes) {
|
|||||||
Result result;
|
Result result;
|
||||||
result.kind = Kind::kMp4;
|
result.kind = Kind::kMp4;
|
||||||
|
|
||||||
// moov is usually at the start for streamed files and at the end otherwise.
|
// moov is usually at the start for streamed files and at the end otherwise. The
|
||||||
|
// walk reads box headers where they lie and steps over mdat in one go, so the
|
||||||
|
// whole file is walked from the top: a fixed prefix window cannot reach a moov
|
||||||
|
// that is larger than the window, which is what an MP4 with its cover art stored
|
||||||
|
// as a video track produces (a 4.9 MB moov against a 4 MiB window). The tail
|
||||||
|
// range stays as a fallback for a file whose leading boxes do not parse.
|
||||||
struct Range {
|
struct Range {
|
||||||
std::uint64_t begin;
|
std::uint64_t begin;
|
||||||
std::uint64_t end;
|
std::uint64_t end;
|
||||||
};
|
};
|
||||||
std::vector<Range> ranges{{0, (std::min<std::uint64_t>)(file.size(), max_bytes)}};
|
std::vector<Range> ranges{{0, file.size()}};
|
||||||
if (file.size() > max_bytes) {
|
if (file.size() > max_bytes) {
|
||||||
ranges.push_back({file.size() - max_bytes, file.size()});
|
ranges.push_back({file.size() - max_bytes, file.size()});
|
||||||
}
|
}
|
||||||
|
// An oversized moov is a file this probe cannot describe, and walking it would be
|
||||||
|
// unbounded work; it is reported instead of entered.
|
||||||
|
constexpr std::uint64_t kMaxMoovBytes = 64ull * 1024ull * 1024ull;
|
||||||
|
bool oversized_moov = false;
|
||||||
|
|
||||||
unsigned audio_seen = 0;
|
unsigned audio_seen = 0;
|
||||||
bool found_any_audio = false;
|
bool found_any_audio = false;
|
||||||
@@ -218,6 +227,10 @@ Result scan_mp4(const Window& file, std::size_t max_bytes) {
|
|||||||
[&](const std::string& type, std::uint64_t payload, std::uint64_t box_end,
|
[&](const std::string& type, std::uint64_t payload, std::uint64_t box_end,
|
||||||
std::size_t) {
|
std::size_t) {
|
||||||
if (type != "moov") return true;
|
if (type != "moov") return true;
|
||||||
|
if (box_end - payload > kMaxMoovBytes) {
|
||||||
|
oversized_moov = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
walk_boxes(file, payload, box_end, 1,
|
walk_boxes(file, payload, box_end, 1,
|
||||||
[&](const std::string& inner, std::uint64_t inner_payload,
|
[&](const std::string& inner, std::uint64_t inner_payload,
|
||||||
std::uint64_t inner_end, std::size_t) {
|
std::uint64_t inner_end, std::size_t) {
|
||||||
@@ -273,6 +286,8 @@ Result scan_mp4(const Window& file, std::size_t max_bytes) {
|
|||||||
result.detail = "mp4: first audio track is " +
|
result.detail = "mp4: first audio track is " +
|
||||||
(first_audio_format.empty() ? std::string("unknown")
|
(first_audio_format.empty() ? std::string("unknown")
|
||||||
: first_audio_format);
|
: first_audio_format);
|
||||||
|
} else if (oversized_moov) {
|
||||||
|
result.detail = "mp4: moov is larger than the scan limit";
|
||||||
} else {
|
} else {
|
||||||
result.detail = "mp4: no audio track found in the scanned window";
|
result.detail = "mp4: no audio track found in the scanned window";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,32 @@ constexpr std::size_t kBedReadBytes = 48u * 1024u;
|
|||||||
constexpr std::size_t kBedPipeBytes = 1u << 20;
|
constexpr std::size_t kBedPipeBytes = 1u << 20;
|
||||||
constexpr std::size_t kFrameSamples = JOC_FRAME_SAMPLES;
|
constexpr std::size_t kFrameSamples = JOC_FRAME_SAMPLES;
|
||||||
|
|
||||||
|
// The decoded bed has to stay on the E-AC-3 frame grid that the JOC matrix and the
|
||||||
|
// OAMD are indexed by. An mp4/mov edit list trims the decoded audio instead, which
|
||||||
|
// takes the bed off that grid by however much the list removes -- a Dolby Atmos
|
||||||
|
// download loses 2432 samples (1.58 frames) -- and every frame's matrix would then be
|
||||||
|
// applied to audio tens of milliseconds away from it, so a subset of the objects comes
|
||||||
|
// out attenuated. The demuxer's own option drops the trim; the option exists only on
|
||||||
|
// the mov/mp4 demuxer, so it is passed for that family alone.
|
||||||
|
bool has_mov_timeline(const std::string& path) {
|
||||||
|
static const char* const kExtensions[] = {".mp4", ".m4a", ".m4b", ".m4v",
|
||||||
|
".mov", ".3gp", ".3g2", ".mj2"};
|
||||||
|
std::string lowered = path;
|
||||||
|
for (char& character : lowered) {
|
||||||
|
if (character >= 'A' && character <= 'Z') {
|
||||||
|
character = static_cast<char>(character - 'A' + 'a');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const char* extension : kExtensions) {
|
||||||
|
const std::size_t length = std::strlen(extension);
|
||||||
|
if (lowered.size() >= length &&
|
||||||
|
lowered.compare(lowered.size() - length, length, extension) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Kernel entry points.
|
// Kernel entry points.
|
||||||
//
|
//
|
||||||
@@ -685,6 +711,7 @@ bool Engine::Impl::start_bed(std::uint64_t source_sample, std::string* error) {
|
|||||||
// at the start of the file, which is a low-level, noise-like difference from a
|
// at the start of the file, which is a low-level, noise-like difference from a
|
||||||
// play-through rather than a misalignment: the position stays exact.
|
// play-through rather than a misalignment: the position stays exact.
|
||||||
std::wstring input_arguments = L"-drc_scale 0 -target_level 0";
|
std::wstring input_arguments = L"-drc_scale 0 -target_level 0";
|
||||||
|
if (has_mov_timeline(input_path)) input_arguments += L" -ignore_editlist 1";
|
||||||
const std::wstring offset = seek_time(source_sample);
|
const std::wstring offset = seek_time(source_sample);
|
||||||
if (!offset.empty()) input_arguments += L" -ss " + offset;
|
if (!offset.empty()) input_arguments += L" -ss " + offset;
|
||||||
std::wstring bed_arguments = L"-map 0:a:";
|
std::wstring bed_arguments = L"-map 0:a:";
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
// Kept in one place: the string reported to foobar2000 and written to the log
|
// Kept in one place: the string reported to foobar2000 and written to the log
|
||||||
// must not drift apart.
|
// must not drift apart.
|
||||||
#define JOC_VERSION "0.2.1"
|
#define JOC_VERSION "0.2.2"
|
||||||
|
|
||||||
DECLARE_COMPONENT_VERSION("JOC decoder (E-AC-3 JOC)", JOC_VERSION,
|
DECLARE_COMPONENT_VERSION("JOC decoder (E-AC-3 JOC)", JOC_VERSION,
|
||||||
"Plays E-AC-3 JOC (Dolby Atmos) files: the JOC objects are "
|
"Plays E-AC-3 JOC (Dolby Atmos) files: the JOC objects are "
|
||||||
|
|||||||
Reference in New Issue
Block a user