diff mbox

[FFmpeg-devel] Limited timecode support for lavd/decklink

Message ID CALRhzq+eXtZCiGks28nwokfMJG6UVMkxLvbJY5yuBwoJnpwy3w@mail.gmail.com
State New
Headers show

Commit Message

Jonathan Morley May 25, 2018, 2:46 p.m. UTC
I apologize in advance for the formatting of this message. My mail
configuration impeded my efforts to use ‘—send-email’.

This commit did pass 'make fate’ though the use of these changes requires
decklink hardware so I did not add any new fate tests. By default the new
optional behavior is skipped for old behavior.

---
libavdevice/decklink_common.cpp | 30 -----------------------------
libavdevice/decklink_common.h   | 42 ++++++++++++++++++++++++++++++
+++++++++++
libavdevice/decklink_common_c.h |  1 +
libavdevice/decklink_dec.cpp    | 19 +++++++++++++++++++
libavdevice/decklink_dec_c.c    |  9 +++++++++
5 files changed, 71 insertions(+), 30 deletions(-)

 AV_OPT_TYPE_CONST, { .i64 = 3}, 0, 0,    DEC, "tc_format"},
+    { "rp188any",      NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0,    DEC, "tc_format"},
+    { "vitc",          NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0,    DEC, "tc_format"},
+    { "vitc2",         NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0,    DEC, "tc_format"},
+    { "serial",        NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 7}, 0, 0,    DEC, "tc_format"},
    { "video_input",  "video input",              OFFSET(video_input),
   AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 6,    DEC, "video_input"},
    { "unset",         NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "video_input"},
    { "sdi",           NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "video_input"},

Comments

Marton Balint May 25, 2018, 3:32 p.m. UTC | #1
On Fri, 25 May 2018, Jonathan Morley wrote:

> I apologize in advance for the formatting of this message. My mail
> configuration impeded my efforts to use ‘—send-email’.

Your mail is corrupted by new lines, attach the .patch file if you cannot 
resolve this.

>
> This commit did pass 'make fate’ though the use of these changes requires
> decklink hardware so I did not add any new fate tests. By default the new
> optional behavior is skipped for old behavior.
>
> ---
> libavdevice/decklink_common.cpp | 30 -----------------------------
> libavdevice/decklink_common.h   | 42 ++++++++++++++++++++++++++++++
> +++++++++++

Why is this huge chunk of function movement needed? If there is a good 
reason to do that, then split it into a separate patch, if there is not, 
then just get rid of it.

