From patchwork Sun Jan 19 21:41:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 17426 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 262C144A255 for ; Sun, 19 Jan 2020 23:48:11 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0B48168B25C; Sun, 19 Jan 2020 23:48:11 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qt1-f179.google.com (mail-qt1-f179.google.com [209.85.160.179]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E2A94687FEB for ; Sun, 19 Jan 2020 23:48:04 +0200 (EET) Received: by mail-qt1-f179.google.com with SMTP id c24so15426434qtp.5 for ; Sun, 19 Jan 2020 13:48:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=g2xVJBO/UMMS48DV1OSDrmvN056qNPiHWYpgzaALkaE=; b=brHb8O9Vcym694hCDxLV3A5rJ+MhIaZ8Cf89sH5TdUMhxo9BdidOvj67XEMB9++BKK hM9p6VBrD1TxfKvg2gYDKmMD4UW/AY+vC8OUMgwhUz+b+hVsS71a7LbRqUsPOaciBnGN BhuxceuJqLngHrMSY/1BkquVJ0wmRpj4GMRDtQyg7zqrIR89LVU/q50gI6tv69RaCpoG O8srAUqL+QNnM4zLmP+ca0QppJPyl/6ChhfgpcOaISw3PGObjnN5xj+4DEDgp3iP6R/7 +pviQiYxTp2LXiPK5eeYGTCi3mWCSH8fdKMKMUDEgcclbKUfcG5u3/7UXsd3FnjHnPjg dy3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=g2xVJBO/UMMS48DV1OSDrmvN056qNPiHWYpgzaALkaE=; b=semizZCutv++MemypA6D6w79jHg8g2DpKpWYaVcQD18F+Ikmn05ZLqTyfFeQyQ3uEi jmPbUlZFeJ0+CWbR4ncnMgV7nVHTyhGIcsyQAZZAFwXOstAoayV2wVb9tl7VWlONXXAi TFAjwq70QuWQ+lVpwLg8JNdhRZ9rhI5WBqiYPyC86RnR6K0LwxSf4jF9CmHVdhVcBDTU ptuXVF+TDfn7t0WXb6PfQecN1XUMHpbING9mzZkFmtLTANY+uZSJsOkN8ZYU0OC1xRb1 d5KnzvsJQU1HZB+u1g0mo0WKgoOGDtdhzyfp5kq3qyjPkQ2tTq2WUTcQ1vu/XqrFux03 atuw== X-Gm-Message-State: APjAAAU9e2MWBjilL2Loh3O3i5VMvofOIj9kCMasOA7o3vOvrNyamsrW FMf612VfC/TKlm3kxmWPtSwJJVyN2Ig= X-Google-Smtp-Source: APXvYqxzZkZdcJ6j5hJWyFW9Ggo3UH7Q+4B0U7kOMk5qqRIlpxUudXg92d5j07WYQDszLeMA93EgLg== X-Received: by 2002:ac8:6153:: with SMTP id d19mr17447821qtm.18.1579470155800; Sun, 19 Jan 2020 13:42:35 -0800 (PST) Received: from localhost.localdomain ([181.23.86.46]) by smtp.gmail.com with ESMTPSA id z15sm5860616qtv.56.2020.01.19.13.42.35 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Jan 2020 13:42:35 -0800 (PST) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Sun, 19 Jan 2020 18:41:59 -0300 Message-Id: <20200119214200.2369-2-jamrial@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200119214200.2369-1-jamrial@gmail.com> References: <20200119214200.2369-1-jamrial@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/3] avformat/dashenc: add Trick Mode support for AdaptationSets X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: James Almer --- doc/muxers.texi | 2 ++ libavformat/dashenc.c | 68 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index 05bf483ba5..dfe858c412 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -286,6 +286,8 @@ For example, -adaptation_sets "id=0,descriptor=ldash && as->max_frag_duration) avio_printf(out, "\t\t\t\n", as->max_frag_duration); + if (as->trick_idx >= 0) + avio_printf(out, "\t\t\t\n", as->id, as->trick_idx); role = av_dict_get(as->metadata, "role", NULL, 0); if (role) avio_printf(out, "\t\t\t\n", role->value); @@ -849,6 +853,13 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind avio_printf(out, " sar=\"%d:%d\"", os->sar.num, os->sar.den); if (st->avg_frame_rate.num && av_cmp_q(as->min_frame_rate, as->max_frame_rate) < 0) avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den); + if (as->trick_idx >= 0) { + AdaptationSet *tas = &c->as[as->trick_idx]; + if (!as->ambiguous_frame_rate && !tas->ambiguous_frame_rate) + avio_printf(out, " maxPlayoutRate=\"%d\"", FFMAX((int)av_q2d(av_div_q(tas->min_frame_rate, as->min_frame_rate)), 1)); + } + if (!os->coding_dependency) + avio_printf(out, " codingDependency=\"false\""); avio_printf(out, ">\n"); } else { avio_printf(out, "\t\t\t\n", @@ -892,6 +903,7 @@ static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMed memset(*as, 0, sizeof(**as)); (*as)->media_type = type; (*as)->frag_type = -1; + (*as)->trick_idx = -1; return 0; } @@ -942,7 +954,8 @@ static int parse_adaptation_sets(AVFormatContext *s) // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on // option id=0,descriptor=descriptor_str,streams=0,1,2 and so on - // option id=0,seg_duration=2.5,frag_duration=0.5,streams=0,1,2 and so on + // option id=0,seg_duration=2.5,frag_duration=0.5,streams=0,1,2 + // option id=1,trick_id=0,seg_duration=10,frag_type=none,streams=3,4,5 and so on // descriptor is useful to the scheme defined by ISO/IEC 23009-1:2014/Amd.2:2015 // descriptor_str should be a self-closing xml tag. // seg_duration and frag_duration have the same syntax as the global options of @@ -1028,6 +1041,20 @@ static int parse_adaptation_sets(AVFormatContext *s) return AVERROR(EINVAL); } p += n; + if (*p) + p++; + state = parse_default; + } else if ((state != new_set) && av_strstart(p, "trick_id=", &p)) { + char trick_id_str[10], *end_str; + + n = strcspn(p, ","); + snprintf(trick_id_str, sizeof(trick_id_str), "%.*s", n, p); + p += n; + + as->trick_idx = strtol(trick_id_str, &end_str, 10); + if (trick_id_str == end_str || as->trick_idx < 0) + return AVERROR(EINVAL); + if (*p) p++; state = parse_default; @@ -1089,6 +1116,22 @@ end: return AVERROR(EINVAL); } } + + // check references for trick mode AdaptationSet + for (i = 0; i < c->nb_as; i++) { + as = &c->as[i]; + if (as->trick_idx < 0) + continue; + for (n = 0; n < c->nb_as; n++) { + if (c->as[n].id == as->trick_idx) + break; + } + if (n >= c->nb_as) { + av_log(s, AV_LOG_ERROR, "reference AdaptationSet id \"%d\" not found for trick mode AdaptationSet id \"%d\"\n", as->trick_idx, as->id); + return AVERROR(EINVAL); + } + } + return 0; } @@ -1479,7 +1522,8 @@ static int dash_init(AVFormatContext *s) return ret; // We only want to parse frame headers os->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; - } + } else + os->coding_dependency = 1; if (c->single_file) { if (os->single_file_name) @@ -2017,6 +2061,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) if (!os->availability_time_offset && ((os->frag_type == FRAG_TYPE_DURATION && os->seg_duration != os->frag_duration) || (os->frag_type == FRAG_TYPE_EVERY_FRAME && pkt->duration))) { + AdaptationSet *as = &c->as[os->as_idx - 1]; int64_t frame_duration = 0; switch (os->frag_type) { @@ -2041,6 +2086,16 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) seg_end_duration = os->seg_duration; } + if (os->parser) { + uint8_t *data; + int size; + av_parser_parse2(os->parser, os->parser_avctx, + &data, &size, pkt->data, pkt->size, + pkt->pts, pkt->dts, pkt->pos); + + os->coding_dependency |= os->parser->pict_type != AV_PICTURE_TYPE_I; + } + if (pkt->flags & AV_PKT_FLAG_KEY && os->packets_written && av_compare_ts(elapsed_duration, st->time_base, seg_end_duration, AV_TIME_BASE_Q) >= 0) { @@ -2088,14 +2143,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && os->frag_type == FRAG_TYPE_PFRAMES && os->packets_written) { - uint8_t *data; - int size; - av_assert0(os->parser); - av_parser_parse2(os->parser, os->parser_avctx, - &data, &size, pkt->data, pkt->size, - pkt->pts, pkt->dts, pkt->pos); - if ((os->parser->pict_type == AV_PICTURE_TYPE_P && st->codecpar->video_delay && !(os->last_flags & AV_PKT_FLAG_KEY)) || @@ -2114,7 +2162,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) } } - if (pkt->flags & AV_PKT_FLAG_KEY && (os->packets_written || os->nb_segments) && !os->gop_size) { + if (pkt->flags & AV_PKT_FLAG_KEY && (os->packets_written || os->nb_segments) && !os->gop_size && as->trick_idx < 0) { os->gop_size = os->last_duration + av_rescale_q(os->total_pkt_duration, st->time_base, AV_TIME_BASE_Q); c->max_gop_size = FFMAX(c->max_gop_size, os->gop_size); }