How to find an audio file's length (in seconds) - iphone

(Objective C)
Just using simple AudioServicesPlaySystemSoundID and its counterparts, but I can't find in the documentation if there is already a way to find the length of an audio file.
I know there is AudioServicesGetPropertyInfo, but that seems to return a byte-buffer - do audio files embed their length in themselves and I can just extract it with this?
Or is there perhaps a formula based on bit-rate * fileSize to convert to length-of-time?
mIL3S
www.milkdrinkingcow.com

According to a quick Google search, there is a formula:
length-of-time (duration in seconds) = fileSize (in bytes) / bit-rate (bits/secs)*8
Is there any particular reason you're using System Sound Services to play a sound?
If you use AVAudioPlayer to handle your sounds you could do something like:
AVAudioPlayer * sound = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:nil];
sound.delegate = self;
sound.volume = 1;
NSLog([NSString stringWithFormat:#"%f", sound.duration]);

sample code from answer How to get the duration of an audio file in iOS?. This is the best answer.
AVURLAsset* audioAsset = [AVURLAsset URLAssetWithURL:audioFileURL options:nil];
CMTime audioDuration = audioAsset.duration;
float audioDurationSeconds = CMTimeGetSeconds(audioDuration);

See at:
Float64 fileDuration = PrepareFileAU (fileAU, fileFormat, audioFile);
see ADC sample at:
http://developer.apple.com/library/mac/#samplecode/PlayFile/Introduction/Intro.html
without using AVPlayer...

Related

AVMutableVideoComposition some inserted video crash composition

Some videos play fine alone as simple AVAssets but when inserted in an AVMutableVideoComposition they make the whole composition fail even if those videos are inserted alone in an empty composition. Anyone has similar issues? Sometime re-encoding the videos before inserting them makes it work sometime not. I can't see any mistake in my timing instruction and using some other video don't cause any problem at all no matter their length. Can there be issues with the number of frame or the duration of the asset or their format? (all are h264 single track)
Well indeed it looks like some video may cause problem when being inserted. example here duration of the track is the issue.
AVAsset * video = ...;
NSArray * videoTracks = [video tracksWithMediaType:AVMediaTypeVideo];
AVAssetTrack * videoTrack = videoTracks.firstObject;
CMTime duration = videoTrack.timeRange.duration // this time cause error
AVMutableCompositionTrack * track = ...;
CMTime insertCMTime = kCMTimeZero;
CMTimeRange trackRange = CMTimeRangeMake(kCMTimeZero, duration);
[track insertTimeRange:trackRange
ofTrack:videoTrack
atTime:insertCMTime
error:nil];
Trimming the range to insert to a round second solved the problem for all video tested so far
NSTimeInterval interval = (int)CMTimeGetSeconds(videoTrack.timeRange.duration);
CMTime roundedDuration = CMTimeMakeWithSeconds(interval, 60000);

iOS6 AVAudioPlayer - AAC audio file duration always return 0

I'm porting an app that works with aac audio files to iOS6 and I've found an strange behavior, when I try to get the duration of the (valid) aac audio file, it's always returns 0, in iOS4 and iOS5 it works fine.
¿Is there any bug on AvAudioPlayer class that affects duration property? I have read about some troubles with the currentTime property.
Here's the code:
NSURL* urlFichero = [NSURL fileURLWithPath:rutaFichero];
avaPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: urlFichero error:nil];
segundos = avaPlayer.duration;
NSLog(#"[ControladorFicheros] Fichero: '%#' Duración: '%f'", nombreFichero, segundos);
[avaPlayer stop];
[avaPlayer release];
Thanks ;)
Finally the problem is that in newest versions of the API, AVAudioPlayer appears to only returns the correct duration of a file when it is ready for play it, that's why my solution was wrong, the correct way to get the duration of a file (in seconds) if you don't want to reproduce it is:
AVURLAsset *asset = [[[AVURLAsset alloc] initWithURL:anURI_ToResource
options:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
AVURLAssetPreferPreciseDurationAndTimingKey,
nil]] autorelease];
NSTimeInterval durationInSeconds = 0.0;
if (asset)
durationInSeconds = CMTimeGetSeconds(asset.duration) ;
Swift
let asset = AVURLAsset(url: url, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
let durationInSeconds = CMTimeGetSeconds(asset.duration)
I noticed the same problem. My solution is to use instead.
MPMoviePlayerController *testPlayer = [[MPMoviePlayerController alloc] initWithContentURL:filePath];
[testPlater prepareToPlay];
[testPlater play];

iPhone: get duration of an audio file

What is the easiest way to get a duration of an audio file?
I could create an object of AVAudioPlayer, initialize it with URL and than get the duration, but this way is too long. Is there an easier way?
Thanks.
Correct code is
NSURL *afUrl = [NSURL fileURLWithPath:soundPath];
AudioFileID fileID;
OSStatus result = AudioFileOpenURL((CFURLRef)afUrl, kAudioFileReadPermission, 0, &fileID);
Float64 outDataSize = 0;
UInt32 thePropSize = sizeof(Float64);
result = AudioFileGetProperty(fileID, kAudioFilePropertyEstimatedDuration, &thePropSize, &outDataSize);
AudioFileClose(fileID);
outDataSize should be Float64 not UInt64.
You can use the Audio File Services functions. There's one property to get that should give you the estimated duration. Code:
NSURL *afUrl = [NSURL fileURLWithPath:soundPath];
AudioFileID fileID;
OSStatus result = AudioFileOpenURL((CFURLRef)afUrl, kAudioFileReadPermission, 0, &fileID);
Float64 outDataSize = 0;
UInt32 thePropSize = sizeof(Float64);
result = AudioFileGetProperty(fileID, kAudioFilePropertyEstimatedDuration, &thePropSize, &outDataSize);
AudioFileClose(fileID);
You can check the docs here
If you know anything about the audio file in question (samplerate, bitdepth, channel count), and it's an uncompressed format (WAV/AIFF), then you can calculate the /approximate/ duration from the filesize:
length_in_seconds = (file_length-guess_100_bytes_for_header) / (samplerate*(bitdepth*channel_count/8))
It depends on the file type. If it's a WAV file you can locate the file's header and determine the playback duration that way. If it's a compressed format (*.mp3 etc.) you're better off sticking to the method you mentioned.
Combining AVAudioPlayer with Swift becomes as easy as (I am migrating a Realm table below, but you get the idea):
import AVFoundation
let resource = old!["filename"] as? String
let afUrl = NSBundle.mainBundle().URLForResource(resource, withExtension: nil)
let player = try! AVAudioPlayer(contentsOfURL: afUrl!)
new!["duration"] = Double(player.duration)
In case anyone lands here looking for a way to get the duration for both audio and video files, have a look at this answer to another post, which instead uses AVAsset instead:
https://stackoverflow.com/a/7052147/381233
Using AudioFileGetProperty (like the other two main answers here) to get the duration of A/V files didn't work for a few .mov files on my device (result was always 0), while the solution using AVAsset got the duration for all audio and video files on my device.
(Interestingly enough, however, the duration from both solutions was sometimes 1 second more than that displayed in the UI of an actual AVAudioPlayer. Most likely the AVAudioPlayer uses a non-standard rounding routine for the displayed duration.)
AVURLAsset* audioAsset = [AVURLAsset URLAssetWithURL:mp3_url options:nil];
[audioAsset loadValuesAsynchronouslyForKeys:#[#"duration"] completionHandler:^{
CMTime audioDuration = audioAsset.duration;
float audioDurationSeconds = CMTimeGetSeconds(audioDuration);
NSLog(#"duration:%f",audioDurationSeconds);
}];
sample code from answer How to get the duration of an audio file in iOS?. This is the best answer.
AVURLAsset* audioAsset = [AVURLAsset URLAssetWithURL:audioFileURL options:nil];
CMTime audioDuration = audioAsset.duration;
float audioDurationSeconds = CMTimeGetSeconds(audioDuration);

Getting iPhone video thumbnails

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.

Multiple AVAudioPlayers: I can only get the first one initialized to play

I have a bunch of sound clips, named sound1.mp3 through soundN.mp3. I want to randomly play them on touch, so I've set up an AVAudioPlayer for each clip which are all stored in players (AVAudioPlayer**). After I initialize everything, the only sound I can get to play is sound1.mp3. What am I doing wrong?
Thanks for the help, init code is below.
players = (AVAudioPlayer**) malloc ( sizeof (AVAudioPlayer*) * NUM_CLIPS);
NSString* path;
NSString* name;
for(uint i = 0; i < NUM_CLIPS; i++){
name = [NSString stringWithFormat: #"sound%d", i+1];
path = [[NSBundle mainBundle] pathForResource:name ofType:#"mp3"];
players[i] = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[players[i] setMeteringEnabled:YES];
[players[i] prepareToPlay];
}
The reason for this is that mp3/aac files are hardware decoded and only on at a time can be decoded.
Nevermind, seems like it was a problem with the way prepareToPlay works
James Brooks (jamesbrooks dot net) says that changing the *.mp3 files into *.caf allowed him to play multiple sounds with the AVAudioPlayer. I personally, however, can not get the *.caf files to play at the same time but I can get *.aiff files to play simultaneously.