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