static gboolean gst_v4l2_transform_decide_allocation (GstBaseTransform * trans, GstQuery * query) { GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans); gboolean ret = FALSE; GST_DEBUG_OBJECT (self, "called"); if (gst_v4l2_object_decide_allocation (self->v4l2capture, query)) { GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2capture->pool); ret = GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans, query); if (!gst_buffer_pool_set_active (pool, TRUE)) goto activate_failed; } return ret; activate_failed: GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, ("failed to activate bufferpool"), ("failed to activate bufferpool")); return TRUE; }
static GstBuffer * gst_v4lmjpegsink_buffer_new (GstBufferPool * pool, guint64 offset, guint size, gpointer user_data) { GstV4lMjpegSink *v4lmjpegsink = GST_V4LMJPEGSINK (user_data); GstBuffer *buffer = NULL; guint8 *data; gint num; if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsink))) return NULL; if (v4lmjpegsink->breq.size < size) { GST_DEBUG ("Requested buffer size is too large (%d > %ld)", size, v4lmjpegsink->breq.size); return NULL; } if (!gst_v4lmjpegsink_wait_frame (v4lmjpegsink, &num)) return NULL; data = gst_v4lmjpegsink_get_buffer (v4lmjpegsink, num); if (!data) return NULL; buffer = gst_buffer_new (); GST_BUFFER_DATA (buffer) = data; GST_BUFFER_MAXSIZE (buffer) = v4lmjpegsink->breq.size; GST_BUFFER_SIZE (buffer) = size; GST_BUFFER_POOL (buffer) = pool; GST_BUFFER_POOL_PRIVATE (buffer) = GINT_TO_POINTER (num); /* with this flag set, we don't need our own buffer_free() function */ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTFREE); return buffer; }
/** * gst_v4l2_buffer_pool_new: * @obj: the v4l2 object owning the pool * * Construct a new buffer pool. * * Returns: the new pool, use gst_object_unref() to free resources */ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) { GstV4l2BufferPool *pool; GstStructure *s; gint fd; fd = v4l2_dup (obj->video_fd); if (fd < 0) goto dup_failed; pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL); pool->video_fd = fd; pool->obj = obj; s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); gst_buffer_pool_config_set_params (s, caps, obj->sizeimage, 2, 0); gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), s); return GST_BUFFER_POOL (pool); /* ERRORS */ dup_failed: { GST_DEBUG ("failed to dup fd %d (%s)", errno, g_strerror (errno)); return NULL; } }
static gboolean mark_meta_pooled (GstBuffer * buffer, GstMeta ** meta, gpointer user_data) { GST_DEBUG_OBJECT (GST_BUFFER_POOL (user_data), "marking meta %p as POOLED in buffer %p", *meta, buffer); GST_META_FLAG_SET (*meta, GST_META_FLAG_POOLED); GST_META_FLAG_SET (*meta, GST_META_FLAG_LOCKED); return TRUE; }
void gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool, GstBufferPool * other_pool) { g_return_if_fail (!gst_buffer_pool_is_active (GST_BUFFER_POOL (pool))); if (pool->other_pool) gst_object_unref (pool->other_pool); pool->other_pool = gst_object_ref (other_pool); }
static gboolean gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder) { GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder); /* We don't allow renegotiation without carefull disabling the pool */ if (self->v4l2capture->pool && gst_buffer_pool_is_active (GST_BUFFER_POOL (self->v4l2capture->pool))) return TRUE; return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); }
GstBufferPool * gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component, GstOMXPort * port) { GstOMXBufferPool *pool; pool = g_object_new (gst_omx_buffer_pool_get_type (), NULL); pool->element = gst_object_ref (element); pool->component = component; pool->port = port; return GST_BUFFER_POOL (pool); }
static void gst_wayland_buffer_pool_finalize (GObject * object) { GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object); if (pool->wl_pool) gst_wayland_buffer_pool_stop (GST_BUFFER_POOL (pool)); g_mutex_clear (&pool->buffers_map_mutex); g_hash_table_unref (pool->buffers_map); g_object_unref (pool->display); G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object); }
static void gst_v4lmjpegsink_chain (GstPad * pad, GstData * _data) { GstBuffer *buf = GST_BUFFER (_data); GstV4lMjpegSink *v4lmjpegsink; gint num; g_return_if_fail (pad != NULL); g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (buf != NULL); v4lmjpegsink = GST_V4LMJPEGSINK (gst_pad_get_parent (pad)); if (v4lmjpegsink->clock) { GST_DEBUG ("videosink: clock wait: %" G_GUINT64_FORMAT, GST_BUFFER_TIMESTAMP (buf)); gst_element_wait (GST_ELEMENT (v4lmjpegsink), GST_BUFFER_TIMESTAMP (buf)); } #if 0 if (GST_BUFFER_POOL (buf) == v4lmjpegsink->bufferpool) { num = GPOINTER_TO_INT (GST_BUFFER_POOL_PRIVATE (buf)); gst_v4lmjpegsink_play_frame (v4lmjpegsink, num); } else { #endif /* check size */ if (GST_BUFFER_SIZE (buf) > v4lmjpegsink->breq.size) { GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, WRITE, (NULL), ("Buffer too big (%d KB), max. buffersize is %ld KB", GST_BUFFER_SIZE (buf) / 1024, v4lmjpegsink->breq.size / 1024)); return; } /* put JPEG data to the device */ gst_v4lmjpegsink_wait_frame (v4lmjpegsink, &num); memcpy (gst_v4lmjpegsink_get_buffer (v4lmjpegsink, num), GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); gst_v4lmjpegsink_play_frame (v4lmjpegsink, num); #if 0 } #endif g_signal_emit (G_OBJECT (v4lmjpegsink), gst_v4lmjpegsink_signals[SIGNAL_FRAME_DISPLAYED], 0); gst_buffer_unref (buf); }
static void gst_v4l2_buffer_pool_group_released (GstV4l2BufferPool * pool) { GstBufferPoolAcquireParams params = { 0 }; GstBuffer *buffer = NULL; GstFlowReturn ret; GST_DEBUG_OBJECT (pool, "A buffer was lost, reallocating it"); params.flags = (GstBufferPoolAcquireFlags) GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT; ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (pool), &buffer, ¶ms); if (ret == GST_FLOW_OK) gst_buffer_unref (buffer); }
void gst_droid_cam_src_stream_window_clear (GstDroidCamSrcStreamWindow * win) { GST_DEBUG ("stream window clear"); g_mutex_lock (&win->lock); if (win->pool) { if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (win->pool), FALSE)) { GST_ERROR ("failed to deactivate buffer pool"); } gst_object_unref (win->pool); win->pool = NULL; } g_mutex_unlock (&win->lock); }
void gst_droid_cam_src_stream_window_destroy (GstDroidCamSrcStreamWindow * win) { GST_DEBUG ("stream window destroy"); gst_object_unref (win->allocator); win->allocator = NULL; g_mutex_clear (&win->lock); if (win->pool) { if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (win->pool), FALSE)) { GST_ERROR ("failed to deactivate buffer pool"); } gst_object_unref (win->pool); } g_slice_free (GstDroidCamSrcStreamWindow, win); }
static GstFlowReturn gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame) { GstV4l2Error error = GST_V4L2_ERROR_INIT; GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder); GstFlowReturn ret = GST_FLOW_OK; gboolean processed = FALSE; GstBuffer *tmp; GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number); if (G_UNLIKELY (!g_atomic_int_get (&self->active))) goto flushing; if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) { if (!self->input_state) goto not_negotiated; if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps, &error)) goto not_negotiated; } if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) { GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool); GstVideoInfo info; GstVideoCodecState *output_state; GstBuffer *codec_data; GstCaps *acquired_caps, *available_caps, *caps, *filter; GstStructure *st; GST_DEBUG_OBJECT (self, "Sending header"); codec_data = self->input_state->codec_data; /* We are running in byte-stream mode, so we don't know the headers, but * we need to send something, otherwise the decoder will refuse to * intialize. */ if (codec_data) { gst_buffer_ref (codec_data); } else { codec_data = gst_buffer_ref (frame->input_buffer); processed = TRUE; } /* Ensure input internal pool is active */ if (!gst_buffer_pool_is_active (pool)) { GstStructure *config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, self->input_state->caps, self->v4l2output->info.size, 2, 2); /* There is no reason to refuse this config */ if (!gst_buffer_pool_set_config (pool, config)) goto activate_failed; if (!gst_buffer_pool_set_active (pool, TRUE)) goto activate_failed; } GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self-> v4l2output->pool), &codec_data); GST_VIDEO_DECODER_STREAM_LOCK (decoder); gst_buffer_unref (codec_data); /* For decoders G_FMT returns coded size, G_SELECTION returns visible size * in the compose rectangle. gst_v4l2_object_acquire_format() checks both * and returns the visible size as with/height and the coded size as * padding. */ if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info)) goto not_negotiated; /* Create caps from the acquired format, remove the format field */ acquired_caps = gst_video_info_to_caps (&info); st = gst_caps_get_structure (acquired_caps, 0); gst_structure_remove_field (st, "format"); /* Probe currently available pixel formats */ available_caps = gst_v4l2_object_probe_caps (self->v4l2capture, NULL); available_caps = gst_caps_make_writable (available_caps); /* Replace coded size with visible size, we want to negotiate visible size * with downstream, not coded size. */ gst_caps_map_in_place (available_caps, gst_v4l2_video_remove_padding, self); filter = gst_caps_intersect_full (available_caps, acquired_caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (acquired_caps); gst_caps_unref (available_caps); caps = gst_pad_peer_query_caps (decoder->srcpad, filter); gst_caps_unref (filter); GST_DEBUG_OBJECT (self, "Possible decoded caps: %" GST_PTR_FORMAT, caps); if (gst_caps_is_empty (caps)) { gst_caps_unref (caps); goto not_negotiated; } /* Fixate pixel format */ caps = gst_caps_fixate (caps); GST_DEBUG_OBJECT (self, "Chosen decoded caps: %" GST_PTR_FORMAT, caps); /* Try to set negotiated format, on success replace acquired format */ if (gst_v4l2_object_set_format (self->v4l2capture, caps, &error)) gst_video_info_from_caps (&info, caps); else gst_v4l2_clear_error (&error); gst_caps_unref (caps); output_state = gst_video_decoder_set_output_state (decoder, info.finfo->format, info.width, info.height, self->input_state); /* Copy the rest of the information, there might be more in the future */ output_state->info.interlace_mode = info.interlace_mode; gst_video_codec_state_unref (output_state); if (!gst_video_decoder_negotiate (decoder)) { if (GST_PAD_IS_FLUSHING (decoder->srcpad)) goto flushing; else goto not_negotiated; } /* Ensure our internal pool is activated */ if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool), TRUE)) goto activate_failed; } if (g_atomic_int_get (&self->processing) == FALSE) { /* It's possible that the processing thread stopped due to an error */ if (self->output_flow != GST_FLOW_OK && self->output_flow != GST_FLOW_FLUSHING) { GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving"); ret = self->output_flow; goto drop; } GST_DEBUG_OBJECT (self, "Starting decoding thread"); /* Start the processing task, when it quits, the task will disable input * processing to unlock input if draining, or prevent potential block */ g_atomic_int_set (&self->processing, TRUE); if (!gst_pad_start_task (decoder->srcpad, (GstTaskFunction) gst_v4l2_video_dec_loop, self, (GDestroyNotify) gst_v4l2_video_dec_loop_stopped)) goto start_task_failed; } if (!processed) { GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output-> pool), &frame->input_buffer); GST_VIDEO_DECODER_STREAM_LOCK (decoder); if (ret == GST_FLOW_FLUSHING) { if (g_atomic_int_get (&self->processing) == FALSE) ret = self->output_flow; goto drop; } else if (ret != GST_FLOW_OK) { goto process_failed; } } /* No need to keep input arround */ tmp = frame->input_buffer; frame->input_buffer = gst_buffer_new (); gst_buffer_copy_into (frame->input_buffer, tmp, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META, 0, 0); gst_buffer_unref (tmp); gst_video_codec_frame_unref (frame); return ret; /* ERRORS */ not_negotiated: { GST_ERROR_OBJECT (self, "not negotiated"); ret = GST_FLOW_NOT_NEGOTIATED; gst_v4l2_error (self, &error); goto drop; } activate_failed: { GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (_("Failed to allocate required memory.")), ("Buffer pool activation failed")); ret = GST_FLOW_ERROR; goto drop; } flushing: { ret = GST_FLOW_FLUSHING; goto drop; } start_task_failed: { GST_ELEMENT_ERROR (self, RESOURCE, FAILED, (_("Failed to start decoding thread.")), (NULL)); g_atomic_int_set (&self->processing, FALSE); ret = GST_FLOW_ERROR; goto drop; } process_failed: { GST_ELEMENT_ERROR (self, RESOURCE, FAILED, (_("Failed to process frame.")), ("Maybe be due to not enough memory or failing driver")); ret = GST_FLOW_ERROR; goto drop; } drop: { gst_video_decoder_drop_frame (decoder, frame); return ret; } }
static GstFlowReturn gst_v4l2_transform_prepare_output_buffer (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer ** outbuf) { GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans); GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool); GstFlowReturn ret = GST_FLOW_OK; GstBaseTransformClass *bclass = GST_BASE_TRANSFORM_CLASS (parent_class); if (gst_base_transform_is_passthrough (trans)) { GST_DEBUG_OBJECT (self, "Passthrough, no need to do anything"); *outbuf = inbuf; goto beach; } /* Ensure input internal pool is active */ if (!gst_buffer_pool_is_active (pool)) { GstStructure *config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, self->incaps, self->v4l2output->info.size, 2, 2); /* There is no reason to refuse this config */ if (!gst_buffer_pool_set_config (pool, config)) goto activate_failed; if (!gst_buffer_pool_set_active (pool, TRUE)) goto activate_failed; } GST_DEBUG_OBJECT (self, "Queue input buffer"); ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), &inbuf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; do { pool = gst_base_transform_get_buffer_pool (trans); if (!gst_buffer_pool_set_active (pool, TRUE)) goto activate_failed; GST_DEBUG_OBJECT (self, "Dequeue output buffer"); ret = gst_buffer_pool_acquire_buffer (pool, outbuf, NULL); g_object_unref (pool); if (ret != GST_FLOW_OK) goto alloc_failed; pool = self->v4l2capture->pool; ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), outbuf); } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER); if (ret != GST_FLOW_OK) { gst_buffer_unref (*outbuf); *outbuf = NULL; } if (bclass->copy_metadata) if (!bclass->copy_metadata (trans, inbuf, *outbuf)) { /* something failed, post a warning */ GST_ELEMENT_WARNING (self, STREAM, NOT_IMPLEMENTED, ("could not copy metadata"), (NULL)); } beach: return ret; activate_failed: GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, ("failed to activate bufferpool"), ("failed to activate bufferpool")); g_object_unref (pool); return GST_FLOW_ERROR; alloc_failed: GST_DEBUG_OBJECT (self, "could not allocate buffer from pool"); return ret; }
static void gst_droidcamsrc_stream_window_reset_buffer_pool_locked (GstDroidCamSrcStreamWindow * win) { GstStructure *config; GstCaps *caps; GstCapsFeatures *feature; GST_DEBUG ("stream window configure buffer pool"); if (win->pool) { /* we will ignore the error here */ if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (win->pool), FALSE)) { GST_WARNING ("Failed to deactivate buffer pool"); } gst_object_unref (win->pool); } win->pool = gst_droid_cam_src_buffer_pool_new (win->info); if (!win->count || !win->width || !win->height || !win->usage || !win->format) { GST_ERROR ("incomplete configuration"); goto clean_and_out; } config = gst_buffer_pool_get_config (GST_BUFFER_POOL (win->pool)); if (!config) { GST_ERROR ("failed to get buffer pool config"); goto clean_and_out; } /* TODO: 30 is hardcoded */ caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "ENCODED", "width", G_TYPE_INT, win->width, "height", G_TYPE_INT, win->height, "framerate", GST_TYPE_FRACTION, 30, 1, NULL); feature = gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DROID_HANDLE, NULL); gst_caps_set_features (caps, 0, feature); gst_buffer_pool_config_set_params (config, caps, 0, win->count, win->count); gst_buffer_pool_config_set_allocator (config, win->allocator, NULL); gst_structure_set (config, GST_DROIDCAMSRC_BUFFER_POOL_USAGE_KEY, G_TYPE_INT, win->usage, GST_DROIDCAMSRC_BUFFER_POOL_WIDTH_KEY, G_TYPE_INT, win->width, GST_DROIDCAMSRC_BUFFER_POOL_HEIGHT_KEY, G_TYPE_INT, win->height, GST_DROIDCAMSRC_BUFFER_POOL_FORMAT_KEY, G_TYPE_INT, win->format, NULL); gst_caps_unref (caps); if (!gst_buffer_pool_set_config (GST_BUFFER_POOL (win->pool), config)) { GST_ERROR ("failed to set buffer pool config"); goto clean_and_out; } if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (win->pool), TRUE)) { GST_ERROR ("failed to activate buffer pool"); goto clean_and_out; } win->needs_reconfigure = FALSE; return; clean_and_out: if (win->pool) { gst_object_unref (win->pool); win->pool = NULL; } }
static int gst_droidcamsrc_stream_window_dequeue_buffer (struct preview_stream_ops *w, buffer_handle_t ** buffer, int *stride) { GstDroidCamSrcStreamWindow *win; GstBuffer *buff; GstFlowReturn ret; int trials; GstBufferPoolAcquireParams params; GstMemory *mem; struct ANativeWindowBuffer *native; int res; GST_DEBUG ("dequeue buffer %p", buffer); win = container_of (w, GstDroidCamSrcStreamWindow, window); g_mutex_lock (&win->lock); retry: GST_DEBUG ("needs reconfigure? %d", win->needs_reconfigure); if (!win->pool || (win->pool && win->needs_reconfigure)) { /* create and re/configure the pool */ gst_droidcamsrc_stream_window_reset_buffer_pool_locked (win); } if (!win->pool) { GST_ERROR ("failed to create buffer pool"); res = -1; goto unlock_and_exit; } mem = NULL; trials = ACQUIRE_BUFFER_TRIALS; params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT; while (trials > 0) { ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (win->pool), &buff, ¶ms); if (ret == GST_FLOW_OK) { /* we have our buffer */ break; } else if (ret == GST_FLOW_ERROR || ret == GST_FLOW_FLUSHING) { /* no point in waiting */ break; } /* we need to unlock here to allow buffers to be returned back */ g_mutex_unlock (&win->lock); usleep (ACQUIRE_BUFFER_TIMEOUT); g_mutex_lock (&win->lock); if (win->needs_reconfigure) { /* out of here */ goto retry; } --trials; } if (buff) { /* handover */ mem = gst_buffer_peek_memory (buff, 0); } else if (ret == GST_FLOW_FLUSHING) { GST_INFO ("pool is flushing"); } else { GST_WARNING ("failed to get a buffer"); } if (!mem) { GST_ERROR ("no buffer memory found"); res = -1; goto unlock_and_exit; } native = gst_memory_get_native_buffer (mem); if (!native) { GST_ERROR ("invalid buffer"); gst_buffer_unref (buff); res = -1; goto unlock_and_exit; } *buffer = &native->handle; *stride = native->stride; GST_LOG ("dequeue buffer done %p", *buffer); res = 0; unlock_and_exit: g_mutex_unlock (&win->lock); return res; }
static GstFlowReturn gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame) { GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder); GstFlowReturn ret = GST_FLOW_OK; GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number); if (G_UNLIKELY (!g_atomic_int_get (&self->active))) goto flushing; if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) { if (!self->input_state) goto not_negotiated; if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps)) goto not_negotiated; } if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) { GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool); GstVideoInfo info; GstVideoCodecState *output_state; GstBuffer *codec_data; GST_DEBUG_OBJECT (self, "Sending header"); codec_data = self->input_state->codec_data; /* We are running in byte-stream mode, so we don't know the headers, but * we need to send something, otherwise the decoder will refuse to * intialize. */ if (codec_data) { gst_buffer_ref (codec_data); } else { codec_data = frame->input_buffer; frame->input_buffer = NULL; } /* Ensure input internal pool is active */ if (!gst_buffer_pool_is_active (pool)) { GstStructure *config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, self->input_state->caps, self->v4l2output->info.size, 2, 2); /* There is no reason to refuse this config */ if (!gst_buffer_pool_set_config (pool, config)) goto activate_failed; if (!gst_buffer_pool_set_active (pool, TRUE)) goto activate_failed; } GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self-> v4l2output->pool), &codec_data); GST_VIDEO_DECODER_STREAM_LOCK (decoder); gst_buffer_unref (codec_data); if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info)) goto not_negotiated; output_state = gst_video_decoder_set_output_state (decoder, info.finfo->format, info.width, info.height, self->input_state); /* Copy the rest of the information, there might be more in the future */ output_state->info.interlace_mode = info.interlace_mode; gst_video_codec_state_unref (output_state); if (!gst_video_decoder_negotiate (decoder)) { if (GST_PAD_IS_FLUSHING (decoder->srcpad)) goto flushing; else goto not_negotiated; } /* Ensure our internal pool is activated */ if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool), TRUE)) goto activate_failed; } if (g_atomic_int_get (&self->processing) == FALSE) { /* It's possible that the processing thread stopped due to an error */ if (self->output_flow != GST_FLOW_OK && self->output_flow != GST_FLOW_FLUSHING) { GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving"); ret = self->output_flow; goto drop; } GST_DEBUG_OBJECT (self, "Starting decoding thread"); /* Start the processing task, when it quits, the task will disable input * processing to unlock input if draining, or prevent potential block */ g_atomic_int_set (&self->processing, TRUE); if (!gst_pad_start_task (decoder->srcpad, (GstTaskFunction) gst_v4l2_video_dec_loop, self, (GDestroyNotify) gst_v4l2_video_dec_loop_stopped)) goto start_task_failed; } if (frame->input_buffer) { GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output-> pool), &frame->input_buffer); GST_VIDEO_DECODER_STREAM_LOCK (decoder); if (ret == GST_FLOW_FLUSHING) { if (g_atomic_int_get (&self->processing) == FALSE) ret = self->output_flow; goto drop; } else if (ret != GST_FLOW_OK) { goto process_failed; } /* No need to keep input arround */ gst_buffer_replace (&frame->input_buffer, NULL); } gst_video_codec_frame_unref (frame); return ret; /* ERRORS */ not_negotiated: { GST_ERROR_OBJECT (self, "not negotiated"); ret = GST_FLOW_NOT_NEGOTIATED; goto drop; } activate_failed: { GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (_("Failed to allocate required memory.")), ("Buffer pool activation failed")); ret = GST_FLOW_ERROR; goto drop; } flushing: { ret = GST_FLOW_FLUSHING; goto drop; } start_task_failed: { GST_ELEMENT_ERROR (self, RESOURCE, FAILED, (_("Failed to start decoding thread.")), (NULL)); g_atomic_int_set (&self->processing, FALSE); ret = GST_FLOW_ERROR; goto drop; } process_failed: { GST_ELEMENT_ERROR (self, RESOURCE, FAILED, (_("Failed to process frame.")), ("Maybe be due to not enough memory or failing driver")); ret = GST_FLOW_ERROR; goto drop; } drop: { gst_video_decoder_drop_frame (decoder, frame); return ret; } }
/** * gst_v4l2_buffer_pool_new: * @obj: the v4l2 object owning the pool * * Construct a new buffer pool. * * Returns: the new pool, use gst_object_unref() to free resources */ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) { GstV4l2BufferPool *pool; GstStructure *config; gchar *name, *parent_name; gint fd; fd = v4l2_dup (obj->video_fd); if (fd < 0) goto dup_failed; /* setting a significant unique name */ parent_name = gst_object_get_name (GST_OBJECT (obj->element)); name = g_strconcat (parent_name, ":", "pool:", V4L2_TYPE_IS_OUTPUT (obj->type) ? "sink" : "src", NULL); g_free (parent_name); pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, "name", name, NULL); g_free (name); gst_poll_fd_init (&pool->pollfd); pool->pollfd.fd = fd; gst_poll_add_fd (pool->poll, &pool->pollfd); if (V4L2_TYPE_IS_OUTPUT (obj->type)) gst_poll_fd_ctl_write (pool->poll, &pool->pollfd, TRUE); else gst_poll_fd_ctl_read (pool->poll, &pool->pollfd, TRUE); pool->video_fd = fd; pool->obj = obj; pool->can_poll_device = TRUE; pool->vallocator = gst_v4l2_allocator_new (GST_OBJECT (pool), obj->video_fd, &obj->format); if (pool->vallocator == NULL) goto allocator_failed; gst_object_ref (obj->element); config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); gst_buffer_pool_config_set_params (config, caps, obj->info.size, 0, 0); /* This will simply set a default config, but will not configure the pool * because min and max are not valid */ gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), config); return GST_BUFFER_POOL (pool); /* ERRORS */ dup_failed: { GST_ERROR ("failed to dup fd %d (%s)", errno, g_strerror (errno)); return NULL; } allocator_failed: { GST_ERROR_OBJECT (pool, "Failed to create V4L2 allocator"); return NULL; } }
static int gst_droidcamsrc_stream_window_enqueue_buffer (struct preview_stream_ops *w, buffer_handle_t * buffer) { GstDroidCamSrcStreamWindow *win; GstDroidCamSrc *src; GstBuffer *buff; int ret; GstVideoCropMeta *meta; GST_DEBUG ("enqueue buffer %p", buffer); win = container_of (w, GstDroidCamSrcStreamWindow, window); g_mutex_lock (&win->lock); src = GST_DROIDCAMSRC (GST_PAD_PARENT (win->pad->pad)); buff = gst_droidcamsrc_stream_window_get_buffer (buffer); if (!buff) { GST_ERROR ("no buffer corresponding to handle %p", buffer); ret = -1; goto unlock_and_out; } /* if the buffer pool is not our current pool then just release it */ if (buff->pool != GST_BUFFER_POOL (win->pool)) { GST_DEBUG ("releasing old buffer %p", buffer); gst_buffer_unref (buff); ret = 0; goto unlock_and_out; } /* now update crop meta */ meta = gst_buffer_get_video_crop_meta (buff); meta->x = win->left; meta->y = win->top; meta->width = win->right - win->left; meta->height = win->bottom - win->top; GST_LOG ("window width = %d, height = %d, crop info: left = %d, top = %d, right = %d, bottom = %d", win->width, win->height, win->left, win->top, win->right, win->bottom); g_mutex_unlock (&win->lock); /* it should be safe to access that variable without locking. * pad gets activated during READY_TO_PAUSED and deactivated during * PAUSED_TO_READY while we start the preview during PAUSED_TO_PLAYING * and stop it during PLAYING_TO_PAUSED. */ if (!win->pad->running) { gst_buffer_unref (buff); GST_DEBUG ("unreffing buffer because pad task is not running"); ret = 0; goto unlock_pad_and_out; } // TODO: duration, offset, offset_end ... gst_droidcamsrc_timestamp (src, buff); g_mutex_lock (&win->pad->queue_lock); g_queue_push_tail (win->pad->queue, buff); g_cond_signal (&win->pad->cond); ret = 0; goto unlock_pad_and_out; unlock_and_out: g_mutex_unlock (&win->lock); return ret; unlock_pad_and_out: g_mutex_unlock (&win->pad->queue_lock); return ret; }