NSData over GameKit и EXC_BAD_ACCESS странная проблема - PullRequest
1 голос
/ 05 декабря 2010

Я пытаюсь транслировать видеоданные по одноранговому соединению, созданному с помощью GameKit. У меня есть метод, который получает объект NSData и использует его для рисования видеопотока на CALayer:

- (void)recieveVideoFromData:(NSData *)data;

Вот первые несколько строк этого метода, которые преобразуют NSData в CMSampleBufferRefs и начинают обработку:

CMSampleBufferRef imgData = (CMSampleBufferRef)data.bytes;
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(imgData); 
CVPixelBufferLockBaseAddress(imageBuffer,0); 

Теперь, когда я передаю видеопоток с локальной камеры в этот метод следующим образом, все работает просто отлично, и видеопоток отображается на экране:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { 
    NSData *data = [[NSData alloc] initWithBytes:sampleBuffer length:malloc_size(sampleBuffer)];
    [self recieveVideoFromData:data]; 
}

Но когда я отправляю поток этих пакетов NSData через одноранговое соединение и получаю их следующим образом, я получаю ошибку EXC_BAD_ACCESS:

- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
    [self recieveVideoFromData:data];
}

Используя отладчик, я узнал, что в этой строке происходит неправильный доступ:

CVPixelBufferLockBaseAddress(imageBuffer,0); 

Я понятия не имею, почему NSData, отправленные по сети, должны отличаться от NSData, отправленного другим методом на том же устройстве. Я проверил, что данные, полученные по сети, принимаются с тем же интервалом и имеют ту же длину (336 байт), что и данные, полученные на локальном устройстве. Я также проверил, что счетчик сохранения для объекта data равен 1, прежде чем он будет использован. Кажется, переменная imageBuffer почему-то теряется.

Пара вопросов:

  1. Является ли преобразование data.bytes в CMSampleBufferRef правильным способом распаковки NSData?

  2. Как мне утверждать, что полученные данные на самом деле являются объектом CMSampleBuffer? Я хочу защитить свой код, но не знаю, как выполнить проверку классов для базовых классов.

Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 20 февраля 2011

Почему вы «распаковываете» (это не распаковываете) свой CMSampleBuffer путем приведения байтов NSData?Это никогда не сработает, потому что CMSampleBuffer не является непрерывным блоком в памяти.

Вы должны извлечь все соответствующие данные из CMSampleBuffer перед отправкой, вставить их в объект и NSDataи повторно объедините его на другой стороне с помощью

OSStatus CMSampleBufferCreate (
    CFAllocatorRef allocator,
    CMBlockBufferRef dataBuffer,
    Boolean dataReady,
    CMSampleBufferMakeDataReadyCallback makeDataReadyCallback,
    void *makeDataReadyRefcon,
    CMFormatDescriptionRef formatDescription,
    CMItemCount numSamples,
    CMItemCount numSampleTimingEntries,
    const CMSampleTimingInfo *sampleTimingArray,
    CMItemCount numSampleSizeEntries,
    const size_t *sampleSizeArray,
    CMSampleBufferRef *sBufOut
);

Типы данных в этой функции могут дать вам подсказку, что вы хотите извлечь из CMSampleBuffer при упаковке ваших данных.

0 голосов
/ 05 декабря 2010

Возможно, это не полный ответ, но ваше использование malloc_size кажется мне огромным красным флагом.Это кажется непереносимым расширением, не управляемым чем-либо вроде ANSI, ISO или POSIX, и у меня есть некоторые сомнения относительно того, как оно может себя вести, если передаст буфер, который не пришел из malloc.Кажется, что это отрывочная вещь, на которую можно положиться.(Я бы сказал, что если доходит до вызова malloc_size, то вы уже делаете что-то не так в качестве C-кодера, поскольку C все знает о том, насколько велики ваши буферы, и не полагается на непереносимые функции libc для выполнения вашего буфера.Размер отслеживания работы для вас.)

...