From patchwork Fri Aug 5 22:54:25 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christopher Snowhill X-Patchwork-Id: 105 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.140.67 with SMTP id o64csp1945336vsd; Fri, 5 Aug 2016 16:11:18 -0700 (PDT) X-Received: by 10.28.170.198 with SMTP id t189mr5360287wme.19.1470438678356; Fri, 05 Aug 2016 16:11:18 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id bq6si20201979wjc.14.2016.08.05.16.11.18; Fri, 05 Aug 2016 16:11:18 -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=@gmail.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; dmarc=fail (p=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id EA9C568A771; Sat, 6 Aug 2016 02:11:07 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-yw0-f193.google.com (mail-yw0-f193.google.com [209.85.161.193]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A8A8468A70A for ; Sat, 6 Aug 2016 02:10:58 +0300 (EEST) Received: by mail-yw0-f193.google.com with SMTP id z8so22202055ywa.0 for ; Fri, 05 Aug 2016 16:11:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=RT5XUvdmaG7W6FQVt2oUkIOfygQbqiJdogtijmPKnKM=; b=E3IiubJmW6vEF03CuYHZOcsLeDDhcCRwlwNxbAb7zBbDF3yS7ouo9bGEAkoOF0+cpr GkmTumogCT0sfMKMoHsELaMyo6c9O/uej+W2X5XMd0t5nFWBnDZWWu0yH9Cm4dcncpsS uCmURNMLVtYouOagXKmsY5NkoKtrUVxK0w5DD1IORNcL+ZrN6VGluHrsjKveo+AM4Iut NFgD2ACBAAZH0Dpuo+3m9dtDd9FZ075gwTN394VcFKacEstK3FYWBlxIvgoYS1b0SaTA jfZFH7XNiWJliT8Xikgv7LMc5PiTpyExud0g3LYYjvRX2dF2PIOTb9XjiLlvPcZLkWpw 3lpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=RT5XUvdmaG7W6FQVt2oUkIOfygQbqiJdogtijmPKnKM=; b=fgu6AjPjne3Yeg94rIsPEHjKqtAxhvt+ESCInALhXcuQWc8A8G2FpzAGNNjA3ngO+N MBWj+n5ejS9YJy57pdaGdhYAxiAR9of7fnFFgbcLkHIUNgpeVbk7/YklEMWotonUqnBz ze9VdkHwsZuDS2q7Rvy3MEAptfL0XHAFsO/nspVUH/A039H60tnAdNiRymv4drLvZDW5 QdhrgC30ne96uekXD8J7kr4BrVqnMXri++/GZLd0vYz2aPM/KIL1tfKBnSjDCJA3EuPb prFvKfrjBqpY18eJoSAHEePOGoyMcmEj5CJfaoODqMGV5+xumPMpTfh2EKDagYcyZSrr EBKg== X-Gm-Message-State: AEkoouvEfCdRCRPADSLyWP9WnTE6xeZ9HqDem2rlV/jvPwSoLjQH94Ail58MdP2D7khd9g== X-Received: by 10.13.196.67 with SMTP id g64mr62914490ywd.224.1470437679614; Fri, 05 Aug 2016 15:54:39 -0700 (PDT) Received: from localhost.localdomain (99-11-158-33.lightspeed.irvnca.sbcglobal.net. [99.11.158.33]) by smtp.gmail.com with ESMTPSA id r186sm8883949ywr.38.2016.08.05.15.54.38 (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 05 Aug 2016 15:54:38 -0700 (PDT) From: kode54@gmail.com To: ffmpeg-devel@ffmpeg.org Date: Fri, 5 Aug 2016 15:54:25 -0700 Message-Id: <1470437665-78199-2-git-send-email-kode54@gmail.com> X-Mailer: git-send-email 2.7.4 (Apple Git-66) In-Reply-To: <1470437665-78199-1-git-send-email-kode54@gmail.com> References: <20160723110334.GB22139@nb4> <1470437665-78199-1-git-send-email-kode54@gmail.com> Subject: [FFmpeg-devel] [PATCHv3 2/2] avformat: parse iTunes gapless information 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: Chris Moeller MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Chris Moeller --- libavformat/mp3dec.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c index 56c7f8c..3055e2c 100644 --- a/libavformat/mp3dec.c +++ b/libavformat/mp3dec.c @@ -295,6 +295,53 @@ static void mp3_parse_vbri_tag(AVFormatContext *s, AVStream *st, int64_t base) } } +static void mp3_parse_itunes_tag(AVFormatContext *s, AVStream *st, MPADecodeHeader *c, int64_t base, int vbrtag_size, unsigned int *size, uint64_t *duration) +{ + uint32_t v; + AVDictionaryEntry *de; + MP3DecContext *mp3 = s->priv_data; + size_t length; + uint32_t zero, start_pad, end_pad; + uint64_t last_eight_frames_offset; + int i; + + if (!s->metadata || !(de = av_dict_get(s->metadata, "iTunSMPB", NULL, 0))) + return; + + length = strlen(de->value); + + /* Minimum length is one digit per field plus the whitespace, maximum length should depend on field type + * There are four fields we need in the first six, the rest are currently zero padding */ + if (length < (12 + 11) || length > (10 * 8 + 2 * 16 + 11)) + return; + + if (sscanf(de->value, "%x %x %x %llx %x %llx", &zero, &start_pad, &end_pad, duration, &zero, &last_eight_frames_offset) < 6) { + *duration = 0; + return; + } + + mp3->start_pad = start_pad; + mp3->end_pad = end_pad; + if (end_pad >= 528 + 1) + mp3->end_pad = end_pad - (528 + 1); + st->start_skip_samples = mp3->start_pad + 528 + 1; + av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3->end_pad); + if (!s->pb->seekable) + return; + + *size = (unsigned int) last_eight_frames_offset; + avio_seek(s->pb, base + vbrtag_size + last_eight_frames_offset, SEEK_SET); + for (i = 0; i < 8; i++) { + v = avio_rb32(s->pb); + if (ff_mpa_check_header(v) < 0) + return; + if (avpriv_mpegaudio_decode_header(c, v) != 0) + break; + *size += c->frame_size; + avio_skip(s->pb, c->frame_size - 4); + } +} + /** * Try to find Xing/Info/VBRI tags and compute duration from info therein */ @@ -303,8 +350,10 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) uint32_t v, spf; MPADecodeHeader c; int vbrtag_size = 0; + unsigned int size = 0; MP3DecContext *mp3 = s->priv_data; int ret; + uint64_t duration = 0; ffio_init_checksum(s->pb, ff_crcA001_update, 0); @@ -327,16 +376,29 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) mp3_parse_vbri_tag(s, st, base); if (!mp3->frames && !mp3->header_filesize) + vbrtag_size = 0; + + mp3_parse_itunes_tag(s, st, &c, base, vbrtag_size, &size, &duration); + + if (!mp3->frames && !size && !duration) return -1; /* Skip the vbr tag frame */ avio_seek(s->pb, base + vbrtag_size, SEEK_SET); - if (mp3->frames) + if (duration) + st->duration = av_rescale_q(duration, (AVRational){1, c.sample_rate}, st->time_base); + else if (mp3->frames) st->duration = av_rescale_q(mp3->frames, (AVRational){spf, c.sample_rate}, st->time_base); if (mp3->header_filesize && mp3->frames && !mp3->is_cbr) st->codecpar->bit_rate = av_rescale(mp3->header_filesize, 8 * c.sample_rate, mp3->frames * (int64_t)spf); + if (size) { + if (duration) + st->codecpar->bit_rate = av_rescale(size, 8 * c.sample_rate, duration); + else if (mp3->frames) + st->codecpar->bit_rate = av_rescale(size, 8 * c.sample_rate, mp3->frames * (int64_t)spf); + } return 0; }