diff mbox

[FFmpeg-devel] avfilter/drawtext: special metadata fields to allow plotting source filename to output.

Message ID 20191214225931.28368-1-alexandre.schmidt@gmail.com
State New
Headers show

Commit Message

Alexandre Heitor Schmidt Dec. 14, 2019, 10:59 p.m. UTC
avfilter/drawtext: Added two special metadata tags which can, be used by
'drawtext' filter and others to have access to source file path, and its
basename.

The new field AVPacket->source_file will contain a path to its corresponding
filename everytime the packet corresponds to a single file. This behavior is
common for image2 filter. When this field is filled, frames passed to filters
will contain two special metadata tags called source_path (the entire path to
the file) and source_basename (only the file name). These metatags can be
used by filters like drawtext to be able to plot the entire path or the
basename of it respectively to the frame being processed.

doc/filters: The documentation for drawtext was also updated and an usage
example was added.

Fixes #2874.

Signed-off-by: Alexandre Heitor Schmidt <alexandre.schmidt@gmail.com>
---
 doc/filters.texi      | 13 +++++++++++++
 fftools/ffmpeg.c      | 12 ++++++++++++
 libavcodec/avcodec.h  |  8 ++++++++
 libavcodec/avpacket.c |  1 +
 libavformat/img2dec.c |  9 +++++++++
 5 files changed, 43 insertions(+)

Comments

Marton Balint Dec. 14, 2019, 11:15 p.m. UTC | #1
On Sat, 14 Dec 2019, Alexandre Heitor Schmidt wrote:

> avfilter/drawtext: Added two special metadata tags which can, be used by
> 'drawtext' filter and others to have access to source file path, and its
> basename.
>
> The new field AVPacket->source_file will contain a path to its corresponding
> filename everytime the packet corresponds to a single file. This behavior is
> common for image2 filter. When this field is filled, frames passed to filters
> will contain two special metadata tags called source_path (the entire path to
> the file) and source_basename (only the file name). These metatags can be
> used by filters like drawtext to be able to plot the entire path or the
> basename of it respectively to the frame being processed.
>
> doc/filters: The documentation for drawtext was also updated and an usage
> example was added.
>
> Fixes #2874.

This seems like something that be done less intrusively by setting an 
AV_PKT_DATA_STRINGS_METADATA packet side data for each packet. That is 
automatically transformed to frame metadata which can be referenced by the 
drawtext filter.

Regards,
Marton

