Skip to content

Commit

Permalink
subtitles manager
Browse files Browse the repository at this point in the history
  • Loading branch information
priore committed Mar 21, 2017
1 parent f3fe58c commit 5ef7155
Show file tree
Hide file tree
Showing 25 changed files with 736 additions and 109 deletions.
2 changes: 1 addition & 1 deletion AVPlayerOverlay.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'AVPlayerOverlay'
s.version = '1.5.1'
s.version = '1.6'
s.summary = 'AVPlayer with custom controls and full screen features.'
s.license = 'MIT'
s.ios.platform = '7.1'
Expand Down
12 changes: 11 additions & 1 deletion AVPlayerOverlay.xcodeproj/project.pbxproj
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
9F0C03A41E7B013B00DD60BD /* SubtitlePackage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F0C03A31E7B013B00DD60BD /* SubtitlePackage.m */; };
9F16AFF01CD3E3980082CC15 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F16AFEF1CD3E3980082CC15 /* main.m */; };
9F16AFF31CD3E3980082CC15 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F16AFF21CD3E3980082CC15 /* AppDelegate.m */; };
9F16AFF61CD3E3980082CC15 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F16AFF51CD3E3980082CC15 /* ViewController.m */; };
Expand All @@ -20,6 +21,8 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
9F0C03A21E7B013B00DD60BD /* SubtitlePackage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SubtitlePackage.h; sourceTree = "<group>"; };
9F0C03A31E7B013B00DD60BD /* SubtitlePackage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SubtitlePackage.m; sourceTree = "<group>"; };
9F16AFEB1CD3E3980082CC15 /* AVPlayerOverlay.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AVPlayerOverlay.app; sourceTree = BUILT_PRODUCTS_DIR; };
9F16AFEF1CD3E3980082CC15 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
9F16AFF11CD3E3980082CC15 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -107,6 +110,8 @@
9F16B0071CD3E4D00082CC15 /* AVPlayerOverlayVC.m */,
9F16B00A1CD3E4D00082CC15 /* AVPlayerVC.h */,
9F16B00B1CD3E4D00082CC15 /* AVPlayerVC.m */,
9F0C03A21E7B013B00DD60BD /* SubtitlePackage.h */,
9F0C03A31E7B013B00DD60BD /* SubtitlePackage.m */,
);
path = AVPlayer;
sourceTree = "<group>";
Expand Down Expand Up @@ -137,7 +142,7 @@
9F16AFE31CD3E3980082CC15 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0730;
LastUpgradeCheck = 0820;
ORGANIZATIONNAME = "Danilo Priore";
TargetAttributes = {
9F16AFEA1CD3E3980082CC15 = {
Expand Down Expand Up @@ -187,6 +192,7 @@
9F16B00C1CD3E4D00082CC15 /* AVPlayerOverlayVC.m in Sources */,
9F16AFF31CD3E3980082CC15 /* AppDelegate.m in Sources */,
9F16AFF01CD3E3980082CC15 /* main.m in Sources */,
9F0C03A41E7B013B00DD60BD /* SubtitlePackage.m in Sources */,
9F16B00F1CD3E4D00082CC15 /* AVPlayerVC.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -227,8 +233,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
Expand Down Expand Up @@ -272,8 +280,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
Expand Down
19 changes: 16 additions & 3 deletions AVPlayerOverlay/AVPlayer/AVPlayerOverlayVC.h
Expand Up @@ -4,12 +4,10 @@
// Created by Danilo Priore on 28/04/16.
// Copyright © 2016 Prioregroup.com. All rights reserved.
//
IB_DESIGNABLE

#define AVPlayerOverlayVCFullScreenNotification @"AVPlayerOverlayVCFullScreen"
#define AVPlayerOverlayVCNormalScreenNotification @"AVPlayerOverlayVCNormalScreen"

#import <UIKit/UIKit.h>
@import UIKit;

@class AVPlayer;

Expand All @@ -19,15 +17,18 @@ typedef NS_ENUM(NSInteger, AVPlayerFullscreenAutorotaionMode)
AVPlayerFullscreenAutorotationLandscapeMode
};

IB_DESIGNABLE
@interface AVPlayerOverlayVC : UIViewController

@property (nonatomic, weak) IBOutlet UIView *playerBarView;
@property (nonatomic, weak) IBOutlet UIButton *playButton;
@property (nonatomic, weak) IBOutlet UIButton *playBigButton;
@property (nonatomic, weak) IBOutlet UIButton *volumeButton;
@property (nonatomic, weak) IBOutlet UIButton *fullscreenButton;
@property (nonatomic, weak) IBOutlet UIButton *subtitlesButton;
@property (nonatomic, weak) IBOutlet UISlider *videoSlider;
@property (nonatomic, weak) IBOutlet UISlider *volumeSlider;
@property (nonatomic, weak) IBOutlet UILabel *subtitlesLabel;

@property (nonatomic, weak) AVPlayer *player;

Expand All @@ -43,9 +44,12 @@ typedef NS_ENUM(NSInteger, AVPlayerFullscreenAutorotaionMode)
- (void)showPlayerBar;

- (void)didTapGesture:(id)sender;
- (void)didDoubleTapGesture:(id)sender;
- (void)didPinchGesture:(id)sender;
- (void)didPlayButtonSelected:(id)sender;
- (void)didVolumeButtonSelected:(id)sender;
- (void)didFullscreenButtonSelected:(id)sender;
- (void)didSubtitlesButtonSelected:(id)sender;

- (void)didVolumeSliderValueChanged:(id)sender;

Expand All @@ -58,4 +62,13 @@ typedef NS_ENUM(NSInteger, AVPlayerFullscreenAutorotaionMode)
- (void)willNormalScreenModeToParentViewController:(UIViewController*)parent;
- (void)didNormalScreenModeToParentViewController:(UIViewController*)parent;

- (void)showSubtitles;
- (void)hideSubtitles;
- (void)loadSubtitlesWithURL:(NSURL*)url;

- (NSAttributedString*)attributedSubtitle:(id)subtitle;

- (void)forceDeviceOrientation:(UIInterfaceOrientation)orientation;
- (void)deviceOrientationDidChange:(NSNotification *)notification;

@end
139 changes: 133 additions & 6 deletions AVPlayerOverlay/AVPlayer/AVPlayerOverlayVC.m
Expand Up @@ -5,6 +5,7 @@
// Copyright © 2016 Prioregroup.com. All rights reserved.
//
#import "AVPlayerOverlayVC.h"
#import "SubtitlePackage.h"

@import AVFoundation;
@import MediaPlayer;
Expand All @@ -24,8 +25,13 @@ @interface AVPlayerOverlayVC ()
@property (nonatomic, strong) id timeObserver;
@property (nonatomic, assign) BOOL isVideoSliderMoving;

@property (nonatomic, assign) BOOL hiddenStatusBar;
@property (nonatomic, assign) BOOL hiddenNavBar;

@property (nonatomic, assign) UIDeviceOrientation currentOrientation;

@property (nonatomic, strong) SubtitlePackage *subtitles;

@end

@implementation AVPlayerOverlayVC
Expand Down Expand Up @@ -67,6 +73,11 @@ - (void)viewDidLoad
_playBigButton.layer.borderColor = [UIColor whiteColor].CGColor;
_playBigButton.layer.cornerRadius = _playBigButton.frame.size.width / 2.0;

_subtitlesLabel.hidden = YES;
_subtitlesLabel.numberOfLines = 0;
_subtitlesLabel.contentMode = UIViewContentModeBottom;
_subtitlesLabel.baselineAdjustment = UIBaselineAdjustmentAlignBaselines;

[self videoSliderEnabled:NO];

// actions
Expand All @@ -77,17 +88,28 @@ - (void)viewDidLoad
[_videoSlider addTarget:self action:@selector(didVideoSliderTouchUp:) forControlEvents:UIControlEventTouchUpInside];
[_videoSlider addTarget:self action:@selector(didVideoSliderTouchDown:) forControlEvents:UIControlEventTouchDown];
[_volumeSlider addTarget:self action:@selector(didVolumeSliderValueChanged:) forControlEvents:UIControlEventValueChanged];
[_subtitlesButton addTarget:self action:@selector(didSubtitlesButtonSelected:) forControlEvents:UIControlEventTouchUpInside];

// tap gesture
// tap gesture for hide/show player bar
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapGesture:)];
[self.view addGestureRecognizer:tap];

// double tap gesture for normal and fullscreen
UITapGestureRecognizer *doubleTapGesture=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didDoubleTapGesture:)];
doubleTapGesture.numberOfTapsRequired = 2;
[self.view addGestureRecognizer:doubleTapGesture];

// pinch gesture for normal and fullscreen
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(didPinchGesture:)];
[self.view addGestureRecognizer:pinchGesture];

// device rotation
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];

[self.view layoutIfNeeded];
[self autoHidePlayerBar];

}

- (void)dealloc
Expand Down Expand Up @@ -124,10 +146,17 @@ - (void)setPlayer:(AVPlayer *)player
} else {

__weak typeof(self) wself = self;
self.timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1.0 / 60.0, NSEC_PER_SEC)
self.timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.5, NSEC_PER_SEC)
queue:NULL
usingBlock:^(CMTime time){
[wself updateProgressBar];
if (!wself.subtitlesLabel.hidden && wself.subtitles.subtitleItems.count > 0)
{
NSInteger index = [wself.subtitles indexOfProperSubtitleWithGivenCMTime:time];
IndividualSubtitle *subtitle = wself.subtitles.subtitleItems[index];
wself.subtitlesLabel.attributedText = [wself attributedSubtitle:subtitle];
[wself.subtitlesLabel setNeedsDisplay];
}
}];
_videoSlider.value = 0;
_volumeSlider.value = _player.volume;
Expand Down Expand Up @@ -227,18 +256,29 @@ - (void)showPlayerBar

#pragma mark - Actions

- (void)didTapGesture:(id)sender
- (void)didTapGesture:(UITapGestureRecognizer*)sender
{
if (_playerBarView.hidden)
{
[self showPlayerBar];
}
else if (_volumeSlider.hidden)
{
[self didPlayButtonSelected:sender];
[self didPlayButtonSelected:nil];
}
}

- (void)didDoubleTapGesture:(UITapGestureRecognizer*)sender
{
[self didFullscreenButtonSelected:nil];
}

- (void)didPinchGesture:(UIPinchGestureRecognizer*)sender
{
if ((sender.scale > 1.0 && !_isFullscreen) || (sender.scale <= 1.0 && _isFullscreen))
[self didFullscreenButtonSelected:nil];
}

- (void)didPlayButtonSelected:(id)sender
{
if (_player.currentItem != nil)
Expand Down Expand Up @@ -361,11 +401,21 @@ - (void)didFullscreenButtonSelected:(id)sender
[self autoHidePlayerBar];
}

- (void)didSubtitlesButtonSelected:(id)sender
{
_subtitlesButton.selected = !_subtitlesButton.selected;
if (_subtitlesButton.selected)
[self showSubtitles];
else
[self hideSubtitles];
}

#pragma mark - Overridable Methods

- (void)willFullScreenModeFromParentViewController:(UIViewController*)parent
{
// NOP
_hiddenNavBar = self.navigationController.isNavigationBarHidden;
_hiddenStatusBar = [UIApplication sharedApplication].isStatusBarHidden;
}

- (void)didFullScreenModeFromParentViewController:(UIViewController*)parent
Expand All @@ -381,6 +431,9 @@ - (void)didFullScreenModeFromParentViewController:(UIViewController*)parent
[self forceDeviceOrientation:UIInterfaceOrientationUnknown];
[self forceDeviceOrientation:UIInterfaceOrientationLandscapeRight];
}

[self.navigationController setNavigationBarHidden:YES animated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
}

[[NSNotificationCenter defaultCenter] postNotificationName:AVPlayerOverlayVCFullScreenNotification object:self];
Expand All @@ -390,6 +443,9 @@ - (void)willNormalScreenModeToParentViewController:(UIViewController*)parent
{
if (_autorotationMode == AVPlayerFullscreenAutorotationLandscapeMode)
[self forceDeviceOrientation:UIInterfaceOrientationPortrait];

[[UIApplication sharedApplication] setStatusBarHidden:_hiddenStatusBar withAnimation:UIStatusBarAnimationFade];
[self.navigationController setNavigationBarHidden:_hiddenNavBar animated:YES];
}

- (void)didNormalScreenModeToParentViewController:(UIViewController*)parent
Expand Down Expand Up @@ -450,6 +506,78 @@ - (void)videoSliderEnabled:(BOOL)enabled
}
}

#pragma mark - Subtitles

- (void)showSubtitles
{
_subtitlesLabel.alpha = 0.0;
_subtitlesLabel.hidden = NO;
[UIView animateWithDuration:.25 animations:^{
_subtitlesLabel.alpha = 1.0;
}];
}

- (void)hideSubtitles
{
[UIView animateWithDuration:.25 animations:^{
_subtitlesLabel.alpha = 0.0;
} completion:^(BOOL finished) {
_subtitlesLabel.hidden = YES;
}];
}

- (void)loadSubtitlesWithURL:(NSURL*)url
{
_subtitles = nil;

if (url == nil || _subtitlesButton == nil || _subtitlesLabel == nil)
return;

NSURLSession *session = [NSURLSession sharedSession];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error == nil) {
NSString *context = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
_subtitles = [[SubtitlePackage alloc] initWithContext:context];
}
}];

[task resume];
}

- (NSAttributedString*)attributedSubtitle:(IndividualSubtitle*)subtitle
{
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:_subtitlesLabel.textColor forKey:NSForegroundColorAttributeName];

__block NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:@"" attributes:attrsDictionary];;

NSString *str = [NSString stringWithFormat:@"%@\n%@", subtitle.ChiSubtitle ?: @"", subtitle.EngSubtitle ?: @""];
[str enumerateLinesUsingBlock:^(NSString *line, BOOL *stop)
{
NSError *error;
line = [NSString stringWithFormat:@"<font color=\"#FFFFFF\">%@</font>", line];
NSAttributedString *preview = [[NSAttributedString alloc] initWithData:[line dataUsingEncoding:NSUTF8StringEncoding]
options:options
documentAttributes:nil
error:&error];
[attrString appendAttributedString:preview];

if (line.length)
[attrString appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n" attributes:attrsDictionary]];
}];

NSRange rng = NSMakeRange(0, attrString.length);
NSMutableParagraphStyle *paragraphStyle = NSMutableParagraphStyle.new;
paragraphStyle.alignment = NSTextAlignmentCenter;
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;

[attrString addAttribute:NSFontAttributeName value:_subtitlesLabel.font range:NSMakeRange(0, attrString.length)];
[attrString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:rng];

return attrString;
}

#pragma mark - Device rotation

- (void)forceDeviceOrientation:(UIInterfaceOrientation)orientation
Expand Down Expand Up @@ -480,5 +608,4 @@ - (void)deviceOrientationDidChange:(NSNotification *)notification
}];
}


@end

0 comments on commit 5ef7155

Please sign in to comment.