From patchwork Thu Feb 2 00:28:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aman Karmani X-Patchwork-Id: 2409 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.89.21 with SMTP id n21csp2692408vsb; Wed, 1 Feb 2017 16:28:35 -0800 (PST) X-Received: by 10.28.141.199 with SMTP id p190mr5355236wmd.89.1485995315038; Wed, 01 Feb 2017 16:28:35 -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 1si26522683wre.62.2017.02.01.16.28.33; Wed, 01 Feb 2017 16:28:35 -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 01078689203; Thu, 2 Feb 2017 02:28: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 8CC11680A6C for ; Thu, 2 Feb 2017 02:28:25 +0200 (EET) Received: by mail-pf0-f196.google.com with SMTP id e4so63501pfg.0 for ; Wed, 01 Feb 2017 16:28:25 -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=tSLHys87dl1b8uld4jlYGoCkv8/ym56386lKHCqsFKk=; b=EVLUALeF2y58/iy+/aLb7Gy+1P0iGAcZFkEFReBtFCKG41Eqd6Nwp7n/+qsbv4JE5M cy4iTFuxNopcmaJ9BPgECfbPIqEHLqPg0kfAOGXrT7zVZFaiG2hcg7Ge2hT3GmnfBton qJLH+MVS85F2xwbe2wctuyRUgXO0nUUrNHKr9c78KSevn4Z1Wyk+WlQLb5xbdl8uCX5U TelpOV6EJysztZ0XO1ZwZd4/4iK87zSchIV7DzILbJ5ysdZ02L6vLsF0TfaBmXYetd6+ AvbYSiVga2JyUmUULHUIqkNZ0nR6sYA/waqOW/pvl56arYcbBHh8a5ZMMt+TD35uVmO5 xViw== 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=tSLHys87dl1b8uld4jlYGoCkv8/ym56386lKHCqsFKk=; b=OMp85OJgvMRb0gL3Q5FktLwus2jAyUsEc4Z3coVHj+0N/OtjYdRefbn8aaJhxq1t8q r32OFwhsg5o4RdJVhEyDCmVaOdRQgjXmRVKaqpJ2aw4rostS8s50mWn8Rby2BegJNDaX OT5wIgHKYA7wGXNYafjlFazNGNo81jO2tYpGczpeH7uWxLKN8aPq9OWMqAlpxDnZb66p ewXR/3pG94j2v4V7eWjF6kvU9Jetj/h1vAbkE1+MuQM/PGnjmjsuU5dLWVmOc5sKxcsw H0YO0G68y0h9cZZJwpuXTilNnBzN80cW2a69qbJsFamBuVOWvQI90hhUIdLMA6/p0JZI 1nHw== X-Gm-Message-State: AIkVDXJunROXMF0VxDaqy82odnGY4WhylnTSoDDydUE2kwRxMqjikRAX22iahFJ7Yf1ZSA== X-Received: by 10.84.253.23 with SMTP id z23mr8454962pll.0.1485995303752; Wed, 01 Feb 2017 16:28:23 -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 a8sm52567461pfa.19.2017.02.01.16.28.22 (version=TLS1 cipher=AES128-SHA bits=128/128); Wed, 01 Feb 2017 16:28:23 -0800 (PST) From: Aman Gupta To: ffmpeg-devel@ffmpeg.org Date: Wed, 1 Feb 2017 16:28:19 -0800 Message-Id: <20170202002819.11363-1-ffmpeg@tmm1.net> X-Mailer: git-send-email 2.10.1 (Apple Git-78) Subject: [FFmpeg-devel] [PATCH v2] 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. --- libavformat/hlsenc.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) 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"},