>
> Signed-off-by: Alexandre Heitor Schmidt <alexandre.schmidt@gmail.com>
> ---
> doc/filters.texi      | 13 +++++++++++++
> fftools/ffmpeg.c      | 12 ++++++++++++
> libavcodec/avcodec.h  |  8 ++++++++
> libavcodec/avpacket.c |  1 +
> libavformat/img2dec.c |  9 +++++++++
> 5 files changed, 43 insertions(+)
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 93f54a2e1e..d984efb73b 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -9726,6 +9726,12 @@ printed by running @code{ffprobe -show_frames}.
> String metadata generated in filters leading to
> the drawtext filter are also available.
> 
> +There are two special metadata fields (@var{source_path} and @var{source_basename})
> +which can be used when input format has a file corresponding to each frame, such
> +as @var{image2}. @var{source_path} will output the entire path to the filename
> +which generated the frame in question, while @var{source_basename} outputs the
> +equivalent to @code{basename(source_path)}.
> +
> @item n, frame_num
> The frame number, starting from 0.
> 
> @@ -9872,6 +9878,13 @@ drawtext=fontfile=FreeSans.ttf:text=DOG:fontsize=24:x=10:y=20+24-max_glyph_a,
> drawtext=fontfile=FreeSans.ttf:text=cow:fontsize=24:x=80:y=20+24-max_glyph_a
> @end example
> 
> +@item
> +Plot special @var{source_basename} metadata, extracted from each input frame, or
> +the string "NA" if the metadata is not defined.
> +@example
> +drawtext="fontsize=20:fontcolor=white:fontfile=FreeSans.ttf:text='%{metadata\:source_basename\:NA}':x=10:y=10"
> +@end example
> +
> @end itemize
> 
> For more information about libfreetype, check:
> diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
> index 27f68933f8..9285f86a81 100644
> --- a/fftools/ffmpeg.c
> +++ b/fftools/ffmpeg.c
> @@ -2375,6 +2375,18 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_
>     if (ret < 0)
>         *decode_failed = 1;
> 
> +    /**
> +     * Set filename as a frame metadata, if it's not empty. This will allow filters
> +     * like drawtext to use this information for cases like image2, where each frame
> +     * corresponds to a file.
> +     */
> +    if (pkt) {
> +        if ( pkt->source_filename != NULL ) {
> +            av_dict_set(&decoded_frame->metadata, "source_path", pkt->source_filename, 0);
> +            av_dict_set(&decoded_frame->metadata, "source_basename", av_basename(pkt->source_filename), 0);
> +        }
> +    }
> +
>     // The following line may be required in some cases where there is no parser
>     // or the parser does not has_b_frames correctly
>     if (ist->st->codecpar->video_delay < ist->dec_ctx->has_b_frames) {
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 119b32dc1f..4e285f4dd8 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -1511,6 +1511,14 @@ typedef struct AVPacket {
>     attribute_deprecated
>     int64_t convergence_duration;
> #endif
> +
> +    /**
> +     * In cases where the packet corresponds to the contents of one single
> +     * file, like when image2 is used, this is set to the source filename,
> +     * so it can be used by filters like drawtext, to plot the source
> +     * filename on the frame.
> +     */
> +    char *source_filename;
> } AVPacket;
> #define AV_PKT_FLAG_KEY     0x0001 ///< The packet contains a keyframe
> #define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
> diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
> index 858f827a0a..c357e2fbac 100644
> --- a/libavcodec/avpacket.c
> +++ b/libavcodec/avpacket.c
> @@ -46,6 +46,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
>     pkt->buf                  = NULL;
>     pkt->side_data            = NULL;
>     pkt->side_data_elems      = 0;
> +    pkt->source_filename      = NULL;
> }
> 
> AVPacket *av_packet_alloc(void)
> diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
> index f8b4a655a5..02119d89fc 100644
> --- a/libavformat/img2dec.c
> +++ b/libavformat/img2dec.c
> @@ -485,6 +485,15 @@ int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt)
>
>     if (s->is_pipe)
>         pkt->pos = avio_tell(f[0]);
> +    else {
> +        // Set the filename which corresponds to this packet.
> +        pkt->source_filename = av_malloc(strlen(filename));
> +        if (!pkt->source_filename) {
> +            av_log(NULL, AV_LOG_FATAL, "Failed to allocate source_filename\n");
> +            return AVERROR(ENOMEM);
> +        }
> +        pkt->source_filename = av_asprintf("%s", filename);
> +    }
>
>     pkt->size = 0;
>     for (i = 0; i < 3; i++) {
> -- 
> 2.17.1
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Alexandre Heitor Schmidt Dec. 15, 2019, 10:42 a.m. UTC | #2
On 14/12/2019 23:15, Marton Balint wrote:
> On Sat, 14 Dec 2019, Alexandre Heitor Schmidt wrote:
>> avfilter/drawtext: Added two special metadata tags which can, be used by
>> 'drawtext' filter and others to have access to source file path, and its
>> basename.
>>
>> The new field AVPacket->source_file will contain a path to its 
>> corresponding
>> filename everytime the packet corresponds to a single file. This 
>> behavior is
>> common for image2 filter. When this field is filled, frames passed to 
>> filters
>> will contain two special metadata tags called source_path (the entire 
>> path to
>> the file) and source_basename (only the file name). These metatags 
>> can be
>> used by filters like drawtext to be able to plot the entire path or the
>> basename of it respectively to the frame being processed.
>>
>> doc/filters: The documentation for drawtext was also updated and an 
>> usage
>> example was added.
>>
>> Fixes #2874.
>
> This seems like something that be done less intrusively by setting an 
> AV_PKT_DATA_STRINGS_METADATA packet side data for each packet. That is 
> automatically transformed to frame metadata which can be referenced by 
> the drawtext filter.
>
> Regards,
> Marton
That's great, Marton! Thanks for the tip! I'll research on how to use 
AV_PKT_DATA_STRINGS_METADATA properly and re-submit the patch. By the 
way, how should I proceed with the patch at 
https://patchwork.ffmpeg.org/patch/16798/? I think it should be deleted 
until I have it implemented the way you suggested, right? Thanks again!

Best wishes,

Alex.
>
>>
>> Signed-off-by: Alexandre Heitor Schmidt <alexandre.schmidt@gmail.com>
>> ---
>> doc/filters.texi      | 13 +++++++++++++
>> fftools/ffmpeg.c      | 12 ++++++++++++
>> libavcodec/avcodec.h  |  8 ++++++++
>> libavcodec/avpacket.c |  1 +
>> libavformat/img2dec.c |  9 +++++++++
>> 5 files changed, 43 insertions(+)
>>
>> diff --git a/doc/filters.texi b/doc/filters.texi
>> index 93f54a2e1e..d984efb73b 100644
>> --- a/doc/filters.texi
>> +++ b/doc/filters.texi
>> @@ -9726,6 +9726,12 @@ printed by running @code{ffprobe -show_frames}.
>> String metadata generated in filters leading to
>> the drawtext filter are also available.
>>
>> +There are two special metadata fields (@var{source_path} and 
>> @var{source_basename})
>> +which can be used when input format has a file corresponding to each 
>> frame, such
>> +as @var{image2}. @var{source_path} will output the entire path to 
>> the filename
>> +which generated the frame in question, while @var{source_basename} 
>> outputs the
>> +equivalent to @code{basename(source_path)}.
>> +
>> @item n, frame_num
>> The frame number, starting from 0.
>>
>> @@ -9872,6 +9878,13 @@ 
>> drawtext=fontfile=FreeSans.ttf:text=DOG:fontsize=24:x=10:y=20+24-max_glyph_a,
>> drawtext=fontfile=FreeSans.ttf:text=cow:fontsize=24:x=80:y=20+24-max_glyph_a 
>>
>> @end example
>>
>> +@item
>> +Plot special @var{source_basename} metadata, extracted from each 
>> input frame, or
>> +the string "NA" if the metadata is not defined.
>> +@example
>> +drawtext="fontsize=20:fontcolor=white:fontfile=FreeSans.ttf:text='%{metadata\:source_basename\:NA}':x=10:y=10" 
>>
>> +@end example
>> +
>> @end itemize
>>
>> For more information about libfreetype, check:
>> diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
>> index 27f68933f8..9285f86a81 100644
>> --- a/fftools/ffmpeg.c
>> +++ b/fftools/ffmpeg.c
>> @@ -2375,6 +2375,18 @@ static int decode_video(InputStream *ist, 
>> AVPacket *pkt, int *got_output, int64_
>>     if (ret < 0)
>>         *decode_failed = 1;
>>
>> +    /**
>> +     * Set filename as a frame metadata, if it's not empty. This 
>> will allow filters
>> +     * like drawtext to use this information for cases like image2, 
>> where each frame
>> +     * corresponds to a file.
>> +     */
>> +    if (pkt) {
>> +        if ( pkt->source_filename != NULL ) {
>> +            av_dict_set(&decoded_frame->metadata, "source_path", 
>> pkt->source_filename, 0);
>> +            av_dict_set(&decoded_frame->metadata, "source_basename", 
>> av_basename(pkt->source_filename), 0);
>> +        }
>> +    }
>> +
>>     // The following line may be required in some cases where there 
>> is no parser
>>     // or the parser does not has_b_frames correctly
>>     if (ist->st->codecpar->video_delay < ist->dec_ctx->has_b_frames) {
>> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
>> index 119b32dc1f..4e285f4dd8 100644
>> --- a/libavcodec/avcodec.h
>> +++ b/libavcodec/avcodec.h
>> @@ -1511,6 +1511,14 @@ typedef struct AVPacket {
>>     attribute_deprecated
>>     int64_t convergence_duration;
>> #endif
>> +
>> +    /**
>> +     * In cases where the packet corresponds to the contents of one 
>> single
>> +     * file, like when image2 is used, this is set to the source 
>> filename,
>> +     * so it can be used by filters like drawtext, to plot the source
>> +     * filename on the frame.
>> +     */
>> +    char *source_filename;
>> } AVPacket;
>> #define AV_PKT_FLAG_KEY     0x0001 ///< The packet contains a keyframe
>> #define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
>> diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
>> index 858f827a0a..c357e2fbac 100644
>> --- a/libavcodec/avpacket.c
>> +++ b/libavcodec/avpacket.c
>> @@ -46,6 +46,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
>>     pkt->buf                  = NULL;
>>     pkt->side_data            = NULL;
>>     pkt->side_data_elems      = 0;
>> +    pkt->source_filename      = NULL;
>> }
>>
>> AVPacket *av_packet_alloc(void)
>> diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
>> index f8b4a655a5..02119d89fc 100644
>> --- a/libavformat/img2dec.c
>> +++ b/libavformat/img2dec.c
>> @@ -485,6 +485,15 @@ int ff_img_read_packet(AVFormatContext *s1, 
>> AVPacket *pkt)
>>
>>     if (s->is_pipe)
>>         pkt->pos = avio_tell(f[0]);
>> +    else {
>> +        // Set the filename which corresponds to this packet.
>> +        pkt->source_filename = av_malloc(strlen(filename));
>> +        if (!pkt->source_filename) {
>> +            av_log(NULL, AV_LOG_FATAL, "Failed to allocate 
>> source_filename\n");
>> +            return AVERROR(ENOMEM);
>> +        }
>> +        pkt->source_filename = av_asprintf("%s", filename);
>> +    }
>>
>>     pkt->size = 0;
>>     for (i = 0; i < 3; i++) {
>> -- 
>> 2.17.1
>>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Michael Niedermayer Dec. 15, 2019, 3:04 p.m. UTC | #3
On Sat, Dec 14, 2019 at 10:59:31PM +0000, Alexandre Heitor Schmidt wrote:
> avfilter/drawtext: Added two special metadata tags which can, be used by
> 'drawtext' filter and others to have access to source file path, and its
> basename.
> 
> The new field AVPacket->source_file will contain a path to its corresponding
> filename everytime the packet corresponds to a single file. This behavior is
> common for image2 filter. When this field is filled, frames passed to filters
> will contain two special metadata tags called source_path (the entire path to
> the file) and source_basename (only the file name). These metatags can be
> used by filters like drawtext to be able to plot the entire path or the
> basename of it respectively to the frame being processed.
> 
> doc/filters: The documentation for drawtext was also updated and an usage
> example was added.
> 
> Fixes #2874.
> 
> Signed-off-by: Alexandre Heitor Schmidt <alexandre.schmidt@gmail.com>
> ---
>  doc/filters.texi      | 13 +++++++++++++
>  fftools/ffmpeg.c      | 12 ++++++++++++
>  libavcodec/avcodec.h  |  8 ++++++++
>  libavcodec/avpacket.c |  1 +
>  libavformat/img2dec.c |  9 +++++++++
>  5 files changed, 43 insertions(+)

doc/filters.texi:9885: misplaced {
doc/filters.texi:9885: misplaced }
make: *** [doc/ffprobe-all.html] Error 1
make: *** Waiting for unfinished jobs....
doc/filters.texi:9885: misplaced {
doc/filters.texi:9885: misplaced }
make: *** [doc/ffplay-all.html] Error 1
doc/filters.texi:9885: misplaced {
doc/filters.texi:9885: misplaced }
make: *** [doc/ffmpeg-all.html] Error 1
doc/filters.texi:9885: misplaced {
doc/filters.texi:9885: misplaced }
make: *** [doc/ffmpeg-filters.html] Error 1

[...]
Alexandre Heitor Schmidt Dec. 15, 2019, 4:20 p.m. UTC | #4
On 15/12/2019 15:04, Michael Niedermayer wrote:
 > On Sat, Dec 14, 2019 at 10:59:31PM +0000, Alexandre Heitor Schmidt wrote:
 >> avfilter/drawtext: Added two special metadata tags which can, be used by
 >> 'drawtext' filter and others to have access to source file path, and its
 >> basename.
 >>
 >> The new field AVPacket->source_file will contain a path to its 
corresponding
 >> filename everytime the packet corresponds to a single file. This 
behavior is
 >> common for image2 filter. When this field is filled, frames passed 
to filters
 >> will contain two special metadata tags called source_path (the 
entire path to
 >> the file) and source_basename (only the file name). These metatags 
can be
 >> used by filters like drawtext to be able to plot the entire path or the
 >> basename of it respectively to the frame being processed.
 >>
 >> doc/filters: The documentation for drawtext was also updated and an 
usage
 >> example was added.
 >>
 >> Fixes #2874.
 >>
 >> Signed-off-by: Alexandre Heitor Schmidt <alexandre.schmidt@gmail.com>
 >> ---
 >>  doc/filters.texi      | 13 +++++++++++++
 >>  fftools/ffmpeg.c      | 12 ++++++++++++
 >>  libavcodec/avcodec.h  |  8 ++++++++
 >>  libavcodec/avpacket.c |  1 +
 >>  libavformat/img2dec.c |  9 +++++++++
 >>  5 files changed, 43 insertions(+)
 >
 > doc/filters.texi:9885: misplaced {
 > doc/filters.texi:9885: misplaced }
 > make: *** [doc/ffprobe-all.html] Error 1
 > make: *** Waiting for unfinished jobs....
 > doc/filters.texi:9885: misplaced {
 > doc/filters.texi:9885: misplaced }
 > make: *** [doc/ffplay-all.html] Error 1
 > doc/filters.texi:9885: misplaced {
 > doc/filters.texi:9885: misplaced }
 > make: *** [doc/ffmpeg-all.html] Error 1
 > doc/filters.texi:9885: misplaced {
 > doc/filters.texi:9885: misplaced }
 > make: *** [doc/ffmpeg-filters.html] Error 1
 >
 > [...]

I saw the problem... git messed up the @item and @example tags in docs. 
:S I'll find out why and re-submit the patch. I have to redo it anyway 
to use AV_PKT_DATA_STRINGS_METADATA, as suggested by Marton Balint.

Alex.
diff mbox

Patch

diff --git a/doc/filters.texi b/doc/filters.texi
index 93f54a2e1e..d984efb73b 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -9726,6 +9726,12 @@  printed by running @code{ffprobe -show_frames}.
 String metadata generated in filters leading to
 the drawtext filter are also available.
 
+There are two special metadata fields (@var{source_path} and @var{source_basename})
+which can be used when input format has a file corresponding to each frame, such
+as @var{image2}. @var{source_path} will output the entire path to the filename
+which generated the frame in question, while @var{source_basename} outputs the
+equivalent to @code{basename(source_path)}.
+
 @item n, frame_num
 The frame number, starting from 0.
 
@@ -9872,6 +9878,13 @@  drawtext=fontfile=FreeSans.ttf:text=DOG:fontsize=24:x=10:y=20+24-max_glyph_a,
 drawtext=fontfile=FreeSans.ttf:text=cow:fontsize=24:x=80:y=20+24-max_glyph_a
 @end example
 
+@item
+Plot special @var{source_basename} metadata, extracted from each input frame, or
+the string "NA" if the metadata is not defined.
+@example
+drawtext="fontsize=20:fontcolor=white:fontfile=FreeSans.ttf:text='%{metadata\:source_basename\:NA}':x=10:y=10"
+@end example
+
 @end itemize
 
 For more information about libfreetype, check:
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 27f68933f8..9285f86a81 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -2375,6 +2375,18 @@  static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_
     if (ret < 0)
         *decode_failed = 1;
 
+    /**
+     * Set filename as a frame metadata, if it's not empty. This will allow filters
+     * like drawtext to use this information for cases like image2, where each frame
+     * corresponds to a file.
+     */
+    if (pkt) {
+        if ( pkt->source_filename != NULL ) {
+            av_dict_set(&decoded_frame->metadata, "source_path", pkt->source_filename, 0);
+            av_dict_set(&decoded_frame->metadata, "source_basename", av_basename(pkt->source_filename), 0);
+        }
+    }
+
     // The following line may be required in some cases where there is no parser
     // or the parser does not has_b_frames correctly
     if (ist->st->codecpar->video_delay < ist->dec_ctx->has_b_frames) {
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 119b32dc1f..4e285f4dd8 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1511,6 +1511,14 @@  typedef struct AVPacket {
     attribute_deprecated
     int64_t convergence_duration;
 #endif
+
+    /**
+     * In cases where the packet corresponds to the contents of one single
+     * file, like when image2 is used, this is set to the source filename,
+     * so it can be used by filters like drawtext, to plot the source
+     * filename on the frame.
+     */
+    char *source_filename;
 } AVPacket;
 #define AV_PKT_FLAG_KEY     0x0001 ///< The packet contains a keyframe
 #define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
index 858f827a0a..c357e2fbac 100644
--- a/libavcodec/avpacket.c
+++ b/libavcodec/avpacket.c
@@ -46,6 +46,7 @@  FF_ENABLE_DEPRECATION_WARNINGS
     pkt->buf                  = NULL;
     pkt->side_data            = NULL;
     pkt->side_data_elems      = 0;
+    pkt->source_filename      = NULL;
 }
 
 AVPacket *av_packet_alloc(void)
diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
index f8b4a655a5..02119d89fc 100644
--- a/libavformat/img2dec.c
+++ b/libavformat/img2dec.c
@@ -485,6 +485,15 @@  int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt)
 
     if (s->is_pipe)
         pkt->pos = avio_tell(f[0]);
+    else {
+        // Set the filename which corresponds to this packet.
+        pkt->source_filename = av_malloc(strlen(filename));
+        if (!pkt->source_filename) {
+            av_log(NULL, AV_LOG_FATAL, "Failed to allocate source_filename\n");
+            return AVERROR(ENOMEM);
+        }
+        pkt->source_filename = av_asprintf("%s", filename);
+    }
 
     pkt->size = 0;
     for (i = 0; i < 3; i++) {