![]() |
Fairplay Apple
Hi,
ich versuche gerade den Alcinoe Player unter IOS mit DRM Streams zu verwenden. Soweit ich das ganze verstanden habe, muss ich ein AVURLAsset erstellen in dem ein Callback für die Ressource hinterlegt wird. Hat jemand ungefähr eine Idee wie ich das umsetzen kann? Der ObjectiveC Code schaut wie folgt aus.
Code:
Peter
- (void)loadPlayerView
{ NSURL *url = [NSURL URLWithString:@"https://nyoba.innoplayer.co/cdn/videos/fairplay/muxed/encrypted/prog_index.m3u8"]; AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil]; [asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()]; AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:[AVPlayerItem playerItemWithAsset:asset]]; AVPlayerViewController *controller = [[AVPlayerViewController alloc] init]; controller.player = player; [self presentViewController:controller animated:YES completion:nil]; } - (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest { NSString *keyURL = @"https://nyoba.innoplayer.co/cdn/videos/fairplay/muxed/encrypted/Key.txt"; NSURL *urlx = [NSURL URLWithString:keyURL]; NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:urlx]; [urlRequest setTimeoutInterval:20]; [urlRequest setHTTPMethod:@"GET"]; NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; NSLog(@"requestHLSKeyWithURL httpResponse ==== %ld", (long)httpResponse.statusCode); if (data != nil && (httpResponse.statusCode == 200 || httpResponse.statusCode == 100)) { NSLog(@"requestHLSKeyWithURL data ==== %@", data); [[loadingRequest contentInformationRequest] setContentType:AVStreamingKeyDeliveryPersistentContentKeyType]; [[loadingRequest contentInformationRequest] setByteRangeAccessSupported:YES]; [[loadingRequest contentInformationRequest] setContentLength:[data length]]; [[loadingRequest dataRequest] respondWithData:data]; [loadingRequest finishLoading]; } else { NSLog(@"requestHLSKeyWithURL ==== NOT OK"); [loadingRequest finishLoading]; } }]; [task resume]; return YES; } |
AW: Fairplay Apple
Hallo,
ich glaube das geht so nicht. Hier ist etwas dazu geschrieben: ![]() Im Prinzip müsstest so etwas machen:
Delphi-Quellcode:
Unter IOS geht das glaube ich auch, aber erst wenn du die Fehlenden Interfaces aus der MacApi.AVFoundation kopiert hast.type TContentKeyDelegate = class(TOCLocal, AVContentKeySessionDelegate) public procedure contentKeySession(session: AVContentKeySession; persistableContentKey: NSData; keyIdentifier: Pointer); overload; cdecl; procedure contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest; err: NSError); overload; cdecl; function contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest; retryReason: AVContentKeyRequestRetryReason): Boolean; overload; cdecl; procedure contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest); overload; cdecl; procedure contentKeySession(session: AVContentKeySession; keyRequest: AVPersistableContentKeyRequest); overload; cdecl; procedure contentKeySessionContentKeyRequestDidSucceed (session: AVContentKeySession; keyRequest: AVContentKeyRequest); cdecl; procedure contentKeySessionContentProtectionSessionIdentifierDidChange (session: AVContentKeySession); cdecl; procedure contentKeySessionDidGenerateExpiredSessionReport (session: AVContentKeySession); cdecl; procedure contentKeySessionDidProvideRenewingContentKeyRequest (session: AVContentKeySession; keyRequest: AVContentKeyRequest); cdecl; end; TContentKeyManager = class private FContentKeySession: AVContentKeySession; FContentKeyDelegate: TContentKeyDelegate; FContentKeyDelegateQueue: dispatch_queue_t; public constructor Create; destructor Destroy; override; function IsAvailable: Boolean; property ContentKeySession: AVContentKeySession read FContentKeySession; end; ... constructor TContentKeyManager.Create; begin FContentKeySession := TAVContentKeySession.Wrap (TAVContentKeySession.OCClass.contentKeySessionWithKeySystem (AVContentKeySystemFairPlayStreaming)); FContentKeyDelegate := TContentKeyDelegate.Create; FContentKeyDelegateQueue := dispatch_queue_create('fairplay.ContentKeyDelegateQueue', dispatch_queue_t(DISPATCH_QUEUE_SERIAL)); FContentKeySession.setDelegate(FContentKeyDelegate.GetObjectID, FContentKeyDelegateQueue); end; |
AW: Fairplay Apple
Nachtrag,
du musst dann bei der Wiedergabe dein AVUrlAsset zu deiner AVContentKeySession via addContentKeyRecipient übergeben. Zumindest in der Theorie. In der Praxis gibt es 2 Probleme: Wenn ich
Delphi-Quellcode:
in AVContentKeySessionDelegate behalte, crasht die Anwendung sobald ich FContentKeyDelegate := TContentKeyDelegate.Create; ausführe. Ich habe keine Ahnung woran das liegen kann, ist eventuell ein Bug. Vielleicht kann das ja jemand reproduzieren?
procedure contentKeySession(session: AVContentKeySession; keyRequest: AVPersistableContentKeyRequest); overload; cdecl;
Delphi-Quellcode:
Das andere Problem ist ein SigSev 6 sobald man das asset übergibt. Aber das liegt eher an der Testimplementierung hier.type AVContentKeySessionDelegate = interface(IObjectiveC) ['{3066C8DB-B31C-4339-A49D-912BA193660C}'] procedure contentKeySession(session: AVContentKeySession; persistableContentKey: NSData; keyIdentifier: Pointer); overload; cdecl; procedure contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest; err: NSError); overload; cdecl; function contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest; retryReason: AVContentKeyRequestRetryReason): Boolean; overload; cdecl; procedure contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest); overload; cdecl; procedure contentKeySession(session: AVContentKeySession; keyRequest: AVPersistableContentKeyRequest); overload; cdecl; procedure contentKeySessionContentKeyRequestDidSucceed(session: AVContentKeySession; keyRequest: AVContentKeyRequest); cdecl; procedure contentKeySessionContentProtectionSessionIdentifierDidChange(session: AVContentKeySession); cdecl; procedure contentKeySessionDidGenerateExpiredSessionReport(session: AVContentKeySession); cdecl; procedure contentKeySessionDidProvideRenewingContentKeyRequest(session: AVContentKeySession; keyRequest: AVContentKeyRequest); cdecl; end; TContentKeyDelegate = class(TOCLocal, AVContentKeySessionDelegate) public procedure contentKeySession(session: AVContentKeySession; persistableContentKey: NSData; keyIdentifier: Pointer); overload; cdecl; procedure contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest; err: NSError); overload; cdecl; function contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest; retryReason: AVContentKeyRequestRetryReason): Boolean; overload; cdecl; procedure contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest); overload; cdecl; procedure contentKeySession(session: AVContentKeySession; keyRequest: AVPersistableContentKeyRequest); overload; cdecl; procedure contentKeySessionContentKeyRequestDidSucceed (session: AVContentKeySession; keyRequest: AVContentKeyRequest); cdecl; procedure contentKeySessionContentProtectionSessionIdentifierDidChange (session: AVContentKeySession); cdecl; procedure contentKeySessionDidGenerateExpiredSessionReport (session: AVContentKeySession); cdecl; procedure contentKeySessionDidProvideRenewingContentKeyRequest (session: AVContentKeySession; keyRequest: AVContentKeyRequest); cdecl; end; { TContentKeyDelegate } procedure TContentKeyDelegate.contentKeySession(session: AVContentKeySession; persistableContentKey: NSData; keyIdentifier: Pointer); begin end; procedure TContentKeyDelegate.contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest; err: NSError); begin end; function TContentKeyDelegate.contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest; retryReason: AVContentKeyRequestRetryReason): Boolean; begin result := false; end; procedure TContentKeyDelegate.contentKeySession(session: AVContentKeySession; keyRequest: AVContentKeyRequest); begin end; procedure TContentKeyDelegate.contentKeySession(session: AVContentKeySession; keyRequest: AVPersistableContentKeyRequest); begin end; procedure TContentKeyDelegate.contentKeySessionContentKeyRequestDidSucceed (session: AVContentKeySession; keyRequest: AVContentKeyRequest); begin end; procedure TContentKeyDelegate. contentKeySessionContentProtectionSessionIdentifierDidChange (session: AVContentKeySession); begin end; procedure TContentKeyDelegate.contentKeySessionDidGenerateExpiredSessionReport (session: AVContentKeySession); begin end; procedure TContentKeyDelegate. contentKeySessionDidProvideRenewingContentKeyRequest (session: AVContentKeySession; keyRequest: AVContentKeyRequest); begin end; ... FContentKeyDelegate := TContentKeyDelegate.Create; |
AW: Fairplay Apple
Ich hab das ganze immer noch nicht zum Laufen bekommen und das ganze auch mit einer älteren Delphiversion probiert. Vielleicht hat ja jemand noch eine Idee?
Peter |
AW: Fairplay Apple
Liste der Anhänge anzeigen (Anzahl: 2)
Klar,
anbei der Code zum Hinzufügen von DRM Infos an den AVPlayer. Ich dachte, ich hab dir das schon via PM zugesandt. Damit du DRM geschützte Inhalte lesen kannst musst du noch den Player anpassen. Für FMX.Media.Mac.pas sieht das so aus:
Delphi-Quellcode:
Die ContentManager Klasse hat zwei Callbacks die implementiert werden müssen. Zum einen musst du das Zertifikat als TMemoryStream liefern und danach den Request für den Contentkey an deinen Server liefern und das Ergebnis, dann zurück an Fairplay geben. Das funktioniert auf MacOS und iOS. Im englischsprachigen Bereich von Delphi-Praxis steht einiges darüber hier:
constructor TMacMedia.Create(const AFileName: string);
var LURL: NSUrl; LAbsoluteFileName: string; LAsset: AVURLAsset; begin inherited Create(AFileName); AVMediaTypeAudio; // Force load the framework if FileExists(FileName) then begin if ExtractFilePath(FileName).IsEmpty then LAbsoluteFileName := TPath.Combine(TPath.GetHomePath, FileName) else LAbsoluteFileName := FileName; LURL := TNSUrl.Wrap(TNSUrl.OCClass.fileURLWithPath(StrToNSStr(LAbsoluteFileName))); end else LURL := StrToNSUrl(FileName); if LURL = nil then raise EFileNotFoundException.Create(SSpecifiedFileNotFound); FPixelBufferBitmap := TBitmap.Create; LAsset := TAVURLAsset.Wrap(TAVURLAsset.OCClass.URLAssetWithURL(LURL, nil)); if LAsset.hasProtectedContent then ContentKeyManager.addContentKeyRecipient(LAsset); FPlayerItem := TAVPlayerItem.Wrap(TAVPlayerItem.OCClass.playerItemWithAsset(LAsset)); FPlayerItem.retain; FPlayer := TAVPlayer.Wrap(TAVPlayer.OCClass.playerWithPlayerItem(FPlayerItem)); FPlayer.retain; FPlayerLayer := TAVPlayerLayer.Wrap(TAVPlayerLayer.OCClass.playerLayerWithPlayer(FPlayer)); FPlayerLayer.retain; FPlayerLayer.setVideoGravity(CocoaNSStringConst(libAVFoundation, 'AVLayerVideoGravityResizeAspectFill')); FPlayerLayer.setAutoresizingMask(kCALayerWidthSizable or kCALayerHeightSizable); FVideoView := TNSView.Create; FVideoView.retain; FVideoView.setWantsLayer(True); FVideoView.layer.addSublayer(FPlayerLayer); SetupVideoOutput; end; ![]() Christian |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:19 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz