This reads burned in timecodes from the headers of the two timecode
flavors I have floating around (Tentacle and GoPro), and provides them
to users.
Signed-off-by: Palmer Dabbelt <pal...@dabbelt.com>
---
I'm very new to all this video editing stuff, but I'm trying to get
multiple devices syced up via timecodes and I think I've mostly got it
working. I'm using kdenlive and have a patch for that as well, but I
think the MLT side of things is going to need some work as what I have
here seems a bit clunky:
* I don't think converting to milliseconds was actually the right thing
to do, as I'm just converting everything to/from frames.
* I'm not sure how cut clips are meant to work, but I don't have any
code to handle timecode offsets either here or in kdenlive so I'm
assuming they're going to be broken.
* I'm just sort of guessing at this metadata based on reading some files
with ffprobe, I didn't read any specs. So I have no idea if that
pattern matching is going to be robust.
That said, I figured I'd just send this for now so at least I could get
it out on the list and see if anyone has a better idea...
---
src/framework/mlt.vers | 6 +++
src/framework/mlt_producer.c | 75 ++++++++++++++++++++++++++++++++++++
src/framework/mlt_producer.h | 2 +
src/mlt++/MltProducer.cpp | 11 ++++++
src/mlt++/MltProducer.h | 2 +
src/mlt++/mlt++.vers | 10 +++++
6 files changed, 106 insertions(+)
diff --git a/src/framework/mlt.vers b/src/framework/mlt.vers
index 1b99babb..85d70a6d 100644
--- a/src/framework/mlt.vers
+++ b/src/framework/mlt.vers
@@ -657,3 +657,9 @@ MLT_7.22.0 {
mlt_property_is_numeric;
mlt_property_is_rect;
} MLT_7.18.0;
+
+MLT_7.226.0 {
+ global:
+ mlt_producer_set_timecode;
+ mlt_producer_get_timecode;
+} MLT_7.22.0;
diff --git a/src/framework/mlt_producer.c b/src/framework/mlt_producer.c
index 904c9e02..fc9756c8 100644
--- a/src/framework/mlt_producer.c
+++ b/src/framework/mlt_producer.c
@@ -1284,6 +1284,81 @@ void mlt_producer_set_creation_time(mlt_producer self,
int64_t creation_time)
free(datestr);
}
+/** Get the timecode associated with the producer.
+ *
+ * \public \memberof mlt_producer_s
+ * \param self a producer
+ * \return The timecode for the given producer, in milliseconds.
+ */
+int64_t mlt_producer_get_timecode(mlt_producer self)
+{
+ mlt_producer producer = mlt_producer_cut_parent(self);
+
+ char *str = mlt_properties_get(MLT_PRODUCER_PROPERTIES(producer),
"timecode");
+ if (str) {
+ int64_t ms;
+ char dummy;
+ int ret = sscanf(str, "%" SCNd64 "%c", &ms, &dummy);
+ if (ret != 1)
+ return -1;
+ return ms;
+ }
+
+ // Check for a "time_reference" in the metadata, which is the timecode
+ // counted in samples. Convert that to milliseconds. This is an audio
+ // file, so just assume it's the first source.
+ str = mlt_properties_get(MLT_PRODUCER_PROPERTIES(producer),
+ "meta.attr.time_reference.markup");
+ if (str) {
+ int64_t samples;
+ char dummy;
+ int ret = sscanf(str, "%" SCNd64 "%c", &samples, &dummy);
+ if (ret != 1)
+ return -1;
+
+ str = mlt_properties_get(MLT_PRODUCER_PROPERTIES(producer),
+ "meta.media.0.codec.sample_rate");
+ if (!str)
+ return -1;
+ int64_t sample_rate;
+ ret = sscanf(str, "%" SCNd64 "%c", &sample_rate, &dummy);
+ if (ret != 1)
+ return -1;
+
+ return (samples * 1000) / sample_rate;
+ }
+
+ // Check for a "timecode" in GoPro format, which is HH:MM:SS;FRAME.
+ str = mlt_properties_get(MLT_PRODUCER_PROPERTIES(producer),
+ "meta.attr.0.stream.timecode.markup");
+ if (str) {
+ int hh, mm, ss, frame;
+ int ret = sscanf(str, "%02d:%02d:%02d;%02d", &hh, &mm, &ss, &frame);
+ if (ret != 4)
+ return -1;
+ return (frame * 1000 / mlt_producer_get_fps(producer)) + (ss + mm * 60
+ hh * 3600) * 1000;
+ }
+
+ return -1;
+}
+
+/** Set the timecode for the producer
+ *
+ * This allows callers to override the timecode deceted by MLT for a producer.
+ *
+ * \public \memberof mlt_producer_s
+ * \praam self a producer
+ * \param timecode The timecode, in milliseconds, to set
+ */
+
+void mlt_producer_set_timecode(mlt_producer self, int64_t timecode)
+{
+ char buf[32];
+ mlt_producer parent = mlt_producer_cut_parent(self);
+ snprintf(buf, sizeof(buf), "%" PRId64, timecode);
+ mlt_properties_set(MLT_PRODUCER_PROPERTIES(parent), "timecode", buf);
+}
+
/** Probe the producer to publish metadata properties.
*
* After this call the producer will publish meta.media properties
diff --git a/src/framework/mlt_producer.h b/src/framework/mlt_producer.h
index 9b7bcff7..a6c7acd6 100644
--- a/src/framework/mlt_producer.h
+++ b/src/framework/mlt_producer.h
@@ -144,6 +144,8 @@ extern int mlt_producer_optimise(mlt_producer self);
extern void mlt_producer_close(mlt_producer self);
int64_t mlt_producer_get_creation_time(mlt_producer self);
void mlt_producer_set_creation_time(mlt_producer self, int64_t creation_time);
+extern int64_t mlt_producer_get_timecode(mlt_producer self);
+extern void mlt_producer_set_timecode(mlt_producer self, int64_t timecode);
extern int mlt_producer_probe(mlt_producer self);
#endif
diff --git a/src/mlt++/MltProducer.cpp b/src/mlt++/MltProducer.cpp
index a837194d..40f305ad 100644
--- a/src/mlt++/MltProducer.cpp
+++ b/src/mlt++/MltProducer.cpp
@@ -262,6 +262,17 @@ void Producer::set_creation_time(int64_t creation_time)
mlt_producer_set_creation_time(get_producer(), creation_time);
}
+int64_t Producer::get_timecode()
+{
+ int64_t tc = mlt_producer_get_timecode(get_producer());
+ return tc;
+}
+
+void Producer::set_timecode(int64_t timecode)
+{
+ mlt_producer_set_timecode(get_producer(), timecode);
+}
+
bool Producer::probe()
{
return mlt_producer_probe(get_producer());
diff --git a/src/mlt++/MltProducer.h b/src/mlt++/MltProducer.h
index 7afefbc3..b1ef4d21 100644
--- a/src/mlt++/MltProducer.h
+++ b/src/mlt++/MltProducer.h
@@ -77,6 +77,8 @@ public:
int clear();
int64_t get_creation_time();
void set_creation_time(int64_t creation_time);
+ int64_t get_timecode();
+ void set_timecode(int64_t timecode);
bool probe();
};
} // namespace Mlt
diff --git a/src/mlt++/mlt++.vers b/src/mlt++/mlt++.vers
index 1934decd..d9ff3764 100644
--- a/src/mlt++/mlt++.vers
+++ b/src/mlt++/mlt++.vers
@@ -710,5 +710,15 @@ MLT_7.14.0 {
extern "C++" {
"Mlt::Producer::probe()";
"Mlt::Chain::attach_normalizers()";
+ "Mlt::Producer::get_timecode()";
+ "Mlt::Producer::set_timecode(int64_t)";
};
} MLT_7.12.0;
+
+MLT_7.26.0 {
+ global:
+ extern "C++" {
+ "Mlt::Producer::get_timecode()";
+ "Mlt::Producer::set_timecode(int64_t)";
+ };
+} MLT_7.14.0;
--
2.45.2
_______________________________________________
Mlt-devel mailing list
Mlt-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlt-devel