From patchwork Sun Jul 28 07:34:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marth64 X-Patchwork-Id: 50775 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:612c:16f:b0:489:2eb3:e4c4 with SMTP id h47csp536413vqi; Sun, 28 Jul 2024 00:35:29 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXUefiDz0UL7Wr/dIOvcHX7oK9/Ulu7xfN1IRjhv0I54sClBleOZAQ6Xa992gXut3J114DpYJdf4WAwqeM1r5Ygb5hC6XHrJJY9JQ== X-Google-Smtp-Source: AGHT+IF75BBSfsY71/LCJ/CzwJrEfNI6uJDAkdckD9als/hKVsFPh+XqkOhwbUQEyTEG7hhML+qH X-Received: by 2002:a17:906:c14b:b0:a77:dc70:b35f with SMTP id a640c23a62f3a-a7d401769b4mr298607666b.58.1722152128936; Sun, 28 Jul 2024 00:35:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1722152128; cv=none; d=google.com; s=arc-20160816; b=a6YTDDy1ZTu001owFkGEipN0bhyJwLbV8fV30pC3P8O9ko9dbWs0uxVgbbanqzVp2V 6iw6O6y61KnIajQl4vJz3jJ+4dKdvSUCs3p/4mi0n6XfO9mF9R7wBEaZR2ZmQqecMRpv FSD3KGb5ytYxE/SU86dpT5UaoEtJB4mfK2bEHNCmIhsqTq5icQD6TLxluP56YKDdn0tW Bj/HdvWeCxUzJz7HbXPiV+6h2zHCVg+CtmFLQiN+WegdriS/8WbboqnQcbqVyW2pj6kz NVQ5DVzfHJaGkpDM7CRS52207Lqh/ksOXnivskRPOa1mljceU1nS4jQlezgX20P7iJ4k sbPQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=OgQgENI6JguKgC71FtEOR38aqbxmkSxmavPKU36kF78=; fh=PlWMzmI9LD2qGS7ipLrQl8z0iaQTLQLHzoGuXcBzpCg=; b=z9bFh5qg6VIX6V3frtxVK7+4HcyS8qm2ND7HM+k29EgBlE7pcfG2zsBuy7HNwjLaD0 w4Ee+LCfBvWoZdg+dxxXF/fr/0U7jeVcdclIEmBBNBjlzijHs8x9OwX4AK21VpapvhVD RWIFuq+EIxT4g46YOeS67o8OLeKbMt9uiBUJfKgtDj7RXHCUKux2fOlx7Oew8jV1Czru exYaDBEKbh0k+oMfzEjIvFVl+s+gURT62Cx1jd4NzPwEKRaXLmAoTiSV4npEjnoAW57O OxKY+qEG4WSL1yyBVs6F1MEJKPPVm11myihXiyDy5+cLoaPDuwhVWhptrzfxIajYM5Hr VtcQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@proxyid.net header.s=google header.b=U2kdtXrY; 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; dara=fail header.i=@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 a640c23a62f3a-a7acacc41ddsi470513566b.957.2024.07.28.00.35.28; Sun, 28 Jul 2024 00:35:28 -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=@proxyid.net header.s=google header.b=U2kdtXrY; 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; dara=fail header.i=@gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 514D768D786; Sun, 28 Jul 2024 10:35:17 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-yb1-f226.google.com (mail-yb1-f226.google.com [209.85.219.226]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 30F1068D76C for ; Sun, 28 Jul 2024 10:35:08 +0300 (EEST) Received: by mail-yb1-f226.google.com with SMTP id 3f1490d57ef6-e05f25fb96eso1005080276.1 for ; Sun, 28 Jul 2024 00:35:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proxyid.net; s=google; t=1722152107; x=1722756907; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=zbTgPcn6HSeKlVg+EX1r9k6y+eAECctz8WGrBRZYs6I=; b=U2kdtXrYk6TqVrhKyVRZkCR/WfNgObvBmJXOD3dz6ZHyw/+ivoARgosdf00cmgS+ZN eJ8DtxBOegRwSr2pwEAF3n0yggQ+APV30RM3TgB0iM3idTrgaGX9PdAPbTarQlbqwUhP pGi++TEH9f/S1eIFD5e4nPpFd5X4N+t4JybZnZ7f1HMZR5sW5fECDp4cFa5gyNjG9ZRB tQ8O9AuN2HZmvmRQ3qal4cI53WADpavfC1Nxb5+q4vD4FxHPW9MzHRayvCxiDk6zCUQr faz6x9prvMahBYhid0EIRIz5efJ40JLPzec9W1kIPIG6cxKD7Z2ZvuLx9gsSw4llF5Hg 4ZSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722152107; x=1722756907; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=zbTgPcn6HSeKlVg+EX1r9k6y+eAECctz8WGrBRZYs6I=; b=bIe8bWN1CEr74207W15evjcLNS29vNS8rc3waUxZYDYtK7znUCmf8IBgP9Prf3aInP zQrkzlJI9IwTWMRj4R79MgYhe4m2jvEv7LxU2qvLrXRQOrRVaW+rt3iGVhMQOFF5zwMu pCTopVhKvzsLpBvlcQTXTD88d1oJUPf/Z5aVuuA4oMr/xXZADnqLci6vWF4oQoigxRJU /Ai8C80QxOmsIFvCL0bzFTn2j+mvAtVZNHvGMEWuKD9MI2gdw1bzBzSlqQwo14sGJWct hhhA4rmn3BZs7BKM9CleTl2HNNsACfB2fEwggPhdlEIPxN2VmlD2Ggrk558CxshQ1gqx UnZA== X-Gm-Message-State: AOJu0Yxr+e6M9b1J150TmkUvJ2mO0f7sk2FkksGKRnklmha3dM2xSmTY hDDRYkoYfg3rah4bg0qOM1v2teEz9+NmwOlrQBWgfLasXC+MILbHVOnmkzv8ux7c9GFVHXYFp2y bggFSutsYtZOVjEEG7ZX0M7Y3W3QmAXNy2rOR1pLR X-Received: by 2002:a05:690c:6610:b0:650:9799:41d2 with SMTP id 00721157ae682-67a09f4ac9bmr51367107b3.30.1722152106538; Sun, 28 Jul 2024 00:35:06 -0700 (PDT) Received: from wsx-cc1-001.. (c-76-136-218-80.hsd1.il.comcast.net. [76.136.218.80]) by smtp-relay.gmail.com with ESMTPS id 00721157ae682-6756ad425desm5735937b3.61.2024.07.28.00.35.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 28 Jul 2024 00:35:06 -0700 (PDT) X-Relaying-Domain: proxyid.net From: Marth64 To: ffmpeg-devel@ffmpeg.org Date: Sun, 28 Jul 2024 02:34:39 -0500 Message-Id: <20240728073445.725161-2-marth64@proxyid.net> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240728073445.725161-1-marth64@proxyid.net> References: <20240728073445.725161-1-marth64@proxyid.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 1/7] avformat/dvdvideodec: Fix racy PTS calculation and frame drops X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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: Marth64 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: KwlENoZlApY8 DVDs naturally consist of segmented MPEG-PS blobs within a VOB (i.e. VOBs are not linear). NAV packs set the segment boundaries. When switching between segments, discontinuities occur and thus the subdemuxer needs to be reset. The current approach to manage this is by invoking ff_read_frame_flush() on the subdemuxer context, via a callback function which is invoked during the menu or dvdnav block functions. The same subdemuxer context is used throughout the demux, with a stretched PTS wrap bits value (64) + disabled overflow correction, and then flushed on each segment. Eventually, a play_end context variable is set to declare EOF. However, this approach is wrong and racy. The block read flushes the demuxer before the frame read is complete, causing frames to drop on discontinuity. The play_end signal likewise ends playback before the frame read is complete, causing frames to drop at end of the title. To compound the issue, the PTS wrap bits value of 64 is wrong; the VOBU limit is actually 32 and the overflow correction should work. Instead, EOF the MPEG-PS subdemuxer organically when each VOB segment ends, and re-open it if needed with the offset after the full frame read is complete. In doing so, correct the PTS wrap behavior to 32 bits, remove the racy play_end/segment_started signals and the callback pattern. The behavior is now more similar to the HLS/DASH demuxers. This commit fixes five intertwined issues, yielding an accurate demux: (1) Racy segment switching (2) Racy EOF signaling (3) Off-by-one leading to missed packets at start of menus (4) Incorrect PTS wrap behavior (5) Unnecessary frame discard workarounds removed Signed-off-by: Marth64 --- libavformat/dvdvideodec.c | 198 +++++++++++++++++++------------------- 1 file changed, 100 insertions(+), 98 deletions(-) diff --git a/libavformat/dvdvideodec.c b/libavformat/dvdvideodec.c index 7a859071c3..e745165e00 100644 --- a/libavformat/dvdvideodec.c +++ b/libavformat/dvdvideodec.c @@ -58,7 +58,7 @@ #define DVDVIDEO_MAX_PS_SEARCH_BLOCKS 128 #define DVDVIDEO_BLOCK_SIZE 2048 #define DVDVIDEO_TIME_BASE_Q (AVRational) { 1, 90000 } -#define DVDVIDEO_PTS_WRAP_BITS 64 /* VOBUs use 32 (PES allows 33) */ +#define DVDVIDEO_PTS_WRAP_BITS 32 /* VOBUs use 32 (PES allows 33) */ #define DVDVIDEO_LIBDVDX_LOG_BUFFER_SIZE 1024 #define PCI_START_BYTE 45 /* complement dvdread's DSI_START_BYTE */ @@ -116,8 +116,9 @@ typedef struct DVDVideoPlaybackState { int pgc_nb_pg_est; /* number of PGs as reported by IFOs */ int pgcn; /* ID of the PGC we are playing */ int pgn; /* ID of the PG we are in now */ + int ptm_discont; /* signal that a PTM discontinuity occurred */ + int64_t ptm_offset; /* PTM discontinuity offset (as NAV value) */ int ptt; /* ID of the chapter we are in now */ - int64_t ts_offset; /* PTS discontinuity offset (ex. VOB change) */ uint32_t vobu_duration; /* duration of the current VOBU */ uint32_t vobu_e_ptm; /* end PTM of the current VOBU */ int vtsn; /* ID of the active VTS (video title set) */ @@ -164,10 +165,11 @@ typedef struct DVDVideoDemuxContext { /* playback control */ int64_t first_pts; /* the PTS of the first video keyframe */ - int play_end; /* signal EOF to the parent demuxer */ - DVDVideoPlaybackState play_state; /* the active playback state */ int play_started; /* signal that playback has started */ - int segment_started; /* signal that subdemuxer is on a segment */ + DVDVideoPlaybackState play_state; /* the active playback state */ + int64_t pts_offset; /* PTS discontinuity offset (ex. VOB change) */ + int seek_warned; /* signal that we warned about seeking limits */ + int subdemux_reset; /* signal that subdemuxer should be reset */ } DVDVideoDemuxContext; static void dvdvideo_libdvdread_log(void *opaque, dvd_logger_level_t level, @@ -344,7 +346,7 @@ static int dvdvideo_menu_open(AVFormatContext *s, DVDVideoPlaybackState *state) } /* make sure the PGC is valid */ - state->pgcn = c->opt_pgc - 1; + state->pgcn = c->opt_pgc; state->pgc = pgci_ut->lu[c->opt_menu_lu - 1].pgcit->pgci_srp[c->opt_pgc - 1].pgc; if (!state->pgc || !state->pgc->program_map || !state->pgc->cell_playback) { av_log(s, AV_LOG_ERROR, "Invalid PGC structure for menu [LU %d, PGC %d]\n", @@ -390,14 +392,16 @@ static int dvdvideo_menu_open(AVFormatContext *s, DVDVideoPlaybackState *state) } static int dvdvideo_menu_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState *state, - uint8_t *buf, int buf_size, - void (*flush_cb)(AVFormatContext *s)) + uint8_t *buf, int buf_size, int *p_is_nav_packet) { int64_t blocks_read = 0; uint8_t read_buf[DVDVIDEO_BLOCK_SIZE] = {0}; pci_t pci = (pci_t) {0}; dsi_t dsi = (dsi_t) {0}; + (*p_is_nav_packet) = 0; + state->ptm_discont = 0; + if (buf_size != DVDVIDEO_BLOCK_SIZE) { av_log(s, AV_LOG_ERROR, "Invalid buffer size (expected=%d actual=%d)\n", DVDVIDEO_BLOCK_SIZE, buf_size); @@ -463,10 +467,8 @@ static int dvdvideo_menu_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState if (state->in_pgc) { if (state->vobu_e_ptm != pci.pci_gi.vobu_s_ptm) { - if (flush_cb) - flush_cb(s); - - state->ts_offset += state->vobu_e_ptm - pci.pci_gi.vobu_s_ptm; + state->ptm_discont = 1; + state->ptm_offset += state->vobu_e_ptm - pci.pci_gi.vobu_s_ptm; } } else { state->in_pgc = 1; @@ -474,13 +476,17 @@ static int dvdvideo_menu_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState } state->vobu_e_ptm = pci.pci_gi.vobu_e_ptm; + state->vobu_duration = pci.pci_gi.vobu_e_ptm - pci.pci_gi.vobu_s_ptm; av_log(s, AV_LOG_DEBUG, "NAV packet: sector=%d " - "vobu_s_ptm=%d vobu_e_ptm=%d ts_offset=%" PRId64 "\n", + "vobu_s_ptm=%d vobu_e_ptm=%d ptm_offset=%" PRId64 "\n", dsi.dsi_gi.nv_pck_lbn, - pci.pci_gi.vobu_s_ptm, pci.pci_gi.vobu_e_ptm, state->ts_offset); + pci.pci_gi.vobu_s_ptm, pci.pci_gi.vobu_e_ptm, state->ptm_offset); - return FFERROR_REDO; + + (*p_is_nav_packet) = 1; + + return DVDVIDEO_BLOCK_SIZE; } /* we are in the middle of a VOBU, so pass on the PS packet */ @@ -610,9 +616,7 @@ end_dvdnav_error: } static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState *state, - uint8_t *buf, int buf_size, - int *p_nav_event, - void (*flush_cb)(AVFormatContext *s)) + uint8_t *buf, int buf_size, int *p_is_nav_packet) { DVDVideoDemuxContext *c = s->priv_data; @@ -626,6 +630,9 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState pci_t *e_pci; dsi_t *e_dsi; + (*p_is_nav_packet) = 0; + state->ptm_discont = 0; + if (buf_size != DVDVIDEO_BLOCK_SIZE) { av_log(s, AV_LOG_ERROR, "Invalid buffer size (expected=%d actual=%d)\n", DVDVIDEO_BLOCK_SIZE, buf_size); @@ -769,16 +776,14 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState state->in_ps = 1; } else { if (state->vobu_e_ptm != e_pci->pci_gi.vobu_s_ptm) { - if (flush_cb) - flush_cb(s); - - state->ts_offset += state->vobu_e_ptm - e_pci->pci_gi.vobu_s_ptm; + state->ptm_discont = 1; + state->ptm_offset += state->vobu_e_ptm - e_pci->pci_gi.vobu_s_ptm; } } state->vobu_e_ptm = e_pci->pci_gi.vobu_e_ptm; - (*p_nav_event) = nav_event; + (*p_is_nav_packet) = 1; return nav_len; case DVDNAV_BLOCK_OK: @@ -809,8 +814,6 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState "this could be due to a missed NAV packet\n", state->pgn, cur_pgn); - (*p_nav_event) = nav_event; - return nav_len; case DVDNAV_WAIT: if (dvdnav_wait_skip(state->dvdnav) != DVDNAV_STATUS_OK) { @@ -908,7 +911,7 @@ static int dvdvideo_chapters_setup_preindex(AVFormatContext *s) DVDVideoPlaybackState state = {0}; uint8_t nav_buf[DVDVIDEO_BLOCK_SIZE]; - int nav_event; + int is_nav_packet; if (c->opt_chapter_start == c->opt_chapter_end) return ret; @@ -924,11 +927,11 @@ static int dvdvideo_chapters_setup_preindex(AVFormatContext *s) while (!(interrupt = ff_check_interrupt(&s->interrupt_callback))) { ret = dvdvideo_play_next_ps_block(s, &state, nav_buf, DVDVIDEO_BLOCK_SIZE, - &nav_event, NULL); + &is_nav_packet); if (ret < 0 && ret != AVERROR_EOF) goto end_close; - if (nav_event != DVDNAV_NAV_PACKET && ret != AVERROR_EOF) + if (!is_nav_packet && ret != AVERROR_EOF) continue; if (state.ptt == last_ptt) { @@ -1420,46 +1423,40 @@ static int dvdvideo_subp_stream_add_all(AVFormatContext *s) return 0; } -static void dvdvideo_subdemux_flush(AVFormatContext *s) -{ - DVDVideoDemuxContext *c = s->priv_data; - - if (!c->segment_started) - return; - - av_log(s, AV_LOG_DEBUG, "flushing sub-demuxer\n"); - avio_flush(&c->mpeg_pb.pub); - ff_read_frame_flush(c->mpeg_ctx); - c->segment_started = 0; -} - static int dvdvideo_subdemux_read_data(void *opaque, uint8_t *buf, int buf_size) { AVFormatContext *s = opaque; DVDVideoDemuxContext *c = s->priv_data; - int ret = 0; - int nav_event; - - if (c->play_end) - return AVERROR_EOF; + int ret; + int is_nav_packet; if (c->opt_menu) - ret = dvdvideo_menu_next_ps_block(s, &c->play_state, buf, buf_size, - dvdvideo_subdemux_flush); + ret = dvdvideo_menu_next_ps_block(s, &c->play_state, buf, buf_size, &is_nav_packet); else - ret = dvdvideo_play_next_ps_block(opaque, &c->play_state, buf, buf_size, - &nav_event, dvdvideo_subdemux_flush); + ret = dvdvideo_play_next_ps_block(s, &c->play_state, buf, buf_size, &is_nav_packet); - if (ret == AVERROR_EOF) { - c->mpeg_pb.pub.eof_reached = 1; - c->play_end = 1; + if (ret < 0) + goto subdemux_eof; - return AVERROR_EOF; - } + if (is_nav_packet) { + if (c->play_state.ptm_discont) { + c->subdemux_reset = 1; + + ret = AVERROR_EOF; + goto subdemux_eof; + } - if (ret >= 0 && nav_event == DVDNAV_NAV_PACKET) return FFERROR_REDO; + } + + return ret; + +subdemux_eof: + c->mpeg_pb.pub.eof_reached = 1; + c->mpeg_pb.pub.error = ret; + c->mpeg_pb.pub.read_packet = NULL; + c->mpeg_pb.pub.buf_end = c->mpeg_pb.pub.buf_ptr = c->mpeg_pb.pub.buffer; return ret; } @@ -1469,7 +1466,9 @@ static void dvdvideo_subdemux_close(AVFormatContext *s) DVDVideoDemuxContext *c = s->priv_data; av_freep(&c->mpeg_pb.pub.buffer); + memset(&c->mpeg_pb, 0x00, sizeof(c->mpeg_pb)); avformat_close_input(&c->mpeg_ctx); + c->mpeg_ctx = NULL; } static int dvdvideo_subdemux_open(AVFormatContext *s) @@ -1501,12 +1500,23 @@ static int dvdvideo_subdemux_open(AVFormatContext *s) c->mpeg_ctx->max_analyze_duration = 0; c->mpeg_ctx->interrupt_callback = s->interrupt_callback; c->mpeg_ctx->pb = &c->mpeg_pb.pub; - c->mpeg_ctx->correct_ts_overflow = 0; - c->mpeg_ctx->io_open = NULL; return avformat_open_input(&c->mpeg_ctx, "", &ff_mpegps_demuxer.p, NULL); } +static int dvdvideo_subdemux_reset(AVFormatContext *s) +{ + int ret; + + av_log(s, AV_LOG_DEBUG, "resetting sub-demuxer\n"); + + dvdvideo_subdemux_close(s); + if ((ret = dvdvideo_subdemux_open(s)) < 0) + return ret; + + return 0; +} + static int dvdvideo_read_header(AVFormatContext *s) { DVDVideoDemuxContext *c = s->priv_data; @@ -1604,72 +1614,64 @@ static int dvdvideo_read_packet(AVFormatContext *s, AVPacket *pkt) DVDVideoDemuxContext *c = s->priv_data; int ret; - enum AVMediaType st_type; - int found_stream = 0; - - if (c->play_end) - return AVERROR_EOF; + int st_matched = 0; + AVStream *st_subdemux; ret = av_read_frame(c->mpeg_ctx, pkt); + if (ret < 0) { + if (c->subdemux_reset) { + c->subdemux_reset = 0; + c->pts_offset = c->play_state.ptm_offset; - if (ret < 0) - return ret; + if ((ret = dvdvideo_subdemux_reset(s)) < 0) + return ret; + + return FFERROR_REDO; + } - if (!c->segment_started) - c->segment_started = 1; + return ret; + } - st_type = c->mpeg_ctx->streams[pkt->stream_index]->codecpar->codec_type; + st_subdemux = c->mpeg_ctx->streams[pkt->stream_index]; /* map the subdemuxer stream to the parent demuxer's stream (by startcode) */ for (int i = 0; i < s->nb_streams; i++) { - if (s->streams[i]->id == c->mpeg_ctx->streams[pkt->stream_index]->id) { + if (s->streams[i]->id == st_subdemux->id) { pkt->stream_index = s->streams[i]->index; - found_stream = 1; + st_matched = 1; break; } } - if (!found_stream) { - av_log(s, AV_LOG_DEBUG, "discarding frame with stream that was not in IFO headers " - "(stream id=%d)\n", c->mpeg_ctx->streams[pkt->stream_index]->id); - - return FFERROR_REDO; - } + if (!st_matched) + goto discard; if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE) { if (!c->play_started) { - /* try to start at the beginning of a GOP */ - if (st_type != AVMEDIA_TYPE_VIDEO || !(pkt->flags & AV_PKT_FLAG_KEY)) { - av_log(s, AV_LOG_VERBOSE, "Discarding packet which is not a video keyframe or " - "with unset PTS/DTS at start\n"); - return FFERROR_REDO; - } - c->first_pts = pkt->pts; c->play_started = 1; } - pkt->pts += c->play_state.ts_offset - c->first_pts; - pkt->dts += c->play_state.ts_offset - c->first_pts; - - if (pkt->pts < 0) { - av_log(s, AV_LOG_VERBOSE, "Discarding packet with negative PTS (st=%d pts=%" PRId64 "), " - "this is OK at start of playback\n", - pkt->stream_index, pkt->pts); - - return FFERROR_REDO; - } + pkt->pts += c->pts_offset - c->first_pts; + pkt->dts += c->pts_offset - c->first_pts; } else { - av_log(s, AV_LOG_WARNING, "Unset PTS or DTS @ st=%d pts=%" PRId64 " dts=%" PRId64 "\n", - pkt->stream_index, pkt->pts, pkt->dts); + av_log(s, AV_LOG_WARNING, "Received packet with unset PTS or DTS\n"); } av_log(s, AV_LOG_TRACE, "st=%d pts=%" PRId64 " dts=%" PRId64 " " - "ts_offset=%" PRId64 " first_pts=%" PRId64 "\n", + "pts_offset=%" PRId64 " first_pts=%" PRId64 "\n", pkt->stream_index, pkt->pts, pkt->dts, - c->play_state.ts_offset, c->first_pts); + c->pts_offset); + + return 0; + +discard: + av_log(s, AV_LOG_VERBOSE, "Discarding packet @ st=%d pts=%" PRId64 " dts=%" PRId64 " " + "st_matched=%d\n", + st_matched ? pkt->stream_index : -1, pkt->pts, pkt->dts, + st_matched); - return c->play_end ? AVERROR_EOF : 0; + return FFERROR_REDO; } static int dvdvideo_close(AVFormatContext *s)