Question

I am using AVAssetReader to get the individual frames from a video file. I would like to know how I can play the audio from Mp4 file.

the return value of method [player play] is false, so there is no sound to play, but why

thanks.

create AVAssetReader

  NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"zhang" ofType:@"mp4"]];
    AVURLAsset *avasset = [[AVURLAsset alloc] initWithURL:url options:nil];
    AVAssetTrack *track1 = [[avasset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];

NSMutableDictionary *dic2 = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,  [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,
                             [NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,
                             [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
                             [NSNumber numberWithBool:NO],AVLinearPCMIsNonInterleaved, nil]; 

output1 = [[AVAssetReaderTrackOutput alloc] initWithTrack:track1 outputSettings:dic2];

AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:avasset error:nil];

[reader addOutput:output1];
[reader startReading];

output code is as following:

  CMSampleBufferRef sample = [output1 copyNextSampleBuffer];
    CMBlockBufferRef blockBufferRef = CMSampleBufferGetDataBuffer(sample);

    size_t length = CMBlockBufferGetDataLength(blockBufferRef);
    UInt8 buffer[length];
    CMBlockBufferCopyDataBytes(blockBufferRef, 0, length, buffer);

    NSData * data = [[NSData alloc] initWithBytes:buffer length:length];
    NSString *docDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *filePath = [NSString stringWithFormat:@"%@/test.mp3", docDirPath];
    [data writeToFile:filePath atomically:YES];
    [data release];

    NSError *error;
    NSURL *fileURL = [NSURL fileURLWithPath:filePath];
    AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
    player.numberOfLoops = 0;
    [player play];
Was it helpful?

Solution

One option would be to avoid using the AVAudioPlayer, and instead use the PCM data you have decoded to fill an AudioQueue for output.

The ideal method would be to create an AVComposition from the audio track of an AVAsset that was created from your source mp4 file. That AVComposition (as a subclass of AVAsset) can be used inside an AVPlayer, which will then play just the audio track for you.

You're not able to simply write out blocks of PCM data into a file with the extension ".mp3" - that's an encoded format. The AVAudioPlayer will be looking for certain encoded data in the file, and the file you have written will be incompatible, which is why you are receiving a return value of false. If you have your heart set on writing the audio out to a file, use an AVAssetWriter with the appropriate settings. This could be written out as a Core Audio file for maximum performance. This step could also encode the audio as another format (say, mp3, or AAC), however this will have a heavy performance cost associated with it, and it's likely that it will not be suitable for real-time playback.

OTHER TIPS

The assets is not playable immediately. Need to observe the value of status using key-value observing. Refer to the AVCam sample of Apple.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top