> libavdevice/decklink_common_c.h |  1 +
> libavdevice/decklink_dec.cpp    | 19 +++++++++++++++++++
> libavdevice/decklink_dec_c.c    |  9 +++++++++
> 5 files changed, 71 insertions(+), 30 deletions(-)
>
> diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.
> cpp
> index d8cced7c74..aab9d85b94 100644
> --- a/libavdevice/decklink_common.cpp
> +++ b/libavdevice/decklink_common.cpp
> @@ -77,36 +77,6 @@ static IDeckLinkIterator
> *decklink_create_iterator(AVFormatContext
> *avctx)
>    return iter;
> }
>
> -#ifdef _WIN32
> -static char *dup_wchar_to_utf8(wchar_t *w)
> -{
> -    char *s = NULL;
> -    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
> -    s = (char *) av_malloc(l);
> -    if (s)
> -        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
> -    return s;
> -}
> -#define DECKLINK_STR    OLECHAR *
> -#define DECKLINK_STRDUP dup_wchar_to_utf8
> -#define DECKLINK_FREE(s) SysFreeString(s)
> -#elif defined(__APPLE__)
> -static char *dup_cfstring_to_utf8(CFStringRef w)
> -{
> -    char s[256];
> -    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
> -    return av_strdup(s);
> -}
> -#define DECKLINK_STR    const __CFString *
> -#define DECKLINK_STRDUP dup_cfstring_to_utf8
> -#define DECKLINK_FREE(s) CFRelease(s)
> -#else
> -#define DECKLINK_STR    const char *
> -#define DECKLINK_STRDUP av_strdup
> -/* free() is needed for a string returned by the DeckLink SDL. */
> -#define DECKLINK_FREE(s) free((void *) s)
> -#endif
> -
> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
> **displayName)
> {
>    DECKLINK_STR tmpDisplayName;
> diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
> index 57ee7d1d68..8c5f8e9f06 100644
> --- a/libavdevice/decklink_common.h
> +++ b/libavdevice/decklink_common.h
> @@ -34,6 +34,36 @@
> #define DECKLINK_BOOL bool
> #endif
>
> +#ifdef _WIN32
> +static char *dup_wchar_to_utf8(wchar_t *w)
> +{
> +    char *s = NULL;
> +    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
> +    s = (char *) av_malloc(l);
> +    if (s)
> +        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
> +    return s;
> +}
> +#define DECKLINK_STR    OLECHAR *
> +#define DECKLINK_STRDUP dup_wchar_to_utf8
> +#define DECKLINK_FREE(s) SysFreeString(s)
> +#elif defined(__APPLE__)
> +static char *dup_cfstring_to_utf8(CFStringRef w)
> +{
> +    char s[256];
> +    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
> +    return av_strdup(s);
> +}
> +#define DECKLINK_STR    const __CFString *
> +#define DECKLINK_STRDUP dup_cfstring_to_utf8
> +#define DECKLINK_FREE(s) CFRelease(s)
> +#else
> +#define DECKLINK_STR    const char *
> +#define DECKLINK_STRDUP av_strdup
> +/* free() is needed for a string returned by the DeckLink SDL. */
> +#define DECKLINK_FREE(s) free((void *) s)
> +#endif
> +
> class decklink_output_callback;
> class decklink_input_callback;
>
> @@ -64,6 +94,7 @@ struct decklink_ctx {
>    BMDDisplayMode bmd_mode;
>    BMDVideoConnection video_input;
>    BMDAudioConnection audio_input;
> +    BMDTimecodeFormat tc_format;
>    int bmd_width;
>    int bmd_height;
>    int bmd_field_dominance;
> @@ -140,6 +171,17 @@ static const BMDVideoConnection
> decklink_video_connection_map[] = {
>    bmdVideoConnectionSVideo,
> };
>
> +static const BMDTimecodeFormat decklink_timecode_format_map[] = {
> +    (BMDTimecodeFormat)0,
> +    bmdTimecodeRP188VITC1,
> +    bmdTimecodeRP188VITC2,
> +    bmdTimecodeRP188LTC,
> +    bmdTimecodeRP188Any,
> +    bmdTimecodeVITC,
> +    bmdTimecodeVITCField2,
> +    bmdTimecodeSerial,
> +};
> +
> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
> **displayName);
> int ff_decklink_set_configs(AVFormatContext *avctx, decklink_direction_t
> direction);
> int ff_decklink_set_format(AVFormatContext *avctx, int width, int height,
> int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t
> direction = DIRECTION_OUT, int num = 0);
> diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_
> c.h
> index 08e9f9bbd5..32a5d70ee1 100644
> --- a/libavdevice/decklink_common_c.h
> +++ b/libavdevice/decklink_common_c.h
> @@ -50,6 +50,7 @@ struct decklink_cctx {
>    DecklinkPtsSource video_pts_source;
>    int audio_input;
>    int video_input;
> +    int tc_format;
>    int draw_bars;
>    char *format_code;
>    int raw_format;
> diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
> index 510637676c..818235bfa6 100644
> --- a/libavdevice/decklink_dec.cpp
> +++ b/libavdevice/decklink_dec.cpp
> @@ -726,6 +726,23 @@ HRESULT decklink_input_callback::
> VideoInputFrameArrived(
>            no_video = 0;
>        }
>
> +        // Handle Timecode (if requested)
> +        if (ctx->tc_format && !(av_dict_get(ctx->video_st->metadata,
> "timecode", NULL, 0)) && !no_video) {
> +            IDeckLinkTimecode *timecode;
> +            if (videoFrame->GetTimecode(ctx->tc_format, &timecode) ==
> S_OK) {
> +                DECKLINK_STR timecodeString = NULL;
> +                timecode->GetString(&timecodeString);
> +                const char* tc = DECKLINK_STRDUP(timecodeString);
> +                if (!(av_dict_set(&ctx->video_st->metadata, "timecode",
> tc, 0)))

Don't you need AV_DICT_DONT_STRDUP_VAL flag here?

> +                    av_log(avctx, AV_LOG_ERROR, "Unable to set
> timecode\n");
> +                if (timecodeString)
> +                    DECKLINK_FREE(timecodeString);
> +                timecode->Release();
> +            } else {
> +                av_log(avctx, AV_LOG_ERROR, "Unable to find timecode.\n");
> +            }
> +        }

Maybe it makes sense to put this under the else branch of if 
(videoFrame->GetFlags() & bmdFrameHasNoInputSource), because if you have 
no input, you won't have any (valid) timecode...

> +
>        pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock,
> abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base,
> &initial_video_pts, cctx->copyts);
>        pkt.dts = pkt.pts;
>
> @@ -939,6 +956,8 @@ av_cold int ff_decklink_read_header(AVFormatContext
> *avctx)
>    ctx->teletext_lines = cctx->teletext_lines;
>    ctx->preroll      = cctx->preroll;
>    ctx->duplex_mode  = cctx->duplex_mode;
> +    if (cctx->tc_format > 0 && (unsigned int)cctx->tc_format <
> FF_ARRAY_ELEMS(decklink_timecode_format_map))
> +        ctx->tc_format = decklink_timecode_format_map[cctx->tc_format];
>    if (cctx->video_input > 0 && (unsigned int)cctx->video_input <
> FF_ARRAY_ELEMS(decklink_video_connection_map))
>        ctx->video_input = decklink_video_connection_map[cctx->video_input];
>    if (cctx->audio_input > 0 && (unsigned int)cctx->audio_input <
> FF_ARRAY_ELEMS(decklink_audio_connection_map))
> diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
> index 47018dc681..6ab3819375 100644
> --- a/libavdevice/decklink_dec_c.c
> +++ b/libavdevice/decklink_dec_c.c
> @@ -48,6 +48,15 @@ static const AVOption options[] = {
>    { "unset",         NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "duplex_mode"},
>    { "half",          NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "duplex_mode"},
>    { "full",          NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "duplex_mode"},
> +    { "timecode_format", "timecode format",           OFFSET(tc_format),
> AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 7,    DEC, "tc_format"},
> +    { "none",          NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "tc_format"},
> +    { "rp188vitc",     NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "tc_format"},
> +    { "rp188vitc2",    NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "tc_format"},
> +    { "rp188ltc",      NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 3}, 0, 0,    DEC, "tc_format"},
> +    { "rp188any",      NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0,    DEC, "tc_format"},
> +    { "vitc",          NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0,    DEC, "tc_format"},
> +    { "vitc2",         NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0,    DEC, "tc_format"},
> +    { "serial",        NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 7}, 0, 0,    DEC, "tc_format"},
>    { "video_input",  "video input",              OFFSET(video_input),
>   AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 6,    DEC, "video_input"},
>    { "unset",         NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "video_input"},
>    { "sdi",           NULL,                                          0,
> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "video_input"},
> --

Documentation update is missing.

Regards,
Marton
Kieran O Leary May 25, 2018, 3:59 p.m. UTC | #2
I'd love to see some documentation and to know how timecode is stored in
the output file. This looks like a really welcome development!
Jonathan Morley May 25, 2018, 5:08 p.m. UTC | #3
> On May 25, 2018, at 8:32 AM, Marton Balint <cus@passwd.hu> wrote:
> 
> 
> 
> On Fri, 25 May 2018, Jonathan Morley wrote:
> 
>> I apologize in advance for the formatting of this message. My mail
>> configuration impeded my efforts to use ‘—send-email’.
> 
> Your mail is corrupted by new lines, attach the .patch file if you cannot resolve this.

Will do! Sorry about that. The mail server’s auth setup kept me from using ‘—send-email’ directly. I will send future patches as attachments.

>> 
>> This commit did pass 'make fate’ though the use of these changes requires
>> decklink hardware so I did not add any new fate tests. By default the new
>> optional behavior is skipped for old behavior.
>> 
>> ---
>> libavdevice/decklink_common.cpp | 30 -----------------------------
>> libavdevice/decklink_common.h   | 42 ++++++++++++++++++++++++++++++
>> +++++++++++
> 
> Why is this huge chunk of function movement needed? If there is a good reason to do that, then split it into a separate patch, if there is not, then just get rid of it.

The move here was so that I could make use of the cross platform safe DECKLINK string methods. I was only able to test with linux and build on mac, but I wanted to do my best to make a contribution that _could_ work on all platforms. I can break this into two patches if you prefer. 

>> libavdevice/decklink_common_c.h |  1 +
>> libavdevice/decklink_dec.cpp    | 19 +++++++++++++++++++
>> libavdevice/decklink_dec_c.c    |  9 +++++++++
>> 5 files changed, 71 insertions(+), 30 deletions(-)
>> 
>> diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.
>> cpp
>> index d8cced7c74..aab9d85b94 100644
>> --- a/libavdevice/decklink_common.cpp
>> +++ b/libavdevice/decklink_common.cpp
>> @@ -77,36 +77,6 @@ static IDeckLinkIterator
>> *decklink_create_iterator(AVFormatContext
>> *avctx)
>>   return iter;
>> }
>> 
>> -#ifdef _WIN32
>> -static char *dup_wchar_to_utf8(wchar_t *w)
>> -{
>> -    char *s = NULL;
>> -    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
>> -    s = (char *) av_malloc(l);
>> -    if (s)
>> -        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
>> -    return s;
>> -}
>> -#define DECKLINK_STR    OLECHAR *
>> -#define DECKLINK_STRDUP dup_wchar_to_utf8
>> -#define DECKLINK_FREE(s) SysFreeString(s)
>> -#elif defined(__APPLE__)
>> -static char *dup_cfstring_to_utf8(CFStringRef w)
>> -{
>> -    char s[256];
>> -    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
>> -    return av_strdup(s);
>> -}
>> -#define DECKLINK_STR    const __CFString *
>> -#define DECKLINK_STRDUP dup_cfstring_to_utf8
>> -#define DECKLINK_FREE(s) CFRelease(s)
>> -#else
>> -#define DECKLINK_STR    const char *
>> -#define DECKLINK_STRDUP av_strdup
>> -/* free() is needed for a string returned by the DeckLink SDL. */
>> -#define DECKLINK_FREE(s) free((void *) s)
>> -#endif
>> -
>> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
>> **displayName)
>> {
>>   DECKLINK_STR tmpDisplayName;
>> diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
>> index 57ee7d1d68..8c5f8e9f06 100644
>> --- a/libavdevice/decklink_common.h
>> +++ b/libavdevice/decklink_common.h
>> @@ -34,6 +34,36 @@
>> #define DECKLINK_BOOL bool
>> #endif
>> 
>> +#ifdef _WIN32
>> +static char *dup_wchar_to_utf8(wchar_t *w)
>> +{
>> +    char *s = NULL;
>> +    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
>> +    s = (char *) av_malloc(l);
>> +    if (s)
>> +        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
>> +    return s;
>> +}
>> +#define DECKLINK_STR    OLECHAR *
>> +#define DECKLINK_STRDUP dup_wchar_to_utf8
>> +#define DECKLINK_FREE(s) SysFreeString(s)
>> +#elif defined(__APPLE__)
>> +static char *dup_cfstring_to_utf8(CFStringRef w)
>> +{
>> +    char s[256];
>> +    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
>> +    return av_strdup(s);
>> +}
>> +#define DECKLINK_STR    const __CFString *
>> +#define DECKLINK_STRDUP dup_cfstring_to_utf8
>> +#define DECKLINK_FREE(s) CFRelease(s)
>> +#else
>> +#define DECKLINK_STR    const char *
>> +#define DECKLINK_STRDUP av_strdup
>> +/* free() is needed for a string returned by the DeckLink SDL. */
>> +#define DECKLINK_FREE(s) free((void *) s)
>> +#endif
>> +
>> class decklink_output_callback;
>> class decklink_input_callback;
>> 
>> @@ -64,6 +94,7 @@ struct decklink_ctx {
>>   BMDDisplayMode bmd_mode;
>>   BMDVideoConnection video_input;
>>   BMDAudioConnection audio_input;
>> +    BMDTimecodeFormat tc_format;
>>   int bmd_width;
>>   int bmd_height;
>>   int bmd_field_dominance;
>> @@ -140,6 +171,17 @@ static const BMDVideoConnection
>> decklink_video_connection_map[] = {
>>   bmdVideoConnectionSVideo,
>> };
>> 
>> +static const BMDTimecodeFormat decklink_timecode_format_map[] = {
>> +    (BMDTimecodeFormat)0,
>> +    bmdTimecodeRP188VITC1,
>> +    bmdTimecodeRP188VITC2,
>> +    bmdTimecodeRP188LTC,
>> +    bmdTimecodeRP188Any,
>> +    bmdTimecodeVITC,
>> +    bmdTimecodeVITCField2,
>> +    bmdTimecodeSerial,
>> +};
>> +
>> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
>> **displayName);
>> int ff_decklink_set_configs(AVFormatContext *avctx, decklink_direction_t
>> direction);
>> int ff_decklink_set_format(AVFormatContext *avctx, int width, int height,
>> int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t
>> direction = DIRECTION_OUT, int num = 0);
>> diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_
>> c.h
>> index 08e9f9bbd5..32a5d70ee1 100644
>> --- a/libavdevice/decklink_common_c.h
>> +++ b/libavdevice/decklink_common_c.h
>> @@ -50,6 +50,7 @@ struct decklink_cctx {
>>   DecklinkPtsSource video_pts_source;
>>   int audio_input;
>>   int video_input;
>> +    int tc_format;
>>   int draw_bars;
>>   char *format_code;
>>   int raw_format;
>> diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
>> index 510637676c..818235bfa6 100644
>> --- a/libavdevice/decklink_dec.cpp
>> +++ b/libavdevice/decklink_dec.cpp
>> @@ -726,6 +726,23 @@ HRESULT decklink_input_callback::
>> VideoInputFrameArrived(
>>           no_video = 0;
>>       }
>> 
>> +        // Handle Timecode (if requested)
>> +        if (ctx->tc_format && !(av_dict_get(ctx->video_st->metadata,
>> "timecode", NULL, 0)) && !no_video) {
>> +            IDeckLinkTimecode *timecode;
>> +            if (videoFrame->GetTimecode(ctx->tc_format, &timecode) ==
>> S_OK) {
>> +                DECKLINK_STR timecodeString = NULL;
>> +                timecode->GetString(&timecodeString);
>> +                const char* tc = DECKLINK_STRDUP(timecodeString);
>> +                if (!(av_dict_set(&ctx->video_st->metadata, "timecode",
>> tc, 0)))
> 
> Don't you need AV_DICT_DONT_STRDUP_VAL flag here?

Yes. I agree.

>> +                    av_log(avctx, AV_LOG_ERROR, "Unable to set
>> timecode\n");
>> +                if (timecodeString)
>> +                    DECKLINK_FREE(timecodeString);
>> +                timecode->Release();
>> +            } else {
>> +                av_log(avctx, AV_LOG_ERROR, "Unable to find timecode.\n");
>> +            }
>> +        }
> 
> Maybe it makes sense to put this under the else branch of if (videoFrame->GetFlags() & bmdFrameHasNoInputSource), because if you have no input, you won't have any (valid) timecode…

I can move this. The logic still checks for !no_video, but moving it should be more explicit.

Sadly I no longer have access to the hardware I used when making these changes and cannot test this kind of change. We have moved on to a video-for-linux based solution with AJA hardware. (I am currently adding support for TC to the v4l2 ffmpeg reader).

>> +
>>       pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock,
>> abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base,
>> &initial_video_pts, cctx->copyts);
>>       pkt.dts = pkt.pts;
>> 
>> @@ -939,6 +956,8 @@ av_cold int ff_decklink_read_header(AVFormatContext
>> *avctx)
>>   ctx->teletext_lines = cctx->teletext_lines;
>>   ctx->preroll      = cctx->preroll;
>>   ctx->duplex_mode  = cctx->duplex_mode;
>> +    if (cctx->tc_format > 0 && (unsigned int)cctx->tc_format <
>> FF_ARRAY_ELEMS(decklink_timecode_format_map))
>> +        ctx->tc_format = decklink_timecode_format_map[cctx->tc_format];
>>   if (cctx->video_input > 0 && (unsigned int)cctx->video_input <
>> FF_ARRAY_ELEMS(decklink_video_connection_map))
>>       ctx->video_input = decklink_video_connection_map[cctx->video_input];
>>   if (cctx->audio_input > 0 && (unsigned int)cctx->audio_input <
>> FF_ARRAY_ELEMS(decklink_audio_connection_map))
>> diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
>> index 47018dc681..6ab3819375 100644
>> --- a/libavdevice/decklink_dec_c.c
>> +++ b/libavdevice/decklink_dec_c.c
>> @@ -48,6 +48,15 @@ static const AVOption options[] = {
>>   { "unset",         NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "duplex_mode"},
>>   { "half",          NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "duplex_mode"},
>>   { "full",          NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "duplex_mode"},
>> +    { "timecode_format", "timecode format",           OFFSET(tc_format),
>> AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 7,    DEC, "tc_format"},
>> +    { "none",          NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "tc_format"},
>> +    { "rp188vitc",     NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "tc_format"},
>> +    { "rp188vitc2",    NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "tc_format"},
>> +    { "rp188ltc",      NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 3}, 0, 0,    DEC, "tc_format"},
>> +    { "rp188any",      NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0,    DEC, "tc_format"},
>> +    { "vitc",          NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0,    DEC, "tc_format"},
>> +    { "vitc2",         NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0,    DEC, "tc_format"},
>> +    { "serial",        NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 7}, 0, 0,    DEC, "tc_format"},
>>   { "video_input",  "video input",              OFFSET(video_input),
>>  AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 6,    DEC, "video_input"},
>>   { "unset",         NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "video_input"},
>>   { "sdi",           NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "video_input"},
>> --
> 
> Documentation update is missing.

D’oh! Sloppy.

> Regards,
> Marton
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
Please have a look at my comments above and let me know about splitting this into two patches and I will resubmit as attachments.

Thank you for taking a look!
Jonathan Morley May 25, 2018, 5:32 p.m. UTC | #4
Hi Kieran,

To answer your question, this change basically takes the first valid TC as a string and sticks it in the video’s avstream metadata dictionary where other muxers and encoders look. It does not make an independent timecode track/stream with samples per frame. That is why I called the patch “limited”. However there doesn’t seem to be many if any parts of ffmpeg that use dedicated timecode streams with individual samples. That is why it still seemed worth submitting my work back as we move on to other solutions.

I hope that still helps you in your case. I will stay the course to address Marton’s feedback and get this in there.

Thanks,
Jon

> On May 25, 2018, at 8:59 AM, Kieran O Leary <kieran.o.leary@gmail.com> wrote:
> 
> I'd love to see some documentation and to know how timecode is stored in
> the output file. This looks like a really welcome development!
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Kieran O Leary May 25, 2018, 5:47 p.m. UTC | #5
Hi Jonathan,

On Fri, May 25, 2018 at 6:32 PM, Jonathan Morley <jmorley@pixsystem.com> wrote:
> Hi Kieran,
>
> To answer your question, this change basically takes the first valid TC as a string and sticks it in the video’s avstream metadata dictionary where other muxers and encoders look. It does not make an independent timecode track/stream with samples per frame. That is why I called the patch “limited”. However there doesn’t seem to be many if any parts of ffmpeg that use dedicated timecode streams with individual samples. That is why it still seemed worth submitting my work back as we move on to other solutions.

It sounds great to me! I think that this type of timecode (just
storing first value as a string string) is all I've ever really seen
in the real world(I work in the Irish Film Archive and we have several
thousand video tapes as well). This is how AJA Control Room and
Blackmagic Media Express work anyhow. I'm hoping that this will allow
open source archival capture tools like
https://github.com/amiaopensource/vrecord to be able to capture
timecode.

I look forward to trying it out, as our goal is to be able to use
vrecord in order to capture tape to FFV1/Matroska. Matroska doesn't
support data tracks (yet), but ffmpeg does store the starting timecode
string as a Matroska Tag when it detects a timecode track in a source
video. I would love if capturing to Matroska from tape could store
that starting timecode value, but it's a completely seperate issue to
this patch.

>
> I hope that still helps you in your case. I will stay the course to address Marton’s feedback and get this in there.

yeah it's great, I'm also interested in your AJA work as we also have
AJA hardware, though as there's no open SDK for AJA, I'm not sure how
this would integrate into FFmpeg.

Best,

Kieran.
Jonathan Morley May 25, 2018, 6:06 p.m. UTC | #6
That sounds great, Kieran!

The plan with AJA is to leverage the open source ntv2_v4l2 (AJA video for linux driver) to capture audio, video, and timecode over SDI to a standard video for linux virtual device (aka /dev/video0). Then use the ffmpeg support for v4l2 to read it in and again set the TC string on the video stream metadata. I am just getting started after hearing confirmation from the AJA dev that he would add TC support to the ntv2_v4l2. In general video for linux could work as a consistent interface for this when capturing.

Sincerely,
Jon

> On May 25, 2018, at 10:47 AM, Kieran O Leary <kieran.o.leary@gmail.com> wrote:
> 
> Hi Jonathan,
> 
> On Fri, May 25, 2018 at 6:32 PM, Jonathan Morley <jmorley@pixsystem.com> wrote:
>> Hi Kieran,
>> 
>> To answer your question, this change basically takes the first valid TC as a string and sticks it in the video’s avstream metadata dictionary where other muxers and encoders look. It does not make an independent timecode track/stream with samples per frame. That is why I called the patch “limited”. However there doesn’t seem to be many if any parts of ffmpeg that use dedicated timecode streams with individual samples. That is why it still seemed worth submitting my work back as we move on to other solutions.
> 
> It sounds great to me! I think that this type of timecode (just
> storing first value as a string string) is all I've ever really seen
> in the real world(I work in the Irish Film Archive and we have several
> thousand video tapes as well). This is how AJA Control Room and
> Blackmagic Media Express work anyhow. I'm hoping that this will allow
> open source archival capture tools like
> https://github.com/amiaopensource/vrecord to be able to capture
> timecode.
> 
> I look forward to trying it out, as our goal is to be able to use
> vrecord in order to capture tape to FFV1/Matroska. Matroska doesn't
> support data tracks (yet), but ffmpeg does store the starting timecode
> string as a Matroska Tag when it detects a timecode track in a source
> video. I would love if capturing to Matroska from tape could store
> that starting timecode value, but it's a completely seperate issue to
> this patch.
> 
>> 
>> I hope that still helps you in your case. I will stay the course to address Marton’s feedback and get this in there.
> 
> yeah it's great, I'm also interested in your AJA work as we also have
> AJA hardware, though as there's no open SDK for AJA, I'm not sure how
> this would integrate into FFmpeg.
> 
> Best,
> 
> Kieran.
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Jonathan Morley May 25, 2018, 7:09 p.m. UTC | #7
Attached are the two patches to address your feedback, Marton. Please advise.

Thanks,
Jon



> On May 25, 2018, at 8:32 AM, Marton Balint <cus@passwd.hu> wrote:
> 
> 
> 
> On Fri, 25 May 2018, Jonathan Morley wrote:
> 
>> I apologize in advance for the formatting of this message. My mail
>> configuration impeded my efforts to use ‘—send-email’.
> 
> Your mail is corrupted by new lines, attach the .patch file if you cannot resolve this.
> 
>> 
>> This commit did pass 'make fate’ though the use of these changes requires
>> decklink hardware so I did not add any new fate tests. By default the new
>> optional behavior is skipped for old behavior.
>> 
>> ---
>> libavdevice/decklink_common.cpp | 30 -----------------------------
>> libavdevice/decklink_common.h   | 42 ++++++++++++++++++++++++++++++
>> +++++++++++
> 
> Why is this huge chunk of function movement needed? If there is a good reason to do that, then split it into a separate patch, if there is not, then just get rid of it.
> 
>> libavdevice/decklink_common_c.h |  1 +
>> libavdevice/decklink_dec.cpp    | 19 +++++++++++++++++++
>> libavdevice/decklink_dec_c.c    |  9 +++++++++
>> 5 files changed, 71 insertions(+), 30 deletions(-)
>> 
>> diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.
>> cpp
>> index d8cced7c74..aab9d85b94 100644
>> --- a/libavdevice/decklink_common.cpp
>> +++ b/libavdevice/decklink_common.cpp
>> @@ -77,36 +77,6 @@ static IDeckLinkIterator
>> *decklink_create_iterator(AVFormatContext
>> *avctx)
>>   return iter;
>> }
>> 
>> -#ifdef _WIN32
>> -static char *dup_wchar_to_utf8(wchar_t *w)
>> -{
>> -    char *s = NULL;
>> -    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
>> -    s = (char *) av_malloc(l);
>> -    if (s)
>> -        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
>> -    return s;
>> -}
>> -#define DECKLINK_STR    OLECHAR *
>> -#define DECKLINK_STRDUP dup_wchar_to_utf8
>> -#define DECKLINK_FREE(s) SysFreeString(s)
>> -#elif defined(__APPLE__)
>> -static char *dup_cfstring_to_utf8(CFStringRef w)
>> -{
>> -    char s[256];
>> -    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
>> -    return av_strdup(s);
>> -}
>> -#define DECKLINK_STR    const __CFString *
>> -#define DECKLINK_STRDUP dup_cfstring_to_utf8
>> -#define DECKLINK_FREE(s) CFRelease(s)
>> -#else
>> -#define DECKLINK_STR    const char *
>> -#define DECKLINK_STRDUP av_strdup
>> -/* free() is needed for a string returned by the DeckLink SDL. */
>> -#define DECKLINK_FREE(s) free((void *) s)
>> -#endif
>> -
>> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
>> **displayName)
>> {
>>   DECKLINK_STR tmpDisplayName;
>> diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
>> index 57ee7d1d68..8c5f8e9f06 100644
>> --- a/libavdevice/decklink_common.h
>> +++ b/libavdevice/decklink_common.h
>> @@ -34,6 +34,36 @@
>> #define DECKLINK_BOOL bool
>> #endif
>> 
>> +#ifdef _WIN32
>> +static char *dup_wchar_to_utf8(wchar_t *w)
>> +{
>> +    char *s = NULL;
>> +    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
>> +    s = (char *) av_malloc(l);
>> +    if (s)
>> +        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
>> +    return s;
>> +}
>> +#define DECKLINK_STR    OLECHAR *
>> +#define DECKLINK_STRDUP dup_wchar_to_utf8
>> +#define DECKLINK_FREE(s) SysFreeString(s)
>> +#elif defined(__APPLE__)
>> +static char *dup_cfstring_to_utf8(CFStringRef w)
>> +{
>> +    char s[256];
>> +    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
>> +    return av_strdup(s);
>> +}
>> +#define DECKLINK_STR    const __CFString *
>> +#define DECKLINK_STRDUP dup_cfstring_to_utf8
>> +#define DECKLINK_FREE(s) CFRelease(s)
>> +#else
>> +#define DECKLINK_STR    const char *
>> +#define DECKLINK_STRDUP av_strdup
>> +/* free() is needed for a string returned by the DeckLink SDL. */
>> +#define DECKLINK_FREE(s) free((void *) s)
>> +#endif
>> +
>> class decklink_output_callback;
>> class decklink_input_callback;
>> 
>> @@ -64,6 +94,7 @@ struct decklink_ctx {
>>   BMDDisplayMode bmd_mode;
>>   BMDVideoConnection video_input;
>>   BMDAudioConnection audio_input;
>> +    BMDTimecodeFormat tc_format;
>>   int bmd_width;
>>   int bmd_height;
>>   int bmd_field_dominance;
>> @@ -140,6 +171,17 @@ static const BMDVideoConnection
>> decklink_video_connection_map[] = {
>>   bmdVideoConnectionSVideo,
>> };
>> 
>> +static const BMDTimecodeFormat decklink_timecode_format_map[] = {
>> +    (BMDTimecodeFormat)0,
>> +    bmdTimecodeRP188VITC1,
>> +    bmdTimecodeRP188VITC2,
>> +    bmdTimecodeRP188LTC,
>> +    bmdTimecodeRP188Any,
>> +    bmdTimecodeVITC,
>> +    bmdTimecodeVITCField2,
>> +    bmdTimecodeSerial,
>> +};
>> +
>> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
>> **displayName);
>> int ff_decklink_set_configs(AVFormatContext *avctx, decklink_direction_t
>> direction);
>> int ff_decklink_set_format(AVFormatContext *avctx, int width, int height,
>> int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t
>> direction = DIRECTION_OUT, int num = 0);
>> diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_
>> c.h
>> index 08e9f9bbd5..32a5d70ee1 100644
>> --- a/libavdevice/decklink_common_c.h
>> +++ b/libavdevice/decklink_common_c.h
>> @@ -50,6 +50,7 @@ struct decklink_cctx {
>>   DecklinkPtsSource video_pts_source;
>>   int audio_input;
>>   int video_input;
>> +    int tc_format;
>>   int draw_bars;
>>   char *format_code;
>>   int raw_format;
>> diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
>> index 510637676c..818235bfa6 100644
>> --- a/libavdevice/decklink_dec.cpp
>> +++ b/libavdevice/decklink_dec.cpp
>> @@ -726,6 +726,23 @@ HRESULT decklink_input_callback::
>> VideoInputFrameArrived(
>>           no_video = 0;
>>       }
>> 
>> +        // Handle Timecode (if requested)
>> +        if (ctx->tc_format && !(av_dict_get(ctx->video_st->metadata,
>> "timecode", NULL, 0)) && !no_video) {
>> +            IDeckLinkTimecode *timecode;
>> +            if (videoFrame->GetTimecode(ctx->tc_format, &timecode) ==
>> S_OK) {
>> +                DECKLINK_STR timecodeString = NULL;
>> +                timecode->GetString(&timecodeString);
>> +                const char* tc = DECKLINK_STRDUP(timecodeString);
>> +                if (!(av_dict_set(&ctx->video_st->metadata, "timecode",
>> tc, 0)))
> 
> Don't you need AV_DICT_DONT_STRDUP_VAL flag here?
> 
>> +                    av_log(avctx, AV_LOG_ERROR, "Unable to set
>> timecode\n");
>> +                if (timecodeString)
>> +                    DECKLINK_FREE(timecodeString);
>> +                timecode->Release();
>> +            } else {
>> +                av_log(avctx, AV_LOG_ERROR, "Unable to find timecode.\n");
>> +            }
>> +        }
> 
> Maybe it makes sense to put this under the else branch of if (videoFrame->GetFlags() & bmdFrameHasNoInputSource), because if you have no input, you won't have any (valid) timecode...
> 
>> +
>>       pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock,
>> abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base,
>> &initial_video_pts, cctx->copyts);
>>       pkt.dts = pkt.pts;
>> 
>> @@ -939,6 +956,8 @@ av_cold int ff_decklink_read_header(AVFormatContext
>> *avctx)
>>   ctx->teletext_lines = cctx->teletext_lines;
>>   ctx->preroll      = cctx->preroll;
>>   ctx->duplex_mode  = cctx->duplex_mode;
>> +    if (cctx->tc_format > 0 && (unsigned int)cctx->tc_format <
>> FF_ARRAY_ELEMS(decklink_timecode_format_map))
>> +        ctx->tc_format = decklink_timecode_format_map[cctx->tc_format];
>>   if (cctx->video_input > 0 && (unsigned int)cctx->video_input <
>> FF_ARRAY_ELEMS(decklink_video_connection_map))
>>       ctx->video_input = decklink_video_connection_map[cctx->video_input];
>>   if (cctx->audio_input > 0 && (unsigned int)cctx->audio_input <
>> FF_ARRAY_ELEMS(decklink_audio_connection_map))
>> diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
>> index 47018dc681..6ab3819375 100644
>> --- a/libavdevice/decklink_dec_c.c
>> +++ b/libavdevice/decklink_dec_c.c
>> @@ -48,6 +48,15 @@ static const AVOption options[] = {
>>   { "unset",         NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "duplex_mode"},
>>   { "half",          NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "duplex_mode"},
>>   { "full",          NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "duplex_mode"},
>> +    { "timecode_format", "timecode format",           OFFSET(tc_format),
>> AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 7,    DEC, "tc_format"},
>> +    { "none",          NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "tc_format"},
>> +    { "rp188vitc",     NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "tc_format"},
>> +    { "rp188vitc2",    NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "tc_format"},
>> +    { "rp188ltc",      NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 3}, 0, 0,    DEC, "tc_format"},
>> +    { "rp188any",      NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0,    DEC, "tc_format"},
>> +    { "vitc",          NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0,    DEC, "tc_format"},
>> +    { "vitc2",         NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0,    DEC, "tc_format"},
>> +    { "serial",        NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 7}, 0, 0,    DEC, "tc_format"},
>>   { "video_input",  "video input",              OFFSET(video_input),
>>  AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 6,    DEC, "video_input"},
>>   { "unset",         NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "video_input"},
>>   { "sdi",           NULL,                                          0,
>> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "video_input"},
>> --
> 
> Documentation update is missing.
> 
> Regards,
> Marton
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
Dave Rice May 25, 2018, 7:41 p.m. UTC | #8
> On May 25, 2018, at 1:08 PM, Jonathan Morley <jmorley@pixsystem.com> wrote:
> 
>> On May 25, 2018, at 8:32 AM, Marton Balint <cus@passwd.hu <mailto:cus@passwd.hu>> wrote:
>> 
>> On Fri, 25 May 2018, Jonathan Morley wrote:
>> 
>>> I apologize in advance for the formatting of this message. My mail
>>> configuration impeded my efforts to use ‘—send-email’.
>> 
>> Your mail is corrupted by new lines, attach the .patch file if you cannot resolve this.
> 
> Will do! Sorry about that. The mail server’s auth setup kept me from using ‘—send-email’ directly. I will send future patches as attachments.

Here is a copy of my adjustments for the patch so that I could apply it for testing. https://gist.github.com/dericed/af69d60a99ad235b17722a64ea9413ba <https://gist.github.com/dericed/af69d60a99ad235b17722a64ea9413ba>
>>> This commit did pass 'make fate’ though the use of these changes requires
>>> decklink hardware so I did not add any new fate tests. By default the new
>>> optional behavior is skipped for old behavior.
>>> 
>>> ---
>>> libavdevice/decklink_common.cpp | 30 -----------------------------
>>> libavdevice/decklink_common.h   | 42 ++++++++++++++++++++++++++++++
>>> +++++++++++
>> 
>> Why is this huge chunk of function movement needed? If there is a good reason to do that, then split it into a separate patch, if there is not, then just get rid of it.
> 
> The move here was so that I could make use of the cross platform safe DECKLINK string methods. I was only able to test with linux and build on mac, but I wanted to do my best to make a contribution that _could_ work on all platforms. I can break this into two patches if you prefer. 
> 
>>> libavdevice/decklink_common_c.h |  1 +
>>> libavdevice/decklink_dec.cpp    | 19 +++++++++++++++++++
>>> libavdevice/decklink_dec_c.c    |  9 +++++++++
>>> 5 files changed, 71 insertions(+), 30 deletions(-)
>>> 
>>> diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.
>>> cpp
>>> index d8cced7c74..aab9d85b94 100644
>>> --- a/libavdevice/decklink_common.cpp
>>> +++ b/libavdevice/decklink_common.cpp
>>> @@ -77,36 +77,6 @@ static IDeckLinkIterator
>>> *decklink_create_iterator(AVFormatContext
>>> *avctx)
>>>  return iter;
>>> }
>>> 
>>> -#ifdef _WIN32
>>> -static char *dup_wchar_to_utf8(wchar_t *w)
>>> -{
>>> -    char *s = NULL;
>>> -    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
>>> -    s = (char *) av_malloc(l);
>>> -    if (s)
>>> -        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
>>> -    return s;
>>> -}
>>> -#define DECKLINK_STR    OLECHAR *
>>> -#define DECKLINK_STRDUP dup_wchar_to_utf8
>>> -#define DECKLINK_FREE(s) SysFreeString(s)
>>> -#elif defined(__APPLE__)
>>> -static char *dup_cfstring_to_utf8(CFStringRef w)
>>> -{
>>> -    char s[256];
>>> -    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
>>> -    return av_strdup(s);
>>> -}
>>> -#define DECKLINK_STR    const __CFString *
>>> -#define DECKLINK_STRDUP dup_cfstring_to_utf8
>>> -#define DECKLINK_FREE(s) CFRelease(s)
>>> -#else
>>> -#define DECKLINK_STR    const char *
>>> -#define DECKLINK_STRDUP av_strdup
>>> -/* free() is needed for a string returned by the DeckLink SDL. */
>>> -#define DECKLINK_FREE(s) free((void *) s)
>>> -#endif
>>> -
>>> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
>>> **displayName)
>>> {
>>>  DECKLINK_STR tmpDisplayName;
>>> diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
>>> index 57ee7d1d68..8c5f8e9f06 100644
>>> --- a/libavdevice/decklink_common.h
>>> +++ b/libavdevice/decklink_common.h
>>> @@ -34,6 +34,36 @@
>>> #define DECKLINK_BOOL bool
>>> #endif
>>> 
>>> +#ifdef _WIN32
>>> +static char *dup_wchar_to_utf8(wchar_t *w)
>>> +{
>>> +    char *s = NULL;
>>> +    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
>>> +    s = (char *) av_malloc(l);
>>> +    if (s)
>>> +        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
>>> +    return s;
>>> +}
>>> +#define DECKLINK_STR    OLECHAR *
>>> +#define DECKLINK_STRDUP dup_wchar_to_utf8
>>> +#define DECKLINK_FREE(s) SysFreeString(s)
>>> +#elif defined(__APPLE__)
>>> +static char *dup_cfstring_to_utf8(CFStringRef w)
>>> +{
>>> +    char s[256];
>>> +    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
>>> +    return av_strdup(s);
>>> +}
>>> +#define DECKLINK_STR    const __CFString *
>>> +#define DECKLINK_STRDUP dup_cfstring_to_utf8
>>> +#define DECKLINK_FREE(s) CFRelease(s)
>>> +#else
>>> +#define DECKLINK_STR    const char *
>>> +#define DECKLINK_STRDUP av_strdup
>>> +/* free() is needed for a string returned by the DeckLink SDL. */
>>> +#define DECKLINK_FREE(s) free((void *) s)
>>> +#endif
>>> +
>>> class decklink_output_callback;
>>> class decklink_input_callback;
>>> 
>>> @@ -64,6 +94,7 @@ struct decklink_ctx {
>>>  BMDDisplayMode bmd_mode;
>>>  BMDVideoConnection video_input;
>>>  BMDAudioConnection audio_input;
>>> +    BMDTimecodeFormat tc_format;
>>>  int bmd_width;
>>>  int bmd_height;
>>>  int bmd_field_dominance;
>>> @@ -140,6 +171,17 @@ static const BMDVideoConnection
>>> decklink_video_connection_map[] = {
>>>  bmdVideoConnectionSVideo,
>>> };
>>> 
>>> +static const BMDTimecodeFormat decklink_timecode_format_map[] = {
>>> +    (BMDTimecodeFormat)0,
>>> +    bmdTimecodeRP188VITC1,
>>> +    bmdTimecodeRP188VITC2,
>>> +    bmdTimecodeRP188LTC,
>>> +    bmdTimecodeRP188Any,
>>> +    bmdTimecodeVITC,
>>> +    bmdTimecodeVITCField2,
>>> +    bmdTimecodeSerial,
>>> +};
>>> +
>>> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
>>> **displayName);
>>> int ff_decklink_set_configs(AVFormatContext *avctx, decklink_direction_t
>>> direction);
>>> int ff_decklink_set_format(AVFormatContext *avctx, int width, int height,
>>> int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t
>>> direction = DIRECTION_OUT, int num = 0);
>>> diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_
>>> c.h
>>> index 08e9f9bbd5..32a5d70ee1 100644
>>> --- a/libavdevice/decklink_common_c.h
>>> +++ b/libavdevice/decklink_common_c.h
>>> @@ -50,6 +50,7 @@ struct decklink_cctx {
>>>  DecklinkPtsSource video_pts_source;
>>>  int audio_input;
>>>  int video_input;
>>> +    int tc_format;
>>>  int draw_bars;
>>>  char *format_code;
>>>  int raw_format;
>>> diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
>>> index 510637676c..818235bfa6 100644
>>> --- a/libavdevice/decklink_dec.cpp
>>> +++ b/libavdevice/decklink_dec.cpp
>>> @@ -726,6 +726,23 @@ HRESULT decklink_input_callback::
>>> VideoInputFrameArrived(
>>>          no_video = 0;
>>>      }
>>> 
>>> +        // Handle Timecode (if requested)
>>> +        if (ctx->tc_format && !(av_dict_get(ctx->video_st->metadata,
>>> "timecode", NULL, 0)) && !no_video) {
>>> +            IDeckLinkTimecode *timecode;
>>> +            if (videoFrame->GetTimecode(ctx->tc_format, &timecode) ==
>>> S_OK) {
>>> +                DECKLINK_STR timecodeString = NULL;
>>> +                timecode->GetString(&timecodeString);
>>> +                const char* tc = DECKLINK_STRDUP(timecodeString);
>>> +                if (!(av_dict_set(&ctx->video_st->metadata, "timecode",
>>> tc, 0)))
>> 
>> Don't you need AV_DICT_DONT_STRDUP_VAL flag here?
> 
> Yes. I agree.
> 
>>> +                    av_log(avctx, AV_LOG_ERROR, "Unable to set
>>> timecode\n");
>>> +                if (timecodeString)
>>> +                    DECKLINK_FREE(timecodeString);
>>> +                timecode->Release();
>>> +            } else {
>>> +                av_log(avctx, AV_LOG_ERROR, "Unable to find timecode.\n");
>>> +            }
>>> +        }
>> 
>> Maybe it makes sense to put this under the else branch of if (videoFrame->GetFlags() & bmdFrameHasNoInputSource), because if you have no input, you won't have any (valid) timecode…
> 
> I can move this. The logic still checks for !no_video, but moving it should be more explicit.
> 
> Sadly I no longer have access to the hardware I used when making these changes and cannot test this kind of change. We have moved on to a video-for-linux based solution with AJA hardware. (I am currently adding support for TC to the v4l2 ffmpeg reader).

I tested moving this function up a few lines into the else branch as Marton suggested and it worked well for me. I’m running this on a Mac. The timecode values when recording with this match what I get via Blackmagic Media Express, but the drop frame flag does not match. I’m testing with a vitc timecode source which is non-drop frame but the value shows in ffmpeg as drop frame, 07:09:56;19.

>>> +
>>>      pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock,
>>> abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base,
>>> &initial_video_pts, cctx->copyts);
>>>      pkt.dts = pkt.pts;
>>> 
>>> @@ -939,6 +956,8 @@ av_cold int ff_decklink_read_header(AVFormatContext
>>> *avctx)
>>>  ctx->teletext_lines = cctx->teletext_lines;
>>>  ctx->preroll      = cctx->preroll;
>>>  ctx->duplex_mode  = cctx->duplex_mode;
>>> +    if (cctx->tc_format > 0 && (unsigned int)cctx->tc_format <
>>> FF_ARRAY_ELEMS(decklink_timecode_format_map))
>>> +        ctx->tc_format = decklink_timecode_format_map[cctx->tc_format];
>>>  if (cctx->video_input > 0 && (unsigned int)cctx->video_input <
>>> FF_ARRAY_ELEMS(decklink_video_connection_map))
>>>      ctx->video_input = decklink_video_connection_map[cctx->video_input];
>>>  if (cctx->audio_input > 0 && (unsigned int)cctx->audio_input <
>>> FF_ARRAY_ELEMS(decklink_audio_connection_map))
>>> diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
>>> index 47018dc681..6ab3819375 100644
>>> --- a/libavdevice/decklink_dec_c.c
>>> +++ b/libavdevice/decklink_dec_c.c
>>> @@ -48,6 +48,15 @@ static const AVOption options[] = {
>>>  { "unset",         NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "duplex_mode"},
>>>  { "half",          NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "duplex_mode"},
>>>  { "full",          NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "duplex_mode"},
>>> +    { "timecode_format", "timecode format",           OFFSET(tc_format),
>>> AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 7,    DEC, "tc_format"},
>>> +    { "none",          NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "tc_format"},
>>> +    { "rp188vitc",     NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "tc_format"},
>>> +    { "rp188vitc2",    NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "tc_format"},
>>> +    { "rp188ltc",      NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 3}, 0, 0,    DEC, "tc_format"},
>>> +    { "rp188any",      NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0,    DEC, "tc_format"},
>>> +    { "vitc",          NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0,    DEC, "tc_format"},
>>> +    { "vitc2",         NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0,    DEC, "tc_format"},
>>> +    { "serial",        NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 7}, 0, 0,    DEC, "tc_format"},
>>>  { "video_input",  "video input",              OFFSET(video_input),
>>> AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 6,    DEC, "video_input"},
>>>  { "unset",         NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "video_input"},
>>>  { "sdi",           NULL,                                          0,
>>> AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "video_input"},
>>> --
>> 
>> Documentation update is missing.
> 
> D’oh! Sloppy.

Thanks for this work!
Dave
Jonathan Morley May 25, 2018, 9:15 p.m. UTC | #9
Thank you for trying it out, Dave.

1) Can you please tell me more about how you tested?

