1、rtp协议头
2、rtp可以基于TCP或者UDP
其中基于TCP需要加4个字节的RTP标志
3、rtph264depay定义解析函数gst_rtp_h264_depay_process,通过RFC 3984文档实现。
static void
gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
{GObjectClass *gobject_class;GstElementClass *gstelement_class;GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;gobject_class = (GObjectClass *) klass;gstelement_class = (GstElementClass *) klass;gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;gobject_class->finalize = gst_rtp_h264_depay_finalize;gobject_class->set_property = gst_rtp_h264_depay_set_property;gobject_class->get_property = gst_rtp_h264_depay_get_property;/*** GstRtpH264Depay:wait-for-keyframe:** Wait for the next keyframe after packet loss,* meaningful only when outputting access units** Since: 1.20*/g_object_class_install_property (gobject_class, PROP_WAIT_FOR_KEYFRAME,g_param_spec_boolean ("wait-for-keyframe", "Wait for Keyframe","Wait for the next keyframe after packet loss, meaningful only when ""outputting access units",DEFAULT_WAIT_FOR_KEYFRAME,G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));/*** GstRtpH264Depay:request-keyframe:** Request new keyframe when packet loss is detected** Since: 1.20*/g_object_class_install_property (gobject_class, PROP_REQUEST_KEYFRAME,g_param_spec_boolean ("request-keyframe", "Request Keyframe","Request new keyframe when packet loss is detected",DEFAULT_REQUEST_KEYFRAME,G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));gst_element_class_add_static_pad_template (gstelement_class,&gst_rtp_h264_depay_src_template);gst_element_class_add_static_pad_template (gstelement_class,&gst_rtp_h264_depay_sink_template);gst_element_class_set_static_metadata (gstelement_class,"RTP H264 depayloader", "Codec/Depayloader/Network/RTP","Extracts H264 video from RTP packets (RFC 3984)","Wim Taymans <wim.taymans@gmail.com>");gstelement_class->change_state = gst_rtp_h264_depay_change_state;gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_h264_depay_process;gstrtpbasedepayload_class->set_caps = gst_rtp_h264_depay_setcaps;gstrtpbasedepayload_class->handle_event = gst_rtp_h264_depay_handle_event;
}
4、gst_rtp_h264_depay_process的具体实现
static GstBuffer *
gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{GstRtpH264Depay *rtph264depay;GstBuffer *outbuf = NULL;guint8 nal_unit_type;rtph264depay = GST_RTP_H264_DEPAY (depayload);if (!rtph264depay->merge)rtph264depay->waiting_for_keyframe = FALSE;/* 是否是弃用数据 */if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {gst_adapter_clear (rtph264depay->adapter);rtph264depay->wait_start = TRUE;rtph264depay->current_fu_type = 0;rtph264depay->last_fu_seqnum = 0;if (rtph264depay->merge && rtph264depay->wait_for_keyframe) {rtph264depay->waiting_for_keyframe = TRUE;}if (rtph264depay->request_keyframe)gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,TRUE, 0));}{gint payload_len;guint8 *payload;guint header_len;guint8 nal_ref_idc;GstMapInfo map;guint outsize, nalu_size;GstClockTime timestamp;gboolean marker;timestamp = GST_BUFFER_PTS (rtp->buffer);payload_len = gst_rtp_buffer_get_payload_len (rtp);payload = gst_rtp_buffer_get_payload (rtp);marker = gst_rtp_buffer_get_marker (rtp);GST_DEBUG_OBJECT (rtph264depay, "receiving %d bytes", payload_len);if (payload_len == 0)goto empty_packet;/* +---------------+* |0|1|2|3|4|5|6|7|* +-+-+-+-+-+-+-+-+* |F|NRI| Type |* +---------------+** F must be 0.*/nal_ref_idc = (payload[0] & 0x60) >> 5;nal_unit_type = payload[0] & 0x1f;/* at least one byte header with type */header_len = 1;GST_DEBUG_OBJECT (rtph264depay, "NRI %d, Type %d %s", nal_ref_idc, nal_unit_type, marker ? "marker" : "");/* If FU unit was being processed, but the current nal is of a different* type. Assume that the remote payloader is buggy (didn't set the end bit* when the FU ended) and send out what we gathered thusfar */if (G_UNLIKELY (rtph264depay->current_fu_type != 0 && nal_unit_type != rtph264depay->current_fu_type))gst_rtp_h264_finish_fragmentation_unit (rtph264depay);switch (nal_unit_type) {case 0:case 30:case 31:/* undefined */goto undefined_type;case 25:/* STAP-B Single-time aggregation packet 5.7.1 *//* 2 byte extra header for DON */header_len += 2;/* fallthrough */case 24:{/* strip headers */payload += header_len;payload_len -= header_len;rtph264depay->wait_start = FALSE;/* STAP-A Single-time aggregation packet 5.7.1 */while (payload_len > 2) {gboolean last = FALSE;/* 1* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+* | NALU Size |* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/nalu_size = (payload[0] << 8) | payload[1];/* don't include nalu_size */if (nalu_size > (payload_len - 2))nalu_size = payload_len - 2;outsize = nalu_size + sizeof (sync_bytes);outbuf = gst_buffer_new_and_alloc (outsize);gst_buffer_map (outbuf, &map, GST_MAP_WRITE);if (rtph264depay->byte_stream) {memcpy (map.data, sync_bytes, sizeof (sync_bytes));} else {map.data[0] = map.data[1] = 0;map.data[2] = payload[0];map.data[3] = payload[1];}/* strip NALU size */payload += 2;payload_len -= 2;memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);gst_buffer_unmap (outbuf, &map);gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);if (payload_len - nalu_size <= 2)last = TRUE;gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,marker && last);payload += nalu_size;payload_len -= nalu_size;}break;}case 26:/* MTAP16 Multi-time aggregation packet 5.7.2 */// header_len = 5;/* fallthrough, not implemented */case 27:/* MTAP24 Multi-time aggregation packet 5.7.2 */// header_len = 6;goto not_implemented;break;case 28:case 29:{/* FU-A Fragmentation unit 5.8 *//* FU-B Fragmentation unit 5.8 */gboolean S, E;/* +---------------+* |0|1|2|3|4|5|6|7|* +-+-+-+-+-+-+-+-+* |S|E|R| Type |* +---------------+** R is reserved and always 0*/S = (payload[1] & 0x80) == 0x80;E = (payload[1] & 0x40) == 0x40;GST_DEBUG_OBJECT (rtph264depay, "S %d, E %d", S, E);if (rtph264depay->wait_start && !S)goto waiting_start;if (S) {/* NAL unit starts here */guint8 nal_header;/* If a new FU unit started, while still processing an older one.* Assume that the remote payloader is buggy (doesn't set the end* bit) and send out what we've gathered thusfar */if (G_UNLIKELY (rtph264depay->current_fu_type != 0))gst_rtp_h264_finish_fragmentation_unit (rtph264depay);rtph264depay->current_fu_type = nal_unit_type;rtph264depay->fu_timestamp = timestamp;rtph264depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp);rtph264depay->wait_start = FALSE;/* reconstruct NAL header */nal_header = (payload[0] & 0xe0) | (payload[1] & 0x1f);/* strip type header, keep FU header, we'll reuse it to reconstruct* the NAL header. */payload += 1;payload_len -= 1;nalu_size = payload_len;outsize = nalu_size + sizeof (sync_bytes);outbuf = gst_buffer_new_and_alloc (outsize);gst_buffer_map (outbuf, &map, GST_MAP_WRITE);memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);map.data[sizeof (sync_bytes)] = nal_header;gst_buffer_unmap (outbuf, &map);gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);/* and assemble in the adapter */gst_adapter_push (rtph264depay->adapter, outbuf);} else {if (rtph264depay->current_fu_type == 0) {/* previous FU packet missing start bit? */GST_WARNING_OBJECT (rtph264depay, "missing FU start bit on an ""earlier packet. Dropping.");gst_adapter_clear (rtph264depay->adapter);return NULL;}if (gst_rtp_buffer_compare_seqnum (rtph264depay->last_fu_seqnum,gst_rtp_buffer_get_seq (rtp)) != 1) {/* jump in sequence numbers within an FU is cause for discarding */GST_WARNING_OBJECT (rtph264depay, "Jump in sequence numbers from ""%u to %u within Fragmentation Unit. Data was lost, dropping ""stored.", rtph264depay->last_fu_seqnum,gst_rtp_buffer_get_seq (rtp));gst_adapter_clear (rtph264depay->adapter);return NULL;}rtph264depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp);/* strip off FU indicator and FU header bytes */payload += 2;payload_len -= 2;outsize = payload_len;outbuf = gst_buffer_new_and_alloc (outsize);gst_buffer_fill (outbuf, 0, payload, outsize);gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);/* and assemble in the adapter */gst_adapter_push (rtph264depay->adapter, outbuf);}outbuf = NULL;rtph264depay->fu_marker = marker;/* if NAL unit ends, flush the adapter */if (E)gst_rtp_h264_finish_fragmentation_unit (rtph264depay);break;}default:{rtph264depay->wait_start = FALSE;/* 1-23 NAL unit Single NAL unit packet per H.264 5.6 *//* the entire payload is the output buffer */nalu_size = payload_len;outsize = nalu_size + sizeof (sync_bytes);outbuf = gst_buffer_new_and_alloc (outsize);gst_buffer_map (outbuf, &map, GST_MAP_WRITE);if (rtph264depay->byte_stream) {memcpy (map.data, sync_bytes, sizeof (sync_bytes));} else {map.data[0] = map.data[1] = 0;map.data[2] = nalu_size >> 8;map.data[3] = nalu_size & 0xff;}memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);gst_buffer_unmap (outbuf, &map);gst_rtp_copy_video_meta (rtph264depay, outbuf, rtp->buffer);gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp, marker);break;}}}return NULL;/* ERRORS */
empty_packet:{GST_DEBUG_OBJECT (rtph264depay, "empty packet");return NULL;}
undefined_type:{GST_ELEMENT_WARNING (rtph264depay, STREAM, DECODE,(NULL), ("Undefined packet type"));return NULL;}
waiting_start:{GST_DEBUG_OBJECT (rtph264depay, "waiting for start");return NULL;}
not_implemented:{GST_ELEMENT_ERROR (rtph264depay, STREAM, FORMAT,(NULL), ("NAL unit type %d not supported yet", nal_unit_type));return NULL;}
}