AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Fairplay Apple

Ein Thema von Peter666 · begonnen am 31. Jul 2021 · letzter Beitrag vom 18. Aug 2021
Antwort Antwort
Peter666

Registriert seit: 11. Aug 2007
339 Beiträge
 
#1

Fairplay Apple

  Alt 31. Jul 2021, 22:34
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:
- (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;
}
Peter
  Mit Zitat antworten Zitat
CHackbart

Registriert seit: 22. Okt 2012
247 Beiträge
 
#2

AW: Fairplay Apple

  Alt 5. Aug 2021, 13:27
Hallo,

ich glaube das geht so nicht. Hier ist etwas dazu geschrieben:
https://medium.com/@burak.oguz/ios-f...s-8aff3d4248dd

Im Prinzip müsstest so etwas machen:

Delphi-Quellcode:
 
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;
Unter IOS geht das glaube ich auch, aber erst wenn du die Fehlenden Interfaces aus der MacApi.AVFoundation kopiert hast.
  Mit Zitat antworten Zitat
CHackbart

Registriert seit: 22. Okt 2012
247 Beiträge
 
#3

AW: Fairplay Apple

  Alt 5. Aug 2021, 14:31
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

procedure contentKeySession(session: AVContentKeySession; keyRequest: AVPersistableContentKeyRequest); overload; cdecl; 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?

Delphi-Quellcode:
 
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;
Das andere Problem ist ein SigSev 6 sobald man das asset übergibt. Aber das liegt eher an der Testimplementierung hier.
  Mit Zitat antworten Zitat
Peter666

Registriert seit: 11. Aug 2007
339 Beiträge
 
#4

AW: Fairplay Apple

  Alt 18. Aug 2021, 10:07
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
  Mit Zitat antworten Zitat
CHackbart

Registriert seit: 22. Okt 2012
247 Beiträge
 
#5

AW: Fairplay Apple

  Alt 18. Aug 2021, 20:55
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:
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;
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: https://en.delphipraxis.net/topic/53...layer-and-drm/

Christian
Miniaturansicht angehängter Grafiken
1629312582588.jpg  
Angehängte Dateien
Dateityp: zip UFairplay.pas.zip (3,4 KB, 1x aufgerufen)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:05 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf