static void gst_droidcamsrc_dev_prepare_buffer (GstDroidCamSrcDev * dev, GstBuffer * buffer, DroidMediaRect rect, int width, int height, GstVideoFormat format) { GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad)); GstVideoCropMeta *crop; GST_LOG_OBJECT (src, "prepare buffer %" GST_PTR_FORMAT, buffer); gst_droidcamsrc_timestamp (src, buffer); crop = gst_buffer_add_video_crop_meta (buffer); crop->x = rect.left; crop->y = rect.top; crop->width = rect.right - rect.left; crop->height = rect.bottom - rect.top; gst_buffer_add_gst_buffer_orientation_meta (buffer, dev->info->orientation, dev->info->direction); gst_buffer_add_video_meta (buffer, GST_VIDEO_FRAME_FLAG_NONE, format, width, height); GST_LOG_OBJECT (src, "preview info: w=%d, h=%d, crop: x=%d, y=%d, w=%d, h=%d", width, height, crop->x, crop->y, crop->width, crop->height); }
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; }
static void gst_droidcamsrc_dev_frame_available (void *user) { GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user; GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad)); GstDroidCamSrcPad *pad = dev->vfsrc; DroidMediaBuffer *buffer; GstMemory *mem; DroidMediaRect rect; guint width, height; GstBuffer *buff; DroidMediaBufferCallbacks cb; GstFlowReturn flow_ret; DroidMediaBufferInfo info; GST_DEBUG_OBJECT (src, "frame available"); if (!pad->running) { GST_DEBUG_OBJECT (src, "vfsrc pad task is not running"); goto acquire_and_release; } /* We are accessing this without a lock because: * 1) We should not be called while preview is stopped and this is when we manipulate this flag * 2) We can get called when we start the preview and we will deadlock because the lock is already held */ if (dev->use_raw_data) { goto acquire_and_release; } flow_ret = gst_buffer_pool_acquire_buffer (dev->pool, &buff, NULL); if (flow_ret != GST_FLOW_OK) { GST_WARNING_OBJECT (src, "failed to acquire buffer from pool: %s", gst_flow_get_name (flow_ret)); goto acquire_and_release; } cb.ref = (DroidMediaCallback) gst_buffer_ref; cb.unref = (DroidMediaCallback) gst_buffer_unref; cb.data = buff; mem = gst_droid_media_buffer_allocator_alloc (dev->media_allocator, dev->queue, &cb); if (!mem) { GST_ERROR_OBJECT (src, "failed to acquire buffer from droidmedia"); gst_buffer_unref (buff); return; } buffer = gst_droid_media_buffer_memory_get_buffer (mem); gst_buffer_insert_memory (buff, 0, mem); gst_droidcamsrc_timestamp (src, buff); rect = droid_media_buffer_get_crop_rect (buffer); width = droid_media_buffer_get_width (buffer); height = droid_media_buffer_get_height (buffer); gst_droidcamsrc_dev_prepare_buffer (dev, buff, rect, width, height, GST_VIDEO_FORMAT_YV12); g_mutex_lock (&pad->lock); g_queue_push_tail (pad->queue, buff); g_cond_signal (&pad->cond); g_mutex_unlock (&pad->lock); GST_OBJECT_LOCK (src); src->crop_rect = rect; GST_OBJECT_UNLOCK (src); return; acquire_and_release: if (droid_media_buffer_queue_acquire_and_release (dev->queue, &info)) { GST_OBJECT_LOCK (src); src->crop_rect = info.crop_rect; GST_OBJECT_UNLOCK (src); } }
static void gst_droidcamsrc_dev_video_frame_callback (void *user, DroidMediaCameraRecordingData * video_data) { GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user; GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad)); void *data = droid_media_camera_recording_frame_get_data (video_data); GstBuffer *buffer; GstMemory *mem; GstDroidCamSrcDevVideoData *mem_data; gboolean drop_buffer; GST_DEBUG_OBJECT (src, "dev video frame callback"); g_mutex_lock (&dev->vid->lock); /* TODO: not sure what to do with timestamp */ /* unlikely but just in case */ if (G_UNLIKELY (!data)) { GST_ERROR ("invalid memory from camera HAL"); droid_media_camera_release_recording_frame (dev->cam, video_data); goto unlock_and_out; } /* TODO: this is bad */ mem_data = g_slice_new0 (GstDroidCamSrcDevVideoData); mem_data->dev = dev; mem_data->data = video_data; buffer = gst_buffer_new (); mem = gst_wrapped_memory_allocator_wrap (dev->wrap_allocator, data, droid_media_camera_recording_frame_get_size (video_data), (GFunc) gst_droidcamsrc_dev_release_recording_frame, mem_data); gst_buffer_insert_memory (buffer, 0, mem); GST_BUFFER_OFFSET (buffer) = dev->vid->video_frames; GST_BUFFER_OFFSET_END (buffer) = ++dev->vid->video_frames; gst_droidcamsrc_timestamp (src, buffer); g_rec_mutex_lock (dev->lock); ++dev->vid->queued_frames; g_rec_mutex_unlock (dev->lock); drop_buffer = !dev->vid->running; if (drop_buffer) { GST_INFO_OBJECT (src, "dropping buffer because video recording is not running"); gst_buffer_unref (buffer); } else { g_mutex_lock (&dev->vidsrc->lock); g_queue_push_tail (dev->vidsrc->queue, buffer); g_cond_signal (&dev->vidsrc->cond); g_mutex_unlock (&dev->vidsrc->lock); } unlock_and_out: /* in case stop_video_recording() is waiting for us */ g_cond_signal (&dev->vid->cond); g_mutex_unlock (&dev->vid->lock); }
static void gst_droidcamsrc_dev_compressed_image_callback (void *user, DroidMediaData * mem) { GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user; GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad)); size_t size = mem->size; void *data = mem->data; GstBuffer *buffer; GstTagList *tags; GstEvent *event = NULL; void *d; GST_DEBUG_OBJECT (src, "dev compressed image callback"); if (!data) { GST_ERROR_OBJECT (src, "invalid memory from camera hal"); return; } /* TODO: research a way to get rid of the memcpy */ d = g_malloc (size); memcpy (d, data, size); buffer = gst_buffer_new_wrapped (d, size); if (!dev->img->image_preview_sent) { gst_droidcamsrc_post_message (src, gst_structure_new_empty (GST_DROIDCAMSRC_CAPTURE_END)); /* TODO: generate and send preview if we don't get it from HAL */ dev->img->image_preview_sent = TRUE; } gst_droidcamsrc_timestamp (src, buffer); tags = gst_droidcamsrc_exif_tags_from_jpeg_data (d, size); if (tags) { GST_INFO_OBJECT (src, "pushing tags %" GST_PTR_FORMAT, tags); event = gst_event_new_tag (tags); } g_mutex_lock (&dev->imgsrc->lock); // TODO: get the correct lock if (event) { src->imgsrc->pending_events = g_list_append (src->imgsrc->pending_events, event); } g_queue_push_tail (dev->imgsrc->queue, buffer); g_cond_signal (&dev->imgsrc->cond); g_mutex_unlock (&dev->imgsrc->lock); /* we need to start restart the preview * android demands this but GStreamer does not know about it. */ g_rec_mutex_lock (dev->lock); dev->running = FALSE; g_rec_mutex_unlock (dev->lock); gst_droidcamsrc_dev_start (dev, TRUE); g_mutex_lock (&src->capture_lock); --src->captures; g_mutex_unlock (&src->capture_lock); g_object_notify (G_OBJECT (src), "ready-for-capture"); }