I am working on an iPhone application that uses a MediaPlayer to play a couple different videos. It works great for the first video but when I try to play another the screen stays black and only the audio plays. Does anyone have any idea why this might be happening?
Here is my code:
-(NSURL *)movieURL
{
NSBundle *bundle = [NSBundle mainBundle];
if (bundle)
{
NSString *moviePath = [bundle pathForResource:vidName ofType:#"mov"];
if (moviePath)
mMovieURL = [NSURL fileURLWithPath:moviePath];
if (vidName == #"Vid01")
vidName = #"Vid02";
else if (vidName == #"Vid02")
vidName = #"Vid03";
}
return mMovieURL;
}
- (void)onHitButton1 {
mMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[self movieURL]];
mMoviePlayer.movieControlMode = MPMovieControlModeHidden;
[mMoviePlayer play];
}
I figured it out. I needed to release the MediaPlayer before calling the second video.
Code example:
- (void)onHitButton1 {
[mMoviePlayer release];
mMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[self movieURL]];
mMoviePlayer.movieControlMode = MPMovieControlModeHidden;
[mMoviePlayer play];
}
You should also note that the playback issues may only occur in the simulator, not on the phone (such as subsequent playback 'flashing' or not displaying an image).
Are you really going to other videos?
I've noticed a bug in 3.0 that if you try to play a video twice from the same file you get some weird playback artifacts. The code you have above looks like it would only ever have a URL pointing to a single file.
The workaround I had was to rename my file, but that means you have to copy it to the documents directory in order to change the name... perhaps you could see if the iPhone file system would support a symbolic or hard link back to the original file in the resource directory so you could feed the movie player different names.
I filed a RADAR on this issue, you should too. Just put together a super simple example showing what is not working.
Shouldn't vidname be changing before the resource path instead of after?
Either way, it would be better to write it to accept an NSString which you could pass the filename to. You know like
-(NSURL *)movieURLForVideo: (NSString) videoFileName
?
Also I didn't like your lack of {}'s. This makes it much easier to read/debug for me. It's a good habit to have in general. Taking the extra time to write things as neat as you can will save you headaches later.
-(NSURL *)movieURL
{
NSBundle *bundle = [NSBundle mainBundle];
if (bundle)
{
if (vidName == #"Vid01")
{
vidName = #"Vid02";
}
else if (vidName == #"Vid02")
{
vidName = #"Vid03";
}
else if (vidName == #"Vid03")
{
vidName = #"Vid01";
}
NSString *moviePath = [bundle pathForResource:vidName ofType:#"mov"];
if (moviePath)
{
mMovieURL = [NSURL fileURLWithPath:moviePath];
}
}
return mMovieURL;
}
Is vidName being set to Vid01 somewhere? I didn't see it so I have to ask. This is just confusing in general. I've been writing for OS X, so I'm not sure if there are any differences, but I use this when I'm loading maps in my current project:
NSString* mapPath = [[NSBundle mainBundle] pathForResource:mapFileName ofType:mapFileType];
NSURL* mapURL = [NSURL fileURLWithPath: mapPath];
currentMap_ = [[Map alloc] initWithContentsOfURL: mapURL];
Just seems like you're writing way more than you need to be.
Related
I want to play a different alert sound if the multiple choice option answer is correct or wrong. I have code for the correct and wrong answer as follows
if (questionNumber == 1) {
[self correctAnswer];
}
if (questionNumber == 2) {
[self wrongAnswer];
}
I have created the correct IBAction Alert code. can I create a simple play.alert statement under either the correct or wrong answer?
If you want to use default Apple sounds, use the code in this question, and click on the link he has there to try out different sounds.
If you would like to play custom sounds, the easiest way is with AVAudioPlayer:
First of all, you will need to add the AVFoundation framework to your project. It is very easy from there:
NSURL *url = [NSURL fileURLWithPath:path isDirectory:YES];
AVAudioPlayer *sound = audioPlayers[url];
NSError *error = nil;
sound = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
[sound play];
I have an object moving around the screen and once it reaches the edges it it changes direction and plays a sound this all works fine except that when it plays the sound I freezes for about half a second is there any way of making this run smoothly with the sound and object movement?
-(void)viewDidLoader
{
NSString *path1 = [[NSBundle mainBundle] pathForResource:#"ballbounce" ofType:#"mp3"];
ballbounce = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path1] error: NULL];
[ballbounce prepareToPlay];
}
-(void) ballcollition
{
[self ballplaysound]
enemy.center = CGPointMake(enemy.center.x+pos.x,enemy.center.y+pos.y);
if (enemy.center.x > 328 || enemy.center.x < 0)
{
pos.x = -pos.x;
}
}
-(void)ballplaysound
{
if (enemy.center.x > 328 || enemy.center.x < 0 ||enemy.center.y < 0||enemy.center.y < 300)
[ballbounce play];
}
use the System Sound for sound that plays smoothly.
Original NON-ARC answer:
#import <AudioToolbox/AudioToolbox.h>
- (IBAction)soundButton:(id)sender {
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"alert" ofType:#"wav"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath: soundPath], &soundID);
AudioServicesPlaySystemSound (soundID);
[soundPath release];
}
Updated for ARC, and turned into a utility function:
- (void)soundPlay:(NSString*)waveName {
// wavName = #"alert" without any file extension (not alert.wav)
NSString *soundPath = [[NSBundle mainBundle] pathForResource:waveName ofType: #"wav"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath: soundPath], &soundID);
AudioServicesPlaySystemSound (soundID);
}
Use AudioServicesPlaySystemSound(): https://developer.apple.com/library/ios/#documentation/AudioToolbox/Reference/SystemSoundServicesReference/Reference/reference.html
You can gain sound "smoothness" with AVPlayer by simply converting your mp3 to caf format as explained here.
1) Create AVAudioPLayer and cache it in your apps initialization code and never call it again
also call prepare as well.
2) so the method you included should only have to call play;
3) If you still get a skip use
[ballbounce performSelectorOnMainThread:#selector(play) withObject:nil];
Since you didnt include all the code and you are clearly doing drawing - putting the play method
on the queue could let the drawing code finish without interruption.
Doing this correctly might fix you. Using AudioSystemSound is much lower overhead but you should follow the same principles of preparing any often used sounds in your app initialization and not spawning them at the exact time you need them to avoid performance issues.
I have an app I am working on and It uses some of the hardware sensors to provide data on screen, there is a Label that updates with the number. I want a sound to play whenever the number is above 100 or something. For example, say it was reading numbers then all of the sudden it finds a good spot (or whatever), then I would like a sound to play or a light to light up. I am an absolute beginner and it would be nice if the answer would be easy for a absolute beginner to understand.
I am using the system AudioToolbox.framework for playing sounds in my simple game. I added this static function to common MyGame class:
+ (SystemSoundID) createSoundID: (NSString*)name
{
NSString *path = [NSString stringWithFormat: #"%#/%#",
[[NSBundle mainBundle] resourcePath], name];
NSURL* filePath = [NSURL fileURLWithPath: path isDirectory: NO];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)filePath, &soundID);
return soundID;
}
I added the "Morse.aiff" file to project Resources and initialized it in (any) class initialization with the following:
self.mySound = [MyGame createSoundID: #"Morse.aiff"];
And then I played sound with this call:
AudioServicesPlaySystemSound(mySound);
Also, don't forget to import AudioServices.h file.
This audio toolbox can play also different sound formats.
h
#import <AVFoundation/AVFoundation.h>
#interface CMAVSound : NSObject {
AVAudioPlayer *audioPlayer;
}
- (id)initWithPath:(NSString*)fileNameWithExctension;
- (void)play;
#end
m
#import "CMAVSound.h"
#implementation CMAVSound
-(void)dealloc {
[audioPlayer release];
}
- (id)initWithPath:(NSString*)fileNameWithExctension {
if ((self = [super init])) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] resourcePath], fileNameWithExctension]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if (audioPlayer == nil) {
NSLog(#"%#", [error description]);
}
}
return self;
}
- (void)play {
[audioPlayer play];
}
#end
Check out the documentation for the AVAudioPlayer class. It allows you to play sounds clips. If you have troubles implementing that, show us some code.
If the sounds gonna up to 5 seconds and no stereo output is needed I would recommend you to do that with system sounds. It is easy and better solution then any other.
Apple sample code is provided under name SysSound
EDIT1
Or maybe tutorial could help you more
http://howtomakeiphoneapps.com/2009/08/how-to-play-a-short-sound-in-iphone-code/
Take a look at following links;
http://blog.guvenergokce.com/avaudioplayer-on-iphone-simulator/57/
http://mobileorchard.com/easy-audio-playback-with-avaudioplayer/
Here you can find list of AudioServicesPlaySystemSound
http://iphonedevwiki.net/index.php/AudioServices
I'm very new to core audio and I just would like some help in coding up a little volume meter for whatever's being outputted through headphones or built-in speaker, like a dB meter. I have the following code, and have been trying to go through the apple source project "SpeakHere", but it's a nightmare trying to go through all that, without knowing how it works first... Could anyone shed some light?
Here's the code I have so far...
(void)displayWaveForm
{
while (musicIsPlaying == YES {
NSLog(#"%f",sizeof(AudioQueueLevelMeterState));
}
}
(IBAction)playMusic
{
if (musicIsPlaying == NO) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/track7.wav",[[NSBundle mainBundle] resourcePath]]];
NSError *error;
music = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
music.numberOfLoops = -1;
music.volume = 0.5;
[music play];
musicIsPlaying = YES;
[self displayWaveForm];
}
else {
[music pause];
musicIsPlaying = NO;
}
}
you can use metering with the AVAudioPlayer class, first enable it then get the average power to use as your meter data avTouch has a working example
How do I get a thumbnail of a video imported from the camera roll, or the camera itself?
This has been asked before, and has been answered. However, the answers kind of suck for me.
This thread iphone sdk > 3.0 . Video Thumbnail? has some options that boil down to:
Crawl some filesystem directory for a JPG with the latest modification date that should correspond to the video you just picked. This is extremely messy, and involves rooting around in directories Apple would probably not really want me doing.
Use ffmpeg. But this is so general that I cannot seem to figure out the steps that it would take to import ffmpeg into my project and to actually call it to extract images.
Is there really no other way? This seems like a HUGE oversight in the SDK to me. I mean the video picker has thumbnails in it, so Apple must be doing something to generate those, yet does not allow us to?
-(void)testGenerateThumbNailDataWithVideo {
NSString *path = [[NSBundle mainBundle] pathForResource:#"IMG_0106" ofType:#"MOV"];
NSURL *url = [NSURL fileURLWithPath:path];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetImageGenerator *generate = [[AVAssetImageGenerator alloc] initWithAsset:asset];
NSError *err = NULL;
CMTime time = CMTimeMake(1, 60);
CGImageRef imgRef = [generate copyCGImageAtTime:time actualTime:NULL error:&err];
[generate release];
NSLog(#"err==%#, imageRef==%#", err, imgRef);
UIImage *currentImg = [[UIImage alloc] initWithCGImage:imgRef];
static BOOL flag = YES;
if (flag) {
NSData *tmpData = UIImageJPEGRepresentation(currentImg, 0.8);
NSString *path = [NSString stringWithFormat:#"%#thumbNail.png", NSTemporaryDirectory()];
BOOL ret = [tmpData writeToFile:path atomically:YES];
NSLog(#"write to path=%#, flag=%d", path, ret);
flag = NO;
}
[currentImg release];
}
Best method I've found... MPMoviePlayerController thumbnailImageAtTime:timeOption
Nevermind this... see first comment below. That's the answer.
We use ffmpeg, you can explore our site for hints on how to do it, eventually I want to put up a tutorial.
But right now I'm more concentrated on getting ffmpeg to play movies.
Understand once you have that code the code to generate a thumbnail is just a subset of that.
http://sol3.typepad.com/tagalong_developer_journa/
This tutorial here, has helped us and maybe the majority of developers using ffmpeg to get started.
dranger.com/ffmpeg/ "
Finally,
Apple probably would maybe not have any problems with using the thumbnail generated from the video camera, I don't think its in a private folder however that is only created by the camera and not for videos picked from the image picker.