From patchwork Wed Aug 31 11:35:48 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: erkki.seppala.ext@nokia.com X-Patchwork-Id: 365 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.140.134 with SMTP id o128csp328411vsd; Wed, 31 Aug 2016 04:38:20 -0700 (PDT) X-Received: by 10.194.127.163 with SMTP id nh3mr8629918wjb.74.1472643499303; Wed, 31 Aug 2016 04:38:19 -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 g79si10122770wme.57.2016.08.31.04.38.18; Wed, 31 Aug 2016 04:38:19 -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=@nokia.onmicrosoft.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=nokia.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B557A689B1E; Wed, 31 Aug 2016 14:36:15 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from EUR01-DB5-obe.outbound.protection.outlook.com (mail-db5eur01on0118.outbound.protection.outlook.com [104.47.2.118]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C7AB4689A87 for ; Wed, 31 Aug 2016 14:36:04 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nokia.onmicrosoft.com; s=selector1-nokia-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=VmNCX8DIkBccPIFUf8S1TbbxlOdcQufe5aHDuSJNEg8=; b=WlsORcxn3OLIjJqFxHKv1EP043kJia7rjOCvPomTjYYr2NJ65waVvgqmraCatkre4zsyJ7wRFHxG6Litbe0VsqD0PN6OY4ke1pmOadazwUpm7H92RW5CRfT5nHDTyv/gHp0FWO4dmgkMrWCkkE/NtkveWOsyKSI8hfNJTwnXZK4= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=erkki.seppala.ext@nokia.com; Received: from erkkise-laptop.vincit.intranet (131.228.2.27) by DB6PR0701MB2536.eurprd07.prod.outlook.com (10.168.76.135) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384) id 15.1.599.9; Wed, 31 Aug 2016 11:36:08 +0000 Received: by erkkise-laptop.vincit.intranet (Postfix, from userid 1000) id CDDB54CB948; Wed, 31 Aug 2016 14:36:01 +0300 (EEST) From: =?UTF-8?q?Erkki=20Sepp=C3=A4l=C3=A4?= To: Date: Wed, 31 Aug 2016 14:35:48 +0300 Message-ID: <1472643361-10118-6-git-send-email-erkki.seppala.ext@nokia.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1472643361-10118-1-git-send-email-erkki.seppala.ext@nokia.com> References: <1471943019-14136-1-git-send-email-erkki.seppala.ext@nokia.com> MIME-Version: 1.0 X-Originating-IP: [131.228.2.27] X-ClientProxiedBy: AM4PR02CA0021.eurprd02.prod.outlook.com (10.165.239.159) To DB6PR0701MB2536.eurprd07.prod.outlook.com (10.168.76.135) X-MS-Office365-Filtering-Correlation-Id: d55de7c7-b22c-4505-5bca-08d3d193001a X-Microsoft-Exchange-Diagnostics: 1; DB6PR0701MB2536; 2:87m4U8RrAsymbVq9e1oVsegys4EimCMQVIodQ5cDOqaiVE2S8v3hrgB8+Gq/Mi0ke1J3DfW8WMV5COvUncayevSvTGGIX3NWnbuUYIokQNC31/qK0tfrMbPZYvyc7lTbasqp6JFeGgwjWGuqa9SxrTY5qicPH4GsvP28LZom4T1Mtb6Xo0/spvEs7r6+1MCQ; 3:iwwdGunYqtmlUWAMbIpeBV/llmCwzAC8TQIVcbPGZnwuvSYPOtKwIWAX6cn//pEDaer0UxC1Q9NV4JcFt5Uhh7jdaj0AXpVzQWAANNSkXd6lAUOY573c6ZXKVchNKNhp; 25:0OjHyg/TRAvMxaXxvytT3RU+U7+Hxg65Bc6ovICPOreCPg1mySIRaeyshjr7PFXrhsG9rchW/9yZtbvuRb38HjXM5sbOrX8O7stG7Bg9oadjMSjL9Vj1W3TIMaWU8WXsr6YC7qIp5c51qF7SvQbykiXnOCfOns4iCb16qavmJpcawU8bv+XxEPyDxB4jB7/lOIvRQg062S7erMBAFi91KQ5yq17OAmZla6fKm6D8eez0vcKu4a7ZE17Pob/VAaB3JCOXl7KbEQPCrG2AJraY7wqwatu8H24zEQ2alxpda6yMhrx7upj5fblK374Ayq10HvY7/8VC2Ip1zToiUAcT6P3uLmlA7gnLA3j7B9hy39+TE/Wx8Ptmf9pOHe7aGrKRsGDiMMLc/ubKDMPBR38CUKgz8lyxJUZgFjbGMOD4Dwk= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:DB6PR0701MB2536; X-Microsoft-Exchange-Diagnostics: 1; DB6PR0701MB2536; 31:6Qlm0f9B7vpJzxsa9OT6183aTb2CGBCoOVoFCiZ/2xmKIbOQPNALohiDzno3/ZsSEoz2tzbvLzrvvW8qJITs2sXPpJVeA6iY1AYDnB2621czXGRnbqddCJuJTTrLnCFAEo6N+DwNLhcjaMG6zUPYyNYfiHsOjtiRmHGBXtF1jIBhbi8+MK7LKd+qnCi1rtf10AnIvWa1Ef9dln1JHAqLSf6gr+k8fNN6mPBw67mdS94=; 20:B06ytLGz99kgetIilO6aujSEERrKprnHFDA9ouoi/gwYPStkIC5Ro5Ra3onqCl9Zz+1lYiGUcSehksskIIpq3CG/WqUIddzMHmE6kalAQwC5DWfSd7xG6X5XvBbNlQoY0qhDp2Ukk28urxqWhk46SWOb516S1LKeD1maOU3mwub8fQ9NEmqdvKPhwEusxis9Rz4DFj50CXLd07XSbuZ1m6dQ4cla/H6YMMJvFVWAEw8Pik22i8AbdV3Rk6/AvjeVbFyilNZBqIyNkMAJRzmTu3lFZl+duT9jtRcs4xQFWYQmygl9Pw6/46u6zv8ckj+Dfy1boh3bgPxgurHyg3dYvsh+gCVJLF7doQ9R+LGezL3+ZOdjgzlk2NSLCcQkqYvhmm+tTM/Do6xCwUDIvmZ2iTPZj/Fc36LTHrxZd5OMxpsaM74hVIeepu6kgHrbXhedVBfQR+JXJAQMqorKWPEPPPANzKYXJtWTlRWHmfv//ZqU7Sreh/ozu/ua0C7Slcw6 X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(82608151540597); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040176)(601004)(2401047)(8121501046)(5005006)(10201501046)(3002001)(6055026); SRVR:DB6PR0701MB2536; BCL:0; PCL:0; RULEID:; SRVR:DB6PR0701MB2536; X-Microsoft-Exchange-Diagnostics: 1; DB6PR0701MB2536; 4:RmaWrYlDBPnzeR9hChHQqkyfrU7hOPjBIAKHP03Q5AgibeCoiB5nf5zvNXGoFgfiimZQfetmJDaTVbo8RDNQxwzarSxCk/fpLJtXZcue4jRyjpRJF4CcyIGcKCA92Fd6CK9CYy7+poNlRMq6z5pp28plD86Fdg8Xx+gYti4DBsOx680uMTdBYu02F2ieMFV6hq7+HsFV6qnAsFg97lxgNtdfSepf3l1OuY4FG8qFXzCWLaJ36uPufdAUTU6M/+KlbyMYbBGU17pltgRxoJZm/FdSeB/Z/e0ZG6FXhDj2ROqrYf+pFyahMvKkd26holL+HvPSs4XrOpn/rc5RhS15IoCAHYHNvz6Em8/lZ+YiLKTXdwhgX7XdaRvMeasADe1YOkqNyRhpKS9g/R8zULt111AsnQj8a9hJS+XUAr7FG7yy93eL+oYwH8bFzXpKiyIA X-Forefront-PRVS: 00514A2FE6 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6009001)(7916002)(199003)(189002)(189998001)(90966002)(106356001)(2950100001)(19580405001)(86362001)(97736004)(36756003)(5660300001)(52956003)(33646002)(110136002)(19580395003)(46386002)(42186005)(5820100001)(122856001)(81156014)(23676002)(92566002)(4326007)(50986999)(450100001)(105586002)(107886002)(101416001)(50226002)(2351001)(229853001)(8676002)(6116002)(7846002)(76176999)(47776003)(68736007)(586003)(81166006)(50466002)(4001430100002)(2870700001)(66066001)(7736002)(3846002)(2906002)(45336002)(305945005)(2004002); DIR:OUT; SFP:1102; SCL:1; SRVR:DB6PR0701MB2536; H:erkkise-laptop.vincit.intranet; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: nokia.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtEQjZQUjA3MDFNQjI1MzY7MjM6VFg2cWprWHdEZWhORWRFVURVNFkwSW80?= =?utf-8?B?U3hXazlJd01ZNWtyZndJNElvRFBBV0NZRUVKeGRKVDlGVWI1Sks0dWpUd0dI?= =?utf-8?B?WVF5RGswQWtydE1MN0k0MVB2WGd0akNBV2ZYanRIYmhzODRodExxc1I3OGJs?= =?utf-8?B?OUJpQTlURjRvbGF2VnpQVkVrcnc3VjMxMDBjdWR0ZFNoZXdrN2R5azhDck84?= =?utf-8?B?eHFsYk9PK2hKZ3hYcVRGUjUxeUVGcGw1Q0JsYzNRbkFCUUJ5UE96d2VIbTZh?= =?utf-8?B?VTZuR0VaUUx0STZIYTVzTWt1UmJQM0N4Q2pJc0VzYXo5Rzc5dENkdlJ0MGJO?= =?utf-8?B?ZUc4TEh0bWpCdklrd3FSSFc2TjYrZHAyaDdXNEZFRGhCWmFyUGl4b1RTUVg4?= =?utf-8?B?N2J6Vkp5d2d1ajdkcDE4bFNySVhBcWVSM2JzSVZZaXlWZjYxYU1kWFBaRE16?= =?utf-8?B?VzdCQjhMS09WTU9hUjBMZXFtdWNFVllFOU40OXdpM1ZGWGZWanRvY0RBWGQ5?= =?utf-8?B?UFo3N05LbFFaeVQ3M0VwaEhRKy9meXRjME53b1ZNU2dXYkc4eHdYNVJKNXB2?= =?utf-8?B?L1YyUExSZU5MSUQ2ZkZkQzBpdWtWNnhqTjZwRnVPMVJvTTMzc2ZIbUdFRTVX?= =?utf-8?B?VlpsVmZiZ2d3TE9iL3h1N2RQZU9PQkoxYmlKamNESm9sT1RWQjlNZzFXb3lI?= =?utf-8?B?c2F5S3hzZG9lZS95SWI1dTVkS0ppMWZaOFBFaXRWRmlDQW1wd0hLRGppVjYz?= =?utf-8?B?RlNzaWtMY0Q1eVczMGQ5eUc3QWZMTUNqL0ErdGQwVWEramJtOXR5RXZ0anJX?= =?utf-8?B?c085RjBqTmFscTlTMkFCL3NGWVNkQzYxbWFUS2tvclBWaTZiWUsycVdzbkNR?= =?utf-8?B?RjRtZmJ1V000bytrZ1hrNW1rZ29ZbjJlRWY0Yi9SKzgra1IrcmNNUTgyMEcz?= =?utf-8?B?MWVtUEFlL1FzZlBRRzdNZ1JOSzNKU2dIWlB6dE1SVHFrZVBzUGpaSFgrS3dh?= =?utf-8?B?Yy9TQ2pEKzBjaVg2NjlRZ2NVZFU0bnJ3MkQrOXAwREtpdHRWbUpKNzhwVTI3?= =?utf-8?B?THphMjNWa2draGNsM3dwVDhiT3N2YnBJK2dxQStqRGl0UlJlZ3NVaEE0OFJH?= =?utf-8?B?cTNZdFZYbXArclZZYXI5ZzVIeENKLzc2Z1RSU3NlQmR1cGIwYVF4Q1J2MHBl?= =?utf-8?B?ZE81dU1QNGlRd3ZSaCtLcjZhUHZZVWs2YzBrQ0lzZWkvL2toM2J4NDdEQ1cr?= =?utf-8?B?VVRiY0hFMEozanA0VzBiUjR2aitKTmFLZG5BcXVwYWFpVklJdGpSSjFDTWNl?= =?utf-8?B?MWk2YWtVdEt6VngxTUJXQ1ZPaHNDaFNLOHlWNmRTMU9DOFZKTU93VU5aaGFu?= =?utf-8?B?RWM5RVh2NDBUR254RVo1ZWE4eWNwdGpUUzVBMTFaakxaK2hiVVNHN3J0UFI0?= =?utf-8?B?dlRaM3gvVDRFdTMzemJKeVJwVXpCUUMvWEpwS25GRzMzS0x5endZQ3FUL3o0?= =?utf-8?B?RkFxTGY0S1Y0aFpDalNIYW1PbGZvYzZocE13bDJISURBT1lmT2tGWGdFdDRK?= =?utf-8?B?ZWtWU29nTVJjcFlzazdvRkw4Y1FXV2RkWmZ1NkxNbWluUGkyb2dENlpZUFp4?= =?utf-8?B?bU45clBZajNKd3B2YjJyNmM1dDAwWWI5dm1WYkFjaWVKbnJXVmZ6dWpRU0Zh?= =?utf-8?B?NHBPVEZzVGRsTnJCTUxkUWxZbmIrdG9rb3E5RllERDR2Q0dyQ2VmVWNHQTF1?= =?utf-8?B?YncrNWtYa2tBV0hGSjRqYm1nPT0=?= X-Microsoft-Exchange-Diagnostics: 1; DB6PR0701MB2536; 6:0K1xUqmuAWXdtNbgHw3sQJKhfEZpWw59lbj8+Nw5xjIsrujDpaKbte1CGs97AQw/LwBH2tQDHO7EVkD/DkfjS2decxD/cebvMTtVDv+UoUAwHeQ/5AiGeOckl3FYygBvBLbzHXCbEM++sXKa0UUv7RE8usa5vEmgGjDmnZb0600cjoDvhcTAhIl4XKaKLH5MN2Ed1PkbuO7GQTYNyfniIUXcOtQGyKRJ+3RhQ1v7hRTOItAGyR34NZVW8LLG4q3BArXjEKrlIvCvuMh5udX5G39PdJxXR3FB2fMzrHpRmMUWDehuO47GThwASGwEgnhni8zQs6v/WU16xupNKOdYdw==; 5:JBAcyYIwM1x0yq5ctlqh1Oa6eyuMsQmqxHwnANOz2h85HBK0v7fhXhkY5jqrRW7l0v4NgVBPIFPZw+/42XF4VT44jTgB4sxmw1EN58DxY3kDPa0062JbELajQLZPvS9wkQ3IWbreFSAMrzOqDOygKw==; 24:IWR5LWCtkob37OKbjM/kz2l0utjFB+ro1n7R1NCjkvCg0AA1JI/aEjH2ZnG2l6Z2zvoyAXUGzNblNhuyBxhhHLvchm0MEmJire2N7UH3RMY=; 7:uzWFW14CpPWK6b8VznbawsXp5L2iUdOoeUP5qyvkj/lfCREzBI+SGV3zcXzpLQJ3Dvp4KG33dXAeWLCLo2zi1jTe4F9z7pZTOzPQ1W389VxJrplTh5KZJoP0O4mAc3rdAaazBIA9v5IHO5ttrCXVM6h7hQ4S/Rc1pzeVpf3Kxs5FiRgRKKdca906Pg3xLrooh5Y16s0rt/q3OKmKldtrgfvoz5G2EZedKXN4WQJt2xUxkSrSW0TqyLKR3nMTHu19 SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: nokia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 31 Aug 2016 11:36:08.0946 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB6PR0701MB2536 Subject: [FFmpeg-devel] [PATCH v2 05/18] avformat/movenc: support for multiple and client-provided track references 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: =?UTF-8?q?Erkki=20Sepp=C3=A4l=C3=A4?= , OZOPlayer Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Instead of one track reference, allow many, and instead of of track reference type (ie. 'cdsc'), allow many. In addition this patch allows client to explicitly add track references with side packet AV_PKT_DATA_TRACK_REFERENCES containing AVTrackReferences (which of there can many many). Internally MOVTrack's track references can be manipulated with helper functions ff_mov_tref* (and is used by a later patch for reading MOVTRefs). Multiple track references can be useful in particular with timed meta data tracks, indicating the track is related to multiple other tracks. This information ends up in ISO media file box 'tref' as specified by ISO/IEC 14496-12. Signed-off-by: Erkki Seppälä Signed-off-by: OZOPlayer --- libavcodec/avcodec.h | 19 +++++++- libavformat/Makefile | 4 +- libavformat/movenc.c | 127 +++++++++++++++++++++++++++++++++++++++++--------- libavformat/movenc.h | 5 +- libavformat/movtref.c | 115 +++++++++++++++++++++++++++++++++++++++++++++ libavformat/movtref.h | 75 +++++++++++++++++++++++++++++ 6 files changed, 318 insertions(+), 27 deletions(-) create mode 100644 libavformat/movtref.c create mode 100644 libavformat/movtref.h diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 0d0447e6..f45cdc2 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1348,6 +1348,15 @@ typedef struct AVCPBProperties { * Types and functions for working with AVPacket. * @{ */ + +typedef struct AVTrackReferences { + int next_tref_ofs; /** offset in bytes to the next AVTrackReferences or 0 if this is the last one*/ + char tag[4]; /** 4cc used for describing this */ + int nb_tracks; /** number of tracks */ + int tracks[1]; /** tracks this track refers to (contains nb_tracks entries) */ + /** followed by an optional gap for alignment purposes and another AVTrackReferences is applicaple */ +} AVTrackReferences; + enum AVPacketSideDataType { AV_PKT_DATA_PALETTE, @@ -1525,7 +1534,15 @@ enum AVPacketSideDataType { * should be associated with a video stream and containts data in the form * of the AVMasteringDisplayMetadata struct. */ - AV_PKT_DATA_MASTERING_DISPLAY_METADATA + AV_PKT_DATA_MASTERING_DISPLAY_METADATA, + + /** + * Define track references (in particular applicaple for ISO MP4 + * files). The data is a sequence of type AVTrackReferences + * (including the track list that follows it), for as long as + * indicated by the key's length. + */ + AV_PKT_DATA_TRACK_REFERENCES, }; #define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED diff --git a/libavformat/Makefile b/libavformat/Makefile index fda1e17..6a393ed 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -280,10 +280,10 @@ OBJS-$(CONFIG_MLV_DEMUXER) += mlvdec.o riffdec.o OBJS-$(CONFIG_MM_DEMUXER) += mm.o OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o OBJS-$(CONFIG_MMF_MUXER) += mmf.o rawenc.o -OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o replaygain.o +OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o replaygain.o movtref.o OBJS-$(CONFIG_MOV_MUXER) += movenc.o avc.o hevc.o vpcc.o \ movenchint.o mov_chan.o rtp.o \ - movenccenc.o rawutils.o + movenccenc.o rawutils.o movtref.o OBJS-$(CONFIG_MP2_MUXER) += mp3enc.o rawenc.o id3v2enc.o OBJS-$(CONFIG_MP3_DEMUXER) += mp3dec.o replaygain.o OBJS-$(CONFIG_MP3_MUXER) += mp3enc.o rawenc.o id3v2enc.o diff --git a/libavformat/movenc.c b/libavformat/movenc.c index f02458b..6cc315a 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -2631,14 +2631,22 @@ static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov, return size; } -static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track) +static int mov_write_tref_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track) { - avio_wb32(pb, 20); // size + int64_t pos = avio_tell(pb); + int i, j; + avio_wb32(pb, 0); // size ffio_wfourcc(pb, "tref"); - avio_wb32(pb, 12); // size (subatom) - avio_wl32(pb, track->tref_tag); - avio_wb32(pb, track->tref_id); - return 20; + for (j = 0; j < track->trefs.nb_trefs; ++j) { + int64_t pos_sub = avio_tell(pb); + MOVTRef* tref = &track->trefs.trefs[j]; + avio_wb32(pb, 0); // size (subatom) + avio_wl32(pb, tref->tag); + for (i = 0; i < tref->nb_track_ids; i++) + avio_wb32(pb, tref->track_ids[i]); + update_size(pb, pos_sub); + } + return update_size(pb, pos); } // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it) @@ -2749,8 +2757,8 @@ static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext "Not writing any edit list even though one would have been required\n"); } - if (track->tref_tag) - mov_write_tref_tag(pb, track); + if (track->trefs.nb_trefs) + mov_write_tref_tag(pb, mov, track); if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0) return ret; @@ -3487,16 +3495,82 @@ static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s) return 0; } +static int mov_tref_copy_from_side_data(MOVMuxContext *mov, MOVTrack *track, AVFormatContext *s) +{ + int size; + int ret; + int i; + MOVTRef *tref; + int *ref_tracks = NULL; + + char *ptr = (void*) av_stream_get_side_data(track->st, + AV_PKT_DATA_TRACK_REFERENCES, + &size); + + if (!ptr) + return 0; + + ret = 0; + while (ret == 0 && size >= sizeof(AVTrackReferences)) { + AVTrackReferences refs; + int *track_ids; + + // avoid any potential alignment issues by copying the struct before accessing it + // to a well-aligned address + memcpy(&refs, ptr, sizeof(refs)); + // as well as the ids + ref_tracks = av_malloc_array(refs.nb_tracks, sizeof(refs.tracks[0])); + memcpy(ref_tracks, &((AVTrackReferences*) ptr)->tracks, sizeof(refs.tracks[0]) * refs.nb_tracks); + + ret = ff_mov_tref_find_or_add(&track->trefs, + MKTAG(refs.tag[0], refs.tag[1], refs.tag[2], refs.tag[3]), + &tref); + if (ret < 0) + goto error; + + ret = ff_mov_tref_alloc(tref, refs.nb_tracks, &track_ids); + if (ret < 0) + goto error; + + for (i = 0; i < refs.nb_tracks; i++) { + int tref_stream_id = ref_tracks[i]; + int stream_idx; + for (stream_idx = 0; stream_idx < mov->nb_streams; ++stream_idx) + if (mov->tracks[stream_idx].st && + mov->tracks[stream_idx].st->id == tref_stream_id) { + track_ids[i] = mov->tracks[stream_idx].track_id; + break; + } + } + + size -= refs.next_tref_ofs; + ptr += refs.next_tref_ofs; + + av_free(ref_tracks); + if (refs.next_tref_ofs == 0) + break; + } + return 0; +error: + av_free(ref_tracks); + return ret; +} + static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) { int i; int64_t pos = avio_tell(pb); + int ret; avio_wb32(pb, 0); /* size placeholder*/ ffio_wfourcc(pb, "moov"); mov_setup_track_ids(mov, s); + for (i = 0; i < mov->nb_streams; i++) + if (mov->tracks[i].st) + mov_tref_copy_from_side_data(mov, &mov->tracks[i], s); + for (i = 0; i < mov->nb_streams; i++) { if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) continue; @@ -3508,34 +3582,42 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, } if (mov->chapter_track) - for (i = 0; i < s->nb_streams; i++) { - mov->tracks[i].tref_tag = MKTAG('c','h','a','p'); - mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id; - } + for (i = 0; i < s->nb_streams; i++) + if (!ff_codec_get_id(ff_codec_metadata_tags, mov->tracks[i].tag)) { + ret = ff_mov_tref_add_one_track(&mov->tracks[i].trefs, MKTAG('c','h','a','p'), mov->chapter_track); + if (ret < 0) + return ret; + } for (i = 0; i < mov->nb_streams; i++) { MOVTrack *track = &mov->tracks[i]; if (track->tag == MKTAG('r','t','p',' ')) { - track->tref_tag = MKTAG('h','i','n','t'); - track->tref_id = mov->tracks[track->src_track].track_id; + ret = ff_mov_tref_add_one_track(&mov->tracks[i].trefs, MKTAG('h','i','n','t'), mov->tracks[track->src_track].track_id); + if (ret < 0) + return ret; } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) { int * fallback, size; fallback = (int*)av_stream_get_side_data(track->st, AV_PKT_DATA_FALLBACK_TRACK, &size); - if (fallback != NULL && size == sizeof(int)) { - if (*fallback >= 0 && *fallback < mov->nb_streams) { - track->tref_tag = MKTAG('f','a','l','l'); - track->tref_id = mov->tracks[*fallback].track_id; - } + if (fallback != NULL && size == sizeof(int) && + *fallback >= 0 && *fallback < mov->nb_streams) { + ret = ff_mov_tref_add_one_track(&track->trefs, MKTAG('f','a','l','l'), *fallback); + if (ret < 0) + return ret; } } } for (i = 0; i < mov->nb_streams; i++) { if (mov->tracks[i].tag == MKTAG('t','m','c','d')) { int src_trk = mov->tracks[i].src_track; - mov->tracks[src_trk].tref_tag = mov->tracks[i].tag; - mov->tracks[src_trk].tref_id = mov->tracks[i].track_id; - //src_trk may have a different timescale than the tmcd track + + ret = ff_mov_tref_add_one_track(&mov->tracks[src_trk].trefs, + mov->tracks[i].tag, + mov->tracks[i].track_id); + if (ret < 0) + return ret; + + //src_trk may have a different timescale than the tmcd track mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration, mov->tracks[i].timescale, mov->tracks[src_trk].timescale); @@ -5346,6 +5428,7 @@ static void mov_free(AVFormatContext *s) av_freep(&mov->tracks[i].vos_data); ff_mov_cenc_free(&mov->tracks[i].cenc); + ff_mov_tref_free(&mov->tracks[i].trefs); } av_freep(&mov->tracks); diff --git a/libavformat/movenc.h b/libavformat/movenc.h index ea76e39..700d8d5 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -26,6 +26,7 @@ #include "avformat.h" #include "movenccenc.h" +#include "movtref.h" #define MOV_FRAG_INFO_ALLOC_INCREMENT 64 #define MOV_INDEX_CLUSTER_SIZE 1024 @@ -110,8 +111,8 @@ typedef struct MOVTrack { unsigned cluster_capacity; int audio_vbr; int height; ///< active picture (w/o VBI) height for D-10/IMX - uint32_t tref_tag; - int tref_id; ///< trackID of the referenced track + + MOVTRefs trefs; int64_t start_dts; int64_t start_cts; int64_t end_pts; diff --git a/libavformat/movtref.c b/libavformat/movtref.c new file mode 100644 index 0000000..dd6059c --- /dev/null +++ b/libavformat/movtref.c @@ -0,0 +1,115 @@ +/* + * ISO base media file format track references + * Copyright (c) 2016 Erkki Seppälä + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "movtref.h" +#include "libavutil/mem.h" + +MOVTRef *ff_mov_tref_find(MOVTRefs *trefs, uint32_t tag) +{ + int i; + MOVTRef *tref = NULL; + + for (i = 0; i < trefs->nb_trefs && !tref; ++i) { + if (trefs->trefs[i].tag == tag) { + tref = trefs->trefs + i; + } + } + + return tref; +} + +int ff_mov_tref_alloc(MOVTRef *tref, int n, int **track_ids_ret) +{ + int ret = av_reallocp_array(&tref->track_ids, tref->nb_track_ids + n, sizeof(tref->track_ids)); + *track_ids_ret = NULL; + if (ret >= 0) { + *track_ids_ret = tref->track_ids + tref->nb_track_ids; + tref->nb_track_ids += n; + } + return ret; +} + +int ff_mov_tref_find_or_add(MOVTRefs *trefs, uint32_t tag, MOVTRef **tref_ret) +{ + int ret; + int i; + MOVTRef *tref = ff_mov_tref_find(trefs, tag); + *tref_ret = NULL; + + for (i = 0; i < trefs->nb_trefs && !tref; ++i) { + if (trefs->trefs[i].tag == tag) { + tref = trefs->trefs + i; + } + } + + if (!tref) { + ret = av_reallocp_array(&trefs->trefs, trefs->nb_trefs + 1, sizeof(*trefs->trefs)); + if (ret < 0) + return ret; + tref = trefs->trefs + trefs->nb_trefs; + trefs->nb_trefs++; + tref->tag = tag; + tref->track_ids = NULL; + tref->nb_track_ids = 0; + } + + *tref_ret = tref; + return 0; +} + +int ff_mov_tref_add_one_track(MOVTRefs *trefs, unsigned tag, int track_id) +{ + int ret; + MOVTRef *tref; + int *ids; + int track_id_exists = 0; + int i; + + ret = ff_mov_tref_find_or_add(trefs, tag, &tref); + if (ret < 0) + return ret; + + for (i = 0; i < tref->nb_track_ids && !track_id_exists; i++) { + if (tref->track_ids[i] == track_id) { + track_id_exists = 1; + } + } + + if (!track_id_exists) { + ret = ff_mov_tref_alloc(tref, 1, &ids); + if (ret >= 0) { + *ids = track_id; + } + } + return ret; +} + +void ff_mov_tref_free(MOVTRefs *trefs) +{ + int i; + for (i = 0; i < trefs->nb_trefs; ++i) + av_freep(&trefs->trefs[i].track_ids); + av_freep(&trefs->trefs); +} diff --git a/libavformat/movtref.h b/libavformat/movtref.h new file mode 100644 index 0000000..091f467 --- /dev/null +++ b/libavformat/movtref.h @@ -0,0 +1,75 @@ +/* + * ISO base media file format track references + * Copyright (c) 2016 Erkki Seppälä + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVFORMAT_MOVTREF_H +#define AVFORMAT_MOVTREF_H + +typedef struct MOVTRef { + uint32_t tag; + int nb_track_ids; + int* track_ids; +} MOVTRef; + +typedef struct MOVTRefs { + int nb_trefs; + MOVTRef *trefs; +} MOVTRefs; + +/** + * @brief Finds a track reference of certain tag from a track; if not + * found, return NULL + * + * @param track The track to search from + * @param tag The tag (4cc) to search for + * @return a MOVTRef describing the track reference or NULL if not found. + */ +MOVTRef *ff_mov_tref_find(MOVTRefs *trefs, uint32_t tag); + +/** + * @brief Allocate space for n more tracks (and increase nb_ids accordingly) returning + * the pointer in *track_ids + * + * @param tref The track reference to allocate tracks to + * @param n Number of tracks to add + * @param track_ids_ret A non-null pointer where the pointer to the first free track + * id is returned to + * @return Returns a value <0 on error, otherwise 0. + */ +int ff_mov_tref_alloc(MOVTRef *tref, int n, int **track_ids_ret); + +/** + * @brief Finds an existing MOVTRef for a track for the given tag, or + * creates a new one if it is missing. Returns the tref in tref_ret. + */ + +int ff_mov_tref_find_or_add(MOVTRefs *trefs, uint32_t tag, MOVTRef **tref_ret); + +/** + * Adds one tref track reference with given track id if it doesn't + * already exist + */ +int ff_mov_tref_add_one_track(MOVTRefs *trefs, unsigned tag, int track_id); + +/** + * Release MOVTRefs + */ +void ff_mov_tref_free(MOVTRefs *trefs); + +#endif /* AVFORMAT_MOVTREF_H */