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

Exoplayer does not play MPEG-DASH + PlayReady contents. #2386

Closed
from-unknown opened this issue Jan 29, 2017 · 7 comments
Closed

Exoplayer does not play MPEG-DASH + PlayReady contents. #2386

from-unknown opened this issue Jan 29, 2017 · 7 comments

Comments

@from-unknown
Copy link

Description

I tried to play MPEG-DASH + PlayReady (actually it was a common encryption media - playready and widevine modular) contents and found that exoplayer could not play it.

Reproduce link

Not available now - I will try to create one if needed.
Manifest file is nearly like this.
Big Buck Bunny

Device

Nexus player (6.1)
Android TV - Sony Bravia (5.1.1)

Possible solution

While debugging this problem, I found that exoplayer did not parse mspr:pro tag in manifest file.
Looking at smooth streaming code, I added code below and then contents played fine.

code (exoplayer 2.X):
DashManifestParser.java

protected SchemeData parseContentProtection(XmlPullParser xpp) throws XmlPullParserException,
      IOException {
    String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri"); // Added
    byte[] data = null;
    UUID uuid = null;
    boolean seenPsshElement = false;
    boolean requiresSecureDecoder = false;
    do {
      xpp.next();
      // The cenc:pssh element is defined in 23001-7:2015.
      if (XmlPullParserUtil.isStartTag(xpp, "cenc:pssh") && xpp.next() == XmlPullParser.TEXT) {
        seenPsshElement = true;
        data = Base64.decode(xpp.getText(), Base64.DEFAULT);
        uuid = PsshAtomUtil.parseUuid(data);
      } else if (XmlPullParserUtil.isStartTag(xpp, "widevine:license")) {
        String robustnessLevel = xpp.getAttributeValue(null, "robustness_level");
        requiresSecureDecoder = robustnessLevel != null && robustnessLevel.startsWith("HW");
      // ----- Add start -----
      } else if (ParserUtil.isStartTag(xpp, "mspr:pro") && xpp.next() == XmlPullParser.TEXT) {
        seenPsshElement = true;
        uuid = UUID.fromString(schemeIdUri.split(":")[2]);
        data = new SchemeInitData(MimeTypes.VIDEO_MP4,
                PsshAtomUtil.buildPsshAtom(uuid,Base64.decode(xpp.getText(), Base64.DEFAULT)));
      }
      // ----- Add end ----- 
    } while (!XmlPullParserUtil.isEndTag(xpp, "ContentProtection"));
    if (!seenPsshElement) {
      return null;
    } else if (uuid != null) {
      return new SchemeData(uuid, MimeTypes.VIDEO_MP4, data, requiresSecureDecoder);
    } else {
      Log.w(TAG, "Skipped unsupported ContentProtection element");
      return null;
    }
}

code (exoplayer 1.X):
MediaPresentationDescriptionParser.java

  protected ContentProtection parseContentProtection(XmlPullParser xpp)
      throws XmlPullParserException, IOException {
    String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri");
    UUID uuid = null;
    SchemeInitData data = null;
    boolean seenPsshElement = false;
    do {
      xpp.next();
      // The cenc:pssh element is defined in 23001-7:2015.
      if (ParserUtil.isStartTag(xpp, "cenc:pssh") && xpp.next() == XmlPullParser.TEXT) {
        seenPsshElement = true;
        data = new SchemeInitData(MimeTypes.VIDEO_MP4,
            Base64.decode(xpp.getText(), Base64.DEFAULT));
        uuid = PsshAtomUtil.parseUuid(data.data);
      }
      // ----- Add start -----
      if (ParserUtil.isStartTag(xpp, "mspr:pro") && xpp.next() == XmlPullParser.TEXT) {
        seenPsshElement = true;
        uuid = UUID.fromString(schemeIdUri.split(":")[2]);
        data = new SchemeInitData(MimeTypes.VIDEO_MP4,
                PsshAtomUtil.buildPsshAtom(uuid,Base64.decode(xpp.getText(), Base64.DEFAULT)));
      }
      // ----- Add end ----- 
    } while (!ParserUtil.isEndTag(xpp, "ContentProtection"));
    if (seenPsshElement && uuid == null) {
      Log.w(TAG, "Skipped unsupported ContentProtection element");
      return null;
    }
    return buildContentProtection(schemeIdUri, uuid, data);
  }

I am not sure that this code is good enough, but at least works at my envelopment.
I hope this code helps solve this issue.

@ojw28
Copy link
Contributor

ojw28 commented Jan 29, 2017

Thanks for reporting this. For the sample manifest I'd expect playback to work due to the presence of cenc:pssh elements. It shouldn't be necessary to look at the mspr:pro elements. According to Microsoft's doc:

In the case of PlayReady, a PlayReady Header Object (PRO) [PRHEADER] can be contained in a
cenc:pssh element, an mspr:pro element, or a ‘pssh’ box to enable license acquisition. The
mspr:pro element is defined by Microsoft PlayReady, and includes only the PRO [PRHEADER]
information, not the box structure included in ‘pssh’ and cenc:pssh. Including both mspr:pro
and cenc:pssh will enable old players including a player based on Silverlight, and new players
including web pages using script to play protected DASH presentations on HTML5 browsers.

Which suggests that "new players" typically look at the cenc:pssh elements only. Could you clarify whether your manifest is missing cenc:pssh elements, and if so why? I think including one is the correct thing to do. If your manifest includes cenc:pssh elements then I think something else is wrong. There's no particular reason why we can't parse mspr:pro elements as well if necessary, but I'd like to make sure we understand exactly what's going on fiest.

@from-unknown
Copy link
Author

Thank you for replying and information, now I understand more about this problem.
I checked manifest file and found that there is a no cenc:pssh element for PlayReady.

Currently I am using bento4 to make a MPEG-DASH file and generated file only have mspr:pro element and no cenc:pssh element for PlayReady.
I think bento4 should have a option to generate cenc:pssh element.
I'm going to check if bento4 is able to do it.

@ojw28
Copy link
Contributor

ojw28 commented Jan 30, 2017

If they don't have an option, you should probably request that they add one (they should probably be including both cenc:pssh and mspr:pro by default as suggested by Microsoft's doc for compatibility with both old and new players.

ojw28 added a commit that referenced this issue Feb 16, 2017
Issue: #2386

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=147725616
@ojw28
Copy link
Contributor

ojw28 commented Feb 16, 2017

The change ref'd above adds support for the mspr:pro element in V2, although I agree they should be including cenc:pssh as well regardless. We have no plans to backport.

@ojw28 ojw28 closed this as completed Feb 16, 2017
@from-unknown
Copy link
Author

Sorry for not replying soon.

First of all, thank you for supporting mspr:pro element.
As far as I read bento4's code, they do not support cenc:pssh.
I'll keep watching bento4.

If you don't mind, would you answer these questions?

  • why do not backport mspr:pro element support?
  • if any suggestions for code which I shared code for exo 1.X, I would like to know

@ojw28
Copy link
Contributor

ojw28 commented Feb 26, 2017

We're pretty much back-porting bug fixes only to V1. This is not a bug fix. There's also not much demand (this is the only issue requesting support for the element), should be fixed on the serving side anyway (by including a cenc:pssh element), and can be resolved by moving to V2.

@from-unknown
Copy link
Author

Ok, I understand.
Thank you for your answer.

@google google locked and limited conversation to collaborators Jun 28, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants