X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Frtp%2Fgstrtpmp4gdepay.c;h=a734be065f972446f8bd8d9bf3ead20d2953cc65;hb=775ccdf9775bd7051929b257444b3be915e88ec6;hp=76b26872b08f142f196bec4baf9c1768937212ec;hpb=07cc855b242e8ff757786bd2320f4db74e99cdfa;p=platform%2Fupstream%2Fgst-plugins-good.git diff --git a/gst/rtp/gstrtpmp4gdepay.c b/gst/rtp/gstrtpmp4gdepay.c index 76b2687..a734be0 100644 --- a/gst/rtp/gstrtpmp4gdepay.c +++ b/gst/rtp/gstrtpmp4gdepay.c @@ -13,8 +13,8 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -26,6 +26,7 @@ #include #include "gstrtpmp4gdepay.h" +#include "gstrtputils.h" GST_DEBUG_CATEGORY_STATIC (rtpmp4gdepay_debug); #define GST_CAT_DEFAULT (rtpmp4gdepay_debug) @@ -46,14 +47,13 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_ALWAYS, GST_STATIC_CAPS ("application/x-rtp, " "media = (string) { \"video\", \"audio\", \"application\" }, " - "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MPEG4-GENERIC\", " /* required string params */ - "streamtype = (string) { \"4\", \"5\" }, " /* 4 = video, 5 = audio */ + /* "streamtype = (string) { \"4\", \"5\" }, " Not set by Wowza 4 = video, 5 = audio */ /* "profile-level-id = (string) [1,MAX], " */ /* "config = (string) [1,MAX]" */ - "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\" } " + "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\", \"aac-hbr\" } " /* Optional general parameters */ /* "objecttype = (string) [1,MAX], " */ /* "constantsize = (string) [1,MAX], " *//* constant size of each AU */ @@ -135,7 +135,7 @@ static void gst_rtp_mp4g_depay_finalize (GObject * object); static gboolean gst_rtp_mp4g_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps); static GstBuffer *gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, - GstBuffer * buf); + GstRTPBuffer * rtp); static gboolean gst_rtp_mp4g_depay_handle_event (GstRTPBaseDepayload * filter, GstEvent * event); @@ -158,16 +158,16 @@ gst_rtp_mp4g_depay_class_init (GstRtpMP4GDepayClass * klass) gstelement_class->change_state = gst_rtp_mp4g_depay_change_state; - gstrtpbasedepayload_class->process = gst_rtp_mp4g_depay_process; + gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_mp4g_depay_process; gstrtpbasedepayload_class->set_caps = gst_rtp_mp4g_depay_setcaps; gstrtpbasedepayload_class->handle_event = gst_rtp_mp4g_depay_handle_event; - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&gst_rtp_mp4g_depay_src_template)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&gst_rtp_mp4g_depay_sink_template)); + gst_element_class_add_static_pad_template (gstelement_class, + &gst_rtp_mp4g_depay_src_template); + gst_element_class_add_static_pad_template (gstelement_class, + &gst_rtp_mp4g_depay_sink_template); - gst_element_class_set_details_simple (gstelement_class, + gst_element_class_set_static_metadata (gstelement_class, "RTP MPEG4 ES depayloader", "Codec/Depayloader/Network/RTP", "Extracts MPEG4 elementary streams from RTP packets (RFC 3640)", "Wim Taymans "); @@ -233,11 +233,15 @@ gst_rtp_mp4g_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) clock_rate = 90000; /* default */ depayload->clock_rate = clock_rate; + rtpmp4gdepay->check_adts = FALSE; + if ((str = gst_structure_get_string (structure, "media"))) { if (strcmp (str, "audio") == 0) { srccaps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 4, "stream-format", G_TYPE_STRING, "raw", NULL); + rtpmp4gdepay->check_adts = TRUE; + rtpmp4gdepay->warn_adts = TRUE; } else if (strcmp (str, "video") == 0) { srccaps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4, @@ -325,10 +329,30 @@ gst_rtp_mp4g_depay_reset (GstRtpMP4GDepay * rtpmp4gdepay) } static void +gst_rtp_mp4g_depay_push_outbuf (GstRtpMP4GDepay * rtpmp4gdepay, + GstBuffer * outbuf, guint AU_index) +{ + gboolean discont = FALSE; + + if (AU_index != rtpmp4gdepay->next_AU_index) { + GST_DEBUG_OBJECT (rtpmp4gdepay, "discont, expected AU_index %u", + rtpmp4gdepay->next_AU_index); + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); + discont = TRUE; + } + + GST_DEBUG_OBJECT (rtpmp4gdepay, "pushing %sAU_index %u", + discont ? "" : "expected ", AU_index); + + gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpmp4gdepay), outbuf, 0); + gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay), outbuf); + rtpmp4gdepay->next_AU_index = AU_index + 1; +} + +static void gst_rtp_mp4g_depay_flush_queue (GstRtpMP4GDepay * rtpmp4gdepay) { GstBuffer *outbuf; - gboolean discont = FALSE; guint AU_index; while ((outbuf = g_queue_pop_head (rtpmp4gdepay->packets))) { @@ -336,20 +360,7 @@ gst_rtp_mp4g_depay_flush_queue (GstRtpMP4GDepay * rtpmp4gdepay) GST_DEBUG_OBJECT (rtpmp4gdepay, "next available AU_index %u", AU_index); - if (rtpmp4gdepay->next_AU_index != AU_index) { - GST_DEBUG_OBJECT (rtpmp4gdepay, "discont, expected AU_index %u", - rtpmp4gdepay->next_AU_index); - discont = TRUE; - } - - if (discont) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - discont = FALSE; - } - - GST_DEBUG_OBJECT (rtpmp4gdepay, "pushing AU_index %u", AU_index); - gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay), outbuf); - rtpmp4gdepay->next_AU_index = AU_index + 1; + gst_rtp_mp4g_depay_push_outbuf (rtpmp4gdepay, outbuf, AU_index); } } @@ -368,8 +379,7 @@ gst_rtp_mp4g_depay_queue (GstRtpMP4GDepay * rtpmp4gdepay, GstBuffer * outbuf) /* we received the expected packet, push it and flush as much as we can from * the queue */ - gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay), outbuf); - rtpmp4gdepay->next_AU_index++; + gst_rtp_mp4g_depay_push_outbuf (rtpmp4gdepay, outbuf, AU_index); while ((outbuf = g_queue_peek_head (rtpmp4gdepay->packets))) { AU_index = GST_BUFFER_OFFSET (outbuf); @@ -377,12 +387,8 @@ gst_rtp_mp4g_depay_queue (GstRtpMP4GDepay * rtpmp4gdepay, GstBuffer * outbuf) GST_DEBUG_OBJECT (rtpmp4gdepay, "next available AU_index %u", AU_index); if (rtpmp4gdepay->next_AU_index == AU_index) { - GST_DEBUG_OBJECT (rtpmp4gdepay, "pushing expected AU_index %u", - AU_index); outbuf = g_queue_pop_head (rtpmp4gdepay->packets); - gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay), - outbuf); - rtpmp4gdepay->next_AU_index++; + gst_rtp_mp4g_depay_push_outbuf (rtpmp4gdepay, outbuf, AU_index); } else { GST_DEBUG_OBJECT (rtpmp4gdepay, "waiting for next AU_index %u", rtpmp4gdepay->next_AU_index); @@ -419,22 +425,21 @@ gst_rtp_mp4g_depay_queue (GstRtpMP4GDepay * rtpmp4gdepay, GstBuffer * outbuf) } static GstBuffer * -gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) +gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpMP4GDepay *rtpmp4gdepay; GstBuffer *outbuf = NULL; GstClockTime timestamp; - GstRTPBuffer rtp; rtpmp4gdepay = GST_RTP_MP4G_DEPAY (depayload); /* flush remaining data on discont */ - if (GST_BUFFER_IS_DISCONT (buf)) { + if (GST_BUFFER_IS_DISCONT (rtp->buffer)) { GST_DEBUG_OBJECT (rtpmp4gdepay, "received DISCONT"); gst_adapter_clear (rtpmp4gdepay->adapter); } - timestamp = GST_BUFFER_TIMESTAMP (buf); + timestamp = GST_BUFFER_PTS (rtp->buffer); { gint payload_len, payload_AU; @@ -444,16 +449,13 @@ gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) guint AU_size, AU_index, AU_index_delta, payload_AU_size; gboolean M; - gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); - payload_len = gst_rtp_buffer_get_payload_len (&rtp); - payload = gst_rtp_buffer_get_payload (&rtp); + payload_len = gst_rtp_buffer_get_payload_len (rtp); + payload = gst_rtp_buffer_get_payload (rtp); GST_DEBUG_OBJECT (rtpmp4gdepay, "received payload of %d", payload_len); - rtptime = gst_rtp_buffer_get_timestamp (&rtp); - M = gst_rtp_buffer_get_marker (&rtp); - - gst_rtp_buffer_unmap (&rtp); + rtptime = gst_rtp_buffer_get_timestamp (rtp); + M = gst_rtp_buffer_get_marker (rtp); if (rtpmp4gdepay->sizelength > 0) { gint num_AU_headers, AU_headers_bytes, i; @@ -561,6 +563,15 @@ gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) /* use number of packets and of previous frame */ cd = diff / rtpmp4gdepay->prev_AU_num; GST_DEBUG_OBJECT (depayload, "guessing constantDuration %d", cd); + if (!GST_BUFFER_IS_DISCONT (rtp->buffer)) { + /* rfc3640 - 3.2.3.2 + * if we see two consecutive packets with AU_index of 0 and + * there has been no discontinuity, we must conclude that this + * value of constantDuration is correct from now on. */ + GST_DEBUG_OBJECT (depayload, + "constantDuration of %d detected", cd); + rtpmp4gdepay->constantDuration = cd; + } } else { /* assume this frame has the same number of packets as the * previous one */ @@ -587,7 +598,7 @@ gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) rtpmp4gdepay->last_AU_index = AU_index; } - /* keep track of the higest AU_index */ + /* keep track of the highest AU_index */ if (rtpmp4gdepay->max_AU_index != -1 && rtpmp4gdepay->max_AU_index <= AU_index) { GST_DEBUG_OBJECT (rtpmp4gdepay, "new interleave group, flushing"); @@ -653,27 +664,58 @@ gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) /* collect stuff in the adapter, strip header from payload and push in * the adapter */ outbuf = - gst_rtp_buffer_get_payload_subbuffer (&rtp, payload_AU, AU_size); + gst_rtp_buffer_get_payload_subbuffer (rtp, payload_AU, AU_size); gst_adapter_push (rtpmp4gdepay->adapter, outbuf); if (M) { + guint32 v = 0; guint avail; /* packet is complete, flush */ avail = gst_adapter_available (rtpmp4gdepay->adapter); + /* Some broken senders send ADTS headers (e.g. some Sony cameras). + * Try to detect those and skip them (still needs config set), but + * don't check every frame, only the first (unless we detect ADTS) */ + if (rtpmp4gdepay->check_adts && avail >= 7) { + if (gst_adapter_masked_scan_uint32_peek (rtpmp4gdepay->adapter, + 0xfffe0000, 0xfff00000, 0, 4, &v) == 0) { + guint adts_hdr_len = (((v >> 16) & 0x1) == 0) ? 9 : 7; + if (avail > adts_hdr_len) { + if (rtpmp4gdepay->warn_adts) { + GST_WARNING_OBJECT (rtpmp4gdepay, "Detected ADTS header of " + "%u bytes, skipping", adts_hdr_len); + rtpmp4gdepay->warn_adts = FALSE; + } + gst_adapter_flush (rtpmp4gdepay->adapter, adts_hdr_len); + avail -= adts_hdr_len; + } + } else { + rtpmp4gdepay->check_adts = FALSE; + rtpmp4gdepay->warn_adts = TRUE; + } + } + outbuf = gst_adapter_take_buffer (rtpmp4gdepay->adapter, avail); /* copy some of the fields we calculated above on the buffer. We also * copy the AU_index so that we can sort the packets in our queue. */ - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + GST_BUFFER_PTS (outbuf) = timestamp; GST_BUFFER_OFFSET (outbuf) = AU_index; - /* make sure we don't use the timestamp again for other AUs in this - * RTP packet. */ - timestamp = -1; + if (rtpmp4gdepay->constantDuration != 0) { + /* if we have constantDuration, calculate timestamp for next AU + * in this RTP packet. */ + timestamp += (rtpmp4gdepay->constantDuration * GST_SECOND) / + depayload->clock_rate; + } else { + /* otherwise, make sure we don't use the timestamp again for other + * AUs. */ + timestamp = GST_CLOCK_TIME_NONE; + } - GST_DEBUG_OBJECT (depayload, "pushing buffer of size %d", + GST_DEBUG_OBJECT (depayload, + "pushing buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (outbuf)); gst_rtp_mp4g_depay_queue (rtpmp4gdepay, outbuf); @@ -684,7 +726,7 @@ gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) } } else { /* push complete buffer in adapter */ - outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, 0, payload_len); + outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, 0, payload_len); gst_adapter_push (rtpmp4gdepay->adapter, outbuf); /* if this was the last packet of the VOP, create and push a buffer */ @@ -695,16 +737,14 @@ gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) outbuf = gst_adapter_take_buffer (rtpmp4gdepay->adapter, avail); - GST_DEBUG ("gst_rtp_mp4g_depay_chain: pushing buffer of size %d", - gst_buffer_get_size (outbuf)); + GST_DEBUG ("gst_rtp_mp4g_depay_chain: pushing buffer of size %" + G_GSIZE_FORMAT, gst_buffer_get_size (outbuf)); - gst_rtp_buffer_unmap (&rtp); return outbuf; } } } - gst_rtp_buffer_unmap (&rtp); return NULL; /* ERRORS */ @@ -712,7 +752,6 @@ short_payload: { GST_ELEMENT_WARNING (rtpmp4gdepay, STREAM, DECODE, ("Packet payload was too short."), (NULL)); - gst_rtp_buffer_unmap (&rtp); return NULL; } }