.m4a来自iPod库的原始数据无法播放

时间:2012-05-11 04:56:40

标签: objective-c ios m4a avassetreader

所以我面临一个非常奇怪和奇怪的问题,并想知道是否有其他人遇到过这个问题。我从手机音乐库中获取MPMediaItem的原始数据,然后通过HTTP发送出去在其他地方播放。我的问题出现的地方是当我从.m4a类型的文件中获取原始数据时,它似乎是缺失的部分。例如,如果我从itunes检查的原始文件是7.4mb,从我的代码得到的大小为7.3mb。我做了一些研究,发现.m4a文件实际上是一个封装,我认为我没有得到文件的封装只是原始的音乐数据所以因此它是不可识别的。这是我的代码,它为我提供了来自MPMediaItem的原始音乐数据

                    NSError * error = nil;
                    MPMediaQuery *query = [MPMediaQuery albumsQuery];
                    NSArray * songs = query.items;  
                    MPMediaItem * song = [songs objectAtIndex:socket_data_index];  
                    AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:[song valueForProperty:MPMediaItemPropertyAssetURL] options:nil];
                    AVAssetReader * reader = [[AVAssetReader alloc] initWithAsset:songAsset error:&error];                  
                    AVAssetTrack * songTrack = [songAsset.tracks objectAtIndex:0];
                    AVAssetReaderTrackOutput * output = [[AVAssetReaderTrackOutput alloc] initWithTrack:songTrack outputSettings:nil];
                    [reader addOutput:output];                         
                    [output release]; 



                    [reader startReading];

                    while (reader.status == AVAssetReaderStatusReading)
                    {                            
                        AVAssetReaderTrackOutput * trackOutput = (AVAssetReaderTrackOutput *)[reader.outputs objectAtIndex:0];
                        CMSampleBufferRef sampleBufferRef = [trackOutput copyNextSampleBuffer];                            
                        if (sampleBufferRef)
                        {
                            CMBlockBufferRef blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef);

                            size_t length = CMBlockBufferGetDataLength(blockBufferRef);
                            NSMutableData * data = [[NSMutableData alloc] initWithLength:length];
                            CMBlockBufferCopyDataBytes(blockBufferRef, 0, length, data.mutableBytes);

                            [data_to_return appendData:data];
                            [data release];

                            CMSampleBufferInvalidate(sampleBufferRef);
                            CFRelease(sampleBufferRef);
                        }
                    }

                    if (reader.status == AVAssetReaderStatusFailed || reader.status == AVAssetReaderStatusUnknown)
                    {
                        // Something went wrong. Handle it.
                    }

                    if (reader.status == AVAssetReaderStatusCompleted)
                    {                         

                       return [[[HTTPDataResponse alloc] initWithData:data_to_return] autorelease];
                    }

                    [reader release];

我会为手机库中的.mp3文件获取正确的数据,但是当涉及.m4a时,它似乎缺少某些部分。

再次感谢您抽出宝贵时间帮助我。

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题。 AVAssetReader仅返回原始音频数据。它适用于.mp3,因为文件格式只是一堆帧,包含播放器播放文件所需的所有内容。您可能会注意到导出文件中缺少所有id3信息。

.m4a音频文件是包含aac音频数据的容器。您只收到了音频数据,没有进一步的信息,即采样率或搜索表。

您的问题的解决方法可能是使用AVAssetExportSession将AVAssetTrack导出到手机上的文件并从那里流式传输文件。我试过这个并写了一个正在运行的.m4a文件。

以下代码基于Apples example how to export a trimmed audio asset

// create the export session
AVAssetExportSession *exportSession = [AVAssetExportSession
                                       exportSessionWithAsset: songAsset
                                       presetName:AVAssetExportPresetAppleM4A];
if (nil == exportSession)
    NSLog(@"Error");

// configure export session  output with all our parameters
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *filePath = [NSString stringWithFormat: @"%@/export.m4a", basePath];

exportSession.outputURL = [NSURL fileURLWithPath: filePath]; // output path
exportSession.outputFileType = AVFileTypeAppleM4A; // output file type

[exportSession exportAsynchronouslyWithCompletionHandler:^{
    if (AVAssetExportSessionStatusCompleted == exportSession.status)
    {
        NSLog(@"AVAssetExportSessionStatusCompleted");
    }
    else if (AVAssetExportSessionStatusFailed == exportSession.status)
    {
        // a failure may happen because of an event out of your control
        // for example, an interruption like a phone call comming in
        // make sure and handle this case appropriately
        NSLog(@"AVAssetExportSessionStatusFailed");
    }
    else
    {
        NSLog(@"Export Session Status: %d", exportSession.status);
    }
}];

此解决方案的缺点是,必须将while文件写入磁盘。我还在寻找一种更好的方法来处理.m4a文件。