From patchwork Sat Dec 21 18:02:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 16917 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 9E991448C81 for ; Sat, 21 Dec 2019 20:11:48 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 858FB68A9FD; Sat, 21 Dec 2019 20:11:48 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-io1-f68.google.com (mail-io1-f68.google.com [209.85.166.68]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 9BD9468A613 for ; Sat, 21 Dec 2019 20:11:41 +0200 (EET) Received: by mail-io1-f68.google.com with SMTP id v3so12592917ioj.5 for ; Sat, 21 Dec 2019 10:11:41 -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=FU2u2oIE7IJkm9MRFtmi7mo+/NV47L9MAesuu0YdHLE=; b=ID9tEPrXW2r2gYFyTO869f4SmI2jmCHukNQodQotP91LEzJbw8ENH24mJhmlR8IMXK n20RZgtxfk74H3lGAAaUcWgqAkKc/lkGQ8IHqxPCxWwcfFoVgkTsMtOb81CGGd+HxV2w vYzPInhAvSA4bzUd5jFPT19P/VqkMOibYJs0PQnwFd8ql7hurA5PQKUqnNaBRNNtw/ma H49uZ9VgW+JkDyBXDZAAJBjpgmhberOZfxdxUl9TPL6bfwO+NqYgIusk9dfRn86wtcS2 3NllnH+nPoiDW7omHAdRTupu/RgmBWv2rzRkYcnkub+6JugIGhHggXfnm/7zDe587loQ dVcQ== 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=FU2u2oIE7IJkm9MRFtmi7mo+/NV47L9MAesuu0YdHLE=; b=ZRLqtcV1L1k4x3iIXRjJo5aq6kTGIAViTV3VZDfts4ypH+Nr41JLaaAsoFq3vnXWIW eX5QjbkC6l0yD/VX/hMXRdHbIvtS5nUCM+RXL/C+vsvG87KWLTBZ+M0VHdQZJ18QzS4/ 8fDQnsUWIe2uVVUmEAZ8T8TT/ScPELS2oubFmiXseJdV/cT63qvrKS4VFT3o9c+wM+KG +Rcvu26s5bIk1b5ZlChHW1gw70sGJQhe8P6FFD51tt29dH5C0qmo4OGLNVfTd/jdSAQy f25rUnCTBmOmHz2KVRUXUeTkhGOEMnyEH6QJquDxBnVgSBDl3q+ZxffcYeUgHYed193M fxLA== X-Gm-Message-State: APjAAAXf+4TAQVKZfn1zyuhOMNZUiLEiyJatn4hRAFNw/jLdWbgWyslD CEN2GETQJNgdlCWBs1vmDmhYG2ru X-Google-Smtp-Source: APXvYqxUc6Er/aOLoOs1/s7dBu6C2rIj5K44Bzt+NWDQPJJ6p7iSRRux37jbtSEK8TIM8LGAk1bODQ== X-Received: by 2002:a63:4d1b:: with SMTP id a27mr21374199pgb.352.1576951410823; Sat, 21 Dec 2019 10:03:30 -0800 (PST) Received: from localhost.localdomain ([191.83.216.116]) by smtp.gmail.com with ESMTPSA id s196sm18223564pfs.136.2019.12.21.10.03.29 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 21 Dec 2019 10:03:30 -0800 (PST) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Sat, 21 Dec 2019 15:02:40 -0300 Message-Id: <20191221180252.6091-3-jamrial@gmail.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20191221180252.6091-1-jamrial@gmail.com> References: <20191221180252.6091-1-jamrial@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 03/15] avformat/dashenc: allow splitting fragments following P-Frame reordering 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" Currently implemented by using the pic_type value from AV_PKT_DATA_QUALITY_STATS packet side data. Signed-off-by: James Almer --- libavformat/dashenc.c | 45 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 05f2700d16..82941eb459 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -62,6 +62,7 @@ enum { FRAG_TYPE_NONE = 0, FRAG_TYPE_EVERY_FRAME, FRAG_TYPE_DURATION, + FRAG_TYPE_PFRAMES, FRAG_TYPE_NB }; @@ -100,6 +101,7 @@ typedef struct OutputStream { Segment **segments; int64_t first_pts, start_pts, max_pts; int64_t last_dts, last_pts; + int last_flags; int bit_rate; SegmentType segment_type; /* segment type selected for this particular stream */ const char *format_name; @@ -115,6 +117,7 @@ typedef struct OutputStream { char temp_path[1024]; double availability_time_offset; int total_pkt_size; + int total_pkt_duration; int muxer_overhead; int frag_type; } OutputStream; @@ -1362,6 +1365,8 @@ static int dash_init(AVFormatContext *s) av_log(s, AV_LOG_WARNING, "frag_type set to duration for stream %d but no frag_duration set\n", i); os->frag_type = c->streaming ? FRAG_TYPE_EVERY_FRAME : FRAG_TYPE_NONE; } + if (os->frag_type == FRAG_TYPE_PFRAMES && st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) + os->frag_type = c->streaming ? FRAG_TYPE_EVERY_FRAME : FRAG_TYPE_NONE; if (os->segment_type == SEGMENT_TYPE_MP4) { if (c->streaming) @@ -1430,6 +1435,8 @@ static int dash_init(AVFormatContext *s) av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n"); return AVERROR(EINVAL); } + if (!c->has_video && c->frag_type == FRAG_TYPE_PFRAMES) + av_log(s, AV_LOG_WARNING, "no video stream and P-frame fragmentation set\n"); c->nr_of_streams_flushed = 0; @@ -1698,6 +1705,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) av_rescale_q(os->max_pts - os->start_pts, st->time_base, AV_TIME_BASE_Q); os->total_pkt_size = 0; + os->total_pkt_duration = 0; if (!os->bit_rate) { // calculate average bitrate of first segment @@ -1799,6 +1807,9 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) sizeof(c->availability_start_time)); } + if (!os->packets_written) + os->availability_time_offset = 0; + if (!os->availability_time_offset && (os->frag_type == FRAG_TYPE_NONE || os->frag_type == FRAG_TYPE_DURATION || @@ -1866,11 +1877,40 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) os->max_pts = pkt->pts + pkt->duration; else os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration); - os->packets_written++; - os->total_pkt_size += pkt->size; + + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + os->frag_type == FRAG_TYPE_PFRAMES && + os->packets_written) { + int side_size, pic_type = 0; + uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, &side_size); + if (side && side_size > 4) + pic_type = side[4]; + + if ((pic_type == AV_PICTURE_TYPE_P && + st->codecpar->video_delay && + !(os->last_flags & AV_PKT_FLAG_KEY)) || + pkt->flags & AV_PKT_FLAG_KEY) { + ret = av_write_frame(os->ctx, NULL); + if (ret < 0) + return ret; + + if (!os->availability_time_offset) { + int64_t frag_duration = av_rescale_q(os->total_pkt_duration, st->time_base, + AV_TIME_BASE_Q); + os->availability_time_offset = ((double) os->seg_duration - + frag_duration) / AV_TIME_BASE; + } + } + } + if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0) return ret; + os->packets_written++; + os->total_pkt_size += pkt->size; + os->total_pkt_duration += pkt->duration; + os->last_flags = pkt->flags; + if (!os->init_range_length) flush_init_segment(s, os); @@ -1997,6 +2037,7 @@ static const AVOption options[] = { { "none", "one fragment per segment", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_NONE }, 0, UINT_MAX, E, "frag_type"}, { "every_frame", "fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_EVERY_FRAME }, 0, UINT_MAX, E, "frag_type"}, { "duration", "fragment at specific time intervals", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_DURATION }, 0, UINT_MAX, E, "frag_type"}, + { "pframes", "fragment at keyframes and following P-Frame reordering (Video only, experimental)", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_PFRAMES }, 0, UINT_MAX, E, "frag_type"}, { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },