1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * This file is part of FFmpeg. 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cabdff1aSopenharmony_ci * Lesser General Public License for more details. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17cabdff1aSopenharmony_ci */ 18cabdff1aSopenharmony_ci 19cabdff1aSopenharmony_ci/* 20cabdff1aSopenharmony_ci * 21cabdff1aSopenharmony_ci * Copyright (c) Sandflow Consulting LLC 22cabdff1aSopenharmony_ci * 23cabdff1aSopenharmony_ci * Redistribution and use in source and binary forms, with or without 24cabdff1aSopenharmony_ci * modification, are permitted provided that the following conditions are met: 25cabdff1aSopenharmony_ci * 26cabdff1aSopenharmony_ci * * Redistributions of source code must retain the above copyright notice, this 27cabdff1aSopenharmony_ci * list of conditions and the following disclaimer. 28cabdff1aSopenharmony_ci * * Redistributions in binary form must reproduce the above copyright notice, 29cabdff1aSopenharmony_ci * this list of conditions and the following disclaimer in the documentation 30cabdff1aSopenharmony_ci * and/or other materials provided with the distribution. 31cabdff1aSopenharmony_ci * 32cabdff1aSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 33cabdff1aSopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34cabdff1aSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35cabdff1aSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 36cabdff1aSopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 37cabdff1aSopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 38cabdff1aSopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39cabdff1aSopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 40cabdff1aSopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 41cabdff1aSopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42cabdff1aSopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 43cabdff1aSopenharmony_ci */ 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_ci/** 46cabdff1aSopenharmony_ci * Demuxes an IMF Composition 47cabdff1aSopenharmony_ci * 48cabdff1aSopenharmony_ci * References 49cabdff1aSopenharmony_ci * OV 2067-0:2018 - SMPTE Overview Document - Interoperable Master Format 50cabdff1aSopenharmony_ci * ST 2067-2:2020 - SMPTE Standard - Interoperable Master Format — Core Constraints 51cabdff1aSopenharmony_ci * ST 2067-3:2020 - SMPTE Standard - Interoperable Master Format — Composition Playlist 52cabdff1aSopenharmony_ci * ST 2067-5:2020 - SMPTE Standard - Interoperable Master Format — Essence Component 53cabdff1aSopenharmony_ci * ST 2067-20:2016 - SMPTE Standard - Interoperable Master Format — Application #2 54cabdff1aSopenharmony_ci * ST 2067-21:2020 - SMPTE Standard - Interoperable Master Format — Application #2 Extended 55cabdff1aSopenharmony_ci * ST 2067-102:2017 - SMPTE Standard - Interoperable Master Format — Common Image Pixel Color Schemes 56cabdff1aSopenharmony_ci * ST 429-9:2007 - SMPTE Standard - D-Cinema Packaging — Asset Mapping and File Segmentation 57cabdff1aSopenharmony_ci * 58cabdff1aSopenharmony_ci * @author Marc-Antoine Arnaud 59cabdff1aSopenharmony_ci * @author Valentin Noel 60cabdff1aSopenharmony_ci * @author Nicholas Vanderzwet 61cabdff1aSopenharmony_ci * @file 62cabdff1aSopenharmony_ci * @ingroup lavu_imf 63cabdff1aSopenharmony_ci */ 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci#include "avio_internal.h" 66cabdff1aSopenharmony_ci#include "demux.h" 67cabdff1aSopenharmony_ci#include "imf.h" 68cabdff1aSopenharmony_ci#include "internal.h" 69cabdff1aSopenharmony_ci#include "libavcodec/packet.h" 70cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 71cabdff1aSopenharmony_ci#include "libavutil/bprint.h" 72cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 73cabdff1aSopenharmony_ci#include "libavutil/opt.h" 74cabdff1aSopenharmony_ci#include "mxf.h" 75cabdff1aSopenharmony_ci#include <inttypes.h> 76cabdff1aSopenharmony_ci#include <libxml/parser.h> 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci#define AVRATIONAL_FORMAT "%d/%d" 79cabdff1aSopenharmony_ci#define AVRATIONAL_ARG(rational) rational.num, rational.den 80cabdff1aSopenharmony_ci 81cabdff1aSopenharmony_ci/** 82cabdff1aSopenharmony_ci * IMF Asset locator 83cabdff1aSopenharmony_ci */ 84cabdff1aSopenharmony_citypedef struct IMFAssetLocator { 85cabdff1aSopenharmony_ci AVUUID uuid; 86cabdff1aSopenharmony_ci char *absolute_uri; 87cabdff1aSopenharmony_ci} IMFAssetLocator; 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci/** 90cabdff1aSopenharmony_ci * IMF Asset locator map 91cabdff1aSopenharmony_ci * Results from the parsing of one or more ASSETMAP XML files 92cabdff1aSopenharmony_ci */ 93cabdff1aSopenharmony_citypedef struct IMFAssetLocatorMap { 94cabdff1aSopenharmony_ci uint32_t asset_count; 95cabdff1aSopenharmony_ci IMFAssetLocator *assets; 96cabdff1aSopenharmony_ci} IMFAssetLocatorMap; 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_citypedef struct IMFVirtualTrackResourcePlaybackCtx { 99cabdff1aSopenharmony_ci IMFAssetLocator *locator; /**< Location of the resource */ 100cabdff1aSopenharmony_ci FFIMFTrackFileResource *resource; /**< Underlying IMF CPL resource */ 101cabdff1aSopenharmony_ci AVFormatContext *ctx; /**< Context associated with the resource */ 102cabdff1aSopenharmony_ci AVRational start_time; /**< inclusive start time of the resource on the CPL timeline (s) */ 103cabdff1aSopenharmony_ci AVRational end_time; /**< exclusive end time of the resource on the CPL timeline (s) */ 104cabdff1aSopenharmony_ci AVRational ts_offset; /**< start_time minus the entry point into the resource (s) */ 105cabdff1aSopenharmony_ci} IMFVirtualTrackResourcePlaybackCtx; 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_citypedef struct IMFVirtualTrackPlaybackCtx { 108cabdff1aSopenharmony_ci int32_t index; /**< Track index in playlist */ 109cabdff1aSopenharmony_ci AVRational current_timestamp; /**< Current temporal position */ 110cabdff1aSopenharmony_ci AVRational duration; /**< Overall duration */ 111cabdff1aSopenharmony_ci uint32_t resource_count; /**< Number of resources (<= INT32_MAX) */ 112cabdff1aSopenharmony_ci unsigned int resources_alloc_sz; /**< Size of the buffer holding the resource */ 113cabdff1aSopenharmony_ci IMFVirtualTrackResourcePlaybackCtx *resources; /**< Buffer holding the resources */ 114cabdff1aSopenharmony_ci int32_t current_resource_index; /**< Index of the current resource in resources, 115cabdff1aSopenharmony_ci or < 0 if a current resource has yet to be selected */ 116cabdff1aSopenharmony_ci} IMFVirtualTrackPlaybackCtx; 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_citypedef struct IMFContext { 119cabdff1aSopenharmony_ci const AVClass *class; 120cabdff1aSopenharmony_ci const char *base_url; 121cabdff1aSopenharmony_ci char *asset_map_paths; 122cabdff1aSopenharmony_ci AVIOInterruptCB *interrupt_callback; 123cabdff1aSopenharmony_ci AVDictionary *avio_opts; 124cabdff1aSopenharmony_ci FFIMFCPL *cpl; 125cabdff1aSopenharmony_ci IMFAssetLocatorMap asset_locator_map; 126cabdff1aSopenharmony_ci uint32_t track_count; 127cabdff1aSopenharmony_ci IMFVirtualTrackPlaybackCtx **tracks; 128cabdff1aSopenharmony_ci} IMFContext; 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_cistatic int imf_uri_is_url(const char *string) 131cabdff1aSopenharmony_ci{ 132cabdff1aSopenharmony_ci return strstr(string, "://") != NULL; 133cabdff1aSopenharmony_ci} 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_cistatic int imf_uri_is_unix_abs_path(const char *string) 136cabdff1aSopenharmony_ci{ 137cabdff1aSopenharmony_ci return string[0] == '/'; 138cabdff1aSopenharmony_ci} 139cabdff1aSopenharmony_ci 140cabdff1aSopenharmony_cistatic int imf_uri_is_dos_abs_path(const char *string) 141cabdff1aSopenharmony_ci{ 142cabdff1aSopenharmony_ci /* Absolute path case: `C:\path\to\somwhere` */ 143cabdff1aSopenharmony_ci if (string[1] == ':' && string[2] == '\\') 144cabdff1aSopenharmony_ci return 1; 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_ci /* Absolute path case: `C:/path/to/somwhere` */ 147cabdff1aSopenharmony_ci if (string[1] == ':' && string[2] == '/') 148cabdff1aSopenharmony_ci return 1; 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci /* Network path case: `\\path\to\somwhere` */ 151cabdff1aSopenharmony_ci if (string[0] == '\\' && string[1] == '\\') 152cabdff1aSopenharmony_ci return 1; 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci return 0; 155cabdff1aSopenharmony_ci} 156cabdff1aSopenharmony_ci 157cabdff1aSopenharmony_cistatic int imf_time_to_ts(int64_t *ts, AVRational t, AVRational time_base) 158cabdff1aSopenharmony_ci{ 159cabdff1aSopenharmony_ci int dst_num; 160cabdff1aSopenharmony_ci int dst_den; 161cabdff1aSopenharmony_ci AVRational r; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci r = av_div_q(t, time_base); 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci if ((av_reduce(&dst_num, &dst_den, r.num, r.den, INT64_MAX) != 1)) 166cabdff1aSopenharmony_ci return 1; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci if (dst_den != 1) 169cabdff1aSopenharmony_ci return 1; 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci *ts = dst_num; 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci return 0; 174cabdff1aSopenharmony_ci} 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci/** 177cabdff1aSopenharmony_ci * Parse a ASSETMAP XML file to extract the UUID-URI mapping of assets. 178cabdff1aSopenharmony_ci * @param s the current format context, if any (can be NULL). 179cabdff1aSopenharmony_ci * @param doc the XML document to be parsed. 180cabdff1aSopenharmony_ci * @param asset_map pointer on the IMFAssetLocatorMap to fill. 181cabdff1aSopenharmony_ci * @param base_url the url of the asset map XML file, if any (can be NULL). 182cabdff1aSopenharmony_ci * @return a negative value in case of error, 0 otherwise. 183cabdff1aSopenharmony_ci */ 184cabdff1aSopenharmony_cistatic int parse_imf_asset_map_from_xml_dom(AVFormatContext *s, 185cabdff1aSopenharmony_ci xmlDocPtr doc, 186cabdff1aSopenharmony_ci IMFAssetLocatorMap *asset_map, 187cabdff1aSopenharmony_ci const char *base_url) 188cabdff1aSopenharmony_ci{ 189cabdff1aSopenharmony_ci xmlNodePtr asset_map_element = NULL; 190cabdff1aSopenharmony_ci xmlNodePtr node = NULL; 191cabdff1aSopenharmony_ci xmlNodePtr asset_element = NULL; 192cabdff1aSopenharmony_ci unsigned long elem_count; 193cabdff1aSopenharmony_ci char *uri; 194cabdff1aSopenharmony_ci int ret = 0; 195cabdff1aSopenharmony_ci IMFAssetLocator *asset = NULL; 196cabdff1aSopenharmony_ci void *tmp; 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_ci asset_map_element = xmlDocGetRootElement(doc); 199cabdff1aSopenharmony_ci 200cabdff1aSopenharmony_ci if (!asset_map_element) { 201cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to parse asset map XML - missing root node\n"); 202cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 203cabdff1aSopenharmony_ci } 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_ci if (asset_map_element->type != XML_ELEMENT_NODE || av_strcasecmp(asset_map_element->name, "AssetMap")) { 206cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to parse asset map XML - wrong root node name[%s] type[%d]\n", 207cabdff1aSopenharmony_ci asset_map_element->name, (int)asset_map_element->type); 208cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 209cabdff1aSopenharmony_ci } 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_ci /* parse asset locators */ 212cabdff1aSopenharmony_ci if (!(node = ff_imf_xml_get_child_element_by_name(asset_map_element, "AssetList"))) { 213cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to parse asset map XML - missing AssetList node\n"); 214cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 215cabdff1aSopenharmony_ci } 216cabdff1aSopenharmony_ci elem_count = xmlChildElementCount(node); 217cabdff1aSopenharmony_ci if (elem_count > UINT32_MAX 218cabdff1aSopenharmony_ci || asset_map->asset_count > UINT32_MAX - elem_count) 219cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 220cabdff1aSopenharmony_ci tmp = av_realloc_array(asset_map->assets, 221cabdff1aSopenharmony_ci elem_count + asset_map->asset_count, 222cabdff1aSopenharmony_ci sizeof(IMFAssetLocator)); 223cabdff1aSopenharmony_ci if (!tmp) { 224cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Cannot allocate IMF asset locators\n"); 225cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 226cabdff1aSopenharmony_ci } 227cabdff1aSopenharmony_ci asset_map->assets = tmp; 228cabdff1aSopenharmony_ci 229cabdff1aSopenharmony_ci asset_element = xmlFirstElementChild(node); 230cabdff1aSopenharmony_ci while (asset_element) { 231cabdff1aSopenharmony_ci if (av_strcasecmp(asset_element->name, "Asset") != 0) 232cabdff1aSopenharmony_ci continue; 233cabdff1aSopenharmony_ci 234cabdff1aSopenharmony_ci asset = &(asset_map->assets[asset_map->asset_count]); 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_ci if (ff_imf_xml_read_uuid(ff_imf_xml_get_child_element_by_name(asset_element, "Id"), asset->uuid)) { 237cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not parse UUID from asset in asset map.\n"); 238cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 239cabdff1aSopenharmony_ci } 240cabdff1aSopenharmony_ci 241cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Found asset id: " AV_PRI_URN_UUID "\n", AV_UUID_ARG(asset->uuid)); 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci if (!(node = ff_imf_xml_get_child_element_by_name(asset_element, "ChunkList"))) { 244cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to parse asset map XML - missing ChunkList node\n"); 245cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 246cabdff1aSopenharmony_ci } 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci if (!(node = ff_imf_xml_get_child_element_by_name(node, "Chunk"))) { 249cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to parse asset map XML - missing Chunk node\n"); 250cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 251cabdff1aSopenharmony_ci } 252cabdff1aSopenharmony_ci 253cabdff1aSopenharmony_ci uri = xmlNodeGetContent(ff_imf_xml_get_child_element_by_name(node, "Path")); 254cabdff1aSopenharmony_ci if (!imf_uri_is_url(uri) && !imf_uri_is_unix_abs_path(uri) && !imf_uri_is_dos_abs_path(uri)) 255cabdff1aSopenharmony_ci asset->absolute_uri = av_append_path_component(base_url, uri); 256cabdff1aSopenharmony_ci else 257cabdff1aSopenharmony_ci asset->absolute_uri = av_strdup(uri); 258cabdff1aSopenharmony_ci xmlFree(uri); 259cabdff1aSopenharmony_ci if (!asset->absolute_uri) 260cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 261cabdff1aSopenharmony_ci 262cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Found asset absolute URI: %s\n", asset->absolute_uri); 263cabdff1aSopenharmony_ci 264cabdff1aSopenharmony_ci asset_map->asset_count++; 265cabdff1aSopenharmony_ci asset_element = xmlNextElementSibling(asset_element); 266cabdff1aSopenharmony_ci } 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_ci return ret; 269cabdff1aSopenharmony_ci} 270cabdff1aSopenharmony_ci 271cabdff1aSopenharmony_ci/** 272cabdff1aSopenharmony_ci * Initializes an IMFAssetLocatorMap structure. 273cabdff1aSopenharmony_ci */ 274cabdff1aSopenharmony_cistatic void imf_asset_locator_map_init(IMFAssetLocatorMap *asset_map) 275cabdff1aSopenharmony_ci{ 276cabdff1aSopenharmony_ci asset_map->assets = NULL; 277cabdff1aSopenharmony_ci asset_map->asset_count = 0; 278cabdff1aSopenharmony_ci} 279cabdff1aSopenharmony_ci 280cabdff1aSopenharmony_ci/** 281cabdff1aSopenharmony_ci * Free a IMFAssetLocatorMap pointer. 282cabdff1aSopenharmony_ci */ 283cabdff1aSopenharmony_cistatic void imf_asset_locator_map_deinit(IMFAssetLocatorMap *asset_map) 284cabdff1aSopenharmony_ci{ 285cabdff1aSopenharmony_ci for (uint32_t i = 0; i < asset_map->asset_count; i++) 286cabdff1aSopenharmony_ci av_freep(&asset_map->assets[i].absolute_uri); 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_ci av_freep(&asset_map->assets); 289cabdff1aSopenharmony_ci} 290cabdff1aSopenharmony_ci 291cabdff1aSopenharmony_cistatic int parse_assetmap(AVFormatContext *s, const char *url) 292cabdff1aSopenharmony_ci{ 293cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 294cabdff1aSopenharmony_ci AVIOContext *in = NULL; 295cabdff1aSopenharmony_ci struct AVBPrint buf; 296cabdff1aSopenharmony_ci AVDictionary *opts = NULL; 297cabdff1aSopenharmony_ci xmlDoc *doc = NULL; 298cabdff1aSopenharmony_ci const char *base_url; 299cabdff1aSopenharmony_ci char *tmp_str = NULL; 300cabdff1aSopenharmony_ci int ret; 301cabdff1aSopenharmony_ci 302cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Asset Map URL: %s\n", url); 303cabdff1aSopenharmony_ci 304cabdff1aSopenharmony_ci av_dict_copy(&opts, c->avio_opts, 0); 305cabdff1aSopenharmony_ci ret = s->io_open(s, &in, url, AVIO_FLAG_READ, &opts); 306cabdff1aSopenharmony_ci av_dict_free(&opts); 307cabdff1aSopenharmony_ci if (ret < 0) 308cabdff1aSopenharmony_ci return ret; 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci av_bprint_init(&buf, 0, INT_MAX); // xmlReadMemory uses integer length 311cabdff1aSopenharmony_ci 312cabdff1aSopenharmony_ci ret = avio_read_to_bprint(in, &buf, SIZE_MAX); 313cabdff1aSopenharmony_ci if (ret < 0 || !avio_feof(in)) { 314cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to read to asset map '%s'\n", url); 315cabdff1aSopenharmony_ci if (ret == 0) 316cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 317cabdff1aSopenharmony_ci goto clean_up; 318cabdff1aSopenharmony_ci } 319cabdff1aSopenharmony_ci 320cabdff1aSopenharmony_ci LIBXML_TEST_VERSION 321cabdff1aSopenharmony_ci 322cabdff1aSopenharmony_ci tmp_str = av_strdup(url); 323cabdff1aSopenharmony_ci if (!tmp_str) { 324cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 325cabdff1aSopenharmony_ci goto clean_up; 326cabdff1aSopenharmony_ci } 327cabdff1aSopenharmony_ci base_url = av_dirname(tmp_str); 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_ci doc = xmlReadMemory(buf.str, buf.len, url, NULL, 0); 330cabdff1aSopenharmony_ci 331cabdff1aSopenharmony_ci ret = parse_imf_asset_map_from_xml_dom(s, doc, &c->asset_locator_map, base_url); 332cabdff1aSopenharmony_ci if (!ret) 333cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Found %d assets from %s\n", 334cabdff1aSopenharmony_ci c->asset_locator_map.asset_count, url); 335cabdff1aSopenharmony_ci 336cabdff1aSopenharmony_ci xmlFreeDoc(doc); 337cabdff1aSopenharmony_ci 338cabdff1aSopenharmony_ciclean_up: 339cabdff1aSopenharmony_ci if (tmp_str) 340cabdff1aSopenharmony_ci av_freep(&tmp_str); 341cabdff1aSopenharmony_ci ff_format_io_close(s, &in); 342cabdff1aSopenharmony_ci av_bprint_finalize(&buf, NULL); 343cabdff1aSopenharmony_ci return ret; 344cabdff1aSopenharmony_ci} 345cabdff1aSopenharmony_ci 346cabdff1aSopenharmony_cistatic IMFAssetLocator *find_asset_map_locator(IMFAssetLocatorMap *asset_map, AVUUID uuid) 347cabdff1aSopenharmony_ci{ 348cabdff1aSopenharmony_ci for (uint32_t i = 0; i < asset_map->asset_count; i++) { 349cabdff1aSopenharmony_ci if (memcmp(asset_map->assets[i].uuid, uuid, 16) == 0) 350cabdff1aSopenharmony_ci return &(asset_map->assets[i]); 351cabdff1aSopenharmony_ci } 352cabdff1aSopenharmony_ci return NULL; 353cabdff1aSopenharmony_ci} 354cabdff1aSopenharmony_ci 355cabdff1aSopenharmony_cistatic int open_track_resource_context(AVFormatContext *s, 356cabdff1aSopenharmony_ci IMFVirtualTrackPlaybackCtx *track, 357cabdff1aSopenharmony_ci int32_t resource_index) 358cabdff1aSopenharmony_ci{ 359cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 360cabdff1aSopenharmony_ci int ret = 0; 361cabdff1aSopenharmony_ci int64_t seek_offset = 0; 362cabdff1aSopenharmony_ci AVDictionary *opts = NULL; 363cabdff1aSopenharmony_ci AVStream *st; 364cabdff1aSopenharmony_ci IMFVirtualTrackResourcePlaybackCtx *track_resource = track->resources + resource_index; 365cabdff1aSopenharmony_ci 366cabdff1aSopenharmony_ci if (track_resource->ctx) { 367cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Input context already opened for %s.\n", 368cabdff1aSopenharmony_ci track_resource->locator->absolute_uri); 369cabdff1aSopenharmony_ci return 0; 370cabdff1aSopenharmony_ci } 371cabdff1aSopenharmony_ci 372cabdff1aSopenharmony_ci track_resource->ctx = avformat_alloc_context(); 373cabdff1aSopenharmony_ci if (!track_resource->ctx) 374cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 375cabdff1aSopenharmony_ci 376cabdff1aSopenharmony_ci track_resource->ctx->io_open = s->io_open; 377cabdff1aSopenharmony_ci track_resource->ctx->io_close = s->io_close; 378cabdff1aSopenharmony_ci track_resource->ctx->io_close2 = s->io_close2; 379cabdff1aSopenharmony_ci track_resource->ctx->flags |= s->flags & ~AVFMT_FLAG_CUSTOM_IO; 380cabdff1aSopenharmony_ci 381cabdff1aSopenharmony_ci if ((ret = ff_copy_whiteblacklists(track_resource->ctx, s)) < 0) 382cabdff1aSopenharmony_ci goto cleanup; 383cabdff1aSopenharmony_ci 384cabdff1aSopenharmony_ci if ((ret = av_opt_set(track_resource->ctx, "format_whitelist", "mxf", 0))) 385cabdff1aSopenharmony_ci goto cleanup; 386cabdff1aSopenharmony_ci 387cabdff1aSopenharmony_ci if ((ret = av_dict_copy(&opts, c->avio_opts, 0)) < 0) 388cabdff1aSopenharmony_ci goto cleanup; 389cabdff1aSopenharmony_ci 390cabdff1aSopenharmony_ci ret = avformat_open_input(&track_resource->ctx, 391cabdff1aSopenharmony_ci track_resource->locator->absolute_uri, 392cabdff1aSopenharmony_ci NULL, 393cabdff1aSopenharmony_ci &opts); 394cabdff1aSopenharmony_ci if (ret < 0) { 395cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not open %s input context: %s\n", 396cabdff1aSopenharmony_ci track_resource->locator->absolute_uri, av_err2str(ret)); 397cabdff1aSopenharmony_ci goto cleanup; 398cabdff1aSopenharmony_ci } 399cabdff1aSopenharmony_ci av_dict_free(&opts); 400cabdff1aSopenharmony_ci 401cabdff1aSopenharmony_ci /* make sure there is only one stream in the file */ 402cabdff1aSopenharmony_ci 403cabdff1aSopenharmony_ci if (track_resource->ctx->nb_streams != 1) { 404cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 405cabdff1aSopenharmony_ci goto cleanup; 406cabdff1aSopenharmony_ci } 407cabdff1aSopenharmony_ci 408cabdff1aSopenharmony_ci st = track_resource->ctx->streams[0]; 409cabdff1aSopenharmony_ci 410cabdff1aSopenharmony_ci /* Determine the seek offset into the Track File, taking into account: 411cabdff1aSopenharmony_ci * - the current timestamp within the virtual track 412cabdff1aSopenharmony_ci * - the entry point of the resource 413cabdff1aSopenharmony_ci */ 414cabdff1aSopenharmony_ci if (imf_time_to_ts(&seek_offset, 415cabdff1aSopenharmony_ci av_sub_q(track->current_timestamp, track_resource->ts_offset), 416cabdff1aSopenharmony_ci st->time_base)) 417cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Incoherent stream timebase " AVRATIONAL_FORMAT 418cabdff1aSopenharmony_ci "and composition timeline position: " AVRATIONAL_FORMAT "\n", 419cabdff1aSopenharmony_ci AVRATIONAL_ARG(st->time_base), AVRATIONAL_ARG(track->current_timestamp)); 420cabdff1aSopenharmony_ci 421cabdff1aSopenharmony_ci if (seek_offset) { 422cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Seek at resource %s entry point: %" PRIi64 "\n", 423cabdff1aSopenharmony_ci track_resource->locator->absolute_uri, seek_offset); 424cabdff1aSopenharmony_ci ret = avformat_seek_file(track_resource->ctx, 0, seek_offset, seek_offset, seek_offset, 0); 425cabdff1aSopenharmony_ci if (ret < 0) { 426cabdff1aSopenharmony_ci av_log(s, 427cabdff1aSopenharmony_ci AV_LOG_ERROR, 428cabdff1aSopenharmony_ci "Could not seek at %" PRId64 "on %s: %s\n", 429cabdff1aSopenharmony_ci seek_offset, 430cabdff1aSopenharmony_ci track_resource->locator->absolute_uri, 431cabdff1aSopenharmony_ci av_err2str(ret)); 432cabdff1aSopenharmony_ci avformat_close_input(&track_resource->ctx); 433cabdff1aSopenharmony_ci return ret; 434cabdff1aSopenharmony_ci } 435cabdff1aSopenharmony_ci } 436cabdff1aSopenharmony_ci 437cabdff1aSopenharmony_ci return 0; 438cabdff1aSopenharmony_ci 439cabdff1aSopenharmony_cicleanup: 440cabdff1aSopenharmony_ci av_dict_free(&opts); 441cabdff1aSopenharmony_ci avformat_free_context(track_resource->ctx); 442cabdff1aSopenharmony_ci track_resource->ctx = NULL; 443cabdff1aSopenharmony_ci return ret; 444cabdff1aSopenharmony_ci} 445cabdff1aSopenharmony_ci 446cabdff1aSopenharmony_cistatic int open_track_file_resource(AVFormatContext *s, 447cabdff1aSopenharmony_ci FFIMFTrackFileResource *track_file_resource, 448cabdff1aSopenharmony_ci IMFVirtualTrackPlaybackCtx *track) 449cabdff1aSopenharmony_ci{ 450cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 451cabdff1aSopenharmony_ci IMFAssetLocator *asset_locator; 452cabdff1aSopenharmony_ci void *tmp; 453cabdff1aSopenharmony_ci 454cabdff1aSopenharmony_ci asset_locator = find_asset_map_locator(&c->asset_locator_map, track_file_resource->track_file_uuid); 455cabdff1aSopenharmony_ci if (!asset_locator) { 456cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not find asset locator for UUID: " AV_PRI_URN_UUID "\n", 457cabdff1aSopenharmony_ci AV_UUID_ARG(track_file_resource->track_file_uuid)); 458cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 459cabdff1aSopenharmony_ci } 460cabdff1aSopenharmony_ci 461cabdff1aSopenharmony_ci av_log(s, 462cabdff1aSopenharmony_ci AV_LOG_DEBUG, 463cabdff1aSopenharmony_ci "Found locator for " AV_PRI_URN_UUID ": %s\n", 464cabdff1aSopenharmony_ci AV_UUID_ARG(asset_locator->uuid), 465cabdff1aSopenharmony_ci asset_locator->absolute_uri); 466cabdff1aSopenharmony_ci 467cabdff1aSopenharmony_ci if (track->resource_count > INT32_MAX - track_file_resource->base.repeat_count 468cabdff1aSopenharmony_ci || (track->resource_count + track_file_resource->base.repeat_count) 469cabdff1aSopenharmony_ci > INT_MAX / sizeof(IMFVirtualTrackResourcePlaybackCtx)) 470cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 471cabdff1aSopenharmony_ci tmp = av_fast_realloc(track->resources, 472cabdff1aSopenharmony_ci &track->resources_alloc_sz, 473cabdff1aSopenharmony_ci (track->resource_count + track_file_resource->base.repeat_count) 474cabdff1aSopenharmony_ci * sizeof(IMFVirtualTrackResourcePlaybackCtx)); 475cabdff1aSopenharmony_ci if (!tmp) 476cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 477cabdff1aSopenharmony_ci track->resources = tmp; 478cabdff1aSopenharmony_ci 479cabdff1aSopenharmony_ci for (uint32_t i = 0; i < track_file_resource->base.repeat_count; i++) { 480cabdff1aSopenharmony_ci IMFVirtualTrackResourcePlaybackCtx vt_ctx; 481cabdff1aSopenharmony_ci 482cabdff1aSopenharmony_ci vt_ctx.locator = asset_locator; 483cabdff1aSopenharmony_ci vt_ctx.resource = track_file_resource; 484cabdff1aSopenharmony_ci vt_ctx.ctx = NULL; 485cabdff1aSopenharmony_ci vt_ctx.start_time = track->duration; 486cabdff1aSopenharmony_ci vt_ctx.ts_offset = av_sub_q(vt_ctx.start_time, 487cabdff1aSopenharmony_ci av_div_q(av_make_q((int)track_file_resource->base.entry_point, 1), 488cabdff1aSopenharmony_ci track_file_resource->base.edit_rate)); 489cabdff1aSopenharmony_ci vt_ctx.end_time = av_add_q(track->duration, 490cabdff1aSopenharmony_ci av_make_q((int)track_file_resource->base.duration 491cabdff1aSopenharmony_ci * track_file_resource->base.edit_rate.den, 492cabdff1aSopenharmony_ci track_file_resource->base.edit_rate.num)); 493cabdff1aSopenharmony_ci track->resources[track->resource_count++] = vt_ctx; 494cabdff1aSopenharmony_ci track->duration = vt_ctx.end_time; 495cabdff1aSopenharmony_ci } 496cabdff1aSopenharmony_ci 497cabdff1aSopenharmony_ci return 0; 498cabdff1aSopenharmony_ci} 499cabdff1aSopenharmony_ci 500cabdff1aSopenharmony_cistatic void imf_virtual_track_playback_context_deinit(IMFVirtualTrackPlaybackCtx *track) 501cabdff1aSopenharmony_ci{ 502cabdff1aSopenharmony_ci for (uint32_t i = 0; i < track->resource_count; i++) 503cabdff1aSopenharmony_ci avformat_close_input(&track->resources[i].ctx); 504cabdff1aSopenharmony_ci 505cabdff1aSopenharmony_ci av_freep(&track->resources); 506cabdff1aSopenharmony_ci} 507cabdff1aSopenharmony_ci 508cabdff1aSopenharmony_cistatic int open_virtual_track(AVFormatContext *s, 509cabdff1aSopenharmony_ci FFIMFTrackFileVirtualTrack *virtual_track, 510cabdff1aSopenharmony_ci int32_t track_index) 511cabdff1aSopenharmony_ci{ 512cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 513cabdff1aSopenharmony_ci IMFVirtualTrackPlaybackCtx *track = NULL; 514cabdff1aSopenharmony_ci void *tmp; 515cabdff1aSopenharmony_ci int ret = 0; 516cabdff1aSopenharmony_ci 517cabdff1aSopenharmony_ci if (!(track = av_mallocz(sizeof(IMFVirtualTrackPlaybackCtx)))) 518cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 519cabdff1aSopenharmony_ci track->current_resource_index = -1; 520cabdff1aSopenharmony_ci track->index = track_index; 521cabdff1aSopenharmony_ci track->duration = av_make_q(0, 1); 522cabdff1aSopenharmony_ci 523cabdff1aSopenharmony_ci for (uint32_t i = 0; i < virtual_track->resource_count; i++) { 524cabdff1aSopenharmony_ci av_log(s, 525cabdff1aSopenharmony_ci AV_LOG_DEBUG, 526cabdff1aSopenharmony_ci "Open stream from file " AV_PRI_URN_UUID ", stream %d\n", 527cabdff1aSopenharmony_ci AV_UUID_ARG(virtual_track->resources[i].track_file_uuid), 528cabdff1aSopenharmony_ci i); 529cabdff1aSopenharmony_ci if ((ret = open_track_file_resource(s, &virtual_track->resources[i], track)) != 0) { 530cabdff1aSopenharmony_ci av_log(s, 531cabdff1aSopenharmony_ci AV_LOG_ERROR, 532cabdff1aSopenharmony_ci "Could not open image track resource " AV_PRI_URN_UUID "\n", 533cabdff1aSopenharmony_ci AV_UUID_ARG(virtual_track->resources[i].track_file_uuid)); 534cabdff1aSopenharmony_ci goto clean_up; 535cabdff1aSopenharmony_ci } 536cabdff1aSopenharmony_ci } 537cabdff1aSopenharmony_ci 538cabdff1aSopenharmony_ci track->current_timestamp = av_make_q(0, track->duration.den); 539cabdff1aSopenharmony_ci 540cabdff1aSopenharmony_ci if (c->track_count == UINT32_MAX) { 541cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 542cabdff1aSopenharmony_ci goto clean_up; 543cabdff1aSopenharmony_ci } 544cabdff1aSopenharmony_ci tmp = av_realloc_array(c->tracks, c->track_count + 1, sizeof(IMFVirtualTrackPlaybackCtx *)); 545cabdff1aSopenharmony_ci if (!tmp) { 546cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 547cabdff1aSopenharmony_ci goto clean_up; 548cabdff1aSopenharmony_ci } 549cabdff1aSopenharmony_ci c->tracks = tmp; 550cabdff1aSopenharmony_ci c->tracks[c->track_count++] = track; 551cabdff1aSopenharmony_ci 552cabdff1aSopenharmony_ci return 0; 553cabdff1aSopenharmony_ci 554cabdff1aSopenharmony_ciclean_up: 555cabdff1aSopenharmony_ci imf_virtual_track_playback_context_deinit(track); 556cabdff1aSopenharmony_ci av_free(track); 557cabdff1aSopenharmony_ci return ret; 558cabdff1aSopenharmony_ci} 559cabdff1aSopenharmony_ci 560cabdff1aSopenharmony_cistatic int set_context_streams_from_tracks(AVFormatContext *s) 561cabdff1aSopenharmony_ci{ 562cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 563cabdff1aSopenharmony_ci int ret = 0; 564cabdff1aSopenharmony_ci 565cabdff1aSopenharmony_ci for (uint32_t i = 0; i < c->track_count; i++) { 566cabdff1aSopenharmony_ci AVStream *asset_stream; 567cabdff1aSopenharmony_ci AVStream *first_resource_stream; 568cabdff1aSopenharmony_ci 569cabdff1aSopenharmony_ci /* Open the first resource of the track to get stream information */ 570cabdff1aSopenharmony_ci ret = open_track_resource_context(s, c->tracks[i], 0); 571cabdff1aSopenharmony_ci if (ret) 572cabdff1aSopenharmony_ci return ret; 573cabdff1aSopenharmony_ci first_resource_stream = c->tracks[i]->resources[0].ctx->streams[0]; 574cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Open the first resource of track %d\n", c->tracks[i]->index); 575cabdff1aSopenharmony_ci 576cabdff1aSopenharmony_ci /* Copy stream information */ 577cabdff1aSopenharmony_ci asset_stream = avformat_new_stream(s, NULL); 578cabdff1aSopenharmony_ci if (!asset_stream) { 579cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not create stream\n"); 580cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 581cabdff1aSopenharmony_ci } 582cabdff1aSopenharmony_ci asset_stream->id = i; 583cabdff1aSopenharmony_ci ret = avcodec_parameters_copy(asset_stream->codecpar, first_resource_stream->codecpar); 584cabdff1aSopenharmony_ci if (ret < 0) { 585cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not copy stream parameters\n"); 586cabdff1aSopenharmony_ci return ret; 587cabdff1aSopenharmony_ci } 588cabdff1aSopenharmony_ci avpriv_set_pts_info(asset_stream, 589cabdff1aSopenharmony_ci first_resource_stream->pts_wrap_bits, 590cabdff1aSopenharmony_ci first_resource_stream->time_base.num, 591cabdff1aSopenharmony_ci first_resource_stream->time_base.den); 592cabdff1aSopenharmony_ci asset_stream->duration = (int64_t)av_q2d(av_mul_q(c->tracks[i]->duration, 593cabdff1aSopenharmony_ci av_inv_q(asset_stream->time_base))); 594cabdff1aSopenharmony_ci } 595cabdff1aSopenharmony_ci 596cabdff1aSopenharmony_ci return 0; 597cabdff1aSopenharmony_ci} 598cabdff1aSopenharmony_ci 599cabdff1aSopenharmony_cistatic int open_cpl_tracks(AVFormatContext *s) 600cabdff1aSopenharmony_ci{ 601cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 602cabdff1aSopenharmony_ci int32_t track_index = 0; 603cabdff1aSopenharmony_ci int ret; 604cabdff1aSopenharmony_ci 605cabdff1aSopenharmony_ci if (c->cpl->main_image_2d_track) { 606cabdff1aSopenharmony_ci if ((ret = open_virtual_track(s, c->cpl->main_image_2d_track, track_index++)) != 0) { 607cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not open image track " AV_PRI_URN_UUID "\n", 608cabdff1aSopenharmony_ci AV_UUID_ARG(c->cpl->main_image_2d_track->base.id_uuid)); 609cabdff1aSopenharmony_ci return ret; 610cabdff1aSopenharmony_ci } 611cabdff1aSopenharmony_ci } 612cabdff1aSopenharmony_ci 613cabdff1aSopenharmony_ci for (uint32_t i = 0; i < c->cpl->main_audio_track_count; i++) { 614cabdff1aSopenharmony_ci if ((ret = open_virtual_track(s, &c->cpl->main_audio_tracks[i], track_index++)) != 0) { 615cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not open audio track " AV_PRI_URN_UUID "\n", 616cabdff1aSopenharmony_ci AV_UUID_ARG(c->cpl->main_audio_tracks[i].base.id_uuid)); 617cabdff1aSopenharmony_ci return ret; 618cabdff1aSopenharmony_ci } 619cabdff1aSopenharmony_ci } 620cabdff1aSopenharmony_ci 621cabdff1aSopenharmony_ci return set_context_streams_from_tracks(s); 622cabdff1aSopenharmony_ci} 623cabdff1aSopenharmony_ci 624cabdff1aSopenharmony_cistatic int imf_read_header(AVFormatContext *s) 625cabdff1aSopenharmony_ci{ 626cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 627cabdff1aSopenharmony_ci char *asset_map_path; 628cabdff1aSopenharmony_ci char *tmp_str; 629cabdff1aSopenharmony_ci int ret = 0; 630cabdff1aSopenharmony_ci 631cabdff1aSopenharmony_ci c->interrupt_callback = &s->interrupt_callback; 632cabdff1aSopenharmony_ci tmp_str = av_strdup(s->url); 633cabdff1aSopenharmony_ci if (!tmp_str) 634cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 635cabdff1aSopenharmony_ci c->base_url = av_strdup(av_dirname(tmp_str)); 636cabdff1aSopenharmony_ci av_freep(&tmp_str); 637cabdff1aSopenharmony_ci if (!c->base_url) 638cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 639cabdff1aSopenharmony_ci 640cabdff1aSopenharmony_ci if ((ret = ffio_copy_url_options(s->pb, &c->avio_opts)) < 0) 641cabdff1aSopenharmony_ci return ret; 642cabdff1aSopenharmony_ci 643cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "start parsing IMF CPL: %s\n", s->url); 644cabdff1aSopenharmony_ci 645cabdff1aSopenharmony_ci if ((ret = ff_imf_parse_cpl(s->pb, &c->cpl)) < 0) 646cabdff1aSopenharmony_ci return ret; 647cabdff1aSopenharmony_ci 648cabdff1aSopenharmony_ci av_log(s, 649cabdff1aSopenharmony_ci AV_LOG_DEBUG, 650cabdff1aSopenharmony_ci "parsed IMF CPL: " AV_PRI_URN_UUID "\n", 651cabdff1aSopenharmony_ci AV_UUID_ARG(c->cpl->id_uuid)); 652cabdff1aSopenharmony_ci 653cabdff1aSopenharmony_ci if (!c->asset_map_paths) { 654cabdff1aSopenharmony_ci c->asset_map_paths = av_append_path_component(c->base_url, "ASSETMAP.xml"); 655cabdff1aSopenharmony_ci if (!c->asset_map_paths) { 656cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 657cabdff1aSopenharmony_ci return ret; 658cabdff1aSopenharmony_ci } 659cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "No asset maps provided, using the default ASSETMAP.xml\n"); 660cabdff1aSopenharmony_ci } 661cabdff1aSopenharmony_ci 662cabdff1aSopenharmony_ci /* Parse each asset map XML file */ 663cabdff1aSopenharmony_ci imf_asset_locator_map_init(&c->asset_locator_map); 664cabdff1aSopenharmony_ci asset_map_path = av_strtok(c->asset_map_paths, ",", &tmp_str); 665cabdff1aSopenharmony_ci while (asset_map_path != NULL) { 666cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "start parsing IMF Asset Map: %s\n", asset_map_path); 667cabdff1aSopenharmony_ci 668cabdff1aSopenharmony_ci if ((ret = parse_assetmap(s, asset_map_path))) 669cabdff1aSopenharmony_ci return ret; 670cabdff1aSopenharmony_ci 671cabdff1aSopenharmony_ci asset_map_path = av_strtok(NULL, ",", &tmp_str); 672cabdff1aSopenharmony_ci } 673cabdff1aSopenharmony_ci 674cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "parsed IMF Asset Maps\n"); 675cabdff1aSopenharmony_ci 676cabdff1aSopenharmony_ci if ((ret = open_cpl_tracks(s))) 677cabdff1aSopenharmony_ci return ret; 678cabdff1aSopenharmony_ci 679cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "parsed IMF package\n"); 680cabdff1aSopenharmony_ci 681cabdff1aSopenharmony_ci return 0; 682cabdff1aSopenharmony_ci} 683cabdff1aSopenharmony_ci 684cabdff1aSopenharmony_cistatic IMFVirtualTrackPlaybackCtx *get_next_track_with_minimum_timestamp(AVFormatContext *s) 685cabdff1aSopenharmony_ci{ 686cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 687cabdff1aSopenharmony_ci IMFVirtualTrackPlaybackCtx *track; 688cabdff1aSopenharmony_ci 689cabdff1aSopenharmony_ci AVRational minimum_timestamp = av_make_q(INT32_MAX, 1); 690cabdff1aSopenharmony_ci for (uint32_t i = c->track_count; i > 0; i--) { 691cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "Compare track %d timestamp " AVRATIONAL_FORMAT 692cabdff1aSopenharmony_ci " to minimum " AVRATIONAL_FORMAT 693cabdff1aSopenharmony_ci " (over duration: " AVRATIONAL_FORMAT ")\n", i, 694cabdff1aSopenharmony_ci AVRATIONAL_ARG(c->tracks[i - 1]->current_timestamp), 695cabdff1aSopenharmony_ci AVRATIONAL_ARG(minimum_timestamp), 696cabdff1aSopenharmony_ci AVRATIONAL_ARG(c->tracks[i - 1]->duration)); 697cabdff1aSopenharmony_ci 698cabdff1aSopenharmony_ci if (av_cmp_q(c->tracks[i - 1]->current_timestamp, minimum_timestamp) <= 0) { 699cabdff1aSopenharmony_ci track = c->tracks[i - 1]; 700cabdff1aSopenharmony_ci minimum_timestamp = track->current_timestamp; 701cabdff1aSopenharmony_ci } 702cabdff1aSopenharmony_ci } 703cabdff1aSopenharmony_ci 704cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Found next track to read: %d (timestamp: %lf / %lf)\n", 705cabdff1aSopenharmony_ci track->index, av_q2d(track->current_timestamp), av_q2d(minimum_timestamp)); 706cabdff1aSopenharmony_ci return track; 707cabdff1aSopenharmony_ci} 708cabdff1aSopenharmony_ci 709cabdff1aSopenharmony_cistatic int get_resource_context_for_timestamp(AVFormatContext *s, IMFVirtualTrackPlaybackCtx *track, IMFVirtualTrackResourcePlaybackCtx **resource) 710cabdff1aSopenharmony_ci{ 711cabdff1aSopenharmony_ci *resource = NULL; 712cabdff1aSopenharmony_ci 713cabdff1aSopenharmony_ci if (av_cmp_q(track->current_timestamp, track->duration) >= 0) { 714cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Reached the end of the virtual track\n"); 715cabdff1aSopenharmony_ci return AVERROR_EOF; 716cabdff1aSopenharmony_ci } 717cabdff1aSopenharmony_ci 718cabdff1aSopenharmony_ci av_log(s, 719cabdff1aSopenharmony_ci AV_LOG_TRACE, 720cabdff1aSopenharmony_ci "Looking for track %d resource for timestamp = %lf / %lf\n", 721cabdff1aSopenharmony_ci track->index, 722cabdff1aSopenharmony_ci av_q2d(track->current_timestamp), 723cabdff1aSopenharmony_ci av_q2d(track->duration)); 724cabdff1aSopenharmony_ci for (uint32_t i = 0; i < track->resource_count; i++) { 725cabdff1aSopenharmony_ci 726cabdff1aSopenharmony_ci if (av_cmp_q(track->resources[i].end_time, track->current_timestamp) > 0) { 727cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Found resource %d in track %d to read at timestamp %lf: " 728cabdff1aSopenharmony_ci "entry=%" PRIu32 ", duration=%" PRIu32 ", editrate=" AVRATIONAL_FORMAT "\n", 729cabdff1aSopenharmony_ci i, track->index, av_q2d(track->current_timestamp), 730cabdff1aSopenharmony_ci track->resources[i].resource->base.entry_point, 731cabdff1aSopenharmony_ci track->resources[i].resource->base.duration, 732cabdff1aSopenharmony_ci AVRATIONAL_ARG(track->resources[i].resource->base.edit_rate)); 733cabdff1aSopenharmony_ci 734cabdff1aSopenharmony_ci if (track->current_resource_index != i) { 735cabdff1aSopenharmony_ci int ret; 736cabdff1aSopenharmony_ci 737cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "Switch resource on track %d: re-open context\n", 738cabdff1aSopenharmony_ci track->index); 739cabdff1aSopenharmony_ci 740cabdff1aSopenharmony_ci ret = open_track_resource_context(s, track, i); 741cabdff1aSopenharmony_ci if (ret != 0) 742cabdff1aSopenharmony_ci return ret; 743cabdff1aSopenharmony_ci if (track->current_resource_index > 0) 744cabdff1aSopenharmony_ci avformat_close_input(&track->resources[track->current_resource_index].ctx); 745cabdff1aSopenharmony_ci track->current_resource_index = i; 746cabdff1aSopenharmony_ci } 747cabdff1aSopenharmony_ci 748cabdff1aSopenharmony_ci *resource = track->resources + track->current_resource_index; 749cabdff1aSopenharmony_ci return 0; 750cabdff1aSopenharmony_ci } 751cabdff1aSopenharmony_ci } 752cabdff1aSopenharmony_ci 753cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not find IMF track resource to read\n"); 754cabdff1aSopenharmony_ci return AVERROR_STREAM_NOT_FOUND; 755cabdff1aSopenharmony_ci} 756cabdff1aSopenharmony_ci 757cabdff1aSopenharmony_cistatic int imf_read_packet(AVFormatContext *s, AVPacket *pkt) 758cabdff1aSopenharmony_ci{ 759cabdff1aSopenharmony_ci IMFVirtualTrackResourcePlaybackCtx *resource = NULL; 760cabdff1aSopenharmony_ci int ret = 0; 761cabdff1aSopenharmony_ci IMFVirtualTrackPlaybackCtx *track; 762cabdff1aSopenharmony_ci int64_t delta_ts; 763cabdff1aSopenharmony_ci AVStream *st; 764cabdff1aSopenharmony_ci AVRational next_timestamp; 765cabdff1aSopenharmony_ci 766cabdff1aSopenharmony_ci track = get_next_track_with_minimum_timestamp(s); 767cabdff1aSopenharmony_ci 768cabdff1aSopenharmony_ci ret = get_resource_context_for_timestamp(s, track, &resource); 769cabdff1aSopenharmony_ci if (ret) 770cabdff1aSopenharmony_ci return ret; 771cabdff1aSopenharmony_ci 772cabdff1aSopenharmony_ci ret = av_read_frame(resource->ctx, pkt); 773cabdff1aSopenharmony_ci if (ret) 774cabdff1aSopenharmony_ci return ret; 775cabdff1aSopenharmony_ci 776cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Got packet: pts=%" PRId64 ", dts=%" PRId64 777cabdff1aSopenharmony_ci ", duration=%" PRId64 ", stream_index=%d, pos=%" PRId64 778cabdff1aSopenharmony_ci ", time_base=" AVRATIONAL_FORMAT "\n", pkt->pts, pkt->dts, pkt->duration, 779cabdff1aSopenharmony_ci pkt->stream_index, pkt->pos, AVRATIONAL_ARG(pkt->time_base)); 780cabdff1aSopenharmony_ci 781cabdff1aSopenharmony_ci /* IMF resources contain only one stream */ 782cabdff1aSopenharmony_ci 783cabdff1aSopenharmony_ci if (pkt->stream_index != 0) 784cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 785cabdff1aSopenharmony_ci st = resource->ctx->streams[0]; 786cabdff1aSopenharmony_ci 787cabdff1aSopenharmony_ci pkt->stream_index = track->index; 788cabdff1aSopenharmony_ci 789cabdff1aSopenharmony_ci /* adjust the packet PTS and DTS based on the temporal position of the resource within the timeline */ 790cabdff1aSopenharmony_ci 791cabdff1aSopenharmony_ci ret = imf_time_to_ts(&delta_ts, resource->ts_offset, st->time_base); 792cabdff1aSopenharmony_ci 793cabdff1aSopenharmony_ci if (!ret) { 794cabdff1aSopenharmony_ci if (pkt->pts != AV_NOPTS_VALUE) 795cabdff1aSopenharmony_ci pkt->pts += delta_ts; 796cabdff1aSopenharmony_ci if (pkt->dts != AV_NOPTS_VALUE) 797cabdff1aSopenharmony_ci pkt->dts += delta_ts; 798cabdff1aSopenharmony_ci } else { 799cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Incoherent time stamp " AVRATIONAL_FORMAT 800cabdff1aSopenharmony_ci " for time base " AVRATIONAL_FORMAT, 801cabdff1aSopenharmony_ci AVRATIONAL_ARG(resource->ts_offset), 802cabdff1aSopenharmony_ci AVRATIONAL_ARG(pkt->time_base)); 803cabdff1aSopenharmony_ci } 804cabdff1aSopenharmony_ci 805cabdff1aSopenharmony_ci /* advance the track timestamp by the packet duration */ 806cabdff1aSopenharmony_ci 807cabdff1aSopenharmony_ci next_timestamp = av_add_q(track->current_timestamp, 808cabdff1aSopenharmony_ci av_mul_q(av_make_q((int)pkt->duration, 1), st->time_base)); 809cabdff1aSopenharmony_ci 810cabdff1aSopenharmony_ci /* if necessary, clamp the next timestamp to the end of the current resource */ 811cabdff1aSopenharmony_ci 812cabdff1aSopenharmony_ci if (av_cmp_q(next_timestamp, resource->end_time) > 0) { 813cabdff1aSopenharmony_ci 814cabdff1aSopenharmony_ci int64_t new_pkt_dur; 815cabdff1aSopenharmony_ci 816cabdff1aSopenharmony_ci /* shrink the packet duration */ 817cabdff1aSopenharmony_ci 818cabdff1aSopenharmony_ci ret = imf_time_to_ts(&new_pkt_dur, 819cabdff1aSopenharmony_ci av_sub_q(resource->end_time, track->current_timestamp), 820cabdff1aSopenharmony_ci st->time_base); 821cabdff1aSopenharmony_ci 822cabdff1aSopenharmony_ci if (!ret) 823cabdff1aSopenharmony_ci pkt->duration = new_pkt_dur; 824cabdff1aSopenharmony_ci else 825cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Incoherent time base in packet duration calculation\n"); 826cabdff1aSopenharmony_ci 827cabdff1aSopenharmony_ci /* shrink the packet itself for audio essence */ 828cabdff1aSopenharmony_ci 829cabdff1aSopenharmony_ci if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { 830cabdff1aSopenharmony_ci 831cabdff1aSopenharmony_ci if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S24LE) { 832cabdff1aSopenharmony_ci /* AV_CODEC_ID_PCM_S24LE is the only PCM format supported in IMF */ 833cabdff1aSopenharmony_ci /* in this case, explicitly shrink the packet */ 834cabdff1aSopenharmony_ci 835cabdff1aSopenharmony_ci int bytes_per_sample = av_get_exact_bits_per_sample(st->codecpar->codec_id) >> 3; 836cabdff1aSopenharmony_ci int64_t nbsamples = av_rescale_q(pkt->duration, 837cabdff1aSopenharmony_ci st->time_base, 838cabdff1aSopenharmony_ci av_make_q(1, st->codecpar->sample_rate)); 839cabdff1aSopenharmony_ci av_shrink_packet(pkt, nbsamples * st->codecpar->ch_layout.nb_channels * bytes_per_sample); 840cabdff1aSopenharmony_ci 841cabdff1aSopenharmony_ci } else { 842cabdff1aSopenharmony_ci /* in all other cases, use side data to skip samples */ 843cabdff1aSopenharmony_ci int64_t skip_samples; 844cabdff1aSopenharmony_ci 845cabdff1aSopenharmony_ci ret = imf_time_to_ts(&skip_samples, 846cabdff1aSopenharmony_ci av_sub_q(next_timestamp, resource->end_time), 847cabdff1aSopenharmony_ci av_make_q(1, st->codecpar->sample_rate)); 848cabdff1aSopenharmony_ci 849cabdff1aSopenharmony_ci if (ret || skip_samples < 0 || skip_samples > UINT32_MAX) { 850cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Cannot skip audio samples\n"); 851cabdff1aSopenharmony_ci } else { 852cabdff1aSopenharmony_ci uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); 853cabdff1aSopenharmony_ci if (!side_data) 854cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 855cabdff1aSopenharmony_ci 856cabdff1aSopenharmony_ci AV_WL32(side_data + 4, skip_samples); /* skip from end of this packet */ 857cabdff1aSopenharmony_ci side_data[6] = 1; /* reason for end is convergence */ 858cabdff1aSopenharmony_ci } 859cabdff1aSopenharmony_ci } 860cabdff1aSopenharmony_ci 861cabdff1aSopenharmony_ci next_timestamp = resource->end_time; 862cabdff1aSopenharmony_ci 863cabdff1aSopenharmony_ci } else { 864cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Non-audio packet duration reduced\n"); 865cabdff1aSopenharmony_ci } 866cabdff1aSopenharmony_ci } 867cabdff1aSopenharmony_ci 868cabdff1aSopenharmony_ci track->current_timestamp = next_timestamp; 869cabdff1aSopenharmony_ci 870cabdff1aSopenharmony_ci return 0; 871cabdff1aSopenharmony_ci} 872cabdff1aSopenharmony_ci 873cabdff1aSopenharmony_cistatic int imf_close(AVFormatContext *s) 874cabdff1aSopenharmony_ci{ 875cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 876cabdff1aSopenharmony_ci 877cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Close IMF package\n"); 878cabdff1aSopenharmony_ci av_dict_free(&c->avio_opts); 879cabdff1aSopenharmony_ci av_freep(&c->base_url); 880cabdff1aSopenharmony_ci imf_asset_locator_map_deinit(&c->asset_locator_map); 881cabdff1aSopenharmony_ci ff_imf_cpl_free(c->cpl); 882cabdff1aSopenharmony_ci 883cabdff1aSopenharmony_ci for (uint32_t i = 0; i < c->track_count; i++) { 884cabdff1aSopenharmony_ci imf_virtual_track_playback_context_deinit(c->tracks[i]); 885cabdff1aSopenharmony_ci av_freep(&c->tracks[i]); 886cabdff1aSopenharmony_ci } 887cabdff1aSopenharmony_ci 888cabdff1aSopenharmony_ci av_freep(&c->tracks); 889cabdff1aSopenharmony_ci 890cabdff1aSopenharmony_ci return 0; 891cabdff1aSopenharmony_ci} 892cabdff1aSopenharmony_ci 893cabdff1aSopenharmony_cistatic int imf_probe(const AVProbeData *p) 894cabdff1aSopenharmony_ci{ 895cabdff1aSopenharmony_ci if (!strstr(p->buf, "<CompositionPlaylist")) 896cabdff1aSopenharmony_ci return 0; 897cabdff1aSopenharmony_ci 898cabdff1aSopenharmony_ci /* check for a ContentTitle element without including ContentTitleText, 899cabdff1aSopenharmony_ci * which is used by the D-Cinema CPL. 900cabdff1aSopenharmony_ci */ 901cabdff1aSopenharmony_ci if (!strstr(p->buf, "ContentTitle>")) 902cabdff1aSopenharmony_ci return 0; 903cabdff1aSopenharmony_ci 904cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 905cabdff1aSopenharmony_ci} 906cabdff1aSopenharmony_ci 907cabdff1aSopenharmony_cistatic int coherent_ts(int64_t ts, AVRational in_tb, AVRational out_tb) 908cabdff1aSopenharmony_ci{ 909cabdff1aSopenharmony_ci int dst_num; 910cabdff1aSopenharmony_ci int dst_den; 911cabdff1aSopenharmony_ci int ret; 912cabdff1aSopenharmony_ci 913cabdff1aSopenharmony_ci ret = av_reduce(&dst_num, &dst_den, ts * in_tb.num * out_tb.den, 914cabdff1aSopenharmony_ci in_tb.den * out_tb.num, INT64_MAX); 915cabdff1aSopenharmony_ci if (!ret || dst_den != 1) 916cabdff1aSopenharmony_ci return 0; 917cabdff1aSopenharmony_ci 918cabdff1aSopenharmony_ci return 1; 919cabdff1aSopenharmony_ci} 920cabdff1aSopenharmony_ci 921cabdff1aSopenharmony_cistatic int imf_seek(AVFormatContext *s, int stream_index, int64_t min_ts, 922cabdff1aSopenharmony_ci int64_t ts, int64_t max_ts, int flags) 923cabdff1aSopenharmony_ci{ 924cabdff1aSopenharmony_ci IMFContext *c = s->priv_data; 925cabdff1aSopenharmony_ci uint32_t i; 926cabdff1aSopenharmony_ci 927cabdff1aSopenharmony_ci if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME)) 928cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 929cabdff1aSopenharmony_ci 930cabdff1aSopenharmony_ci /* rescale timestamps to Composition edit units */ 931cabdff1aSopenharmony_ci if (stream_index < 0) 932cabdff1aSopenharmony_ci ff_rescale_interval(AV_TIME_BASE_Q, 933cabdff1aSopenharmony_ci av_make_q(c->cpl->edit_rate.den, c->cpl->edit_rate.num), 934cabdff1aSopenharmony_ci &min_ts, &ts, &max_ts); 935cabdff1aSopenharmony_ci else 936cabdff1aSopenharmony_ci ff_rescale_interval(s->streams[stream_index]->time_base, 937cabdff1aSopenharmony_ci av_make_q(c->cpl->edit_rate.den, c->cpl->edit_rate.num), 938cabdff1aSopenharmony_ci &min_ts, &ts, &max_ts); 939cabdff1aSopenharmony_ci 940cabdff1aSopenharmony_ci /* requested timestamp bounds are too close */ 941cabdff1aSopenharmony_ci if (max_ts < min_ts) 942cabdff1aSopenharmony_ci return -1; 943cabdff1aSopenharmony_ci 944cabdff1aSopenharmony_ci /* clamp requested timestamp to provided bounds */ 945cabdff1aSopenharmony_ci ts = FFMAX(FFMIN(ts, max_ts), min_ts); 946cabdff1aSopenharmony_ci 947cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Seeking to Composition Playlist edit unit %" PRIi64 "\n", ts); 948cabdff1aSopenharmony_ci 949cabdff1aSopenharmony_ci /* set the dts of each stream and temporal offset of each track */ 950cabdff1aSopenharmony_ci for (i = 0; i < c->track_count; i++) { 951cabdff1aSopenharmony_ci AVStream *st = s->streams[i]; 952cabdff1aSopenharmony_ci IMFVirtualTrackPlaybackCtx *t = c->tracks[i]; 953cabdff1aSopenharmony_ci int64_t dts; 954cabdff1aSopenharmony_ci 955cabdff1aSopenharmony_ci if (!coherent_ts(ts, av_make_q(c->cpl->edit_rate.den, c->cpl->edit_rate.num), 956cabdff1aSopenharmony_ci st->time_base)) 957cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Seek position is not coherent across tracks\n"); 958cabdff1aSopenharmony_ci 959cabdff1aSopenharmony_ci dts = av_rescale(ts, 960cabdff1aSopenharmony_ci st->time_base.den * c->cpl->edit_rate.den, 961cabdff1aSopenharmony_ci st->time_base.num * c->cpl->edit_rate.num); 962cabdff1aSopenharmony_ci 963cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Seeking to dts=%" PRId64 " on stream_index=%d\n", 964cabdff1aSopenharmony_ci dts, i); 965cabdff1aSopenharmony_ci 966cabdff1aSopenharmony_ci t->current_timestamp = av_mul_q(av_make_q(dts, 1), st->time_base); 967cabdff1aSopenharmony_ci if (t->current_resource_index >= 0) { 968cabdff1aSopenharmony_ci avformat_close_input(&t->resources[t->current_resource_index].ctx); 969cabdff1aSopenharmony_ci t->current_resource_index = -1; 970cabdff1aSopenharmony_ci } 971cabdff1aSopenharmony_ci } 972cabdff1aSopenharmony_ci 973cabdff1aSopenharmony_ci return 0; 974cabdff1aSopenharmony_ci} 975cabdff1aSopenharmony_ci 976cabdff1aSopenharmony_cistatic const AVOption imf_options[] = { 977cabdff1aSopenharmony_ci { 978cabdff1aSopenharmony_ci .name = "assetmaps", 979cabdff1aSopenharmony_ci .help = "Comma-separated paths to ASSETMAP files." 980cabdff1aSopenharmony_ci "If not specified, the `ASSETMAP.xml` file in the same " 981cabdff1aSopenharmony_ci "directory as the CPL is used.", 982cabdff1aSopenharmony_ci .offset = offsetof(IMFContext, asset_map_paths), 983cabdff1aSopenharmony_ci .type = AV_OPT_TYPE_STRING, 984cabdff1aSopenharmony_ci .default_val = {.str = NULL}, 985cabdff1aSopenharmony_ci .flags = AV_OPT_FLAG_DECODING_PARAM, 986cabdff1aSopenharmony_ci }, 987cabdff1aSopenharmony_ci {NULL}, 988cabdff1aSopenharmony_ci}; 989cabdff1aSopenharmony_ci 990cabdff1aSopenharmony_cistatic const AVClass imf_class = { 991cabdff1aSopenharmony_ci .class_name = "imf", 992cabdff1aSopenharmony_ci .item_name = av_default_item_name, 993cabdff1aSopenharmony_ci .option = imf_options, 994cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 995cabdff1aSopenharmony_ci}; 996cabdff1aSopenharmony_ci 997cabdff1aSopenharmony_ciconst AVInputFormat ff_imf_demuxer = { 998cabdff1aSopenharmony_ci .name = "imf", 999cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("IMF (Interoperable Master Format)"), 1000cabdff1aSopenharmony_ci .flags = AVFMT_EXPERIMENTAL | AVFMT_NO_BYTE_SEEK, 1001cabdff1aSopenharmony_ci .flags_internal = FF_FMT_INIT_CLEANUP, 1002cabdff1aSopenharmony_ci .priv_class = &imf_class, 1003cabdff1aSopenharmony_ci .priv_data_size = sizeof(IMFContext), 1004cabdff1aSopenharmony_ci .read_probe = imf_probe, 1005cabdff1aSopenharmony_ci .read_header = imf_read_header, 1006cabdff1aSopenharmony_ci .read_packet = imf_read_packet, 1007cabdff1aSopenharmony_ci .read_close = imf_close, 1008cabdff1aSopenharmony_ci .read_seek2 = imf_seek, 1009cabdff1aSopenharmony_ci}; 1010