2) Did you run a capture command with ffmpeg after patching?

3) What was the target output you we using?

Thanks,
Jon
Dave Rice May 26, 2018, 2:35 a.m. UTC | #10
> On May 25, 2018, at 17:15, Jonathan Morley <jmorley@pixsystem.com> wrote:
> 
> Thank you for trying it out, Dave.
> 
> 1) Can you please tell me more about how you tested?

J30 digibeta deck playing a Betacam SP with SDI to an Ultrastudio 3D with ffmpeg with your patch and configured with decklink. 

> 2) Did you run a capture command with ffmpeg after patching?

Yes. And I should have shared that command in my email. From memory it was something like: ffmpeg -f decklink $input-format-options-for-an-sd-ntsc-input -i “Ultrastudio 3D” -c:v v210 -c:a aac output.mov

> 3) What was the target output you we using?

QuickTime since the -metadata timecode=##### tag works well there.

I can test more on Tuesday. Thanks for this work!

> Thanks,
> Jon
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Jonathan Morley May 26, 2018, 4:04 a.m. UTC | #11
On Fri, May 25, 2018 at 7:36 PM Dave Rice <dave@dericed.com> wrote:

>
>
> > On May 25, 2018, at 17:15, Jonathan Morley <jmorley@pixsystem.com>
> wrote:
> >
> > Thank you for trying it out, Dave.
> >
> > 1) Can you please tell me more about how you tested?
>
> J30 digibeta deck playing a Betacam SP with SDI to an Ultrastudio 3D with
> ffmpeg with your patch and configured with decklink.
>
> > 2) Did you run a capture command with ffmpeg after patching?
>
> Yes. And I should have shared that command in my email. From memory it was
> something like: ffmpeg -f decklink
> $input-format-options-for-an-sd-ntsc-input -i “Ultrastudio 3D” -c:v v210
> -c:a aac output.mov


