Hi Palmer,

I think it would make sense to send your patch for MLT as a pull request on 
GitHub as one can discuss the code better over there (Dan and Brian correct me 
if that's not what you prefer).

For Kdenlive also feel free to open a draft merge request with your changes 
even in an early state.

Cheers,
Julius (Kdenlive Team)

07.08.2024 08:35:11 Palmer Dabbelt <pal...@dabbelt.com>:

> 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


_______________________________________________
Mlt-devel mailing list
Mlt-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlt-devel

Reply via email to