- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
注意:请参阅底部的更新。
我有一个应用程序可以从列表中一个一个地播放视频。因此,为了测试此功能,我创建了一个只有一个 View Controller 的简单应用程序。我在实现 this 之前引用了此博客 View Controller 。 View Controller 命名为TNViewController
,其实现如下:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
@interface TNViewController : UIViewController {
@private
NSMutableArray *_videoArray;
int _currentVideo;
MPMoviePlayerController *_moviePlayer;
NSURL *_movieUrl;
}
@end
它的实现是:
#import "TNViewController.h"
@implementation TNViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
[self.view setFrame:CGRectMake(0, 0, 480, 320)];
[self initVideos];
[self initPlayer];
}
- (void) initVideos {
_videoArray = [[NSMutableArray alloc] init];
NSString *path = [[NSBundle mainBundle] pathForResource:@"sintel_trailer" ofType:@"mp4" inDirectory:nil];
[_videoArray addObject:path];
path = [[NSBundle mainBundle] pathForResource:@"elephants_dream_trailer" ofType:@"mp4" inDirectory:nil];
[_videoArray addObject:path];
path = [[NSBundle mainBundle] pathForResource:@"big_buck_bunny_trailer" ofType:@"mp4" inDirectory:nil];
[_videoArray addObject:path];
_currentVideo = -1;
}
- (NSString*) nextVideo {
_currentVideo++;
if (_currentVideo >= _videoArray.count) {
_currentVideo = 0;
}
return [_videoArray objectAtIndex:_currentVideo];
}
- (void) initPlayer {
_moviePlayer = [[MPMoviePlayerController alloc]init];
[self readyPlayer];
[self.view addSubview:_moviePlayer.view];
// Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePlayer];
}
- (void) readyPlayer {
_movieUrl = [NSURL fileURLWithPath:[self nextVideo]];
[_movieUrl retain];
_moviePlayer.contentURL = _movieUrl;
// For 3.2 devices and above
if ([_moviePlayer respondsToSelector:@selector(loadState)]) {
// Set movie player layout
[_moviePlayer setControlStyle:MPMovieControlStyleNone];
[_moviePlayer setFullscreen:YES];
// May help to reduce latency
[_moviePlayer prepareToPlay];
// Register that the load state changed (movie is ready)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayerLoadStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
} else {
// Register to receive a notification when the movie is in memory and ready to play.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePreloadDidFinish:)
name:MPMoviePlayerContentPreloadDidFinishNotification
object:nil];
}
}
/*---------------------------------------------------------------------------
* For 3.1.x devices
*--------------------------------------------------------------------------*/
- (void) moviePreloadDidFinish:(NSNotification*)notification {
// Remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerContentPreloadDidFinishNotification
object:nil];
// Play the movie
[_moviePlayer play];
}
/*---------------------------------------------------------------------------
* For 3.2 and 4.x devices
*--------------------------------------------------------------------------*/
- (void) moviePlayerLoadStateChanged:(NSNotification*)notification {
NSLog(@"moviePlayerLoadStateChanged");
// Unless state is unknown, start playback
if ([_moviePlayer loadState] != MPMovieLoadStateUnknown) {
// Remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
// Set frame of movie player
[[_moviePlayer view] setFrame:CGRectMake(0, 0, 480, 320)];
// Play the movie
[_moviePlayer play];
}
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
NSLog(@"playback finished...");
NSLog(@"End Playback Time: %f", _moviePlayer.endPlaybackTime);
int reason = [[[notification userInfo] valueForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
if (reason == MPMovieFinishReasonPlaybackEnded) {
NSLog(@"Reason: movie finished playing");
}else if (reason == MPMovieFinishReasonUserExited) {
NSLog(@"Reason: user hit done button");
}else if (reason == MPMovieFinishReasonPlaybackError) {
NSLog(@"Reason: error");
}
[self playNextVideo];
}
- (void) playNextVideo {
NSString *filePath = [self nextVideo];
[_movieUrl release];
_movieUrl = [NSURL fileURLWithPath:filePath];
[_movieUrl retain];
_moviePlayer.contentURL = _movieUrl;
[_moviePlayer play];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void) dealloc {
[_moviePlayer release];
[_movieUrl release];
[_videoArray release];
[super dealloc];
}
@end
现在,我的问题是通知 MPMoviePlayerPlaybackDidFinishNotification
被调用了两次。从上面的代码可以看出,我在viewDidLoad
中只注册了一次(在viewDidLoad
调用的initPlayer
中)。这是日志输出:
2012-07-02 12:29:17.661 DemoApp[1191:ef03] moviePlayerLoadStateChanged
2012-07-02 12:30:11.470 DemoApp[1191:ef03] playback finished...
2012-07-02 12:30:11.471 DemoApp[1191:ef03] End Playback Time: -1.000000
2012-07-02 12:30:11.472 DemoApp[1191:ef03] Reason: movie finished playing
2012-07-02 12:30:11.474 DemoApp[1191:ef03] playback finished...
2012-07-02 12:30:11.475 DemoApp[1191:ef03] End Playback Time: -1.000000
2012-07-02 12:30:11.476 DemoApp[1191:ef03] Reason: movie finished playing
2012-07-02 12:31:03.821 DemoApp[1191:ef03] playback finished...
2012-07-02 12:31:03.822 DemoApp[1191:ef03] End Playback Time: -1.000000
2012-07-02 12:31:03.824 DemoApp[1191:ef03] Reason: movie finished playing
2012-07-02 12:31:03.826 DemoApp[1191:ef03] playback finished...
2012-07-02 12:31:03.827 DemoApp[1191:ef03] End Playback Time: -1.000000
2012-07-02 12:31:03.827 DemoApp[1191:ef03] Reason: movie finished playing
如您所见,播放完成被调用了两次。这会导致从队列中跳过一个视频。 (事实上,在出现问题的原始项目中,nextVideo
会预先从服务器缓存一个视频,如果缓存中存在,则返回缓存视频的路径。否则,它返回 nil
。)。在这里,首先播放 sintel_trailer.mp4
。播放结束后,它播放的不是 elephants_dream_trailer.mp4
,而是 big_buck_bunny_trailer.mp4
。也就是说,它循环播放中间跳过的视频。那么,是什么导致 MPMoviePlayerPlaybackDidFinishNotification
调用两次?我为此工作了两天,仍然没有运气。有什么想法吗?
更新 1:
目前我正在回调 moviePlayBackDidFinish:
中使用一个开关,如下所示并且正在工作:
if (!_playNextVideo) {
_playNextVideo = YES;
return;
}
_playNextVideo = NO;
// code to play video....
但我仍然想知道是什么导致回调被调用两次。我觉得当前的 switch 解决方案就像一个 hack,并希望将其删除。
更新 2:
到目前为止,我一直在使用 iPhone 4.3 模拟器进行尝试。但是,当我用 iPhone 5.0 模拟器和 iPhone 5.1 模拟器尝试相同的程序时,它没有任何问题。也就是说,电影播放完毕后只发送一个回调。这使我的小技巧(更新 1)变得毫无用处(它解决了 4.3 中的问题,但在 5.0 和 5.1 中产生了问题)。我正在使用在 MacOSX Lion - 10.7.4 上运行的 Xcode 4.3.2。你知道如何解决这个问题吗?为什么在 4.3 上有两个回调?
更新 3:
我查明了导致问题的线路。它在 playNextVideo
方法中。导致问题的行是 _moviePlayer.contentURL = _movieUrl;
。在第一个回调中更改它会导致再次发送 MPMoviePlayerPlaybackDidFinishNotification
。但是,它只发生在 iPhone 4.3 模拟器中。有什么想法吗?
更新 4:
不过,我对这种奇怪的行为一无所知。所以,我现在在 moviePlayBackDidFinish:
NSTimeInterval currentCallback = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval difference = currentCallback - _lastCallback;
_lastCallback = currentCallback;
if (difference < 5.0) {
return;
}
// code to play video....
最佳答案
我遇到了同样的问题。并以这种方式解决:
我创建了一种跳过视频的新方法
- (void) skipVideo {
[_moviePlayer stop];
}
在 skipVideo
中停止播放器将导致 MPMovieFinishReasonPlaybackEnded
通知(在模拟器和设备上)。现在设置播放器的contentUrl时,不会引起其他MPMovieFinishReasonPlaybackEnded
通知,所以moviePlayBackDidFinish
只调用一次;
在播放下一个视频之前(在playNextVideo
)你必须调用
[_moviePlayer prepareToPlay];
这对我来说很好用!
关于iphone - 设置 contentURL 时在 iPhone 4.3 模拟器中再次调用 MPMoviePlayerPlaybackDidFinishNotification,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11289401/
阅读official documentation关于 adMob contentURL 参数,不清楚传递 URL 的目的是什么。 文档说: Content URL Applications that
我正在使用 Erik Vold 的工具栏按钮。我有一个固定在上面的面板。当在面板中呈现的 html 静态页面上单击其中一个链接时,我需要在同一面板中显示其他内容。 我正在尝试使用端口 API 在插件代
我尝试将视频分享到我的应用程序。它收到了通知,但没有 contentUrl 来加载视频。以下是通知中的附件字段: attachments: [{contentType: 'video/mp4', 'i
我正在使用 addon-sdk 构建 Firefox 插件。 该插件有一个按钮,单击后会显示一个面板。该面板有一个运行它的内容脚本。现在,我需要面板根据用户当前的选项卡看起来有所不同,并且偶尔显示外部
当我单击小部件图标时,如何使用 contenturl 刷新面板?我的代码很简单: var data = require("sdk/self").data; exports.main = fun
我尝试使用 MPMoviePlayerController 播放视频。设置是:我推送一个新的 ViewController,然后在 viewDidLoad 中设置 View 和电影播放器实例,然后
简而言之,我的应用程序正在这样做: 1)当我点击它时,我的主 View (RootViewController)有一个按钮,它显示播放器(PlayerViewController): 2)在我的播放器
我在 loadView 方法中创建了一个嵌入式 MPMoviePlayerController: self.moviePlayerController = [[[MPMoviePlayerContro
我正在做一个 iPad 项目,我必须一个接一个地流畅地播放短视频文件。为了播放我正在使用的视频 MPMoviePlayerController .我面临的问题是当我打电话时 [self.moviePl
当我检索时间线项目时,它显示有附件和正确的内容类型,但 ContentUrl 为空,为什么?我还尝试获取 timelineResource.GetRequest 并将 Alt 更改为“媒体”,但它返回
我正在开发一个简单的词典插件,它允许用户突出显示一个词(通过双击它),这将导致出现一个显示该词的词典定义的弹出窗口。 我无法动态更改我正在使用的页面 worker 的 ContentURL,以便我可以
我希望你能帮助我,我正在尝试使用 Bing 图像搜索 API,到目前为止一切都很好,只有一件事我不明白,contentURL 是一个重定向,哪里应该是图像 url从源网站至少这就是文档所说的(以及搜索
我在我的应用程序中使用 facebook 版本 4.14,以便使用 ShareLinkConent 与 Imageurl 和 Contenturl 一起共享 Hashtag。现在Hashtag已经成功
注意:请参阅底部的更新。 我有一个应用程序可以从列表中一个一个地播放视频。因此,为了测试此功能,我创建了一个只有一个 View Controller 的简单应用程序。我在实现 this 之前引用了此博
指令 app.directive('PanelbarDirective', function ($http) { return { restrict: "EA",
我是一名优秀的程序员,十分优秀!