Do you think you could share with me the contents of
$input-format-options-for-an-sd-ntsc-input?

>
>
> > 3) What was the target output you we using?
>
> QuickTime since the -metadata timecode=##### tag works well there.
>
> I can test more on Tuesday. Thanks for this work!
>
> > Thanks,
> > Jon
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel@ffmpeg.org
> > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Jonathan Morley May 26, 2018, 4:28 a.m. UTC | #12
Also please include the frame rate coming from the ultrastudio. I suspect
there is a mismatch in the works.

On Fri, May 25, 2018 at 7:36 PM Dave Rice <dave@dericed.com> wrote:

>
>
> > On May 25, 2018, at 17:15, Jonathan Morley <jmorley@pixsystem.com>
> wrote:
> >
> > Thank you for trying it out, Dave.
> >
> > 1) Can you please tell me more about how you tested?
>
> J30 digibeta deck playing a Betacam SP with SDI to an Ultrastudio 3D with
> ffmpeg with your patch and configured with decklink.
>
> > 2) Did you run a capture command with ffmpeg after patching?
>
> Yes. And I should have shared that command in my email. From memory it was
> something like: ffmpeg -f decklink
> $input-format-options-for-an-sd-ntsc-input -i “Ultrastudio 3D” -c:v v210
> -c:a aac output.mov
>
> > 3) What was the target output you we using?
>
> QuickTime since the -metadata timecode=##### tag works well there.
>
> I can test more on Tuesday. Thanks for this work!
>
> > Thanks,
> > Jon
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel@ffmpeg.org
> > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Marton Balint May 26, 2018, 7:23 a.m. UTC | #13
On Fri, 25 May 2018, Jonathan Morley wrote:

> Attached are the two patches to address your feedback, Marton. Please advise.
>

Your mail contains no attachments as far as I see.

Regards,
Marton
Jonathan Morley May 26, 2018, 1:55 p.m. UTC | #14
Attaching again from another mail client.

On Sat, May 26, 2018 at 12:23 AM, Marton Balint <cus@passwd.hu> wrote:

>
>
> On Fri, 25 May 2018, Jonathan Morley wrote:
>
> Attached are the two patches to address your feedback, Marton. Please
>> advise.
>>
>>
> Your mail contains no attachments as far as I see.
>
>
> Regards,
> Marton
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Marton Balint May 29, 2018, 8:41 a.m. UTC | #15
On Sat, 26 May 2018, Jonathan Morley wrote:

> Attaching again from another mail client.

Thanks. There is one issue I found:

You are setting &ctx->video_st->metadata from the VideoInputFrameArrived 
callback. That runs in a separate thread from the main thread 
handling read_packet calls, and you can only invalidate 
video_st->metadata in the main thread. So I suggest to store the timecode 
string in a context variable, and do av_dict_set in 
ff_decklink_read_packet after avpacket_queue_get.

Regards,
Marton
Jonathan Morley May 29, 2018, 3:56 p.m. UTC | #16
Thank you Marton, That makes sense to me, but can you please clarify which context is the most appropriate to use?

Thanks,
Jon

> On May 29, 2018, at 1:41 AM, Marton Balint <cus@passwd.hu> wrote:
> 
> 
> 
> On Sat, 26 May 2018, Jonathan Morley wrote:
> 
>> Attaching again from another mail client.
> 
> Thanks. There is one issue I found:
> 
> You are setting &ctx->video_st->metadata from the VideoInputFrameArrived callback. That runs in a separate thread from the main thread handling read_packet calls, and you can only invalidate video_st->metadata in the main thread. So I suggest to store the timecode string in a context variable, and do av_dict_set in ff_decklink_read_packet after avpacket_queue_get.
> 
> Regards,
> Marton
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Marton Balint May 30, 2018, 6:04 p.m. UTC | #17
On Tue, 29 May 2018, Jonathan Morley wrote:

> Thank you Marton, That makes sense to me, but can you please clarify which context is the most appropriate to use?

Just put it in decklink_ctx in the Status section.

Don't forget to free it in ff_decklink_read_close.

Regards,
Marton
Jonathan Morley May 30, 2018, 6:16 p.m. UTC | #18
Thank you. I will add that and get you a new patch for review.

> On May 30, 2018, at 11:04 AM, Marton Balint <cus@passwd.hu> wrote:
> 
> 
> 
> On Tue, 29 May 2018, Jonathan Morley wrote:
> 
>> Thank you Marton, That makes sense to me, but can you please clarify which context is the most appropriate to use?
> 
> Just put it in decklink_ctx in the Status section.
> 
> Don't forget to free it in ff_decklink_read_close.
> 
> Regards,
> Marton
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Jonathan Morley May 31, 2018, 9:49 a.m. UTC | #19
Please take a look at my latest patches.

NOTE: I no longer have the hardware to test this work!

On Wed, May 30, 2018 at 11:04 AM, Marton Balint <cus@passwd.hu> wrote:

>
>
> On Tue, 29 May 2018, Jonathan Morley wrote:
>
> Thank you Marton, That makes sense to me, but can you please clarify which
>> context is the most appropriate to use?
>>
>
> Just put it in decklink_ctx in the Status section.
>
> Don't forget to free it in ff_decklink_read_close.
>
>
> Regards,
> Marton
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Dave Rice May 31, 2018, 2:59 p.m. UTC | #20
> On May 31, 2018, at 5:49 AM, Jonathan Morley <jmorley@pixsystem.com> wrote:
> 
> Please take a look at my latest patches.
> 
> NOTE: I no longer have the hardware to test this work!

I tested these patches with an Ultrastudio 3D.

I find that in some cases it provides the “Unable to set timecode” warning although it does provide the timecode value. Such as:

./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac signs.mov
ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
  built with Apple LLVM version 9.0.0 (clang-900.0.38)
  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
  libavutil      56. 18.102 / 56. 18.102
  libavcodec     58. 19.104 / 58. 19.104
  libavformat    58. 17.100 / 58. 17.100
  libavdevice    58.  4.100 / 58.  4.100
  libavfilter     7. 24.100 /  7. 24.100
  libswscale      5.  2.100 /  5.  2.100
  libswresample   3.  2.100 /  3.  2.100
[decklink @ 0x7f8711802600] Found Decklink mode 720 x 486 with rate 29.97(i)
[decklink @ 0x7f8711802600] Unable to set timecode
Guessed Channel Layout for Input Stream #0.0 : 7.1
Input #0, decklink, from 'UltraStudio 3D':
  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
    Metadata:
      timecode        : 00:59:53;25
Stream mapping:
  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, mov, to 'signs.mov':
  Metadata:
    encoder         : Lavf58.17.100
    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 0.03 fps, 30k tbn, 29.97 tbc
    Metadata:
      timecode        : 00:59:53;25
      encoder         : Lavc58.19.104 v210
    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
    Metadata:
      encoder         : Lavc58.19.104 aac
frame=  407 fps= 30 q=-0.0 Lsize=  371576kB time=00:00:13.54 bitrate=224697.2kbits/s speed=1.01x    
video:370879kB audio:685kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.003177%
[aac @ 0x7f8711805800] Qavg: 30894.625

Another comment is that if I start the recording with ffmpeg before I play through a source I get spammed with timecode errors such as:

./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac notplaying.mov
ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
  built with Apple LLVM version 9.0.0 (clang-900.0.38)
  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
  libavutil      56. 18.102 / 56. 18.102
  libavcodec     58. 19.104 / 58. 19.104
  libavformat    58. 17.100 / 58. 17.100
  libavdevice    58.  4.100 / 58.  4.100
  libavfilter     7. 24.100 /  7. 24.100
  libswscale      5.  2.100 /  5.  2.100
  libswresample   3.  2.100 /  3.  2.100
[decklink @ 0x7fe313803000] Found Decklink mode 720 x 486 with rate 29.97(i)
[decklink @ 0x7fe313803000] Unable to find timecode.
    Last message repeated 5 times
Guessed Channel Layout for Input Stream #0.0 : 7.1
Input #0, decklink, from 'UltraStudio 3D':
  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
Stream mapping:
  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, mov, to 'notplaying.mov':
  Metadata:
    encoder         : Lavf58.17.100
    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
    Metadata:
      encoder         : Lavc58.19.104 v210
    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
    Metadata:
      encoder         : Lavc58.19.104 aac
[decklink @ 0x7fe313803000] Unable to find timecode.
    Last message repeated 14 times
[decklink @ 0x7fe313803000] Unable to find timecode.0:00.66 bitrate=210543.0kbits/s speed=1.33x    
    Last message repeated 14 times
[decklink @ 0x7fe313803000] Unable to find timecode.0:01.16 bitrate=217281.3kbits/s speed=1.17x    
    Last message repeated 14 times
[decklink @ 0x7fe313803000] Unable to find timecode.0:01.66 bitrate=218719.7kbits/s speed=1.11x    
    Last message repeated 14 times
[decklink @ 0x7fe313803000] Unable to find timecode.0:02.16 bitrate=219494.2kbits/s speed=1.08x    
    Last message repeated 14 times
[decklink @ 0x7fe313803000] Unable to find timecode.0:02.66 bitrate=220763.9kbits/s speed=1.07x    
    Last message repeated 14 times
[decklink @ 0x7fe313803000] Unable to find timecode.0:03.16 bitrate=220971.1kbits/s speed=1.06x    
    Last message repeated 14 times
[decklink @ 0x7fe313803000] Unable to find timecode.0:03.67 bitrate=221693.2kbits/s speed=1.05x    
    Last message repeated 14 times
[decklink @ 0x7fe313803000] Unable to find timecode.0:04.17 bitrate=223247.5kbits/s speed=1.04x  

Until I hit the play button on my source.

I tested the same videotape sources with Media Express and ffmpeg with this patch and the initial timecode values are aligned to the same frames accurately, but with 4 random videotapes I’ve tried, all the Media Express captures are Non-Drop Frame and all the ffmpeg captures are Drop Frame, so one has to be wrong. I’ll try to find a source that can provide a known df and ndf signal to determine which is correct.

Thanks for the update,
Dave Rice
Jonathan Morley May 31, 2018, 3:41 p.m. UTC | #21
Thank you very much, Dave. I am really curious about the df vs ndf since the Blackmagic SDK call I am making doesn’t have any arguments for specifying that kind of distinction. It simply returns what it finds in the SDI stream. And when I skimmed the movenc timecode handling it doesn’t seem to make any assumptions or changes either.

Please keep me posted. Meanwhile I will look into what could be causing all the error chatter.

Thanks,
Jon

> On May 31, 2018, at 7:59 AM, Dave Rice <dave@dericed.com> wrote:
> 
> 
>> On May 31, 2018, at 5:49 AM, Jonathan Morley <jmorley@pixsystem.com> wrote:
>> 
>> Please take a look at my latest patches.
>> 
>> NOTE: I no longer have the hardware to test this work!
> 
> I tested these patches with an Ultrastudio 3D.
> 
> I find that in some cases it provides the “Unable to set timecode” warning although it does provide the timecode value. Such as:
> 
> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac signs.mov
> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>  built with Apple LLVM version 9.0.0 (clang-900.0.38)
>  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>  libavutil      56. 18.102 / 56. 18.102
>  libavcodec     58. 19.104 / 58. 19.104
>  libavformat    58. 17.100 / 58. 17.100
>  libavdevice    58.  4.100 / 58.  4.100
>  libavfilter     7. 24.100 /  7. 24.100
>  libswscale      5.  2.100 /  5.  2.100
>  libswresample   3.  2.100 /  3.  2.100
> [decklink @ 0x7f8711802600] Found Decklink mode 720 x 486 with rate 29.97(i)
> [decklink @ 0x7f8711802600] Unable to set timecode
> Guessed Channel Layout for Input Stream #0.0 : 7.1
> Input #0, decklink, from 'UltraStudio 3D':
>  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>    Metadata:
>      timecode        : 00:59:53;25
> Stream mapping:
>  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
> Press [q] to stop, [?] for help
> Output #0, mov, to 'signs.mov':
>  Metadata:
>    encoder         : Lavf58.17.100
>    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 0.03 fps, 30k tbn, 29.97 tbc
>    Metadata:
>      timecode        : 00:59:53;25
>      encoder         : Lavc58.19.104 v210
>    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>    Metadata:
>      encoder         : Lavc58.19.104 aac
> frame=  407 fps= 30 q=-0.0 Lsize=  371576kB time=00:00:13.54 bitrate=224697.2kbits/s speed=1.01x    
> video:370879kB audio:685kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.003177%
> [aac @ 0x7f8711805800] Qavg: 30894.625
> 
> Another comment is that if I start the recording with ffmpeg before I play through a source I get spammed with timecode errors such as:
> 
> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac notplaying.mov
> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>  built with Apple LLVM version 9.0.0 (clang-900.0.38)
>  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>  libavutil      56. 18.102 / 56. 18.102
>  libavcodec     58. 19.104 / 58. 19.104
>  libavformat    58. 17.100 / 58. 17.100
>  libavdevice    58.  4.100 / 58.  4.100
>  libavfilter     7. 24.100 /  7. 24.100
>  libswscale      5.  2.100 /  5.  2.100
>  libswresample   3.  2.100 /  3.  2.100
> [decklink @ 0x7fe313803000] Found Decklink mode 720 x 486 with rate 29.97(i)
> [decklink @ 0x7fe313803000] Unable to find timecode.
>    Last message repeated 5 times
> Guessed Channel Layout for Input Stream #0.0 : 7.1
> Input #0, decklink, from 'UltraStudio 3D':
>  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
> Stream mapping:
>  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
> Press [q] to stop, [?] for help
> Output #0, mov, to 'notplaying.mov':
>  Metadata:
>    encoder         : Lavf58.17.100
>    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
>    Metadata:
>      encoder         : Lavc58.19.104 v210
>    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>    Metadata:
>      encoder         : Lavc58.19.104 aac
> [decklink @ 0x7fe313803000] Unable to find timecode.
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:00.66 bitrate=210543.0kbits/s speed=1.33x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.16 bitrate=217281.3kbits/s speed=1.17x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.66 bitrate=218719.7kbits/s speed=1.11x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.16 bitrate=219494.2kbits/s speed=1.08x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.66 bitrate=220763.9kbits/s speed=1.07x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.16 bitrate=220971.1kbits/s speed=1.06x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.67 bitrate=221693.2kbits/s speed=1.05x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:04.17 bitrate=223247.5kbits/s speed=1.04x  
> 
> Until I hit the play button on my source.
> 
> I tested the same videotape sources with Media Express and ffmpeg with this patch and the initial timecode values are aligned to the same frames accurately, but with 4 random videotapes I’ve tried, all the Media Express captures are Non-Drop Frame and all the ffmpeg captures are Drop Frame, so one has to be wrong. I’ll try to find a source that can provide a known df and ndf signal to determine which is correct.
> 
> Thanks for the update,
> Dave Rice
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Jonathan Morley May 31, 2018, 4:32 p.m. UTC | #22
Hi Dave,

