You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
487 lines
11 KiB
487 lines
11 KiB
#include "UniversalMediaPlayer.h"
|
|
|
|
@implementation UniversalMediaPlayer
|
|
|
|
- (id)init
|
|
{
|
|
if (self = [super init])
|
|
{
|
|
_playerStates = [NSMutableArray array];
|
|
_cachedVolume = -1;
|
|
_cachedRate = -1;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)setupPlayer:(NSString *)options
|
|
{
|
|
options = [options stringByReplacingOccurrencesOfString:@":" withString:@""];
|
|
NSArray *optionsArray = [options componentsSeparatedByString:@"\n"];
|
|
_playerType = FFmpeg;
|
|
|
|
for(NSString *option in optionsArray)
|
|
{
|
|
NSArray *optionData = [option componentsSeparatedByString:@"="];
|
|
|
|
if ([optionData[0] isEqual: @"player-type"])
|
|
_playerType = (PlayerTypes)[optionData[1] integerValue];
|
|
}
|
|
|
|
#if NATIVE
|
|
if (_playerType == Native)
|
|
_player = [[PlayerNative alloc] init];
|
|
#endif
|
|
|
|
#if FFMPEG
|
|
if (_playerType == FFmpeg)
|
|
_player = [[PlayerFFmpeg alloc] init];
|
|
#endif
|
|
|
|
[self setupAudioSession];
|
|
[_player setupPlayer:optionsArray];
|
|
_player.delegate = self;
|
|
}
|
|
|
|
- (void)setupAudioSession
|
|
{
|
|
NSError *categoryError = nil;
|
|
BOOL success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&categoryError];
|
|
if (!success)
|
|
{
|
|
NSLog(@"Error setting audio session category: %@", categoryError);
|
|
}
|
|
|
|
NSError *activeError = nil;
|
|
success = [[AVAudioSession sharedInstance] setActive:YES error:&activeError];
|
|
if (!success)
|
|
{
|
|
NSLog(@"Error setting audio session active: %@", activeError);
|
|
}
|
|
}
|
|
|
|
- (int)getFramesCounter
|
|
{
|
|
return [_player getFramesCounter];
|
|
}
|
|
|
|
- (CMVideoSampling*)getVideoSampling
|
|
{
|
|
return &_videoSampling;
|
|
}
|
|
|
|
- (CVPixelBufferRef)getPixelBuffer
|
|
{
|
|
return [_player getPixelBuffer];
|
|
}
|
|
|
|
- (void)setDataSource:(NSString *)path
|
|
{
|
|
[_player setDataSource:path];
|
|
}
|
|
|
|
- (void)play
|
|
{
|
|
if (_videoSampling.cvTextureCache == nil)
|
|
CMVideoSampling_Initialize(&_videoSampling);
|
|
|
|
[_player play];
|
|
}
|
|
|
|
- (void)pause
|
|
{
|
|
[_player pause];
|
|
}
|
|
|
|
- (void)stop
|
|
{
|
|
if (_player != nil)
|
|
{
|
|
_cachedVolume = [_player getVolume];
|
|
_cachedRate = [_player getPlaybackRate];
|
|
|
|
[_player stop];
|
|
CMVideoSampling_Uninitialize(&_videoSampling);
|
|
}
|
|
}
|
|
|
|
- (int)getDuration
|
|
{
|
|
return [_player getDuration];
|
|
}
|
|
|
|
- (int)getVolume
|
|
{
|
|
return [self isReady] ? [_player getVolume] : _cachedVolume;
|
|
}
|
|
|
|
- (void)setVolume:(int)value
|
|
{
|
|
if ([self isReady])
|
|
[_player setVolume:value];
|
|
else
|
|
_cachedVolume = value;
|
|
}
|
|
|
|
- (int)getTime
|
|
{
|
|
return [_player getTime];
|
|
}
|
|
|
|
- (void)setTime:(int)value
|
|
{
|
|
[_player setTime:value];
|
|
}
|
|
|
|
- (float)getPosition
|
|
{
|
|
return [_player getPosition];
|
|
}
|
|
|
|
- (void)setPosition:(float)value
|
|
{
|
|
[_player setPosition:value];
|
|
}
|
|
|
|
- (float)getPlaybackRate
|
|
{
|
|
return [self isReady] ? [_player getPlaybackRate] : _cachedRate;
|
|
}
|
|
|
|
- (void)setPlaybackRate:(float)value
|
|
{
|
|
if ([self isReady])
|
|
[_player setPlaybackRate:value];
|
|
else
|
|
_cachedRate = value;
|
|
}
|
|
|
|
- (bool)isPlaying
|
|
{
|
|
return [_player isPlaying];
|
|
}
|
|
|
|
- (bool)isReady
|
|
{
|
|
return [_player isReady];
|
|
}
|
|
|
|
- (int)getVideoWidth
|
|
{
|
|
return [_player getVideoWidth];
|
|
}
|
|
|
|
- (int)getVideoHeight
|
|
{
|
|
return [_player getVideoHeight];
|
|
}
|
|
|
|
- (void)mediaPlayerStateChanged:(PlayerState*)state
|
|
{
|
|
[_playerStates queuePush:state];
|
|
}
|
|
|
|
@end
|
|
|
|
static std::vector<UniversalMediaPlayer*> _players;
|
|
|
|
static NSString* CreateNSString(const char* string)
|
|
{
|
|
if (string != NULL)
|
|
return [NSString stringWithUTF8String:string];
|
|
else
|
|
return [NSString stringWithUTF8String:""];
|
|
}
|
|
|
|
intptr_t CMVideoSampling_SampleBuffer(CMVideoSampling* sampling, CVImageBufferRef pixelBuffer)
|
|
{
|
|
intptr_t retTex = 0;
|
|
|
|
if (sampling->cvImageBuffer)
|
|
CFRelease(sampling->cvImageBuffer);
|
|
|
|
sampling->cvImageBuffer = pixelBuffer;
|
|
CFRetain(sampling->cvImageBuffer);
|
|
|
|
int w = (int)CVPixelBufferGetWidth((CVImageBufferRef)sampling->cvImageBuffer);
|
|
int h = (int)CVPixelBufferGetHeight((CVImageBufferRef)sampling->cvImageBuffer);
|
|
if (sampling->cvTextureCacheTexture)
|
|
{
|
|
CFRelease(sampling->cvTextureCacheTexture);
|
|
FlushCVTextureCache(sampling->cvTextureCache);
|
|
}
|
|
|
|
#if BGRA32
|
|
sampling->cvTextureCacheTexture = CreateBGRA32TextureFromCVTextureCache(sampling->cvTextureCache, sampling->cvImageBuffer, w, h);
|
|
#else
|
|
sampling->cvTextureCacheTexture = CreateTextureFromCVTextureCache(sampling->cvTextureCache, sampling->cvImageBuffer, w, h);
|
|
#endif
|
|
|
|
if (sampling->cvTextureCacheTexture)
|
|
retTex = GetTextureFromCVTextureCache(sampling->cvTextureCacheTexture);
|
|
|
|
if (UnitySelectedRenderingAPI() == apiOpenGLES2 || UnitySelectedRenderingAPI() == apiOpenGLES3)
|
|
{
|
|
GLint oldTexBinding = 0;
|
|
|
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexBinding);
|
|
glBindTexture(GL_TEXTURE_2D, (GLuint)retTex);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glBindTexture(GL_TEXTURE_2D, oldTexBinding);
|
|
}
|
|
|
|
return retTex;
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
int UMPNativeInit()
|
|
{
|
|
_players.push_back([[UniversalMediaPlayer alloc] init]);
|
|
return (int)_players.size();
|
|
}
|
|
|
|
void UMPNativeInitPlayer(int index, char *options)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
NSString *optionsString = CreateNSString(options);
|
|
[player setupPlayer:optionsString];
|
|
}
|
|
|
|
int UMPGetBufferingPercentage()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
intptr_t UMPNativeGetTexturePointer(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
CMVideoSampling* sampling = [player getVideoSampling];
|
|
intptr_t texture = CMVideoSampling_LastSampledTexture(sampling);
|
|
|
|
if (player.playerType == Native || texture == 0)
|
|
{
|
|
CVPixelBufferRef pixelBuffer = [player getPixelBuffer];
|
|
if (pixelBuffer != nil)
|
|
texture = CMVideoSampling_SampleBuffer(sampling, pixelBuffer);
|
|
}
|
|
|
|
return texture;
|
|
}
|
|
|
|
void UMPNativeUpdateTexture(int index, intptr_t texture) {}
|
|
|
|
void UMPNativeSetPixelsBuffer(int index, unsigned char *buffer, int width, int height)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
player.frameBuffer = buffer;
|
|
}
|
|
|
|
void UMPNativeUpdateFrameBuffer(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
if (kCVReturnSuccess == CVPixelBufferLockBaseAddress([player getPixelBuffer], kCVPixelBufferLock_ReadOnly))
|
|
{
|
|
unsigned char *tmpBuffer = (uint8_t*)CVPixelBufferGetBaseAddress([player getPixelBuffer]);
|
|
memcpy(player.frameBuffer, tmpBuffer, player.getVideoWidth * player.getVideoHeight * 4);
|
|
CVPixelBufferUnlockBaseAddress([player getPixelBuffer], kCVPixelBufferLock_ReadOnly);
|
|
}
|
|
}
|
|
|
|
void UMPSetDataSource(int index, char *path)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
NSString *pathString = CreateNSString(path);
|
|
[player setDataSource:pathString];
|
|
}
|
|
|
|
bool UMPPlay(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
[player play];
|
|
return true;
|
|
}
|
|
|
|
void UMPPause(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
[player pause];
|
|
}
|
|
|
|
void UMPStop(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
[player stop];
|
|
}
|
|
|
|
void UMPRelease(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
[player stop];
|
|
}
|
|
|
|
bool UMPIsPlaying(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
return [player isPlaying];
|
|
}
|
|
|
|
bool UMPIsReady(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
return [player isReady];
|
|
}
|
|
|
|
int UMPGetLength(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
return [player getDuration];
|
|
}
|
|
|
|
int UMPGetTime(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
return [player getTime];
|
|
}
|
|
|
|
void UMPSetTime(int index, int time)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
[player setTime:time];
|
|
}
|
|
|
|
float UMPGetPosition(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
return [player getPosition];
|
|
}
|
|
|
|
void UMPSetPosition(int index, float position)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
[player setPosition:position];
|
|
}
|
|
|
|
float UMPGetRate(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
return [player getPlaybackRate];
|
|
}
|
|
|
|
void UMPSetRate(int index, float rate)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
if (rate != player.getPlaybackRate)
|
|
[player setPlaybackRate:rate];
|
|
}
|
|
|
|
int UMPGetVolume(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
return [player getVolume];
|
|
}
|
|
|
|
void UMPSetVolume(int index, int value)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
[player setVolume:value];
|
|
}
|
|
|
|
bool UMPGetMute(int index)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void UMPSetMute(int index, bool state)
|
|
{
|
|
}
|
|
|
|
int UMPVideoWidth(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
return [player getVideoWidth];
|
|
}
|
|
|
|
int UMPVideoHeight(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
return [player getVideoHeight];
|
|
}
|
|
|
|
long UMPVideoFrameCount(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
if ([player isReady])
|
|
{
|
|
if (player.cachedVolume >= 0)
|
|
{
|
|
[player setVolume:player.cachedVolume];
|
|
player.cachedVolume = -1;
|
|
}
|
|
|
|
if (player.cachedRate >= 0)
|
|
{
|
|
[player setPlaybackRate:player.cachedRate];
|
|
player.cachedRate = -1;
|
|
}
|
|
}
|
|
|
|
return [player getFramesCounter];
|
|
}
|
|
|
|
int UMPGetState(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
|
|
if (player.playerStates.count > 0)
|
|
{
|
|
player.playerState = player.playerStates.queuePop;
|
|
return player.playerState.state;
|
|
}
|
|
|
|
return Empty;
|
|
}
|
|
|
|
float UMPGetStateFloatValue(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
return player.playerState.valueFloat;
|
|
}
|
|
|
|
long UMPGetStateLongValue(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
return player.playerState.valueLong;
|
|
}
|
|
|
|
char* UMPGetStateStringValue(int index)
|
|
{
|
|
UniversalMediaPlayer *player = _players.at(index - 1);
|
|
return player.playerState.valueString;
|
|
}
|
|
}
|