From patchwork Tue Jan 31 20:29:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aman Karmani X-Patchwork-Id: 2385 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.89.21 with SMTP id n21csp2118225vsb; Tue, 31 Jan 2017 12:30:12 -0800 (PST) X-Received: by 10.223.147.100 with SMTP id 91mr15249699wro.5.1485894612072; Tue, 31 Jan 2017 12:30:12 -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 w77si18557438wmw.30.2017.01.31.12.30.11; Tue, 31 Jan 2017 12:30:12 -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 E09DB689A28; Tue, 31 Jan 2017 22:30:02 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf0-f195.google.com (mail-pf0-f195.google.com [209.85.192.195]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EF913689812 for ; Tue, 31 Jan 2017 22:29:55 +0200 (EET) Received: by mail-pf0-f195.google.com with SMTP id 19so29559505pfo.3 for ; Tue, 31 Jan 2017 12:29:58 -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=svXiuVeVbFXoDsj5JQCTzRbXwHyQrrHCcVg2ofobvIo=; b=gHn6wI5BF5HLSO7M+UqNKl+CMrpJPnOauzLJnT/hW2J+3BV/TrUIZHxzBNDgw2mNx+ QPe20RmFQepIcnUT6tvygi+6Y5DRuwsp7Fg6a63tTRba9m16PVkUjy/cNYdc+FKTCBdf FO7jwbpjlieePY9l9rndOGKrDcJ55Ya+Tj9F7r8PkRNHUpOqsmrJiqHEslXAje7+KyiI w/YdTtgpwn+LNaOFeeA5sMlXRnM01WxWDuOLe4jL/kmbDaz5A0tHR9waz+d/iRiCm9wo EDaFWR/3spjUmhFuRggxAdjSW0asv/9mG5hIZMZlQw8I1IzI501eU3WYySuwL5/SiaLS cs3g== 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=svXiuVeVbFXoDsj5JQCTzRbXwHyQrrHCcVg2ofobvIo=; b=NBUUhjQcIubL7IojfpctyBWyutqrKWxWMy07640AtmRDD2YnxKHWW+zs48+NbEYUgN Pg0u3Lhzx1hYygvhaoBd30bcFmb601I+u/4l6ATK2dvnt5q+Ja/EtIBBRud8df3cGbVE SG7Z5/kgCoWYnSZTBHPRHzy2OJnbzpjfZscPFi+r3xWn8dwD5pfibIrJITDQdprC/3mF 2XYi2gyFkNZW0e1hNWL3u8nnPuMXrWB4hKMf2EfDIboebKytufu1Qdh+vARksouwl5aH RsXQP29tYMeDm7ZT1Ix9ulaw3aff/T5WDUtz32SqGPBKVv24oPsFZDNqZ4odnhO1a5U3 U3/w== X-Gm-Message-State: AIkVDXI7AgTma1RpcrKRSrB2zjhO8J7nxKZqLjMqmOT08vWWBthfMw3NLkagoh9vI1PJyA== X-Received: by 10.99.121.77 with SMTP id u74mr32694629pgc.200.1485894596874; Tue, 31 Jan 2017 12:29:56 -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 d68sm43287742pfj.92.2017.01.31.12.29.55 (version=TLS1 cipher=AES128-SHA bits=128/128); Tue, 31 Jan 2017 12:29:56 -0800 (PST) From: Aman Gupta To: ffmpeg-devel@ffmpeg.org Date: Tue, 31 Jan 2017 12:29:42 -0800 Message-Id: <20170131202942.62185-1-ffmpeg@tmm1.net> X-Mailer: git-send-email 2.10.1 (Apple Git-78) Subject: [FFmpeg-devel] [PATCH] avformat/hlsenc: add hls_flag option to create segments atomically 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 and before the file is added to the m3u8 playlist. 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 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index bd1e684..23b9011 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 { @@ -915,6 +916,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; @@ -1276,6 +1281,15 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) av_write_frame(oc, NULL); /* Flush any buffered data */ + if (hls->flags & HLS_TEMP_FILE) { + 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'; + } + new_start_pos = avio_tell(hls->avf->pb); hls->size = new_start_pos - hls->start_pos; ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size); @@ -1406,6 +1420,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"},