emarsden / dash-mpd-rs Goto Github PK
View Code? Open in Web Editor NEWRust library for parsing, serializing and downloading media content from a DASH MPD manifest.
License: MIT License
Rust library for parsing, serializing and downloading media content from a DASH MPD manifest.
License: MIT License
0.8 introduced a regression with our DASH example in GStreamer.
$ xmllint -format dash_stream/manifest.mpd
dash_stream/manifest.mpd:2: namespace error : Namespace prefix xsi for schemaLocation on MPD is not defined
:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT1M23.333S"
With 0.7
the XML was
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" type="dynamic" schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="2023-04-26T13:35:15.546317603Z">
which changed to this with 0.8
:
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" type="dynamic" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="2023-04-26T13:34:24.374770165Z">
The XML parser does not seem happy with prefixing schemaLocation
with xsi:
.
I moved from 0.14.7 to 0.14.8 (only using "scte35" feature - only doing serialization of MPDs, not fetching via lib) and now I get protobuf build/link errors
ld: multiple errors: archive member '/' not a mach-o file in '/Users/buzz/comcast-development/viper/clo/clo.main/target/debug/build/protobuf-src-ac10cb5cd0b29ebe/out/install/build/src/.libs/libprotoc.a'; archive member '/' not a mach-o file in '/Users/buzz/comcast-development/viper/clo/clo.main/target/debug/build/protobuf-src-ac10cb5cd0b29ebe/out/install/build/src/.libs/libprotobuf.a'; archive member '/' not a mach-o file in '/Users/buzz/comcast-development/viper/clo/clo.main/target/debug/build/protobuf-src-ac10cb5cd0b29ebe/out/install/build/src/.libs/libprotobuf.a'
Any idea what I can do to get around it?
I figured if I wasn't using the non-serialization features I wouldn't bring them in as dependencies but it could be a transient dependency.
Thanks as always for the lib!
Because the iso860
crate only includes precision down to millisecond, if an MPD is delivered with more precision date/time (as some of ours are), we lose that precision. It would be helpful if there was a way we could maintain that precision.
Serde serialize f64::INFINITY to 'inf', in XML it should be INF
see http://www.datypic.com/sc/xsd/t-xsd_float.html
You will find bellow an example of MPD that I want to deserialize and serialize again. availabilityTimeOffset="INF"
becomes availabilityTimeOffset="inf"
after serialization and then is not accepted by Dash.js
<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" profiles="urn:mpeg:dash:profile:full:2011" type="dynamic" availabilityStartTime="1970-01-01T00:00:00Z" publishTime="1970-01-01T00:00:00Z" minimumUpdatePeriod="PT1S" minBufferTime="PT1S" timeShiftBufferDepth="PT1M" maxSegmentDuration="PT1S">
<Period id="P0" start="PT0S">
<AdaptationSet id="1" contentType="video" par="16:9" maxWidth="3840" maxHeight="2160" segmentAlignment="true">
<SegmentTemplate media="$RepresentationID$/$Number$.m4s" initialization="$RepresentationID$/init.mp4" duration="12800" startNumber="0" timescale="12800" availabilityTimeOffset="INF"></SegmentTemplate>
<Representation id="2160p" bandwidth="19242008" width="3840" height="2160" mimeType="video/mp4" codecs="hev1.1.6.L153.90" startWithSAP="1"></Representation>
</AdaptationSet>
<AdaptationSet id="2" lang="en" contentType="audio" segmentAlignment="true">
<SegmentTemplate media="$RepresentationID$/$Number$.m4s" initialization="$RepresentationID$/init.mp4" duration="48000" startNumber="0" timescale="48000" availabilityTimeOffset="INF"></SegmentTemplate>
<Representation id="audio" bandwidth="297168" audioSamplingRate="48000" mimeType="audio/mp4" codecs="mp4a.40.2" startWithSAP="1">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"></AudioChannelConfiguration>
</Representation>
</AdaptationSet>
</Period>
<UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-xsdate:2014" value="https://time.akamai.com/?iso&ms"></UTCTiming>
</MPD>
I'm not sure how to fix that, one possibility is to overwrite the f64 serializer
#[serde(rename = "@availabilityTimeOffset", serialize_with = "f64_to_xml")]
pub availabilityTimeOffset: Option<f64>,
Maybe quick-xml has a solution ?
It would be useful to implement a scripting interface to the muxing functionality required by this library. This would make it easier to implement a new muxer, and to change the arguments used for a muxing application (in particular, ffmpeg has many commandline arguments that control encoding which can be useful to change, for example depending on the container format).
We need muxing for:
This could be implemented using the platform's commandline interface, or a scripting platform such as rhai or Python-in-WASM.
dash_mpd currently uses blocking HTTP when downloading a stream which can cause problems in async applications. Is there an intent to support async HTTP?
byteRange, availabilityTimeComplete and availabilityTimeOffset should be part of BaseURL attribute
The schema from 23009-1:2019 is the following
<!-- Base URL -->
<xs:complexType name="BaseURLType">
<xs:simpleContent>
<xs:extension base="xs:anyURI">
<xs:attribute name="serviceLocation" type="xs:string"/>
<xs:attribute name="byteRange" type="xs:string"/>
<xs:attribute name="availabilityTimeOffset" type="xs:double"/>
<xs:attribute name="availabilityTimeComplete" type="xs:boolean"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
Is there a way to download video and audio without muxing them into one file? I would like to have them as separate files.
Role
struct is exported but isn't used anywhere.
https://docs.rs/dash-mpd/0.7.2/dash_mpd/struct.AdaptationSet.html?search=Role
<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT734.1666870117188S">
<Period id="0">
<AdaptationSet contentType="audio" lang="en" subsegmentAlignment="true" group="1" label="English">
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
<Label>English</Label>
<Representation id="0" bandwidth="134352" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
<BaseURL>audio-en-audio-en-mp4a.mp4</BaseURL>
<SegmentBase indexRange="822-2329" timescale="44100">
<Initialization range="0-821" />
</SegmentBase>
</Representation>
</AdaptationSet>
<AdaptationSet contentType="audio" lang="en-low" subsegmentAlignment="true" group="2" label="English-low">
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
<Label>English-low</Label>
<Representation id="1" bandwidth="133675" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
<BaseURL>audio-de-audio-de-mp4a.mp4</BaseURL>
<SegmentBase indexRange="822-2329" timescale="44100">
<Initialization range="0-821" />
</SegmentBase>
</Representation>
</AdaptationSet>
<AdaptationSet contentType="audio" lang="en-high" subsegmentAlignment="true" group="3" label="English-high">
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
<Label>English-high</Label>
<Representation id="2" bandwidth="133550" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
<BaseURL>audio-fr-audio-fr-mp4a.mp4</BaseURL>
<SegmentBase indexRange="822-2329" timescale="44100">
<Initialization range="0-821" />
</SegmentBase>
</Representation>
</AdaptationSet>
<AdaptationSet contentType="video" maxWidth="1920" maxHeight="1080" frameRate="24/1" subsegmentAlignment="true" par="16:9" group="4">
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
<Representation id="3" bandwidth="484364" codecs="avc1.640015" mimeType="video/mp4" sar="1:1" width="512" height="288">
<BaseURL>video-H264-288-400k-video-avc1.mp4</BaseURL>
<SegmentBase indexRange="865-2372" timescale="24">
<Initialization range="0-864" />
</SegmentBase>
</Representation>
<Representation id="4" bandwidth="947132" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360">
<BaseURL>video-H264-360-800k-video-avc1.mp4</BaseURL>
<SegmentBase indexRange="866-2373" timescale="24">
<Initialization range="0-865" />
</SegmentBase>
</Representation>
<Representation id="5" bandwidth="1425808" codecs="avc1.64001e" mimeType="video/mp4" sar="640:639" width="852" height="480">
<BaseURL>video-H264-480-1200k-video-avc1.mp4</BaseURL>
<SegmentBase indexRange="886-2393" timescale="24">
<Initialization range="0-885" />
</SegmentBase>
</Representation>
<Representation id="6" bandwidth="2498547" codecs="avc1.64001f" mimeType="video/mp4" sar="1:1" width="1280" height="720">
<BaseURL>video-H264-720-2100k-video-avc1.mp4</BaseURL>
<SegmentBase indexRange="866-2373" timescale="24">
<Initialization range="0-865" />
</SegmentBase>
</Representation>
<Representation id="7" bandwidth="3573424" codecs="avc1.640028" mimeType="video/mp4" sar="1:1" width="1920" height="1080">
<BaseURL>video-H264-1080-3000k-video-avc1.mp4</BaseURL>
<SegmentBase indexRange="867-2374" timescale="24">
<Initialization range="0-866" />
</SegmentBase>
</Representation>
</AdaptationSet>
<AdaptationSet contentType="text" mimeType="text/vtt" lang="de" group="5" label="German">
<Label>German</Label>
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="subtitle" />
<Representation bandwidth="1225" id="8">
<BaseURL>subtitle-de.vtt</BaseURL>
</Representation>
</AdaptationSet>
<AdaptationSet contentType="text" mimeType="text/vtt" lang="en" group="6" label="English">
<Label>English</Label>
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="subtitle" />
<Representation bandwidth="1119" id="9">
<BaseURL>subtitle-en.vtt</BaseURL>
</Representation>
</AdaptationSet>
<AdaptationSet contentType="text" mimeType="text/vtt" lang="fr" group="7" label="French">
<Label>French</Label>
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="subtitle" />
<Representation bandwidth="1165" id="10">
<BaseURL>subtitle-fr.vtt</BaseURL>
</Representation>
</AdaptationSet>
</Period>
</MPD>
Line 1657 in 0e543c4
The field is missing
#[serde(rename = "Location", default)]
Under the Limitations / unsupported features
section of the README it lists dynamic MPD manifests. Is there plans to support dynamic MPD manifests or is this something you decided not to implement?
My specific use case is as follows:
I have a media ingest server written in Rust that takes in some streams from OBS, re-encodes in various formats, and then produces HLS and DASH manifests. Currently the HLS + DASH manifests are produced by FFmpeg, but I'd like to have some more control over the manifests outputted so I was hoping to build them myself and just use FFmpeg for the encoding.
I don't actually know much about the difference between static/dynamic MPDs, so I'm not sure what "supporting" them would mean for you ๐ so was just curious
This library is super useful but requires more dependencies than required (for parsing only).
Main mpd parser only use serde, quick-xml and regex dependencies all other dependencies are used by fetch module. My proposal is that fetch module and it's dependencies should be kept under a feature and main mpd parser in the root.
anyhow can also be replaced with std::error::Error trait. For fetch feature anyhow can be optional dep.
Can MPD be serialized to String?
It can be useful to allow the user to read and modify the MPD manifest before downloading media segments from it. Use cases:
As of 2023-10-22 we have implemented support for XSLT stylesheets via xsltproc, which allows XML rewriting. This is a standards-based and easy to implement solution to filtering/rewriting, but xsltproc only supports XSLT v1.0 (v3.0 is more flexible and for example includes functions for manipulating xs:duration attributes) and XSLT is not the most widely adopted language.
Possible alternatives:
I will be thinking about implementing some of these in the next few months.
You may have noticed in the past few days a build issue when using the "trust-dns" feature, caused by hickory-dns/hickory-dns#1946. The build failure is now resolved, but HTTP requests don't seem to be working currently (indefinite hang) with this feature enabled. This probably affects all users of the reqwest crate build with the trust-dns feature. I'll close this issue when the problem is resolved.
I took a look through the new async changes and that tokio
is not a dev-dependency. Since this is a library crate, the rt-multi-thread feature is not required and backoff
will take care of its dependency on tokio by itself. So, tokio
can be safely moved to be a dev-dependency.
For 0.15 I noticed there's bitstreamSwitching and BitstreamSwitching properties in SegmentTemplate - that seems like a mistake?
Even though a ContentProtection
struct exists, it is not deserialized as part of the AdaptationSet
struct.
Is there any reason for this?
Furthermore, I'd be interested in deserializing ContentProtection
with the following structure, which currently isn't possible:
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<cenc:pssh>Base64Data==</cenc:pssh>
</ContentProtection>
Adding both the schemeIdUri
and cenc:pssh
fields to ContentProtection
would be appreciated.
I like to keep my binary size down and some features specified for reqwest I don't need. For example, compression and use of rustls over native-tls are features I don't need in my application and I prefer to turn those off to speed up CI and lower binary size.
Ideally, those features would be enabled by default (using default features) but opt-out for those that don't need it. Considering the next update will be a breaking release, I think now is the ideal time to introduce these changes.
Any objective to adding derived PartialEq to the data structures?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.