diff --git a/common b/common index 50b34abb46..605cd9a65e 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 50b34abb468b6572a92f6700552f6f541c655be8 +Subproject commit 605cd9a65ed61505f24b840d3fe8e252be72b151 diff --git a/ext/x264/Makefile.am b/ext/x264/Makefile.am index f5590139fe..92691d1535 100644 --- a/ext/x264/Makefile.am +++ b/ext/x264/Makefile.am @@ -6,7 +6,9 @@ libgstx264_la_CFLAGS = \ $(GST_CFLAGS) \ $(X264_CFLAGS) libgstx264_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstvideo-$(GST_MAJORMINOR) \ + -lgstpbutils-$(GST_MAJORMINOR) \ $(GST_LIBS) \ $(X264_LIBS) libgstx264_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/ext/x264/gstx264enc.c b/ext/x264/gstx264enc.c index 66e764797e..3aa02feadc 100644 --- a/ext/x264/gstx264enc.c +++ b/ext/x264/gstx264enc.c @@ -37,9 +37,11 @@ * If #GstX264Enc:dct8x8 is enabled, then High profile is used. * Otherwise, if #GstX264Enc:cabac entropy coding is enabled or #GstX264Enc:bframes * are allowed, then Main Profile is in effect, and otherwise Baseline profile - * applies. No profile is imposed by default, which is fine for most software - * players and settings, but in some cases (e.g. hardware platforms) a more - * restricted profile/level may be necessary. + * applies. The main profile is imposed by default, + * which is fine for most software players and settings, + * but in some cases (e.g. hardware platforms) a more restricted profile/level + * may be necessary. The recommended way to set a profile is to set it in the + * downstream caps. * * If a preset/tuning are specified then these will define the default values and * the property defaults will be ignored. After this the option-string property is @@ -71,7 +73,7 @@ * ]| This example pipeline will encode a test video source to H264 using fixed * quantization, and muxes it in a Matroska container. * |[ - * gst-launch -v videotestsrc num-buffers=1000 ! x264enc pass=5 quantizer=25 speed-preset=6 profile=1 ! \ + * gst-launch -v videotestsrc num-buffers=1000 ! x264enc pass=5 quantizer=25 speed-preset=6 ! video/x-h264, profile=baseline ! \ * qtmux ! filesink location=videotestsrc.mov * ]| This example pipeline will encode a test video source to H264 using * constant quality at around Q25 using the 'medium' speed/quality preset and @@ -94,6 +96,8 @@ #include "gstx264enc.h" +#include + #if X264_BUILD >= 71 #define X264_DELAYED_FRAMES_API #endif @@ -214,6 +218,13 @@ static GString *x264enc_defaults; #define ARG_PSY_TUNE_DEFAULT 0 /* no psy tuning */ #define ARG_TUNE_DEFAULT 0 /* no tuning */ +enum +{ + GST_X264_ENC_STREAM_FORMAT_FROM_PROPERTY, + GST_X264_ENC_STREAM_FORMAT_AVC, + GST_X264_ENC_STREAM_FORMAT_BYTE_STREAM +}; + enum { GST_X264_ENC_PASS_CBR = 0, @@ -461,7 +472,9 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", "framerate = (fraction) [0/1, MAX], " "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], " "stream-format = (string) { byte-stream, avc }, " - "alignment = (string) { au }") + "alignment = (string) { au }, " + "profile = (string) { high-10, high, main, constrained-baseline, " + "high-10-intra }") ); static void gst_x264_enc_finalize (GObject * object); @@ -604,7 +617,8 @@ gst_x264_enc_class_init (GstX264EncClass * klass) g_object_class_install_property (gobject_class, ARG_PROFILE, g_param_spec_enum ("profile", "H.264 profile", "Apply restrictions to meet H.264 Profile constraints. This will " - "override other properties if necessary.", + "override other properties if necessary. This will only be used " + "if downstream elements do not specify a profile in their caps (DEPRECATED)", GST_X264_ENC_PROFILE_TYPE, ARG_PROFILE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); #endif /* X264_PRESETS */ @@ -673,8 +687,9 @@ gst_x264_enc_class_init (GstX264EncClass * klass) x264_motion_est_names[ARG_ME_DEFAULT]); g_object_class_install_property (gobject_class, ARG_SUBME, g_param_spec_uint ("subme", "Subpixel Motion Estimation", - "Subpixel motion estimation and partition decision quality: 1=fast, 6=best", - 1, 6, ARG_SUBME_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + "Subpixel motion estimation and partition decision quality: 1=fast, 10=best", + 1, 10, ARG_SUBME_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_string_append_printf (x264enc_defaults, ":subme=%d", ARG_SUBME_DEFAULT); g_object_class_install_property (gobject_class, ARG_ANALYSE, g_param_spec_flags ("analyse", "Analyse", "Partitions to consider", @@ -932,6 +947,7 @@ gst_x264_enc_reset (GstX264Enc * encoder) encoder->x264enc = NULL; encoder->width = 0; encoder->height = 0; + encoder->current_byte_stream = GST_X264_ENC_STREAM_FORMAT_FROM_PROPERTY; GST_OBJECT_LOCK (encoder); encoder->i_type = X264_TYPE_AUTO; @@ -1149,8 +1165,8 @@ gst_x264_enc_init_encoder (GstX264Enc * encoder) encoder->x264param.rc.i_rc_method = X264_RC_ABR; encoder->x264param.rc.i_bitrate = encoder->bitrate; encoder->x264param.rc.i_vbv_max_bitrate = encoder->bitrate; - encoder->x264param.rc.i_vbv_buffer_size - = encoder->x264param.rc.i_vbv_max_bitrate + encoder->x264param.rc.i_vbv_buffer_size = + encoder->x264param.rc.i_vbv_max_bitrate * encoder->vbv_buf_capacity / 1000; pass = encoder->pass & 0xF; break; @@ -1206,14 +1222,45 @@ gst_x264_enc_init_encoder (GstX264Enc * encoder) #endif #ifdef X264_PRESETS - if (encoder->profile - && x264_param_apply_profile (&encoder->x264param, - x264_profile_names[encoder->profile - 1])) { - GST_WARNING_OBJECT (encoder, "Bad profile name: %s", - x264_profile_names[encoder->profile - 1]); + if (encoder->peer_profile) { + if (x264_param_apply_profile (&encoder->x264param, encoder->peer_profile)) + GST_WARNING_OBJECT (encoder, "Bad downstream profile name: %s", + encoder->peer_profile); + } else if (encoder->profile) { + if (x264_param_apply_profile (&encoder->x264param, + x264_profile_names[encoder->profile - 1])) + GST_WARNING_OBJECT (encoder, "Bad profile name: %s", + x264_profile_names[encoder->profile - 1]); } #endif /* X264_PRESETS */ + /* If using an intra profile, all frames are intra frames */ + if (encoder->peer_intra_profile) + encoder->x264param.i_keyint_max = encoder->x264param.i_keyint_min = 1; + + /* Enforce level limits if they were in the caps */ + if (encoder->peer_level) { + encoder->x264param.i_level_idc = encoder->peer_level->level_idc; + + encoder->x264param.rc.i_bitrate = MIN (encoder->x264param.rc.i_bitrate, + encoder->peer_level->bitrate); + encoder->x264param.rc.i_vbv_max_bitrate = + MIN (encoder->x264param.rc.i_vbv_max_bitrate, + encoder->peer_level->bitrate); + encoder->x264param.rc.i_vbv_buffer_size = + MIN (encoder->x264param.rc.i_vbv_buffer_size, encoder->peer_level->cpb); + encoder->x264param.analyse.i_mv_range = + MIN (encoder->x264param.analyse.i_mv_range, + encoder->peer_level->mv_range); + + if (encoder->peer_level->frame_only) { + encoder->x264param.b_interlaced = FALSE; +#if X264_BUILD >= 95 + encoder->x264param.b_fake_interlaced = FALSE; +#endif + } + } + encoder->reconfig = FALSE; GST_OBJECT_UNLOCK (encoder); @@ -1246,6 +1293,42 @@ gst_x264_enc_close_encoder (GstX264Enc * encoder) } } +static gboolean +gst_x264_enc_set_profile_and_level (GstX264Enc * encoder, GstCaps * caps) +{ + x264_nal_t *nal; + int i_nal; + int header_return; + gint sps_ni = 0; + guint8 *sps; + + + header_return = x264_encoder_headers (encoder->x264enc, &nal, &i_nal); + if (header_return < 0) { + GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x264 header failed."), + ("x264_encoder_headers return code=%d", header_return)); + return FALSE; + } + + /* old x264 returns SEI, SPS and PPS, newer one has SEI last */ + if (i_nal == 3 && nal[sps_ni].i_type != 7) + sps_ni = 1; + + /* old style API: nal's are not encapsulated, and have no sync/size prefix, + * new style API: nal's are encapsulated, and have 4-byte size prefix */ +#ifndef X264_ENC_NALS + sps = nal[sps_ni].p_payload; +#else + sps = nal[sps_ni].p_payload + 4; + /* skip NAL unit type */ + sps++; +#endif + + gst_codec_utils_h264_caps_set_level_and_profile (caps, sps, 3); + + return TRUE; +} + /* * Returns: Buffer with the stream headers. */ @@ -1372,7 +1455,14 @@ gst_x264_enc_set_src_caps (GstX264Enc * encoder, GstPad * pad, GstCaps * caps) structure = gst_caps_get_structure (outcaps, 0); - if (!encoder->byte_stream) { + if (encoder->current_byte_stream == GST_X264_ENC_STREAM_FORMAT_FROM_PROPERTY) { + if (encoder->byte_stream) { + encoder->current_byte_stream = GST_X264_ENC_STREAM_FORMAT_BYTE_STREAM; + } else { + encoder->current_byte_stream = GST_X264_ENC_STREAM_FORMAT_AVC; + } + } + if (encoder->current_byte_stream == GST_X264_ENC_STREAM_FORMAT_AVC) { buf = gst_x264_enc_header_buf (encoder); if (buf != NULL) { gst_caps_set_simple (outcaps, "codec_data", GST_TYPE_BUFFER, buf, NULL); @@ -1385,6 +1475,11 @@ gst_x264_enc_set_src_caps (GstX264Enc * encoder, GstPad * pad, GstCaps * caps) } gst_structure_set (structure, "alignment", G_TYPE_STRING, "au", NULL); + if (!gst_x264_enc_set_profile_and_level (encoder, outcaps)) { + gst_caps_unref (outcaps); + return FALSE; + } + res = gst_pad_set_caps (pad, outcaps); gst_caps_unref (outcaps); @@ -1400,6 +1495,10 @@ gst_x264_enc_sink_set_caps (GstPad * pad, GstCaps * caps) gint fps_num, fps_den; gint par_num, par_den; gint i; + GstCaps *peer_caps; + const GstCaps *template_caps; + GstCaps *allowed_caps = NULL; + gboolean level_ok = TRUE; /* get info from caps */ if (!gst_video_format_parse_caps (caps, &format, &width, &height)) @@ -1446,6 +1545,131 @@ gst_x264_enc_sink_set_caps (GstPad * pad, GstCaps * caps) i, width); } + encoder->peer_profile = NULL; + encoder->peer_intra_profile = FALSE; + encoder->peer_level = NULL; + + /* FIXME: Remove THIS bit in 0.11 when the profile property is removed */ + peer_caps = gst_pad_peer_get_caps_reffed (encoder->srcpad); + if (peer_caps) { + gint i; + gboolean has_profile_or_level_or_format = FALSE; + + for (i = 0; i < gst_caps_get_size (peer_caps); i++) { + GstStructure *s = gst_caps_get_structure (peer_caps, i); + + if (gst_structure_has_name (s, "video/x-h264") && + (gst_structure_has_field (s, "profile") || + gst_structure_has_field (s, "level") || + gst_structure_has_field (s, "stream-format"))) { + has_profile_or_level_or_format = TRUE; + break; + } + } + + if (has_profile_or_level_or_format) { + template_caps = gst_pad_get_pad_template_caps (encoder->srcpad); + + allowed_caps = gst_caps_intersect (peer_caps, template_caps); + } + + gst_caps_unref (peer_caps); + } + + /* Replace the bit since FIXME with this + * allowed_caps = gst_pad_get_allowed_caps (encoder->srcpad); + */ + + if (allowed_caps) { + GstStructure *s; + const gchar *profile; + const gchar *level; + const gchar *stream_format; + + if (gst_caps_is_empty (allowed_caps)) { + gst_caps_unref (allowed_caps); + return FALSE; + } + + allowed_caps = gst_caps_make_writable (allowed_caps); + gst_pad_fixate_caps (encoder->srcpad, allowed_caps); + s = gst_caps_get_structure (allowed_caps, 0); + + profile = gst_structure_get_string (s, "profile"); + if (profile) { + if (!strcmp (profile, "constrained-baseline")) { + encoder->peer_profile = "baseline"; + } else if (!strcmp (profile, "high-10-intra")) { + encoder->peer_intra_profile = TRUE; + encoder->peer_profile = "high10"; + } else if (!strcmp (profile, "high-10")) { + encoder->peer_profile = "high10"; + } else if (!strcmp (profile, "high")) { + encoder->peer_profile = "high"; + } else if (!strcmp (profile, "main")) { + encoder->peer_profile = "main"; + } else { + g_assert_not_reached (); + } + } + + level = gst_structure_get_string (s, "level"); + if (level) { + int level_idc = gst_codec_utils_h264_get_level_idc (level); + + if (level_idc) { + gint i; + + for (i = 0; x264_levels[i].level_idc; i++) { + if (level_idc == x264_levels[i].level_idc) { + int mb_width = (width + 15) / 16; + int mb_height = (height + 15) / 16; + int mbs = mb_width * mb_height; + + if (x264_levels[i].frame_size < mbs || + x264_levels[i].frame_size * 8 < mb_width * mb_width || + x264_levels[i].frame_size * 8 < mb_height * mb_height) { + GST_WARNING_OBJECT (encoder, + "Frame size larger than level %s allows", level); + level_ok = FALSE; + break; + } + + if (fps_den && + x264_levels[i].mbps < (gint64) mbs * fps_num / fps_den) { + GST_WARNING_OBJECT (encoder, + "Macroblock rate higher than level %s allows", level); + level_ok = FALSE; + break; + } + + encoder->peer_level = &x264_levels[i]; + break; + } + } + } + } + + stream_format = gst_structure_get_string (s, "stream-format"); + encoder->current_byte_stream = GST_X264_ENC_STREAM_FORMAT_FROM_PROPERTY; + if (stream_format) { + if (!strcmp (stream_format, "avc")) { + encoder->current_byte_stream = GST_X264_ENC_STREAM_FORMAT_AVC; + g_string_append_printf (encoder->option_string, ":annexb=0"); + } else if (!strcmp (stream_format, "byte-stream")) { + encoder->current_byte_stream = GST_X264_ENC_STREAM_FORMAT_BYTE_STREAM; + g_string_append_printf (encoder->option_string, ":annexb=1"); + } else { + /* means we have both in caps and _FROM_PROPERTY should be the option */ + } + } + + gst_caps_unref (allowed_caps); + } + + if (!level_ok) + return FALSE; + if (!gst_x264_enc_init_encoder (encoder)) return FALSE; @@ -1464,10 +1688,6 @@ gst_x264_enc_sink_get_caps (GstPad * pad) GstPad *peer; GstCaps *caps; - /* If we already have caps return them */ - if (GST_PAD_CAPS (pad)) - return gst_caps_ref (GST_PAD_CAPS (pad)); - encoder = GST_X264_ENC (gst_pad_get_parent (pad)); if (!encoder) return gst_caps_new_empty (); @@ -1501,6 +1721,14 @@ gst_x264_enc_sink_get_caps (GstPad * pad) caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); } + /* If we already have caps return them */ + if (GST_PAD_CAPS (pad) && gst_caps_can_intersect (GST_PAD_CAPS (pad), caps)) { + GstCaps *tmpcaps = gst_caps_copy (GST_PAD_CAPS (pad)); + + gst_caps_merge (tmpcaps, caps); + caps = tmpcaps; + } + gst_object_unref (encoder); return caps; @@ -1709,7 +1937,9 @@ gst_x264_enc_encode_frame (GstX264Enc * encoder, x264_picture_t * pic_in, nal_size = x264_nal_encode (encoder->buffer + i_size + 4, &i_data, 0, &nal[i]); - if (encoder->byte_stream) + g_assert (encoder->current_byte_stream != + GST_X264_ENC_STREAM_FORMAT_FROM_PROPERTY); + if (encoder->current_byte_stream == GST_X264_ENC_STREAM_FORMAT_BYTE_STREAM) GST_WRITE_UINT32_BE (encoder->buffer + i_size, 1); else GST_WRITE_UINT32_BE (encoder->buffer + i_size, nal_size); diff --git a/ext/x264/gstx264enc.h b/ext/x264/gstx264enc.h index 01cd27de1f..a2f1145b97 100644 --- a/ext/x264/gstx264enc.h +++ b/ext/x264/gstx264enc.h @@ -52,6 +52,7 @@ struct _GstX264Enc x264_t *x264enc; x264_param_t x264param; + gint current_byte_stream; /* properties */ guint threads; @@ -115,6 +116,11 @@ struct _GstX264Enc /* configuration changed while playing */ gboolean reconfig; + + /* from the downstream caps */ + const gchar *peer_profile; + gboolean peer_intra_profile; + const x264_level_t *peer_level; }; struct _GstX264EncClass diff --git a/gst/asfdemux/gstrtpasfdepay.c b/gst/asfdemux/gstrtpasfdepay.c index 8756400d86..0d6c5568c8 100644 --- a/gst/asfdemux/gstrtpasfdepay.c +++ b/gst/asfdemux/gstrtpasfdepay.c @@ -320,9 +320,6 @@ gst_rtp_asf_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) guint payload_len, hdr_len, offset; guint len_offs; GstClockTime timestamp; - gpointer bufdata; - guint8 *data; - gsize bufsize; GstRTPBuffer rtpbuf; depay = GST_RTP_ASF_DEPAY (depayload); @@ -345,6 +342,7 @@ gst_rtp_asf_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) do { guint packet_len; + gsize plen; /* packet header is at least 4 bytes */ if (payload_len < 4) @@ -462,25 +460,20 @@ gst_rtp_asf_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) return NULL; /* we need to pad with zeroes to packet_size if it's smaller */ - bufdata = gst_buffer_map (outbuf, &bufsize, NULL, GST_MAP_READ); - g_assert (packet_len == bufsize); - packet_len = bufsize; - if (packet_len < depay->packet_size) { + plen = gst_buffer_get_size (outbuf); + if (plen < depay->packet_size) { GstBuffer *tmp; GST_LOG_OBJECT (depay, "padding buffer size %d to packet size %d", - packet_len, depay->packet_size); + plen, depay->packet_size); + tmp = gst_buffer_new_and_alloc (depay->packet_size); - gst_buffer_copy_into (tmp, outbuf, GST_BUFFER_COPY_ALL, 0, packet_len); - gst_buffer_unmap (outbuf, bufdata, bufsize); + gst_buffer_copy_into (tmp, outbuf, GST_BUFFER_COPY_ALL, 0, plen); gst_buffer_unref (outbuf); outbuf = tmp; - bufdata = gst_buffer_map (outbuf, &bufsize, NULL, GST_MAP_WRITE); - data = (guint8 *) bufdata; - memset (data + packet_len, 0, depay->packet_size - packet_len); - gst_rtp_asf_depay_set_padding (depay, outbuf, - depay->packet_size - packet_len); + gst_buffer_memset (outbuf, plen, 0, depay->packet_size - plen); + gst_rtp_asf_depay_set_padding (depay, outbuf, depay->packet_size - plen); } if (!S) @@ -494,7 +487,6 @@ gst_rtp_asf_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - gst_buffer_unmap (outbuf, bufdata, bufsize); gst_base_rtp_depayload_push (depayload, outbuf); /* only apply the timestamp to the first buffer of this packet */ diff --git a/gst/synaesthesia/gstsynaesthesia.c b/gst/synaesthesia/gstsynaesthesia.c index 910ffb2932..79ca45fef3 100644 --- a/gst/synaesthesia/gstsynaesthesia.c +++ b/gst/synaesthesia/gstsynaesthesia.c @@ -312,7 +312,8 @@ done: /* Errors */ missing_caps_details: { - GST_WARNING_OBJECT (synaesthesia, "missing channels or rate in the caps"); + GST_WARNING_OBJECT (synaesthesia, + "missing width, height or framerate in the caps"); res = FALSE; goto done; } diff --git a/tests/check/elements/x264enc.c b/tests/check/elements/x264enc.c index ecfa4d4105..777a4725bb 100644 --- a/tests/check/elements/x264enc.c +++ b/tests/check/elements/x264enc.c @@ -211,6 +211,108 @@ GST_START_TEST (test_video_pad) GST_END_TEST; +GstCaps *pad_caps; + +GstCaps * +getcaps_test (GstPad * pad) +{ + return gst_caps_ref (pad_caps); +} + +GST_START_TEST (test_profile_in_caps) +{ + GstElement *x264enc; + GstPad *srcpad; + GstPad *sinkpad; + GstStructure *s; + + pad_caps = gst_caps_from_string (MPEG_CAPS_STRING); + + x264enc = setup_x264enc (); + gst_pad_set_getcaps_function (mysinkpad, getcaps_test); + srcpad = gst_element_get_static_pad (x264enc, "src"); + sinkpad = gst_element_get_static_pad (x264enc, "sink"); + fail_unless (gst_element_set_state (x264enc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + fail_unless (gst_pad_set_caps (sinkpad, + (GstCaps *) gst_pad_get_pad_template_caps (mysrcpad))); + s = gst_caps_get_structure (GST_PAD_CAPS (srcpad), 0); + fail_unless (!g_strcmp0 (gst_structure_get_string (s, "profile"), "main")); + + fail_unless (gst_element_set_state (x264enc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + g_object_set (x264enc, "profile", 1, NULL); + fail_unless (gst_element_set_state (x264enc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + fail_unless (gst_pad_set_caps (sinkpad, + (GstCaps *) gst_pad_get_pad_template_caps (mysrcpad))); + s = gst_caps_get_structure (GST_PAD_CAPS (srcpad), 0); + fail_unless (!g_strcmp0 (gst_structure_get_string (s, "profile"), + "constrained-baseline")); + + fail_unless (gst_element_set_state (x264enc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + g_object_set (x264enc, "profile", 3, NULL); + fail_unless (gst_element_set_state (x264enc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + fail_unless (gst_pad_set_caps (sinkpad, + (GstCaps *) gst_pad_get_pad_template_caps (mysrcpad))); + s = gst_caps_get_structure (GST_PAD_CAPS (srcpad), 0); + fail_unless (!g_strcmp0 (gst_structure_get_string (s, "profile"), "high")); + + fail_unless (gst_element_set_state (x264enc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + g_object_set (x264enc, "profile", 2, NULL); + fail_unless (gst_element_set_state (x264enc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + fail_unless (gst_pad_set_caps (sinkpad, + (GstCaps *) gst_pad_get_pad_template_caps (mysrcpad))); + s = gst_caps_get_structure (GST_PAD_CAPS (srcpad), 0); + fail_unless (!g_strcmp0 (gst_structure_get_string (s, "profile"), "main")); + + s = gst_caps_get_structure (pad_caps, 0); + gst_structure_set (s, "profile", G_TYPE_STRING, "constrained-baseline", NULL); + fail_unless (gst_element_set_state (x264enc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + fail_unless (gst_element_set_state (x264enc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + fail_unless (gst_pad_set_caps (sinkpad, + (GstCaps *) gst_pad_get_pad_template_caps (mysrcpad))); + s = gst_caps_get_structure (GST_PAD_CAPS (srcpad), 0); + fail_unless (!g_strcmp0 (gst_structure_get_string (s, "profile"), + "constrained-baseline")); + + s = gst_caps_get_structure (pad_caps, 0); + gst_structure_set (s, "profile", G_TYPE_STRING, "high", NULL); + fail_unless (gst_element_set_state (x264enc, + GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS, + "could not set to ready"); + fail_unless (gst_element_set_state (x264enc, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + fail_unless (gst_pad_set_caps (sinkpad, + (GstCaps *) gst_pad_get_pad_template_caps (mysrcpad))); + s = gst_caps_get_structure (GST_PAD_CAPS (srcpad), 0); + fail_unless (!g_strcmp0 (gst_structure_get_string (s, "profile"), "high")); + + gst_object_unref (srcpad); + gst_object_unref (sinkpad); + cleanup_x264enc (x264enc); + gst_caps_unref (pad_caps); +} + +GST_END_TEST; + Suite * x264enc_suite (void) { @@ -219,6 +321,7 @@ x264enc_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_video_pad); + tcase_add_test (tc_chain, test_profile_in_caps); return s; }