Декодируйте поток H264 с помощью API VideoToolbox (kVTVideoDecoderBadDataErr) - PullRequest
2 голосов
/ 21 июня 2020

моя цель - закодировать основной буфер кадра моей Windows машины с помощью nven c и передать его содержимое на мой iPad с помощью API VideoToolbox

Код, который я использую для кодирования потока h264, в основном копирование / вставка https://github.com/NVIDIA/video-sdk-samples/tree/master/nvEncDXGIOutputDuplicationSample единственное изменение состоит в том, что вместо записи в файл я отправляю данные

Для декодирования я использую https://github.com/zerdzhong/SwfitH264Demo/blob/master/SwiftH264/ViewController.swift#L71

Кодирование работает отлично, когда я записываю все содержимое в файл, я могу без проблем использовать онлайн-конвертер h264-> mp4, проблема в том, что декодер выдает мне ошибку kVTVideoDecoderBadDataErr в function decopressionSessionDecodeFrameCallback

Итак, для того, что я пробовал:

  • Сначала, используя анализатор h264, я обнаружил, что порядок кадров: 7/8/5/5/5/5/1. ..
  • Я обнаружил, что nven c кодирует фреймы 7/8/5/5/5/5 только в одном пакете
  • Я попытался разделить этот пакет на несколько используя последовательность (0x00 0x00 0x00 0x01), он дал мне fr ames 7/8/5 отдельно
  • Как вы можете видеть, у меня есть только один 5 кадров, который составляет около 100 КБ, анализатор H264 сказал, что есть четыре 5 кадра (что-то вроде 40 КБ, 20 КБ, 30 КБ, 10 КБ )
  • Используя программу просмотра шестнадцатеричных файлов, я увидел, что последовательность, разделяющая эти 5 кадров, была (0x00 0x00 0x01) вместо этого, я попытался также разделить их, но при распаковке
я получил ту же самую ошибку VideoToolbox

вот код, который я использую для разделения и отправки кадров: Протокол просто PACKET_SIZE-> PACKET_DATA. Быстрый код может читать типы NALU, поэтому я уверен, что это не проблема

    unsafe {
        Setup();
        loop {
            CaptureFrame();

            let frame_count = GetDataCount();
            if frame_count == 0 {
                continue;
            }

            for i in 0..frame_count {
                let size = RetrieveDataSize(i as i32);
                let size_slice = &(u32::to_le_bytes(size as u32));

                let data = RetrieveData(i as i32);
                let data_slice = std::slice::from_raw_parts(data, size);

                let mut last_frame = 0;

                for x in 0..size {
                    if data_slice[x] == 0 &&
                        data_slice[x + 1] == 0 &&
                        data_slice[x + 2] == 0 &&
                        data_slice[x + 3] == 1 {
                        let frame_size = x - last_frame;
                        if frame_size > 0 {
                            let frame_data = &data_slice[last_frame..x];
                            stream.write(&(u32::to_le_bytes(frame_size as u32))).unwrap();
                            stream.write(frame_data).unwrap();
                            println!("SEND MULTIPLE {}", frame_size);
                        }

                        last_frame = x;
                        println!("NALU {}", data_slice[x + 4] & 0x1F);
                        //println!("TEST {} {}",i, size);
                        continue;
                    }
                }
                // Packet was a single frame
                let frame_size = size - last_frame;
                let frame_data = &data_slice[last_frame..size];
                stream.write(&(u32::to_le_bytes(frame_size as u32))).unwrap();
                stream.write(frame_data).unwrap();
                println!("SEND SINGLE {} {}", last_frame, size);
            }
        }
    }

Это может быть связано с форматом текстуры, VideoToolbox упоминает kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, а в кодах NVEN C упоминаются YUV420 и NV12, я не уверен, одинаковы они или нет

Вот мое описание :

Optional(<CMVideoFormatDescription 0x2823dd410 [0x1e0921e20]> {
    mediaType:'vide' 
    mediaSubType:'avc1' 
    mediaSpecific: {
        codecType: 'avc1'       dimensions: 3840 x 2160 
    } 
    extensions: {{
    CVFieldCount = 1;
    CVImageBufferChromaLocationBottomField = Left;
    CVImageBufferChromaLocationTopField = Left;
    CVPixelAspectRatio =     {
        HorizontalSpacing = 1;
        VerticalSpacing = 1;
    };
    FullRangeVideo = 0;
    SampleDescriptionExtensionAtoms =     {
        avcC = {length = 41, bytes = 0x01640033 ffe10016 67640033 ac2b401e ... 68ee3cb0 fdf8f800 };
    };
}}
})

1 Ответ

0 голосов
/ 24 июня 2020

Хорошо, как бы странно это ни звучало, но мой код работает на симуляторе, но не на моем iPad Pro. В конце концов, он работает, поэтому я все равно отмечу его как правильный ответ

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