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 Producer from "./producer.mjs";
|
||||
|
||||
export default async function kdenliveProject(
|
||||
source_files,
|
||||
project_settings, // const project_settings = { fps: 30 };
|
||||
clips
|
||||
) {
|
||||
const producers = await Promise.all(source_files.map(Producer.fromFile));
|
||||
return `<?xml version='1.0' encoding='utf-8'?>
|
||||
export default class Project {
|
||||
constructor(fps) {
|
||||
this.producers = [];
|
||||
this.clips = [];
|
||||
this.fps = fps;
|
||||
}
|
||||
|
||||
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">
|
||||
<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"/>
|
||||
${(
|
||||
await Promise.all(
|
||||
producers.map((producer) => producer.toXML(project_settings))
|
||||
)
|
||||
await Promise.all(this.producers.map((producer) => producer.toXML(this.fps)))
|
||||
).join("\n")}
|
||||
<playlist id="main_bin">
|
||||
<property name="kdenlive:docproperties.activeTrack">2</property>
|
||||
@ -29,15 +34,12 @@ ${(
|
||||
]
|
||||
</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:documentnotes"/>
|
||||
<property name="xml_retain">1</property>
|
||||
${producers
|
||||
.map(
|
||||
(producer, index) =>
|
||||
`<entry producer="producer${index}" in="00:00:00.000" out="${producer.getDuration()}"/>`
|
||||
)
|
||||
${this.producers
|
||||
.map((producer) => `<entry producer="producer${producer.index}"/>`)
|
||||
.join("\n")}
|
||||
</playlist>
|
||||
<producer id="black_track" in="00:00:00.000" out="00:08:20.000">
|
||||
@ -51,6 +53,8 @@ ${producers
|
||||
</producer>
|
||||
<playlist id="playlist0">
|
||||
<property name="kdenlive:audio_track">1</property>
|
||||
<blank length="1000"/>
|
||||
<entry producer="producer1"/>
|
||||
</playlist>
|
||||
<playlist id="playlist1">
|
||||
<property name="kdenlive:audio_track">1</property>
|
||||
@ -93,12 +97,12 @@ ${producers
|
||||
</tractor>
|
||||
</mlt>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
const project_content = await kdenliveProject(
|
||||
["/home/kuba/Videos/5min.mp4", "/home/kuba/Videos/5min.wav"],
|
||||
{
|
||||
fps: 30,
|
||||
}
|
||||
);
|
||||
await $`echo ${project_content} > project-generated.kdenlive`;
|
||||
const project = new Project(30);
|
||||
|
||||
project.addProducer("/home/kuba/Videos/5min.mp4");
|
||||
project.addProducer("/home/kuba/Videos/5min.wav");
|
||||
|
||||
await $`echo ${await project.toXML()} > project-generated.kdenlive`;
|
||||
|
102
producer.mjs
102
producer.mjs
@ -6,107 +6,23 @@ import {
|
||||
formatDuration,
|
||||
} 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 producerIndexGen = makeIDGen(0);
|
||||
|
||||
export default class Producer {
|
||||
constructor(metadata) {
|
||||
this.metadata = metadata;
|
||||
constructor(path) {
|
||||
this.path = path;
|
||||
this.index = producerIndexGen.next().value;
|
||||
}
|
||||
|
||||
static prop_types = {
|
||||
length: (metadata, project_settings) => {
|
||||
const duration = getStream(metadata.track, "General").Duration;
|
||||
return `${duration * project_settings.fps}`;
|
||||
},
|
||||
eof: "pause",
|
||||
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")}.`
|
||||
),
|
||||
};
|
||||
},
|
||||
};
|
||||
async toXML(fps) {
|
||||
const xml = (
|
||||
await $`melt ${
|
||||
this.path
|
||||
} -consumer xml ${`frame_rate_num=${fps}`} | htmlq producer`
|
||||
).stdout;
|
||||
|
||||
static async fromFile(file_path) {
|
||||
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>
|
||||
`;
|
||||
return xml.replace("producer0", `producer${this.index}`);
|
||||
}
|
||||
}
|
||||
|
1
util.mjs
1
util.mjs
@ -20,7 +20,6 @@ export async function renderProperty(
|
||||
} else {
|
||||
value = await fn(metadata, project_settings);
|
||||
}
|
||||
console.log(name, value);
|
||||
if (value === null) {
|
||||
return "";
|
||||
} 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