diff --git a/ext/celt/gstceltdec.c b/ext/celt/gstceltdec.c index e27c6a52c8..f80e5cdb18 100644 --- a/ext/celt/gstceltdec.c +++ b/ext/celt/gstceltdec.c @@ -734,7 +734,12 @@ celt_dec_chain_parse_data (GstCeltDec * dec, GstBuffer * buf, } if (dec->discont) { +#ifdef CELT_GET_LOOKAHEAD_REQUEST + /* what will be 0.11.5, I guess, but no versioning yet in git */ + celt_decoder_ctl (dec->state, CELT_GET_LOOKAHEAD_REQUEST, &skip); +#else celt_mode_info (dec->mode, CELT_GET_LOOKAHEAD, &skip); +#endif } res = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, diff --git a/ext/dirac/gstdiracenc.cc b/ext/dirac/gstdiracenc.cc index 118a315279..eb19d78071 100644 --- a/ext/dirac/gstdiracenc.cc +++ b/ext/dirac/gstdiracenc.cc @@ -145,8 +145,6 @@ static GstFlowReturn gst_dirac_enc_handle_frame (GstBaseVideoEncoder * base_video_encoder, GstVideoFrame * frame); static GstFlowReturn gst_dirac_enc_shape_output (GstBaseVideoEncoder * base_video_encoder, GstVideoFrame * frame); -static GstCaps *gst_dirac_enc_get_caps (GstBaseVideoEncoder * - base_video_encoder); static void gst_dirac_enc_create_codec_data (GstDiracEnc * dirac_enc, GstBuffer * seq_header); @@ -314,7 +312,6 @@ gst_dirac_enc_class_init (GstDiracEncClass * klass) GST_DEBUG_FUNCPTR (gst_dirac_enc_handle_frame); basevideoencoder_class->shape_output = GST_DEBUG_FUNCPTR (gst_dirac_enc_shape_output); - basevideoencoder_class->get_caps = GST_DEBUG_FUNCPTR (gst_dirac_enc_get_caps); } static void @@ -331,29 +328,10 @@ gst_dirac_enc_set_format (GstBaseVideoEncoder * base_video_encoder, { GstDiracEnc *dirac_enc = GST_DIRAC_ENC (base_video_encoder); GstCaps *caps; - GstStructure *structure; + gboolean ret; GST_DEBUG ("set_format"); - caps = - gst_pad_get_allowed_caps (GST_BASE_VIDEO_CODEC_SRC_PAD - (base_video_encoder)); - - if (caps == NULL) { - caps = - gst_caps_copy (gst_pad_get_pad_template_caps - (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder))); - } - - if (gst_caps_is_empty (caps)) { - gst_caps_unref (caps); - return FALSE; - } - - structure = gst_caps_get_structure (caps, 0); - - gst_caps_unref (caps); - gst_base_video_encoder_set_latency_fields (base_video_encoder, 2 * 2); switch (state->format) { @@ -402,7 +380,18 @@ gst_dirac_enc_set_format (GstBaseVideoEncoder * base_video_encoder, dirac_enc->encoder = dirac_encoder_init (&dirac_enc->enc_ctx, FALSE); - return TRUE; + caps = gst_caps_new_simple ("video/x-dirac", + "width", G_TYPE_INT, state->width, + "height", G_TYPE_INT, state->height, + "framerate", GST_TYPE_FRACTION, state->fps_n, + state->fps_d, + "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, + state->par_d, NULL); + + ret = gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (dirac_enc), caps); + gst_caps_unref (caps); + + return ret; } static void @@ -1112,7 +1101,7 @@ static GstFlowReturn gst_dirac_enc_process (GstDiracEnc * dirac_enc, gboolean end_sequence) { GstBuffer *outbuf; - GstFlowReturn ret; + GstFlowReturn ret = GST_FLOW_OK; int parse_code; int state; GstVideoFrame *frame; @@ -1174,7 +1163,28 @@ gst_dirac_enc_process (GstDiracEnc * dirac_enc, gboolean end_sequence) } if (!dirac_enc->codec_data) { + GstCaps *caps; + const GstVideoState *state = gst_base_video_encoder_get_state (GST_BASE_VIDEO_ENCODER (dirac_enc)); + gst_dirac_enc_create_codec_data (dirac_enc, outbuf); + + caps = gst_caps_new_simple ("video/x-dirac", + "width", G_TYPE_INT, state->width, + "height", G_TYPE_INT, state->height, + "framerate", GST_TYPE_FRACTION, state->fps_n, + state->fps_d, + "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, + state->par_d, "streamheader", GST_TYPE_BUFFER, dirac_enc->codec_data, + NULL); + if (!gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (dirac_enc), caps)) + ret = GST_FLOW_NOT_NEGOTIATED; + gst_caps_unref (caps); + + if (ret != GST_FLOW_OK) { + GST_ERROR ("Failed to set srcpad caps"); + gst_buffer_unref (outbuf); + return ret; + } } frame->src_buffer = outbuf; @@ -1245,10 +1255,6 @@ static GstFlowReturn gst_dirac_enc_shape_output (GstBaseVideoEncoder * base_video_encoder, GstVideoFrame * frame) { - GstDiracEnc *dirac_enc; - - dirac_enc = GST_DIRAC_ENC (base_video_encoder); - gst_dirac_enc_shape_output_ogg (base_video_encoder, frame); return GST_FLOW_ERROR; @@ -1286,25 +1292,4 @@ gst_dirac_enc_create_codec_data (GstDiracEnc * dirac_enc, dirac_enc->codec_data = buf; } -static GstCaps * -gst_dirac_enc_get_caps (GstBaseVideoEncoder * base_video_encoder) -{ - GstCaps *caps; - const GstVideoState *state; - GstDiracEnc *dirac_enc; - dirac_enc = GST_DIRAC_ENC (base_video_encoder); - - state = gst_base_video_encoder_get_state (base_video_encoder); - - caps = gst_caps_new_simple ("video/x-dirac", - "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, - "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, - "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, - state->par_d, - "streamheader", GST_TYPE_BUFFER, dirac_enc->codec_data, NULL); - - return caps; -} diff --git a/ext/ofa/gstofa.c b/ext/ofa/gstofa.c index d1be48635e..a18d7e352e 100644 --- a/ext/ofa/gstofa.c +++ b/ext/ofa/gstofa.c @@ -117,16 +117,27 @@ create_fingerprint (GstOFA * ofa) GstBuffer *buf; gint rate = GST_AUDIO_FILTER (ofa)->format.rate; gint channels = GST_AUDIO_FILTER (ofa)->format.channels; - gint endianness = - (GST_AUDIO_FILTER (ofa)->format. - bigend) ? OFA_BIG_ENDIAN : OFA_LITTLE_ENDIAN; + gint endianness; GstTagList *tags; + guint available; + + available = gst_adapter_available (ofa->adapter); + + if (available == 0) { + GST_WARNING_OBJECT (ofa, "No data to take fingerprint from"); + ofa->record = FALSE; + return; + } + + if (GST_AUDIO_FILTER (ofa)->format.bigend) + endianness = OFA_BIG_ENDIAN; + else + endianness = OFA_LITTLE_ENDIAN; + GST_DEBUG ("Generating fingerprint"); - buf = - gst_adapter_take_buffer (ofa->adapter, - gst_adapter_available (ofa->adapter)); + buf = gst_adapter_take_buffer (ofa->adapter, available); ofa->fingerprint = g_strdup (ofa_create_print (GST_BUFFER_DATA (buf), endianness, GST_BUFFER_SIZE (buf) / 2, rate, diff --git a/ext/opencv/gstmotioncells.c b/ext/opencv/gstmotioncells.c index a349bcac1d..71b41c350a 100644 --- a/ext/opencv/gstmotioncells.c +++ b/ext/opencv/gstmotioncells.c @@ -105,9 +105,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_motion_cells_debug); POINTER = NULL;\ } -int instanceCounter = 0; -gboolean element_id_was_max = false; - /* Filter signals and args */ enum { @@ -396,8 +393,7 @@ gst_motion_cells_init (GstMotioncells * filter, GstMotioncellsClass * gclass) filter->datafileidx = 0; g_mutex_lock (filter->propset_mutex); - filter->id = instanceCounter; - motion_cells_init (); + filter->id = motion_cells_init (); g_mutex_unlock (filter->propset_mutex); } diff --git a/ext/opencv/motioncells_wrapper.cpp b/ext/opencv/motioncells_wrapper.cpp index b768f9ece9..d509686774 100644 --- a/ext/opencv/motioncells_wrapper.cpp +++ b/ext/opencv/motioncells_wrapper.cpp @@ -46,12 +46,13 @@ #include #include "motioncells_wrapper.h" -extern int instanceCounter; -extern bool element_id_was_max; +static int instanceCounter = 0; +static gboolean element_id_was_max = false; + MotionCells *mc; char p_str[] = "idx failed"; -void +int motion_cells_init () { mc = new MotionCells (); @@ -67,6 +68,7 @@ motion_cells_init () instanceCounter = motioncellsfreeids.back (); motioncellsfreeids.pop_back (); } + return tmpmc.id; } int diff --git a/ext/opencv/motioncells_wrapper.h b/ext/opencv/motioncells_wrapper.h index 0feaafa8bd..470bcfbe42 100644 --- a/ext/opencv/motioncells_wrapper.h +++ b/ext/opencv/motioncells_wrapper.h @@ -62,7 +62,7 @@ extern "C" { #endif - void motion_cells_init (); + int motion_cells_init (); int perform_detection_motion_cells (IplImage * p_image, double p_sensitivity, double p_framerate, int p_gridx, int p_gridy, long int p_timestamp_millisec, bool p_isVisible, bool p_useAlpha, diff --git a/ext/schroedinger/gstschroenc.c b/ext/schroedinger/gstschroenc.c index ffb4bdb8d7..beda4eac96 100644 --- a/ext/schroedinger/gstschroenc.c +++ b/ext/schroedinger/gstschroenc.c @@ -60,7 +60,6 @@ struct _GstSchroEnc /* state */ SchroEncoder *encoder; SchroVideoFormat *video_format; - GstBuffer *seq_header_buffer; guint64 last_granulepos; guint64 granule_offset; @@ -102,8 +101,6 @@ static GstFlowReturn gst_schro_enc_handle_frame (GstBaseVideoEncoder * base_video_encoder, GstVideoFrame * frame); static GstFlowReturn gst_schro_enc_shape_output (GstBaseVideoEncoder * base_video_encoder, GstVideoFrame * frame); -static GstCaps *gst_schro_enc_get_caps (GstBaseVideoEncoder * - base_video_encoder); static GstStaticPadTemplate gst_schro_enc_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", @@ -219,7 +216,6 @@ gst_schro_enc_class_init (GstSchroEncClass * klass) GST_DEBUG_FUNCPTR (gst_schro_enc_handle_frame); basevideocoder_class->shape_output = GST_DEBUG_FUNCPTR (gst_schro_enc_shape_output); - basevideocoder_class->get_caps = GST_DEBUG_FUNCPTR (gst_schro_enc_get_caps); } static void @@ -241,28 +237,12 @@ static gboolean gst_schro_enc_set_format (GstBaseVideoEncoder * base_video_encoder, GstVideoState * state) { - GstCaps *caps; - GstStructure *structure; GstSchroEnc *schro_enc = GST_SCHRO_ENC (base_video_encoder); + GstCaps *caps; + GstBuffer *seq_header_buffer; + gboolean ret; GST_DEBUG ("set_output_caps"); - caps = - gst_pad_get_allowed_caps (GST_BASE_VIDEO_CODEC_SRC_PAD - (base_video_encoder)); - if (caps == NULL) { - caps = - gst_caps_copy (gst_pad_get_pad_template_caps - (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder))); - } - - if (gst_caps_is_empty (caps)) { - gst_caps_unref (caps); - return FALSE; - } - - structure = gst_caps_get_structure (caps, 0); - - gst_caps_unref (caps); gst_base_video_encoder_set_latency_fields (base_video_encoder, 2 * (int) schro_encoder_setting_get_double (schro_enc->encoder, @@ -311,13 +291,58 @@ gst_schro_enc_set_format (GstBaseVideoEncoder * base_video_encoder, schro_encoder_set_video_format (schro_enc->encoder, schro_enc->video_format); schro_encoder_start (schro_enc->encoder); - schro_enc->seq_header_buffer = + seq_header_buffer = gst_schro_wrap_schro_buffer (schro_encoder_encode_sequence_header (schro_enc->encoder)); schro_enc->granule_offset = ~0; - return TRUE; + caps = gst_caps_new_simple ("video/x-dirac", + "width", G_TYPE_INT, state->width, + "height", G_TYPE_INT, state->height, + "framerate", GST_TYPE_FRACTION, state->fps_n, + state->fps_d, + "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, + state->par_d, NULL); + + GST_BUFFER_FLAG_SET (seq_header_buffer, GST_BUFFER_FLAG_IN_CAPS); + { + GValue array = { 0 }; + GValue value = { 0 }; + GstBuffer *buf; + int size; + + g_value_init (&array, GST_TYPE_ARRAY); + g_value_init (&value, GST_TYPE_BUFFER); + size = GST_BUFFER_SIZE (seq_header_buffer); + buf = gst_buffer_new_and_alloc (size + SCHRO_PARSE_HEADER_SIZE); + + /* ogg(mux) expects the header buffers to have 0 timestamps - + set OFFSET and OFFSET_END accordingly */ + GST_BUFFER_OFFSET (buf) = 0; + GST_BUFFER_OFFSET_END (buf) = 0; + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS); + + memcpy (GST_BUFFER_DATA (buf), GST_BUFFER_DATA (seq_header_buffer), size); + GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + size + 0, 0x42424344); + GST_WRITE_UINT8 (GST_BUFFER_DATA (buf) + size + 4, + SCHRO_PARSE_CODE_END_OF_SEQUENCE); + GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + size + 5, 0); + GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + size + 9, size); + gst_value_set_buffer (&value, buf); + gst_buffer_unref (buf); + gst_value_array_append_value (&array, &value); + gst_structure_set_value (gst_caps_get_structure (caps, 0), + "streamheader", &array); + g_value_unset (&value); + g_value_unset (&array); + } + gst_buffer_unref (seq_header_buffer); + + ret = gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (schro_enc), caps); + gst_caps_unref (caps); + + return ret; } static void @@ -404,10 +429,6 @@ gst_schro_enc_stop (GstBaseVideoEncoder * base_video_encoder) schro_encoder_free (schro_enc->encoder); schro_enc->encoder = NULL; } - if (schro_enc->seq_header_buffer) { - gst_buffer_unref (schro_enc->seq_header_buffer); - schro_enc->seq_header_buffer = NULL; - } if (schro_enc->video_format) { g_free (schro_enc->video_format); schro_enc->video_format = NULL; @@ -458,91 +479,6 @@ gst_schro_enc_handle_frame (GstBaseVideoEncoder * base_video_encoder, return ret; } -#if 0 -static void -gst_caps_add_streamheader (GstCaps * caps, GList * list) -{ - GValue array = { 0 }; - GValue value = { 0 }; - GstBuffer *buf; - GList *g; - - g_value_init (&array, GST_TYPE_ARRAY); - - for (g = g_list_first (list); g; g = g_list_next (list)) { - g_value_init (&value, GST_TYPE_BUFFER); - buf = gst_buffer_copy (GST_BUFFER (g->data)); - gst_value_set_buffer (&value, buf); - gst_buffer_unref (buf); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - } - gst_structure_set_value (gst_caps_get_structure (caps, 0), - "streamheader", &array); - g_value_unset (&array); -} -#endif - -static GstCaps * -gst_schro_enc_get_caps (GstBaseVideoEncoder * base_video_encoder) -{ - GstCaps *caps; - const GstVideoState *state; - GstSchroEnc *schro_enc; - - schro_enc = GST_SCHRO_ENC (base_video_encoder); - - state = gst_base_video_encoder_get_state (base_video_encoder); - - caps = gst_caps_new_simple ("video/x-dirac", - "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, - "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, - "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, - state->par_d, NULL); - - GST_BUFFER_FLAG_SET (schro_enc->seq_header_buffer, GST_BUFFER_FLAG_IN_CAPS); - - { - GValue array = { 0 }; - GValue value = { 0 }; - GstBuffer *buf; - int size; - - g_value_init (&array, GST_TYPE_ARRAY); - g_value_init (&value, GST_TYPE_BUFFER); - size = GST_BUFFER_SIZE (schro_enc->seq_header_buffer); - buf = gst_buffer_new_and_alloc (size + SCHRO_PARSE_HEADER_SIZE); - - /* ogg(mux) expects the header buffers to have 0 timestamps - - set OFFSET and OFFSET_END accordingly */ - GST_BUFFER_OFFSET (buf) = 0; - GST_BUFFER_OFFSET_END (buf) = 0; - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS); - - memcpy (GST_BUFFER_DATA (buf), - GST_BUFFER_DATA (schro_enc->seq_header_buffer), size); - GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + size + 0, 0x42424344); - GST_WRITE_UINT8 (GST_BUFFER_DATA (buf) + size + 4, - SCHRO_PARSE_CODE_END_OF_SEQUENCE); - GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + size + 5, 0); - GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + size + 9, size); - gst_value_set_buffer (&value, buf); - gst_buffer_unref (buf); - gst_value_array_append_value (&array, &value); - gst_structure_set_value (gst_caps_get_structure (caps, 0), - "streamheader", &array); - g_value_unset (&value); - g_value_unset (&array); - } - - return caps; -} - - - - static GstFlowReturn gst_schro_enc_shape_output (GstBaseVideoEncoder * base_video_encoder, GstVideoFrame * frame) diff --git a/ext/vp8/gstvp8enc.c b/ext/vp8/gstvp8enc.c index 26f79fadc6..78325265ad 100644 --- a/ext/vp8/gstvp8enc.c +++ b/ext/vp8/gstvp8enc.c @@ -220,7 +220,6 @@ static GstFlowReturn gst_vp8_enc_shape_output (GstBaseVideoEncoder * encoder, GstVideoFrame * frame); static gboolean gst_vp8_enc_sink_event (GstBaseVideoEncoder * base_video_encoder, GstEvent * event); -static GstCaps *gst_vp8_enc_get_caps (GstBaseVideoEncoder * base_video_encoder); static GstStaticPadTemplate gst_vp8_enc_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", @@ -291,7 +290,6 @@ gst_vp8_enc_class_init (GstVP8EncClass * klass) base_video_encoder_class->finish = gst_vp8_enc_finish; base_video_encoder_class->shape_output = gst_vp8_enc_shape_output; base_video_encoder_class->event = gst_vp8_enc_sink_event; - base_video_encoder_class->get_caps = gst_vp8_enc_get_caps; g_object_class_install_property (gobject_class, PROP_BITRATE, g_param_spec_int ("bitrate", "Bit rate", @@ -695,6 +693,8 @@ gst_vp8_enc_set_format (GstBaseVideoEncoder * base_video_encoder, vpx_codec_err_t status; vpx_image_t *image; guint8 *data = NULL; + GstCaps *caps; + gboolean ret; encoder = GST_VP8_ENC (base_video_encoder); GST_DEBUG_OBJECT (base_video_encoder, "set_format"); @@ -845,23 +845,6 @@ gst_vp8_enc_set_format (GstBaseVideoEncoder * base_video_encoder, data + gst_video_format_get_component_offset (state->format, 2, state->width, state->height); - return TRUE; -} - -static GstCaps * -gst_vp8_enc_get_caps (GstBaseVideoEncoder * base_video_encoder) -{ - GstCaps *caps; - const GstVideoState *state; - GstTagList *tags = NULL; - const GstTagList *iface_tags; - GstBuffer *stream_hdr, *vorbiscomment; - guint8 *data; - GstStructure *s; - GValue array = { 0 }; - GValue value = { 0 }; - - state = gst_base_video_encoder_get_state (base_video_encoder); caps = gst_caps_new_simple ("video/x-vp8", "width", G_TYPE_INT, state->width, @@ -870,56 +853,66 @@ gst_vp8_enc_get_caps (GstBaseVideoEncoder * base_video_encoder) state->fps_d, "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, state->par_d, NULL); + { + GstStructure *s; + GstBuffer *stream_hdr, *vorbiscomment; + const GstTagList *iface_tags; + GstTagList *tags; + GValue array = { 0, }; + GValue value = { 0, }; + s = gst_caps_get_structure (caps, 0); - s = gst_caps_get_structure (caps, 0); - - /* put buffers in a fixed list */ - g_value_init (&array, GST_TYPE_ARRAY); - g_value_init (&value, GST_TYPE_BUFFER); - - /* Create Ogg stream-info */ - stream_hdr = gst_buffer_new_and_alloc (26); - data = GST_BUFFER_DATA (stream_hdr); - - GST_WRITE_UINT8 (data, 0x4F); - GST_WRITE_UINT32_BE (data + 1, 0x56503830); /* "VP80" */ - GST_WRITE_UINT8 (data + 5, 0x01); /* stream info header */ - GST_WRITE_UINT8 (data + 6, 1); /* Major version 1 */ - GST_WRITE_UINT8 (data + 7, 0); /* Minor version 0 */ - GST_WRITE_UINT16_BE (data + 8, state->width); - GST_WRITE_UINT16_BE (data + 10, state->height); - GST_WRITE_UINT24_BE (data + 12, state->par_n); - GST_WRITE_UINT24_BE (data + 15, state->par_d); - GST_WRITE_UINT32_BE (data + 18, state->fps_n); - GST_WRITE_UINT32_BE (data + 22, state->fps_d); - - GST_BUFFER_FLAG_SET (stream_hdr, GST_BUFFER_FLAG_IN_CAPS); - gst_value_set_buffer (&value, stream_hdr); - gst_value_array_append_value (&array, &value); - g_value_unset (&value); - gst_buffer_unref (stream_hdr); - - iface_tags = - gst_tag_setter_get_tag_list (GST_TAG_SETTER (base_video_encoder)); - if (iface_tags) { - vorbiscomment = - gst_tag_list_to_vorbiscomment_buffer ((iface_tags) ? iface_tags : tags, - (const guint8 *) "OVP80\2 ", 7, - "Encoded with GStreamer vp8enc " PACKAGE_VERSION); - - GST_BUFFER_FLAG_SET (vorbiscomment, GST_BUFFER_FLAG_IN_CAPS); - + /* put buffers in a fixed list */ + g_value_init (&array, GST_TYPE_ARRAY); g_value_init (&value, GST_TYPE_BUFFER); - gst_value_set_buffer (&value, vorbiscomment); + + /* Create Ogg stream-info */ + stream_hdr = gst_buffer_new_and_alloc (26); + data = GST_BUFFER_DATA (stream_hdr); + + GST_WRITE_UINT8 (data, 0x4F); + GST_WRITE_UINT32_BE (data + 1, 0x56503830); /* "VP80" */ + GST_WRITE_UINT8 (data + 5, 0x01); /* stream info header */ + GST_WRITE_UINT8 (data + 6, 1); /* Major version 1 */ + GST_WRITE_UINT8 (data + 7, 0); /* Minor version 0 */ + GST_WRITE_UINT16_BE (data + 8, state->width); + GST_WRITE_UINT16_BE (data + 10, state->height); + GST_WRITE_UINT24_BE (data + 12, state->par_n); + GST_WRITE_UINT24_BE (data + 15, state->par_d); + GST_WRITE_UINT32_BE (data + 18, state->fps_n); + GST_WRITE_UINT32_BE (data + 22, state->fps_d); + + GST_BUFFER_FLAG_SET (stream_hdr, GST_BUFFER_FLAG_IN_CAPS); + gst_value_set_buffer (&value, stream_hdr); gst_value_array_append_value (&array, &value); g_value_unset (&value); - gst_buffer_unref (vorbiscomment); + gst_buffer_unref (stream_hdr); + + iface_tags = + gst_tag_setter_get_tag_list (GST_TAG_SETTER (base_video_encoder)); + if (iface_tags) { + vorbiscomment = + gst_tag_list_to_vorbiscomment_buffer ((iface_tags) ? iface_tags : + tags, (const guint8 *) "OVP80\2 ", 7, + "Encoded with GStreamer vp8enc " PACKAGE_VERSION); + + GST_BUFFER_FLAG_SET (vorbiscomment, GST_BUFFER_FLAG_IN_CAPS); + + g_value_init (&value, GST_TYPE_BUFFER); + gst_value_set_buffer (&value, vorbiscomment); + gst_value_array_append_value (&array, &value); + g_value_unset (&value); + gst_buffer_unref (vorbiscomment); + } + + gst_structure_set_value (s, "streamheader", &array); + g_value_unset (&array); } - gst_structure_set_value (s, "streamheader", &array); - g_value_unset (&array); + ret = gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (encoder), caps); + gst_caps_unref (caps); - return caps; + return ret; } static GstFlowReturn diff --git a/gst-libs/gst/video/gstbasevideodecoder.c b/gst-libs/gst/video/gstbasevideodecoder.c index 0278abc83e..5392d44866 100644 --- a/gst-libs/gst/video/gstbasevideodecoder.c +++ b/gst-libs/gst/video/gstbasevideodecoder.c @@ -1917,11 +1917,9 @@ gst_base_video_decoder_alloc_src_buffer (GstBaseVideoDecoder * { GstBuffer *buffer; GstFlowReturn flow_ret; - int num_bytes; GstVideoState *state = &GST_BASE_VIDEO_CODEC (base_video_decoder)->state; + int num_bytes = state->bytes_per_picture; - num_bytes = gst_video_format_get_size (state->format, state->width, - state->height); GST_DEBUG ("alloc src buffer caps=%" GST_PTR_FORMAT, GST_PAD_CAPS (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_decoder))); flow_ret = diff --git a/gst-libs/gst/video/gstbasevideoencoder.c b/gst-libs/gst/video/gstbasevideoencoder.c index e4efe6d39f..88d8c72dc8 100644 --- a/gst-libs/gst/video/gstbasevideoencoder.c +++ b/gst-libs/gst/video/gstbasevideoencoder.c @@ -91,7 +91,7 @@ * * Provide pad templates * - * Provide source pad caps in @get_caps. + * Provide source pad caps before pushing the first buffer * * * Accept data in @handle_frame and provide encoded results to @@ -117,6 +117,7 @@ static void gst_base_video_encoder_finalize (GObject * object); static gboolean gst_base_video_encoder_sink_setcaps (GstPad * pad, GstCaps * caps); +static GstCaps *gst_base_video_encoder_sink_getcaps (GstPad * pad); static gboolean gst_base_video_encoder_src_event (GstPad * pad, GstEvent * event); static gboolean gst_base_video_encoder_sink_event (GstPad * pad, @@ -179,7 +180,6 @@ gst_base_video_encoder_reset (GstBaseVideoEncoder * base_video_encoder) base_video_encoder->distance_from_sync = 0; base_video_encoder->force_keyframe = FALSE; - base_video_encoder->set_output_caps = FALSE; base_video_encoder->drained = TRUE; base_video_encoder->min_latency = 0; base_video_encoder->max_latency = 0; @@ -211,6 +211,8 @@ gst_base_video_encoder_init (GstBaseVideoEncoder * base_video_encoder, GST_DEBUG_FUNCPTR (gst_base_video_encoder_sink_event)); gst_pad_set_setcaps_function (pad, GST_DEBUG_FUNCPTR (gst_base_video_encoder_sink_setcaps)); + gst_pad_set_getcaps_function (pad, + GST_DEBUG_FUNCPTR (gst_base_video_encoder_sink_getcaps)); pad = GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder); @@ -359,6 +361,74 @@ exit: return ret; } +static GstCaps * +gst_base_video_encoder_sink_getcaps (GstPad * pad) +{ + GstBaseVideoEncoder *base_video_encoder; + const GstCaps *templ_caps; + GstCaps *allowed; + GstCaps *fcaps, *filter_caps; + gint i, j; + + base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); + + /* FIXME: Allow subclass to override this? */ + + /* Allow downstream to specify width/height/framerate/PAR constraints + * and forward them upstream for video converters to handle + */ + templ_caps = + gst_pad_get_pad_template_caps (GST_BASE_VIDEO_CODEC_SINK_PAD + (base_video_encoder)); + allowed = + gst_pad_get_allowed_caps (GST_BASE_VIDEO_CODEC_SRC_PAD + (base_video_encoder)); + if (!allowed || gst_caps_is_empty (allowed) || gst_caps_is_any (allowed)) { + fcaps = gst_caps_copy (templ_caps); + goto done; + } + + GST_LOG_OBJECT (base_video_encoder, "template caps %" GST_PTR_FORMAT, + templ_caps); + GST_LOG_OBJECT (base_video_encoder, "allowed caps %" GST_PTR_FORMAT, allowed); + + filter_caps = gst_caps_new_empty (); + + for (i = 0; i < gst_caps_get_size (templ_caps); i++) { + GQuark q_name = + gst_structure_get_name_id (gst_caps_get_structure (templ_caps, i)); + + for (j = 0; j < gst_caps_get_size (allowed); j++) { + const GstStructure *allowed_s = gst_caps_get_structure (allowed, j); + const GValue *val; + GstStructure *s; + + s = gst_structure_id_empty_new (q_name); + if ((val = gst_structure_get_value (allowed_s, "width"))) + gst_structure_set_value (s, "width", val); + if ((val = gst_structure_get_value (allowed_s, "height"))) + gst_structure_set_value (s, "height", val); + if ((val = gst_structure_get_value (allowed_s, "framerate"))) + gst_structure_set_value (s, "framerate", val); + if ((val = gst_structure_get_value (allowed_s, "pixel-aspect-ratio"))) + gst_structure_set_value (s, "pixel-aspect-ratio", val); + + gst_caps_merge_structure (filter_caps, s); + } + } + + fcaps = gst_caps_intersect (filter_caps, templ_caps); + gst_caps_unref (filter_caps); + +done: + + gst_caps_replace (&allowed, NULL); + + GST_LOG_OBJECT (base_video_encoder, "Returning caps %" GST_PTR_FORMAT, fcaps); + + return fcaps; +} + static void gst_base_video_encoder_finalize (GObject * object) { @@ -761,27 +831,6 @@ gst_base_video_encoder_finish_frame (GstBaseVideoEncoder * base_video_encoder, GST_LOG_OBJECT (base_video_encoder, "finish frame fpn %d", frame->presentation_frame_number); - /* FIXME get rid of this ? - * seems a roundabout way that adds little benefit to simply get - * and subsequently set. subclass is adult enough to set_caps itself ... - * so simply check/ensure/assert that src pad caps are set by now */ - if (!base_video_encoder->set_output_caps) { - if (!GST_PAD_CAPS (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder))) { - GstCaps *caps; - - if (base_video_encoder_class->get_caps) { - caps = base_video_encoder_class->get_caps (base_video_encoder); - } else { - caps = gst_caps_new_simple ("video/unknown", NULL); - } - GST_DEBUG_OBJECT (base_video_encoder, "src caps %" GST_PTR_FORMAT, caps); - gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), - caps); - gst_caps_unref (caps); - } - base_video_encoder->set_output_caps = TRUE; - } - /* Push all pending events that arrived before this frame */ for (l = base_video_encoder->base_video_codec.frames; l; l = l->next) { GstVideoFrame *tmp = l->data; diff --git a/gst-libs/gst/video/gstbasevideoencoder.h b/gst-libs/gst/video/gstbasevideoencoder.h index e1dd03be13..c712fe86e5 100644 --- a/gst-libs/gst/video/gstbasevideoencoder.h +++ b/gst-libs/gst/video/gstbasevideoencoder.h @@ -89,7 +89,6 @@ struct _GstBaseVideoEncoder /*< private >*/ /* FIXME move to real private part ? * (and introduce a context ?) */ - gboolean set_output_caps; gboolean drained; gint64 min_latency; @@ -131,8 +130,6 @@ struct _GstBaseVideoEncoder * Event handler on the sink pad. This function should return * TRUE if the event was handled and should be discarded * (i.e. not unref'ed). - * @getcaps: Optional, but recommended. - * Provides src pad caps to baseclass. * * Subclasses can override any of the available virtual methods or not, as * needed. At minimum @handle_frame needs to be overridden, and @set_format @@ -164,8 +161,6 @@ struct _GstBaseVideoEncoderClass gboolean (*event) (GstBaseVideoEncoder *coder, GstEvent *event); - GstCaps * (*get_caps) (GstBaseVideoEncoder *coder); - /*< private >*/ /* FIXME before moving to base */ gpointer _gst_reserved[GST_PADDING_LARGE]; diff --git a/gst/aiff/aiffmux.c b/gst/aiff/aiffmux.c index 39770cf2e3..a2d99f587c 100644 --- a/gst/aiff/aiffmux.c +++ b/gst/aiff/aiffmux.c @@ -130,6 +130,7 @@ gst_aiff_mux_change_state (GstElement * element, GstStateChange transition) aiffmux->length = 0; aiffmux->rate = 0.0; aiffmux->sent_header = FALSE; + aiffmux->overflow = FALSE; break; default: break; @@ -160,7 +161,7 @@ gst_aiff_mux_class_init (GstAiffMuxClass * klass) (AIFF_FORM_HEADER_LEN + AIFF_COMM_HEADER_LEN + AIFF_SSND_HEADER_LEN) static void -gst_aiff_mux_write_form_header (GstAiffMux * aiffmux, guint audio_data_size, +gst_aiff_mux_write_form_header (GstAiffMux * aiffmux, guint32 audio_data_size, GstByteWriter * writer) { /* ckID == 'FORM' */ @@ -228,7 +229,7 @@ gst_aiff_mux_write_ext (GstByteWriter * writer, double d) */ static void -gst_aiff_mux_write_comm_header (GstAiffMux * aiffmux, guint audio_data_size, +gst_aiff_mux_write_comm_header (GstAiffMux * aiffmux, guint32 audio_data_size, GstByteWriter * writer) { gst_byte_writer_put_uint32_le (writer, GST_MAKE_FOURCC ('C', 'O', 'M', 'M')); @@ -236,13 +237,13 @@ gst_aiff_mux_write_comm_header (GstAiffMux * aiffmux, guint audio_data_size, gst_byte_writer_put_uint16_be (writer, aiffmux->channels); /* numSampleFrames value will be overwritten when known */ gst_byte_writer_put_uint32_be (writer, - (audio_data_size * 8) / (aiffmux->width * aiffmux->channels)); + audio_data_size / (aiffmux->width / 8 * aiffmux->channels)); gst_byte_writer_put_uint16_be (writer, aiffmux->depth); gst_aiff_mux_write_ext (writer, aiffmux->rate); } static void -gst_aiff_mux_write_ssnd_header (GstAiffMux * aiffmux, guint audio_data_size, +gst_aiff_mux_write_ssnd_header (GstAiffMux * aiffmux, guint32 audio_data_size, GstByteWriter * writer) { gst_byte_writer_put_uint32_le (writer, GST_MAKE_FOURCC ('S', 'S', 'N', 'D')); @@ -255,7 +256,7 @@ gst_aiff_mux_write_ssnd_header (GstAiffMux * aiffmux, guint audio_data_size, } static GstFlowReturn -gst_aiff_mux_push_header (GstAiffMux * aiffmux, guint audio_data_size) +gst_aiff_mux_push_header (GstAiffMux * aiffmux, guint32 audio_data_size) { GstFlowReturn ret; GstBuffer *outbuf; @@ -296,12 +297,16 @@ gst_aiff_mux_chain (GstPad * pad, GstBuffer * buf) { GstAiffMux *aiffmux = GST_AIFF_MUX (GST_PAD_PARENT (pad)); GstFlowReturn flow = GST_FLOW_OK; + guint64 cur_size; if (!aiffmux->channels) { gst_buffer_unref (buf); return GST_FLOW_NOT_NEGOTIATED; } + if (G_UNLIKELY (aiffmux->overflow)) + goto overflow; + if (!aiffmux->sent_header) { /* use bogus size initially, we'll write the real * header when we get EOS and know the exact length */ @@ -316,6 +321,20 @@ gst_aiff_mux_chain (GstPad * pad, GstBuffer * buf) aiffmux->sent_header = TRUE; } + /* AIFF has an audio data size limit of slightly under 4 GB. + A value of audiosize + AIFF_HEADER_LEN - 8 is written, so + I'll error out if writing data that makes this overflow. */ + cur_size = aiffmux->length + AIFF_HEADER_LEN - 8; + if (G_UNLIKELY (cur_size + GST_BUFFER_SIZE (buf) >= G_MAXUINT32)) { + GST_ERROR_OBJECT (aiffmux, "AIFF only supports about 4 GB worth of " + "audio data, dropping any further data on the floor"); + GST_ELEMENT_WARNING (aiffmux, STREAM, MUX, ("AIFF has a 4GB size limit"), + ("AIFF only supports about 4 GB worth of audio data, " + "dropping any further data on the floor")); + aiffmux->overflow = TRUE; + goto overflow; + } + GST_LOG_OBJECT (aiffmux, "pushing %u bytes raw audio, ts=%" GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); @@ -330,6 +349,13 @@ gst_aiff_mux_chain (GstPad * pad, GstBuffer * buf) flow = gst_pad_push (aiffmux->srcpad, buf); return flow; + +overflow: + { + GST_WARNING_OBJECT (aiffmux, "output file too large, dropping buffer"); + gst_buffer_unref (buf); + return GST_FLOW_OK; + } } static gboolean diff --git a/gst/aiff/aiffmux.h b/gst/aiff/aiffmux.h index 73c1d89d3a..9c0954f589 100644 --- a/gst/aiff/aiffmux.h +++ b/gst/aiff/aiffmux.h @@ -81,6 +81,7 @@ struct _GstAiffMux gdouble rate; gboolean sent_header; + gboolean overflow; }; struct _GstAiffMuxClass diff --git a/gst/audiovisualizers/gstbaseaudiovisualizer.c b/gst/audiovisualizers/gstbaseaudiovisualizer.c index 52fe5acd42..6d42b7dc58 100644 --- a/gst/audiovisualizers/gstbaseaudiovisualizer.c +++ b/gst/audiovisualizers/gstbaseaudiovisualizer.c @@ -20,10 +20,13 @@ /** * SECTION:gstbaseaudiovisualizer * - * A basclass for scopes. It takes care of re-fitting the audio-rate to - * video-rate. It also provides several background shading effects. These - * effects are applied to a previous picture before the render() implementation - * can draw a new frame. + * A basclass for scopes (visualizers). It takes care of re-fitting the + * audio-rate to video-rate and handles renegotiation (downstream video size + * changes). + * + * It also provides several background shading effects. These effects are + * applied to a previous picture before the render() implementation can draw a + * new frame. */ #ifdef HAVE_CONFIG_H @@ -85,9 +88,19 @@ gst_base_audio_visualizer_shader_get_type (void) "fade-and-move-up"}, {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN, "Fade and move down", "fade-and-move-down"}, + {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT, "Fade and move left", + "fade-and-move-left"}, + {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT, + "Fade and move right", + "fade-and-move-right"}, {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT, - "Fade and move horizontaly out", - "fade-and-move-horiz-out"}, + "Fade and move horizontally out", "fade-and-move-horiz-out"}, + {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN, + "Fade and move horizontally in", "fade-and-move-horiz-in"}, + {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT, + "Fade and move vertically out", "fade-and-move-vert-out"}, + {GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN, + "Fade and move vertically in", "fade-and-move-vert-in"}, {0, NULL, NULL}, }; @@ -98,6 +111,59 @@ gst_base_audio_visualizer_shader_get_type (void) return shader_type; } +/* we're only supporting GST_VIDEO_FORMAT_xRGB right now) */ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + +#define SHADE1(_d, _s, _i, _r, _g, _b) \ +G_STMT_START { \ + _d[_i] = (_s[_i] > _b) ? _s[_i] - _b : 0; \ + _i++; \ + _d[_i] = (_s[_i] > _g) ? _s[_i] - _g : 0; \ + _i++; \ + _d[_i] = (_s[_i] > _r) ? _s[_i] - _r : 0; \ + _i++; \ + _d[_i++] = 0; \ +} G_STMT_END + +#define SHADE2(_d, _s, _j, _i, _r, _g, _b) \ +G_STMT_START { \ + _d[_j++] = (_s[_i] > _b) ? _s[_i] - _b : 0; \ + _i++; \ + _d[_j++] = (_s[_i] > _g) ? _s[_i] - _g : 0; \ + _i++; \ + _d[_j++] = (_s[_i] > _r) ? _s[_i] - _r : 0; \ + _i++; \ + _d[_j++] = 0; \ + _i++; \ +} G_STMT_END + +#else + +#define SHADE1(_d, _s, _i, _r, _g, _b) \ +G_STMT_START { \ + _d[_i++] = 0; \ + _d[_i] = (_s[_i] > _r) ? _s[_i] - _r : 0; \ + _i++; \ + _d[_i] = (_s[_i] > _g) ? _s[_i] - _g : 0; \ + _i++; \ + _d[_i] = (_s[_i] > _b) ? _s[_i] - _b : 0; \ + _i++; \ +} G_STMT_END + +#define SHADE2(_d, _s, _j, _i, _r, _g, _b) \ +G_STMT_START { \ + _d[_j++] = 0; \ + _i++; \ + _d[_j++] = (_s[_i] > _r) ? _s[_i] - _r : 0; \ + _i++; \ + _d[_j++] = (_s[_i] > _g) ? _s[_i] - _g : 0; \ + _i++; \ + _d[_j++] = (_s[_i] > _b) ? _s[_i] - _b : 0; \ + _i++; \ +} G_STMT_END + +#endif + static void shader_fade (GstBaseAudioVisualizer * scope, const guint8 * s, guint8 * d) { @@ -106,28 +172,9 @@ shader_fade (GstBaseAudioVisualizer * scope, const guint8 * s, guint8 * d) guint g = (scope->shade_amount >> 8) & 0xff; guint b = (scope->shade_amount >> 0) & 0xff; - /* we're only supporting GST_VIDEO_FORMAT_xRGB right now) */ -#if G_BYTE_ORDER == G_LITTLE_ENDIAN for (i = 0; i < bpf;) { - d[i] = (s[i] > b) ? s[i] - b : 0; - i++; - d[i] = (s[i] > g) ? s[i] - g : 0; - i++; - d[i] = (s[i] > r) ? s[i] - r : 0; - i++; - d[i++] = 0; + SHADE1 (d, s, i, r, g, b); } -#else - for (i = 0; i < bpf;) { - d[i++] = 0; - d[i] = (s[i] > r) ? s[i] - r : 0; - i++; - d[i] = (s[i] > g) ? s[i] - g : 0; - i++; - d[i] = (s[i] > b) ? s[i] - b : 0; - i++; - } -#endif } static void @@ -140,47 +187,9 @@ shader_fade_and_move_up (GstBaseAudioVisualizer * scope, const guint8 * s, guint g = (scope->shade_amount >> 8) & 0xff; guint b = (scope->shade_amount >> 0) & 0xff; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN for (j = 0, i = bpl; i < bpf;) { - d[j++] = (s[i] > b) ? s[i] - b : 0; - i++; - d[j++] = (s[i] > g) ? s[i] - g : 0; - i++; - d[j++] = (s[i] > r) ? s[i] - r : 0; - i++; - d[j++] = 0; - i++; + SHADE2 (d, s, j, i, r, g, b); } - for (i = 0; i < bpl; i += 4) { - d[j] = (s[j] > b) ? s[j] - b : 0; - j++; - d[j] = (s[j] > g) ? s[j] - g : 0; - j++; - d[j] = (s[j] > r) ? s[j] - r : 0; - j++; - d[j++] = 0; - } -#else - for (j = 0, i = bpl; i < bpf;) { - d[j++] = 0; - i++; - d[j++] = (s[i] > r) ? s[i] - r : 0; - i++; - d[j++] = (s[i] > g) ? s[i] - g : 0; - i++; - d[j++] = (s[i] > b) ? s[i] - b : 0; - i++; - } - for (i = 0; i < bpl; i += 4) { - d[j++] = 0; - d[j] = (s[j] > r) ? s[j] - r : 0; - j++; - d[j] = (s[j] > g) ? s[j] - g : 0; - j++; - d[j] = (s[j] > b) ? s[j] - b : 0; - j++; - } -#endif } static void @@ -193,47 +202,49 @@ shader_fade_and_move_down (GstBaseAudioVisualizer * scope, const guint8 * s, guint g = (scope->shade_amount >> 8) & 0xff; guint b = (scope->shade_amount >> 0) & 0xff; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - for (i = 0; i < bpl;) { - d[i] = (s[i] > b) ? s[i] - b : 0; - i++; - d[i] = (s[i] > g) ? s[i] - g : 0; - i++; - d[i] = (s[i] > r) ? s[i] - r : 0; - i++; - d[i++] = 0; - } for (j = bpl, i = 0; j < bpf;) { - d[j++] = (s[i] > b) ? s[i] - b : 0; - i++; - d[j++] = (s[i] > g) ? s[i] - g : 0; - i++; - d[j++] = (s[i] > r) ? s[i] - r : 0; - i++; - d[j++] = 0; - i++; + SHADE2 (d, s, j, i, r, g, b); } -#else - for (i = 0; i < bpl;) { - d[i++] = 0; - d[i] = (s[i] > r) ? s[i] - r : 0; - i++; - d[i] = (s[i] > g) ? s[i] - g : 0; - i++; - d[i] = (s[i] > b) ? s[i] - b : 0; - i++; +} + +static void +shader_fade_and_move_left (GstBaseAudioVisualizer * scope, + const guint8 * s, guint8 * d) +{ + guint i, j, k, bpf = scope->bpf; + guint w = scope->width; + guint r = (scope->shade_amount >> 16) & 0xff; + guint g = (scope->shade_amount >> 8) & 0xff; + guint b = (scope->shade_amount >> 0) & 0xff; + + /* move to the left */ + for (j = 0, i = 4; i < bpf;) { + for (k = 0; k < w - 1; k++) { + SHADE2 (d, s, j, i, r, g, b); + } + i += 4; + j += 4; } - for (j = bpl, i = 0; j < bpf;) { - d[j++] = 0; - i++; - d[j++] = (s[i] > r) ? s[i] - r : 0; - i++; - d[j++] = (s[i] > g) ? s[i] - g : 0; - i++; - d[j++] = (s[i] > b) ? s[i] - b : 0; - i++; +} + +static void +shader_fade_and_move_right (GstBaseAudioVisualizer * scope, + const guint8 * s, guint8 * d) +{ + guint i, j, k, bpf = scope->bpf; + guint w = scope->width; + guint r = (scope->shade_amount >> 16) & 0xff; + guint g = (scope->shade_amount >> 8) & 0xff; + guint b = (scope->shade_amount >> 0) & 0xff; + + /* move to the left */ + for (j = 4, i = 0; i < bpf;) { + for (k = 0; k < w - 1; k++) { + SHADE2 (d, s, j, i, r, g, b); + } + i += 4; + j += 4; } -#endif } static void @@ -246,91 +257,91 @@ shader_fade_and_move_horiz_out (GstBaseAudioVisualizer * scope, guint g = (scope->shade_amount >> 8) & 0xff; guint b = (scope->shade_amount >> 0) & 0xff; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - /* middle up */ + /* move upper half up */ for (j = 0, i = bpl; i < bpf;) { - d[j++] = (s[i] > b) ? s[i] - b : 0; - i++; - d[j++] = (s[i] > g) ? s[i] - g : 0; - i++; - d[j++] = (s[i] > r) ? s[i] - r : 0; - i++; - d[j++] = 0; - i++; - } - for (i = 0; i < bpl; i += 4) { - d[j] = (s[j] > b) ? s[j] - b : 0; - j++; - d[j] = (s[j] > g) ? s[j] - g : 0; - j++; - d[j] = (s[j] > r) ? s[j] - r : 0; - j++; - d[j++] = 0; - } - /* middle down */ - for (i = bpf; i < bpf + bpl;) { - d[i] = (s[i] > b) ? s[i] - b : 0; - i++; - d[i] = (s[i] > g) ? s[i] - g : 0; - i++; - d[i] = (s[i] > r) ? s[i] - r : 0; - i++; - d[i++] = 0; + SHADE2 (d, s, j, i, r, g, b); } + /* move lower half down */ for (j = bpf + bpl, i = bpf; j < bpf + bpf;) { - d[j++] = (s[i] > b) ? s[i] - b : 0; - i++; - d[j++] = (s[i] > g) ? s[i] - g : 0; - i++; - d[j++] = (s[i] > r) ? s[i] - r : 0; - i++; - d[j++] = 0; - i++; + SHADE2 (d, s, j, i, r, g, b); } -#else - /* middle up */ - for (j = 0, i = bpl; i < bpf;) { - d[j++] = 0; - i++; - d[j++] = (s[i] > r) ? s[i] - r : 0; - i++; - d[j++] = (s[i] > g) ? s[i] - g : 0; - i++; - d[j++] = (s[i] > b) ? s[i] - b : 0; - i++; - } - for (i = 0; i < bpl; i += 4) { - d[j++] = 0; - d[j] = (s[j] > r) ? s[j] - r : 0; - j++; - d[j] = (s[j] > g) ? s[j] - g : 0; - j++; - d[j] = (s[j] > b) ? s[j] - b : 0; - j++; - } - /* middle down */ - for (i = bpf; i < bpf + bpl;) { - d[i++] = 0; - d[i] = (s[i] > r) ? s[i] - r : 0; - i++; - d[i] = (s[i] > g) ? s[i] - g : 0; - i++; - d[i] = (s[i] > b) ? s[i] - b : 0; - i++; - } - for (j = bpf + bpl, i = bpf; j < bpf + bpf;) { - d[j++] = 0; - i++; - d[j++] = (s[i] > r) ? s[i] - r : 0; - i++; - d[j++] = (s[i] > g) ? s[i] - g : 0; - i++; - d[j++] = (s[i] > b) ? s[i] - b : 0; - i++; - } -#endif } +static void +shader_fade_and_move_horiz_in (GstBaseAudioVisualizer * scope, + const guint8 * s, guint8 * d) +{ + guint i, j, bpf = scope->bpf / 2; + guint bpl = 4 * scope->width; + guint r = (scope->shade_amount >> 16) & 0xff; + guint g = (scope->shade_amount >> 8) & 0xff; + guint b = (scope->shade_amount >> 0) & 0xff; + + /* move upper half down */ + for (i = 0, j = bpl; i < bpf;) { + SHADE2 (d, s, j, i, r, g, b); + } + /* move lower half up */ + for (i = bpf + bpl, j = bpf; i < bpf + bpf;) { + SHADE2 (d, s, j, i, r, g, b); + } +} + +static void +shader_fade_and_move_vert_out (GstBaseAudioVisualizer * scope, + const guint8 * s, guint8 * d) +{ + guint i, j, k, bpf = scope->bpf; + guint m = scope->width / 2; + guint r = (scope->shade_amount >> 16) & 0xff; + guint g = (scope->shade_amount >> 8) & 0xff; + guint b = (scope->shade_amount >> 0) & 0xff; + + /* move left half to the left */ + for (j = 0, i = 4; i < bpf;) { + for (k = 0; k < m; k++) { + SHADE2 (d, s, j, i, r, g, b); + } + j += 4 * m; + i += 4 * m; + } + /* move right half to the right */ + for (j = 4 * (m + 1), i = 4 * m; j < bpf;) { + for (k = 0; k < m; k++) { + SHADE2 (d, s, j, i, r, g, b); + } + j += 4 * m; + i += 4 * m; + } +} + +static void +shader_fade_and_move_vert_in (GstBaseAudioVisualizer * scope, + const guint8 * s, guint8 * d) +{ + guint i, j, k, bpf = scope->bpf; + guint m = scope->width / 2; + guint r = (scope->shade_amount >> 16) & 0xff; + guint g = (scope->shade_amount >> 8) & 0xff; + guint b = (scope->shade_amount >> 0) & 0xff; + + /* move left half to the right */ + for (j = 4, i = 0; j < bpf;) { + for (k = 0; k < m; k++) { + SHADE2 (d, s, j, i, r, g, b); + } + j += 4 * m; + i += 4 * m; + } + /* move right half to the left */ + for (j = 4 * m, i = 4 * (m + 1); i < bpf;) { + for (k = 0; k < m; k++) { + SHADE2 (d, s, j, i, r, g, b); + } + j += 4 * m; + i += 4 * m; + } +} static void gst_base_audio_visualizer_change_shader (GstBaseAudioVisualizer * scope) @@ -348,9 +359,24 @@ gst_base_audio_visualizer_change_shader (GstBaseAudioVisualizer * scope) case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN: scope->shader = shader_fade_and_move_down; break; + case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT: + scope->shader = shader_fade_and_move_left; + break; + case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT: + scope->shader = shader_fade_and_move_right; + break; case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT: scope->shader = shader_fade_and_move_horiz_out; break; + case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN: + scope->shader = shader_fade_and_move_horiz_in; + break; + case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT: + scope->shader = shader_fade_and_move_vert_out; + break; + case GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN: + scope->shader = shader_fade_and_move_vert_in; + break; default: GST_ERROR ("invalid shader function"); scope->shader = NULL; @@ -463,6 +489,7 @@ gst_base_audio_visualizer_init (GstBaseAudioVisualizer * scope, scope->next_ts = GST_CLOCK_TIME_NONE; + scope->config_lock = g_mutex_new (); } static void @@ -521,6 +548,10 @@ gst_base_audio_visualizer_dispose (GObject * object) g_free (scope->pixelbuf); scope->pixelbuf = NULL; } + if (scope->config_lock) { + g_mutex_free (scope->config_lock); + scope->config_lock = NULL; + } G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -644,6 +675,8 @@ gst_base_audio_visualizer_src_setcaps (GstPad * pad, GstCaps * caps) goto missing_caps_details; } + g_mutex_lock (scope->config_lock); + scope->width = w; scope->height = h; scope->fps_n = num; @@ -669,6 +702,9 @@ gst_base_audio_visualizer_src_setcaps (GstPad * pad, GstCaps * caps) scope->width, scope->height, scope->fps_n, scope->fps_d); GST_DEBUG_OBJECT (scope, "blocks: spf %u, req_spf %u", scope->spf, scope->req_spf); + + g_mutex_unlock (scope->config_lock); + done: gst_object_unref (scope); return res; @@ -691,6 +727,7 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer) GstBaseAudioVisualizerClass *klass; GstBuffer *inbuf; guint avail, sbpf; + guint8 *adata; gboolean (*render) (GstBaseAudioVisualizer * scope, GstBuffer * audio, GstBuffer * video); @@ -718,6 +755,8 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer) gst_adapter_push (scope->adapter, buffer); + g_mutex_lock (scope->config_lock); + /* this is what we want */ sbpf = scope->req_spf * scope->channels * sizeof (gint16); @@ -731,9 +770,13 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer) while (avail >= sbpf) { GstBuffer *outbuf; + g_mutex_unlock (scope->config_lock); ret = gst_pad_alloc_buffer_and_set_caps (scope->srcpad, GST_BUFFER_OFFSET_NONE, scope->bpf, GST_PAD_CAPS (scope->srcpad), &outbuf); + g_mutex_lock (scope->config_lock); + /* recheck as the value could have changed */ + sbpf = scope->req_spf * scope->channels * sizeof (gint16); /* no buffer allocated, we don't care why. */ if (ret != GST_FLOW_OK) @@ -750,8 +793,11 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer) memset (GST_BUFFER_DATA (outbuf), 0, scope->bpf); } - GST_BUFFER_DATA (inbuf) = - (guint8 *) gst_adapter_peek (scope->adapter, sbpf); + /* this can fail as the data size we need could have changed */ + if (!(adata = (guint8 *) gst_adapter_peek (scope->adapter, sbpf))) + break; + + GST_BUFFER_DATA (inbuf) = adata; GST_BUFFER_SIZE (inbuf) = sbpf; /* call class->render() vmethod */ @@ -766,9 +812,13 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer) } } + g_mutex_unlock (scope->config_lock); ret = gst_pad_push (scope->srcpad, outbuf); outbuf = NULL; + g_mutex_lock (scope->config_lock); + /* recheck as the value could have changed */ + sbpf = scope->req_spf * scope->channels * sizeof (gint16); GST_LOG_OBJECT (scope, "avail: %u, bpf: %u", avail, sbpf); /* we want to take less or more, depending on spf : req_spf */ if (avail - sbpf >= sbpf) { @@ -787,6 +837,8 @@ gst_base_audio_visualizer_chain (GstPad * pad, GstBuffer * buffer) scope->next_ts += scope->frame_duration; } + g_mutex_unlock (scope->config_lock); + gst_object_unref (scope); return ret; diff --git a/gst/audiovisualizers/gstbaseaudiovisualizer.h b/gst/audiovisualizers/gstbaseaudiovisualizer.h index e2119b6114..42a4c07339 100644 --- a/gst/audiovisualizers/gstbaseaudiovisualizer.h +++ b/gst/audiovisualizers/gstbaseaudiovisualizer.h @@ -45,7 +45,12 @@ typedef void (*GstBaseAudioVisualizerShaderFunc)(GstBaseAudioVisualizer *scope, * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE: plain fading * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_UP: fade and move up * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN: fade and move down - * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT: fade and move horizontaly out + * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT: fade and move left + * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT: fade and move right + * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT: fade and move horizontally out + * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN: fade and move horizontally in + * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT: fade and move vertically out + * @GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN: fade and move vertically in * * Different types of supported background shading functions. */ @@ -54,7 +59,12 @@ typedef enum { GST_BASE_AUDIO_VISUALIZER_SHADER_FADE, GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_UP, GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN, - GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT + GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT, + GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT, + GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT, + GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN, + GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT, + GST_BASE_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN } GstBaseAudioVisualizerShader; struct _GstBaseAudioVisualizer @@ -89,6 +99,9 @@ struct _GstBaseAudioVisualizer /* audio state */ gint sample_rate; gint rate; + + /* configuration mutex */ + GMutex *config_lock; }; struct _GstBaseAudioVisualizerClass diff --git a/gst/audiovisualizers/gstspectrascope.c b/gst/audiovisualizers/gstspectrascope.c index 9ab5419833..4ebc7a15b2 100644 --- a/gst/audiovisualizers/gstspectrascope.c +++ b/gst/audiovisualizers/gstspectrascope.c @@ -165,7 +165,8 @@ gst_spectra_scope_render (GstBaseAudioVisualizer * bscope, GstBuffer * audio, { GstSpectraScope *scope = GST_SPECTRA_SCOPE (bscope); guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video); - gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio); + gint16 *adata = (gint16 *) g_memdup (GST_BUFFER_DATA (audio), + GST_BUFFER_SIZE (audio)); GstFFTS16Complex *fdata = scope->freq_data; guint x, y, off; guint l, h = bscope->height - 1; @@ -190,6 +191,7 @@ gst_spectra_scope_render (GstBaseAudioVisualizer * bscope, GstBuffer * audio, /* run fft */ gst_fft_s16_window (scope->fft_ctx, adata, GST_FFT_WINDOW_HAMMING); gst_fft_s16_fft (scope->fft_ctx, adata, fdata); + g_free (adata); /* draw lines */ for (x = 0; x < bscope->width; x++) { diff --git a/gst/camerabin2/gstcamerabin2.c b/gst/camerabin2/gstcamerabin2.c index 8d799277bf..fc517e1219 100644 --- a/gst/camerabin2/gstcamerabin2.c +++ b/gst/camerabin2/gstcamerabin2.c @@ -19,19 +19,115 @@ /** * SECTION:element-camerabin2 * - * GstCameraBin22 is a high-level camera object that encapsulates the gstreamer - * internals and provides a task based API for the application. + * CameraBin2 is a high-level camera object that encapsulates gstreamer + * elements, providing an API for controlling a digital camera. * * - * Note that camerabin2 is still UNSTABLE, EXPERIMENTAL and under heavy + * Note that camerabin2 is still UNSTABLE, EXPERIMENTAL and under * development. * * + * CameraBin2 has the following main features: + * + * + * Record videos + * + * + * Capture pictures + * + * + * Display a viewfinder + * + * + * Post preview images for each capture (video and image) + * + * + * + * + * Usage + * + * Camerabin2 can be created using gst_element_factory_make() just like + * any other element. Video or image capture mode can be selected using + * the #GstCameraBin2:mode property and the file to save the capture is + * selected using #GstCameraBin2:location property. + * + * After creating camerabin2, applications might want to do some + * customization (there's a section about this below), then select + * the desired mode and start capturing. + * + * In image capture mode, just send a #GstCameraBin:start-capture and a + * picture will be captured. When the picture is stored on the selected + * location, a %GST_MESSAGE_ELEMENT named 'image-done' will be posted on + * the #GstBus. + * + * In video capture mode, send a #GstCameraBin2:start-capture to start + * recording, then send a #GstCameraBin2:stop-capture to stop recording. + * Note that both signals are asynchronous, so, calling + * #GstCameraBin2:stop-capture doesn't guarantee that the video has been + * properly finished yet. Applications should wait for the 'video-done' + * message to be posted on the bus. + * + * In both modes, if #GstCameraBin2:post-previews is %TRUE, a #GstBuffer + * will be post to the #GstBus in a field named 'buffer', in a + * 'preview-image' message of type %GST_MESSAGE_ELEMENT. + * + * + + * + * Customization + * + * Camerabin2 provides various customization properties, allowing the user + * to set custom filters, selecting the viewfinder sink and formats to + * use to encode the captured images/videos. + * + * #GstEncodingProfiles are used to tell camerabin2 which formats it + * should encode the captures to, those should be set to + * #GstCameraBin2:image-profile and #GstCameraBin2:video-profile. Default is + * jpeg for images, and ogg (theora and vorbis) for video. If a profile without + * an audio stream is set for video, audio will be disabled on recordings. + * + * #GstCameraBin2:preview-caps can be used to select which format preview + * images should be posted on the #GstBus. It has to be a raw video format. + * + * Camerabin2 has a #GstCameraBin2:camera-source property so applications can + * set their source that will provide buffers for the viewfinder and for + * captures. This camera source is a special type of source that has 3 pads. + * To use a 'regular' source with a single pad you should use + * #GstWrapperCameraBinSource, it will adapt your source and provide 3 pads. + * + * Applications can also select the desired viewfinder sink using + * #GstCameraBin2:viewfinder-sink, it is also possible to select the audio + * source using #GstCameraBin2:audio-source. + * + * The viewfinder resolution can be configured using + * #GstCameraBin2:viewfinder-caps, these #GstCaps should be a subset of + * #GstCameraBin2:viewfinder-supported-caps. + * + * To select the desired resolution for captures, camerabin2 provides + * #GstCameraBin2:image-capture-caps and #GstCameraBin2:video-capture-caps, + * these caps must be a subset of what the source can produce. The allowed + * caps can be probed using #GstCameraBin2:image-capture-supported-caps and + * #GstCameraBin2:video-capture-supported-caps. In an analogous way, there + * are #GstCameraBin2:audio-capture-caps and + * #GstCameraBin2:audio-capture-supported-caps. + * + * Camerabin2 also allows applications to insert custom #GstElements on any + * of its branches: video capture, image capture, viewfinder and preview. + * Check #GstCameraBin2:video-filter, #GstCameraBin2:image-filter, + * #GstCameraBin2:viewfinder-filter and #GstCameraBin2:preview-filter. + * + * + * * * Example launch line + * + * Unfortunatelly, camerabin2 can't be really used from gst-launch, as you need + * to send signals to control it. The following pipeline might be able + * to show the viewfinder using all the default elements. * |[ * gst-launch -v -m camerabin2 * ]| + * * */ @@ -75,7 +171,7 @@ gint bef = g_atomic_int_exchange_and_add (&c->processing_counter, 1); \ if (bef == 0) \ g_object_notify (G_OBJECT (c), "idle"); \ - GST_DEBUG_OBJECT ((c), "Processing counter increModemented to: %d", \ + GST_DEBUG_OBJECT ((c), "Processing counter incremented to: %d", \ bef + 1); \ } @@ -125,7 +221,8 @@ enum PROP_MAX_ZOOM, PROP_IMAGE_ENCODING_PROFILE, PROP_IDLE, - PROP_FLAGS + PROP_FLAGS, + PROP_AUDIO_FILTER }; enum @@ -449,9 +546,13 @@ gst_camera_bin_dispose (GObject * object) gst_object_unref (camerabin->image_filter); if (camerabin->viewfinder_filter) gst_object_unref (camerabin->viewfinder_filter); + if (camerabin->audio_filter) + gst_object_unref (camerabin->audio_filter); if (camerabin->user_video_filter) gst_object_unref (camerabin->user_video_filter); + if (camerabin->user_audio_filter) + gst_object_unref (camerabin->user_audio_filter); if (camerabin->user_image_filter) gst_object_unref (camerabin->user_image_filter); if (camerabin->user_viewfinder_filter) @@ -626,6 +727,12 @@ gst_camera_bin_class_init (GstCameraBin2Class * klass) " (Should be set on NULL state)", GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_AUDIO_FILTER, + g_param_spec_object ("audio-filter", "Audio filter", + "The element that will process captured audio buffers when recording" + ". (Should be set on NULL state)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_PREVIEW_FILTER, g_param_spec_object ("preview-filter", "Preview filter", "The element that will process preview buffers." @@ -780,6 +887,18 @@ gst_image_capture_bin_post_image_done (GstCameraBin2 * camera, GST_WARNING_OBJECT (camera, "Failed to post image-done message"); } +static void +gst_video_capture_bin_post_video_done (GstCameraBin2 * camera) +{ + GstMessage *msg; + + msg = gst_message_new_element (GST_OBJECT_CAST (camera), + gst_structure_new ("video-done", NULL)); + + if (!gst_element_post_message (GST_ELEMENT_CAST (camera), msg)) + GST_WARNING_OBJECT (camera, "Failed to post video-done message"); +} + static void gst_camera_bin_handle_message (GstBin * bin, GstMessage * message) { @@ -814,6 +933,7 @@ gst_camera_bin_handle_message (GstBin * bin, GstMessage * message) if (src == GST_CAMERA_BIN2_CAST (bin)->videosink) { GST_DEBUG_OBJECT (bin, "EOS from video branch"); GST_CAMERA_BIN2_PROCESSING_DEC (GST_CAMERA_BIN2_CAST (bin)); + gst_video_capture_bin_post_video_done (GST_CAMERA_BIN2_CAST (bin)); } } break; @@ -1421,6 +1541,11 @@ gst_camera_bin_create_elements (GstCameraBin2 * camera) gst_element_link_many (camera->audio_src, camera->audio_volume, camera->audio_capsfilter, NULL); } + if (has_audio) { + gst_camera_bin_check_and_replace_filter (camera, &camera->audio_filter, + camera->user_audio_filter, camera->audio_src, camera->audio_volume, + "src"); + } if ((profile_switched && has_audio) || new_audio_src) { if (GST_PAD_LINK_FAILED (gst_camera_bin_link_encodebin (camera, @@ -1734,6 +1859,12 @@ gst_camera_bin_set_property (GObject * object, guint prop_id, g_object_set (camera->src, "preview-filter", camera->preview_filter, NULL); break; + case PROP_AUDIO_FILTER: + if (camera->user_audio_filter) + g_object_unref (camera->user_audio_filter); + + camera->user_audio_filter = g_value_dup_object (value); + break; case PROP_VIEWFINDER_SINK: g_object_set (camera->viewfinderbin, "video-sink", g_value_get_object (value), NULL); @@ -1890,6 +2021,10 @@ gst_camera_bin_get_property (GObject * object, guint prop_id, if (camera->user_viewfinder_filter) g_value_set_object (value, camera->user_viewfinder_filter); break; + case PROP_AUDIO_FILTER: + if (camera->user_audio_filter) + g_value_set_object (value, camera->user_audio_filter); + break; case PROP_PREVIEW_FILTER: if (camera->preview_filter) g_value_set_object (value, camera->preview_filter); diff --git a/gst/camerabin2/gstcamerabin2.h b/gst/camerabin2/gstcamerabin2.h index 3276429ca7..e8611a8774 100644 --- a/gst/camerabin2/gstcamerabin2.h +++ b/gst/camerabin2/gstcamerabin2.h @@ -68,9 +68,11 @@ struct _GstCameraBin2 GstElement *video_filter; GstElement *image_filter; GstElement *viewfinder_filter; + GstElement *audio_filter; GstElement *user_video_filter; GstElement *user_image_filter; GstElement *user_viewfinder_filter; + GstElement *user_audio_filter; GstElement *audio_src; GstElement *user_audio_src; diff --git a/gst/mpeg4videoparse/mpeg4parse.c b/gst/mpeg4videoparse/mpeg4parse.c index 50fd3c7482..c00c85a6c2 100644 --- a/gst/mpeg4videoparse/mpeg4parse.c +++ b/gst/mpeg4videoparse/mpeg4parse.c @@ -140,7 +140,8 @@ gst_mpeg4_params_parse_vo (MPEG4Params * params, GstBitReader * br) GET_BITS (br, 1, &bits); if (bits) { /* skip vbv_parameters */ - GET_BITS (br, 79, &bits); + if (!gst_bit_reader_skip (br, 79)) + goto failed; } } diff --git a/gst/mxf/mxfmetadata.c b/gst/mxf/mxfmetadata.c index ed05703ee3..cf3ccb6555 100644 --- a/gst/mxf/mxfmetadata.c +++ b/gst/mxf/mxfmetadata.c @@ -6371,9 +6371,13 @@ mxf_descriptive_metadata_new (guint8 scheme, guint32 type, _MXFDescriptiveMetadataScheme *s = NULL; MXFDescriptiveMetadata *ret = NULL; - g_return_val_if_fail (type != 0, NULL); g_return_val_if_fail (primer != NULL, NULL); + if (G_UNLIKELY (type == 0)) { + GST_WARNING ("Type 0 is invalid"); + return NULL; + } + for (i = 0; i < _dm_schemes->len; i++) { _MXFDescriptiveMetadataScheme *data = &g_array_index (_dm_schemes, _MXFDescriptiveMetadataScheme, i); diff --git a/gst/videoparsers/mpegvideoparse.c b/gst/videoparsers/mpegvideoparse.c index 45f8dd306c..e85d77bdbb 100644 --- a/gst/videoparsers/mpegvideoparse.c +++ b/gst/videoparsers/mpegvideoparse.c @@ -209,6 +209,10 @@ gst_mpeg_video_params_parse_sequence (MPEGVParams * params, GstBitReader * br) params->bitrate *= 400; } + /* skip 1 + VBV buffer size */ + if (!gst_bit_reader_skip (br, 11)) + goto failed; + /* constrained_parameters_flag */ GET_BITS (br, 1, &bits); diff --git a/sys/applemedia/qtkitvideosrc.m b/sys/applemedia/qtkitvideosrc.m index 67388f051a..c228692ddb 100644 --- a/sys/applemedia/qtkitvideosrc.m +++ b/sys/applemedia/qtkitvideosrc.m @@ -42,40 +42,35 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", "format = (fourcc) " DEVICE_YUV_FOURCC ", " "width = (int) 640, " "height = (int) 480, " - "framerate = (fraction) " G_STRINGIFY (DEVICE_FPS_N) "/" - G_STRINGIFY (DEVICE_FPS_D) ", " + "framerate = [0/1, 100/1], " "pixel-aspect-ratio = (fraction) 1/1" "; " "video/x-raw-yuv, " "format = (fourcc) " DEVICE_YUV_FOURCC ", " "width = (int) 160, " "height = (int) 120, " - "framerate = (fraction) " G_STRINGIFY (DEVICE_FPS_N) "/" - G_STRINGIFY (DEVICE_FPS_D) ", " + "framerate = [0/1, 100/1], " "pixel-aspect-ratio = (fraction) 1/1" "; " "video/x-raw-yuv, " "format = (fourcc) " DEVICE_YUV_FOURCC ", " "width = (int) 176, " "height = (int) 144, " - "framerate = (fraction) " G_STRINGIFY (DEVICE_FPS_N) "/" - G_STRINGIFY (DEVICE_FPS_D) ", " + "framerate = [0/1, 100/1], " "pixel-aspect-ratio = (fraction) 12/11" "; " "video/x-raw-yuv, " "format = (fourcc) " DEVICE_YUV_FOURCC ", " "width = (int) 320, " "height = (int) 240, " - "framerate = (fraction) " G_STRINGIFY (DEVICE_FPS_N) "/" - G_STRINGIFY (DEVICE_FPS_D) ", " + "framerate = [0/1, 100/1], " "pixel-aspect-ratio = (fraction) 1/1" "; " "video/x-raw-yuv, " "format = (fourcc) " DEVICE_YUV_FOURCC ", " "width = (int) 352, " "height = (int) 288, " - "framerate = (fraction) " G_STRINGIFY (DEVICE_FPS_N) "/" - G_STRINGIFY (DEVICE_FPS_D) ", " + "framerate = [0/1, 100/1], " "pixel-aspect-ratio = (fraction) 12/11" ";" ) @@ -107,6 +102,7 @@ GST_BOILERPLATE (GstQTKitVideoSrc, gst_qtkit_video_src, GstPushSrc, BOOL stopRequest; gint width, height; + gint fps_n, fps_d; GstClockTime duration; guint64 offset; } @@ -123,6 +119,7 @@ GST_BOILERPLATE (GstQTKitVideoSrc, gst_qtkit_video_src, GstPushSrc, - (BOOL)stop; - (BOOL)unlock; - (BOOL)unlockStop; +- (void)fixate:(GstCaps *)caps; - (BOOL)query:(GstQuery *)query; - (GstStateChangeReturn)changeState:(GstStateChange)transition; - (GstFlowReturn)create:(GstBuffer **)buf; @@ -243,6 +240,7 @@ openFailed: NSDictionary *outputAttrs; BOOL success; NSRunLoop *mainRunLoop; + NSTimeInterval interval; g_assert (device != nil); @@ -251,7 +249,12 @@ openFailed: s = gst_caps_get_structure (caps, 0); gst_structure_get_int (s, "width", &width); gst_structure_get_int (s, "height", &height); + if (!gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d)) { + fps_n = DEVICE_FPS_N; + fps_d = DEVICE_FPS_D; + } + GST_INFO ("got caps %dx%d %d/%d", width, height, fps_n, fps_d); input = [[QTCaptureDeviceInput alloc] initWithDevice:device]; output = [[QTCaptureDecompressedVideoOutput alloc] init]; @@ -269,6 +272,16 @@ openFailed: ]; [output setPixelBufferAttributes:outputAttrs]; + if (fps_n != 0) { + duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n); + gst_util_fraction_to_double (fps_d, fps_n, (gdouble *) &interval); + } else { + duration = GST_CLOCK_TIME_NONE; + interval = 0; + } + + [output setMinimumVideoFrameInterval:interval]; + session = [[QTCaptureSession alloc] init]; success = [session addInput:input error:nil]; @@ -299,8 +312,11 @@ openFailed: queue = [[NSMutableArray alloc] initWithCapacity:FRAME_QUEUE_SIZE]; stopRequest = NO; - duration = gst_util_uint64_scale (GST_SECOND, DEVICE_FPS_D, DEVICE_FPS_N); offset = 0; + width = height = 0; + fps_n = 0; + fps_d = 1; + duration = GST_CLOCK_TIME_NONE; return YES; } @@ -359,6 +375,18 @@ openFailed: return YES; } +- (void)fixate:(GstCaps *)caps +{ + GstStructure *structure; + + gst_caps_truncate (caps); + structure = gst_caps_get_structure (caps, 0); + if (gst_structure_has_field (structure, "framerate")) { + gst_structure_fixate_field_nearest_fraction (structure, "framerate", + DEVICE_FPS_N, DEVICE_FPS_D); + } +} + - (GstStateChangeReturn)changeState:(GstStateChange)transition { GstStateChangeReturn ret; @@ -484,6 +512,7 @@ static gboolean gst_qtkit_video_src_unlock (GstBaseSrc * basesrc); static gboolean gst_qtkit_video_src_unlock_stop (GstBaseSrc * basesrc); static GstFlowReturn gst_qtkit_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf); +static void gst_qtkit_video_src_fixate (GstBaseSrc * basesrc, GstCaps * caps); static void gst_qtkit_video_src_base_init (gpointer gclass) @@ -519,6 +548,7 @@ gst_qtkit_video_src_class_init (GstQTKitVideoSrcClass * klass) gstbasesrc_class->query = gst_qtkit_video_src_query; gstbasesrc_class->unlock = gst_qtkit_video_src_unlock; gstbasesrc_class->unlock_stop = gst_qtkit_video_src_unlock_stop; + gstbasesrc_class->fixate = gst_qtkit_video_src_fixate; gstpushsrc_class->create = gst_qtkit_video_src_create; @@ -684,3 +714,11 @@ gst_qtkit_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf) return ret; } + +static void +gst_qtkit_video_src_fixate (GstBaseSrc * basesrc, GstCaps * caps) +{ + OBJC_CALLOUT_BEGIN (); + [GST_QTKIT_VIDEO_SRC_IMPL (basesrc) fixate: caps]; + OBJC_CALLOUT_END (); +} diff --git a/sys/decklink/Makefile.am b/sys/decklink/Makefile.am index ffa4ac25cc..c84d871264 100644 --- a/sys/decklink/Makefile.am +++ b/sys/decklink/Makefile.am @@ -20,6 +20,7 @@ libgstdecklink_la_SOURCES = \ DeckLinkAPIDispatch.cpp noinst_HEADERS = \ + gstdecklink.h \ gstdecklinksrc.h \ gstdecklinksink.h \ capture.h \ diff --git a/tests/check/elements/camerabin2.c b/tests/check/elements/camerabin2.c index 5277b619a6..6638ccf767 100644 --- a/tests/check/elements/camerabin2.c +++ b/tests/check/elements/camerabin2.c @@ -1162,10 +1162,12 @@ GST_START_TEST (test_video_custom_filter) GstElement *vf_filter; GstElement *video_filter; GstElement *preview_filter; + GstElement *audio_filter; GstPad *pad; gint vf_probe_counter = 0; gint video_probe_counter = 0; gint preview_probe_counter = 0; + gint audio_probe_counter = 0; if (!camera) return; @@ -1173,6 +1175,7 @@ GST_START_TEST (test_video_custom_filter) vf_filter = gst_element_factory_make ("identity", "vf-filter"); video_filter = gst_element_factory_make ("identity", "video-filter"); preview_filter = gst_element_factory_make ("identity", "preview-filter"); + audio_filter = gst_element_factory_make ("identity", "audio-filter"); pad = gst_element_get_static_pad (vf_filter, "src"); gst_pad_add_buffer_probe (pad, (GCallback) filter_buffer_count, @@ -1184,6 +1187,11 @@ GST_START_TEST (test_video_custom_filter) &video_probe_counter); gst_object_unref (pad); + pad = gst_element_get_static_pad (audio_filter, "src"); + gst_pad_add_buffer_probe (pad, (GCallback) filter_buffer_count, + &audio_probe_counter); + gst_object_unref (pad); + pad = gst_element_get_static_pad (preview_filter, "src"); gst_pad_add_buffer_probe (pad, (GCallback) filter_buffer_count, &preview_probe_counter); @@ -1193,11 +1201,12 @@ GST_START_TEST (test_video_custom_filter) g_object_set (camera, "mode", 2, "location", make_test_file_name (VIDEO_FILENAME, -1), "viewfinder-filter", vf_filter, "video-filter", video_filter, - "preview-filter", preview_filter, NULL); + "preview-filter", preview_filter, "audio-filter", audio_filter, NULL); gst_object_unref (vf_filter); gst_object_unref (preview_filter); gst_object_unref (video_filter); + gst_object_unref (audio_filter); if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { @@ -1223,6 +1232,7 @@ GST_START_TEST (test_video_custom_filter) fail_unless (vf_probe_counter > 0); fail_unless (video_probe_counter > 0); + fail_unless (audio_probe_counter > 0); fail_unless (preview_probe_counter == 1); } diff --git a/tests/examples/opencv/Makefile.am b/tests/examples/opencv/Makefile.am index 16af077a29..4241e9e579 100644 --- a/tests/examples/opencv/Makefile.am +++ b/tests/examples/opencv/Makefile.am @@ -1,7 +1,11 @@ noinst_PROGRAMS = gstmotioncells_dynamic_test -gstmotioncells_dynamic_test_SOURCES = gstmotioncells_dynamic_test.c gst_element_print_properties.c +gstmotioncells_dynamic_test_SOURCES = \ + gstmotioncells_dynamic_test.c \ + gst_element_print_properties.c gstmotioncells_dynamic_test_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) gstmotioncells_dynamic_test_LDFLAGS = $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GSTPB_BASE_LIBS) -noinst_HEADERS = gst_element_print_properties.h +noinst_HEADERS = \ + gstmotioncells_dynamic_test.h \ + gst_element_print_properties.h