On 7/18/2016 9:29 PM, Soft Works wrote:
> From a04ec6e7ad1a96013ea1f49fa790abc6e6281ca3 Mon Sep 17 00:00:00 2001
> From: softworkz <softwo...@hotmail.com>
> Date: Sun, 17 Jul 2016 04:19:41 +0200
> Subject: [PATCH] avformat/matroskaenc: Write duration early during 
> mkv_write_header (Rev #2)
> 
> Revised patch: Fixes doubled header writing, checked FATE running without 
> errors
> 
> This commit addresses the following scenario:
> 
> we are using ffmpeg to transcode or remux mkv (or something else) to mkv. The 
> result is being streamed on-the-fly to an HTML5 client (streaming starts 
> while ffmpeg is still running). The problem here is that the client is unable 
> to detect the duration because the duration is only written to the mkv at the 
> end of the transcoding/remoxing process. In matroskaenc.c, the duration is 
> only written during mkv_write_trailer but not during mkv_write_header.
> 
> The approach:
> 
> FFMPEG is currently putting quite some effort to estimate the durations of 
> source streams, but in many cases the source stream durations are still left 
> at 0 and these durations are nowhere mapped to or used for output streams. As 
> much as I would have liked to deduct or estimate output durations based on 
> input stream durations - I realized that this is a hard task (as Nicolas 
> already mentioned in a previous conversation). It would involve changes to 
> the duration calculation/estimation/deduction for input streams and 
> propagating these durations to output streams or the output context in a 
> correct way.
> So I looked for a simple and small solution with better chances to get 
> accepted. In webmdashenc.c I found that a duration is written during 
> write_header and this duration is taken from the streams' metadata, so I 
> decided for a similar approach.
> 
> And here's what it does:
> 
> At first it is checking the duration of the AVFormatContext. In typical cases 
> this value is not set, but: It is set in cases where the user has specified a 
> recording_time or an end_time via the -t or -to parameters.
> Then it is looking for a DURATION metadata field in the metadata of the 
> output context (AVFormatContext::metadata). This would only exist in case the 
> user has explicitly specified a metadata DURATION value from the command line.
> Then it is iterating all streams looking for a "DURATION" metadata (this 
> works unless the option "-map_metadata -1" has been specified) and determines 
> the maximum value.
> The precendence is as follows: 1. Use duration of AVFormatContext - 2. Use 
> explicitly specified metadata duration value - 3. Use maximum (mapped) 
> metadata duration over all streams.
> 
> To test this:
> 
> 1. With explicit recording time:
> ffmpeg -i file:"src.mkv" -loglevel debug -t 01:38:36.000 -y "dest.mkv"
> 
> 2. Take duration from metadata specified via command line parameters:
> ffmpeg -i file:"src.mkv" -loglevel debug -map_metadata -1 -metadata 
> Duration="01:14:33.00" -y "dest.mkv"
> 
> 3. Take duration from mapped input metadata:
> ffmpeg -i file:"src.mkv" -loglevel debug -y "dest.mkv"
> 
> Regression risk:
> 
> Very low IMO because it only affects the header while ffmpeg is still 
> running. When ffmpeg completes the process, the duration is rewritten to the 
> header with the usual value (same like without this commit).
> 
> Signed-off-by: SoftWorkz <softwo...@hotmail.com>
> ---
>  libavformat/matroskaenc.c | 40 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
> index 53353bd..b872e84 100644
> --- a/libavformat/matroskaenc.c
> +++ b/libavformat/matroskaenc.c
> @@ -44,6 +44,7 @@
>  #include "libavutil/mastering_display_metadata.h"
>  #include "libavutil/mathematics.h"
>  #include "libavutil/opt.h"
> +#include "libavutil/parseutils.h"
>  #include "libavutil/random_seed.h"
>  #include "libavutil/rational.h"
>  #include "libavutil/samplefmt.h"
> @@ -1487,6 +1488,30 @@ static int mkv_write_attachments(AVFormatContext *s)
>      return 0;
>  }
>  
> +static int64_t get_metadata_duration(AVFormatContext *s)
> +{
> +    int i = 0;
> +    int64_t max = 0;
> +    int64_t us;
> +
> +    AVDictionaryEntry *explicitDuration = av_dict_get(s->metadata, 
> "DURATION", NULL, 0);
> +    if (explicitDuration && (av_parse_time(&us, explicitDuration->value, 1) 
> == 0) && us > 0) {
> +        av_log(s, AV_LOG_DEBUG, "get_metadata_duration found duration in 
> context metadata: %" PRId64 "\n", us);
> +        return us;
> +    }
> +
> +    for (i = 0; i < s->nb_streams; i++) {
> +        int64_t us;
> +        AVDictionaryEntry *duration = av_dict_get(s->streams[i]->metadata, 
> "DURATION", NULL, 0);
> +
> +        if (duration && (av_parse_time(&us, duration->value, 1) == 0))
> +            max = FFMAX(max, us);
> +    }
> +
> +    av_log(s, AV_LOG_DEBUG, "get_metadata_duration returned: %" PRId64 "\n", 
> max);
> +    return max;
> +}
> +
>  static int mkv_write_header(AVFormatContext *s)
>  {
>      MatroskaMuxContext *mkv = s->priv_data;
> @@ -1495,6 +1520,7 @@ static int mkv_write_header(AVFormatContext *s)
>      AVDictionaryEntry *tag;
>      int ret, i, version = 2;
>      int64_t creation_time;
> +    int64_t metadataDuration;
>  
>      if (!strcmp(s->oformat->name, "webm"))
>          mkv->mode = MODE_WEBM;
> @@ -1593,7 +1619,19 @@ static int mkv_write_header(AVFormatContext *s)
>      mkv->duration = 0;
>      mkv->duration_offset = avio_tell(pb);
>      if (!mkv->is_live) {
> -        put_ebml_void(pb, 11);              // assumes double-precision 
> float to be written
> +        metadataDuration = get_metadata_duration(s);
> +
> +        if (s->duration > 0) {
> +            int64_t scaledDuration = av_rescale(s->duration, 1000, 
> AV_TIME_BASE);
> +            put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration);
> +            av_log(s, AV_LOG_DEBUG, "Write early duration from recording 
> time = %" PRIu64 "\n", scaledDuration);
> +        } else if (metadataDuration > 0) {
> +            int64_t scaledDuration = av_rescale(metadataDuration, 1000, 
> AV_TIME_BASE);
> +            put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration);
> +            av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" 
> PRIu64 "\n", scaledDuration);
> +             } else {
> +                     put_ebml_void(pb, 11);              // assumes 
> double-precision float to be written
> +             }

Don't use tabs, use spaces like you did above. The git hooks
will reject the patch otherwise.

>      }
>      end_ebml_master(pb, segment_info);
>  
> 
> 
> 
> _______________________________________________
> 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

Reply via email to