Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widevine stream not working #213

Open
el-gringo opened this issue Sep 30, 2024 · 10 comments
Open

Widevine stream not working #213

el-gringo opened this issue Sep 30, 2024 · 10 comments

Comments

@el-gringo
Copy link

el-gringo commented Sep 30, 2024

I have generated a Widevine stream with shaka-packager but it is not working when served with livesim2. The player start playing the content but no deciphering happens, I have a black screen.

The VOD stream works through a basic HTTP server.

Here is how I generated the stream, the video comes from the livesim content testpic4_8s :

docker run -v $PWD:/media google/shaka-packager packager \
  'in=/media/V300.mp4,stream=video,init_segment=/media/V300/init.mp4,segment_template=/media/V300/$Time$.m4s,drm_label=SD' \
  --generate_static_live_mpd \
  --allow_approximate_segment_timeline \
  --segment_duration 8 \
  --enable_widevine_encryption \
  --protection_systems widevine \
  --content_id 5832d59081a4fa6a28da2c7ffa5e2aaa \
  --key_server_url https://license.uat.widevine.com/cenc/getcontentkey/widevine_test \
  --signer widevine_test \
  --aes_signing_key 1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9 \
  --aes_signing_iv d58ce954203b7c9a9a9d467f59839249 \
  --mpd_output "/media/live.mpd" \
  --hls_master_playlist_output "/media/live.m3u8"

The difference between the initialization files is in the mvex box, the mehd box is not in the stream served by livesim2.
livesim2-widevine.tar.gz

@tobbee
Copy link
Contributor

tobbee commented Oct 1, 2024

@el-gringo Thanks for your input. The mehd box describes the asset's duration and should only be there for VoD, so its absence from livesim2 is expected. I'll take a look once I get time.

@tobbee
Copy link
Contributor

tobbee commented Oct 2, 2024

@el-gringo I tried to generate an input asset following your recipe.
When running livesim2 with that asset it reported that it couldn't handle it at startup:

{"time":"2024-10-02T08:17:05.726916+02:00","level":"WARN","msg":"Asset loading problem. Skipping","asset":"enc/live.mpd","err":"no SegmentTemplate in adaptation set"}
{"time":"2024-10-02T08:17:05.726967+02:00","level":"WARN","msg":"Asset consolidation problem. Skipping","error":"setReferenceRep: no video or audio representation found"}

Do you see the same type of message?

If properly parsed you should be able to see the asset as a VoD on the landing page http://localhost:8888 under the VoD list. It was empty for me.

The parsing problems have nothing to do with the DRM, but with the structure of the MPD being in a form that livesim2 cannot handle.

The generated MPD (72s long from nine 8s segments) looked like

<?xml version="1.0" encoding="UTF-8"?>
<!--Generated with https://github.com/shaka-project/shaka-packager version v3.2.0-53b8668-debug-->
<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" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT72S">
  <Period id="0">
    <AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="15360/512" segmentAlignment="true" par="16:9">
      <ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="59e82dc3-3771-5fc0-9e52-f0e84f13534d"/>
      <ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
        <cenc:pssh>AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABgiEFgy1ZCBpPpqKNosf/peKqpI49yVmwY=</cenc:pssh>
      </ContentProtection>
      <Representation id="0" bandwidth="308820" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
        <SegmentTemplate timescale="15360" initialization="V300/init.mp4" media="V300/$Time$.m4s" startNumber="1">
          <SegmentTimeline>
            <S t="0" d="122880" r="8"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>

There core of the issue for livesim2 is that the SegmentTemplate is inside a Representation. This is allowed, but in principle this could lead to cases where different representations in the same adaptation set has different segment templates, so to avoid that can of worms, livesim2 only handes MPDs with SegmentTemplate on the AdaptationSet level. By manually rewriting the MPD as

<?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" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT72S">
  <Period id="0">
    <AdaptationSet id="0" contentType="video" mimeType="video/mp4" width="640" height="360" frameRate="15360/512" segmentAlignment="true" par="16:9">
      <ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="59e82dc3-3771-5fc0-9e52-f0e84f13534d"/>
      <ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
        <cenc:pssh>AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABgiEFgy1ZCBpPpqKNosf/peKqpI49yVmwY=</cenc:pssh>
      </ContentProtection>
      <SegmentTemplate timescale="15360" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/$Time$.m4s" startNumber="1">
          <SegmentTimeline>
            <S t="0" d="122880" r="8"/>
          </SegmentTimeline>
      </SegmentTemplate>
      <Representation id="V300" bandwidth="308820" codecs="avc1.64001e"  sar="1:1"/>
    </AdaptationSet>
  </Period>
</MPD>

As you can see, I have moved the SegmentTemplate outside of the Representation and given the Representation the id V300.

This issue has been discussed before in #204, where I motivated why I don't think it is worth the effort to try to support this placement of SegmentTemplate. I also made an issue #205 on documenting how to prepare content for livesim2. I should probably spend some time on that, since these issues keep popping up.

