菜鸟教程小白 发表于 2022-12-13 05:27:11

ios - 在 iOS8 中从 gstreamer 解码基本 h264 流


                                            <p><p>我正在尝试使用 AVSampleBufferDisplayLayer 来呈现通过 UDP 连接传来的基本 h264 流。
对于一个来源,我正在使用这个 gstreamer 命令:</p>

<pre><code>gst-launch-1.0 -v videotestsrc is-live=true pattern-ball ! video/x-raw,width-120,height=90,framerate=15/1 ! x264enc tune=zerolatency ! h264parse ! video/x-h264,stream-format=byte-stream ! rtph264pay mtu=100000000 ! udpsink host=127.0.0.1 port=1234
</code></pre>

<p>客户端获取SPS和PPS参数后,读取流,将payload打包成CMBlockBuffer(带有正确的NAL头),将CMBlockBuffer打包成CMSampleBuffer,然后将CMSampleBuffer传递给AVSampleBufferDisplayLayer。 <a href="https://stackoverflow.com/questions/25980070/how-to-use-avsamplebufferdisplaylayer-in-ios-8-for-rtp-h264-streams-with-gstream" rel="noreferrer noopener nofollow">This post on using the AVSampleBufferDisplayLayer</a>提供了一个很好的例子来执行这个,我的原型(prototype)实现非常相似。对于这个基本情况,它工作得很好,而且我的非常小的 (120x90) 视频可以完美呈现。</p>

<p><strong>但是</strong>,当我尝试提高源视频的分辨率时,一切都崩溃了。
在 400x300 分辨率的视频中,我开始在每个访问单元分隔符数据包之间获取 4 个 NAL 单元(每个单元在一个单独的 UDP 数据包中)。我希望这些 NAL 单元中的每一个现在都代表最终帧的一部分,而不是整个帧。因此,我正在收集一帧的所有切片并将它们捆绑到单个 CMSampleBuffer 中以传递给 AVSampleBufferDisplayLayer。</p>

<p>捆绑切片时,AVSampleBufferDisplayLayer 不渲染任何内容。
当切片作为单独的 CMSampleBuffers 单独传递到图层时,AVSampleBufferDisplayLayer 显示大部分为绿色,顶部有一条闪烁的黑色 strip 。</p>

<p>这是在将数据包数据发送到 AVSampleBufferDisplayLayer 之前捆绑数据包数据的代码:</p>

<pre><code>-(void)udpStreamSource:(UdpSource*)source didReceiveCodedSlicePacket:(NSData*)packet withPayloadOffset:(NSInteger)payloadOffset withPayloadLength:(NSInteger)payloadLength {
    const size_t nalLength = payloadLength+4;
    uint8_t *videoData = malloc(sizeof(uint8_t)*nalLength);

    // first byte of payload is NAL header byte
    ;
    // prepend payloadLength to NAL
    videoData = (uint8_t)(payloadLength &gt;&gt; 24);
    videoData = (uint8_t)(payloadLength &gt;&gt; 16);
    videoData = (uint8_t)(payloadLength &gt;&gt; 8);
    videoData = (uint8_t) payloadLength;

    sliceSizes = nalLength;
    sliceList = videoData;
}

-(void)udpStreamSource:(UdpSource*)source didReceiveAccessUnitDelimiter:(NSData*)packet {
    if (sliceCount &lt;= 0) {
      return;
    }
    CMBlockBufferRef videoBlock = NULL;
    OSStatus status = CMBlockBufferCreateWithMemoryBlock(NULL, sliceList, sliceSizes, NULL, NULL, 0, sliceSizes, 0, &amp;videoBlock);
    if (status != noErr) {
      NSLog(@&#34;CMBlockBufferCreateWithMemoryBlock failed with error: %d&#34;, status);
    }

    for (int i=1; i &lt; sliceCount; i++) {
      status = CMBlockBufferAppendMemoryBlock(videoBlock, sliceList, sliceSizes, NULL, NULL, 0, sliceSizes, 0);
      if (status != noErr) {
            NSLog(@&#34;CMBlockBufferAppendMemoryBlock failed with error: %d&#34;, status);
      }
    }

    CMSampleBufferRef sampleBuffer = NULL;
    status = CMSampleBufferCreate(NULL, videoBlock, TRUE, NULL, NULL, _formatDescription, sliceCount, 0, NULL, sliceCount, sliceSizes, &amp;sampleBuffer);
    if (status != noErr) {
      NSLog(@&#34;CMSampleBufferCreate failed with error: %d&#34;, status);
    }

    CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
    CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
    CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);

    sliceCount = 0;
    // videoLayer is an AVSampleBufferDisplayLayer
    ;
    ;
}
</code></pre>

<p>任何帮助或想法将不胜感激。</p>

<p>请注意,当我使用低分辨率视频源时,实现效果很好。只有当我提高视频源的分辨率时才会遇到问题。</p>

<p>我也尝试过使用 VTDecompressionSession 来解码数据。在那种情况下,解码器给了我没有错误的帧,但我无法弄清楚如何将它们渲染到屏幕上。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>原来问题出在 get-launch-1.0 管道的“mtu=100000000”部分。</p>

<p>Gstreamer 会尝试发送大于网络处理能力的数据包。尽管 udp 上的理论数据包大小限制约为 65k,但网络(甚至操作系统)可能会施加其自己的“最大传输单元”限制。我确定我使用的网络的 MTU 为 1492。</p>

<p>因此,为了使数据正确传输(并成功接收所有数据包),我不得不将 MTU 更改为更小的尺寸。我选择了 1400。在客户端,这意味着 NAL 单元将在 FU-A 类型 NAL 结构中的多个 RTP 数据包中分段。因此,我必须将这些数据包聚合成原始的全尺寸 NAL,然后再将它们发送到解码器。</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 在 iOS8 中从 gstreamer 解码基本 h264 流,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/28680535/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/28680535/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 在 iOS8 中从 gstreamer 解码基本 h264 流