Problem
szukam do ekstraktu próbki z dokładnością zakresy LPCM audio z ścieżek audio w plikach wideo. Obecnie staram się to osiągnąć, używając AVAssetReaderTrackOutput
przeciwko AVAssetTrack
dostarczonego z czytania AVURLAsset
.Próbka dokładne wydobycie kawałkami audio za pomocą AVFoundation
Pomimo przygotowania i zapewnienia, że zasób zostanie zainicjowany przy użyciu zestawu AVURLAssetPreferPreciseDurationAndTimingKey
, ustawionego na YES
, próba znalezienia dokładnej pozycji w obrębie danego elementu wydaje się być niedokładna.
NSDictionary *options = @{ AVURLAssetPreferPreciseDurationAndTimingKey : @(YES) };
_asset = [[AVURLAsset alloc] initWithURL:fileURL options:options];
Przejawia się to np. strumienie AAC zakodowane z różną przepływnością. Chociaż wiem, że strumienie audio VBR przedstawiają koszty ogólne w dokładnym poszukiwaniu, jestem skłonny zapłacić, pod warunkiem, że dostarczyłem dokładne próbki.
Podczas korzystania np. Rozszerzone usługi plików audio i interfejsy API ExtAudioFileRef
pozwalają uzyskać precyzyjne wyszukiwanie i ekstrakcję dźwięku. Podobnie jest z AVAudioFile
, ponieważ jest on zbudowany na bazie ExtAudioFileRef
.
Problem jest jednak to, chciałbym również, aby wyodrębnić audio z pojemników mediów, że tylko audio-file API odrzucają, lecz są obsługiwane AVFoundation poprzez AVURLAsset
.
Sposób
Próbkę dokładny przedział czasu ekstrakcji jest zdefiniowana CMTime
i CMTimeRange
i ustawiony na AVAssetReaderTrackOutput
. Próbki są następnie ekstrahowane iteracyjnie.
-(NSData *)readFromFrame:(SInt64)startFrame
requestedFrameCount:(UInt32)frameCount
{
NSUInteger expectedByteCount = frameCount * _bytesPerFrame;
NSMutableData *data = [NSMutableData dataWithCapacity:expectedByteCount];
//
// Configure Output
//
NSDictionary *settings = @{ AVFormatIDKey : @(kAudioFormatLinearPCM),
AVLinearPCMIsNonInterleaved : @(NO),
AVLinearPCMIsBigEndianKey : @(NO),
AVLinearPCMIsFloatKey : @(YES),
AVLinearPCMBitDepthKey : @(32),
AVNumberOfChannelsKey : @(2) };
AVAssetReaderOutput *output = [[AVAssetReaderTrackOutput alloc] initWithTrack:_track outputSettings:settings];
CMTime startTime = CMTimeMake(startFrame, _sampleRate);
CMTime durationTime = CMTimeMake(frameCount, _sampleRate);
CMTimeRange range = CMTimeRangeMake(startTime, durationTime);
//
// Configure Reader
//
NSError *error = nil;
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:_asset error:&error];
if(!reader)
{
fprintf(stderr, "avf : failed to initialize reader\n");
fprintf(stderr, "avf : %s\n%s\n", error.localizedDescription.UTF8String, error.localizedFailureReason.UTF8String);
exit(EXIT_FAILURE);
}
[reader addOutput:output];
[reader setTimeRange:range];
BOOL startOK = [reader startReading];
NSAssert(startOK && reader.status == AVAssetReaderStatusReading, @"Ensure we've started reading.");
NSAssert(_asset.providesPreciseDurationAndTiming, @"We expect the asset to provide accurate timing.");
//
// Start reading samples
//
CMSampleBufferRef sample = NULL;
while((sample = [output copyNextSampleBuffer]))
{
CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sample);
if(data.length == 0)
{
// First read - we should be at the expected presentation time requested.
int32_t comparisonResult = CMTimeCompare(presentationTime, startTime);
NSAssert(comparisonResult == 0, @"We expect sample accurate seeking");
}
CMBlockBufferRef buffer = CMSampleBufferGetDataBuffer(sample);
if(!buffer)
{
fprintf(stderr, "avf : failed to obtain buffer");
exit(EXIT_FAILURE);
}
size_t lengthAtOffset = 0;
size_t totalLength = 0;
char *bufferData = NULL;
if(CMBlockBufferGetDataPointer(buffer, 0, &lengthAtOffset, &totalLength, &bufferData) != kCMBlockBufferNoErr)
{
fprintf(stderr, "avf : failed to get sample\n");
exit(EXIT_FAILURE);
}
if(bufferData && lengthAtOffset)
{
[data appendBytes:bufferData length:lengthAtOffset];
}
CFRelease(sample);
}
NSAssert(reader.status == AVAssetReaderStatusCompleted, @"Completed reading");
[output release];
[reader release];
return [NSData dataWithData:data];
}
Uwagi
Czas prezentacji że CMSampleBufferGetPresentationTimeStamp
daje mi wydaje się, aby dopasować to, co poszukiwane - ale jak się wydaje niedokładne, to nie ma szans, aby skorygować i wyrównać próbki odzyskać.
Wszelkie uwagi na temat tego, jak to zrobić?
Czy istnieje sposób dostosowania AVAssetTrack
do wykorzystania przez AVAudioFile
lub ExtAudioFile
?
Czy można uzyskać dostęp do ścieżki audio przez AudioFileOpenWithCallbacks
?
Czy można uzyskać w strumieniu audio z kontenera wideo w inny sposób w systemie MacOS?
Należy zauważyć, że czasami AVFoundation dostarcza mniej niż próbki są niezbędne do wystarczająco spełniają wymagania durationTime' '. To nie stanowi problemu dla np. mieć 'durationTime' z' kCMTimePositiveInfinity' i po prostu odczytać wystarczającą liczbę próbek w razie potrzeby ... to początkowe wyszukiwanie jest problematyczne. – Dan