From b01ee6bbf102087fab8c4907bf96374183d81321 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Thu, 4 Aug 2011 09:49:46 +0200 Subject: [PATCH 01/30] mpegvideoparse: fix sequence header parsing After bitrate there's 11 bits (1 marker bit + VBV buffer size) before the load intra quantiser flag. --- gst/videoparsers/mpegvideoparse.c | 4 ++++ 1 file changed, 4 insertions(+) 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); From 8132a5d46eff58217bad31cb3fc0495846fd0f01 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 4 Aug 2011 11:28:30 +0200 Subject: [PATCH 02/30] decklink: Add gstdecklink.h to list of headers --- sys/decklink/Makefile.am | 1 + 1 file changed, 1 insertion(+) 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 \ From 3d86389e068c05db54512f7e0365b9fac7030bf7 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 4 Aug 2011 13:33:56 +0200 Subject: [PATCH 03/30] examples: Add missing header file --- tests/examples/opencv/Makefile.am | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 From f241dafe5c55c02d81f153de2a59e0a83d12d1c9 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 4 Aug 2011 13:33:20 +0200 Subject: [PATCH 04/30] motioncells: turn two global vars into static variables Move 2 variable to motioncells_warpper and make them static. --- ext/opencv/gstmotioncells.c | 6 +----- ext/opencv/motioncells_wrapper.cpp | 8 +++++--- ext/opencv/motioncells_wrapper.h | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) 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, From 69b7326399ea1add11f361f5d006b99b828ad625 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 5 Aug 2011 13:34:08 -0300 Subject: [PATCH 05/30] camerabin2: Fixing typo --- gst/camerabin2/gstcamerabin2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/camerabin2/gstcamerabin2.c b/gst/camerabin2/gstcamerabin2.c index 8d799277bf..f1855fa019 100644 --- a/gst/camerabin2/gstcamerabin2.c +++ b/gst/camerabin2/gstcamerabin2.c @@ -75,7 +75,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); \ } From 80fb9170347376fa100d57f1572672c6b14034c1 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 5 Aug 2011 15:48:53 -0300 Subject: [PATCH 06/30] camerabin2: Adding top-level element documentation --- gst/camerabin2/gstcamerabin2.c | 102 ++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/gst/camerabin2/gstcamerabin2.c b/gst/camerabin2/gstcamerabin2.c index f1855fa019..cd2d5f37f6 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. Users can check the #GstCameraBin2:idle property + * to verify that it has stopped. + * + * 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 * ]| + * * */ From 8dc9551f9a7493f83ece51a6894ec40990a98ac9 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Sat, 6 Aug 2011 12:13:22 -0300 Subject: [PATCH 07/30] camerabin2: Adding video-done message video-done message will be posted when a video recording is finished. Similar to image-done message. --- gst/camerabin2/gstcamerabin2.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/gst/camerabin2/gstcamerabin2.c b/gst/camerabin2/gstcamerabin2.c index cd2d5f37f6..3c3a6944ed 100644 --- a/gst/camerabin2/gstcamerabin2.c +++ b/gst/camerabin2/gstcamerabin2.c @@ -64,8 +64,8 @@ * 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. Users can check the #GstCameraBin2:idle property - * to verify that it has stopped. + * 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 @@ -876,6 +876,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) { @@ -910,6 +922,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; From 27f40d8a577789a53e2b7bb1c762b71bc62a7c54 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Mon, 8 Aug 2011 16:44:20 +0200 Subject: [PATCH 08/30] dirac: Fix set but unused variables Remove some dead code that triggers "set but unused variables" from Gcc 4.6. Fixes #656164. Signed-off-by: David Schleef --- ext/dirac/gstdiracenc.cc | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/ext/dirac/gstdiracenc.cc b/ext/dirac/gstdiracenc.cc index 118a315279..a564af79ab 100644 --- a/ext/dirac/gstdiracenc.cc +++ b/ext/dirac/gstdiracenc.cc @@ -330,30 +330,9 @@ gst_dirac_enc_set_format (GstBaseVideoEncoder * base_video_encoder, GstVideoState * state) { GstDiracEnc *dirac_enc = GST_DIRAC_ENC (base_video_encoder); - GstCaps *caps; - GstStructure *structure; 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) { @@ -1245,10 +1224,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; From 04b74947adc7351c44a4d0037a4e5f7a3672e612 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Mon, 8 Aug 2011 17:53:16 +0200 Subject: [PATCH 09/30] schroedinger: Fix set but unused variables Remove some dead code that triggers "set but unused variables" from Gcc 4.6. Fixes #656166 Signed-off-by: David Schleef --- ext/schroedinger/gstschroenc.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/ext/schroedinger/gstschroenc.c b/ext/schroedinger/gstschroenc.c index ffb4bdb8d7..3190e950e7 100644 --- a/ext/schroedinger/gstschroenc.c +++ b/ext/schroedinger/gstschroenc.c @@ -241,28 +241,9 @@ 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); 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, From 6e4e4e107cd8ee28c6872c046b242e05dc800fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 3 Aug 2011 16:02:01 +0200 Subject: [PATCH 10/30] basevideodecoder: Use the cached video frame size instead of recalculating it --- gst-libs/gst/video/gstbasevideodecoder.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 = From 2728ead8a22183c5ea542a7098317bba4f0304d6 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 9 Aug 2011 09:29:21 +0100 Subject: [PATCH 11/30] mxf: do not assert on the values of data read from input Instead, log a warning, and return. https://bugzilla.gnome.org/show_bug.cgi?id=563827 --- gst/mxf/mxfmetadata.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gst/mxf/mxfmetadata.c b/gst/mxf/mxfmetadata.c index b55bf0d009..ca05ad7ba7 100644 --- a/gst/mxf/mxfmetadata.c +++ b/gst/mxf/mxfmetadata.c @@ -6379,9 +6379,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); From 4a76d3a978857412820494e949ebf1a3e135ad4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 12 Aug 2011 12:06:23 +0200 Subject: [PATCH 12/30] basevideoencoder: Remove ::get_caps() vfunc Subclasses can set the caps more efficiently and this only caused additional indirections. --- gst-libs/gst/video/gstbasevideoencoder.c | 24 +----------------------- gst-libs/gst/video/gstbasevideoencoder.h | 3 --- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/gst-libs/gst/video/gstbasevideoencoder.c b/gst-libs/gst/video/gstbasevideoencoder.c index e4efe6d39f..7e96e1fae9 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 @@ -179,7 +179,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; @@ -761,27 +760,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..dea5e86a1d 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; @@ -164,8 +163,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]; From 896a0edbdcc14765b7ac8bc7cc8a52158b7535d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 12 Aug 2011 12:08:08 +0200 Subject: [PATCH 13/30] vp8enc: Update for basevideoencoder ::get_caps() removal --- ext/vp8/gstvp8enc.c | 117 +++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 62 deletions(-) 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 From 935b3828a3e926ac89d33c0b77ca4b44519cce41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 12 Aug 2011 12:08:20 +0200 Subject: [PATCH 14/30] schroenc: Update for basevideoencoder ::get_caps() removal --- ext/schroedinger/gstschroenc.c | 145 ++++++++++++--------------------- 1 file changed, 50 insertions(+), 95 deletions(-) diff --git a/ext/schroedinger/gstschroenc.c b/ext/schroedinger/gstschroenc.c index 3190e950e7..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 @@ -242,6 +238,9 @@ gst_schro_enc_set_format (GstBaseVideoEncoder * base_video_encoder, GstVideoState * state) { GstSchroEnc *schro_enc = GST_SCHRO_ENC (base_video_encoder); + GstCaps *caps; + GstBuffer *seq_header_buffer; + gboolean ret; GST_DEBUG ("set_output_caps"); @@ -292,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 @@ -385,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; @@ -439,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) From cc447af202f196f7718fc10aa748caf98f8a3a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 12 Aug 2011 12:08:32 +0200 Subject: [PATCH 15/30] diracenc: Update for basevideoencoder ::get_caps() removal --- ext/dirac/gstdiracenc.cc | 62 +++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/ext/dirac/gstdiracenc.cc b/ext/dirac/gstdiracenc.cc index a564af79ab..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 @@ -330,6 +327,8 @@ gst_dirac_enc_set_format (GstBaseVideoEncoder * base_video_encoder, GstVideoState * state) { GstDiracEnc *dirac_enc = GST_DIRAC_ENC (base_video_encoder); + GstCaps *caps; + gboolean ret; GST_DEBUG ("set_format"); @@ -381,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 @@ -1091,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; @@ -1153,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; @@ -1261,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; -} From 92c3aaa6e577f560ee2a2ea5427df24e8d100b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 12 Aug 2011 12:13:45 +0200 Subject: [PATCH 16/30] basevideoencoder: Remove old ::getcaps() comment --- gst-libs/gst/video/gstbasevideoencoder.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/gst-libs/gst/video/gstbasevideoencoder.h b/gst-libs/gst/video/gstbasevideoencoder.h index dea5e86a1d..c712fe86e5 100644 --- a/gst-libs/gst/video/gstbasevideoencoder.h +++ b/gst-libs/gst/video/gstbasevideoencoder.h @@ -130,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 From d576e23aa4c1c36389e9547bb28bf6147b716232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 12 Aug 2011 12:25:03 +0200 Subject: [PATCH 17/30] basevideoencoder: Proxy the width/height/framerate/PAR constraints of downstream caps to upstream This allows to specify constraints on the compressed downstream caps by muxers or capsfilters, which will then be forwarded to upstream and allows video converters to fulfill the constraints. Code based on Mark Nauwelaerts audio encoder base class. --- gst-libs/gst/video/gstbasevideoencoder.c | 71 ++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/gst-libs/gst/video/gstbasevideoencoder.c b/gst-libs/gst/video/gstbasevideoencoder.c index 7e96e1fae9..88d8c72dc8 100644 --- a/gst-libs/gst/video/gstbasevideoencoder.c +++ b/gst-libs/gst/video/gstbasevideoencoder.c @@ -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, @@ -210,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); @@ -358,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) { From 058c63d1852fc5b3b92e88b1588433d5b11dc7f1 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 12 Aug 2011 16:57:49 +0200 Subject: [PATCH 18/30] spectrascope: make a copy of the audiodata before downmixing and windowing The buffers come from the adapter and the data might overlap. We don't want to modify it in place. --- gst/audiovisualizers/gstspectrascope.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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++) { From 3ba5b8bd0e5a81ad5d2f31d17fbfc9edbefdc44a Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 12 Aug 2011 21:18:44 +0200 Subject: [PATCH 19/30] baseaudiovisualizer: protect config with a lock Before it was easy to crash the elements when using a ximagesink and triggering renegotiation by resizing. --- gst/audiovisualizers/gstbaseaudiovisualizer.c | 30 +++++++++++++++++-- gst/audiovisualizers/gstbaseaudiovisualizer.h | 3 ++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/gst/audiovisualizers/gstbaseaudiovisualizer.c b/gst/audiovisualizers/gstbaseaudiovisualizer.c index 52fe5acd42..811b92dc99 100644 --- a/gst/audiovisualizers/gstbaseaudiovisualizer.c +++ b/gst/audiovisualizers/gstbaseaudiovisualizer.c @@ -463,6 +463,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 +522,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 +649,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 +676,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 +701,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 +729,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 +744,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 +767,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 +786,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 +811,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..fe40e80fda 100644 --- a/gst/audiovisualizers/gstbaseaudiovisualizer.h +++ b/gst/audiovisualizers/gstbaseaudiovisualizer.h @@ -89,6 +89,9 @@ struct _GstBaseAudioVisualizer /* audio state */ gint sample_rate; gint rate; + + /* configuration mutex */ + GMutex *config_lock; }; struct _GstBaseAudioVisualizerClass From 039ff3873b231ef6d2301cf881c35b0080a40b52 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 12 Aug 2011 21:22:20 +0200 Subject: [PATCH 20/30] basevisualizer: more docs --- gst/audiovisualizers/gstbaseaudiovisualizer.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gst/audiovisualizers/gstbaseaudiovisualizer.c b/gst/audiovisualizers/gstbaseaudiovisualizer.c index 811b92dc99..8598b5b28f 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 From 008fa0770b7b242e1c12e7b61240cb187788b804 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 12 Aug 2011 22:39:53 +0200 Subject: [PATCH 21/30] basevisualizer: add more shader variants and simplify code Use macros to simplyfy the shading code. Those will ease to add support for other colorspaces in the future. Add more variants for the shading (left,right, horiz-in, vert-out, vert-in). --- gst/audiovisualizers/gstbaseaudiovisualizer.c | 377 ++++++++++-------- gst/audiovisualizers/gstbaseaudiovisualizer.h | 14 +- 2 files changed, 212 insertions(+), 179 deletions(-) diff --git a/gst/audiovisualizers/gstbaseaudiovisualizer.c b/gst/audiovisualizers/gstbaseaudiovisualizer.c index 8598b5b28f..6d42b7dc58 100644 --- a/gst/audiovisualizers/gstbaseaudiovisualizer.c +++ b/gst/audiovisualizers/gstbaseaudiovisualizer.c @@ -88,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}, }; @@ -101,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) { @@ -109,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 @@ -143,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 @@ -196,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 @@ -249,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) @@ -351,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; diff --git a/gst/audiovisualizers/gstbaseaudiovisualizer.h b/gst/audiovisualizers/gstbaseaudiovisualizer.h index fe40e80fda..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 From 19e5736acd9557ad0458b39ecdabccfcfb9c8d00 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 11 Aug 2011 18:59:07 -0300 Subject: [PATCH 22/30] camerabin2: Add audio-filter property Adds a property to add a custom GstElement to the audio branch of the pipeline. This allows the user to do custom audio processing/analysis when recording videos. --- gst/camerabin2/gstcamerabin2.c | 28 +++++++++++++++++++++++++++- gst/camerabin2/gstcamerabin2.h | 2 ++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/gst/camerabin2/gstcamerabin2.c b/gst/camerabin2/gstcamerabin2.c index 3c3a6944ed..fc517e1219 100644 --- a/gst/camerabin2/gstcamerabin2.c +++ b/gst/camerabin2/gstcamerabin2.c @@ -221,7 +221,8 @@ enum PROP_MAX_ZOOM, PROP_IMAGE_ENCODING_PROFILE, PROP_IDLE, - PROP_FLAGS + PROP_FLAGS, + PROP_AUDIO_FILTER }; enum @@ -545,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) @@ -722,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." @@ -1530,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, @@ -1843,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); @@ -1999,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; From 84ee1c4d5833db1e7370330ff994e4cac5430013 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Sat, 13 Aug 2011 15:55:01 -0300 Subject: [PATCH 23/30] tests: camerabin2: Add test for audio-filter property Checks that the audio-filter is properly plugged in the pipeline and receives buffers when recording a video. --- tests/check/elements/camerabin2.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) 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); } From b6747292e0a21799ff5df23283156cb84314b343 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Mon, 15 Aug 2011 02:08:14 +0200 Subject: [PATCH 24/30] qtkitvideosrc: get the framerate from caps ...and configure QTKit accordingly. Hardcoding to 30fps was pretty -bad. --- sys/applemedia/qtkitvideosrc.m | 60 +++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 11 deletions(-) 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 (); +} From 743b4677a2293b4ec7f5504b8fdf67504e2caeb5 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Tue, 16 Aug 2011 19:47:02 +0300 Subject: [PATCH 25/30] mpeg4videoparse: Use gst_bit_reader_skip to skip more than 32 bits. GET_BITS is a macro for gst_bit_reader_get_bits_uint32, which cannot read more than 32 bits and will fail in this case where it is called to read 79 bits. Since we want to skip those bits, gst_bit_reader_skip is more appropriate in this case. --- gst/mpeg4videoparse/mpeg4parse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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; } } From 5a0a0aac192e732e248d6b15343643d01a297817 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 16 Aug 2011 18:34:59 +0100 Subject: [PATCH 26/30] ofa: don't crash when there's no data to create a fingerprint from Fixes a crash when no data flowed through. https://bugzilla.gnome.org/show_bug.cgi?id=656641 --- ext/ofa/gstofa.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) 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, From ffa9c8179818abd237d3883aee053adce56851f9 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 16 Aug 2011 19:39:40 +0100 Subject: [PATCH 27/30] celtdec: make this compile with git libcelt celt_mode_info was removed, in favor of a _ctl. https://bugzilla.gnome.org/show_bug.cgi?id=656686 --- ext/celt/gstceltdec.c | 5 +++++ 1 file changed, 5 insertions(+) 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, From fb2479d1dacc5f05bc9723791cbf1e1ad3f1121c Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 16 Aug 2011 10:02:11 +0100 Subject: [PATCH 28/30] aiffmux: avoid integer overflow These values are 32 bits, and width is a multiple of 8. https://bugzilla.gnome.org/show_bug.cgi?id=654278 --- gst/aiff/aiffmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/aiff/aiffmux.c b/gst/aiff/aiffmux.c index 39770cf2e3..6119cca588 100644 --- a/gst/aiff/aiffmux.c +++ b/gst/aiff/aiffmux.c @@ -236,7 +236,7 @@ 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); } From 76c0f9bfe77af7dcf7ae60753260925ee8264253 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 16 Aug 2011 10:02:59 +0100 Subject: [PATCH 29/30] aiffmux: use guint32 for guint32 parameters This makes explicit that the range is limited. https://bugzilla.gnome.org/show_bug.cgi?id=654278 --- gst/aiff/aiffmux.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gst/aiff/aiffmux.c b/gst/aiff/aiffmux.c index 6119cca588..e9f7aa5ebc 100644 --- a/gst/aiff/aiffmux.c +++ b/gst/aiff/aiffmux.c @@ -160,7 +160,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 +228,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')); @@ -242,7 +242,7 @@ gst_aiff_mux_write_comm_header (GstAiffMux * aiffmux, guint audio_data_size, } 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 +255,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; From 0381919e83eb891d2a76eda1dfab15b7e641fca9 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 16 Aug 2011 10:24:37 +0100 Subject: [PATCH 30/30] aiffmux: drop data after 4ish GB and moan https://bugzilla.gnome.org/show_bug.cgi?id=654278 --- gst/aiff/aiffmux.c | 26 ++++++++++++++++++++++++++ gst/aiff/aiffmux.h | 1 + 2 files changed, 27 insertions(+) diff --git a/gst/aiff/aiffmux.c b/gst/aiff/aiffmux.c index e9f7aa5ebc..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; @@ -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