From patchwork Tue Jul 31 19:16:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Karsten Otto X-Patchwork-Id: 9852 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:104:0:0:0:0:0 with SMTP id c4-v6csp5412909jad; Tue, 31 Jul 2018 12:16:44 -0700 (PDT) X-Google-Smtp-Source: AAOMgpeGrR9iS2DPxUyE0BeWNWKlNnIaQWBFZ3xxT9I6vW4YUyWBHvNVRlR7YNpLcnjYIL+Bw5tg X-Received: by 2002:adf:de84:: with SMTP id w4-v6mr22754658wrl.270.1533064604169; Tue, 31 Jul 2018 12:16:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1533064604; cv=none; d=google.com; s=arc-20160816; b=f0Pue7ovYvpjw3ZwX4mrtnkYjb2zWNMB709eVvSsAUm3cSSt/6P6FexjmRWfqvUymB 962jaxwRzSjmIrOB6JFkF1FOOWlesC8biIjEn/cuWbaELQOBhpnDjifKFu9XrsD4GOQV DJVIJa+U6Wq9CeVXSu3GUMjrXWcTe2hd37IJtABlaSQG7qV+1dvgeqOoqaOq0n/pXyxV c2t2djDhXb4ufoa791ZOoDSGYDf+jRxxLyIwFJou5pXbvBgDoaNXiKn+yiYBNV3c5FPI WYPyw6MrvvpscixxRUZ8pOxRfo0/wzIp0R82tYuuiUHDtByRay6ltL2JhjruO61+Nebo vHBw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:message-id:date:to:from:dkim-signature :delivered-to:arc-authentication-results; bh=fI6Pjx7kR1lzQLIwXlns/d4KZJJwKmZBRojhnhANWF4=; b=Ydgr80xzCWbRBm/KkDsGd8xG8WG0TfA3/bLuzoLskQRy45AoqYtNYmh9rVWxRcPK+j Kp94L3kN/gyl/Uov0xu6urKDfWXZLp/oLmXPe3rW4uJZfELOqD2ZD9ktjvdCLLJ80mIQ iJ5sLlG9f+HLwr0K9DRHdrjp36afG7MC2XpgXm74kNSqfR6w+1xbAU+88ezmbonYVOCc Ul5/pngNUmOdpfkvDq5ewLiQpBjrt3Oc8+po6itxg7qNuguA7/pyteZB8ju4ucszciZ1 KgsqJXNOUTC82ffSQLfKij7F9kHwiRupAnRn37RUZSW6HyvKrOJ3KTGCD/j3AFtjFKmQ XkMQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@posteo.de header.s=2017 header.b=D848oI0h; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=posteo.de Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id i10-v6si6017654wre.380.2018.07.31.12.16.43; Tue, 31 Jul 2018 12:16:44 -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=@posteo.de header.s=2017 header.b=D848oI0h; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=posteo.de Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id A7C9C68832E; Tue, 31 Jul 2018 22:16:24 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mout02.posteo.de (mout02.posteo.de [185.67.36.66]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 82E4268832E for ; Tue, 31 Jul 2018 22:16:17 +0300 (EEST) Received: from submission (posteo.de [89.146.220.130]) by mout02.posteo.de (Postfix) with ESMTPS id 076E021251 for ; Tue, 31 Jul 2018 21:16:33 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.de; s=2017; t=1533064594; bh=3yxo6LmIU1mSO2JmuKQCIPlN7M/XzzNUckdol3vNTu8=; h=From:To:Subject:Date:From; b=D848oI0hYkVu+1w3sDE5s8ZrFOlkgZq3xhWe7+yEo10ZhEJxWEJxtBTpY6f4rfQ7L 1mYC3h7CB/Z5afAV+etSW1aHS870vKqfXoHKaMJW6UJYws/E/Y/yxiQ+iCvor71d5q 6rc+XfEHODtUJX8p0Oudqguav6wqBirPO/kRlpfUiwsygT26qeDXabZdVBlb9H1/2C 9o4LdyxE9VHsRMNveSdgCzcDl3DQ/3Fydg7XjElxhWcUd3I2m1zqxEKcGc0RgfIHsD aAbwyzRJNO9Zbzbk+yNpAQWQuoF0oFSY2IHYxm7L3UX59RK5cgy5tNXD6pxWmCGYm8 TCp4obi64K6ZQ== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 41g5lP3Vfqz9rxN for ; Tue, 31 Jul 2018 21:16:33 +0200 (CEST) From: Karsten Otto To: ffmpeg-devel@ffmpeg.org Date: Tue, 31 Jul 2018 21:16:32 +0200 Message-Id: <20180731191632.2327-1-ottoka@posteo.de> X-Mailer: git-send-email 2.14.3 (Apple Git-98) Subject: [FFmpeg-devel] [PATCH] aadec: alternate mp3 seek handling 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" After seeking, determine the offset of the next frame in the decrypted buffer by scanning the first few bytes for a valid mp3 header. This significantly improves the listening experience for audio content with untypical encoding. --- This is a refinement of an earlier patch iteration, according to lessons learned and discussions on the mailing list: Scan a limited range to find the first shifted frame only, check for a very specific bit pattern, and add extra checks and guards for better code maintainability. Unfortunately, this variant violates the architectural layering between demuxer and codec. But I did some more testing with untypical encodings, where the current estimation mechanism fails, and the resulting audio on seek was just too horribly annoying. I believe the better listening experience outweighs the architectural uglyness, so this should be in the official code base. But if you think otherwise, just let me know, and I will keep this a private patch. libavformat/aadec.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/libavformat/aadec.c b/libavformat/aadec.c index d83f283ffe..9b1495c218 100644 --- a/libavformat/aadec.c +++ b/libavformat/aadec.c @@ -37,7 +37,7 @@ #define TEA_BLOCK_SIZE 8 #define CHAPTER_HEADER_SIZE 8 #define TIMEPREC 1000 -#define MP3_FRAME_SIZE 104 +#define MP3_FRAME_SIZE 105 typedef struct AADemuxContext { AVClass *class; @@ -51,7 +51,7 @@ typedef struct AADemuxContext { int64_t current_chapter_size; int64_t content_start; int64_t content_end; - int seek_offset; + int did_seek; } AADemuxContext; static int get_second_size(char *codec_name) @@ -179,7 +179,7 @@ static int aa_read_header(AVFormatContext *s) st->codecpar->sample_rate = 22050; st->need_parsing = AVSTREAM_PARSE_FULL_RAW; avpriv_set_pts_info(st, 64, 8, 32000 * TIMEPREC); - // encoded audio frame is MP3_FRAME_SIZE bytes (+1 with padding, unlikely) + // encoded audio frame is MP3_FRAME_SIZE bytes (-1 without padding) } else if (!strcmp(codec_name, "acelp85")) { st->codecpar->codec_id = AV_CODEC_ID_SIPR; st->codecpar->block_align = 19; @@ -231,7 +231,7 @@ static int aa_read_header(AVFormatContext *s) ff_update_cur_dts(s, st, 0); avio_seek(pb, start, SEEK_SET); c->current_chapter_size = 0; - c->seek_offset = 0; + c->did_seek = 0; return 0; } @@ -244,7 +244,7 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt) int trailing_bytes; int blocks; uint8_t buf[MAX_CODEC_SECOND_SIZE * 2]; - int written = 0; + int written = 0, offset = 0; int ret; AADemuxContext *c = s->priv_data; uint64_t pos = avio_tell(s->pb); @@ -297,16 +297,33 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt) if (c->current_chapter_size <= 0) c->current_chapter_size = 0; - if (c->seek_offset > written) - c->seek_offset = 0; // ignore wrong estimate + if (c->did_seek) { + c->did_seek = 0; + + if (s->streams[0]->codecpar->codec_id == AV_CODEC_ID_MP3 && written >= MP3_FRAME_SIZE + 3) { + for (offset = 0; offset < MP3_FRAME_SIZE; ++offset) { + // find mp3 header: sync, v2, layer3, no crc, 32kbps, 22kHz, mono + if ((buf[offset + 0] ) == 0xff && + (buf[offset + 1] ) == 0xf3 && + (buf[offset + 2] & 0xfc) == 0x40 && + (buf[offset + 3] & 0xf0) == 0xc0) + break; + } + if (offset == MP3_FRAME_SIZE) offset = 0; // not found, just use as is + } + + ff_update_cur_dts(s, s->streams[0], + (pos + offset - c->content_start - CHAPTER_HEADER_SIZE * (c->chapter_idx - 1)) + * TIMEPREC); + } - ret = av_new_packet(pkt, written - c->seek_offset); + if (offset > written) offset = 0; + ret = av_new_packet(pkt, written - offset); if (ret < 0) return ret; - memcpy(pkt->data, buf + c->seek_offset, written - c->seek_offset); + memcpy(pkt->data, buf + offset, written - offset); pkt->pos = pos; - c->seek_offset = 0; return 0; } @@ -349,13 +366,7 @@ static int aa_read_seek(AVFormatContext *s, c->current_codec_second_size = c->codec_second_size; c->current_chapter_size = chapter_size - chapter_pos; c->chapter_idx = 1 + chapter_idx; - - // for unaligned frames, estimate offset of first frame in block (assume no padding) - if (s->streams[0]->codecpar->codec_id == AV_CODEC_ID_MP3) { - c->seek_offset = (MP3_FRAME_SIZE - chapter_pos % MP3_FRAME_SIZE) % MP3_FRAME_SIZE; - } - - ff_update_cur_dts(s, s->streams[0], ch->start + (chapter_pos + c->seek_offset) * TIMEPREC); + c->did_seek = 1; return 1; }