3

所以我面临一个非常奇怪和奇怪的问题,想知道是否有其他人遇到过这个问题。我从手机音乐库中获取 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 时,它似乎缺少某些部分。

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

4

1 回答 1

1

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

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

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

以下代码基于Apple 示例如何导出修剪后的音频资产

// 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 文件。

于 2013-02-01T14:11:08.710 回答