Я пытаюсь взять видеофайл, прочитав его с помощью AVAssetReader и передав аудио в CoreAudio для обработки (добавления эффектов и т. Д.), Прежде чем сохранять его обратно на диск с помощью AVAssetWriter. Я хотел бы отметить, что если я установил компонент ComponentSubType на AudioComponentDescription моего выходного узла как RemoteIO, все будет правильно воспроизводиться, если динамики. Это делает меня уверенным в том, что мой AUGraph настроен правильно, так как я слышу, как все работает. Я устанавливаю subType в GenericOutput, хотя я могу сделать рендеринг самостоятельно и вернуть отрегулированный звук.ошибка преобразования AudioBufferList в CMBlockBufferRef
Я читаю аудио, и я передаю CMSampleBufferRef в copyBuffer. Это помещает аудио в круговой буфер, который будет читаться позже.
- (void)copyBuffer:(CMSampleBufferRef)buf {
if (_readyForMoreBytes == NO)
{
return;
}
AudioBufferList abl;
CMBlockBufferRef blockBuffer;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(buf, NULL, &abl, sizeof(abl), NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer);
UInt32 size = (unsigned int)CMSampleBufferGetTotalSampleSize(buf);
BOOL bytesCopied = TPCircularBufferProduceBytes(&circularBuffer, abl.mBuffers[0].mData, size);
if (!bytesCopied){
/
_readyForMoreBytes = NO;
if (size > kRescueBufferSize){
NSLog(@"Unable to allocate enought space for rescue buffer, dropping audio frame");
} else {
if (rescueBuffer == nil) {
rescueBuffer = malloc(kRescueBufferSize);
}
rescueBufferSize = size;
memcpy(rescueBuffer, abl.mBuffers[0].mData, size);
}
}
CFRelease(blockBuffer);
if (!self.hasBuffer && bytesCopied > 0)
{
self.hasBuffer = YES;
}
}
Далее я вызываю processOutput. Это сделает ручную перезагрузку на outputUnit. Когда вызывается AudioUnitRender, он вызывает приведенный ниже список воспроизведения. Это то, что подключено как обратный вызов ввода на моем первом узле. playbackCallback вытаскивает данные из кругового буфера и передает его в передаваемый audioBufferList. Как я уже говорил, если выход установлен как RemoteIO, это приведет к правильному воспроизведению звука на динамиках. Когда AudioUnitRender заканчивается, он возвращает noErr, а объект bufferList содержит достоверные данные. Когда я вызываю CMSampleBufferSetDataBufferFromAudioBufferList, хотя я получаю kCMSampleBufferError_RequiredParameterMissing (-12731).
-(CMSampleBufferRef)processOutput
{
if(self.offline == NO)
{
return NULL;
}
AudioUnitRenderActionFlags flags = 0;
AudioTimeStamp inTimeStamp;
memset(&inTimeStamp, 0, sizeof(AudioTimeStamp));
inTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
UInt32 busNumber = 0;
UInt32 numberFrames = 512;
inTimeStamp.mSampleTime = 0;
UInt32 channelCount = 2;
AudioBufferList *bufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList)+sizeof(AudioBuffer)*(channelCount-1));
bufferList->mNumberBuffers = channelCount;
for (int j=0; j<channelCount; j++)
{
AudioBuffer buffer = {0};
buffer.mNumberChannels = 1;
buffer.mDataByteSize = numberFrames*sizeof(SInt32);
buffer.mData = calloc(numberFrames,sizeof(SInt32));
bufferList->mBuffers[j] = buffer;
}
CheckError(AudioUnitRender(outputUnit, &flags, &inTimeStamp, busNumber, numberFrames, bufferList), @"AudioUnitRender outputUnit");
CMSampleBufferRef sampleBufferRef = NULL;
CMFormatDescriptionRef format = NULL;
CMSampleTimingInfo timing = { CMTimeMake(1, 44100), kCMTimeZero, kCMTimeInvalid };
AudioStreamBasicDescription audioFormat = self.audioFormat;
CheckError(CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &audioFormat, 0, NULL, 0, NULL, NULL, &format), @"CMAudioFormatDescriptionCreate");
CheckError(CMSampleBufferCreate(kCFAllocatorDefault, NULL, false, NULL, NULL, format, numberFrames, 1, &timing, 0, NULL, &sampleBufferRef), @"CMSampleBufferCreate");
CheckError(CMSampleBufferSetDataBufferFromAudioBufferList(sampleBufferRef, kCFAllocatorDefault, kCFAllocatorDefault, 0, bufferList), @"CMSampleBufferSetDataBufferFromAudioBufferList");
return sampleBufferRef;
}
static OSStatus playbackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
int numberOfChannels = ioData->mBuffers[0].mNumberChannels;
SInt16 *outSample = (SInt16 *)ioData->mBuffers[0].mData;
/
memset(outSample, 0, ioData->mBuffers[0].mDataByteSize);
MyAudioPlayer *p = (__bridge MyAudioPlayer *)inRefCon;
if (p.hasBuffer){
int32_t availableBytes;
SInt16 *bufferTail = TPCircularBufferTail([p getBuffer], &availableBytes);
int32_t requestedBytesSize = inNumberFrames * kUnitSize * numberOfChannels;
int bytesToRead = MIN(availableBytes, requestedBytesSize);
memcpy(outSample, bufferTail, bytesToRead);
TPCircularBufferConsume([p getBuffer], bytesToRead);
if (availableBytes <= requestedBytesSize*2){
[p setReadyForMoreBytes];
}
if (availableBytes <= requestedBytesSize) {
p.hasBuffer = NO;
}
}
return noErr;
}
CMSampleBufferRef я прохожу в выглядит правомочно (ниже свалка объекта из отладчика)
CMSampleBuffer 0x7f87d2a03120 retainCount: 1 allocator: 0x103333180
invalid = NO
dataReady = NO
makeDataReadyCallback = 0x0
makeDataReadyRefcon = 0x0
formatDescription = <CMAudioFormatDescription 0x7f87d2a02b20 [0x103333180]> {
mediaType:'soun'
mediaSubType:'lpcm'
mediaSpecific: {
ASBD: {
mSampleRate: 44100.000000
mFormatID: 'lpcm'
mFormatFlags: 0xc2c
mBytesPerPacket: 2
mFramesPerPacket: 1
mBytesPerFrame: 2
mChannelsPerFrame: 1
mBitsPerChannel: 16 }
cookie: {(null)}
ACL: {(null)}
}
extensions: {(null)}
}
sbufToTrackReadiness = 0x0
numSamples = 512
sampleTimingArray[1] = {
{PTS = {0/1 = 0.000}, DTS = {INVALID}, duration = {1/44100 = 0.000}},
}
dataBuffer = 0x0
Список буфер выглядит так
Printing description of bufferList:
(AudioBufferList *) bufferList = 0x00007f87d280b0a0
Printing description of bufferList->mNumberBuffers:
(UInt32) mNumberBuffers = 2
Printing description of bufferList->mBuffers:
(AudioBuffer [1]) mBuffers = {
[0] = (mNumberChannels = 1, mDataByteSize = 2048, mData = 0x00007f87d3008c00)
}
Really в убыток здесь, надеюсь, кто-то может помочь. Спасибо,
В случае, если это имеет значение, я отлаживаю это в симуляторе ios 8.3, и звук поступает с mp4, который я снял на своем iphone 6, затем сохранен на моем ноутбуке.
Я прочитал следующие проблемы, однако все еще не напрасно, все не работает.
How to convert AudioBufferList to CMSampleBuffer?
Converting an AudioBufferList to a CMSampleBuffer Produces Unexpected Results
CMSampleBufferSetDataBufferFromAudioBufferList returning error 12731
core audio offline rendering GenericOutput
UPDATE
Я пошарил еще немного, и заметить, что, когда мой AudioBufferList прямо перед Аудио UnitRender прогонов выглядит следующим образом:
bufferList->mNumberBuffers = 2,
bufferList->mBuffers[0].mNumberChannels = 1,
bufferList->mBuffers[0].mDataByteSize = 2048
mDataByteSize является numberFrames * SizeOf (SInt32), который является 512 * 4. Когда я смотрю на AudioBufferList прошел в playbackCallback, список выглядит следующим образом:
bufferList->mNumberBuffers = 1,
bufferList->mBuffers[0].mNumberChannels = 1,
bufferList->mBuffers[0].mDataByteSize = 1024
не совсем уверен, куда идет этот другой буфер, или другой размер 1024 байта ...
если, когда я закончу вызова Реднер, если я что-то вроде этого
AudioBufferList newbuff;
newbuff.mNumberBuffers = 1;
newbuff.mBuffers[0] = bufferList->mBuffers[0];
newbuff.mBuffers[0].mDataByteSize = 1024;
и передать newbuff прочь к CMSampleBufferSetDataBufferFromAudioBufferList ошибка уходит.
Если я попробовать установить размер BufferList иметь 1 mNumberBuffers или его mDataByteSize, чтобы быть numberFrames * SizeOf (SInt16) я получаю -50 при вызове AudioUnitRender
UPDATE 2
Я подключил обратный вызов рендеринга, поэтому я могу проверять вывод, когда я воспроизвожу звук по громкоговорителям. Я заметил, что на выходе, который поступает на колонки, также есть AudioBufferList с двумя буферами, а mDataByteSize во время обратного вызова ввода - 1024, а в обратном вызове рендеринга - 2048, что является тем же, что я видел при ручном вызове AudioUnitRender. Когда я проверяю данные в обработанном AudioBufferList, я замечаю, что байты в двух буферах одинаковы, а это значит, что я могу просто игнорировать второй буфер. Но я не уверен, как справиться с тем, что данные размером 2048 после визуализации вместо 1024, когда они принимаются. Любые идеи о том, почему это может произойти? Является ли он более сырой формой после прохождения аудиогида, и поэтому размер удваивается?
Выяснил, что здесь происходит. Я принимал монофонический звук -> отправлял его на блок тангажа, который преобразовывал его в стерео. Формат, который я передавал в CMAudioFormatDescriptionCreate, был моно, и он должен был быть стерео, так как это были данные в AudioBufferList. – odyth