I took a closer look at these messages. I can see why the “Unable to find timecode” messages are repeated. That is sort of correctly reporting that the current video stream does not have a valid timecode, however reporting it as an error seems unnecessary. How would changing it to a debug message sound?

As for the “Unable to set timecode” I am still not sure how that could happen unless the way I am testing for the uninitialized ctx->first_tc is inconsistent. I will have to hear back from Marton I believe.

Thanks,
Jon

> On May 31, 2018, at 7:59 AM, Dave Rice <dave@dericed.com> wrote:
> 
> 
>> On May 31, 2018, at 5:49 AM, Jonathan Morley <jmorley@pixsystem.com> wrote:
>> 
>> Please take a look at my latest patches.
>> 
>> NOTE: I no longer have the hardware to test this work!
> 
> I tested these patches with an Ultrastudio 3D.
> 
> I find that in some cases it provides the “Unable to set timecode” warning although it does provide the timecode value. Such as:
> 
> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac signs.mov
> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>  built with Apple LLVM version 9.0.0 (clang-900.0.38)
>  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>  libavutil      56. 18.102 / 56. 18.102
>  libavcodec     58. 19.104 / 58. 19.104
>  libavformat    58. 17.100 / 58. 17.100
>  libavdevice    58.  4.100 / 58.  4.100
>  libavfilter     7. 24.100 /  7. 24.100
>  libswscale      5.  2.100 /  5.  2.100
>  libswresample   3.  2.100 /  3.  2.100
> [decklink @ 0x7f8711802600] Found Decklink mode 720 x 486 with rate 29.97(i)
> [decklink @ 0x7f8711802600] Unable to set timecode
> Guessed Channel Layout for Input Stream #0.0 : 7.1
> Input #0, decklink, from 'UltraStudio 3D':
>  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>    Metadata:
>      timecode        : 00:59:53;25
> Stream mapping:
>  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
> Press [q] to stop, [?] for help
> Output #0, mov, to 'signs.mov':
>  Metadata:
>    encoder         : Lavf58.17.100
>    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 0.03 fps, 30k tbn, 29.97 tbc
>    Metadata:
>      timecode        : 00:59:53;25
>      encoder         : Lavc58.19.104 v210
>    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>    Metadata:
>      encoder         : Lavc58.19.104 aac
> frame=  407 fps= 30 q=-0.0 Lsize=  371576kB time=00:00:13.54 bitrate=224697.2kbits/s speed=1.01x    
> video:370879kB audio:685kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.003177%
> [aac @ 0x7f8711805800] Qavg: 30894.625
> 
> Another comment is that if I start the recording with ffmpeg before I play through a source I get spammed with timecode errors such as:
> 
> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac notplaying.mov
> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>  built with Apple LLVM version 9.0.0 (clang-900.0.38)
>  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>  libavutil      56. 18.102 / 56. 18.102
>  libavcodec     58. 19.104 / 58. 19.104
>  libavformat    58. 17.100 / 58. 17.100
>  libavdevice    58.  4.100 / 58.  4.100
>  libavfilter     7. 24.100 /  7. 24.100
>  libswscale      5.  2.100 /  5.  2.100
>  libswresample   3.  2.100 /  3.  2.100
> [decklink @ 0x7fe313803000] Found Decklink mode 720 x 486 with rate 29.97(i)
> [decklink @ 0x7fe313803000] Unable to find timecode.
>    Last message repeated 5 times
> Guessed Channel Layout for Input Stream #0.0 : 7.1
> Input #0, decklink, from 'UltraStudio 3D':
>  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
> Stream mapping:
>  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
> Press [q] to stop, [?] for help
> Output #0, mov, to 'notplaying.mov':
>  Metadata:
>    encoder         : Lavf58.17.100
>    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
>    Metadata:
>      encoder         : Lavc58.19.104 v210
>    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>    Metadata:
>      encoder         : Lavc58.19.104 aac
> [decklink @ 0x7fe313803000] Unable to find timecode.
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:00.66 bitrate=210543.0kbits/s speed=1.33x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.16 bitrate=217281.3kbits/s speed=1.17x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.66 bitrate=218719.7kbits/s speed=1.11x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.16 bitrate=219494.2kbits/s speed=1.08x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.66 bitrate=220763.9kbits/s speed=1.07x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.16 bitrate=220971.1kbits/s speed=1.06x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.67 bitrate=221693.2kbits/s speed=1.05x    
>    Last message repeated 14 times
> [decklink @ 0x7fe313803000] Unable to find timecode.0:04.17 bitrate=223247.5kbits/s speed=1.04x  
> 
> Until I hit the play button on my source.
> 
> I tested the same videotape sources with Media Express and ffmpeg with this patch and the initial timecode values are aligned to the same frames accurately, but with 4 random videotapes I’ve tried, all the Media Express captures are Non-Drop Frame and all the ffmpeg captures are Drop Frame, so one has to be wrong. I’ll try to find a source that can provide a known df and ndf signal to determine which is correct.
> 
> Thanks for the update,
> Dave Rice
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Dave Rice May 31, 2018, 7:39 p.m. UTC | #23
Hi Jonathan,

> On May 31, 2018, at 11:41 AM, Jonathan Morley <jmorley@pixsystem.com> wrote:
> 
> Thank you very much, Dave. I am really curious about the df vs ndf since the Blackmagic SDK call I am making doesn’t have any arguments for specifying that kind of distinction. It simply returns what it finds in the SDI stream.

I know have a tape known to be NDF and a tape known to be DF. The messages I sent before were from DF tapes. When I tried a NDF tape, I get the "Unable to find timecode” warning repeatedly and no timecode on the output file.

./ffmpeg -timecode_format vitc2 -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac devlin5.mov
ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
  built with Apple LLVM version 9.0.0 (clang-900.0.38)
  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
  libavutil      56. 18.102 / 56. 18.102
  libavcodec     58. 19.104 / 58. 19.104
  libavformat    58. 17.100 / 58. 17.100
  libavdevice    58.  4.100 / 58.  4.100
  libavfilter     7. 24.100 /  7. 24.100
  libswscale      5.  2.100 /  5.  2.100
  libswresample   3.  2.100 /  3.  2.100
[decklink @ 0x7f9f66800000] Found Decklink mode 720 x 486 with rate 29.97(i)
[decklink @ 0x7f9f66800000] Unable to find timecode.
    Last message repeated 5 times
Guessed Channel Layout for Input Stream #0.0 : 7.1
Input #0, decklink, from 'UltraStudio 3D':
  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
Stream mapping:
  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, mov, to 'devlin5.mov':
  Metadata:
    encoder         : Lavf58.17.100
    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
    Metadata:
      encoder         : Lavc58.19.104 v210
    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
    Metadata:
      encoder         : Lavc58.19.104 aac
[decklink @ 0x7f9f66800000] Unable to find timecode.
    Last message repeated 15 times
[decklink @ 0x7f9f66800000] Unable to find timecode.0:00.70 bitrate=200517.8kbits/s speed= 1.4x    
    Last message repeated 14 times
[decklink @ 0x7f9f66800000] Unable to find timecode.0:01.20 bitrate=211246.0kbits/s speed= 1.2x    
    Last message repeated 14 times
[decklink @ 0x7f9f66800000] Unable to find timecode.0:01.70 bitrate=214431.3kbits/s speed=1.13x    
    Last message repeated 14 times
[decklink @ 0x7f9f66800000] Unable to find timecode.0:02.20 bitrate=217121.0kbits/s speed= 1.1x    
    Last message repeated 14 times
[decklink @ 0x7f9f66800000] Unable to find timecode.0:02.70 bitrate=221142.3kbits/s speed=1.07x    
    Last message repeated 14 times
[decklink @ 0x7f9f66800000] Unable to find timecode.0:03.20 bitrate=221288.2kbits/s speed=1.06x    

So when inputing DF this appears to work while Media Express gets it wrong by writing the timecode with a NDF flag.
However when inputing NDF no timecode is communicated.

I ran this to check if somehow I was called the wrong timecode 

for i in rp188vitc rp188vitc2 rp188ltc rp188any vitc vitc2 serial ; do echo -n "${i}: " ; ./ffprobe -v quiet -timecode_format "$i" -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -select_streams v -show_entries stream_tags=timecode -of default=nw=1:nk=1 ; echo ; done

rp188vitc: 
rp188vitc2: 
rp188ltc: 
rp188any: 
vitc: 
vitc2: 
serial: 

I may try to find another NDF tape to make sure this isn’t a fluke.

> And when I skimmed the movenc timecode handling it doesn’t seem to make any assumptions or changes either.

I’ve replicated it with Matroska which simply moves the timecode into metadata as a string.

> Please keep me posted. Meanwhile I will look into what could be causing all the error chatter.

Thanks!

> Thanks,
> Jon
> 
>> On May 31, 2018, at 7:59 AM, Dave Rice <dave@dericed.com> wrote:
>> 
>> 
>>> On May 31, 2018, at 5:49 AM, Jonathan Morley <jmorley@pixsystem.com> wrote:
>>> 
>>> Please take a look at my latest patches.
>>> 
>>> NOTE: I no longer have the hardware to test this work!
>> 
>> I tested these patches with an Ultrastudio 3D.
>> 
>> I find that in some cases it provides the “Unable to set timecode” warning although it does provide the timecode value. Such as:
>> 
>> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac signs.mov
>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>> libavutil      56. 18.102 / 56. 18.102
>> libavcodec     58. 19.104 / 58. 19.104
>> libavformat    58. 17.100 / 58. 17.100
>> libavdevice    58.  4.100 / 58.  4.100
>> libavfilter     7. 24.100 /  7. 24.100
>> libswscale      5.  2.100 /  5.  2.100
>> libswresample   3.  2.100 /  3.  2.100
>> [decklink @ 0x7f8711802600] Found Decklink mode 720 x 486 with rate 29.97(i)
>> [decklink @ 0x7f8711802600] Unable to set timecode
>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>> Input #0, decklink, from 'UltraStudio 3D':
>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>   Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>   Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>>   Metadata:
>>     timecode        : 00:59:53;25
>> Stream mapping:
>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>> Press [q] to stop, [?] for help
>> Output #0, mov, to 'signs.mov':
>> Metadata:
>>   encoder         : Lavf58.17.100
>>   Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 0.03 fps, 30k tbn, 29.97 tbc
>>   Metadata:
>>     timecode        : 00:59:53;25
>>     encoder         : Lavc58.19.104 v210
>>   Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>   Metadata:
>>     encoder         : Lavc58.19.104 aac
>> frame=  407 fps= 30 q=-0.0 Lsize=  371576kB time=00:00:13.54 bitrate=224697.2kbits/s speed=1.01x    
>> video:370879kB audio:685kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.003177%
>> [aac @ 0x7f8711805800] Qavg: 30894.625
>> 
>> Another comment is that if I start the recording with ffmpeg before I play through a source I get spammed with timecode errors such as:
>> 
>> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac notplaying.mov
>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>> libavutil      56. 18.102 / 56. 18.102
>> libavcodec     58. 19.104 / 58. 19.104
>> libavformat    58. 17.100 / 58. 17.100
>> libavdevice    58.  4.100 / 58.  4.100
>> libavfilter     7. 24.100 /  7. 24.100
>> libswscale      5.  2.100 /  5.  2.100
>> libswresample   3.  2.100 /  3.  2.100
>> [decklink @ 0x7fe313803000] Found Decklink mode 720 x 486 with rate 29.97(i)
>> [decklink @ 0x7fe313803000] Unable to find timecode.
>>   Last message repeated 5 times
>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>> Input #0, decklink, from 'UltraStudio 3D':
>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>   Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>   Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>> Stream mapping:
>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>> Press [q] to stop, [?] for help
>> Output #0, mov, to 'notplaying.mov':
>> Metadata:
>>   encoder         : Lavf58.17.100
>>   Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
>>   Metadata:
>>     encoder         : Lavc58.19.104 v210
>>   Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>   Metadata:
>>     encoder         : Lavc58.19.104 aac
>> [decklink @ 0x7fe313803000] Unable to find timecode.
>>   Last message repeated 14 times
>> [decklink @ 0x7fe313803000] Unable to find timecode.0:00.66 bitrate=210543.0kbits/s speed=1.33x    
>>   Last message repeated 14 times
>> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.16 bitrate=217281.3kbits/s speed=1.17x    
>>   Last message repeated 14 times
>> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.66 bitrate=218719.7kbits/s speed=1.11x    
>>   Last message repeated 14 times
>> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.16 bitrate=219494.2kbits/s speed=1.08x    
>>   Last message repeated 14 times
>> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.66 bitrate=220763.9kbits/s speed=1.07x    
>>   Last message repeated 14 times
>> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.16 bitrate=220971.1kbits/s speed=1.06x    
>>   Last message repeated 14 times
>> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.67 bitrate=221693.2kbits/s speed=1.05x    
>>   Last message repeated 14 times
>> [decklink @ 0x7fe313803000] Unable to find timecode.0:04.17 bitrate=223247.5kbits/s speed=1.04x  
>> 
>> Until I hit the play button on my source.
>> 
>> I tested the same videotape sources with Media Express and ffmpeg with this patch and the initial timecode values are aligned to the same frames accurately, but with 4 random videotapes I’ve tried, all the Media Express captures are Non-Drop Frame and all the ffmpeg captures are Drop Frame, so one has to be wrong. I’ll try to find a source that can provide a known df and ndf signal to determine which is correct.
>> 
>> Thanks for the update,
>> Dave Rice
>> 
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Jonathan Morley May 31, 2018, 7:56 p.m. UTC | #24
Well that is helpful information if not a bit disappointing. Perhaps if I use the SDK calls to get the individual timecode components _and_ check the drop frame flag I can reassemble what the GetString() method on the IDeckLinkTimecode class is supposed to provide.

I will add that to the next patch, but it might be a minute before I get to it. Thank you again for taking a look.

I guess we got really lucky in our use case.

Thanks,
Jon

