summaryrefslogtreecommitdiff
path: root/gst/rtp/gstrtph264pay.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/rtp/gstrtph264pay.c')
-rw-r--r--gst/rtp/gstrtph264pay.c189
1 files changed, 172 insertions, 17 deletions
diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c
index a4830e6..1d0721e 100644
--- a/gst/rtp/gstrtph264pay.c
+++ b/gst/rtp/gstrtph264pay.c
@@ -22,8 +22,10 @@
#endif
#include <string.h>
+#include <stdlib.h>
#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/pbutils/pbutils.h>
#include "gstrtph264pay.h"
@@ -108,6 +110,8 @@ static void gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
static void gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
+static GstCaps *gst_rtp_h264_pay_getcaps (GstBaseRTPPayload * payload,
+ GstPad * pad);
static gboolean gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload,
GstCaps * caps);
static GstFlowReturn gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * pad,
@@ -124,10 +128,10 @@ gst_rtp_h264_pay_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_rtp_h264_pay_src_template));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_rtp_h264_pay_sink_template));
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_rtp_h264_pay_src_template);
+ gst_element_class_add_static_pad_template (element_class,
+ &gst_rtp_h264_pay_sink_template);
gst_element_class_set_details_simple (element_class, "RTP H264 payloader",
"Codec/Payloader/Network/RTP",
@@ -191,6 +195,7 @@ gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass)
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_basertppayload_change_state);
+ gstbasertppayload_class->get_caps = gst_rtp_h264_pay_getcaps;
gstbasertppayload_class->set_caps = gst_rtp_h264_pay_setcaps;
gstbasertppayload_class->handle_buffer = gst_rtp_h264_pay_handle_buffer;
gstbasertppayload_class->handle_event = gst_rtp_h264_pay_handle_event;
@@ -243,6 +248,133 @@ gst_rtp_h264_pay_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
+static const gchar *all_levels[] = {
+ "1",
+ "1b",
+ "1.1",
+ "1.2",
+ "1.3",
+ "2",
+ "2.1",
+ "2.2",
+ "3",
+ "3.1",
+ "3.2",
+ "4",
+ "4.1",
+ "4.2",
+ "5",
+ "5.1",
+ NULL
+};
+
+static GstCaps *
+gst_rtp_h264_pay_getcaps (GstBaseRTPPayload * payload, GstPad * pad)
+{
+ GstCaps *allowed_caps;
+
+ allowed_caps =
+ gst_pad_peer_get_caps_reffed (GST_BASE_RTP_PAYLOAD_SRCPAD (payload));
+
+ if (allowed_caps) {
+ GstCaps *caps = NULL;
+ guint i;
+
+ if (gst_caps_is_any (allowed_caps)) {
+ gst_caps_unref (allowed_caps);
+ goto any;
+ }
+
+ if (gst_caps_is_empty (allowed_caps))
+ return allowed_caps;
+
+ caps = gst_caps_new_empty ();
+
+ for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
+ GstStructure *s = gst_caps_get_structure (allowed_caps, i);
+ GstStructure *new_s = gst_structure_new ("video/x-h264", NULL);
+ const gchar *profile_level_id;
+
+ profile_level_id = gst_structure_get_string (s, "profile-level-id");
+
+ if (profile_level_id && strlen (profile_level_id) == 6) {
+ const gchar *profile;
+ const gchar *level;
+ long int spsint;
+ guint8 sps[3];
+
+ spsint = strtol (profile_level_id, NULL, 16);
+ sps[0] = spsint >> 16;
+ sps[1] = spsint >> 8;
+ sps[2] = spsint;
+
+ profile = gst_codec_utils_h264_get_profile (sps, 3);
+ level = gst_codec_utils_h264_get_level (sps, 3);
+
+ if (profile && level) {
+ GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s",
+ profile, level);
+
+ if (!strcmp (profile, "constrained-baseline"))
+ gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL);
+ else {
+ GValue val = { 0, };
+ GValue profiles = { 0, };
+
+ g_value_init (&profiles, GST_TYPE_LIST);
+ g_value_init (&val, G_TYPE_STRING);
+
+ g_value_set_static_string (&val, profile);
+ gst_value_list_append_value (&profiles, &val);
+
+ g_value_set_static_string (&val, "constrained-baseline");
+ gst_value_list_append_value (&profiles, &val);
+
+ gst_structure_take_value (new_s, "profile", &profiles);
+ }
+
+ if (!strcmp (level, "1"))
+ gst_structure_set (new_s, "level", G_TYPE_STRING, level, NULL);
+ else {
+ GValue levels = { 0, };
+ GValue val = { 0, };
+ int j;
+
+ g_value_init (&levels, GST_TYPE_LIST);
+ g_value_init (&val, G_TYPE_STRING);
+
+ for (j = 0; all_levels[j]; j++) {
+ g_value_set_static_string (&val, all_levels[j]);
+ gst_value_list_prepend_value (&levels, &val);
+ if (!strcmp (level, all_levels[j]))
+ break;
+ }
+ gst_structure_take_value (new_s, "level", &levels);
+ }
+ } else {
+ /* Invalid profile-level-id means baseline */
+
+ gst_structure_set (new_s,
+ "profile", G_TYPE_STRING, "constrained-baseline", NULL);
+ }
+ } else {
+ /* No profile-level-id also means baseline */
+
+ gst_structure_set (new_s,
+ "profile", G_TYPE_STRING, "constrained-baseline", NULL);
+ }
+
+ gst_caps_merge_structure (caps, new_s);
+ }
+
+ gst_caps_unref (allowed_caps);
+ return caps;
+ }
+
+any:
+ return gst_caps_new_simple ("video/x-h264", NULL);
+}
+
/* take the currently configured SPS and PPS lists and set them on the caps as
* sprop-parameter-sets */
static gboolean
@@ -298,6 +430,7 @@ gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
const GValue *value;
guint8 *data;
guint size;
+ const gchar *alignment;
rtph264pay = GST_RTP_H264_PAY (basepayload);
@@ -307,7 +440,12 @@ gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
* NALs */
gst_basertppayload_set_options (basepayload, "video", TRUE, "H264", 90000);
-#if 0 // yoserb yi - not to check sps/pps when savsenc_h264 and rtph264pay are linked
+ alignment = gst_structure_get_string (str, "alignment");
+ if (alignment && !strcmp (alignment, "au"))
+ rtph264pay->au_alignment = TRUE;
+ else
+ rtph264pay->au_alignment = FALSE;
+
/* packetized AVC video has a codec_data */
if ((value = gst_structure_get_value (str, "codec_data"))) {
GstBuffer *buffer;
@@ -409,10 +547,6 @@ gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
GST_DEBUG_OBJECT (rtph264pay, "have bytestream h264");
rtph264pay->packetized = FALSE;
}
-#else
- GST_DEBUG_OBJECT (rtph264pay, "have bytestream h264");
- rtph264pay->packetized = FALSE;
-#endif
return TRUE;
@@ -646,7 +780,7 @@ gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
static GstFlowReturn
gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
const guint8 * data, guint size, GstClockTime timestamp,
- GstBuffer * buffer_orig);
+ GstBuffer * buffer_orig, gboolean end_of_au);
static GstFlowReturn
gst_rtp_h264_pay_send_sps_pps (GstBaseRTPPayload * basepayload,
@@ -662,7 +796,7 @@ gst_rtp_h264_pay_send_sps_pps (GstBaseRTPPayload * basepayload,
/* resend SPS */
ret = gst_rtp_h264_pay_payload_nal (basepayload,
GST_BUFFER_DATA (sps_buf), GST_BUFFER_SIZE (sps_buf), timestamp,
- sps_buf);
+ sps_buf, FALSE);
/* Not critical here; but throw a warning */
if (ret != GST_FLOW_OK)
GST_WARNING ("Problem pushing SPS");
@@ -674,7 +808,7 @@ gst_rtp_h264_pay_send_sps_pps (GstBaseRTPPayload * basepayload,
/* resend PPS */
ret = gst_rtp_h264_pay_payload_nal (basepayload,
GST_BUFFER_DATA (pps_buf), GST_BUFFER_SIZE (pps_buf), timestamp,
- pps_buf);
+ pps_buf, FALSE);
/* Not critical here; but throw a warning */
if (ret != GST_FLOW_OK)
GST_WARNING ("Problem pushing PPS");
@@ -689,7 +823,7 @@ gst_rtp_h264_pay_send_sps_pps (GstBaseRTPPayload * basepayload,
static GstFlowReturn
gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
const guint8 * data, guint size, GstClockTime timestamp,
- GstBuffer * buffer_orig)
+ GstBuffer * buffer_orig, gboolean end_of_au)
{
GstRtpH264Pay *rtph264pay;
GstFlowReturn ret;
@@ -768,7 +902,7 @@ gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
}
/* only set the marker bit on packets containing access units */
- if (IS_ACCESS_UNIT (nalType)) {
+ if (IS_ACCESS_UNIT (nalType) && end_of_au) {
gst_rtp_buffer_set_marker (outbuf, 1);
}
@@ -858,7 +992,7 @@ gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
end = 1;
}
if (IS_ACCESS_UNIT (nalType)) {
- gst_rtp_buffer_set_marker (outbuf, end);
+ gst_rtp_buffer_set_marker (outbuf, end && end_of_au);
}
/* FU indicator */
@@ -958,6 +1092,7 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
while (size > nal_length_size) {
gint i;
+ gboolean end_of_au = FALSE;
nal_len = 0;
for (i = 0; i < nal_length_size; i++) {
@@ -976,9 +1111,16 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
nal_len);
}
+ /* If we're at the end of the buffer, then we're at the end of the
+ * access unit
+ */
+ if (rtph264pay->au_alignment && size - nal_len <= nal_length_size) {
+ end_of_au = TRUE;
+ }
+
ret =
gst_rtp_h264_pay_payload_nal (basepayload, data, nal_len, timestamp,
- buffer);
+ buffer, end_of_au);
if (ret != GST_FLOW_OK)
break;
@@ -1080,6 +1222,7 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
for (i = 0; i < nal_queue->len; i++) {
guint size;
+ gboolean end_of_au = FALSE;
nal_len = g_array_index (nal_queue, guint, i);
/* skip start code */
@@ -1095,10 +1238,22 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
for (; size > 1 && data[size - 1] == 0x0; size--)
/* skip */ ;
+ /* If it's the last nal unit we have in non-bytestream mode, we can
+ * assume it's the end of an access-unit
+ *
+ * FIXME: We need to wait until the next packet or EOS to
+ * actually payload the NAL so we can know if the current NAL is
+ * the last one of an access unit or not if we are in bytestream mode
+ */
+ if (rtph264pay->au_alignment &&
+ rtph264pay->scan_mode != GST_H264_SCAN_MODE_BYTESTREAM &&
+ i == nal_queue->len - 1)
+ end_of_au = TRUE;
+
/* put the data in one or more RTP packets */
ret =
gst_rtp_h264_pay_payload_nal (basepayload, data, size, timestamp,
- buffer);
+ buffer, end_of_au);
if (ret != GST_FLOW_OK) {
break;
}