簡體   English   中英

如何正確地將 FLV 視頻解包為 gstreamer 緩沖區的原始有效 h264 段?

[英]How do I properly unwrap FLV video into raw and valid h264 segments for gstreamer buffers?

我在rust寫了一個RTMP服務器成功讓RTMP發布者連接,推送一個視頻stream,RTMP客戶端可以連接成功觀看那些視頻流。

當視頻 RTMP 數據包傳入時,我嘗試通過以下方式從 FLV 容器中解包視頻:

    // TODO: The FLV spec has the AVCPacketType and composition time as the first parts of the
    // AVCPACKETTYPE.  It's unclear if these two fields are part of h264 or FLV specific. 
    let flv_tag = data.split_to(1);
    let is_sequence_header;
    let codec = if flv_tag[0] & 0x07 == 0x07 {
        is_sequence_header = data[0] == 0x00;
        VideoCodec::H264
    } else {
        is_sequence_header = false;
        VideoCodec::Unknown
    };

    let is_keyframe = flv_tag[0] & 0x10 == 0x10;

在此運行之后, data包含刪除了 flv 標簽的AVCVIDEOPACKET 當我將此視頻發送到其他 RTMP 客戶端時,我只是在其前面加上正確的 flv 標簽並將其發送出去。

現在我正在嘗試將視頻數據包傳遞給 gstreamer,以便進行進程轉碼。 為此,我設置了一個appsrc | avdec_264 appsrc | avdec_264管道,並為appsrc組件提供以下上限:

        video_source.set_caps(Some(
            &Caps::builder("video/x-h264")
                .field("alignment", "nal")
                .field("stream-format", "byte-stream")
                .build()
        ));

現在,當 RTMP 發布者發送視頻數據包時,我將(嘗試)解包視頻數據包並通過以下方式將其傳遞到我的appsrc

    pub fn push_video(&self, data: Bytes, timestamp: RtmpTimestamp) {
        let mut buffer = Buffer::with_size(data.len()).unwrap();
        {
            let buffer = buffer.get_mut().unwrap();
            buffer.set_pts(ClockTime::MSECOND * timestamp.value as u64);

            let mut samples = buffer.map_writable().unwrap();
            {
                let samples = samples.as_mut_slice();
                for index in 0..data.len() {
                    samples[index] = data[index];
                }
            }
        }

        self.video_source.push_buffer(buffer).unwrap();
    }

發生這種情況時,會出現以下 gstreamer 調試 output

2022-02-09T18:25:15Z INFO  gstreamer_mmids_scratchpad] Pushing packet #0 (is_sequence_header:true, is_keyframe=true)
[2022-02-09T18:25:15Z INFO  gstreamer_mmids_scratchpad] Connection 63397d56-16fb-4b54-a622-d991b5ad2d8e sent audio data
0:00:05.531722000  7516 000001C0C04011C0 INFO               GST_EVENT gstevent.c:973:gst_event_new_segment: creating segment event bytes segment start=0, offset=0, stop=-1, rate=1.000000, applied_rate=1.000000, flags=0x00, time=0, base=0, position 0, duration -1
0:00:05.533525000  7516 000001C0C04011C0 INFO                 basesrc gstbasesrc.c:3018:gst_base_src_loop:<video_source> marking pending DISCONT
0:00:05.535385000  7516 000001C0C04011C0 WARN            videodecoder gstvideodecoder.c:2818:gst_video_decoder_chain:<video_decode> Received buffer without a new-segment. Assuming timestamps start from 0.
0:00:05.537381000  7516 000001C0C04011C0 INFO               GST_EVENT gstevent.c:973:gst_event_new_segment: creating segment event time segment start=0:00:00.000000000, offset=0:00:00.000000000, stop=99:99:99.999999999, rate=1.000000, applied_rate=1.000000, flags=0x00, time=0:00:00.000000000, base=0:00:00.000000000, position 0:00:00.000000000, duration 99:99:99.999999999
[2022-02-09T18:25:15Z INFO  gstreamer_mmids_scratchpad] Pushing packet #1 (is_sequence_header:false, is_keyframe=true)
0:00:05.563445000  7516 000001C0C04011C0 INFO                   libav :0:: Invalid NAL unit 0, skipping.
[2022-02-09T18:25:15Z INFO  gstreamer_mmids_scratchpad] Pushing packet #2 (is_sequence_header:false, is_keyframe=false)
0:00:05.579274000  7516 000001C0C04011C0 ERROR                  libav :0:: No start code is found.
0:00:05.581338000  7516 000001C0C04011C0 ERROR                  libav :0:: Error splitting the input into NAL units.
0:00:05.583337000  7516 000001C0C04011C0 WARN                   libav gstavviddec.c:2068:gst_ffmpegviddec_handle_frame:<video_decode> Failed to send data for decoding
[2022-02-09T18:25:15Z INFO  gstreamer_mmids_scratchpad] Pushing packet #3 (is_sequence_header:false, is_keyframe=false)
0:00:05.595253000  7516 000001C0C04011C0 ERROR                  libav :0:: No start code is found.
0:00:05.597204000  7516 000001C0C04011C0 ERROR                  libav :0:: Error splitting the input into NAL units.
0:00:05.599262000  7516 000001C0C04011C0 WARN                   libav gstavviddec.c:2068:gst_ffmpegviddec_handle_frame:<video_decode> Failed to send data for decoding

基於此,我認為這可能是由於AVCVIDEOPACKET的非數據部分不是 h264 流的一部分,而是 FLV 特定流引起的。 所以我嘗試忽略我寫入緩沖區的每個數據包的前 4 個字節( AVCPacketTypeCompositionTime字段):

    pub fn push_video(&self, data: Bytes, timestamp: RtmpTimestamp) {
        let mut buffer = Buffer::with_size(data.len() - 4).unwrap();
        {
            let buffer = buffer.get_mut().unwrap();
            buffer.set_pts(ClockTime::MSECOND * timestamp.value as u64);

            let mut samples = buffer.map_writable().unwrap();
            {
                let samples = samples.as_mut_slice();
                for index in 4..data.len() {
                    samples[index - 4] = data[index];
                }
            }
        }

        self.video_source.push_buffer(buffer).unwrap();
    }

這基本上給了我相同的日志記錄 output 和錯誤。 這也可以通過h264parse插件重現。

在將原始 h264 視頻傳遞給 gstreamer 的展開過程中,我缺少什么?

編輯:

意識到我誤讀了 pad 模板,我嘗試了以下大寫字母

        video_source.set_caps(Some(
            &Caps::builder("video/x-h264")
                .field("alignment", "au")
                .field("stream-format", "avc")
                .build()
        ));

這也因非常相似的 output 而失敗。

我想我終於想通了。

第一件事是我需要包括刪除AVCVIDEOPACKET標頭(數據包類型和組合時間字段)。 這些不是 h264 格式的一部分,因此會導致解析錯誤。

我需要做的第二件事是不要將序列 header 作為緩沖區傳遞給源。 相反,序列 header 字節需要設置為appsrc的 caps 的codec_data字段。 這現在允許在將視頻數據傳遞給h264parse時沒有解析錯誤,甚至給我一個正確大小的 window。

我缺少的第三件事是正確的dtspts值。 結果我給出的 RTMP 時間戳是dtspts = AVCVIDEOPACKET.CompositionTime + dts

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM