From patchwork Sat Feb 4 17:55:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aman Karmani X-Patchwork-Id: 2422 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.89.21 with SMTP id n21csp1146574vsb; Sat, 4 Feb 2017 10:02:37 -0800 (PST) X-Received: by 10.223.154.114 with SMTP id z105mr2644788wrb.89.1486231357900; Sat, 04 Feb 2017 10:02:37 -0800 (PST) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id r1si36124233wra.91.2017.02.04.10.02.37; Sat, 04 Feb 2017 10:02:37 -0800 (PST) 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=@tmm1-net.20150623.gappssmtp.com; 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 Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 9A13368995F; Sat, 4 Feb 2017 20:02:32 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf0-f196.google.com (mail-pf0-f196.google.com [209.85.192.196]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 37486680A18 for ; Sat, 4 Feb 2017 20:02:26 +0200 (EET) Received: by mail-pf0-f196.google.com with SMTP id y143so3849542pfb.1 for ; Sat, 04 Feb 2017 10:02:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tmm1-net.20150623.gappssmtp.com; s=20150623; h=sender:from:to:cc:subject:date:message-id; bh=xYimwm4B7otviUm4XcYxuJsexZIikV4qpLvMCZRCRIs=; b=qNXiTgyaWFh3uktmu3+AZmT/1cLe/W5evuSpr1nCAzPdGzdt76Cyoy7OciN3db87Cd kVhaL5LPujMynKUAju5fjbODu4DcEpes1kRnRhQGOoETTScw5Sxyavffr0dp094CpaiY FFn1e5ZY+A2TPVEx6IlvXk5O6lD8SwVitAk0hXjhGMmUm3m44EAgI9U5pwD5p7FECqVz eY0HI8AJgXfyssYVCw8+k0OQ5I5ZqAtwQr0Aw0/cCGeDsX9hV9jmgO2qZzCcHNgSd3Np J6cIn5/J4SukoUm8SVl0T0PpG3yt2LRlubIpL0K5vHjJgFGaJfT/tKSXrBo3aQBXWPlt uZPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id; bh=xYimwm4B7otviUm4XcYxuJsexZIikV4qpLvMCZRCRIs=; b=NoASoaY6r+/V5J5sQSg5x271Tmua1eBwFtW6Ufo4DYulqvW7eMJeBPDRnXNJrtM+KH TVl5SfxrOjdPvkMOtWwjOAUZY86R3KZ0GifbVCTDZ5HNDXq0LrqPYTbb/sfuDn64rfMw MxqEDnGSr5kixfEFTTBDvxRvg2pgbn80tPoVaSXzaDo0S1HoTTThEgRLz8vJpaf/KSkC N4QmeEvWQupIt+lHMZrc1g9cDMD3hI0D3SKdJadERX5L2sn1xDSXdsJrIZifTsXn8oeF +EPzGvA/8f0XZ6Pz6sJYsruMTAkaHYdFeKTikskK8GpVsi0jsMljbMcthRjf9ACavVTx xBJg== X-Gm-Message-State: AIkVDXIJqOkab8fGj5AzfwKueXMdJVHj1iMdGxDieZYsTKlK2rNqYZ7Q2sz/jVwSM8sspA== X-Received: by 10.98.73.74 with SMTP id w71mr3900179pfa.52.1486230912827; Sat, 04 Feb 2017 09:55:12 -0800 (PST) Received: from tmm1-macbook.local.net (c-73-252-174-83.hsd1.ca.comcast.net. [73.252.174.83]) by smtp.gmail.com with ESMTPSA id u24sm76733335pfi.25.2017.02.04.09.55.11 (version=TLS1 cipher=AES128-SHA bits=128/128); Sat, 04 Feb 2017 09:55:11 -0800 (PST) From: Aman Gupta To: ffmpeg-devel@ffmpeg.org Date: Sat, 4 Feb 2017 09:55:06 -0800 Message-Id: <20170204175506.74792-1-ffmpeg@tmm1.net> X-Mailer: git-send-email 2.10.1 (Apple Git-78) Subject: [FFmpeg-devel] [PATCH v3] avformat/hlsenc: add hls_flag option to write segments to temporary file until complete 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 Cc: Aman Gupta MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Aman Gupta Adds a `-hls_flags +temp_file` which will write segment data to filename.tmp, and then rename to filename when the segment is complete. This patch is similar in spirit to one used in Plex's ffmpeg fork, and allows a transcoding webserver to ensure incomplete segment files are never served up accidentally. --- doc/muxers.texi | 5 +++++ libavformat/hlsenc.c | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/doc/muxers.texi b/doc/muxers.texi index 4372078..0d98805 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -656,6 +656,11 @@ Makes it possible to use segment duration (calculated in microseconds) as %%t i expression besides date/time values when use_localtime is on. To get fixed width numbers with trailing zeroes, %%0xt format is available where x is the required width. +@item temp_file +Write segment data to filename.tmp and rename to filename only once the segment is complete. A webserver +serving up segments can be configured to reject requests to *.tmp to prevent access to in-progress segments +before they have been added to the m3u8 playlist. + @example ffmpeg -i sample.mpeg \ -f hls -hls_time 3 -hls_list_size 5 \ diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index bd1e684..17d4fe4 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -76,6 +76,7 @@ typedef enum HLSFlags { HLS_SECOND_LEVEL_SEGMENT_INDEX = (1 << 8), // include segment index in segment filenames when use_localtime e.g.: %%03d HLS_SECOND_LEVEL_SEGMENT_DURATION = (1 << 9), // include segment duration (microsec) in segment filenames when use_localtime e.g.: %%09t HLS_SECOND_LEVEL_SEGMENT_SIZE = (1 << 10), // include segment size (bytes) in segment filenames when use_localtime e.g.: %%014s + HLS_TEMP_FILE = (1 << 11), } HLSFlags; typedef enum { @@ -416,6 +417,7 @@ static int hls_mux_init(AVFormatContext *s) return ret; oc = hls->avf; + oc->filename[0] = '\0'; oc->oformat = hls->oformat; oc->interrupt_callback = s->interrupt_callback; oc->max_delay = s->max_delay; @@ -815,6 +817,15 @@ static int hls_start(AVFormatContext *s) char *filename, iv_string[KEYSIZE*2 + 1]; int err = 0; + if ((c->flags & HLS_TEMP_FILE) && oc->filename[0] != 0) { + size_t len = strlen(oc->filename); + char final_filename[sizeof(oc->filename)]; + av_strlcpy(final_filename, oc->filename, len); + final_filename[len-4] = '\0'; + ff_rename(oc->filename, final_filename, s); + oc->filename[len-4] = '\0'; + } + if (c->flags & HLS_SINGLE_FILE) { av_strlcpy(oc->filename, c->basename, sizeof(oc->filename)); @@ -915,6 +926,10 @@ static int hls_start(AVFormatContext *s) set_http_options(&options, c); + if (c->flags & HLS_TEMP_FILE) { + av_strlcat(oc->filename, ".tmp", sizeof(oc->filename)); + } + if (c->key_info_file) { if ((err = hls_encryption_start(s)) < 0) goto fail; @@ -1364,6 +1379,15 @@ static int hls_write_trailer(struct AVFormatContext *s) ff_rename(old_filename, hls->avf->filename, hls); } + if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0] != 0) { + size_t len = strlen(oc->filename); + char final_filename[sizeof(oc->filename)]; + av_strlcpy(final_filename, oc->filename, len); + final_filename[len-4] = '\0'; + ff_rename(oc->filename, final_filename, s); + oc->filename[len-4] = '\0'; + } + if (vtt_oc) { if (vtt_oc->pb) av_write_trailer(vtt_oc); @@ -1406,6 +1430,7 @@ static const AVOption options[] = { {"hls_subtitle_path", "set path of hls subtitles", OFFSET(subtitle_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"}, {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"}, + {"temp_file", "write segment to temporary file and rename when complete", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_TEMP_FILE }, 0, UINT_MAX, E, "flags"}, {"delete_segments", "delete segment files that are no longer part of the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DELETE_SEGMENTS }, 0, UINT_MAX, E, "flags"}, {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX, E, "flags"}, {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX, E, "flags"},