streamlink/tests/stream/test_dash_parser.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

457 lines
21 KiB
Python
Raw Normal View History

MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
import datetime
import itertools
import unittest
from operator import attrgetter
from unittest.mock import Mock
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
2023-02-16 00:51:25 +01:00
import pytest
from freezegun import freeze_time
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
from streamlink.stream.dash_manifest import MPD, MPDParsers, MPDParsingError, Representation, Segment
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
from tests.resources import xml
UTC = datetime.timezone.utc
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
class TestSegment:
@pytest.mark.parametrize(("segmentdata", "expected"), [
({"url": "https://foo/bar", "number": 123, "init": True, "content": False}, "initialization"),
({"url": "https://foo/bar", "number": 123, "init": True, "content": True}, "123"),
({"url": "https://foo/bar", "number": None, "init": True, "content": True}, "bar"),
({"url": "https://foo/bar", "number": 123}, "123"),
({"url": "https://foo/bar"}, "bar"),
({"url": "https://foo/bar/"}, "bar"),
({"url": "https://foo/bar/baz.qux"}, "baz.qux"),
({"url": "https://foo/bar/baz.qux"}, "baz.qux"),
({"url": "https://foo/bar/baz.qux?asdf"}, "baz.qux"),
])
def test_name(self, segmentdata: dict, expected: str):
segment = Segment(**segmentdata)
assert segment.name == expected
@pytest.mark.parametrize(("available_at", "expected"), [
(datetime.datetime(2000, 1, 2, 3, 4, 5, 123456, tzinfo=UTC), 1 * 86400 + 3 * 3600 + 4 * 60 + 5 + 0.123456),
(datetime.datetime(2000, 1, 1, 0, 0, 0, 0, tzinfo=UTC), 0.0),
(datetime.datetime(1999, 12, 31, 23, 59, 59, 999999, tzinfo=UTC), 0.0),
])
def test_available_in(self, available_at: datetime.datetime, expected: float):
segment = Segment(url="foo", available_at=available_at)
with freeze_time("2000-01-01T00:00:00Z"):
assert segment.available_in == pytest.approx(expected)
def test_availability(self):
segment = Segment(url="foo", available_at=datetime.datetime(2000, 1, 2, 3, 4, 5, 123456, tzinfo=UTC))
with freeze_time("2000-01-01T00:00:00Z"):
assert segment.availability == "2000-01-02T03:04:05.123456Z / 2000-01-01T00:00:00.000000Z"
class TestMPDParsers(unittest.TestCase):
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_bool_str(self):
2023-02-16 00:51:25 +01:00
assert MPDParsers.bool_str("true")
assert MPDParsers.bool_str("TRUE")
assert MPDParsers.bool_str("True")
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
2023-02-16 00:51:25 +01:00
assert not MPDParsers.bool_str("0")
assert not MPDParsers.bool_str("False")
assert not MPDParsers.bool_str("false")
assert not MPDParsers.bool_str("FALSE")
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_type(self):
2023-02-16 00:51:25 +01:00
assert MPDParsers.type("dynamic") == "dynamic"
assert MPDParsers.type("static") == "static"
with pytest.raises(MPDParsingError):
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
MPDParsers.type("other")
def test_duration(self):
2023-02-16 00:51:25 +01:00
assert MPDParsers.duration("PT1S") == datetime.timedelta(0, 1)
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_datetime(self):
assert MPDParsers.datetime("2018-01-01T00:00:00Z") == datetime.datetime(2018, 1, 1, 0, 0, 0, tzinfo=UTC)
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_segment_template(self):
2023-02-16 00:51:25 +01:00
assert MPDParsers.segment_template("$Time$-$Number$-$Other$")(Time=1, Number=2, Other=3) == "1-2-3"
assert MPDParsers.segment_template("$Number%05d$")(Number=123) == "00123"
assert MPDParsers.segment_template("$Time%0.02f$")(Time=100.234) == "100.23"
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_frame_rate(self):
2023-02-16 00:51:25 +01:00
assert MPDParsers.frame_rate("1/25") == pytest.approx(1.0 / 25.0)
assert MPDParsers.frame_rate("0.2") == pytest.approx(0.2)
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_timedelta(self):
2023-02-16 00:51:25 +01:00
assert MPDParsers.timedelta(1)(100) == datetime.timedelta(0, 100.0)
assert MPDParsers.timedelta(10)(100) == datetime.timedelta(0, 10.0)
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_range(self):
2023-02-16 00:51:25 +01:00
assert MPDParsers.range("100-") == (100, None)
assert MPDParsers.range("100-199") == (100, 100)
with pytest.raises(MPDParsingError):
MPDParsers.range("100")
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
class TestMPDParser(unittest.TestCase):
maxDiff = None
def test_no_segment_list_or_template(self):
with xml("dash/test_no_segment_list_or_template.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test/", url="http://test/manifest.mpd")
segments = [
{
"ident": representation.ident,
"mimeType": representation.mimeType,
"segments": [
(segment.url, segment.number, segment.duration, segment.available_at, segment.init, segment.content)
for segment in itertools.islice(representation.segments(), 100)
],
}
for adaptationset in mpd.periods[0].adaptationSets for representation in adaptationset.representations
if representation.id in ("1", "5", "6")
]
availability = datetime.datetime(1970, 1, 1, 0, 0, 0, tzinfo=UTC)
assert segments == [
{
"ident": (None, None, "1"),
"mimeType": "audio/mp4",
"segments": [("http://cdn1.example.com/7657412348.mp4", None, 3256.0, availability, True, True)],
},
{
"ident": (None, None, "5"),
"mimeType": "application/ttml+xml",
"segments": [("http://cdn1.example.com/796735657.xml", None, 3256.0, availability, True, True)],
},
{
"ident": (None, None, "6"),
"mimeType": "video/mp4",
"segments": [("http://cdn1.example.com/8563456473.mp4", None, 3256.0, availability, True, True)],
},
]
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_segments_number_time(self):
with xml("dash/test_1.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test.se/", url="http://test.se/manifest.mpd")
segments = mpd.periods[0].adaptationSets[0].representations[0].segments()
init_segment = next(segments)
2023-02-16 00:51:25 +01:00
assert init_segment.url == "http://test.se/tracks-v3/init-1526842800.g_m4v"
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
video_segments = list(map(attrgetter("url"), (itertools.islice(segments, 5))))
# suggested delay is 11 seconds, each segment is 5 seconds long - so there should be 3
2023-02-16 00:51:25 +01:00
assert video_segments == [
"http://test.se/tracks-v3/dvr-1526842800-698.g_m4v?t=3403000",
"http://test.se/tracks-v3/dvr-1526842800-699.g_m4v?t=3408000",
"http://test.se/tracks-v3/dvr-1526842800-700.g_m4v?t=3413000",
]
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_segments_static_number(self):
with xml("dash/test_2.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test.se/", url="http://test.se/manifest.mpd")
segments = mpd.periods[0].adaptationSets[3].representations[0].segments()
init_segment = next(segments)
2023-02-16 00:51:25 +01:00
assert init_segment.url == "http://test.se/video/250kbit/init.mp4"
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
video_segments = list(map(attrgetter("url"), (itertools.islice(segments, 100000))))
2023-02-16 00:51:25 +01:00
assert len(video_segments) == 444
assert video_segments[:5] == [
"http://test.se/video/250kbit/segment_1.m4s",
"http://test.se/video/250kbit/segment_2.m4s",
"http://test.se/video/250kbit/segment_3.m4s",
"http://test.se/video/250kbit/segment_4.m4s",
"http://test.se/video/250kbit/segment_5.m4s",
]
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_segments_dynamic_time(self):
with xml("dash/test_3.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test.se/", url="http://test.se/manifest.mpd")
segments = mpd.periods[0].adaptationSets[0].representations[0].segments()
init_segment = next(segments)
2023-02-16 00:51:25 +01:00
assert init_segment.url == "http://test.se/video-2800000-0.mp4?z32="
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
video_segments = list(map(attrgetter("url"), (itertools.islice(segments, 3))))
# default suggested delay is 3 seconds, each segment is 4 seconds long - so there should be 1 segment
2023-02-16 00:51:25 +01:00
assert video_segments == [
"http://test.se/video-time=1525450872000-2800000-0.m4s?z32=",
]
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_segments_dynamic_number(self):
# access manifest one hour after its availabilityStartTime
with xml("dash/test_segments_dynamic_number.mpd") as mpd_xml, \
freeze_time("2000-01-01T01:00:00Z"):
mpd = MPD(mpd_xml, base_url="http://test/", url="http://test/manifest.mpd")
stream_urls = [
(segment.url, segment.available_at)
for segment in itertools.islice(mpd.periods[0].adaptationSets[0].representations[0].segments(), 4)
]
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
assert stream_urls == [
(
"http://test/hd-5-init.mp4",
datetime.datetime(2000, 1, 1, 0, 1, 30, tzinfo=UTC),
),
(
"http://test/hd-5_000000793.mp4",
datetime.datetime(2000, 1, 1, 0, 59, 15, tzinfo=UTC),
),
(
"http://test/hd-5_000000794.mp4",
datetime.datetime(2000, 1, 1, 0, 59, 20, tzinfo=UTC),
),
(
"http://test/hd-5_000000795.mp4",
datetime.datetime(2000, 1, 1, 0, 59, 25, tzinfo=UTC),
),
]
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
def test_static_no_publish_time(self):
with xml("dash/test_static_no_publish_time.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test/", url="http://test/manifest.mpd")
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
segments = mpd.periods[0].adaptationSets[1].representations[0].segments()
segment_urls = [(segment.url, segment.available_at) for segment in itertools.islice(segments, 4)]
# ignores period start time in static manifests
expected_availability = datetime.datetime(2020, 1, 1, 0, 0, 0, tzinfo=UTC)
MPEG DASH Support (initial) (#1637) * stream.dash: parser for dash manifest files * stream.dash: stream player for dash with plugin to support dash:// prefixed urls * cli.main: make sure that streams are closed on errors * stream.dash: fix some parsing bugs * stream.dash: tidy up the segment number generation * plugins.dash: wip segment timeline * stream.dash: update to segment timeline parsing * stream.dash: py3 support * stream.dash: raise an error for DRM protected streams * stream.dash: fixes for timescaling and some segment templates * docs: add DASHStream to docs with other Stream classes * dash: fix for video only stream * plugins.dash: fix bug where all URLs were matched * stream.dash: fix issue with manifest reload * plugin.dash: add tests and fix a couple of bugs found in testing * stream.dash: add some tests to cover the DASHStream classes * WIP: audio only streams * add some debugging for threads and remove the thread joins * dash: startNumber should default to 1 * dash: follow redirects to get the base url * dash: fix bool parser, and segment template parser * dash: fixed some issues... ...with some segment templates, as well as improving the presentation delay handling * dash: add a back-off for checking for manifest changes * dash: fix broken tests * dash: incomplete support for Segment@r * dash: fixed audio/video sync issue Added a `copyts` option to the FFMPEG muxer class so that the timestamps given in the source files are maintained, this appears to fix the a/v sync issues. NB. The timestamp can get weird, but that's how it is :) * dash: support for Time _and_ Number in segment timeline * tests: add some dash parser tests + a little refactor * tests: add dash to built in plugins * tests: more coverage of dash_parser Added a new module for tests, `freezegun`, for mocking time. * dash: fix for missing publishTime * dash: update available_at times to be datetime This should fix any timezone or leap-second issues, etc. * fixed timing issue for 1tv.ru * dash: fix availability timeline for segment timeline * dash: flake8 tweaks * dash: add a few debug logging messages
2018-05-30 21:30:38 +02:00
assert segment_urls == [
("http://test/dash/150633-video_eng=194000.dash", expected_availability),
("http://test/dash/150633-video_eng=194000-0.dash", expected_availability),
("http://test/dash/150633-video_eng=194000-2000.dash", expected_availability),
("http://test/dash/150633-video_eng=194000-4000.dash", expected_availability),
]
def test_segment_list(self):
with xml("dash/test_segment_list.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test/", url="http://test/manifest.mpd")
segments = mpd.periods[0].adaptationSets[0].representations[0].segments()
segment_urls = [(segment.url, segment.available_at) for segment in itertools.islice(segments, 4)]
# ignores period start time in static manifests
expected_availability = datetime.datetime(2020, 1, 1, 0, 0, 0, tzinfo=UTC)
assert segment_urls == [
("http://test/chunk_ctvideo_ridp0va0br4332748_cinit_mpd.m4s", expected_availability),
("http://test/chunk_ctvideo_ridp0va0br4332748_cn1_mpd.m4s", expected_availability),
("http://test/chunk_ctvideo_ridp0va0br4332748_cn2_mpd.m4s", expected_availability),
("http://test/chunk_ctvideo_ridp0va0br4332748_cn3_mpd.m4s", expected_availability),
]
def test_dynamic_timeline_continued(self):
with xml("dash/test_dynamic_timeline_continued_p1.mpd") as mpd_xml_p1:
mpd_p1 = MPD(mpd_xml_p1, base_url="http://test/", url="http://test/manifest.mpd")
iter_segment_p1 = mpd_p1.periods[0].adaptationSets[0].representations[0].segments()
segments_p1 = [
(segment.url, segment.number, segment.available_at)
for segment in itertools.islice(iter_segment_p1, 100)
]
assert segments_p1 == [
("http://test/video/init.mp4", None, datetime.datetime(2018, 1, 1, 1, 0, 0, tzinfo=UTC)),
("http://test/video/1006000.mp4", 7, datetime.datetime(2018, 1, 1, 12, 59, 56, tzinfo=UTC)),
("http://test/video/1007000.mp4", 8, datetime.datetime(2018, 1, 1, 12, 59, 57, tzinfo=UTC)),
("http://test/video/1008000.mp4", 9, datetime.datetime(2018, 1, 1, 12, 59, 58, tzinfo=UTC)),
("http://test/video/1009000.mp4", 10, datetime.datetime(2018, 1, 1, 12, 59, 59, tzinfo=UTC)),
("http://test/video/1010000.mp4", 11, datetime.datetime(2018, 1, 1, 13, 0, 0, tzinfo=UTC)),
]
# continue with the next manifest
with xml("dash/test_dynamic_timeline_continued_p2.mpd") as mpd_xml_p2:
mpd_p2 = MPD(mpd_xml_p2, base_url=mpd_p1.base_url, url=mpd_p1.url, timelines=mpd_p1.timelines)
iter_segment_p2 = mpd_p2.periods[0].adaptationSets[0].representations[0].segments(init=False)
segments_p2 = [
(segment.url, segment.number, segment.available_at)
for segment in itertools.islice(iter_segment_p2, 100)
]
assert segments_p2 == [
("http://test/video/1011000.mp4", 7, datetime.datetime(2018, 1, 1, 13, 0, 1, tzinfo=UTC)),
("http://test/video/1012000.mp4", 8, datetime.datetime(2018, 1, 1, 13, 0, 2, tzinfo=UTC)),
("http://test/video/1013000.mp4", 9, datetime.datetime(2018, 1, 1, 13, 0, 3, tzinfo=UTC)),
("http://test/video/1014000.mp4", 10, datetime.datetime(2018, 1, 1, 13, 0, 4, tzinfo=UTC)),
("http://test/video/1015000.mp4", 11, datetime.datetime(2018, 1, 1, 13, 0, 5, tzinfo=UTC)),
]
def test_tsegment_t_is_none_1895(self):
"""
Verify the fix for https://github.com/streamlink/streamlink/issues/1895
"""
with xml("dash/test_8.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test.se/", url="http://test.se/manifest.mpd")
segments = mpd.periods[0].adaptationSets[0].representations[0].segments()
init_segment = next(segments)
2023-02-16 00:51:25 +01:00
assert init_segment.url == "http://test.se/video-2799000-0.mp4?z32=CENSORED_SESSION"
video_segments = [x.url for x in itertools.islice(segments, 3)]
2023-02-16 00:51:25 +01:00
assert video_segments == [
"http://test.se/video-time=0-2799000-0.m4s?z32=CENSORED_SESSION",
"http://test.se/video-time=4000-2799000-0.m4s?z32=CENSORED_SESSION",
"http://test.se/video-time=8000-2799000-0.m4s?z32=CENSORED_SESSION",
]
2018-08-06 12:18:26 +02:00
def test_bitrate_rounded(self):
def mock_rep(bandwidth):
node = Mock(
tag="Representation",
attrib={
"id": "test",
"bandwidth": bandwidth,
"mimeType": "video/mp4",
},
)
node.findall.return_value = []
root = Mock()
root.parent = None
period = Mock()
period.parent = root
aset = Mock()
aset.parent = period
return Representation(node, root=root, parent=aset, period=period)
2018-08-06 12:18:26 +02:00
2023-02-16 00:51:25 +01:00
assert mock_rep(1.2 * 1000.0).bandwidth_rounded == pytest.approx(1.2)
assert mock_rep(45.6 * 1000.0).bandwidth_rounded == pytest.approx(46.0)
assert mock_rep(134.0 * 1000.0).bandwidth_rounded == pytest.approx(130.0)
assert mock_rep(1324.0 * 1000.0).bandwidth_rounded == pytest.approx(1300.0)
def test_duplicated_resolutions(self):
"""
Verify the fix for https://github.com/streamlink/streamlink/issues/3365
"""
with xml("dash/test_10.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test.se/", url="http://test.se/manifest.mpd")
representations_0 = mpd.periods[0].adaptationSets[0].representations[0]
2023-02-16 00:51:25 +01:00
assert representations_0.height == 804
assert representations_0.bandwidth == pytest.approx(10000.0)
representations_1 = mpd.periods[0].adaptationSets[0].representations[1]
2023-02-16 00:51:25 +01:00
assert representations_1.height == 804
assert representations_1.bandwidth == pytest.approx(8000.0)
stream.dash: Fix static playlist - refresh_wait - Pipe copy aborted - Read timeout - set `refresh_wait` for static playlists to default 5 seconds for this example the `refresh_wait` time was set to 204.32 seconds which would result in some unexpected behavior. - Fix for not correct closing streamlink process - Fix for Pipe copy aborted - Read timeout `--player-no-close` must be used now https://streamlink.github.io/cli.html#cmdoption-player-no-close ``` $ streamlink https://vimeo.com/176894130 --stream-type dash -o test.mp4 -l debug [cli][info] Found matching plugin vimeo for URL https://vimeo.com/176894130 [stream.dash][debug] Opening DASH reader for: video-574992937 (video/mp4) [stream.dash][debug] Opening DASH reader for: audio-574992933 (audio/mp4) [stream.dash_manifest][debug] Generating segment timeline for static playlist (id=video-574992937)) [stream.dash_manifest][debug] Generating segment timeline for static playlist (id=audio-574992933)) [stream.ffmpegmux][debug] ffmpeg command: /usr/bin/ffmpeg -nostats -y -i /tmp/ffmpeg-114055-652 -i /tmp/ffmpeg-114055-914 -c:v copy -c:a copy -copyts -f matroska pipe:1 [stream.ffmpegmux][debug] Starting copy to pipe: /tmp/ffmpeg-114055-652 [stream.ffmpegmux][debug] Starting copy to pipe: /tmp/ffmpeg-114055-914 [cli][debug] Pre-buffering 8192 bytes [stream.dash][debug] Download of segment: segment-0.mp4 complete [stream.dash][debug] Download of segment: segment-0.mp4 complete [cli][debug] Checking file output [cli][debug] Writing stream to output [download][test.mp4] Written 72.6 MB [stream.dash][debug] Download of segment: segment-34.m4s complete [stream.dash][debug] Download of segment: segment-34.m4s complete [stream.segmented][debug] Closing writer thread [stream.ffmpegmux][debug] Pipe copy complete: /tmp/ffmpeg-114055-914 [stream.ffmpegmux][debug] Pipe copy complete: /tmp/ffmpeg-114055-652 [stream.ffmpegmux][debug] Closing ffmpeg thread [stream.ffmpegmux][debug] Closed all the substreams [cli][info] Stream ended [cli][info] Closing currently open stream... ```
2020-12-25 12:05:10 +01:00
def test_segments_static_periods_duration(self):
"""
Verify the fix for https://github.com/streamlink/streamlink/issues/2873
"""
with xml("dash/test_11_static.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test.se/", url="http://test.se/manifest.mpd")
duration = mpd.periods[0].duration.total_seconds()
2023-02-16 00:51:25 +01:00
assert duration == pytest.approx(204.32)
def test_segments_byterange(self):
with xml("dash/test_segments_byterange.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test/", url="http://test/manifest.mpd")
segment_urls = [
[
(seg.url, seg.init, seg.byterange)
for seg in adaptationset.representations[0].segments()
]
for adaptationset in mpd.periods[0].adaptationSets
]
assert segment_urls == [
[
("http://test/video-frag.mp4", True, (36, 711)),
("http://test/video-frag.mp4", False, (747, 875371)),
("http://test/video-frag.mp4", False, (876118, 590796)),
("http://test/video-frag.mp4", False, (1466914, 487041)),
("http://test/video-frag.mp4", False, (1953955, 40698)),
],
[
("http://test/audio-frag.mp4", True, (32, 592)),
("http://test/audio-frag.mp4", False, (624, 123576)),
("http://test/audio-frag.mp4", False, (124200, 126104)),
("http://test/audio-frag.mp4", False, (250304, 124062)),
("http://test/audio-frag.mp4", False, (374366, 471)),
],
]
def test_nested_baseurls(self):
with xml("dash/test_nested_baseurls.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="https://foo/", url="https://test/manifest.mpd")
segment_urls = [
[(segment.url, segment.available_at) for segment in itertools.islice(representation.segments(), 2)]
for adaptationset in mpd.periods[0].adaptationSets for representation in adaptationset.representations
]
# ignores period start time in static manifests
expected_availability = datetime.datetime(2020, 1, 1, 0, 0, 0, tzinfo=UTC)
assert segment_urls == [
[
("https://hostname/period/init_video_5000kbps.m4s", expected_availability),
("https://hostname/period/media_video_5000kbps-1.m4s", expected_availability),
],
[
("https://hostname/period/representation/init_video_9000kbps.m4s", expected_availability),
("https://hostname/period/representation/media_video_9000kbps-1.m4s", expected_availability),
],
[
("https://hostname/period/adaptationset/init_audio_128kbps.m4s", expected_availability),
("https://hostname/period/adaptationset/media_audio_128kbps-1.m4s", expected_availability),
],
[
("https://hostname/period/adaptationset/representation/init_audio_256kbps.m4s", expected_availability),
("https://hostname/period/adaptationset/representation/media_audio_256kbps-1.m4s", expected_availability),
],
[
("https://other/init_audio_320kbps.m4s", expected_availability),
("https://other/media_audio_320kbps-1.m4s", expected_availability),
],
]
def test_timeline_ids(self):
with xml("dash/test_timeline_ids.mpd") as mpd_xml, \
freeze_time("2000-01-01T00:00:00Z"):
mpd = MPD(mpd_xml, base_url="http://test/", url="http://test/manifest.mpd")
segment_urls = [
[
segment.url
for segment in itertools.islice(representation.segments(), 3)
]
for adaptationset in mpd.periods[0].adaptationSets for representation in adaptationset.representations
]
assert segment_urls == [
[
"http://test/audio1/init.mp4",
"http://test/audio1/t0.m4s",
"http://test/audio1/t1.m4s",
],
[
"http://test/audio2/init.mp4",
"http://test/audio2/t0.m4s",
"http://test/audio2/t1.m4s",
],
[
"http://test/video1/init.mp4",
"http://test/video1/t0.m4s",
"http://test/video1/t1.m4s",
],
[
"http://test/video2/init.mp4",
"http://test/video2/t0.m4s",
"http://test/video2/t1.m4s",
],
]
assert list(mpd.timelines.keys()) == [
("period-0", "0", "audio1"),
("period-0", "0", "audio2"),
("period-0", None, "video1"),
("period-0", None, "video2"),
]
def test_get_representation(self):
with xml("dash/test_timeline_ids.mpd") as mpd_xml:
mpd = MPD(mpd_xml, base_url="http://test/", url="http://test/manifest.mpd")
assert mpd.get_representation((None, None, "unknown")) is None
assert mpd.get_representation((None, None, "audio1")) is None
assert mpd.get_representation((None, "0", "audio1")) is None
assert mpd.get_representation(("period-0", None, "audio1")) is None
2023-03-24 14:22:33 +01:00
assert getattr(mpd.get_representation(("period-0", "0", "audio1")), "mimeType", None) == "audio/mp4"
assert getattr(mpd.get_representation(("period-0", "0", "audio2")), "mimeType", None) == "audio/mp4"
assert getattr(mpd.get_representation(("period-0", None, "video1")), "mimeType", None) == "video/mp4"
assert getattr(mpd.get_representation(("period-0", None, "video2")), "mimeType", None) == "video/mp4"