> On May 31, 2018, at 12:39 PM, Dave Rice <dave@dericed.com> wrote:
> 
> Hi Jonathan,
> 
>> On May 31, 2018, at 11:41 AM, Jonathan Morley <jmorley@pixsystem.com <mailto:jmorley@pixsystem.com>> wrote:
>> 
>> Thank you very much, Dave. I am really curious about the df vs ndf since the Blackmagic SDK call I am making doesn’t have any arguments for specifying that kind of distinction. It simply returns what it finds in the SDI stream.
> 
> I know have a tape known to be NDF and a tape known to be DF. The messages I sent before were from DF tapes. When I tried a NDF tape, I get the "Unable to find timecode” warning repeatedly and no timecode on the output file.
> 
> ./ffmpeg -timecode_format vitc2 -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac devlin5.mov
> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>  built with Apple LLVM version 9.0.0 (clang-900.0.38)
>  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>  libavutil      56. 18.102 / 56. 18.102
>  libavcodec     58. 19.104 / 58. 19.104
>  libavformat    58. 17.100 / 58. 17.100
>  libavdevice    58.  4.100 / 58.  4.100
>  libavfilter     7. 24.100 /  7. 24.100
>  libswscale      5.  2.100 /  5.  2.100
>  libswresample   3.  2.100 /  3.  2.100
> [decklink @ 0x7f9f66800000] Found Decklink mode 720 x 486 with rate 29.97(i)
> [decklink @ 0x7f9f66800000] Unable to find timecode.
>    Last message repeated 5 times
> Guessed Channel Layout for Input Stream #0.0 : 7.1
> Input #0, decklink, from 'UltraStudio 3D':
>  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
> Stream mapping:
>  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
> Press [q] to stop, [?] for help
> Output #0, mov, to 'devlin5.mov':
>  Metadata:
>    encoder         : Lavf58.17.100
>    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
>    Metadata:
>      encoder         : Lavc58.19.104 v210
>    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>    Metadata:
>      encoder         : Lavc58.19.104 aac
> [decklink @ 0x7f9f66800000] Unable to find timecode.
>    Last message repeated 15 times
> [decklink @ 0x7f9f66800000] Unable to find timecode.0:00.70 bitrate=200517.8kbits/s speed= 1.4x    
>    Last message repeated 14 times
> [decklink @ 0x7f9f66800000] Unable to find timecode.0:01.20 bitrate=211246.0kbits/s speed= 1.2x    
>    Last message repeated 14 times
> [decklink @ 0x7f9f66800000] Unable to find timecode.0:01.70 bitrate=214431.3kbits/s speed=1.13x    
>    Last message repeated 14 times
> [decklink @ 0x7f9f66800000] Unable to find timecode.0:02.20 bitrate=217121.0kbits/s speed= 1.1x    
>    Last message repeated 14 times
> [decklink @ 0x7f9f66800000] Unable to find timecode.0:02.70 bitrate=221142.3kbits/s speed=1.07x    
>    Last message repeated 14 times
> [decklink @ 0x7f9f66800000] Unable to find timecode.0:03.20 bitrate=221288.2kbits/s speed=1.06x    
> 
> So when inputing DF this appears to work while Media Express gets it wrong by writing the timecode with a NDF flag.
> However when inputing NDF no timecode is communicated.
> 
> I ran this to check if somehow I was called the wrong timecode 
> 
> for i in rp188vitc rp188vitc2 rp188ltc rp188any vitc vitc2 serial ; do echo -n "${i}: " ; ./ffprobe -v quiet -timecode_format "$i" -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -select_streams v -show_entries stream_tags=timecode -of default=nw=1:nk=1 ; echo ; done
> 
> rp188vitc: 
> rp188vitc2: 
> rp188ltc: 
> rp188any: 
> vitc: 
> vitc2: 
> serial: 
> 
> I may try to find another NDF tape to make sure this isn’t a fluke.
> 
>> And when I skimmed the movenc timecode handling it doesn’t seem to make any assumptions or changes either.
> 
> I’ve replicated it with Matroska which simply moves the timecode into metadata as a string.
> 
>> Please keep me posted. Meanwhile I will look into what could be causing all the error chatter.
> 
> Thanks!
> 
>> Thanks,
>> Jon
>> 
>>> On May 31, 2018, at 7:59 AM, Dave Rice <dave@dericed.com> wrote:
>>> 
>>> 
>>>> On May 31, 2018, at 5:49 AM, Jonathan Morley <jmorley@pixsystem.com> wrote:
>>>> 
>>>> Please take a look at my latest patches.
>>>> 
>>>> NOTE: I no longer have the hardware to test this work!
>>> 
>>> I tested these patches with an Ultrastudio 3D.
>>> 
>>> I find that in some cases it provides the “Unable to set timecode” warning although it does provide the timecode value. Such as:
>>> 
>>> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac signs.mov
>>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>>> libavutil      56. 18.102 / 56. 18.102
>>> libavcodec     58. 19.104 / 58. 19.104
>>> libavformat    58. 17.100 / 58. 17.100
>>> libavdevice    58.  4.100 / 58.  4.100
>>> libavfilter     7. 24.100 /  7. 24.100
>>> libswscale      5.  2.100 /  5.  2.100
>>> libswresample   3.  2.100 /  3.  2.100
>>> [decklink @ 0x7f8711802600] Found Decklink mode 720 x 486 with rate 29.97(i)
>>> [decklink @ 0x7f8711802600] Unable to set timecode
>>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>>> Input #0, decklink, from 'UltraStudio 3D':
>>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>>  Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>>  Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>>>  Metadata:
>>>    timecode        : 00:59:53;25
>>> Stream mapping:
>>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>>> Press [q] to stop, [?] for help
>>> Output #0, mov, to 'signs.mov':
>>> Metadata:
>>>  encoder         : Lavf58.17.100
>>>  Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 0.03 fps, 30k tbn, 29.97 tbc
>>>  Metadata:
>>>    timecode        : 00:59:53;25
>>>    encoder         : Lavc58.19.104 v210
>>>  Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>>  Metadata:
>>>    encoder         : Lavc58.19.104 aac
>>> frame=  407 fps= 30 q=-0.0 Lsize=  371576kB time=00:00:13.54 bitrate=224697.2kbits/s speed=1.01x    
>>> video:370879kB audio:685kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.003177%
>>> [aac @ 0x7f8711805800] Qavg: 30894.625
>>> 
>>> Another comment is that if I start the recording with ffmpeg before I play through a source I get spammed with timecode errors such as:
>>> 
>>> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac notplaying.mov
>>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>>> libavutil      56. 18.102 / 56. 18.102
>>> libavcodec     58. 19.104 / 58. 19.104
>>> libavformat    58. 17.100 / 58. 17.100
>>> libavdevice    58.  4.100 / 58.  4.100
>>> libavfilter     7. 24.100 /  7. 24.100
>>> libswscale      5.  2.100 /  5.  2.100
>>> libswresample   3.  2.100 /  3.  2.100
>>> [decklink @ 0x7fe313803000] Found Decklink mode 720 x 486 with rate 29.97(i)
>>> [decklink @ 0x7fe313803000] Unable to find timecode.
>>>  Last message repeated 5 times
>>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>>> Input #0, decklink, from 'UltraStudio 3D':
>>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>>  Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>>  Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>>> Stream mapping:
>>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>>> Press [q] to stop, [?] for help
>>> Output #0, mov, to 'notplaying.mov':
>>> Metadata:
>>>  encoder         : Lavf58.17.100
>>>  Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
>>>  Metadata:
>>>    encoder         : Lavc58.19.104 v210
>>>  Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>>  Metadata:
>>>    encoder         : Lavc58.19.104 aac
>>> [decklink @ 0x7fe313803000] Unable to find timecode.
>>>  Last message repeated 14 times
>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:00.66 bitrate=210543.0kbits/s speed=1.33x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.16 bitrate=217281.3kbits/s speed=1.17x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.66 bitrate=218719.7kbits/s speed=1.11x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.16 bitrate=219494.2kbits/s speed=1.08x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.66 bitrate=220763.9kbits/s speed=1.07x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.16 bitrate=220971.1kbits/s speed=1.06x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.67 bitrate=221693.2kbits/s speed=1.05x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:04.17 bitrate=223247.5kbits/s speed=1.04x  
>>> 
>>> Until I hit the play button on my source.
>>> 
>>> I tested the same videotape sources with Media Express and ffmpeg with this patch and the initial timecode values are aligned to the same frames accurately, but with 4 random videotapes I’ve tried, all the Media Express captures are Non-Drop Frame and all the ffmpeg captures are Drop Frame, so one has to be wrong. I’ll try to find a source that can provide a known df and ndf signal to determine which is correct.
>>> 
>>> Thanks for the update,
>>> Dave Rice
>>> 
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org
>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>> 
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
Dave Rice May 31, 2018, 8:17 p.m. UTC | #25
Hi Jonathan,

> On May 31, 2018, at 3:56 PM, Jonathan Morley <jmorley@pixsystem.com> wrote:
> 
> Well that is helpful information if not a bit disappointing. Perhaps if I use the SDK calls to get the individual timecode components _and_ check the drop frame flag I can reassemble what the GetString() method on the IDeckLinkTimecode class is supposed to provide.

I tried with another NDF tape and it worked appropriately. So I do have a capture with NDF and another capture with DF timecode as intended. I am still uncertain what’s wrong with the first NDF that I reported before but I’m supposing it’s an issue with that tape rather than your work.

Here’s the output of the capture of the new NDF tape, note that I’m still getting the "Unable to set timecode” even though the timecode is set.

./ffmpeg -timecode_format vitc2 -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac maybendf.mov
ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
  built with Apple LLVM version 9.0.0 (clang-900.0.38)
  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
  libavutil      56. 18.102 / 56. 18.102
  libavcodec     58. 19.104 / 58. 19.104
  libavformat    58. 17.100 / 58. 17.100
  libavdevice    58.  4.100 / 58.  4.100
  libavfilter     7. 24.100 /  7. 24.100
  libswscale      5.  2.100 /  5.  2.100
  libswresample   3.  2.100 /  3.  2.100
[decklink @ 0x7fdd75800a00] Found Decklink mode 720 x 486 with rate 29.97(i)
[decklink @ 0x7fdd75800a00] Unable to set timecode
Guessed Channel Layout for Input Stream #0.0 : 7.1
Input #0, decklink, from 'UltraStudio 3D':
  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
    Metadata:
      timecode        : 03:48:55:26
Stream mapping:
  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, mov, to 'maybendf.mov':
  Metadata:
    encoder         : Lavf58.17.100
    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 0.03 fps, 30k tbn, 29.97 tbc
    Metadata:
      timecode        : 03:48:55:26
      encoder         : Lavc58.19.104 v210
    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
    Metadata:
      encoder         : Lavc58.19.104 aac
frame=   48 fps= 34 q=-0.0 Lsize=   43745kB time=00:00:01.56 bitrate=228505.8kbits/s speed=1.12x    
video:43740kB audio:2kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.007146%
[aac @ 0x7fdd77801e00] Qavg: 65536.000

> I will add that to the next patch, but it might be a minute before I get to it. Thank you again for taking a look.
> 
> I guess we got really lucky in our use case.
> 
> Thanks,
> Jon
> 
>> On May 31, 2018, at 12:39 PM, Dave Rice <dave@dericed.com> wrote:
>> 
>> Hi Jonathan,
>> 
>>> On May 31, 2018, at 11:41 AM, Jonathan Morley <jmorley@pixsystem.com <mailto:jmorley@pixsystem.com>> wrote:
>>> 
>>> Thank you very much, Dave. I am really curious about the df vs ndf since the Blackmagic SDK call I am making doesn’t have any arguments for specifying that kind of distinction. It simply returns what it finds in the SDI stream.
>> 
>> I know have a tape known to be NDF and a tape known to be DF. The messages I sent before were from DF tapes. When I tried a NDF tape, I get the "Unable to find timecode” warning repeatedly and no timecode on the output file.
>> 
>> ./ffmpeg -timecode_format vitc2 -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac devlin5.mov
>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>> libavutil      56. 18.102 / 56. 18.102
>> libavcodec     58. 19.104 / 58. 19.104
>> libavformat    58. 17.100 / 58. 17.100
>> libavdevice    58.  4.100 / 58.  4.100
>> libavfilter     7. 24.100 /  7. 24.100
>> libswscale      5.  2.100 /  5.  2.100
>> libswresample   3.  2.100 /  3.  2.100
>> [decklink @ 0x7f9f66800000] Found Decklink mode 720 x 486 with rate 29.97(i)
>> [decklink @ 0x7f9f66800000] Unable to find timecode.
>>   Last message repeated 5 times
>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>> Input #0, decklink, from 'UltraStudio 3D':
>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>   Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>   Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>> Stream mapping:
>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>> Press [q] to stop, [?] for help
>> Output #0, mov, to 'devlin5.mov':
>> Metadata:
>>   encoder         : Lavf58.17.100
>>   Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
>>   Metadata:
>>     encoder         : Lavc58.19.104 v210
>>   Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>   Metadata:
>>     encoder         : Lavc58.19.104 aac
>> [decklink @ 0x7f9f66800000] Unable to find timecode.
>>   Last message repeated 15 times
>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:00.70 bitrate=200517.8kbits/s speed= 1.4x    
>>   Last message repeated 14 times
>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:01.20 bitrate=211246.0kbits/s speed= 1.2x    
>>   Last message repeated 14 times
>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:01.70 bitrate=214431.3kbits/s speed=1.13x    
>>   Last message repeated 14 times
>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:02.20 bitrate=217121.0kbits/s speed= 1.1x    
>>   Last message repeated 14 times
>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:02.70 bitrate=221142.3kbits/s speed=1.07x    
>>   Last message repeated 14 times
>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:03.20 bitrate=221288.2kbits/s speed=1.06x    
>> 
>> So when inputing DF this appears to work while Media Express gets it wrong by writing the timecode with a NDF flag.
>> However when inputing NDF no timecode is communicated.
>> 
>> I ran this to check if somehow I was called the wrong timecode 
>> 
>> for i in rp188vitc rp188vitc2 rp188ltc rp188any vitc vitc2 serial ; do echo -n "${i}: " ; ./ffprobe -v quiet -timecode_format "$i" -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -select_streams v -show_entries stream_tags=timecode -of default=nw=1:nk=1 ; echo ; done
>> 
>> rp188vitc: 
>> rp188vitc2: 
>> rp188ltc: 
>> rp188any: 
>> vitc: 
>> vitc2: 
>> serial: 
>> 
>> I may try to find another NDF tape to make sure this isn’t a fluke.
>> 
>>> And when I skimmed the movenc timecode handling it doesn’t seem to make any assumptions or changes either.
>> 
>> I’ve replicated it with Matroska which simply moves the timecode into metadata as a string.
>> 
>>> Please keep me posted. Meanwhile I will look into what could be causing all the error chatter.
>> 
>> Thanks!
>> 
>>> Thanks,
>>> Jon
>>> 
>>>> On May 31, 2018, at 7:59 AM, Dave Rice <dave@dericed.com> wrote:
>>>> 
>>>> 
>>>>> On May 31, 2018, at 5:49 AM, Jonathan Morley <jmorley@pixsystem.com> wrote:
>>>>> 
>>>>> Please take a look at my latest patches.
>>>>> 
>>>>> NOTE: I no longer have the hardware to test this work!
>>>> 
>>>> I tested these patches with an Ultrastudio 3D.
>>>> 
>>>> I find that in some cases it provides the “Unable to set timecode” warning although it does provide the timecode value. Such as:
>>>> 
>>>> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac signs.mov
>>>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>>>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>>>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>>>> libavutil      56. 18.102 / 56. 18.102
>>>> libavcodec     58. 19.104 / 58. 19.104
>>>> libavformat    58. 17.100 / 58. 17.100
>>>> libavdevice    58.  4.100 / 58.  4.100
>>>> libavfilter     7. 24.100 /  7. 24.100
>>>> libswscale      5.  2.100 /  5.  2.100
>>>> libswresample   3.  2.100 /  3.  2.100
>>>> [decklink @ 0x7f8711802600] Found Decklink mode 720 x 486 with rate 29.97(i)
>>>> [decklink @ 0x7f8711802600] Unable to set timecode
>>>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>>>> Input #0, decklink, from 'UltraStudio 3D':
>>>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>>> Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>>> Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>>>> Metadata:
>>>>   timecode        : 00:59:53;25
>>>> Stream mapping:
>>>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>>>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>>>> Press [q] to stop, [?] for help
>>>> Output #0, mov, to 'signs.mov':
>>>> Metadata:
>>>> encoder         : Lavf58.17.100
>>>> Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 0.03 fps, 30k tbn, 29.97 tbc
>>>> Metadata:
>>>>   timecode        : 00:59:53;25
>>>>   encoder         : Lavc58.19.104 v210
>>>> Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>>> Metadata:
>>>>   encoder         : Lavc58.19.104 aac
>>>> frame=  407 fps= 30 q=-0.0 Lsize=  371576kB time=00:00:13.54 bitrate=224697.2kbits/s speed=1.01x    
>>>> video:370879kB audio:685kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.003177%
>>>> [aac @ 0x7f8711805800] Qavg: 30894.625
>>>> 
>>>> Another comment is that if I start the recording with ffmpeg before I play through a source I get spammed with timecode errors such as:
>>>> 
>>>> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac notplaying.mov
>>>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>>>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>>>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>>>> libavutil      56. 18.102 / 56. 18.102
>>>> libavcodec     58. 19.104 / 58. 19.104
>>>> libavformat    58. 17.100 / 58. 17.100
>>>> libavdevice    58.  4.100 / 58.  4.100
>>>> libavfilter     7. 24.100 /  7. 24.100
>>>> libswscale      5.  2.100 /  5.  2.100
>>>> libswresample   3.  2.100 /  3.  2.100
>>>> [decklink @ 0x7fe313803000] Found Decklink mode 720 x 486 with rate 29.97(i)
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.
>>>> Last message repeated 5 times
>>>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>>>> Input #0, decklink, from 'UltraStudio 3D':
>>>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>>> Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>>> Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>>>> Stream mapping:
>>>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>>>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>>>> Press [q] to stop, [?] for help
>>>> Output #0, mov, to 'notplaying.mov':
>>>> Metadata:
>>>> encoder         : Lavf58.17.100
>>>> Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
>>>> Metadata:
>>>>   encoder         : Lavc58.19.104 v210
>>>> Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>>> Metadata:
>>>>   encoder         : Lavc58.19.104 aac
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.
>>>> Last message repeated 14 times
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:00.66 bitrate=210543.0kbits/s speed=1.33x    
>>>> Last message repeated 14 times
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.16 bitrate=217281.3kbits/s speed=1.17x    
>>>> Last message repeated 14 times
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.66 bitrate=218719.7kbits/s speed=1.11x    
>>>> Last message repeated 14 times
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.16 bitrate=219494.2kbits/s speed=1.08x    
>>>> Last message repeated 14 times
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.66 bitrate=220763.9kbits/s speed=1.07x    
>>>> Last message repeated 14 times
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.16 bitrate=220971.1kbits/s speed=1.06x    
>>>> Last message repeated 14 times
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.67 bitrate=221693.2kbits/s speed=1.05x    
>>>> Last message repeated 14 times
>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:04.17 bitrate=223247.5kbits/s speed=1.04x  
>>>> 
>>>> Until I hit the play button on my source.
>>>> 
>>>> I tested the same videotape sources with Media Express and ffmpeg with this patch and the initial timecode values are aligned to the same frames accurately, but with 4 random videotapes I’ve tried, all the Media Express captures are Non-Drop Frame and all the ffmpeg captures are Drop Frame, so one has to be wrong. I’ll try to find a source that can provide a known df and ndf signal to determine which is correct.
>>>> 
>>>> Thanks for the update,
>>>> Dave Rice
>>>> 
>>>> _______________________________________________
>>>> ffmpeg-devel mailing list
>>>> ffmpeg-devel@ffmpeg.org
>>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>> 
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
>> 
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Jonathan Morley May 31, 2018, 8:43 p.m. UTC | #26
Thank you for the clarification, Dave. It might be that the Blackmagic approach to collecting timecode doesn’t work for that one source because it is in the horizontal space (HANC) instead of the vertical (VANC). I am not sure. Sadly I don’t think my solution is all encompassing, but it does seem to help in enough cases I would like to get it integrated with master.

