From patchwork Tue Aug 1 06:33:49 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rodger Combs X-Patchwork-Id: 4564 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.1.85 with SMTP id 82csp3301172vsb; Mon, 31 Jul 2017 23:41:20 -0700 (PDT) X-Received: by 10.28.49.134 with SMTP id x128mr531526wmx.111.1501569680805; Mon, 31 Jul 2017 23:41:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1501569680; cv=none; d=google.com; s=arc-20160816; b=WyY1o7OCfALfGBmpfG5jW/Ke7CJiVEo47CEK67h5NSstHZyesC3nZJ3rObz4tdHrjF RqJCvPf6dXhZbEDuvwBm8VLMuO4tIGkxvELE3YeNBOtHotB+HXLAk9kugDjs6ATWpNTH LLcqoWr9Xi9P2cUaVKnlyDr8uLDAOI43lNHQYjivUwY6mv5YlcqReTaW51OSeiyWEfaO XdTHnfTiLNYa7TAy1CNRrFIATWsXg9mY833RXn20CKPu95/5A+z+TWqIPF/AXOI1L5Uq Qz7AIaDQ8pF9rzE/WVca5IKO+97wW38j4z/fCODYs2F+EJzYJ8ztDSPE076YHzM5R5T8 nZkA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=93KUSyJI2cJOVdCRYuNo4+A3DK/ySnh6iSzVuaXUZJk=; b=oI1vldptTBtS/4e7EAkTTpYEe3RPGh65e7ISAEyDec+p40C4mhjASFUTrhf+TNwSTT ftakybFhdbUzR1BU4dGZw4RRxrYjNJ3E1bScuBzgY3vWQfMPUUhNBbS0FO4Bcv9oLRdr luUyP+xwSvMta6pKo/Hhn0pqvuID2k9afDfGoux5RRt745xsw4RGh7zWbh2PGb813qf6 eT9DN7gtT38h+Xgn7esemlH3hC62trYBDUXriaPB++P2TpPa27d87iHMTZf1SV4ETGfl gFcdv/6GCxqB2SBGSAUfCXzPvzazu4VlR/wRs+Eyz5NMJVS6KkZq1eBF1hTX+xgW7zbG N4+A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=OKZh+imD; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id 198si597703wmm.132.2017.07.31.23.41.20; Mon, 31 Jul 2017 23:41:20 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=OKZh+imD; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 8401B68A325; Tue, 1 Aug 2017 09:41:15 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-it0-f65.google.com (mail-it0-f65.google.com [209.85.214.65]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 3ECAB68A316 for ; Tue, 1 Aug 2017 09:41:08 +0300 (EEST) Received: by mail-it0-f65.google.com with SMTP id r9so858974ita.3 for ; Mon, 31 Jul 2017 23:41:11 -0700 (PDT) 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; bh=63eF7WMIG/F+FZovIOJIZCSuxPvFiBsBEg6bo4taAMg=; b=OKZh+imDELAofUExHYWkwlC3M0Wo+CrJnLVAOa92SO87W3wH4oyKYB2FYEXVhaGvw+ Nxbm55qlF8CwSsaeVYc4t8h9e52ReGXLvWv8Dj2CGwHjTdAfn4FIks7dlhRVT+8P87eI kBR7cJ+ShIubD+wuuhusaKL/KgrLz+wg/jYC9Ks0h6b94ckkz6ZYeH48DG3jqy0RZ/mS lRkKOAdRIDC4I4qWJaqEpZ/Ra+mOLLduQ80UpDAEskPAod7JocBFr24PrMbGRVkTln/z iLo4qTf/3lkHaGtXgRAxFxrfZg0Zx30m2Pt6I4W1SoYzukkkuLu+5gIHzqHsdEfKVz18 sSwg== 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; bh=63eF7WMIG/F+FZovIOJIZCSuxPvFiBsBEg6bo4taAMg=; b=o1SG9PRiHq0IBKl0PNDemutiubJnGj89oK79NSPceMNDr1x9oBzSDK+gxIJmFman87 VGewwP3rHD6SSnfD7p3UuQQBw9Xe9k/Vb07iYfKM4x1lsH7YhrokY1i+L0qq+II1Hhmk zhELNg1mQQJ71weeddMlVEkKlhZxnDGFLdpYNFhSmIT4Jclp8CLOcIN2DU7rVq3JG9K9 ZxOe7+JPgkb/hcTESg4dBhmV4ttRw3xwIW3fqNssUlM+3IRtD4nnjFBJcF5K3WPuGj0a 98QESLVJnM55E8fjILxewO4zz71sNaG7uH/cfMva7Nf4e3VMkpu9r8tuebi57IOHO9M/ ts3Q== X-Gm-Message-State: AIVw112czq1MBu1dWjq84gPRGpOQNhF2qyIq6aYsjsfouAalM+YGsF0d z/FL9ZnuDFbb7tzp9tg= X-Received: by 10.36.87.5 with SMTP id u5mr611357ita.151.1501569238516; Mon, 31 Jul 2017 23:33:58 -0700 (PDT) Received: from rcombs-NAS.hsd1.il.comcast.net. (c-73-110-121-59.hsd1.il.comcast.net. [73.110.121.59]) by smtp.gmail.com with ESMTPSA id 186sm13887294iow.44.2017.07.31.23.33.57 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 31 Jul 2017 23:33:57 -0700 (PDT) From: Rodger Combs To: ffmpeg-devel@ffmpeg.org Date: Tue, 1 Aug 2017 01:33:49 -0500 Message-Id: <1501569234-29896-2-git-send-email-rodger.combs@gmail.com> X-Mailer: git-send-email 2.6.4 In-Reply-To: <1501569234-29896-1-git-send-email-rodger.combs@gmail.com> References: <1501569234-29896-1-git-send-email-rodger.combs@gmail.com> Subject: [FFmpeg-devel] [PATCH 2/7] lavf/segment: add option to segment by chapter 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 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" --- doc/muxers.texi | 6 +++++ libavformat/segment.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++---- libavformat/version.h | 2 +- 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index 94472ce..23ef2e7 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1538,6 +1538,12 @@ This option specifies to start a new segment whenever a reference stream key frame is found and the sequential number (starting from 0) of the frame is greater or equal to the next value in the list. +@item segment_chapters @var{1|0} +Split each chapter into its own segment. Metadata from the chapters +will be written to the corresponding segments. If this option is selected +and the filename contains tokens in the format @code{$varname$}, they +will be replaced by the corresponding metadata values. + @item segment_wrap @var{limit} Wrap around segment index once it reaches @var{limit}. diff --git a/libavformat/segment.c b/libavformat/segment.c index 0e8bcdd..590f62b 100644 --- a/libavformat/segment.c +++ b/libavformat/segment.c @@ -106,6 +106,8 @@ typedef struct SegmentContext { int frame_count; ///< total number of reference frames int segment_frame_count; ///< number of reference frames in the segment + int split_chapters; ///< split on chapter markers + int64_t time_delta; int individual_header_trailer; /**< Set by a private option. */ int write_header_trailer; /**< Set by a private option. */ @@ -186,6 +188,43 @@ static int segment_mux_init(AVFormatContext *s) return 0; } +static int replace_variables(AVFormatContext *oc) +{ + char name[sizeof(oc->filename)]; + char *p = name; + char *out = oc->filename; + strncpy(name, oc->filename, sizeof(name)); + while (*p) { + char c = *p++; + if (c == '$') { + if (*p == '$') { + p++; + goto append; + } else { + int len; + const char *val; + const AVDictionaryEntry *e; + int end = strcspn(p, "$"); + if (p[end] == '\0') + continue; + p[end] = '\0'; + e = av_dict_get(oc->metadata, p, NULL, 0); + val = e ? e->value : "(unknown)"; + len = strlen(val); + strncpy(out, val, oc->filename + sizeof(oc->filename) - 1 - out); + out = FFMIN(oc->filename + sizeof(oc->filename) - 1, out + len); + p += end + 1; + } + } else { +append: + if (out - oc->filename < sizeof(oc->filename) - 1) + *out++ = c; + } + } + *out = '\0'; + return 0; +} + static int set_segment_filename(AVFormatContext *s) { SegmentContext *seg = s->priv_data; @@ -210,6 +249,9 @@ static int set_segment_filename(AVFormatContext *s) return AVERROR(EINVAL); } + if (seg->split_chapters) + replace_variables(oc); + /* copy modified name in list entry */ size = strlen(av_basename(oc->filename)) + 1; if (seg->entry_prefix) @@ -236,6 +278,8 @@ static int segment_start(AVFormatContext *s, int write_header) if ((err = segment_mux_init(s)) < 0) return err; oc = seg->avf; + if (seg->split_chapters && seg->segment_count < s->nb_chapters && (err = av_dict_copy(&oc->metadata, s->chapters[seg->segment_count]->metadata, 0)) < 0) + return err; } seg->segment_idx++; @@ -659,10 +703,14 @@ static int seg_init(AVFormatContext *s) "you can use output_ts_offset instead of it\n"); } - if (!!seg->time_str + !!seg->times_str + !!seg->frames_str > 1) { + if (seg->segment_idx < 0) + seg->segment_idx = seg->split_chapters; + + if (!!seg->time_str + !!seg->times_str + !!seg->frames_str + !!seg->split_chapters > 1) { av_log(s, AV_LOG_ERROR, - "segment_time, segment_times, and segment_frames options " - "are mutually exclusive, select just one of them\n"); + "segment_time, segment_times, segment_frames, and " + "segment_chapters options are mutually exclusive; " + "select just one of them\n"); return AVERROR(EINVAL); } @@ -672,7 +720,7 @@ static int seg_init(AVFormatContext *s) } else if (seg->frames_str) { if ((ret = parse_frames(s, &seg->frames, &seg->nb_frames, seg->frames_str)) < 0) return ret; - } else { + } else if (!seg->split_chapters) { /* set default value if not specified */ if (!seg->time_str) seg->time_str = av_strdup("2"); @@ -739,6 +787,9 @@ static int seg_init(AVFormatContext *s) if ((ret = segment_mux_init(s)) < 0) return ret; + if (seg->split_chapters && s->nb_chapters && (ret = av_dict_copy(&seg->avf->metadata, s->chapters[0]->metadata, 0)) < 0) + return ret; + if ((ret = set_segment_filename(s)) < 0) return ret; oc = seg->avf; @@ -860,6 +911,9 @@ calc_times: } else if (seg->frames) { start_frame = seg->segment_count < seg->nb_frames ? seg->frames[seg->segment_count] : INT_MAX; + } else if (seg->split_chapters) { + end_pts = seg->segment_count + 1 < s->nb_chapters ? + av_rescale_q(s->chapters[seg->segment_count]->end, s->chapters[seg->segment_count]->time_base, AV_TIME_BASE_Q) : INT64_MAX; } else { if (seg->use_clocktime) { int64_t avgt = av_gettime(); @@ -1042,9 +1096,10 @@ static const AVOption options[] = { { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 0, E }, { "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, { "segment_frames", "set segment split frame numbers", OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, + { "segment_chapters", "split segments on chapter markers", OFFSET(split_chapters), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E }, { "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, { "segment_list_entry_prefix", "set base url prefix for segments", OFFSET(entry_prefix), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, - { "segment_start_number", "set the sequence number of the first segment", OFFSET(segment_idx), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, + { "segment_start_number", "set the sequence number of the first segment", OFFSET(segment_idx), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, E }, { "segment_wrap_number", "set the number of wrap before the first segment", OFFSET(segment_idx_wrap_nb), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, { "strftime", "set filename expansion with strftime at segment creation", OFFSET(use_strftime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, { "increment_tc", "increment timecode between each segment", OFFSET(increment_tc), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, diff --git a/libavformat/version.h b/libavformat/version.h index a8cf4c1..4d12f5b 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -33,7 +33,7 @@ // Also please add any ticket numbers that you believe might be affected here #define LIBAVFORMAT_VERSION_MAJOR 57 #define LIBAVFORMAT_VERSION_MINOR 77 -#define LIBAVFORMAT_VERSION_MICRO 100 +#define LIBAVFORMAT_VERSION_MICRO 101 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \