rtph264pay: implement full bytestream scan mode.

Implement the full bytestream scan mode.

Fixes #634910
This commit is contained in:
Tambet Ingo 2010-11-16 15:39:24 +01:00 committed by Wim Taymans
parent fdfe76ac53
commit 9d52c1a1d7
2 changed files with 66 additions and 11 deletions

View file

@ -66,7 +66,7 @@ gst_h264_scan_mode_get_type (void)
static GType h264_scan_mode_type = 0; static GType h264_scan_mode_type = 0;
static const GEnumValue h264_scan_modes[] = { static const GEnumValue h264_scan_modes[] = {
{GST_H264_SCAN_MODE_BYTESTREAM, {GST_H264_SCAN_MODE_BYTESTREAM,
"Scan complete bytestream for NALUs (not implemented)", "Scan complete bytestream for NALUs",
"bytestream"}, "bytestream"},
{GST_H264_SCAN_MODE_MULTI_NAL, "Buffers contain multiple complete NALUs", {GST_H264_SCAN_MODE_MULTI_NAL, "Buffers contain multiple complete NALUs",
"multiple"}, "multiple"},
@ -236,6 +236,11 @@ gst_rtp_h264_pay_finalize (GObject * object)
g_free (rtph264pay->sprop_parameter_sets); g_free (rtph264pay->sprop_parameter_sets);
if (rtph264pay->adapter) {
g_object_unref (rtph264pay->adapter);
rtph264pay->adapter = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
@ -911,16 +916,30 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
guint8 *data, *nal_data; guint8 *data, *nal_data;
GstClockTime timestamp; GstClockTime timestamp;
GArray *nal_queue; GArray *nal_queue;
guint pushed;
rtph264pay = GST_RTP_H264_PAY (basepayload); rtph264pay = GST_RTP_H264_PAY (basepayload);
/* the input buffer contains one or more NAL units */ /* the input buffer contains one or more NAL units */
size = GST_BUFFER_SIZE (buffer);
data = GST_BUFFER_DATA (buffer);
timestamp = GST_BUFFER_TIMESTAMP (buffer);
ret = GST_FLOW_OK;
GST_DEBUG_OBJECT (basepayload, "got %d bytes", size); if (rtph264pay->scan_mode == GST_H264_SCAN_MODE_BYTESTREAM) {
timestamp = gst_adapter_prev_timestamp (rtph264pay->adapter, 0);
gst_adapter_push (rtph264pay->adapter, buffer);
size = gst_adapter_available (rtph264pay->adapter);
data = gst_adapter_peek (rtph264pay->adapter, size);
GST_DEBUG_OBJECT (basepayload, "got %d bytes (%d)", size,
GST_BUFFER_SIZE (buffer));
if (!GST_CLOCK_TIME_IS_VALID (timestamp))
timestamp = GST_BUFFER_TIMESTAMP (buffer);
} else {
size = GST_BUFFER_SIZE (buffer);
data = GST_BUFFER_DATA (buffer);
timestamp = GST_BUFFER_TIMESTAMP (buffer);
GST_DEBUG_OBJECT (basepayload, "got %d bytes", size);
}
ret = GST_FLOW_OK;
/* now loop over all NAL units and put them in a packet /* now loop over all NAL units and put them in a packet
* FIXME, we should really try to pack multiple NAL units into one RTP packet * FIXME, we should really try to pack multiple NAL units into one RTP packet
@ -999,6 +1018,12 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
* data is unchanged by the call to next_start_code() * data is unchanged by the call to next_start_code()
*/ */
next = next_start_code (data, size); next = next_start_code (data, size);
if (next == size
&& rtph264pay->scan_mode == GST_H264_SCAN_MODE_BYTESTREAM) {
/* Didn't find the start of next NAL, handle it next time */
break;
}
} }
/* nal length is distance to next start code */ /* nal length is distance to next start code */
@ -1045,6 +1070,8 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
/* second pass to payload and push */ /* second pass to payload and push */
data = nal_data; data = nal_data;
pushed = 0;
for (i = 0; i < nal_queue->len; i++) { for (i = 0; i < nal_queue->len; i++) {
guint size; guint size;
@ -1057,9 +1084,10 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
* starts with 0x000001 so all the 0x00 bytes at the end of this one are * starts with 0x000001 so all the 0x00 bytes at the end of this one are
* trailing 0x0 that can be discarded */ * trailing 0x0 that can be discarded */
size = nal_len; size = nal_len;
if (i + 1 != nal_queue->len) if (i + 1 != nal_queue->len
for ( ; size > 1 && data[size - 1] == 0x0; size--) || rtph264pay->scan_mode == GST_H264_SCAN_MODE_BYTESTREAM)
/* skip */; for (; size > 1 && data[size - 1] == 0x0; size--)
/* skip */ ;
/* put the data in one or more RTP packets */ /* put the data in one or more RTP packets */
ret = ret =
@ -1072,11 +1100,15 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
/* move to next NAL packet */ /* move to next NAL packet */
data += nal_len; data += nal_len;
size -= nal_len; size -= nal_len;
pushed += nal_len + 3;
} }
g_array_set_size (nal_queue, 0); g_array_set_size (nal_queue, 0);
} }
gst_buffer_unref (buffer); if (rtph264pay->scan_mode == GST_H264_SCAN_MODE_BYTESTREAM)
gst_adapter_flush (rtph264pay->adapter, pushed);
else
gst_buffer_unref (buffer);
return ret; return ret;
@ -1122,6 +1154,8 @@ gst_basertppayload_change_state (GstElement * element,
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_READY_TO_PAUSED:
rtph264pay->send_spspps = FALSE; rtph264pay->send_spspps = FALSE;
if (rtph264pay->adapter)
gst_adapter_clear (rtph264pay->adapter);
break; break;
default: default:
break; break;
@ -1132,6 +1166,24 @@ gst_basertppayload_change_state (GstElement * element,
return ret; return ret;
} }
static void
gst_rtp_h264_pay_set_scan_mode (GstRtpH264Pay * rtph264pay,
GstH264ScanMode scan_mode)
{
if (rtph264pay->scan_mode == scan_mode)
return;
if (rtph264pay->adapter) {
g_object_unref (rtph264pay->adapter);
rtph264pay->adapter = NULL;
}
rtph264pay->scan_mode = scan_mode;
if (rtph264pay->scan_mode == GST_H264_SCAN_MODE_BYTESTREAM) {
rtph264pay->adapter = gst_adapter_new ();
}
}
static void static void
gst_rtp_h264_pay_set_property (GObject * object, guint prop_id, gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
@ -1149,7 +1201,7 @@ gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
rtph264pay->update_caps = TRUE; rtph264pay->update_caps = TRUE;
break; break;
case PROP_SCAN_MODE: case PROP_SCAN_MODE:
rtph264pay->scan_mode = g_value_get_enum (value); gst_rtp_h264_pay_set_scan_mode (rtph264pay, g_value_get_enum (value));
break; break;
case PROP_BUFFER_LIST: case PROP_BUFFER_LIST:
rtph264pay->buffer_list = g_value_get_boolean (value); rtph264pay->buffer_list = g_value_get_boolean (value);

View file

@ -21,6 +21,7 @@
#define __GST_RTP_H264_PAY_H__ #define __GST_RTP_H264_PAY_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include <gst/rtp/gstbasertppayload.h> #include <gst/rtp/gstbasertppayload.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -61,6 +62,8 @@ struct _GstRtpH264Pay
gboolean update_caps; gboolean update_caps;
GstH264ScanMode scan_mode; GstH264ScanMode scan_mode;
GstAdapter *adapter;
guint spspps_interval; guint spspps_interval;
gboolean send_spspps; gboolean send_spspps;
GstClockTime last_spspps; GstClockTime last_spspps;