XCODE - (iOS) синхронизация / синхронизация просмотра, который ведет себя как слайд-шоу с видео - PullRequest
0 голосов
/ 20 апреля 2011

Этот занимался моей работой уже несколько месяцев - так что пора проглотить мою гордость и протянуть руку помощи. На данный момент это делается в UIWebView как управляемая система HTML5 / JS. Но UIWebview откровенно лаконичен и надеется сделать этот последний компонент родным.

У меня есть коллекция видео и в определенные моменты времени во время видео, я вызываю страницу инструкций, которые относятся к временному периоду в видео. Элементы управления видео также действуют в качестве контроллера для страниц инструкций. Таким образом, в любой момент времени соответствующая страница анимируется на место.

Я просмотрел множество вариантов, наиболее близкий из которых - потоковое видео http и использование синхронизированных метаданных для запуска просмотра, но я храню видео локально на устройстве. И, пока еще не могу найти ничего, что выглядит так, как оно будет работать Кажется, в принципе все достаточно просто, но будь я проклят, если найду достойное решение ...

Есть идеи / указатели?

Вот последняя попытка стать нативным с этим до того, как выпадет оставшаяся часть моих волос - я думаю, что я могу видеть, куда я направляюсь в неправильном направлении, но если бы вы могли сэкономить несколько минут, я был бы очень признателен это!

ЦЕЛЬ - иметь крик, который живет под видео и содержит страницу с инструкциями. Через x секунд контент будет обновляться, чтобы соответствовать этой части видео, и сохраняться до следующего выкрики для свежего контента. Этого мне удалось добиться успешно. Когда я падаю (много), это когда я вычищаю видео назад к предыдущему разделу, контент shoutOut остается в той позиции, с которой я вычистил, и остается там навсегда. Или, если код приведен ниже, просто не появляется снова, так как для него задана видимая длительность по времени.

В любом случае, вот код ...

Заголовок:

// START:import
#import <UIKit/UIKit.h>
// START_HIGHLIGHT  
#import <MediaPlayer/MPMoviePlayerController.h>
#import "CommentView.h"
// END_HIGHLIGHT    


// START:def
// START:wiring
@interface MoviePlayerViewController : UIViewController {
    UIView *viewForMovie;
    // END:wiring
    // START_HIGHLIGHT  
    MPMoviePlayerController *player;
    // END_HIGHLIGHT
    // START:wiring
    UILabel *onScreenDisplayLabel;
    UIScrollView *myScrollView;
    NSMutableArray *keyframeTimes;
    NSArray *shoutOutTexts;
    NSArray *shoutOutTimes;
}

@property (nonatomic, retain) IBOutlet UIView *viewForMovie;
// END:wiring
// START_HIGHLIGHT
@property (nonatomic, retain) MPMoviePlayerController *player;
// END_HIGHLIGHT
@property (nonatomic, retain) IBOutlet UILabel *onScreenDisplayLabel;

@property (nonatomic, retain) IBOutlet UIScrollView *myScrollView;
@property (nonatomic, retain) NSMutableArray *keyframeTimes;


// START_HIGHLIGHT
-(NSURL *)movieURL;
- (void)timerAction:(NSTimer*)theTimer;
- (void) playerThumbnailImageRequestDidFinish:(NSNotification*)notification;
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer;
- (IBAction) getInfo:(id)sender;
- (void)removeView:(NSTimer*)theTimer;

// END_HIGHLIGHT
// START:wiring
@end
// END:def
// END:wiring
// END:import

Main:

@implementation MoviePlayerViewController
// START:synth
@synthesize player;
@synthesize viewForMovie;
@synthesize onScreenDisplayLabel;
@synthesize myScrollView;
@synthesize keyframeTimes;
// END:synth




