Rework to use the melt binary
This commit is contained in:
parent
3deb39fabb
commit
f205deb5e4
@ -1,13 +0,0 @@
|
|||||||
const audio_props = {
|
|
||||||
"stream.handler_name.markup": "SoundHandler",
|
|
||||||
"stream.type": "audio",
|
|
||||||
"codec.sample_fmt": (metadata) => {
|
|
||||||
const type = metadata.data.Format_Settings_Sign == "Signed" ? "s" : "u";
|
|
||||||
const bit_depth = metadata.data.BitDepth;
|
|
||||||
return `${type}${bit_depth}`;
|
|
||||||
},
|
|
||||||
"codec.channels": (metadata) => metadata.data.Channels,
|
|
||||||
"codec.sample_rate": (metadata) => metadata.data.SamplingRate,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default audio_props;
|
|
52
kdenlive.mjs
52
kdenlive.mjs
@ -3,21 +3,26 @@
|
|||||||
import { formatDuration } from "./util.mjs";
|
import { formatDuration } from "./util.mjs";
|
||||||
import Producer from "./producer.mjs";
|
import Producer from "./producer.mjs";
|
||||||
|
|
||||||
export default async function kdenliveProject(
|
export default class Project {
|
||||||
source_files,
|
constructor(fps) {
|
||||||
project_settings, // const project_settings = { fps: 30 };
|
this.producers = [];
|
||||||
clips
|
this.clips = [];
|
||||||
) {
|
this.fps = fps;
|
||||||
const producers = await Promise.all(source_files.map(Producer.fromFile));
|
}
|
||||||
return `<?xml version='1.0' encoding='utf-8'?>
|
|
||||||
|
addProducer(file) {
|
||||||
|
this.producers.push(new Producer(file));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
async toXML() {
|
||||||
|
return `<?xml version='1.0' encoding='utf-8'?>
|
||||||
<mlt LC_NUMERIC="C" producer="main_bin" version="7.0.0" root="/home/kuba/Downloads">
|
<mlt LC_NUMERIC="C" producer="main_bin" version="7.0.0" root="/home/kuba/Downloads">
|
||||||
<profile frame_rate_num="${
|
<profile frame_rate_num="${
|
||||||
project_settings.fps
|
this.fps
|
||||||
}" sample_aspect_num="1" display_aspect_den="9" colorspace="601" progressive="1" description="1920x1080 29.90fps" display_aspect_num="16" frame_rate_den="1" width="1920" height="1080" sample_aspect_den="1"/>
|
}" sample_aspect_num="1" display_aspect_den="9" colorspace="601" progressive="1" description="1920x1080 29.90fps" display_aspect_num="16" frame_rate_den="1" width="1920" height="1080" sample_aspect_den="1"/>
|
||||||
${(
|
${(
|
||||||
await Promise.all(
|
await Promise.all(this.producers.map((producer) => producer.toXML(this.fps)))
|
||||||
producers.map((producer) => producer.toXML(project_settings))
|
|
||||||
)
|
|
||||||
).join("\n")}
|
).join("\n")}
|
||||||
<playlist id="main_bin">
|
<playlist id="main_bin">
|
||||||
<property name="kdenlive:docproperties.activeTrack">2</property>
|
<property name="kdenlive:docproperties.activeTrack">2</property>
|
||||||
@ -29,15 +34,12 @@ ${(
|
|||||||
]
|
]
|
||||||
</property>
|
</property>
|
||||||
<property name="kdenlive:docproperties.kdenliveversion">21.08.1</property>
|
<property name="kdenlive:docproperties.kdenliveversion">21.08.1</property>
|
||||||
<property name="kdenlive:docproperties.version">1.02</property>
|
g <property name="kdenlive:docproperties.version">1.02</property>
|
||||||
<property name="kdenlive:expandedFolders"/>
|
<property name="kdenlive:expandedFolders"/>
|
||||||
<property name="kdenlive:documentnotes"/>
|
<property name="kdenlive:documentnotes"/>
|
||||||
<property name="xml_retain">1</property>
|
<property name="xml_retain">1</property>
|
||||||
${producers
|
${this.producers
|
||||||
.map(
|
.map((producer) => `<entry producer="producer${producer.index}"/>`)
|
||||||
(producer, index) =>
|
|
||||||
`<entry producer="producer${index}" in="00:00:00.000" out="${producer.getDuration()}"/>`
|
|
||||||
)
|
|
||||||
.join("\n")}
|
.join("\n")}
|
||||||
</playlist>
|
</playlist>
|
||||||
<producer id="black_track" in="00:00:00.000" out="00:08:20.000">
|
<producer id="black_track" in="00:00:00.000" out="00:08:20.000">
|
||||||
@ -51,6 +53,8 @@ ${producers
|
|||||||
</producer>
|
</producer>
|
||||||
<playlist id="playlist0">
|
<playlist id="playlist0">
|
||||||
<property name="kdenlive:audio_track">1</property>
|
<property name="kdenlive:audio_track">1</property>
|
||||||
|
<blank length="1000"/>
|
||||||
|
<entry producer="producer1"/>
|
||||||
</playlist>
|
</playlist>
|
||||||
<playlist id="playlist1">
|
<playlist id="playlist1">
|
||||||
<property name="kdenlive:audio_track">1</property>
|
<property name="kdenlive:audio_track">1</property>
|
||||||
@ -93,12 +97,12 @@ ${producers
|
|||||||
</tractor>
|
</tractor>
|
||||||
</mlt>
|
</mlt>
|
||||||
`;
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const project_content = await kdenliveProject(
|
const project = new Project(30);
|
||||||
["/home/kuba/Videos/5min.mp4", "/home/kuba/Videos/5min.wav"],
|
|
||||||
{
|
project.addProducer("/home/kuba/Videos/5min.mp4");
|
||||||
fps: 30,
|
project.addProducer("/home/kuba/Videos/5min.wav");
|
||||||
}
|
|
||||||
);
|
await $`echo ${await project.toXML()} > project-generated.kdenlive`;
|
||||||
await $`echo ${project_content} > project-generated.kdenlive`;
|
|
||||||
|
102
producer.mjs
102
producer.mjs
@ -6,107 +6,23 @@ import {
|
|||||||
formatDuration,
|
formatDuration,
|
||||||
} from "./util.mjs";
|
} from "./util.mjs";
|
||||||
import { makeIDGen } from "./util.mjs";
|
import { makeIDGen } from "./util.mjs";
|
||||||
import video_props from "./video_props.mjs";
|
|
||||||
import audio_props from "./audio_props.mjs";
|
|
||||||
|
|
||||||
const makeId = makeIDGen(1);
|
const makeId = makeIDGen(1);
|
||||||
const producerIndexGen = makeIDGen(0);
|
const producerIndexGen = makeIDGen(0);
|
||||||
|
|
||||||
export default class Producer {
|
export default class Producer {
|
||||||
constructor(metadata) {
|
constructor(path) {
|
||||||
this.metadata = metadata;
|
this.path = path;
|
||||||
this.index = producerIndexGen.next().value;
|
this.index = producerIndexGen.next().value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static prop_types = {
|
async toXML(fps) {
|
||||||
length: (metadata, project_settings) => {
|
const xml = (
|
||||||
const duration = getStream(metadata.track, "General").Duration;
|
await $`melt ${
|
||||||
return `${duration * project_settings.fps}`;
|
this.path
|
||||||
},
|
} -consumer xml ${`frame_rate_num=${fps}`} | htmlq producer`
|
||||||
eof: "pause",
|
).stdout;
|
||||||
resource: (metadata) => metadata["@ref"],
|
|
||||||
audio_index: (metadata) => getStreamIndex(metadata.track, "Audio"),
|
|
||||||
video_index: (metadata) => getStreamIndex(metadata.track, "Video"),
|
|
||||||
mute_on_pause: "0",
|
|
||||||
mlt_service: "avformat-novalidate",
|
|
||||||
seekable: "1",
|
|
||||||
aspect_ratio: "1",
|
|
||||||
"kdenlive:clipname": "",
|
|
||||||
"kdenlive:folderid": "-1",
|
|
||||||
"kdenlive:audio_max0": "208",
|
|
||||||
"kdenlive:id": () => makeId.next().value,
|
|
||||||
"kdenlive:file_size": async (metadata) =>
|
|
||||||
(
|
|
||||||
await $`du --bytes ${metadata["@ref"]} | awk '{print $1}'`
|
|
||||||
).stdout.replace("\n", ""),
|
|
||||||
"kdenlive:file_hash": async (metadata) =>
|
|
||||||
(
|
|
||||||
await $`head -c 1000000 ${metadata["@ref"]} && tail -c 1000000 ${metadata["@ref"]}`.pipe(
|
|
||||||
$`md5sum | awk '{print $1}'`
|
|
||||||
)
|
|
||||||
).stdout.replace("\n", ""),
|
|
||||||
"meta.media.nb_streams": (metadata) => metadata.track.length - 1,
|
|
||||||
$$$video: async (metadata, project_settings) => {
|
|
||||||
const video_index = indexOf(metadata.track, (e) => e["@type"] == "Video");
|
|
||||||
if (video_index == -1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
$replace: await renderAllProps(
|
|
||||||
video_props,
|
|
||||||
{
|
|
||||||
index: video_index,
|
|
||||||
path: metadata["@ref"],
|
|
||||||
data: metadata.track[video_index],
|
|
||||||
},
|
|
||||||
project_settings,
|
|
||||||
`meta.media.${getStreamIndex(metadata.track, "Video")}.`
|
|
||||||
),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
$$$audio: async (metadata, project_settings) => {
|
|
||||||
const audio_index = indexOf(metadata.track, (e) => e["@type"] == "Audio");
|
|
||||||
if (audio_index == -1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
$replace: await renderAllProps(
|
|
||||||
audio_props,
|
|
||||||
{
|
|
||||||
index: audio_index,
|
|
||||||
path: metadata["@ref"],
|
|
||||||
data: metadata.track[audio_index],
|
|
||||||
},
|
|
||||||
project_settings,
|
|
||||||
`meta.media.${getStreamIndex(metadata.track, "Audio")}.`
|
|
||||||
),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static async fromFile(file_path) {
|
return xml.replace("producer0", `producer${this.index}`);
|
||||||
const metadata = JSON.parse(
|
|
||||||
(await $`mediainfo --Output=JSON ${file_path}`).stdout
|
|
||||||
).media;
|
|
||||||
return new Producer(metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
getDuration() {
|
|
||||||
return formatDuration(
|
|
||||||
parseFloat(getStream(this.metadata.track, "General").Duration)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async toXML(project_settings) {
|
|
||||||
return `<producer id="producer${
|
|
||||||
this.index
|
|
||||||
}" in="00:00:00.000" out="${this.getDuration()}">
|
|
||||||
${await renderAllProps(
|
|
||||||
Producer.prop_types,
|
|
||||||
this.metadata,
|
|
||||||
project_settings
|
|
||||||
)}
|
|
||||||
</producer>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
util.mjs
1
util.mjs
@ -20,7 +20,6 @@ export async function renderProperty(
|
|||||||
} else {
|
} else {
|
||||||
value = await fn(metadata, project_settings);
|
value = await fn(metadata, project_settings);
|
||||||
}
|
}
|
||||||
console.log(name, value);
|
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
return "";
|
return "";
|
||||||
} else if (value && value.$replace) {
|
} else if (value && value.$replace) {
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
const video_props = {
|
|
||||||
"stream.type": "video",
|
|
||||||
"stream.frame_rate": (metadata) => metadata.data.FrameRate,
|
|
||||||
"stream.sample_aspect_ratio": "1",
|
|
||||||
"codec.width": (metadata) => metadata.data.Width,
|
|
||||||
"codec.height": (metadata) => metadata.data.Height,
|
|
||||||
"codec.rotate": "0",
|
|
||||||
"codec.frame_rate": (metadata) => metadata.data.FrameRate,
|
|
||||||
"stream.handler_name.markup": "VideoHandle",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default video_props
|
|
Loading…
Reference in New Issue
Block a user