I am still a bit thrown about the initial “Unable to set timecode” error, but believe it to be initialization related. I will wait to hear back from Marton on my overall approach and see what I can do to clean that up.

As for the other error message my plan is to demote that to a debug.

Thanks,
Jon

> On May 31, 2018, at 1:17 PM, Dave Rice <dave@dericed.com> wrote:
> 
> Hi Jonathan,
> 
>> On May 31, 2018, at 3:56 PM, Jonathan Morley <jmorley@pixsystem.com <mailto:jmorley@pixsystem.com>> wrote:
>> 
>> Well that is helpful information if not a bit disappointing. Perhaps if I use the SDK calls to get the individual timecode components _and_ check the drop frame flag I can reassemble what the GetString() method on the IDeckLinkTimecode class is supposed to provide.
> 
> I tried with another NDF tape and it worked appropriately. So I do have a capture with NDF and another capture with DF timecode as intended. I am still uncertain what’s wrong with the first NDF that I reported before but I’m supposing it’s an issue with that tape rather than your work.
> 
> Here’s the output of the capture of the new NDF tape, note that I’m still getting the "Unable to set timecode” even though the timecode is set.
> 
> ./ffmpeg -timecode_format vitc2 -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac maybendf.mov
> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>  built with Apple LLVM version 9.0.0 (clang-900.0.38)
>  configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>  libavutil      56. 18.102 / 56. 18.102
>  libavcodec     58. 19.104 / 58. 19.104
>  libavformat    58. 17.100 / 58. 17.100
>  libavdevice    58.  4.100 / 58.  4.100
>  libavfilter     7. 24.100 /  7. 24.100
>  libswscale      5.  2.100 /  5.  2.100
>  libswresample   3.  2.100 /  3.  2.100
> [decklink @ 0x7fdd75800a00] Found Decklink mode 720 x 486 with rate 29.97(i)
> [decklink @ 0x7fdd75800a00] Unable to set timecode
> Guessed Channel Layout for Input Stream #0.0 : 7.1
> Input #0, decklink, from 'UltraStudio 3D':
>  Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>    Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>    Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>    Metadata:
>      timecode        : 03:48:55:26
> Stream mapping:
>  Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>  Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
> Press [q] to stop, [?] for help
> Output #0, mov, to 'maybendf.mov':
>  Metadata:
>    encoder         : Lavf58.17.100
>    Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 0.03 fps, 30k tbn, 29.97 tbc
>    Metadata:
>      timecode        : 03:48:55:26
>      encoder         : Lavc58.19.104 v210
>    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>    Metadata:
>      encoder         : Lavc58.19.104 aac
> frame=   48 fps= 34 q=-0.0 Lsize=   43745kB time=00:00:01.56 bitrate=228505.8kbits/s speed=1.12x    
> video:43740kB audio:2kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.007146%
> [aac @ 0x7fdd77801e00] Qavg: 65536.000
> 
>> I will add that to the next patch, but it might be a minute before I get to it. Thank you again for taking a look.
>> 
>> I guess we got really lucky in our use case.
>> 
>> Thanks,
>> Jon
>> 
>>> On May 31, 2018, at 12:39 PM, Dave Rice <dave@dericed.com <mailto:dave@dericed.com>> wrote:
>>> 
>>> Hi Jonathan,
>>> 
>>>> On May 31, 2018, at 11:41 AM, Jonathan Morley <jmorley@pixsystem.com <mailto:jmorley@pixsystem.com> <mailto:jmorley@pixsystem.com <mailto:jmorley@pixsystem.com>>> wrote:
>>>> 
>>>> Thank you very much, Dave. I am really curious about the df vs ndf since the Blackmagic SDK call I am making doesn’t have any arguments for specifying that kind of distinction. It simply returns what it finds in the SDI stream.
>>> 
>>> I know have a tape known to be NDF and a tape known to be DF. The messages I sent before were from DF tapes. When I tried a NDF tape, I get the "Unable to find timecode” warning repeatedly and no timecode on the output file.
>>> 
>>> ./ffmpeg -timecode_format vitc2 -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac devlin5.mov
>>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>>> libavutil      56. 18.102 / 56. 18.102
>>> libavcodec     58. 19.104 / 58. 19.104
>>> libavformat    58. 17.100 / 58. 17.100
>>> libavdevice    58.  4.100 / 58.  4.100
>>> libavfilter     7. 24.100 /  7. 24.100
>>> libswscale      5.  2.100 /  5.  2.100
>>> libswresample   3.  2.100 /  3.  2.100
>>> [decklink @ 0x7f9f66800000] Found Decklink mode 720 x 486 with rate 29.97(i)
>>> [decklink @ 0x7f9f66800000] Unable to find timecode.
>>>  Last message repeated 5 times
>>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>>> Input #0, decklink, from 'UltraStudio 3D':
>>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>>  Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>>  Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>>> Stream mapping:
>>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>>> Press [q] to stop, [?] for help
>>> Output #0, mov, to 'devlin5.mov':
>>> Metadata:
>>>  encoder         : Lavf58.17.100
>>>  Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
>>>  Metadata:
>>>    encoder         : Lavc58.19.104 v210
>>>  Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>>  Metadata:
>>>    encoder         : Lavc58.19.104 aac
>>> [decklink @ 0x7f9f66800000] Unable to find timecode.
>>>  Last message repeated 15 times
>>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:00.70 bitrate=200517.8kbits/s speed= 1.4x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:01.20 bitrate=211246.0kbits/s speed= 1.2x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:01.70 bitrate=214431.3kbits/s speed=1.13x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:02.20 bitrate=217121.0kbits/s speed= 1.1x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:02.70 bitrate=221142.3kbits/s speed=1.07x    
>>>  Last message repeated 14 times
>>> [decklink @ 0x7f9f66800000] Unable to find timecode.0:03.20 bitrate=221288.2kbits/s speed=1.06x    
>>> 
>>> So when inputing DF this appears to work while Media Express gets it wrong by writing the timecode with a NDF flag.
>>> However when inputing NDF no timecode is communicated.
>>> 
>>> I ran this to check if somehow I was called the wrong timecode 
>>> 
>>> for i in rp188vitc rp188vitc2 rp188ltc rp188any vitc vitc2 serial ; do echo -n "${i}: " ; ./ffprobe -v quiet -timecode_format "$i" -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -select_streams v -show_entries stream_tags=timecode -of default=nw=1:nk=1 ; echo ; done
>>> 
>>> rp188vitc: 
>>> rp188vitc2: 
>>> rp188ltc: 
>>> rp188any: 
>>> vitc: 
>>> vitc2: 
>>> serial: 
>>> 
>>> I may try to find another NDF tape to make sure this isn’t a fluke.
>>> 
>>>> And when I skimmed the movenc timecode handling it doesn’t seem to make any assumptions or changes either.
>>> 
>>> I’ve replicated it with Matroska which simply moves the timecode into metadata as a string.
>>> 
>>>> Please keep me posted. Meanwhile I will look into what could be causing all the error chatter.
>>> 
>>> Thanks!
>>> 
>>>> Thanks,
>>>> Jon
>>>> 
>>>>> On May 31, 2018, at 7:59 AM, Dave Rice <dave@dericed.com> wrote:
>>>>> 
>>>>> 
>>>>>> On May 31, 2018, at 5:49 AM, Jonathan Morley <jmorley@pixsystem.com> wrote:
>>>>>> 
>>>>>> Please take a look at my latest patches.
>>>>>> 
>>>>>> NOTE: I no longer have the hardware to test this work!
>>>>> 
>>>>> I tested these patches with an Ultrastudio 3D.
>>>>> 
>>>>> I find that in some cases it provides the “Unable to set timecode” warning although it does provide the timecode value. Such as:
>>>>> 
>>>>> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac signs.mov
>>>>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>>>>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>>>>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>>>>> libavutil      56. 18.102 / 56. 18.102
>>>>> libavcodec     58. 19.104 / 58. 19.104
>>>>> libavformat    58. 17.100 / 58. 17.100
>>>>> libavdevice    58.  4.100 / 58.  4.100
>>>>> libavfilter     7. 24.100 /  7. 24.100
>>>>> libswscale      5.  2.100 /  5.  2.100
>>>>> libswresample   3.  2.100 /  3.  2.100
>>>>> [decklink @ 0x7f8711802600] Found Decklink mode 720 x 486 with rate 29.97(i)
>>>>> [decklink @ 0x7f8711802600] Unable to set timecode
>>>>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>>>>> Input #0, decklink, from 'UltraStudio 3D':
>>>>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>>>> Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>>>> Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>>>>> Metadata:
>>>>>  timecode        : 00:59:53;25
>>>>> Stream mapping:
>>>>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>>>>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>>>>> Press [q] to stop, [?] for help
>>>>> Output #0, mov, to 'signs.mov':
>>>>> Metadata:
>>>>> encoder         : Lavf58.17.100
>>>>> Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 0.03 fps, 30k tbn, 29.97 tbc
>>>>> Metadata:
>>>>>  timecode        : 00:59:53;25
>>>>>  encoder         : Lavc58.19.104 v210
>>>>> Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>>>> Metadata:
>>>>>  encoder         : Lavc58.19.104 aac
>>>>> frame=  407 fps= 30 q=-0.0 Lsize=  371576kB time=00:00:13.54 bitrate=224697.2kbits/s speed=1.01x    
>>>>> video:370879kB audio:685kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.003177%
>>>>> [aac @ 0x7f8711805800] Qavg: 30894.625
>>>>> 
>>>>> Another comment is that if I start the recording with ffmpeg before I play through a source I get spammed with timecode errors such as:
>>>>> 
>>>>> ./ffmpeg -timecode_format vitc -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac notplaying.mov
>>>>> ffmpeg version N-91200-g1616b1be5a Copyright (c) 2000-2018 the FFmpeg developers
>>>>> built with Apple LLVM version 9.0.0 (clang-900.0.38)
>>>>> configuration: --enable-nonfree --enable-decklink --extra-cflags=-I/usr/local/include --extra-ldflags=-L/usr/local/include
>>>>> libavutil      56. 18.102 / 56. 18.102
>>>>> libavcodec     58. 19.104 / 58. 19.104
>>>>> libavformat    58. 17.100 / 58. 17.100
>>>>> libavdevice    58.  4.100 / 58.  4.100
>>>>> libavfilter     7. 24.100 /  7. 24.100
>>>>> libswscale      5.  2.100 /  5.  2.100
>>>>> libswresample   3.  2.100 /  3.  2.100
>>>>> [decklink @ 0x7fe313803000] Found Decklink mode 720 x 486 with rate 29.97(i)
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.
>>>>> Last message repeated 5 times
>>>>> Guessed Channel Layout for Input Stream #0.0 : 7.1
>>>>> Input #0, decklink, from 'UltraStudio 3D':
>>>>> Duration: N/A, start: 0.000000, bitrate: 229869 kb/s
>>>>> Stream #0:0: Audio: pcm_s16le, 48000 Hz, 7.1, s16, 6144 kb/s
>>>>> Stream #0:1: Video: v210 (V210 / 0x30313256), yuv422p10le(bottom first), 720x486, 223725 kb/s, 29.97 fps, 29.97 tbr, 1000k tbn, 1000k tbc
>>>>> Stream mapping:
>>>>> Stream #0:1 -> #0:0 (v210 (native) -> v210 (native))
>>>>> Stream #0:0 -> #0:1 (pcm_s16le (native) -> aac (native))
>>>>> Press [q] to stop, [?] for help
>>>>> Output #0, mov, to 'notplaying.mov':
>>>>> Metadata:
>>>>> encoder         : Lavf58.17.100
>>>>> Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(bottom coded first (swapped)), 720x486, q=2-31, 223725 kb/s, 29.97 fps, 30k tbn, 29.97 tbc
>>>>> Metadata:
>>>>>  encoder         : Lavc58.19.104 v210
>>>>> Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 7.1, fltp, 469 kb/s
>>>>> Metadata:
>>>>>  encoder         : Lavc58.19.104 aac
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.
>>>>> Last message repeated 14 times
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:00.66 bitrate=210543.0kbits/s speed=1.33x    
>>>>> Last message repeated 14 times
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.16 bitrate=217281.3kbits/s speed=1.17x    
>>>>> Last message repeated 14 times
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:01.66 bitrate=218719.7kbits/s speed=1.11x    
>>>>> Last message repeated 14 times
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.16 bitrate=219494.2kbits/s speed=1.08x    
>>>>> Last message repeated 14 times
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:02.66 bitrate=220763.9kbits/s speed=1.07x    
>>>>> Last message repeated 14 times
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.16 bitrate=220971.1kbits/s speed=1.06x    
>>>>> Last message repeated 14 times
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:03.67 bitrate=221693.2kbits/s speed=1.05x    
>>>>> Last message repeated 14 times
>>>>> [decklink @ 0x7fe313803000] Unable to find timecode.0:04.17 bitrate=223247.5kbits/s speed=1.04x  
>>>>> 
>>>>> Until I hit the play button on my source.
>>>>> 
>>>>> I tested the same videotape sources with Media Express and ffmpeg with this patch and the initial timecode values are aligned to the same frames accurately, but with 4 random videotapes I’ve tried, all the Media Express captures are Non-Drop Frame and all the ffmpeg captures are Drop Frame, so one has to be wrong. I’ll try to find a source that can provide a known df and ndf signal to determine which is correct.
>>>>> 
>>>>> Thanks for the update,
>>>>> Dave Rice
>>>>> 
>>>>> _______________________________________________
>>>>> ffmpeg-devel mailing list
>>>>> ffmpeg-devel@ffmpeg.org
>>>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>>> 
>>>> _______________________________________________
>>>> ffmpeg-devel mailing list
>>>> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org> <mailto:ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>>
>>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel> <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>>
>>> 
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org> <mailto:ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>>
>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel> <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel <http://ffmpeg.org/mailman/listinfo/ffmpeg-devel>
Marton Balint May 31, 2018, 9:29 p.m. UTC | #27
On Thu, 31 May 2018, Jonathan Morley wrote:

