[longomatch/camera_capturer] Almost everything working
- From: Andoni Morales Alastruey <amorales src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [longomatch/camera_capturer] Almost everything working
- Date: Tue, 2 Oct 2012 19:56:27 +0000 (UTC)
commit e0dd3c43013febe4e45d4b5de63038ee4238db00
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date: Tue Oct 2 21:54:33 2012 +0200
Almost everything working
libcesarplayer/gst-camera-capturer.c | 588 ++++++++++++++++++----------------
libcesarplayer/main.c | 2 +-
2 files changed, 316 insertions(+), 274 deletions(-)
---
diff --git a/libcesarplayer/gst-camera-capturer.c b/libcesarplayer/gst-camera-capturer.c
index 01dd87f..0ec13af 100644
--- a/libcesarplayer/gst-camera-capturer.c
+++ b/libcesarplayer/gst-camera-capturer.c
@@ -100,8 +100,6 @@ struct GstCameraCapturerPrivate
gchar *device_id;
guint output_height;
guint output_width;
- guint output_fps_n;
- guint output_fps_d;
guint audio_bitrate;
guint video_bitrate;
gboolean audio_enabled;
@@ -136,7 +134,6 @@ struct GstCameraCapturerPrivate
GstElement *audio_enc;
GstElement *muxer;
GstElement *filesink;
- guint source_probe_id;
/* Recording */
gboolean is_recording;
@@ -146,6 +143,8 @@ struct GstCameraCapturerPrivate
GstClockTime accum_recorded_ts;
GstClockTime last_accum_recorded_ts;
GstClockTime current_recording_start_ts;
+ GstClockTime last_video_buf_ts;
+ GstClockTime last_audio_buf_ts;
GMutex *recording_lock;
/*Overlay */
@@ -186,152 +185,6 @@ static void gst_camera_capturer_link_encoder_bin (GstCameraCapturer *gcc);
G_DEFINE_TYPE (GstCameraCapturer, gst_camera_capturer, GTK_TYPE_EVENT_BOX);
-static void
-gst_camera_capturer_init (GstCameraCapturer * object)
-{
- GstCameraCapturerPrivate *priv;
- object->priv = priv =
- G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_CAMERA_CAPTURER,
- GstCameraCapturerPrivate);
-
- GTK_WIDGET_SET_FLAGS (GTK_WIDGET (object), GTK_CAN_FOCUS);
- GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (object), GTK_DOUBLE_BUFFERED);
-
- priv->zoom = 1.0;
- priv->output_height = 576;
- priv->output_width = 720;
- priv->output_fps_n = 25;
- priv->output_fps_d = 1;
- priv->audio_bitrate = 128;
- priv->video_bitrate = 5000;
- priv->last_buffer = NULL;
- priv->current_recording_start_ts = GST_CLOCK_TIME_NONE;
- priv->accum_recorded_ts = GST_CLOCK_TIME_NONE;
- priv->last_accum_recorded_ts = GST_CLOCK_TIME_NONE;
- priv->is_recording = FALSE;
- priv->recording_lock = g_mutex_new();
- //priv->audio_enabled = TRUE;
-
- priv->lock = g_mutex_new ();
-}
-
-void
-gst_camera_capturer_finalize (GObject * object)
-{
- GstCameraCapturer *gcc = (GstCameraCapturer *) object;
-
- GST_DEBUG_OBJECT (gcc, "Finalizing.");
- if (gcc->priv->bus) {
- /* make bus drop all messages to make sure none of our callbacks is ever
- * called again (main loop might be run again to display error dialog) */
- gst_bus_set_flushing (gcc->priv->bus, TRUE);
-
- if (gcc->priv->sig_bus_async)
- g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_async);
-
- if (gcc->priv->sig_bus_sync)
- g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_sync);
-
- gst_object_unref (gcc->priv->bus);
- gcc->priv->bus = NULL;
- }
-
- if (gcc->priv->output_file) {
- g_free (gcc->priv->output_file);
- gcc->priv->output_file = NULL;
- }
-
- if (gcc->priv->device_id) {
- g_free (gcc->priv->device_id);
- gcc->priv->device_id = NULL;
- }
-
- if (gcc->priv->logo_pixbuf) {
- g_object_unref (gcc->priv->logo_pixbuf);
- gcc->priv->logo_pixbuf = NULL;
- }
-
- if (gcc->priv->interface_update_id) {
- g_source_remove (gcc->priv->interface_update_id);
- gcc->priv->interface_update_id = 0;
- }
-
- if (gcc->priv->last_buffer != NULL)
- gst_buffer_unref (gcc->priv->last_buffer);
-
- if (gcc->priv->main_pipeline != NULL
- && GST_IS_ELEMENT (gcc->priv->main_pipeline)) {
- gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
- gst_object_unref (gcc->priv->main_pipeline);
- gcc->priv->main_pipeline = NULL;
- }
-
- g_mutex_free (gcc->priv->lock);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_camera_capturer_apply_resolution (GstCameraCapturer * gcc)
-{
- GST_INFO_OBJECT (gcc, "Changed video resolution to %dx%d %d/%dfps",
- gcc->priv->output_width, gcc->priv->output_height,
- gcc->priv->output_fps_n, gcc->priv->output_fps_d);
-
- /* FIXME */
-}
-
-static void
-gst_camera_capturer_set_video_bit_rate (GstCameraCapturer * gcc, gint bitrate)
-{
- gcc->priv->video_bitrate = bitrate;
- if (gcc->priv->video_encoder_type == VIDEO_ENCODER_MPEG4 ||
- gcc->priv->video_encoder_type == VIDEO_ENCODER_XVID)
- g_object_set (gcc->priv->video_enc, "bitrate", bitrate * 1000, NULL);
- else
- g_object_set (gcc->priv->video_enc, "bitrate", gcc->priv->video_bitrate,
- NULL);
- GST_INFO_OBJECT (gcc, "Changed video bitrate to :\n%d",
- gcc->priv->video_bitrate);
-}
-
-static void
-gst_camera_capturer_set_audio_bit_rate (GstCameraCapturer * gcc, gint bitrate)
-{
-
- gcc->priv->audio_bitrate = bitrate;
- if (gcc->priv->audio_encoder_type == AUDIO_ENCODER_MP3)
- g_object_set (gcc->priv->audio_enc, "bitrate", bitrate, NULL);
- else
- g_object_set (gcc->priv->audio_enc, "bitrate", 1000 * bitrate, NULL);
- GST_INFO_OBJECT (gcc, "Changed audio bitrate to :\n%d",
- gcc->priv->audio_bitrate);
-
-}
-
-static void
-gst_camera_capturer_set_audio_enabled (GstCameraCapturer * gcc,
- gboolean enabled)
-{
- /* FIXME */
-}
-
-static void
-gst_camera_capturer_set_output_file (GstCameraCapturer * gcc,
- const gchar * file)
-{
- gcc->priv->output_file = g_strdup (file);
- GST_INFO_OBJECT (gcc, "Changed output filename to :\n%s", file);
-}
-
-static void
-gst_camera_capturer_set_device_id (GstCameraCapturer * gcc,
- const gchar * device_id)
-{
- gcc->priv->device_id = g_strdup (device_id);
- GST_INFO_OBJECT (gcc, "Changed device id/name to :\n%s", device_id);
-}
-
/***********************************
*
* GTK Widget
@@ -645,10 +498,10 @@ gst_camera_capturer_expose_event (GtkWidget * widget, GdkEventExpose * event)
g_mutex_lock (gcc->priv->lock);
xoverlay = gcc->priv->xoverlay;
- if (xoverlay == NULL) {
- //gcc_update_interface_implementations (gcc);
- //resize_video_window (gcc);
- //xoverlay = gcc->priv->xoverlay;
+ if (xoverlay == NULL && gcc->priv->preview_bin != NULL) {
+ gcc_update_interface_implementations (gcc);
+ resize_video_window (gcc);
+ xoverlay = gcc->priv->xoverlay;
}
if (xoverlay != NULL)
gst_object_ref (xoverlay);
@@ -740,6 +593,148 @@ gst_camera_capturer_expose_event (GtkWidget * widget, GdkEventExpose * event)
return TRUE;
}
+/***********************************
+*
+* Class, Object and Properties
+*
+************************************/
+
+static void
+gst_camera_capturer_init (GstCameraCapturer * object)
+{
+ GstCameraCapturerPrivate *priv;
+ object->priv = priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_CAMERA_CAPTURER,
+ GstCameraCapturerPrivate);
+
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET (object), GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (object), GTK_DOUBLE_BUFFERED);
+
+ priv->zoom = 1.0;
+ priv->output_height = 480;
+ priv->output_width = 640;
+ priv->audio_bitrate = 128;
+ priv->video_bitrate = 5000;
+ priv->last_buffer = NULL;
+ priv->current_recording_start_ts = GST_CLOCK_TIME_NONE;
+ priv->accum_recorded_ts = GST_CLOCK_TIME_NONE;
+ priv->last_accum_recorded_ts = GST_CLOCK_TIME_NONE;
+ priv->last_video_buf_ts = GST_CLOCK_TIME_NONE;
+ priv->last_audio_buf_ts = GST_CLOCK_TIME_NONE;
+ priv->is_recording = FALSE;
+ priv->recording_lock = g_mutex_new();
+
+ priv->lock = g_mutex_new ();
+}
+
+void
+gst_camera_capturer_finalize (GObject * object)
+{
+ GstCameraCapturer *gcc = (GstCameraCapturer *) object;
+
+ GST_DEBUG_OBJECT (gcc, "Finalizing.");
+ if (gcc->priv->bus) {
+ /* make bus drop all messages to make sure none of our callbacks is ever
+ * called again (main loop might be run again to display error dialog) */
+ gst_bus_set_flushing (gcc->priv->bus, TRUE);
+
+ if (gcc->priv->sig_bus_async)
+ g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_async);
+
+ if (gcc->priv->sig_bus_sync)
+ g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_sync);
+
+ gst_object_unref (gcc->priv->bus);
+ gcc->priv->bus = NULL;
+ }
+
+ if (gcc->priv->output_file) {
+ g_free (gcc->priv->output_file);
+ gcc->priv->output_file = NULL;
+ }
+
+ if (gcc->priv->device_id) {
+ g_free (gcc->priv->device_id);
+ gcc->priv->device_id = NULL;
+ }
+
+ if (gcc->priv->logo_pixbuf) {
+ g_object_unref (gcc->priv->logo_pixbuf);
+ gcc->priv->logo_pixbuf = NULL;
+ }
+
+ if (gcc->priv->interface_update_id) {
+ g_source_remove (gcc->priv->interface_update_id);
+ gcc->priv->interface_update_id = 0;
+ }
+
+ if (gcc->priv->last_buffer != NULL)
+ gst_buffer_unref (gcc->priv->last_buffer);
+
+ if (gcc->priv->main_pipeline != NULL
+ && GST_IS_ELEMENT (gcc->priv->main_pipeline)) {
+ gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+ gst_object_unref (gcc->priv->main_pipeline);
+ gcc->priv->main_pipeline = NULL;
+ }
+
+ g_mutex_free (gcc->priv->lock);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_camera_capturer_set_video_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+{
+ gcc->priv->video_bitrate = bitrate;
+ if (gcc->priv->video_encoder_type == VIDEO_ENCODER_MPEG4 ||
+ gcc->priv->video_encoder_type == VIDEO_ENCODER_XVID)
+ g_object_set (gcc->priv->video_enc, "bitrate", bitrate * 1000, NULL);
+ else
+ g_object_set (gcc->priv->video_enc, "bitrate", gcc->priv->video_bitrate,
+ NULL);
+ GST_INFO_OBJECT (gcc, "Changed video bitrate to: %d",
+ gcc->priv->video_bitrate);
+}
+
+static void
+gst_camera_capturer_set_audio_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+{
+
+ gcc->priv->audio_bitrate = bitrate;
+ if (gcc->priv->audio_encoder_type == AUDIO_ENCODER_MP3)
+ g_object_set (gcc->priv->audio_enc, "bitrate", bitrate, NULL);
+ else
+ g_object_set (gcc->priv->audio_enc, "bitrate", 1000 * bitrate, NULL);
+ GST_INFO_OBJECT (gcc, "Changed audio bitrate to: %d",
+ gcc->priv->audio_bitrate);
+
+}
+
+static void
+gst_camera_capturer_set_audio_enabled (GstCameraCapturer * gcc,
+ gboolean enabled)
+{
+ gcc->priv->audio_enabled = enabled;
+ GST_INFO_OBJECT (gcc, "Audio is %s", enabled ? "enabled": "disabled");
+}
+
+static void
+gst_camera_capturer_set_output_file (GstCameraCapturer * gcc,
+ const gchar * file)
+{
+ gcc->priv->output_file = g_strdup (file);
+ GST_INFO_OBJECT (gcc, "Changed output filename to: %s", file);
+}
+
+static void
+gst_camera_capturer_set_device_id (GstCameraCapturer * gcc,
+ const gchar * device_id)
+{
+ gcc->priv->device_id = g_strdup (device_id);
+ GST_INFO_OBJECT (gcc, "Changed device id/name to: %s", device_id);
+}
+
static void
gst_camera_capturer_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
@@ -751,11 +746,9 @@ gst_camera_capturer_set_property (GObject * object, guint property_id,
switch (property_id) {
case PROP_OUTPUT_HEIGHT:
gcc->priv->output_height = g_value_get_uint (value);
- gst_camera_capturer_apply_resolution (gcc);
break;
case PROP_OUTPUT_WIDTH:
gcc->priv->output_width = g_value_get_uint (value);
- gst_camera_capturer_apply_resolution (gcc);
break;
case PROP_VIDEO_BITRATE:
gst_camera_capturer_set_video_bit_rate (gcc, g_value_get_uint (value));
@@ -886,6 +879,12 @@ gst_camera_capturer_class_init (GstCameraCapturerClass * klass)
NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
}
+/***********************************
+*
+* GStreamer
+*
+************************************/
+
void
gst_camera_capturer_init_backend (int *argc, char ***argv)
{
@@ -920,93 +919,6 @@ gst_camera_capture_videosrc_buffer_probe (GstPad * pad, GstBuffer * buf,
return TRUE;
}
-void
-gst_camera_capturer_run (GstCameraCapturer * gcc)
-{
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
-
- gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_PLAYING);
-}
-
-void
-gst_camera_capturer_close (GstCameraCapturer * gcc)
-{
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
-
- gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
-}
-
-void
-gst_camera_capturer_start (GstCameraCapturer * gcc)
-{
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
-
- GST_INFO_OBJECT(gcc, "Started capture");
- g_mutex_lock(gcc->priv->recording_lock);
- if (!gcc->priv->is_recording && gcc->priv->accum_recorded_ts == GST_CLOCK_TIME_NONE) {
- gcc->priv->accum_recorded_ts = 0;
- gcc->priv->is_recording = TRUE;
- gst_camera_capturer_link_encoder_bin (gcc);
- }
- g_mutex_unlock(gcc->priv->recording_lock);
-}
-
-void
-gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc)
-{
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
-
- g_mutex_lock(gcc->priv->recording_lock);
- if (!gcc->priv->is_recording) {
- gcc->priv->current_recording_start_ts = GST_CLOCK_TIME_NONE;
- gcc->priv->is_recording = TRUE;
- } else {
- gcc->priv->is_recording = FALSE;
- gcc->priv->video_synced = FALSE;
- }
- g_mutex_unlock(gcc->priv->recording_lock);
-
- GST_INFO_OBJECT(gcc, "Capture state changed to %s", gcc->priv->is_recording ? "recording": "paused");
-}
-
-void
-gst_camera_capturer_stop (GstCameraCapturer * gcc)
-{
- GstPad *video_pad;
-
- g_return_if_fail (gcc != NULL);
- g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
-
-#ifdef WIN32
- //On windows we can't handle device disconnections until dshowvideosrc
- //supports it. When a device is disconnected, the source is locked
- //in ::create(), blocking the streaming thread. We need to change its
- //state to null, this way camerabin doesn't block in ::do_stop().
- gst_element_set_state(gcc->priv->device_source, GST_STATE_NULL);
-#endif
-
- GST_INFO_OBJECT(gcc, "Closing capture");
- g_mutex_lock(gcc->priv->recording_lock);
- gcc->priv->closing_recording = TRUE;
- g_mutex_unlock(gcc->priv->recording_lock);
-
- video_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "video");
- gst_pad_send_event(video_pad, gst_event_new_eos());
- gst_object_unref(video_pad);
-
- if (gcc->priv->audio_enabled) {
- GstPad *audio_pad;
-
- audio_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "audio");
- gst_pad_send_event(audio_pad, gst_event_new_eos());
- gst_object_unref(audio_pad);
- }
-}
-
static void
gst_camera_capturer_update_device_id(GstCameraCapturer *gcc)
{
@@ -1043,7 +955,9 @@ static void
gst_camera_capturer_create_encoder_bin (GstCameraCapturer *gcc)
{
GstElement *colorspace, *videoscale, *videorate;
+ GstCaps *caps;
GstPad *v_sink_pad;
+ gchar *caps_str;
GST_INFO_OBJECT (gcc, "Creating encoder bin");
gcc->priv->encoder_bin = gst_bin_new ("encoder_bin");
@@ -1054,6 +968,14 @@ gst_camera_capturer_create_encoder_bin (GstCameraCapturer *gcc)
gcc->priv->video_filter = gst_element_factory_make("capsfilter", NULL);
gcc->priv->filesink = gst_element_factory_make("filesink", NULL);
+ /* Set caps for the encoding resolution */
+ caps_str = g_strdup_printf("video/x-raw-yuv, width=%d, height=%d",
+ gcc->priv->output_width, gcc->priv->output_height);
+ caps = gst_caps_from_string(caps_str);
+ g_object_set(gcc->priv->video_filter, "caps", caps, NULL);
+ gst_caps_unref(caps);
+ g_free(caps_str);
+
g_object_set(videorate, "skip-to-first", TRUE, NULL);
gst_bin_add_many(GST_BIN(gcc->priv->encoder_bin), videoscale, videorate,
@@ -1287,11 +1209,13 @@ gst_camera_capturer_encoding_retimestamper (GstCameraCapturer *gcc,
} else {
GstClockTime duration;
+ /* If we are just remuxing, drop everything until we see a keyframe */
if (gcc->priv->video_needs_keyframe_sync && !gcc->priv->video_synced) {
if (is_video && !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
gcc->priv->video_synced = TRUE;
} else {
- GST_LOG_OBJECT (gcc, "Waitin for a keyframe, dropping buffer on %s pad", is_video ? "video": "audio");
+ GST_LOG_OBJECT (gcc, "Waiting for a keyframe, "
+ "dropping buffer on %s pad", is_video ? "video": "audio");
ret = FALSE;
goto done;
}
@@ -1302,6 +1226,8 @@ gst_camera_capturer_encoding_retimestamper (GstCameraCapturer *gcc,
if (duration == GST_CLOCK_TIME_NONE)
duration = 0;
+ /* Check if it's the first buffer after starting or restarting the capture
+ * and update the timestamps accordingly */
if (G_UNLIKELY(gcc->priv->current_recording_start_ts == GST_CLOCK_TIME_NONE)) {
gcc->priv->current_recording_start_ts = buf_ts;
gcc->priv->last_accum_recorded_ts = gcc->priv->accum_recorded_ts;
@@ -1309,22 +1235,39 @@ gst_camera_capturer_encoding_retimestamper (GstCameraCapturer *gcc,
GST_TIME_ARGS(gcc->priv->last_accum_recorded_ts));
}
+ /* Clip buffers that are not in the segment */
if (buf_ts < gcc->priv->current_recording_start_ts) {
ret = FALSE;
goto done;
}
if (buf_ts != GST_CLOCK_TIME_NONE) {
+ /* Get the buffer timestamp with respect of the encoding time and not
+ * the playing time for a continous stream in the encoders input */
new_buf_ts = buf_ts - gcc->priv->current_recording_start_ts + gcc->priv->last_accum_recorded_ts;
+
+ /* Store the last timestamp seen on this pad */
+ if (is_video)
+ gcc->priv->last_video_buf_ts = new_buf_ts;
+ else
+ gcc->priv->last_audio_buf_ts = new_buf_ts;
+
+ /* Update the highest encoded timestamp */
if (new_buf_ts + duration > gcc->priv->accum_recorded_ts)
- {
gcc->priv->accum_recorded_ts = new_buf_ts + duration;
- gcc->priv->accum_recorded_ts = new_buf_ts;
- }
} else {
- /* h264parse only sets the timestamp on the first buffer */
- new_buf_ts = gcc->priv->accum_recorded_ts;
+ /* h264parse only sets the timestamp on the first buffer if a frame is
+ * split in several ones. Other parsers might do the same. We only set
+ * the last timestamp seen on the pad */
+ if (is_video)
+ new_buf_ts = gcc->priv->last_video_buf_ts;
+ else
+ new_buf_ts = gcc->priv->last_audio_buf_ts;
}
+
+ /* We don't want to overwrite timestamps of the preview branch */
+ buf = gst_buffer_make_metadata_writable(buf);
+ data = (GstMiniObject*) buf;
GST_BUFFER_TIMESTAMP(buf) = new_buf_ts;
GST_LOG_OBJECT(gcc, "Pushing %s frame to the encoder in ts:% " GST_TIME_FORMAT
@@ -1530,10 +1473,10 @@ gst_camera_capturer_create_preview(GstCameraCapturer *gcc)
GstElement *v_decoder, *video_bin;
GstPad *video_pad;
- v_decoder = gst_element_factory_make("decodebin2", NULL);
+ v_decoder = gst_element_factory_make("decodebin2", "preview-decoder");
video_bin = gst_parse_bin_from_description(
- "videorate ! videoscale ! ffmpegcolorspace ! autovideosink name=videosink", TRUE, NULL);
+ "videoscale ! ffmpegcolorspace ! autovideosink name=videosink", TRUE, NULL);
gcc->priv->preview_bin = gst_bin_new("preview_bin");
gst_bin_add_many (GST_BIN(gcc->priv->preview_bin), v_decoder, video_bin, NULL);
@@ -1569,32 +1512,32 @@ gst_camera_capturer_create_preview(GstCameraCapturer *gcc)
}
static gboolean
-gst_camera_capturer_source_pad_probe (GstPad *pad, GstBuffer *buf, GstCameraCapturer *gcc)
+gst_camera_capturer_have_type_cb (GstElement *typefind, guint prob,
+ GstCaps *caps, GstCameraCapturer *gcc)
{
- GstCaps *src_caps, *media_caps;
+ GstCaps *media_caps;
GstElement *decoder_bin = NULL;
- src_caps = gst_buffer_get_caps(buf);
- GST_INFO_OBJECT (gcc, "Got first buffer from the source with caps %s", gst_caps_to_string(src_caps));
+ GST_INFO_OBJECT (gcc, "Found type with caps %s", gst_caps_to_string(caps));
/* Check for DV streams */
media_caps = gst_caps_from_string("video/x-dv, systemstream=true");
- if (gst_caps_can_intersect(src_caps, media_caps)) {
+ if (gst_caps_can_intersect(caps, media_caps)) {
decoder_bin = gst_camera_capturer_prepare_dv_source(gcc);
gst_caps_unref(media_caps);
}
/* Check for MPEG-TS streams */
media_caps = gst_caps_from_string("video/mpegts");
- if (gst_caps_can_intersect(src_caps, media_caps)) {
+ if (gst_caps_can_intersect(caps, media_caps)) {
decoder_bin = gst_camera_capturer_prepare_mpegts_source(gcc);
gst_caps_unref(media_caps);
}
/* Check for Raw streams */
media_caps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
- if (gst_caps_can_intersect(src_caps, media_caps)) {
+ if (gst_caps_can_intersect(caps, media_caps)) {
gcc->priv->audio_enabled = FALSE;
decoder_bin = gst_camera_capturer_prepare_raw_source(gcc);
gst_caps_unref(media_caps);
@@ -1606,7 +1549,6 @@ gst_camera_capturer_source_pad_probe (GstPad *pad, GstBuffer *buf, GstCameraCapt
gst_camera_capturer_link_preview(gcc);
gst_element_set_state(gcc->priv->main_pipeline, GST_STATE_PLAYING);
- gst_pad_remove_buffer_probe(pad, gcc->priv->source_probe_id);
} else {
/* FIXME: post error */
}
@@ -1617,8 +1559,9 @@ static gboolean
gst_camera_capturer_create_video_source (GstCameraCapturer * gcc,
GstCameraCaptureSourceType type, GError ** err)
{
- GstPad *pad;
- gchar *name = NULL;
+ GstElement *typefind;
+ const gchar *source_desc = "";
+ gchar *source_str;
g_return_val_if_fail (gcc != NULL, FALSE);
g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
@@ -1626,37 +1569,37 @@ gst_camera_capturer_create_video_source (GstCameraCapturer * gcc,
switch (type) {
case GST_CAMERA_CAPTURE_SOURCE_TYPE_DV:
GST_INFO_OBJECT(gcc, "Creating dv video source");
- gcc->priv->source =
- gst_element_factory_make (DVVIDEOSRC, "source");
- name = DVVIDEOSRC;
+ source_desc = DVVIDEOSRC;
break;
case GST_CAMERA_CAPTURE_SOURCE_TYPE_SYSTEM:
GST_INFO_OBJECT(gcc, "Creating system video source");
- gcc->priv->source =
- gst_element_factory_make (SYSVIDEOSRC, "source");
- //gcc->priv->source = gst_parse_bin_from_description("filesrc location=/home/andoni/test.dv ! typefind", TRUE, NULL);
- name = SYSVIDEOSRC;
+ source_desc = SYSVIDEOSRC;
+ //source_desc = "filesrc location=/home/andoni/test.ts";
break;
default:
g_assert_not_reached();
}
+
+ source_str = g_strdup_printf("%s name=source ! typefind name=typefind", source_desc);
+ gcc->priv->source = gst_parse_bin_from_description(source_str, TRUE, NULL);
+ g_free(source_str);
if (!gcc->priv->source) {
g_set_error (err,
GCC_ERROR,
GST_ERROR_PLUGIN_LOAD,
"Failed to create the %s element. "
- "Please check your GStreamer installation.", name);
+ "Please check your GStreamer installation.", source_desc);
return FALSE;
}
gcc->priv->source_type = type;
- pad = gst_element_get_static_pad(gcc->priv->source, "src");
- gcc->priv->source_probe_id = gst_pad_add_buffer_probe(pad,
- (GCallback) gst_camera_capturer_source_pad_probe, gcc);
+ typefind = gst_bin_get_by_name (GST_BIN(gcc->priv->source), "typefind");
+ g_signal_connect (typefind, "have-type",
+ G_CALLBACK (gst_camera_capturer_have_type_cb), gcc);
gst_camera_capturer_update_device_id(gcc);
- GST_INFO_OBJECT(gcc, "Created video source %s", name);
+ GST_INFO_OBJECT(gcc, "Created video source %s", source_desc);
return TRUE;
}
@@ -2029,6 +1972,12 @@ gcc_get_video_stream_info (GstCameraCapturer * gcc)
return 1;
}
+/*****************************************************
+ *
+ * Device Probe
+ *
+ * **************************************************/
+
GList *
gst_camera_capturer_enum_devices (gchar * device_name)
{
@@ -2089,6 +2038,65 @@ gst_camera_capturer_enum_audio_devices (void)
return gst_camera_capturer_enum_devices (AUDIOSRC);
}
+/*******************************************
+ *
+ * Public methods
+ *
+ * ****************************************/
+
+void
+gst_camera_capturer_run (GstCameraCapturer * gcc)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_PLAYING);
+}
+
+void
+gst_camera_capturer_close (GstCameraCapturer * gcc)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+}
+
+void
+gst_camera_capturer_start (GstCameraCapturer * gcc)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ GST_INFO_OBJECT(gcc, "Started capture");
+ g_mutex_lock(gcc->priv->recording_lock);
+ if (!gcc->priv->is_recording && gcc->priv->accum_recorded_ts == GST_CLOCK_TIME_NONE) {
+ gcc->priv->accum_recorded_ts = 0;
+ gcc->priv->is_recording = TRUE;
+ gst_camera_capturer_link_encoder_bin (gcc);
+ }
+ g_mutex_unlock(gcc->priv->recording_lock);
+}
+
+void
+gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc)
+{
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+ g_mutex_lock(gcc->priv->recording_lock);
+ if (!gcc->priv->is_recording) {
+ gcc->priv->current_recording_start_ts = GST_CLOCK_TIME_NONE;
+ gcc->priv->is_recording = TRUE;
+ } else {
+ gcc->priv->is_recording = FALSE;
+ gcc->priv->video_synced = FALSE;
+ }
+ g_mutex_unlock(gcc->priv->recording_lock);
+
+ GST_INFO_OBJECT(gcc, "Capture state changed to %s", gcc->priv->is_recording ? "recording": "paused");
+}
+
gboolean
gst_camera_capturer_can_get_frames (GstCameraCapturer * gcc, GError ** error)
{
@@ -2218,6 +2226,41 @@ gst_camera_capturer_get_current_frame (GstCameraCapturer * gcc)
return pixbuf;
}
+
+void
+gst_camera_capturer_stop (GstCameraCapturer * gcc)
+{
+ GstPad *video_pad;
+
+ g_return_if_fail (gcc != NULL);
+ g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+#ifdef WIN32
+ //On windows we can't handle device disconnections until dshowvideosrc
+ //supports it. When a device is disconnected, the source is locked
+ //in ::create(), blocking the streaming thread. We need to change its
+ //state to null, this way camerabin doesn't block in ::do_stop().
+ gst_element_set_state(gcc->priv->device_source, GST_STATE_NULL);
+#endif
+
+ GST_INFO_OBJECT(gcc, "Closing capture");
+ g_mutex_lock(gcc->priv->recording_lock);
+ gcc->priv->closing_recording = TRUE;
+ g_mutex_unlock(gcc->priv->recording_lock);
+
+ video_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "video");
+ gst_pad_send_event(video_pad, gst_event_new_eos());
+ gst_object_unref(video_pad);
+
+ if (gcc->priv->audio_enabled) {
+ GstPad *audio_pad;
+
+ audio_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "audio");
+ gst_pad_send_event(audio_pad, gst_event_new_eos());
+ gst_object_unref(audio_pad);
+ }
+}
+
GstCameraCapturer *
gst_camera_capturer_new (gchar * filename, GstCameraCaptureSourceType source,
VideoEncoderType venc, AudioEncoderType aenc, VideoMuxerType muxer, GError ** err)
@@ -2286,4 +2329,3 @@ missing_plugin:
return NULL;
}
}
-
diff --git a/libcesarplayer/main.c b/libcesarplayer/main.c
index 4eaabda..0f1dad6 100644
--- a/libcesarplayer/main.c
+++ b/libcesarplayer/main.c
@@ -39,7 +39,7 @@ window_state_event (GtkWidget * widget, GdkEventWindowState * event,
}
if (i == 5)
- gst_camera_capturer_toggle_pause (GST_CAMERA_CAPTURER (gvc));
+ gst_camera_capturer_stop (GST_CAMERA_CAPTURER (gvc));
if (i == 6)
gst_camera_capturer_toggle_pause (GST_CAMERA_CAPTURER (gvc));
if (i == 7)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]