diff --git a/src/framework/mlt.vers b/src/framework/mlt.vers index 1b99babb0..85d70a6d0 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 904c9e029..fc9756c8f 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 9b7bcff7b..a6c7acd68 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 a837194df..40f305ad2 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 7afefbc36..b1ef4d21d 100644 --- a/src/mlt++/MltProducer.h +++ b/src/mlt++/MltProducer.h @@ -77,6 +77,8 @@ class MLTPP_DECLSPEC Producer : public Service 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 1934decd8..d9ff37643 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;