From patchwork Tue Jan 16 18:15:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Bex Kelly X-Patchwork-Id: 45618 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:8199:b0:199:de12:6fa6 with SMTP id pd25csp2164414pzb; Tue, 16 Jan 2024 10:16:32 -0800 (PST) X-Google-Smtp-Source: AGHT+IGDg48+rmhVlkWpb9f1Tgxtkv0myboTrV8b4sa2ag9RgcXaEZU63j4DalUSqvxMBS643tGK X-Received: by 2002:a17:906:7147:b0:a2e:52ff:68a6 with SMTP id z7-20020a170906714700b00a2e52ff68a6mr570747ejj.143.1705428992027; Tue, 16 Jan 2024 10:16:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1705428992; cv=none; d=google.com; s=arc-20160816; b=RlOgRdmQZ7ZLSGugavH8XSk4tG5fAoPxYqlcXOG0779EBDYloot3jqrewhhzRQFipS XzvuFMIxUvt8p1whiUTz1aTydP/wTGdItjFoixUGE64X9rln+XNhmkgYraYiKJUs5pIE WkNnOIEHvwhXvVUsFYjlzkR+GFJIvFlk4EkJhLvHwAEji3ZlCI8vAsys0arIbm8b2Z5I HmbeqdeVajJGetRtBOxmlf1aefrN9cnkIBOIQu0AgNOhJXSPj4l4PAE5CvR/ACXUjmTW nw+V4diPMiQzUCsUO9vqHchM/yJic1r6jvvp7jtOS237a1LhhXr58K8zv8IQKprzqaFs mAQg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=uyviCwENz1zRaBlDLrNFYM8NR/4NzEuOYcRKiU0kJUA=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=VCvXl2xS1F9bagBF7woL8WV+ZsomEBJ0NPtNkSoqXvOOyNFe3CIWK0cFmOZpoNGhN7 mUZr9Sr8UcRA+Xqz28GEhQflJuAf/k6bvL6U344bsVrM348FkycVVDNzNhEuM0+VS8ja PWtELTYA5mDgyJCmxWevXfVjjt6B6NFJqzyrCNNRY+IJCu4A48rvTPzoyexXZLsW6LEm k6loHcdVb7YOTmk/wY8PLxUsNSCqISsv1Qinhifqk+iNz2HD8wfQtfjfPFng5cl+g1UM vBhAdi2Jns4t/eJWSqMF/lWmllB67fwqR9XDIyjFwm5fZvPN5pzOY8whV5YENvWwQNmN 97dQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@ancilla-ca.20230601.gappssmtp.com header.s=20230601 header.b=TiPwmm1r; 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 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id k1-20020a17090666c100b00a2ceb076c21si3759365ejp.801.2024.01.16.10.16.01; Tue, 16 Jan 2024 10:16:32 -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=@ancilla-ca.20230601.gappssmtp.com header.s=20230601 header.b=TiPwmm1r; 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 02B7268D054; Tue, 16 Jan 2024 20:15:59 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ot1-f41.google.com (mail-ot1-f41.google.com [209.85.210.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id D93CA68AB1D for ; Tue, 16 Jan 2024 20:15:51 +0200 (EET) Received: by mail-ot1-f41.google.com with SMTP id 46e09a7af769-6e0a89b98e4so2622972a34.1 for ; Tue, 16 Jan 2024 10:15:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ancilla-ca.20230601.gappssmtp.com; s=20230601; t=1705428949; x=1706033749; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=pItemsZy4s7gnHvyHwyAXFrrKtlUHSu+nY/aQ8VntMQ=; b=TiPwmm1rugvc2m+DXFSyCsIL0MJJLQAhN4AMiA3l/dVECMV4fnWj49LMdNuXsunEKk 8SNtWGnF0WERVfh9ddhHiIOEK87KauljrgHVlVNDtye8iwsLtqn9ECoiCayST8DJZjBd QoVmpQiNAYvE5K8aiECBHVzjJO0ghkz2qbTx7KEONeRTDUVPGrY/fRJlOowVl75X6yB4 cCnnxnRIjtjb/8YJ3aV2aqxbZiu9UtICU0vi8uVeqBrFrEA5JcqWbjpFyaApu1FE/V3Y B7ATovZiMdtPQuG1qCWHVPJ7c2C+iDG8DDBaIJ/7cwlptQRRaoqXQS7xVHplpV0bIL66 4mjg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1705428949; x=1706033749; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=pItemsZy4s7gnHvyHwyAXFrrKtlUHSu+nY/aQ8VntMQ=; b=JVC4lwK9fg3slYH3PrS1KuV7Lo8OKWbUDvqXR135zAGZjPe6R7zNeMWQ6vqhRe1+P6 AYUfLfuDsKH3N2N8H1ahsTg9emJlivLDKORXevnmzKn9juS9e88E9NsSva7wHCHyPKh4 kDvKuzSUSpgA7F7/14sJ7FUB0L3V1zjQsYbdvsOemenyIXMy5Ga4wfwvIa7Kc7U5JIxt JKDAP7XFJvBZO8zYJpiNI0KFbUr0jTPOiV31kXlX+lDZ1i/+Wy3hWuv+dAXpw4JFcm+o 1BPHyR92LhZeqnuvRSorWdwjmzaMozdTgDnLLi6BOuWGuTIobWHujivXiL0mkrAXUOlZ aIpw== X-Gm-Message-State: AOJu0YxSHDXN2GYhmkBBvJ6yTmZekBndJ0EhCJAlmGNcbevgh4WsRR8N U810OGuV4zWC6aN9F5DHC5mCWEc7pyNFRrfr5k0jo4sad8k= X-Received: by 2002:a9d:6408:0:b0:6e0:c467:aab3 with SMTP id h8-20020a9d6408000000b006e0c467aab3mr1947835otl.15.1705428949164; Tue, 16 Jan 2024 10:15:49 -0800 (PST) Received: from localhost (69-171-137-1.rdns.distributel.net. [69.171.137.1]) by smtp.gmail.com with ESMTPSA id i12-20020a05622a08cc00b00429bc01acc5sm5048078qte.68.2024.01.16.10.15.48 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 16 Jan 2024 10:15:48 -0800 (PST) From: Bex Kelly To: ffmpeg-devel@ffmpeg.org Date: Tue, 16 Jan 2024 13:15:11 -0500 Message-ID: <20240116181524.2682575-1-bk@ancilla.ca> X-Mailer: git-send-email 2.42.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] libavformat/libgme: avoid infinite reads of looping files 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: GBr+y1ukKRV2 From: Rebecca Kelly This fixes an issue where certain VGM/VGZ files (and possibly other formats handled by libgme) will report a duration of "N/A" when ffprobed, and will produce an infinite-length audio file when converted with ffmpeg. The behaviour here follows the recommendations in the libgme documentation¹: use total duration if available, otherwise use intro length + two loops, otherwise pretend the file is 2.5 minutes long. It uses gme_set_fade() to implement this, which will cause libgme to insert a clean fade-out and then report end of file at the specified time. Patch released under the LGPL 2.1 license (or any later version). ——— ¹ https://github.com/mcfiredrill/libgme/blob/master/gme.txt Signed-off-by: Rebecca Kelly --- libavformat/libgme.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/libavformat/libgme.c b/libavformat/libgme.c index 4d04537339..b2635fc89f 100644 --- a/libavformat/libgme.c +++ b/libavformat/libgme.c @@ -63,7 +63,26 @@ static int load_metadata(AVFormatContext *s, int64_t *duration) if (gme_track_info(gme->music_emu, &info, gme->track_index)) return AVERROR_STREAM_NOT_FOUND; - *duration = info->length; + // Some formats support looped audio. In these cases, length will be -1, and + // the track length needs to be determined from intro_length and loop_length + // instead. Furthermore, some formats have no length data at all, in which + // case all of these fields will be -1. + // When reading these formats, GME will return audio frames forever if you + // ask for them; it's up to the caller to decide when to stop, either by + // closing the file after a certain point or by calling gme_set_fade() + // before starting playback, which will cause GME to simulate a fadeout and + // end of file at that point. + // The GME documentation recommends a default behaviour of playing the intro + // followed by two loops, for looped audio, or playing 2.5 minutes and then + // fading out, for audio of indeterminate length. + if (info->length > 0) { + *duration = info->length; + } else if (info->intro_length > 0 || info->loop_length > 0) { + *duration = info->intro_length + info->loop_length * 2; + } else { + *duration = 150000; // 2.5 minutes in milliseconds + } + add_meta(s, "system", info->system); add_meta(s, "game", info->game); add_meta(s, "song", info->song); @@ -138,8 +157,10 @@ static int read_header_gme(AVFormatContext *s) if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 1000); - if (duration > 0) + if (duration > 0) { st->duration = duration; + gme_set_fade(gme->music_emu, duration); // Avoid infinite playback + } st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_id = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE); st->codecpar->ch_layout.nb_channels = 2;