macOS Video Player
From Free Pascal wiki
Revision as of 05:51, 3 November 2021 by Trev (talk | contribs) (→Example code: Basic video player)
This article applies to macOS only.
See also: Multiplatform Programming Guide
Overview
AVPlayer vs AVAudioPlayer
For audio, ...
Example code
unit Unit1;
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$linkframework AvKit}
{$linkframework AVFoundation}
// Enable/Disbale DEBUGGING
//{$define DEBUG}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
CTypes,
MacOSAll,
{$ifdef DEBUG}
CocoaUtils,
{$endif}
CocoaAll;
type
{ TForm1 }
TForm1 = class(TForm)
ResumeButton: TButton;
PauseButton: TButton;
PlayButton: TButton;
QuitButton: TButton;
procedure PauseButtonClick(Sender: TObject);
procedure PlayButtonClick(Sender: TObject);
procedure QuitButtonClick(Sender: TObject);
procedure ResumeButtonClick(Sender: TObject);
private
public
end;
AVPlayerStatus = NSInteger;
AVPlayerItemStatus = NSInteger;
AVKeyValueStatus = NSInteger;
CMTimeValue = cint64;
CMTimeValuePtr = ^CMTimeValue;
CMTimeScale = cint32;
CMTimeScalePtr = ^CMTimeScale;
CMTimeEpoch = cint64;
CMTimeEpochPtr = ^CMTimeEpoch;
CMTimeFlags = cuint32;
CMTimeFlagsPtr = ^CMTimeFlags;
CMTime = record
value: CMTimeValue;
timescale: CMTimeScale;
flags: CMTimeFlags;
epoch: CMTimeEpoch;
end;
AVAsynchronousKeyValueLoadingProtocol = objcprotocol external name 'AVAsynchronousKeyValueLoading' required
function statusOfValueForKey_error (key: NSString; outError: NSErrorPtr): AVKeyValueStatus;
message 'statusOfValueForKey:error:';
procedure loadValuesAsynchronouslyForKeys_completionHandler (keys: NSArray; handler: OpaqueCBlock);
message 'loadValuesAsynchronouslyForKeys:completionHandler:';
end;
AVAsset = objcclass external (NSObject, NSCopyingProtocol, AVAsynchronousKeyValueLoadingProtocol)
private
_asset: id; //AVAssetInternal;
public
class function assetWithURL (URL: NSURL): id; message 'assetWithURL:';
function duration: CMTime; message 'duration';
function preferredRate: single; message 'preferredRate';
function preferredVolume: single; message 'preferredVolume';
function preferredTransform: CGAffineTransform; message 'preferredTransform';
function naturalSize: CGSize; message 'naturalSize';
{ Adopted protocols }
function copyWithZone (mzone: NSZonePtr): id; message 'copyWithZone:';
procedure loadValuesAsynchronouslyForKeys_completionHandler (keys: NSArray; handler: OpaqueCBlock);
message 'loadValuesAsynchronouslyForKeys:completionHandler:';
function statusOfValueForKey_error (mkey: NSString; outError: NSErrorPtr): AVKeyValueStatus;
message 'statusOfValueForKey:error:';
end;
AVPlayerItem = objcclass external (NSObject, NSCopyingProtocol)
private
_playerItem: id; //AVPlayerItemInternal;
public
class function playerItemWithURL (URL: NSURL): AVPlayerItem; message 'playerItemWithURL:';
class function playerItemWithAsset (asset: AVAsset): AVPlayerItem; message 'playerItemWithAsset:';
class function playerItemWithAsset_automaticallyLoadedAssetKeys (asset: AVAsset; automaticallyLoadedAssetKeys: NSArray): AVPlayerItem;
message 'playerItemWithAsset:automaticallyLoadedAssetKeys:'; { available in 10_9, 7_0 }
function initWithURL (URL: NSURL): id; message 'initWithURL:';
function initWithAsset (asset: AVAsset): id; message 'initWithAsset:';
function initWithAsset_automaticallyLoadedAssetKeys (asset: AVAsset; automaticallyLoadedAssetKeys: NSArray): id;
message 'initWithAsset:automaticallyLoadedAssetKeys:'; { available in 10_9, 7_0 }
function status: AVPlayerItemStatus; message 'status';
function error: NSError; message 'error';
{ Adopted protocols }
function copyWithZone (mzone: NSZonePtr): id; message 'copyWithZone:';
end;
AVPlayer = objcclass external (NSObject)
private
_player: id; //AVPlayerInternal;
public
class function playerWithURL (URL: NSURL): id; message 'playerWithURL:';
class function playerWithPlayerItem (item: AVPlayerItem): id; message 'playerWithPlayerItem:';
function initWithURL (URL: NSURL): id; message 'initWithURL:';
function initWithPlayerItem (item: AVPlayerItem): id; message 'initWithPlayerItem:';
function status: AVPlayerStatus; message 'status';
function error: NSError; message 'error';
procedure setVolume(newValue: Single); message 'setVolume:';
end;
AVURLAsset = objcclass external (AVAsset)
private
_URLAsset: id; //AVURLAssetInternal;
public
class function audiovisualTypes: NSArray; message 'audiovisualTypes'; { available in 10_7, 5_0 }
class function audiovisualMIMETypes: NSArray; message 'audiovisualMIMETypes'; { available in 10_7, 5_0 }
class function isPlayableExtendedMIMEType (extendedMIMEType: NSString): ObjCBOOL;
message 'isPlayableExtendedMIMEType:'; { available in 10_7, 5_0 }
class function URLAssetWithURL_options (URL: NSURL; options: NSDictionary): AVURLAsset;
message 'URLAssetWithURL:options:';
function initWithURL_options (URL: NSURL; options: NSDictionary): id;
message 'initWithURL:options:';
function URL: NSURL; message 'URL';
end;
AVPlayerPlaybackControl = objccategory external (AVPlayer)
procedure setRate(newValue: single); message 'setRate:';
function rate: single; message 'rate';
procedure play; message 'play';
procedure pause; message 'pause';
end;
AVPlayerLayer = objcclass external (CALayer)
private
_playerLayer: id; //AVPlayerLayerInternal;
public
class function playerLayerWithPlayer (player: AVPlayer): AVPlayerLayer;
message 'playerLayerWithPlayer:';
procedure setPlayer(newValue: AVPlayer); message 'setPlayer:';
function player: AVPlayer; message 'player';
procedure setVideoGravity(newValue: NSString); message 'setVideoGravity:';
function videoGravity: NSString; message 'videoGravity';
function isReadyForDisplay: ObjCBOOL; message 'isReadyForDisplay';
function videoRect: CGRect; message 'videoRect';
end;
const
AVPlayerStatusUnknown = 0;
AVPlayerStatusReadyToPlay = 1;
AVPlayerStatusFailed = 2;
AVPlayerItemStatusUnknown = 0;
AVPlayerItemStatusReadyToPlay = 1;
AVPlayerItemStatusFailed = 2;
var
Form1: TForm1;
myPlayer: AVPlayer = Nil;
myAsset: AVAsset = Nil;
myPlayerItem: AVPlayerItem = Nil;
myPlayerLayer: AVPlayerLayer = Nil;
myURL: NSUrl = Nil;
myView: NSView = Nil;
implementation
{$R *.lfm}
{ TForm1 }
//
// Play video or audio asset
//
procedure TForm1.PlayButtonClick(Sender: TObject);
begin
//
// 1. Create a URL
//
myURL := NSURL.URLWithString(NSSTR(PAnsiChar('https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_ts/master.m3u8')));
//myURL := NSURL.fileURLWithPath(NSStr(PAnsiChar('/Users/trev/alt.mp4')));
if(myURL = Nil) then
begin
ShowMessage('myURL creation failed!');
exit;
end;
//
// 2. Create AVAsset, AVPlayerItem and AVPlayer objects
//
myAsset := AVAsset.alloc.assetWithURL(myURL);
myPlayerItem := AVPlayerItem.alloc.initWithAsset(myAsset);
myPlayer := AVPlayer.alloc.initWithPlayerItem(myPlayerItem);
// Wait until status is known (while loading AVAsset)
while(myPlayer.Status = AVPlayerStatusUnknown)
do
application.processmessages;
{$ifdef DEBUG}
// Status information for debugginh
if(myPlayer.Status = AVPlayerStatusFailed) then
ShowMessage('AVplayer status: failed')
else if(myPlayer.Status = AVPlayerStatusReadyToPlay) then
ShowMessage('AVplayer status: ready to play');
{$endif}
//
// 3. Create PlayerLayer to display video
//
myPlayerLayer := AVPlayerLayer.playerLayerWithPlayer(myPlayer);
// enable resizing on the fly
myPlayerLayer.setVideoGravity(NSStr('AVLayerVideoGravityResizeAspect'));
myPlayerLayer.setAutoresizingMask(kCALayerHeightSizable or kCALayerWidthSizable);
// setup border color and border width
myPlayerLayer.setBorderWidth(3);
myPlayerLayer.setBorderColor(NSColor.yellowColor.cgColor);
// Make visible by adding PlayerLayer to Form1 View
myView := NSView(Form1.Handle);
myView.layer.addSublayer(myPlayerLayer);
// Setup video frame size and bounds
myPlayerLayer.setFrame(CGRectMake(0, 0, myView.frame.size.width, myView.frame.size.height - 100));
myPlayerLayer.setBounds(CGRectMake(0, 0, myView.frame.size.width, myView.frame.size.height - 100));
{$ifdef DEBUG}
// Status Information for debugging
ShowMessage('Frame Height: ' + FloatToStr(myView.frame.size.height) + LineEnding
+ 'Frame Width : ' + FloatToStr(myView.frame.size.width) + LineEnding
+ 'Video gravity: ' + NSStringToString(myPlayerLayer.videoGravity) + LineEnding
+ 'Needs display (layer): ' + BoolToStr(myPlayerLayer.needsDisplay) + LineEnding);
if(myPlayerLayer.isReadyForDisplay) then
ShowMessage('PlayerLayer: Ready for display')
else
ShowMessage('PlayerLayer: Not ready for display');
{$endif}
//
// 4. Play
//
myPlayer.setRate(1); // play normal speed
myPlayer.setVolume(0.5); // 50% volume
myPlayer.play;
end;
//
// Pause playback
//
procedure TForm1.PauseButtonClick(Sender: TObject);
begin
myPlayer.pause;
end;
//
// Resume playback
//
procedure TForm1.ResumeButtonClick(Sender: TObject);
begin
myPlayer.play;
end;
//
// Quit player
//
procedure TForm1.QuitButtonClick(Sender: TObject);
begin
Close;
end;
end.
See also
- macOS Audio Player
- macOS Audio Recorder
- macOS MIDI Player
- macOS NSSound
- macOS Sound Utilities
- System Sound Services
- Multimedia Programming
External links
- t/c