mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 02:06:43 +00:00
fix(media): m4a/AAC audio files from non-Apple sources are misidentified as video/mp4 and excluded from audio workflows (#111177)
* fix(media): preserve audio hints for isom-brand m4a/AAC files misidentified as video/mp4 * fix(media): correct ambiguous M4A aliases Co-authored-by: 潘晓波0668000512 <pan.xiaobo@xydigit.com> --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
co-authored by
Peter Steinberger
parent
bdf71d7d98
commit
e45ebac97a
@@ -26,6 +26,12 @@ async function makeOoxmlZip(opts: { mainMime: string; partPath: string }): Promi
|
||||
return await zip.generateAsync({ type: "nodebuffer" });
|
||||
}
|
||||
|
||||
// file-type classifies this generic ISO-BMFF brand as video/mp4 without track metadata.
|
||||
const ISOM_BRAND_BUFFER = Buffer.from(
|
||||
"0000001c6674797069736f6d0000000069736f6d0000000000000000",
|
||||
"hex",
|
||||
);
|
||||
|
||||
describe("mime detection", () => {
|
||||
async function expectDetectedMime(params: {
|
||||
input: Parameters<typeof detectMime>[0];
|
||||
@@ -221,10 +227,51 @@ describe("mime detection", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves audio metadata when an MP4 extension cannot identify track kind", async () => {
|
||||
await expectDetectedMime({
|
||||
input: { filePath: "voice.mp4", headerMime: "audio/mp4" },
|
||||
it.each([
|
||||
{
|
||||
name: "audio/mp4 header",
|
||||
filePath: "voice.mp4",
|
||||
headerMime: "audio/mp4",
|
||||
expected: "audio/mp4",
|
||||
},
|
||||
{
|
||||
name: "audio/x-m4a header",
|
||||
filePath: "voice.m4a",
|
||||
headerMime: "audio/x-m4a",
|
||||
expected: "audio/x-m4a",
|
||||
},
|
||||
{
|
||||
name: "audio/m4a header",
|
||||
filePath: "voice.m4a",
|
||||
headerMime: "audio/m4a",
|
||||
expected: "audio/m4a",
|
||||
},
|
||||
{
|
||||
name: "m4a extension",
|
||||
filePath: "voice.m4a",
|
||||
headerMime: undefined,
|
||||
expected: "audio/x-m4a",
|
||||
},
|
||||
{
|
||||
name: "mp4 extension without an audio hint",
|
||||
filePath: "clip.mp4",
|
||||
headerMime: undefined,
|
||||
expected: "video/mp4",
|
||||
},
|
||||
{
|
||||
name: "audio/aac elementary-stream metadata",
|
||||
filePath: "voice.aac",
|
||||
headerMime: "audio/aac",
|
||||
expected: "video/mp4",
|
||||
},
|
||||
] as const)("resolves ambiguous isom-brand bytes from $name", async (testCase) => {
|
||||
await expectDetectedMime({
|
||||
input: {
|
||||
buffer: ISOM_BRAND_BUFFER,
|
||||
filePath: testCase.filePath,
|
||||
headerMime: testCase.headerMime,
|
||||
},
|
||||
expected: testCase.expected,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -381,6 +428,7 @@ describe("extensionForMime", () => {
|
||||
{ mime: "audio/x-wav", expected: ".wav" },
|
||||
{ mime: "audio/webm", expected: ".webm" },
|
||||
{ mime: "audio/x-m4a", expected: ".m4a" },
|
||||
{ mime: "audio/m4a", expected: ".m4a" },
|
||||
{ mime: "audio/mp4", expected: ".m4a" },
|
||||
{ mime: "video/x-msvideo", expected: ".avi" },
|
||||
{ mime: "video/mp4", expected: ".mp4" },
|
||||
|
||||
@@ -28,6 +28,7 @@ const EXT_BY_MIME: Record<string, string> = {
|
||||
"audio/opus": ".opus",
|
||||
"audio/webm": ".webm",
|
||||
"audio/x-m4a": ".m4a",
|
||||
"audio/m4a": ".m4a",
|
||||
"audio/mp4": ".m4a",
|
||||
"audio/x-caf": ".caf",
|
||||
"video/x-msvideo": ".avi",
|
||||
@@ -88,6 +89,8 @@ const MIME_BY_EXT: Record<string, string> = {
|
||||
|
||||
const AMBIGUOUS_VIDEO_MIME_BY_AUDIO_MIME: Readonly<Record<string, string>> = {
|
||||
"audio/mp4": "video/mp4",
|
||||
"audio/x-m4a": "video/mp4",
|
||||
"audio/m4a": "video/mp4",
|
||||
"audio/webm": "video/webm",
|
||||
};
|
||||
|
||||
@@ -243,9 +246,9 @@ export async function detectMime(opts: {
|
||||
: (sniffed ?? extMime);
|
||||
// file-type defaults these containers to video without parsing their tracks.
|
||||
// Preserve a concrete audio hint only for those documented ambiguous results.
|
||||
const audioContainerHint = mimeHints.find(
|
||||
(mime) => AMBIGUOUS_VIDEO_MIME_BY_AUDIO_MIME[mime] === inferred,
|
||||
);
|
||||
const audioContainerHint =
|
||||
mimeHints.find((mime) => AMBIGUOUS_VIDEO_MIME_BY_AUDIO_MIME[mime] === inferred) ??
|
||||
(extMime && AMBIGUOUS_VIDEO_MIME_BY_AUDIO_MIME[extMime] === inferred ? extMime : undefined);
|
||||
if (audioContainerHint) {
|
||||
return audioContainerHint;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user