From patchwork Wed Oct 5 02:27:53 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rodger Combs X-Patchwork-Id: 878 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.140.66 with SMTP id o63csp80879vsd; Tue, 4 Oct 2016 19:28:17 -0700 (PDT) X-Received: by 10.194.55.65 with SMTP id q1mr5293797wjp.45.1475634497863; Tue, 04 Oct 2016 19:28:17 -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 h79si29102452wme.119.2016.10.04.19.28.16; Tue, 04 Oct 2016 19:28:17 -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 E8FE0689DEE; Wed, 5 Oct 2016 05:27:53 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-it0-f66.google.com (mail-it0-f66.google.com [209.85.214.66]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2637C689C91 for ; Wed, 5 Oct 2016 05:27:47 +0300 (EEST) Received: by mail-it0-f66.google.com with SMTP id j69so9941584itb.1 for ; Tue, 04 Oct 2016 19:28:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id:in-reply-to:references; bh=u+rRpMpOghk6L9t5egZwC6Spz00e3rovK2ZoZ0p95TI=; b=pJeLix5y22/MoEkFqOa2csiENm84xB7lMYcQSARxlCTlFbdAHmL7mt3P69a5GnKMe1 7yl9tyylnVl3rqXf85Pk5uVqzHZdOp2RqzSevoNvmWfobm2oekrC1tcRRujOgNWqp9P2 lpw7aaGFrhT7QKfFI+rb6KzezGWXX/0TaY0wMEhS8mX4es481nIKoxJ0uuGyYPWvlYu/ kF6YCpXM01vOp3zy8FAUm9dVHfaUAOPyD+OI9pPY09sa6hOwOxpQXBqdeVAt8lLE0mWr BpcaaBqdt248SE6h56eX4UT/Mz203yMXBDqbXWsDAqlzcHVIop8KROnTGbMc5+9xRTFk O23Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=u+rRpMpOghk6L9t5egZwC6Spz00e3rovK2ZoZ0p95TI=; b=EEzvnH0uln1c7wbTbNrEn8+w6C/74FQlG6xsqLdCAsRaTjqfdhGO3bAPk8WnQzHh1X n9gJ12r1WzdIFj7p5U7hhxgQYdH3QjJUOjM4FKmhGkkSoA9Ds9uNiuClaqoi6wsaDOT9 u1qckO0Tn9Riz0qpXPJ7IuscLcpfUnNjjcsFQHOmZRA18AX7VhHw4Mn2N9qqIlMw9rop sbHcSWxzoMM5ReJ3x9y6Mg3Et16fmnHkjJq/ec54hKGVl1xWw2k2oi+0vZEeMuafdlww g0ynrhOEXTlypaP2pzhsFGlNigeYs4yzKQt6lwS4SXf6wJ3r0XFr0lbn5ZtYx6CfAGFh dwgA== X-Gm-Message-State: AA6/9Rl8nvfn+xsiSxRtfBMUUGFdbCQza3WlBCz8KBuFiX2PklY+VEIsEnqxBDO+ma0BZw== X-Received: by 10.107.150.195 with SMTP id y186mr8535075iod.8.1475634480799; Tue, 04 Oct 2016 19:28:00 -0700 (PDT) Received: from Rodgers-MacBook-Pro.local.net (c-73-209-137-129.hsd1.il.comcast.net. [73.209.137.129]) by smtp.gmail.com with ESMTPSA id r123sm11707911ith.1.2016.10.04.19.28.00 for (version=TLS1 cipher=AES128-SHA bits=128/128); Tue, 04 Oct 2016 19:28:00 -0700 (PDT) From: Rodger Combs To: ffmpeg-devel@ffmpeg.org Date: Tue, 4 Oct 2016 21:27:53 -0500 Message-Id: <20161005022754.44256-2-rodger.combs@gmail.com> X-Mailer: git-send-email 2.10.0 In-Reply-To: <20161005022754.44256-1-rodger.combs@gmail.com> References: <20161005022754.44256-1-rodger.combs@gmail.com> Subject: [FFmpeg-devel] [PATCH 2/3] lavf/mov: improve `tref/chap` chapter 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" 3 parts: - Supports multiple chapter streams - Exports regular text chapter streams as opaque data. This prevents consumers from showing chapters as if they were regular subtitle streams. - Exports video chapter streams as thumbnails, and provides the first one as an attached_pic. --- libavformat/isom.h | 3 ++- libavformat/mov.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/libavformat/isom.h b/libavformat/isom.h index 2246fed..9038057 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -210,7 +210,8 @@ typedef struct MOVContext { unsigned trex_count; int itunes_metadata; ///< metadata are itunes style int handbrake_version; - int chapter_track; + int *chapter_tracks; + unsigned int nb_chapter_tracks; int use_absolute_path; int ignore_editlist; int ignore_chapters; diff --git a/libavformat/mov.c b/libavformat/mov.c index a15c8d1..d0f1316 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -3971,7 +3971,20 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_chap(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - c->chapter_track = avio_rb32(pb); + unsigned i, num; + void *new_tracks; + + num = atom.size / 4; + if (!(new_tracks = av_malloc_array(num, sizeof(int)))) + return AVERROR(ENOMEM); + + av_free(c->chapter_tracks); + c->chapter_tracks = new_tracks; + c->nb_chapter_tracks = num; + + for (i = 0; i < num && !pb->eof_reached; i++) + c->chapter_tracks[i] = avio_rb32(pb); + return 0; } @@ -5034,25 +5047,50 @@ static int mov_probe(AVProbeData *p) static void mov_read_chapters(AVFormatContext *s) { MOVContext *mov = s->priv_data; - AVStream *st = NULL; + AVStream *st; MOVStreamContext *sc; int64_t cur_pos; - int i; + int i, j; + int chapter_track; + for (j = 0; j < mov->nb_chapter_tracks; j++) { + chapter_track = mov->chapter_tracks[j]; + st = NULL; for (i = 0; i < s->nb_streams; i++) - if (s->streams[i]->id == mov->chapter_track) { + if (s->streams[i]->id == chapter_track) { st = s->streams[i]; break; } if (!st) { av_log(s, AV_LOG_ERROR, "Referenced QT chapter track not found\n"); - return; + continue; } - st->discard = AVDISCARD_ALL; sc = st->priv_data; cur_pos = avio_tell(sc->pb); + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + st->disposition |= AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS; + if (st->nb_index_entries) { + // Retrieve the first frame, if possible + AVPacket pkt; + AVIndexEntry *sample = &st->index_entries[0]; + if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) { + av_log(s, AV_LOG_ERROR, "Failed to retrieve first frame\n"); + goto finish; + } + + if (av_get_packet(sc->pb, &pkt, sample->size) < 0) + goto finish; + + st->attached_pic = pkt; + st->attached_pic.stream_index = st->index; + st->attached_pic.flags |= AV_PKT_FLAG_KEY; + } + } else { + st->codecpar->codec_type = AVMEDIA_TYPE_DATA; + st->codecpar->codec_id = AV_CODEC_ID_BIN_DATA; + st->discard = AVDISCARD_ALL; for (i = 0; i < st->nb_index_entries; i++) { AVIndexEntry *sample = &st->index_entries[i]; int64_t end = i+1 < st->nb_index_entries ? st->index_entries[i+1].timestamp : st->duration; @@ -5101,8 +5139,10 @@ static void mov_read_chapters(AVFormatContext *s) avpriv_new_chapter(s, i, st->time_base, sample->timestamp, end, title); av_freep(&title); } + } finish: avio_seek(sc->pb, cur_pos, SEEK_SET); + } } static int parse_timecode_in_framenum_format(AVFormatContext *s, AVStream *st, @@ -5425,7 +5465,7 @@ static int mov_read_header(AVFormatContext *s) av_log(mov->fc, AV_LOG_TRACE, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); if (pb->seekable) { - if (mov->chapter_track > 0 && !mov->ignore_chapters) + if (mov->nb_chapter_tracks > 0 && !mov->ignore_chapters) mov_read_chapters(s); for (i = 0; i < s->nb_streams; i++) if (s->streams[i]->codecpar->codec_tag == AV_RL32("tmcd")) {