// Implement loadView to create a view hierarchy programmatically, without using a nib.
// START:viewDidLoad
// START:viewDidLoad1
- (void)viewDidLoad {
    [super viewDidLoad];

    keyframeTimes = [[NSMutableArray alloc] init];

    shoutOutTexts = [[NSArray 
                      arrayWithObjects:@"This is a test\nLabel at 2 secs ", 
                      @"This is a test\nLabel at 325 secs",
                      nil] retain];
    shoutOutTimes = [[NSArray 
                      arrayWithObjects:[[NSNumber alloc] initWithInt: 2], 
                      [[NSNumber alloc] initWithInt: 325],
                      nil] retain];



    self.player = [[MPMoviePlayerController alloc] init];
    self.player.contentURL = [self movieURL];
    // END:viewDidLoad1


    self.player.view.frame = self.viewForMovie.bounds;
    self.player.view.autoresizingMask = 
    UIViewAutoresizingFlexibleWidth |
    UIViewAutoresizingFlexibleHeight;

    [self.viewForMovie addSubview:player.view];
    [self.player play];
    // START_HIGHLIGHT  

    [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
    // END_HIGHLIGHT    

    // START:viewDidLoad1

    [self.view addSubview:self.myScrollView];


    [[NSNotificationCenter defaultCenter] 
     addObserver:self 
     selector:@selector(movieDurationAvailable:)
     name:MPMovieDurationAvailableNotification
     object:nil];
}
// END:viewDidLoad
// END:viewDidLoad1

// START:movieURL
-(NSURL *)movieURL
{
    NSBundle *bundle = [NSBundle mainBundle];
    NSString *moviePath = 
    [bundle 
     pathForResource:@"BigBuckBunny_640x360" 
     ofType:@"m4v"];
    if (moviePath) {
        return [NSURL fileURLWithPath:moviePath];
    } else {
        return nil;
    }
}
// END:movieURL

int position = 0;

- (void)timerAction:(NSTimer*)theTimer {
    NSLog(@"hi");
    int count = [shoutOutTimes count];
    NSLog(@"count is at %d", count);

    if (position < count) {
        NSNumber *timeObj = [shoutOutTimes objectAtIndex:position];
        int time = [timeObj intValue];
        NSLog(@"time is at %d", time);
        if (self.player.currentPlaybackTime >= time) {
            CommentView *cview = [[CommentView alloc] 
                                  initWithText:[shoutOutTexts objectAtIndex:position]];
            [self.player.view addSubview:cview];
            position++;
            [NSTimer scheduledTimerWithTimeInterval:4.0f target:self selector:@selector(removeView:) userInfo:cview repeats:NO];
        }
    }

}

- (void)removeView:(NSTimer*)theTimer {
    UIView *view = [theTimer userInfo];
    [view removeFromSuperview];
}
/*
 // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
 - (void)viewDidLoad {
 [super viewDidLoad];
 }
 */

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}


- (void)dealloc {
    [super dealloc];
}

- (void) movieDurationAvailable:(NSNotification*)notification {
    MPMoviePlayerController *moviePlayer = [notification object];
    int duration = [moviePlayer duration];

    [[NSNotificationCenter defaultCenter] 
     addObserver:self 
     selector:@selector(playerThumbnailImageRequestDidFinish:)
     name:MPMoviePlayerThumbnailImageRequestDidFinishNotification
     object:nil];

    NSMutableArray *times = [[NSMutableArray alloc] init];
    for(int i = 0; i < 20; i++) {
        [times addObject:[NSNumber numberWithInt:5+i*((duration)/20)]];
    }
    [self.player requestThumbnailImagesAtTimes:times timeOption: MPMovieTimeOptionNearestKeyFrame];
}

int p = 0;
int ll=0;
- (void) playerThumbnailImageRequestDidFinish:(NSNotification*)notification {


    NSDictionary *userInfo;
    userInfo = [notification userInfo];

    NSNumber *timecode;
    timecode = [userInfo objectForKey: @"MPMoviePlayerThumbnailTimeKey"];


    [keyframeTimes addObject: timecode];

    UIImage *image;
    image = [userInfo objectForKey: @"MPMoviePlayerThumbnailImageKey"];

    int width = image.size.width;
    int height = image.size.height;
    float newwidth = 75 * ((float)width / (float)height);


    self.myScrollView.contentSize = CGSizeMake((newwidth + 2) * 20, 75);

    UIImageView *imgv = [[UIImageView alloc] initWithImage:image];
    [imgv setUserInteractionEnabled:YES];

    [imgv setFrame:CGRectMake(ll, 0, newwidth, 75.0f)];
    ll+=newwidth + 2;



    UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] 
                                             initWithTarget:self action:@selector(handleTapFrom:)];
    [tapRecognizer setNumberOfTapsRequired:1];

    [imgv addGestureRecognizer:tapRecognizer];
    [tapRecognizer release];


    [myScrollView addSubview:imgv];

}