Can you rewrite your MPD in a similar way and see if it is properly parsed and working after that rewrite?

@el-gringo
Copy link
Author

Sorry, I did not specified that I patch the manifest to make it work in livesim2.

I can see the asset in the VoD list.

Here is the output for my widevine stream :

$ ./start-home.sh | grep widevine
time=2024-10-02T15:56:47.718+02:00 level=INFO msg=asset widevine=repID 0="Init segment already encrypted"
time=2024-10-02T15:56:47.769+02:00 level=INFO msg="asset MPD loaded" asset=assets/widevine mpdName=assets/widevine/live.mpd
time=2024-10-02T15:56:47.822+02:00 level=INFO msg="Asset consolidated" asset=assets/widevine loopDurMS=3600000
time=2024-10-02T15:56:47.822+02:00 level=INFO msg="Available MPD" assetPath=assets/widevine mpdName=live.mpd

Here is the patch I apply after shaka-packager

from xml.dom.minidom import parse, parseString

document = parse('live.mpd')
adaptation_set_elements = document.getElementsByTagName("AdaptationSet")
for adaptation_set_element in adaptation_set_elements:
  representation_elements = adaptation_set_element.getElementsByTagName('Representation')
  for index, representation_element in enumerate(representation_elements):
    segment_templates = representation_element.getElementsByTagName('SegmentTemplate')
    if len(segment_templates) == 0:
        continue
    segment_template_element = segment_templates[0]
    if index == 0:
        adaptation_set_element.appendChild(segment_template_element)
    else:
        representation_element.removeChild(segment_template_element)

with open('live.mpd', 'w') as out_file:
  document.writexml(out_file)

@tobbee
Copy link
Contributor

tobbee commented Oct 2, 2024

OK. After I wrote my comment, I wondered how you came to compare the init segments, since you must have been able to access it via livesim2 server.

Your script doesn't change the SegmentTemplate to use RepresentationID, but that should be no problem as long as there is only one representation in every AdaptationSet.

Regarding the content, I looked a bit further and there are some extra stuff:

One particular thing with the Shaka-packager output segments is that the first segment is not encrypted. This is for fast startup for VoD, but is not a good idea when looping a sequence. A peculiar thing is then that the init segment has two sample descriptor boxes in stsd. An [encv] box for the encrypted segments and an [avc1] box for the unencrypted.
This also leads to two different sampleDescriptionIndexes depending on encryption or not. I will check if that is supported in livesim2. In general, it would be best if all segments are encrypted. I think there should be a setting in shaka-packager for that??

Another small detail I saw is that there is a sidx box in each segment. It is almost without value for a one-segment file, but it contains timestamps that must either be updated or the whole box removed. I'll check that as well.

@tobbee
Copy link
Contributor

tobbee commented Oct 2, 2024

The two sample descriptors seems to go through the system. However, the sidx box is not removed or updated so that is a potential player issue. I will remove it.

@el-gringo
Copy link
Author

I realized that the VOD was not working after all. only the first seconds plays.

I was using a wrong content Id. It should be --content_id 7465737420636f6e74656e74206964

Those options in shaka-packager should encrypt from the first segment & remove the sidx boxes

  --clear_lead 0 \
  --nogenerate_sidx_in_media_segments \

The live stream doesn't play though.

@el-gringo
Copy link
Author

I finally got it working !

I had to remove the --nogenerate_sidx_in_media_segments option. I works with the dashif player. But I was trying on the RxPlayer which doesn't work with this stream.

@tobbee
Copy link
Contributor

tobbee commented Oct 2, 2024

Great that you got it working.

Was that with or without sidx boxes in dash.js?

Does the RxPlayer work with the VoD stream, but not from livesim2?

In general, I'd rather remove the sidx boxes than update them. They are useful for dash-on demand profile where one wants to find a subsegment byte-range, but for single-segment files they don't carry any information that cannot be extracted from the other boxes in the moof box.

@el-gringo
Copy link
Author

I finally made it work with RxPlayer & Shaka too. I surely made a mistake in the URL.

I let shaka-packager generate the sidx boxes as it seems to not work without them.

But now it is not working anymore even if I set back values that used to work. The VoD stream still works.

@tobbee
Copy link
Contributor

tobbee commented Oct 2, 2024

The sidx boxes out of livesim2 are erroneous since their timestamps are not updated to reflect the time since 1970. Most sources don't have any sidx boxes inside segments, so it is really strange that you seem to need them.

Please make more trials without the sidx boxes. One can also change livesim2 to remove any sidx boxes, but if a player needs them (with correct values) it would be interesting to know.

dash.js and shaka-player do not need these sidx boxes. I've never used RxPlayer, but it seems strange that it should be dependent on sidx boxes.

There is of course a possibility that using there is some side-effect in Shaka-packager when turning on the --nosidx_in_segments flag.

Btw, I wrote a Wiki-page on content preparation at https://github.com/Dash-Industry-Forum/livesim2/wiki/Preparing-Content-for-livesim2 If you have any comments, please drop me a line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants