GNOME Bugzilla – Bug 761700
basedrm: a base class based on CENC common encryption scheme for DRM playback
Last modified: 2018-11-03 13:46:12 UTC
Created attachment 320610 [details] [review] basedrm patch short_description: Base class for DRM using ISOBMFF CENC common encryption and 'piff' (PSSH box) Common encryption (CENC) in ISO base media file format files (ISOBMFF) ISO/IEC 23001-7 standard Common encryption (CENC) of MPEG-2 transport streams (MPEG-2 TS) ISO/IEC 23001-9 standard This basedrm class does license management and other common activities to enable DRM management systems to decrypt the encrypted audio / video samples. The subclass is responsible for providing pad template caps for source and sink pads. The pads need to be named "sink" and "src". DRM subsystem should do in place decryption so that input and output buffer are same. gstbasedrm class will not implement any default methods therefore all necessary methods required for DRM management should be implemented by derived class. We have developed and tested this plugin in STMicroelectronics for DRM playback on our HW platform. This class has been tested on STB platform using latest gstreamer baseline for DASH / MSS and HLS streaming playback of PlayReady protected data. gstreamer patches for CENC support in gstreamer for MSS and HLS (in mpegts ) have been developed in ST for CENC encrypted PlayReady streams. This BaseDRM class has also been tested using clear key DRM in native gstreamer with CENC encrypted DASH streams with clearkey mechanism.
The clear key DRM has also been developed in STMicroelectronics
Very interesting! You mention that it has been tested with CENC encrypted PlayReady streams. Is it possible for you to provide some unit tests to complement the new code? Thanks!
Hi Luis, we have tested basedrm class for CENC encrypted playready streams for DASH, MSS and HLS. we have developed playready drm plugin using basedrm class and playready library but because of the license terms of the commercial DRM solution we use, we can't give the code of the playready plugin. we need to look for some alternative way of unit testing. BR/ Rajesh
Hi Luis, we have also developed clear key DRM plugin using basedrm class. This plugin uses OPENSSL library available in native gstreamer. The streams for clear key drm have been created using BENTO4 tools. This plugin seems to be good for doing unit testing of basedrm class in native gstreamer. could you pl. provide your view about using this plugin for unit testing. BR/ Rajesh
Yes a ClearKey decryptor would be interesting to have I think. Maybe keep it internal for unit-tests purpose though? BTW for WebKit I have done some similar work: https://bugs.webkit.org/show_bug.cgi?id=154235
thanks for quick response ... I will provide the clear key drm patch within one or two weeks.. should I open new bugzilla for clear key drm ?
(In reply to Rajesh from comment #6) > thanks for quick response ... > I will provide the clear key drm patch within one or two weeks.. > > should I open new bugzilla for clear key drm ? IMHO this could be a new patch attached to this bug.
ok, I will attach another patch for clear key DRM.
Created attachment 322347 [details] [review] clear key drm patch This is clear key DRM (ckdrm) patch. ckdrm is clear key DRM plugin and derived from basedrm class. this plugin can be used for testing of basedrm class and also validating the gstreamer data flow of protected stream (clear key). The license acquisition URL i.e license server is embedded in the PSSH box in clear key stream. Testing would require the clear key streams to be hosted on some http server, which can also be used as license server for these streams. BR/ Rajesh
Hi Philippe, I have a clear key stream for testing of this ckdrm (and basedrm) plugin. could you pl. tell me that how can I submit this stream for testing and where it will be hosted. BR/ Rajesh
There is some infrastructure code in -bad/tests/check to set-up a fake http server, that's used by the adaptivedemux implementations tests.
Created attachment 330703 [details] [review] basedrm patch basedrm patch aligned to master branch
Created attachment 330704 [details] [review] clear key drm patch clearkey drm patch aligned to master branch
(In reply to Philippe Normand from comment #11) > There is some infrastructure code in -bad/tests/check to set-up a fake http > server, that's used by the adaptivedemux implementations tests. Hi Philippe, I checked in "-bad/tests/check" and found code for unit testing of dash demux and some other elements. I want to add test case for basedrm & ckdrm using gst-play (full decrypt / decode pipeline). we have been testing these plugins inside ST with gst-play and using http server on our own m/c. I could not understand from unit test of dash demux that how can I create fake http server which can be used by gst-play as uri. BR/ Rajesh
> > I could not understand from unit test of dash demux that how can I create > fake http server which can be used by gst-play as uri. > > BR/ > Rajesh You will have to create an app, rather than use a command line tool like gst-play. You use gst_test_http_src_register_plugin() to cause the fake HTTP source element to be installed. It is given a very high rank so will be picked in preference to souphttpsrc. That means any HTTP request from gstreamer will be served by this fake source element. You then use gst_test_http_src_install_callbacks() to install a couple of functions that handle every request for an HTTP source. You could then use playbin with a URI. That URI will turn up in the src_start() callback you registered with gst_test_http_src_install_callbacks(). The src-create() callback will be called, which is used to feed the fake data into the pipeline.
Hi Ashley, Thanks for this suggestion. I will work on this and update asap. BR/ Rajesh
Review of attachment 330703 [details] [review]: Having a library that only appears if you have some library installed, maybe we could use GstURIDownloader instead? Also, your code has a undeclared dep on libxml2. I see HTTP SOAP requests and parsing of an XML file, what spec are those from? Can you add that to the doc at the top? I know PlayReady uses SOAP, but do Widevine, Marlin, etc? Also you put stubs for all the functions, you may want to not put a stub for the functions that really need to be implemented, and instead if g_assert() on their presence. ::: gst-libs/gst/basedrm/gstbasedrm.c @@ +293,3 @@ + drm_license_info->response_length = 0; + + proxy = g_getenv ("http_proxy"); This is not standard. LibSoup should just get the proxy config for you. Otherwise, if you insist on a "manual", add a "proxy" property like souphttpsrc. @@ +458,3 @@ + gst_structure_remove_field (fields, field_name); + } + } Same here, you can just do gst_structure_remove_fields(fields, "base-profile", "codec_data", ..., NULL); @@ +511,3 @@ + gst_structure_get_string (out, "original-media-type")); + + /* filter out the DRM related fields from the down-stream caps */ Comment is upside down.. the DRM fields are in the upstream caps (upstraem is towards the source).. @@ +520,3 @@ + g_str_has_prefix (field_name, "original-media-type")) { + gst_structure_remove_field (out, field_name); + } The whole for() loop can be replace with gst_structure_remove_fields(in, "protection-system", "original-media-type", NULL); @@ +1057,3 @@ + GST_DEBUG_OBJECT (basedrm, "event carries pssh data from qtdemux"); + ret = gst_basedrm_parse_pssh_box (basedrm, pssi); + } else if (g_str_has_prefix (loc, "smooth-streaming")) { In many places where you use g_str_has_prefix() you probably just can !strcmp() instead.
Review of attachment 330704 [details] [review]: The W3C ClearKey spec seems to mandate using some kind of JSON format and not SOAP https://w3c.github.io/encrypted-media/ I would just drop the SOAP bits from the base class and move that to the subclasses.. Potentially even move the whole HTTP processing to the subclasses, it seems very DRM system specific. If possible, it would also be nice if we could have the ClearKey implementation under a more liberal license (like BSD), so that other people can use it as a starting point to integrate real DRM systems. ::: ext/ckdrm/gstckdrm.c @@ +350,3 @@ + if (!gst_aesctr_decrypt_ip (ckdrm->drm_handle, decrypt_info->data, + decrypt_info->data_size)) { + GST_ERROR_OBJECT (ckdrm, "Failed to decrypt"); Use GST_ELEMENT_ERROR() to also post a ERROR GstMessage on the bus. Same thing everywhere else where you do GST_ERROR_OBJECT(), you should use GST_ELEMENT_ERROR instead @@ +483,3 @@ + } + + memcpy (url, ckdrm->license_url, ckdrm->license_url_length); Can't use just do g_strndup() like you did earlier?
Any update? We also need this.
I really like the idea and I think it's the right approach and I appreciate the effort of submitting the proposal. I'm not going to review it in details though (I'd have some comments) because I think there are major design problems. First of all, as some have already mentioned, it's PlayReady specific. I'd even say that it's actually PlayReady SDK specific. Each DRM system has its own specification(s) and everyone can implement every aspect of it on their own and go through a certification process. But let's face it: hardly anyone wants to do that and rather "reference" libraries (SDKs) are used. So what we are dealing with here are really various aspects of different DRMs and "blessed" SDKs. * no key rotation support You seem to have been dealing with PlayReady WRM licenses of version < 4.1 which do not support multiple keys and binding a license means the only key is set up automatically. But CENC supports a different KID for each sample, which may or may not change on every buffer/sample. In the Clear Key implementation you have an attempt to at least support separate KIDs for audio and video but each track may have rotating keys. Thereby, a base class should provide KID information for each buffer/subsample, something like `void (*load_key)(GstBaseDrm * basedrm, GBytes * key, GBytes * iv)`. * different DRM (SDKs) deal with license acquisition and decryption differently PlayReady requires a client app to participate in license acquisition and to make requests to a license server. The PlayReady SDK only deals with the header, challenge, response, ack. and ack. response. Also PlayReady SDK handles decryption. On a contrary, Marlin SDK for example does the entire license acquisition internally and require a client app to do the decryption. The decryption bit is not a big problem as there's a separate `decrypt()` method proposed so the implementing classes can be built with or without accelerated decryption implemented inside or outside DRM SDK, as required. The license acquisition bit could be something like `bool (*acquire_license) (GstBaseDrm * basedrm, GBytes * license_info, GBytes * default_key_id)` where the implementation of the base class needs to handle `license_info` specific to the implemented DRM system (SDK). * no DME scatter-gather support Again, the "block offset" approch seems PlayReady specific but some implementations may want to use scatter-gather approach and need to know when the base class is done with the sample, so for example: `void (*decrypt) (GstBaseDrm * basedrm, guint8 * data, gsize size)` and `void (*decrypt_finish)(GstBaseDrm * basedrm)`. * this is CENC specific The proposal is for `GstBaseDrm` but it should be rather something like `GstBaseCencDec` as it's not universal enought to represent any DRM system, although I'd like to also see support for example for Marlin MPEG-2 TS which requires additional signalling. * CENC for MPEG-2 TS support I don't know much about CENC specifically in the context of MPEG-2 TS but I don't see how this proposal supports that directly without additional elements upstream in a pipeline doing MPEG-2 TS parsing, handling additional signalling and decorating outgoing buffers with `GstProtectionMeta`. Presumabely there needs to be an element to reassembles PES and decorate each AU with `GstProtectionMeta`? I wonder then what role of `GstBaseDrm` would be if MPEG-2 TS processing (filtering/signalling and decoding) is hardware assisted. Not to mention other DRM SDKs like Marlin one which may handle MPEG-2 TS (PAT, PMT and ECM) signalling and ECM parsing internally.
Yes. As decryption maybe processed on media container, PES in MPEG-2 TS or video ES slice data, which module should responsible for TS or video ES parsing before decryption. I notice the DRM plugin input and output caps is video ES stream. So seems the DRM SDK should responsible for video ES parsing. Is it right? But video decoder will do those kind of video ES parsing, so it is duplicate effort. How to balance those video ES parsing loading?
You state: "Marlin SDK for example does the entire license acquisition internally" As license acquisition need access socket. Maybe has problem on Android platform which need authority for socket access. Application has the authority, but DRM plugin maybe haven't the authority.
> So seems the DRM SDK should responsible for video ES parsing. Is it right? But > video decoder will do those kind of video ES parsing, so it is duplicate > effort. How to balance those video ES parsing loading? In this case only ECM PID needs to be parsed so there's no duplication of effort if a GStreamer element does that. DRM SDK in this case is merely responsible for providing ECM PID based on information in PAT/PMT (as this may be DRM specific) and for the actual ECM _payload_ parsing (not ES parsing). In this situation it's GStreamer element feeding DRM SDK with PAT/PMT and ECM payloads. The situation is different if decryption needs to be done in the H/W as well and in case of MPEG-TS usually demuxing already happens in H/W. It's a bit tricky as ECM signalling must be aligned with what's in demuxer's buffer as the stream is far from being framed, so not visible really in GStreamer pipeline. In this case H/W demuxer would need to provide similar PAT/PMT and ECM signalling (with payloads). > As license acquisition need access socket. Maybe has problem on Android > platform which need authority for socket access. Application has the authority, > but DRM plugin maybe haven't the authority. What do you mean by "access socket"? In case of Marlin SDK it's "merely" a TCP socket with all TLS and HTTP(S) done by the SDK. If you think of it as the "authority" to access network then it's a fair point as it's not desired for the DRM part to do much of networking but this is the approach taken by Marlin SDK. PlayReady makes the app responsible for this instead. A matter of choice I guess and trust in the implementation robustness.
-- GitLab Migration Automatic Message -- This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/347.