![](/img/trans.png)
[英]How do I add async=false in python to a Gstreamer splitmuxsink element Audio/video/H264 combined
[英]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 個字節( AVCPacketType
和CompositionTime
字段):
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。
我缺少的第三件事是正確的dts
和pts
值。 結果我給出的 RTMP 時間戳是dts
和pts = AVCVIDEOPACKET.CompositionTime + dts
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.