From patchwork Tue Dec 18 13:56:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 11460 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 6254C44E125 for ; Tue, 18 Dec 2018 16:04:11 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 8EA4568A9C3; Tue, 18 Dec 2018 16:04:11 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id F28A068A911 for ; Tue, 18 Dec 2018 16:04:04 +0200 (EET) Received: by mail-wr1-f45.google.com with SMTP id x10so16019938wrs.8 for ; Tue, 18 Dec 2018 06:04:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=TkCWhjSsah2j/+rB7Pw9rNs1MKbGFCBORGjxSb9XvSY=; b=DE2sxxcrRFdPi/llk7xJFp1xdV+FC+eYtAEMnPI+goW6DkBMbte1RhDLGrhzYIPQlZ V1qwMEyYds7jeyw6fAaMj1iQiF9J+b18FVjFrn4lzUyFHl0Lm8/EyeDlyK9HysSUlzY0 JosddVIVKEsQHyZczHsPTHH1cmfyW38EwdbvyiHzYTV4+bPjNf3JMK+rTljK2gBq7bpY dZaaVmeE6EtzF8OQJZBRAZu5okaoUGof+pv3zFYq7qU/1Cg6IeeEUvySL00MQ5kOB8hm NjIvkknwRkdpNU90zt0HPgK+bIS0kRMHpxRiwX0dkuEgXEimKatdEROTLYLlyZxRytah /++Q== 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; bh=TkCWhjSsah2j/+rB7Pw9rNs1MKbGFCBORGjxSb9XvSY=; b=BFPeFwCUoCkw50EyYruZAgd3CyZVMdxQgzV4SI8FUl5DCShzLlwXC9mnWYND/WI8rR Cty44nRGZcyZwcHWOH8+w+rOQKmutshNEQza7IxfCqCUOpo+6hYDKtStC8+LfHu0mNXa R7MEKBgtZMHLhGSK2L8fg8cKLEFc70v82Rncn03xdL23OSQiX86fqx3WRMjneQa0U4uU mxY7xClVKXFLvKTqZoabft2X5qlrC7jvd1m04j2/afC4rzUHI8I0YLw0fc4Z2n4ZOQFc NF2dwZMlLcd2x34zHqWlijkrKkc5QRTSAnLAbA7iNFA+LI82VaOMwtLFP7glIog+ZDGZ x3PA== X-Gm-Message-State: AA+aEWavT8V9PA05rDmD8HNxin1p71uD46w/UgF5MPlMVTYKpn2wqVha EfKnkTnIu6jnmZ4UZyLGVcaDvO4I X-Google-Smtp-Source: AFSGD/X8tuq5WKX0Oo8Pg+GGtSGi0XffKMciAwDpZFx/O33BjzjhOTE+TxJi5/3IJkgp2lr3lz38qQ== X-Received: by 2002:adf:b649:: with SMTP id i9mr15325268wre.70.1545141424841; Tue, 18 Dec 2018 05:57:04 -0800 (PST) Received: from localhost.localdomain ([94.250.174.60]) by smtp.gmail.com with ESMTPSA id d2sm2747498wrs.97.2018.12.18.05.57.03 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 18 Dec 2018 05:57:04 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Tue, 18 Dec 2018 14:56:54 +0100 Message-Id: <20181218135655.4152-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH 1/2] avformat/nutenc: fix duration estimation by writing EOR packets 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" Signed-off-by: Paul B Mahol --- libavformat/nut.h | 3 + libavformat/nutenc.c | 130 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 129 insertions(+), 4 deletions(-) diff --git a/libavformat/nut.h b/libavformat/nut.h index a4409ee23d..4b15dca1ea 100644 --- a/libavformat/nut.h +++ b/libavformat/nut.h @@ -76,6 +76,9 @@ typedef struct StreamContext { int last_flags; int skip_until_key_frame; int64_t last_pts; + int64_t eor_pts; + int64_t eor_dts; + int eor_flushed; int time_base_id; AVRational *time_base; int msb_pts_shift; diff --git a/libavformat/nutenc.c b/libavformat/nutenc.c index e9a3bb49db..9d1c540a9d 100644 --- a/libavformat/nutenc.c +++ b/libavformat/nutenc.c @@ -940,6 +940,80 @@ fail: return ret; } +static void nut_update_max_pts(AVFormatContext *s, int stream_index, int64_t pts) +{ + NUTContext *nut = s->priv_data; + StreamContext *nus = &nut->stream[stream_index]; + + if (!nut->max_pts_tb || av_compare_ts(nut->max_pts, *nut->max_pts_tb, pts, *nus->time_base) < 0) { + nut->max_pts = pts; + nut->max_pts_tb = nus->time_base; + } +} + +static int nut_write_eor(AVFormatContext *s, AVPacket *pkt) +{ + AVIOContext *bc = s->pb, *dyn_bc; + NUTContext *nut = s->priv_data; + StreamContext *nus = &nut->stream[pkt->stream_index]; + int ret, frame_code, flags, needed_flags; + int64_t pts = pkt->pts; + int64_t coded_pts; + FrameCode *fc; + + coded_pts = pts & ((1 << nus->msb_pts_shift) - 1); + if (ff_lsb2full(nus, coded_pts) != pts) + coded_pts = pts + (1 << nus->msb_pts_shift); + + nut->last_syncpoint_pos = avio_tell(bc); + ret = avio_open_dyn_buf(&dyn_bc); + if (ret < 0) + return ret; + put_tt(nut, nus->time_base, dyn_bc, pkt->dts); + ff_put_v(dyn_bc, 0); + + if (nut->flags & NUT_BROADCAST) { + put_tt(nut, nus->time_base, dyn_bc, + av_rescale_q(av_gettime(), AV_TIME_BASE_Q, *nus->time_base)); + } + put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE); + + frame_code = -1; + for (int i = 0; i < 256; i++) { + FrameCode *fc = &nut->frame_code[i]; + int flags = fc->flags; + + if (flags & FLAG_INVALID) + continue; + + if (!(flags & FLAG_CODED)) { + continue; + } + + frame_code = i; + break; + } + av_assert0(frame_code != -1); + + fc = &nut->frame_code[frame_code]; + flags = fc->flags; + needed_flags = FLAG_KEY | FLAG_EOR | FLAG_CODED_PTS | FLAG_STREAM_ID; + + ffio_init_checksum(bc, ff_crc04C11DB7_update, 0); + avio_w8(bc, frame_code); + if (flags & FLAG_CODED) { + ff_put_v(bc, (flags ^ needed_flags) & ~(FLAG_CODED)); + flags = needed_flags; + } + if (flags & FLAG_STREAM_ID) ff_put_v(bc, pkt->stream_index); + if (flags & FLAG_CODED_PTS) ff_put_v(bc, coded_pts); + ffio_get_checksum(bc); + + nut_update_max_pts(s, pkt->stream_index, pkt->pts); + + return 0; +} + static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) { NUTContext *nut = s->priv_data; @@ -956,6 +1030,9 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) int data_size = pkt->size; uint8_t *sm_buf = NULL; + if (!data_size) + return nut_write_eor(s, pkt); + if (pkt->pts < 0) { av_log(s, AV_LOG_ERROR, "Negative pts not supported stream %d, pts %"PRId64"\n", @@ -1150,10 +1227,7 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) nus->keyframe_pts[nut->sp_count] = pkt->pts; } - if (!nut->max_pts_tb || av_compare_ts(nut->max_pts, *nut->max_pts_tb, pkt->pts, *nus->time_base) < 0) { - nut->max_pts = pkt->pts; - nut->max_pts_tb = nus->time_base; - } + nut_update_max_pts(s, pkt->stream_index, pkt->pts); fail: av_freep(&sm_buf); @@ -1161,6 +1235,53 @@ fail: return ret; } +static int nut_interleave_packet(AVFormatContext *s, AVPacket *out, + AVPacket *pkt, int flush) +{ + NUTContext *nut = s->priv_data; + int ret; + + if (pkt) { + StreamContext *nus = &nut->stream[pkt->stream_index]; + + nus->eor_pts = FFMAX(pkt->pts + pkt->duration, nus->eor_pts); + nus->eor_dts = FFMAX(pkt->dts + pkt->duration, nus->eor_dts); + } else if (flush) { + StreamContext *nus; + int i; + + for (i = 0; i < s->nb_streams; i++) { + nus = &nut->stream[i]; + + if (nus->eor_flushed) + continue; + + if (s->streams[i]->last_in_packet_buffer) + continue; + + break; + } + + if (i < s->nb_streams) { + pkt = av_packet_alloc(); + if (!pkt) + return AVERROR(ENOMEM); + + ret = av_new_packet(pkt, 0); + if (ret < 0) + return ret; + pkt->stream_index = i; + pkt->pts = nus->eor_pts; + pkt->dts = nus->eor_dts; + pkt->duration = 0; + nus->eor_flushed = 1; + ret = ff_interleave_packet_per_dts(s, out, pkt, 0); + pkt = NULL; + } + } + return ff_interleave_packet_per_dts(s, out, pkt, flush); +} + static int nut_write_trailer(AVFormatContext *s) { NUTContext *nut = s->priv_data; @@ -1225,6 +1346,7 @@ AVOutputFormat ff_nut_muxer = { .write_header = nut_write_header, .write_packet = nut_write_packet, .write_trailer = nut_write_trailer, + .interleave_packet = nut_interleave_packet, .deinit = nut_write_deinit, .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS, .codec_tag = ff_nut_codec_tags,