- (void) getInfo:(id)sender
{
    MPMovieMediaTypeMask mask = self.player.movieMediaTypes;
    NSMutableString *mediaTypes = [[NSMutableString alloc] init];
    if (mask == MPMovieMediaTypeMaskNone) {
        [mediaTypes appendString:@"Unknown Media Type"];
    } else {
        if (mask & MPMovieMediaTypeMaskAudio) {
            [mediaTypes appendString:@"Audio"];
        }       
        if (mask & MPMovieMediaTypeMaskVideo) {
            [mediaTypes appendString:@"Video"];
        }

    }

    MPMovieSourceType type = self.player.movieSourceType;
    NSMutableString *sourceType = [[NSMutableString alloc] initWithString:@""];
    if (type == MPMovieSourceTypeUnknown) {
        [sourceType appendString:@"Source Unknown"];
    } else if (type == MPMovieSourceTypeFile) {
        [sourceType appendString:@"File"];
    } else if (type == MPMovieSourceTypeStreaming) {
        [sourceType appendString:@"Streaming"];
    }           


    CGSize size = self.player.naturalSize;

    onScreenDisplayLabel.text = [NSString stringWithFormat:@"[Type: %@] [Source: %@] [Time: %.1f of %.f secs] [Playback: %.0fx] [Size: %.0fx%.0f]", 
                                 mediaTypes,
                                 sourceType,
                                 self.player.currentPlaybackTime, 
                                 self.player.duration,
                                 self.player.currentPlaybackRate,
                                 size.width,
                                 size.height];
}

- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer {
    NSArray *subviews = [myScrollView subviews];
    for (int i = 0; i < 20; i++) {
        if (recognizer.view == [subviews objectAtIndex:i]) {
            NSNumber *num = [keyframeTimes objectAtIndex:i];
            self.player.currentPlaybackTime = [num intValue];
            return;
        }
    }

}

@end

Заголовок представления комментария:

#import <UIKit/UIKit.h>


@interface CommentView : UIView {

}

- (id)initWithFrame:(CGRect)frame andText:(NSString *) text;
- (id)initWithText:(NSString *) text;

@end

The View View Main:

#import "CommentView.h"


@implementation CommentView

- (id)initWithFrame:(CGRect)frame andText:(NSString *) text {
    if ((self = [super initWithFrame:frame])) {
        UIImage *image = [UIImage imageNamed:@"comment.png"];
        UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
        [self addSubview:imageView];

        CGRect rect = CGRectMake(20, 20, 200.0f, 90.0f);
        UILabel *label = [[UILabel alloc] initWithFrame:rect];
        label.text = text;
        label.numberOfLines = 3;
        label.adjustsFontSizeToFitWidth = YES;
        label.textAlignment = UITextAlignmentCenter;
        label.backgroundColor = [UIColor clearColor];
        [self addSubview:label];
    }
    return self;
}

- (id)initWithText:(NSString *) text {
    if ((self = [super init])) {
        UIImage *image = [UIImage imageNamed:@"comment.png"];
        UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
        [self addSubview:imageView];

        CGRect rect = CGRectMake(20, 20, 200.0f, 90.0f);
        UILabel *label = [[UILabel alloc] initWithFrame:rect];
        label.text = text;
        label.numberOfLines = 3;
        label.adjustsFontSizeToFitWidth = YES;
        label.textAlignment = UITextAlignmentCenter;
        label.backgroundColor = [UIColor clearColor];
        [self addSubview:label];
    }
    return self;
}



- (void)dealloc {
    [super dealloc];
}


@end

Кто-нибудь думает?

Ура!

1 Ответ

0 голосов
/ 20 апреля 2011

Что не так с мониторингом currentPlaybackTime через регулярные промежутки времени (при условии, что вы используете экземпляр, который реализует MPMediaPlayback для воспроизведения).

...