Проблемы с памятью с [AVAssetWriterInput requestMediaDataWhenReadyOnQueue: usingBlock:] - PullRequest
3 голосов
/ 23 января 2012

Я пишу библиотеку для экспорта ресурсов в файл с помощью AVFoundation.Я создаю устройство чтения, записи, подключаю к ним входы и выходы, а затем вызываю метод requestMediaDataWhenReadyOnQueue на входах, чтобы начать извлечение данных.Обратный вызов блока, предоставленный этому методу, выглядит примерно так:

[input requestMediaDataWhenReadyOnQueue:queue usingBlock:^{
    while ([input isReadyForMoreMediaData]) {
        CMSampleBufferRef buffer;
        // The track has some more data for us
        if ([reader status] == AVAssetReaderStatusReading
               && (buffer = [output copyNextSampleBuffer])) {
            BOOL result = [input appendSampleBuffer:buffer];
            CFRelease(buffer);
            if (!result) {
                // handle error
                break;
            }
        // The track is finished, for whatever reason
        } else {
            [input markAsFinished]; ⬅
            switch ([reader status]) {
                // inspect the status and act accordingly
            }
        }
    }
}];

Это прекрасно работает на iOS 5, но на iOS 4 код умирает от EXC_BAD_ACCESS после строки, отмеченной стрелкой..После некоторого возни, я чувствую, что блок был как-то разрушен сразу после того, как пометил ввод как завершенный.Указатель self, который является совершенно допустимым перед выполнением неверной строки, каким-то образом превращается в 0xfff… или в какое-то значение мусора, сообщаемое отладчиком.Но объект, на который он указывал ранее, в порядке, что подтверждается инструментом зомби, он не освобождается.

Чего мне не хватает?

Ответы [ 2 ]

1 голос
/ 24 января 2012

Видя ту же (похожую) проблему. iOS5 доволен, iOS4.3.5, не доволен. Заинтересованы в том, чтобы узнать, что вы в конечном итоге найдете.

Обошли его, явно сохранив запись, запись, чтение, чтение перед блоком requestMedatWhenReadyOnQueue и явно освободив все четыре в самом конце предложения else.

Док говорит, что после завершения маркировки "Блок должен выйти". Может быть, они не шутят. Если вы делаете что-то кроме выхода, это ошибка. Похоже, что вышеуказанный обходной путь работает.

ОБНОВЛЕНИЕ: Я все же обнаружил, что он иногда зависал даже после сохранения и освобождения всех объектов актива. Как видно из вашего вопроса, он вылетает вскоре после того, как вы помечаете ввод средства записи как завершенный, как если бы сам блок был освобожден. Вместо того, чтобы просто передать блок как часть функции. Я создаю скопированное свойство блока, которое является частью долгоживущего объекта. Я инициализирую его с помощью Block_copy и освобождаю его только в деструкторе долгоживущего объекта. Это, кажется, делает трюк. С тех пор я не видел сбоев 4.3.5.

0 голосов
/ 10 мая 2012

Попробуйте [self retain] в качестве первой строки блока и [self release] в качестве последней строки.

Другая критическая проблема заключается в том, что если приложение приостановлено (входит в фоновый режим) с использованием requestMediaDataWhenReadyOnQueue, вам необходимо явно охватить все значения [читательский статус], так как при перезапуске приложения произойдет сбой. В некоторых случаях я обнаружил, что блок запускался более одного раза с флагом ошибки. В других постах со схожим кодом есть много [сохраняющих] AV-переменных, которые затем освобождаются в конце блока. Поскольку блок может запускаться более одного раза, этот подход не работает в случаях, когда приложение переходит в фоновое состояние.

Я нашел следующее, чтобы хорошо работать в "переключателе" (выше):

                case AVAssetReaderStatusReading:
                    break;

                case AVAssetReaderStatusCompleted:
                    [videoWriterInput markAsFinished];
                    //do something else, like add an audio stream
                    [videoWriter finishWriting];
                    break;

                case AVAssetReaderStatusFailed:
                    [videoWriterInput markAsFinished];
                    [videoWriter finishWriting];
                    break;

                case AVAssetReaderStatusCancelled:
                case AVAssetReaderStatusUnknown:
                    [videoWriterInput markAsFinished];
                    [videoWriter cancelWriting];
                    break;
            }

            dispatch_sync(dispatch_get_main_queue(), ^{
              //hide any progress indicators
            });

            break;

кроме "я", ничего не сохраняется. Блок должен автоматически сохранять переменные, если они необходимы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...