canalplus / rx-player

DASH/Smooth HTML5 Video Player
https://developers.canal-plus.com/rx-player/
Apache License 2.0
867 stars 131 forks source link

Infinite loop (or recursion) while parsing .mpd #1110

Closed arzeth closed 2 years ago

arzeth commented 2 years ago

Version: latest (v3.27.0) I've removed audio from the .mpd so that it's easier to find the bug. The bug doesn't occur when only the last period remains. The bug occurs when the last two periods remain.

Maybe it's because the periods here have different maxWidth and maxHeight?

Probably something is wrong with flattenOverlappingPeriods (100% CPU usage) according to Firefox's profiler. I could not use inspector in Chromium because the tab completely freezed. And even when I completely close the tab in Chromium, the Chromium's main process's CPU usage remains 100%, other tabs continue to work, but when I try to exit the Chromium, it freezes, so I kill -9 it.

This .mpd is generated on-the-fly from several .mpd by my cdn-server's short code so that a streamer could pause/unpause a recording, and then after the stream ends it would be "one" video (actually several) for viewers.

...Now that I think it I forgot to upscale so that the number of resolutions (media_*.m3u8) was the same everywhere to make videos HLS (iOS) compatible...

<?xml version="1.0" encoding="utf-8"?>
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="urn:mpeg:dash:schema:mpd:2011"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
    profiles="urn:mpeg:dash:profile:isoff-live:2011"
    type="static"
    mediaPresentationDuration="PT13M39.2S"
    maxSegmentDuration="PT1.6S"
    minBufferTime="PT1.6S">
    <ProgramInformation>
        <Title>FFmpeg</Title>
    </ProgramInformation>
    <ServiceDescription id="0">
    </ServiceDescription>
    <Period id="0" start="PT0.0S">
        <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
            <Representation id="0" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="1378000" width="864" height="486" sar="1:1">
                <SegmentTemplate timescale="1000000" duration="1600000" availabilityTimeOffset="1.567" initialization="0/$RepresentationID$/init.m4s" media="0/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                </SegmentTemplate>
            </Representation>
            <Representation id="1" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="2438000" width="1280" height="720" sar="1:1">
                <SegmentTemplate timescale="1000000" duration="1600000" availabilityTimeOffset="1.567" initialization="0/$RepresentationID$/init.m4s" media="0/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                </SegmentTemplate>
            </Representation>
            <Representation id="2" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="742000" width="640" height="360" sar="1:1">
                <SegmentTemplate timescale="1000000" duration="1600000" availabilityTimeOffset="1.567" initialization="0/$RepresentationID$/init.m4s" media="0/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                </SegmentTemplate>
            </Representation>
            <Representation id="3" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="328000" width="416" height="234" sar="1:1">
                <SegmentTemplate timescale="1000000" duration="1600000" availabilityTimeOffset="1.567" initialization="0/$RepresentationID$/init.m4s" media="0/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                </SegmentTemplate>
            </Representation>
            <Representation id="4" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="135000" width="256" height="144" sar="1:1">
                <SegmentTemplate timescale="1000000" duration="1600000" availabilityTimeOffset="1.567" initialization="0/$RepresentationID$/init.m4s" media="0/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
    </Period>
    <Period id="1" start="PT2M30.1S">
        <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="864" maxHeight="486" par="16:9">
            <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="0" />
            <Representation id="0" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="1378000" width="864" height="486" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="1/$RepresentationID$/init.m4s" media="1/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="10240" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="1" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="742000" width="640" height="360" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="1/$RepresentationID$/init.m4s" media="1/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="10240" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="2" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="328000" width="416" height="234" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="1/$RepresentationID$/init.m4s" media="1/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="10240" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="3" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="135000" width="256" height="144" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="1/$RepresentationID$/init.m4s" media="1/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="10240" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
    </Period>
    <Period id="2" start="PT3M2.7S">
        <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="864" maxHeight="486" par="16:9">
            <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="1" />
            <Representation id="0" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="1378000" width="864" height="486" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="2/$RepresentationID$/init.m4s" media="2/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="376" />
                        <S d="8704" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="1" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="742000" width="640" height="360" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="2/$RepresentationID$/init.m4s" media="2/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="376" />
                        <S d="8704" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="2" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="328000" width="416" height="234" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="2/$RepresentationID$/init.m4s" media="2/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="376" />
                        <S d="8704" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="3" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="135000" width="256" height="144" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="2/$RepresentationID$/init.m4s" media="2/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="376" />
                        <S d="8704" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
    </Period>
    <Period id="3" start="PT13M6.4S">
        <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1920" maxHeight="1080" par="16:9">
            <SupplementalProperty schemeIdUri="urn:mpeg:dash:period_continuity:2014" value="2" />
            <Representation id="0" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="1378000" width="864" height="486" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="3/$RepresentationID$/init.m4s" media="3/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="12288" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="1" mimeType="video/mp4" codecs="avc1.640029" bandwidth="4240000" width="1920" height="1080" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="3/$RepresentationID$/init.m4s" media="3/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="12288" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="2" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="2438000" width="1280" height="720" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="3/$RepresentationID$/init.m4s" media="3/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="12288" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="3" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="742000" width="640" height="360" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="3/$RepresentationID$/init.m4s" media="3/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="12288" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="4" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="328000" width="416" height="234" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="3/$RepresentationID$/init.m4s" media="3/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="12288" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
            <Representation id="5" mimeType="video/mp4" codecs="avc1.4d401f" bandwidth="135000" width="256" height="144" sar="1:1">
                <SegmentTemplate timescale="15360" initialization="3/$RepresentationID$/init.m4s" media="3/$RepresentationID$/$RepresentationID$s$Number%07d$.m4s" startNumber="1">
                    <SegmentTimeline>
                        <S t="3932" d="24576" r="19" />
                        <S d="12288" />
                    </SegmentTimeline>
                </SegmentTemplate>
            </Representation>
        </AdaptationSet>
    </Period>
</MPD>
peaBerberian commented 2 years ago

Hi,

I was able to reproduce it. I looked at it and it seems to be linked to an unfortunate rounding error on our side found in the following loop: https://github.com/canalplus/rx-player/blob/5846b7913932ed4f8268856768283fdd99675580/src/parsers/manifest/dash/common/flatten_overlapping_periods.ts#L58

With your MPD, that quoted line is doing the following operation:

(182.7 + 603.7) > 786.4

Here, 182.7 + 603.7 should be equal to 786.4 and we should thus exit the loop.

But it appears that due to how floating numbers are managed in JavaScript (and most other languages), it is actually equal to a nonsensical 786.4000000000001. Due to this, we're locked in that loop indefinitely, as the condition never becomes false.

This should be relatively easy to fix on our side. Thanks!