> Thank you for the clarification, Dave. It might be that the Blackmagic 
> approach to collecting timecode doesn’t work for that one source because 
> it is in the horizontal space (HANC) instead of the vertical (VANC). I 
> am not sure. Sadly I don’t think my solution is all encompassing, but it 
> does seem to help in enough cases I would like to get it integrated with 
> master.
>
> I am still a bit thrown about the initial “Unable to set timecode” 
> error, but believe it to be initialization related. I will wait to hear 
> back from Marton on my overall approach and see what I can do to clean 
> that up.

av_dict_set returns < 0 on error, so the condition seems wrong.

>
> As for the other error message my plan is to demote that to a debug.

That is a good idea.

On the other hand, I believe the usefulness of this is in its current form 
is still very limited, because typically the first few frames are NoSignal 
frames, how the end user supposed to know which frame is the one with the 
first valid timecode?

I'd rather see a new AVPacketSideData type which will contain the timecode 
as a string, so you can set it frame-by-frame.

Regards,
Marton
Devin Heitmueller May 31, 2018, 9:59 p.m. UTC | #28
> 
> I'd rather see a new AVPacketSideData type which will contain the timecode as a string, so you can set it frame-by-frame.

For what it’s worth, this is what I’ve done on the decklink output side.  I’ve introduced a new side data type and I’m able to decode timecodes provided in H.264 streams and output them as SDI VANC (i.e. continuous output of timecodes as opposed to just the first timecode).

I just haven’t gotten to doing the capture side yet.  It’s on my TODO list though.

Devin
Dave Rice June 1, 2018, 12:52 p.m. UTC | #29
> On May 31, 2018, at 5:29 PM, Marton Balint <cus@passwd.hu> wrote:
> 
> On Thu, 31 May 2018, Jonathan Morley wrote:
> 
>> Thank you for the clarification, Dave. It might be that the Blackmagic approach to collecting timecode doesn’t work for that one source because it is in the horizontal space (HANC) instead of the vertical (VANC). I am not sure. Sadly I don’t think my solution is all encompassing, but it does seem to help in enough cases I would like to get it integrated with master.
>> 
>> I am still a bit thrown about the initial “Unable to set timecode” error, but believe it to be initialization related. I will wait to hear back from Marton on my overall approach and see what I can do to clean that up.
> 
> av_dict_set returns < 0 on error, so the condition seems wrong.
> 
>> 
>> As for the other error message my plan is to demote that to a debug.
> 
> That is a good idea.

+1

> On the other hand, I believe the usefulness of this is in its current form is still very limited, because typically the first few frames are NoSignal frames, how the end user supposed to know which frame is the one with the first valid timecode?

In my testing the timecode value set here has corrected been associated with the first video frame (maintaining the timecode-to-first-frame relationship as found on the source video stream). Although only having first timecode value known is limiting, I think this is still quite useful. This function also mirrors how BlackMagic Media Express and Adobe Premiere handle capturing video+timecode where only the first value is documented and all subsequent values are presumed.

> I'd rather see a new AVPacketSideData type which will contain the timecode as a string, so you can set it frame-by-frame.

Using side data for timecode would be preferable, but the possibility that a patch for that may someday arrive shouldn’t completely block this more limited patch.

[…]

Dave
Marton Balint June 4, 2018, 4:24 p.m. UTC | #30
On Fri, 1 Jun 2018, Dave Rice wrote:

>
>> On May 31, 2018, at 5:29 PM, Marton Balint <cus@passwd.hu> wrote:
>> 
>> On Thu, 31 May 2018, Jonathan Morley wrote:
>> 
>>> Thank you for the clarification, Dave. It might be that the Blackmagic approach to collecting timecode doesn’t work for that one source because it is in the horizontal space (HANC) instead of the vertical (VANC). I am not sure. Sadly I don’t think my solution is all encompassing, but it does seem to help in enough cases I would like to get it integrated with master.
>>> 
>>> I am still a bit thrown about the initial “Unable to set timecode” error, but believe it to be initialization related. I will wait to hear back from Marton on my overall approach and see what I can do to clean that up.
>> 
>> av_dict_set returns < 0 on error, so the condition seems wrong.
>> 
>>> 
>>> As for the other error message my plan is to demote that to a debug.
>> 
>> That is a good idea.
>
> +1
>
>> On the other hand, I believe the usefulness of this is in its current form is still very limited, because typically the first few frames are NoSignal frames, how the end user supposed to know which frame is the one with the first valid timecode?
>
> In my testing the timecode value set here has corrected been associated 
> with the first video frame (maintaining the timecode-to-first-frame 
> relationship as found on the source video stream). Although only having 
> first timecode value known is limiting, I think this is still quite 
> useful. This function also mirrors how BlackMagic Media Express and 
> Adobe Premiere handle capturing video+timecode where only the first 
> value is documented and all subsequent values are presumed.

Could you give me an example? (e.g. ffmpeg command line?)

>
>> I'd rather see a new AVPacketSideData type which will contain the timecode as a string, so you can set it frame-by-frame.
>
> Using side data for timecode would be preferable, but the possibility that a patch for that may someday arrive shouldn’t completely block this more limited patch.

I would like to make sure the code works reliably even for the limited use 
case and no race conditions are affectig the way it works.

Thanks,
Marton
Dave Rice June 4, 2018, 6:07 p.m. UTC | #31
> On Jun 4, 2018, at 12:24 PM, Marton Balint <cus@passwd.hu> wrote:
> 
> On Fri, 1 Jun 2018, Dave Rice wrote:
> 
>>> On May 31, 2018, at 5:29 PM, Marton Balint <cus@passwd.hu> wrote:
>>> On Thu, 31 May 2018, Jonathan Morley wrote:
>>>> Thank you for the clarification, Dave. It might be that the Blackmagic approach to collecting timecode doesn’t work for that one source because it is in the horizontal space (HANC) instead of the vertical (VANC). I am not sure. Sadly I don’t think my solution is all encompassing, but it does seem to help in enough cases I would like to get it integrated with master.
>>>> I am still a bit thrown about the initial “Unable to set timecode” error, but believe it to be initialization related. I will wait to hear back from Marton on my overall approach and see what I can do to clean that up.
>>> av_dict_set returns < 0 on error, so the condition seems wrong.
>>>> As for the other error message my plan is to demote that to a debug.
>>> That is a good idea.
>> 
>> +1
>> 
>>> On the other hand, I believe the usefulness of this is in its current form is still very limited, because typically the first few frames are NoSignal frames, how the end user supposed to know which frame is the one with the first valid timecode?
>> 
>> In my testing the timecode value set here has corrected been associated with the first video frame (maintaining the timecode-to-first-frame relationship as found on the source video stream). Although only having first timecode value known is limiting, I think this is still quite useful. This function also mirrors how BlackMagic Media Express and Adobe Premiere handle capturing video+timecode where only the first value is documented and all subsequent values are presumed.
> 
> Could you give me an example? (e.g. ffmpeg command line?)

./ffmpeg -timecode_format vitc2 -f decklink -draw_bars 0 -audio_input embedded -video_input sdi -format_code ntsc -channels 8 -raw_format yuv422p10 -i "UltraStudio 3D" -c:v v210 -c:a aac output.mov

This worked for me to embed a QuickTime timecode track based upon the timecode value of the first frame. If the input contained non-sequential timecode values then the timecode track would not be accurate from that point onward, but creating a timecode track based only upon the initial value is what BlackMagic Media Express and Adobe Premiere are doing anyhow.

>>> I'd rather see a new AVPacketSideData type which will contain the timecode as a string, so you can set it frame-by-frame.
>> 
>> Using side data for timecode would be preferable, but the possibility that a patch for that may someday arrive shouldn’t completely block this more limited patch.
> 
> I would like to make sure the code works reliably even for the limited use case and no race conditions are affectig the way it works.

Feel welcome to suggest any testing. I’ll have access for testing again tomorrow.
Dave
diff mbox

Patch

diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.
cpp
index d8cced7c74..aab9d85b94 100644
--- a/libavdevice/decklink_common.cpp
+++ b/libavdevice/decklink_common.cpp
@@ -77,36 +77,6 @@  static IDeckLinkIterator
*decklink_create_iterator(AVFormatContext
*avctx)
    return iter;
}

-#ifdef _WIN32
-static char *dup_wchar_to_utf8(wchar_t *w)
-{
-    char *s = NULL;
-    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
-    s = (char *) av_malloc(l);
-    if (s)
-        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
-    return s;
-}
-#define DECKLINK_STR    OLECHAR *
-#define DECKLINK_STRDUP dup_wchar_to_utf8
-#define DECKLINK_FREE(s) SysFreeString(s)
-#elif defined(__APPLE__)
-static char *dup_cfstring_to_utf8(CFStringRef w)
-{
-    char s[256];
-    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
-    return av_strdup(s);
-}
-#define DECKLINK_STR    const __CFString *
-#define DECKLINK_STRDUP dup_cfstring_to_utf8
-#define DECKLINK_FREE(s) CFRelease(s)
-#else
-#define DECKLINK_STR    const char *
-#define DECKLINK_STRDUP av_strdup
-/* free() is needed for a string returned by the DeckLink SDL. */
-#define DECKLINK_FREE(s) free((void *) s)
-#endif
-
HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
**displayName)
{
    DECKLINK_STR tmpDisplayName;
diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
index 57ee7d1d68..8c5f8e9f06 100644
--- a/libavdevice/decklink_common.h
+++ b/libavdevice/decklink_common.h
@@ -34,6 +34,36 @@ 
#define DECKLINK_BOOL bool
#endif

+#ifdef _WIN32
+static char *dup_wchar_to_utf8(wchar_t *w)
+{
+    char *s = NULL;
+    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
+    s = (char *) av_malloc(l);
+    if (s)
+        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
+    return s;
+}
+#define DECKLINK_STR    OLECHAR *
+#define DECKLINK_STRDUP dup_wchar_to_utf8
+#define DECKLINK_FREE(s) SysFreeString(s)
+#elif defined(__APPLE__)
+static char *dup_cfstring_to_utf8(CFStringRef w)
+{
+    char s[256];
+    CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
+    return av_strdup(s);
+}
+#define DECKLINK_STR    const __CFString *
+#define DECKLINK_STRDUP dup_cfstring_to_utf8
+#define DECKLINK_FREE(s) CFRelease(s)
+#else
+#define DECKLINK_STR    const char *
+#define DECKLINK_STRDUP av_strdup
+/* free() is needed for a string returned by the DeckLink SDL. */
+#define DECKLINK_FREE(s) free((void *) s)
+#endif
+
class decklink_output_callback;
class decklink_input_callback;

@@ -64,6 +94,7 @@  struct decklink_ctx {
    BMDDisplayMode bmd_mode;
    BMDVideoConnection video_input;
    BMDAudioConnection audio_input;
+    BMDTimecodeFormat tc_format;
    int bmd_width;
    int bmd_height;
    int bmd_field_dominance;
@@ -140,6 +171,17 @@  static const BMDVideoConnection
decklink_video_connection_map[] = {
    bmdVideoConnectionSVideo,
};

+static const BMDTimecodeFormat decklink_timecode_format_map[] = {
+    (BMDTimecodeFormat)0,
+    bmdTimecodeRP188VITC1,
+    bmdTimecodeRP188VITC2,
+    bmdTimecodeRP188LTC,
+    bmdTimecodeRP188Any,
+    bmdTimecodeVITC,
+    bmdTimecodeVITCField2,
+    bmdTimecodeSerial,
+};
+
HRESULT ff_decklink_get_display_name(IDeckLink *This, const char
**displayName);
int ff_decklink_set_configs(AVFormatContext *avctx, decklink_direction_t
direction);
int ff_decklink_set_format(AVFormatContext *avctx, int width, int height,
int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t
direction = DIRECTION_OUT, int num = 0);
diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_
c.h
index 08e9f9bbd5..32a5d70ee1 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -50,6 +50,7 @@  struct decklink_cctx {
    DecklinkPtsSource video_pts_source;
    int audio_input;
    int video_input;
+    int tc_format;
    int draw_bars;
    char *format_code;
    int raw_format;
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index 510637676c..818235bfa6 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -726,6 +726,23 @@  HRESULT decklink_input_callback::
VideoInputFrameArrived(
            no_video = 0;
        }

+        // Handle Timecode (if requested)
+        if (ctx->tc_format && !(av_dict_get(ctx->video_st->metadata,
"timecode", NULL, 0)) && !no_video) {
+            IDeckLinkTimecode *timecode;
+            if (videoFrame->GetTimecode(ctx->tc_format, &timecode) ==
S_OK) {
+                DECKLINK_STR timecodeString = NULL;
+                timecode->GetString(&timecodeString);
+                const char* tc = DECKLINK_STRDUP(timecodeString);
+                if (!(av_dict_set(&ctx->video_st->metadata, "timecode",
tc, 0)))
+                    av_log(avctx, AV_LOG_ERROR, "Unable to set
timecode\n");
+                if (timecodeString)
+                    DECKLINK_FREE(timecodeString);
+                timecode->Release();
+            } else {
+                av_log(avctx, AV_LOG_ERROR, "Unable to find timecode.\n");
+            }
+        }
+
        pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock,
abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base,
&initial_video_pts, cctx->copyts);
        pkt.dts = pkt.pts;

@@ -939,6 +956,8 @@  av_cold int ff_decklink_read_header(AVFormatContext
*avctx)
    ctx->teletext_lines = cctx->teletext_lines;
    ctx->preroll      = cctx->preroll;
    ctx->duplex_mode  = cctx->duplex_mode;
+    if (cctx->tc_format > 0 && (unsigned int)cctx->tc_format <
FF_ARRAY_ELEMS(decklink_timecode_format_map))
+        ctx->tc_format = decklink_timecode_format_map[cctx->tc_format];
    if (cctx->video_input > 0 && (unsigned int)cctx->video_input <
FF_ARRAY_ELEMS(decklink_video_connection_map))
        ctx->video_input = decklink_video_connection_map[cctx->video_input];
    if (cctx->audio_input > 0 && (unsigned int)cctx->audio_input <
FF_ARRAY_ELEMS(decklink_audio_connection_map))
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index 47018dc681..6ab3819375 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -48,6 +48,15 @@  static const AVOption options[] = {
    { "unset",         NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "duplex_mode"},
    { "half",          NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "duplex_mode"},
    { "full",          NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "duplex_mode"},
+    { "timecode_format", "timecode format",           OFFSET(tc_format),
 AV_OPT_TYPE_INT,   { .i64 = 0}, 0, 7,    DEC, "tc_format"},
+    { "none",          NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0,    DEC, "tc_format"},
+    { "rp188vitc",     NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0,    DEC, "tc_format"},
+    { "rp188vitc2",    NULL,                                          0,
 AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0,    DEC, "tc_format"},
+    { "rp188ltc",      NULL,                                          0,