dual-stream: implement second stream of /dev/video1
authorWind Yuan <feng.yuan@intel.com>
Tue, 2 Apr 2013 05:27:15 +0000 (13:27 +0800)
committerMarko Ollonen <marko.ollonen@ixonos.com>
Sun, 7 Apr 2013 09:46:40 +0000 (12:46 +0300)
Change-Id: I822526d1383e33a8aa805d1d48ec61a026fee063

gst-libs/gst/camera/gstmfldcamerasrc.c
gst-libs/gst/camera/gstmfldcamerasrc.h
gst/mfldv4l2cam/v4l2camsrc_calls.c
gst/mfldv4l2cam/v4l2camsrc_calls.h

index 995b88a..2e9cc46 100644 (file)
@@ -299,9 +299,9 @@ static gboolean gst_camerasrc_query (GstBaseSrc * bsrc, GstQuery * query);
 
 static GstFlowReturn gst_camerasrc_create (GstPushSrc * src, GstBuffer ** out);
 
-static void gst_camerasrc_fixate (GstBaseSrc * basesrc, GstCaps * caps);
+static void gst_camerasrc_fixate_main (GstBaseSrc *basesrc, GstCaps * caps);
 
-static gboolean gst_camerasrc_negotiate (GstBaseSrc * basesrc);
+static gboolean gst_camerasrc_negotiate_main (GstBaseSrc *basesrc);
 
 static void gst_camerasrc_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
@@ -322,6 +322,17 @@ static gboolean gst_camerasrc_send_event (GstElement * element,
 
 static void gst_camerasrc_update_max_zoom (GstCameraSrc * camerasrc);
 
+static gboolean gst_camerasrc_get_caps_info (GstCameraSrc * camerasrc,
+    GstCaps * caps, guint32 * four_cc, guint * w, guint * h,
+    guint * fps_n, guint * fps_d, guint * size);
+
+static gboolean gst_camerasrc_negotiate (GstCameraSrc *src, GstPad *pad);
+
+static void gst_camerasrc_fixate (GstCameraSrc *src, GstCaps * caps);
+
+static void
+gst_camerasrc_apply_timestamp (GstCameraSrc * camerasrc, GstBuffer * buf);
+
 /*
  */
 static void
@@ -416,6 +427,211 @@ int gst_camerasrc_send_af_status(GstCameraSrc *camsrc , int state)
 
   return 0;
 }
+
+static gboolean
+gst_camerasrc_second_pad_check_get_range(GstPad *pad)
+{
+  return FALSE;
+}
+
+static gboolean
+gst_camerasrc_second_pad_activate_pull(GstPad *pad, gboolean active)
+{
+  return FALSE;
+}
+
+static gboolean
+ensure_second_stream_started(GstCameraSrc *src)
+{
+  GstCameraSrcClass *kclass;
+  gboolean ret;
+
+  if (src->second_started)
+    return TRUE;
+
+  kclass = GST_CAMERA_SRC_GET_CLASS(src);
+
+  /* wait until first(main) stream started */
+  g_mutex_lock(src->second_lock);
+  while(!src->first_started && !src->second_stoped)
+    g_cond_wait(src->first_done_cond, src->second_lock);
+  g_mutex_unlock(src->second_lock);
+
+  if (src->second_stoped)
+    return FALSE;
+
+  ret = kclass->start_second(src, src->second_caps);
+  if (!ret)
+    goto failed;
+
+  src->second_started = TRUE;
+  return TRUE;
+
+failed:
+  return FALSE;
+}
+
+static void
+_second_pad_loop(GstPad *pad)
+{
+  GstCameraSrc *src = GST_CAMERA_SRC(GST_OBJECT_PARENT(pad));
+  GstCameraSrcClass *kclass = GST_CAMERA_SRC_GET_CLASS(src);
+  GstBuffer *buf = NULL;
+  GstFlowReturn ret;
+
+  if(!ensure_second_stream_started(src))
+    goto stop;
+
+  ret = kclass->create_second_buffer(src, &buf);
+
+  if (ret != GST_FLOW_OK || !buf) {
+    GST_WARNING_OBJECT(src, "get second buffer failed.");
+    return;
+  }
+
+  if (!GST_BUFFER_CAPS(buf))
+    gst_buffer_set_caps (buf, src->second_caps);
+
+  if (GST_BUFFER_TIMESTAMP (buf) == GST_CLOCK_TIME_NONE) {
+    gst_camerasrc_apply_timestamp (src, buf);
+  }
+
+  ret = gst_pad_push (pad, buf);
+  if (ret != GST_FLOW_OK) {
+    GST_WARNING_OBJECT(src, "push second buffer failed.");
+    goto stop;
+  }
+  return;
+
+stop:
+  /* TODO, may need stop whole pipeline  or send signal */
+  GST_WARNING_OBJECT(src, "second pad need to stop");
+}
+
+static gboolean
+gst_camerasrc_second_pad_activate_push(GstPad *pad, gboolean active)
+{
+  GstCameraSrc *src;
+  GstCameraSrcClass *kclass;
+  gboolean ret = TRUE;
+
+  src = GST_CAMERA_SRC(GST_OBJECT_PARENT(pad));
+  kclass = GST_CAMERA_SRC_GET_CLASS(src);
+
+  g_return_val_if_fail(kclass->open_second, FALSE);
+
+  if (active) {
+    if (!GST_PAD_IS_LINKED(pad))
+      return TRUE; /* do nothing to make main pad works */
+
+    ret = kclass->open_second(src);
+    if (!ret)
+      goto failed;
+
+    ret = gst_camerasrc_negotiate(src, pad);
+    if (!ret)
+      goto failed;
+
+    ret = gst_pad_start_task (pad, (GstTaskFunction)_second_pad_loop, pad);
+  }
+  else {
+    g_mutex_lock(src->second_lock);
+    src->second_stoped = TRUE;
+    g_cond_signal(src->first_done_cond);
+    g_mutex_unlock(src->second_lock);
+
+    gst_pad_stop_task (pad);
+    src->second_started = FALSE;
+
+    if (kclass->close_second)
+      ret = kclass->close_second(src);
+  }
+  return ret;
+
+failed:
+  GST_WARNING_OBJECT(src, "%s second stream failed", (active? "start" : "stop"));
+  return FALSE;
+}
+
+static GstCaps*
+gst_camerasrc_second_pad_getcaps(GstPad *pad)
+{
+  return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+}
+
+static gboolean
+gst_camerasrc_second_pad_setcaps(GstPad *pad, GstCaps *caps)
+{
+  GstCameraSrc *src;
+  GstCameraSrcClass *bclass;
+  guint w = 0, h = 0;
+  guint32 fourcc = 0;
+  guint fps_n, fps_d;
+  guint size;
+  gboolean ret;
+
+  src = GST_CAMERA_SRC(GST_OBJECT_PARENT(pad));
+  bclass = GST_CAMERA_SRC_GET_CLASS(src);
+
+  g_return_val_if_fail(gst_caps_is_fixed(caps), FALSE);
+
+  if (!bclass->is_second_open (src))
+    return FALSE;
+
+  if (!gst_camerasrc_get_caps_info(src, caps, &fourcc, &w, &h, &fps_n,
+          &fps_d, &size)) {
+    GST_DEBUG_OBJECT (src,
+        "second pad can't get capture info from caps %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+
+  if (src->second_caps) {
+    gst_caps_unref(src->second_caps);
+    GST_DEBUG_OBJECT (src,
+        "second pad remove old caps %" GST_PTR_FORMAT, src->second_caps);
+  }
+  src->second_caps = gst_caps_ref(caps);
+
+  ret = bclass->set_second_capture_mode(src);
+  ret = bclass->set_second_capture(src, &fourcc, &w, &h, &fps_n, &fps_d);
+  if (ret) {
+    src->second_w = w;
+    src->second_h = h;
+    src->second_fps_n = fps_n;
+    src->second_fps_d = fps_d;
+    src->second_fourcc = fourcc;
+    src->second_duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
+  } else
+    goto failed;
+
+  return TRUE;
+
+failed:
+  GST_WARNING_OBJECT(src,
+      "set second pad's caps failed, caps %" GST_PTR_FORMAT, caps);
+  return FALSE;
+}
+
+static void
+gst_camerasrc_second_pad_fixate(GstPad *pad, GstCaps *caps)
+{
+  GstCameraSrc *src = GST_CAMERA_SRC(GST_OBJECT_PARENT(pad));
+  gst_camerasrc_fixate(src, caps);
+}
+
+static GstPadLinkReturn
+gst_camerasrc_second_pad_link(GstPad *pad, GstPad *peer)
+{
+  GstCameraSrc *src = GST_CAMERA_SRC(GST_OBJECT_PARENT(pad));
+  GstPad *main_pad = GST_BASE_SRC_PAD(src);
+
+  /* need link src pad first */
+  if (!gst_pad_is_linked(main_pad))
+    return GST_PAD_LINK_REFUSED;
+
+  return GST_PAD_LINK_OK;
+}
+
 /*
  */
 static void
@@ -583,14 +799,22 @@ gst_camerasrc_class_init (GstCameraSrcClass * klass)
   basesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_camerasrc_unlock_stop);
   basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_camerasrc_stop);
   basesrc_class->query = GST_DEBUG_FUNCPTR (gst_camerasrc_query);
-  basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_camerasrc_fixate);
-  basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_camerasrc_negotiate);
+  basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_camerasrc_fixate_main);
+  basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_camerasrc_negotiate_main);
   basesrc_class->event = GST_DEBUG_FUNCPTR (gst_camerasrc_event);
 
   pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_camerasrc_create);
 
   /* Initialize vmethods with default implementations */
   gst_camerasrc_default_functions_init (klass);
+
+  GST_DEBUG_REGISTER_FUNCPTR(gst_camerasrc_second_pad_activate_push);
+  GST_DEBUG_REGISTER_FUNCPTR(gst_camerasrc_second_pad_activate_pull);
+  GST_DEBUG_REGISTER_FUNCPTR(gst_camerasrc_second_pad_check_get_range);
+  GST_DEBUG_REGISTER_FUNCPTR(gst_camerasrc_second_pad_getcaps);
+  GST_DEBUG_REGISTER_FUNCPTR(gst_camerasrc_second_pad_setcaps);
+  GST_DEBUG_REGISTER_FUNCPTR(gst_camerasrc_second_pad_fixate);
+  GST_DEBUG_REGISTER_FUNCPTR(gst_camerasrc_second_pad_link);
 }
 
 /*
@@ -598,6 +822,9 @@ gst_camerasrc_class_init (GstCameraSrcClass * klass)
 static void
 gst_camerasrc_init (GstCameraSrc * camerasrc, GstCameraSrcClass * klass)
 {
+  GstPad *second_pad;
+  GstPadTemplate *pad_template;
+
   /* number of buffers requested */
   camerasrc->always_copy = DEFAULT_PROP_ALWAYS_COPY;
 
@@ -644,6 +871,36 @@ gst_camerasrc_init (GstCameraSrc * camerasrc, GstCameraSrcClass * klass)
 
   camerasrc->requested_af_mode = AF_NONE_REQUESTED;
   camerasrc->maker_note = FALSE;
+
+  /* second pad init */
+  pad_template =
+    gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "second");
+  second_pad = gst_pad_new_from_template (pad_template, "second");
+  gst_pad_set_activatepush_function (second_pad, gst_camerasrc_second_pad_activate_push);
+  gst_pad_set_activatepull_function (second_pad, gst_camerasrc_second_pad_activate_pull);
+  //gst_pad_set_event_function (second_pad, gst_camerasrc_second_pad_event_handler);
+  //gst_pad_set_query_function (second_pad, gst_camerasrc_second_pad_query);
+  gst_pad_set_checkgetrange_function (second_pad, gst_camerasrc_second_pad_check_get_range);
+  //gst_pad_set_getrange_function (second_pad, gst_camerasrc_second_pad_get_range);
+  gst_pad_set_getcaps_function (second_pad, gst_camerasrc_second_pad_getcaps);
+  gst_pad_set_setcaps_function (second_pad, gst_camerasrc_second_pad_setcaps);
+  gst_pad_set_fixatecaps_function (second_pad, gst_camerasrc_second_pad_fixate);
+  //gst_pad_set_link_function (second_pad, gst_camerasrc_second_pad_link);
+
+  GST_CAMERA_SRC_SECOND_PAD(camerasrc) = second_pad;
+  gst_element_add_pad(GST_ELEMENT(camerasrc), second_pad);
+
+  camerasrc->second_w = 0;
+  camerasrc->second_h = 0;
+  camerasrc->second_fps_n = 0;
+  camerasrc->second_fps_d = 0;
+  camerasrc->second_fourcc = 0;
+  camerasrc->second_duration = 0;
+  camerasrc->second_started = FALSE;
+  camerasrc->second_stoped = FALSE;
+  camerasrc->second_lock = g_mutex_new ();
+  camerasrc->first_done_cond = g_cond_new();
+  camerasrc->first_started = FALSE;
 }
 
 /*
@@ -665,6 +922,14 @@ gst_camerasrc_dispose (GObject * object)
     g_mutex_free (camerasrc->af_lock);
     camerasrc->af_lock = NULL;
   }
+  if (camerasrc->second_lock) {
+    g_mutex_free(camerasrc->second_lock);
+    camerasrc->second_lock = NULL;
+  }
+  if (camerasrc->first_done_cond) {
+    g_cond_free(camerasrc->first_done_cond);
+    camerasrc->first_done_cond = NULL;
+  }
   gst_camerasrc_clear_color_channels (camerasrc);
 
   gst_camerasrc_clear_cameracontrol_channels (camerasrc);
@@ -859,13 +1124,13 @@ gst_camerasrc_get_property (GObject * object,
 
 /* this function is a bit of a last resort */
 static void
-gst_camerasrc_fixate (GstBaseSrc * basesrc, GstCaps * caps)
+gst_camerasrc_fixate (GstCameraSrc *src, GstCaps * caps)
 {
   GstStructure *structure;
 
   gint i;
 
-  GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);
+  GST_DEBUG_OBJECT (src, "fixating caps %" GST_PTR_FORMAT, caps);
 
   for (i = 0; i < gst_caps_get_size (caps); ++i) {
     const GValue *v;
@@ -900,13 +1165,19 @@ gst_camerasrc_fixate (GstBaseSrc * basesrc, GstCaps * caps)
     }
   }
 
-  GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps);
+  GST_DEBUG_OBJECT (src, "fixated caps %" GST_PTR_FORMAT, caps);
+}
+
+static void
+gst_camerasrc_fixate_main (GstBaseSrc *basesrc, GstCaps * caps)
+{
+  gst_camerasrc_fixate(GST_CAMERA_SRC_CAST(basesrc), caps);
 }
 
 /*
  */
 static gboolean
-gst_camerasrc_negotiate (GstBaseSrc * basesrc)
+gst_camerasrc_negotiate (GstCameraSrc *src, GstPad *pad)
 {
   GstCaps *thiscaps;
 
@@ -917,16 +1188,16 @@ gst_camerasrc_negotiate (GstBaseSrc * basesrc)
   gboolean result = FALSE;
 
   /* first see what is possible on our source pad */
-  thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
-  GST_DEBUG_OBJECT (basesrc, "caps of src suppressed on DEBUG (>= 5 to see)");
-  GST_LOG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
+  thiscaps = gst_pad_get_caps (pad);
+  GST_DEBUG_OBJECT (src, "caps of src suppressed on DEBUG (>= 5 to see)");
+  GST_LOG_OBJECT (src, "caps of src: %" GST_PTR_FORMAT, thiscaps);
   /* nothing or anything is allowed, we're done */
   if (thiscaps == NULL || gst_caps_is_any (thiscaps))
     goto no_nego_needed;
 
   /* get the peer caps */
-  peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
-  GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
+  peercaps = gst_pad_peer_get_caps (pad);
+  GST_DEBUG_OBJECT (src, "caps of peer: %" GST_PTR_FORMAT, peercaps);
   if (peercaps && !gst_caps_is_any (peercaps)) {
     GstCaps *icaps = NULL;
     int i;
@@ -936,7 +1207,7 @@ gst_camerasrc_negotiate (GstBaseSrc * basesrc)
       /* get intersection */
       GstCaps *ipcaps = gst_caps_copy_nth (peercaps, i);
 
-      GST_DEBUG_OBJECT (basesrc, "peer: %" GST_PTR_FORMAT, ipcaps);
+      GST_DEBUG_OBJECT (src, "peer: %" GST_PTR_FORMAT, ipcaps);
 
       icaps = gst_caps_intersect (thiscaps, ipcaps);
       gst_caps_unref (ipcaps);
@@ -948,7 +1219,7 @@ gst_camerasrc_negotiate (GstBaseSrc * basesrc)
       icaps = NULL;
     }
 
-    GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, icaps);
+    GST_DEBUG_OBJECT (src, "intersect: %" GST_PTR_FORMAT, icaps);
     if (icaps) {
       /* If there are multiple intersections pick the one with the smallest
        * resolution strictly bigger then the first peer caps */
@@ -1008,8 +1279,8 @@ gst_camerasrc_negotiate (GstBaseSrc * basesrc)
             gst_structure_set (s, "row-stride", GST_TYPE_INT_RANGE, 0, G_MAXINT, NULL);
         }
       }
-      gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
-      GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
+      gst_pad_fixate_caps (pad, caps);
+      GST_DEBUG_OBJECT (src, "fixated to: %" GST_PTR_FORMAT, caps);
 
       if (gst_caps_is_any (caps)) {
         /* hmm, still anything, so element can do anything and
@@ -1017,8 +1288,8 @@ gst_camerasrc_negotiate (GstBaseSrc * basesrc)
         result = TRUE;
       } else if (gst_caps_is_fixed (caps)) {
         /* yay, fixed caps, use those then */
-        result = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
-        GST_DEBUG_OBJECT (basesrc, "Set caps returned: %d", result);
+        result = gst_pad_set_caps (pad, caps);
+        GST_DEBUG_OBJECT (src, "Set caps returned: %d", result);
       }
     }
     gst_caps_unref (caps);
@@ -1027,13 +1298,23 @@ gst_camerasrc_negotiate (GstBaseSrc * basesrc)
 
 no_nego_needed:
   {
-    GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
+    GST_DEBUG_OBJECT (src, "no negotiation needed");
     if (thiscaps)
       gst_caps_unref (thiscaps);
     return TRUE;
   }
 }
 
+static gboolean
+gst_camerasrc_negotiate_main (GstBaseSrc *basesrc)
+{
+  GstPad *pad = GST_BASE_SRC_PAD (basesrc);
+  GstCameraSrc *src = GST_CAMERA_SRC_CAST(basesrc);
+
+  g_return_val_if_fail(pad, FALSE);
+
+  return gst_camerasrc_negotiate(src, pad);
+}
 
 /*
  */
@@ -1374,6 +1655,11 @@ gst_camerasrc_init_from_caps (GstCameraSrc * camerasrc, GstCaps * caps)
         GST_TIME_ARGS (camerasrc->duration));
 
 //      camerasrc->frame_byte_size = size;
+
+    g_mutex_lock(camerasrc->second_lock);
+    camerasrc->first_started = TRUE;
+    g_cond_signal(camerasrc->first_done_cond);
+    g_mutex_unlock(camerasrc->second_lock);
   }
 
   return ret;
@@ -1480,6 +1766,10 @@ gst_camerasrc_stop (GstBaseSrc * src)
 
   camerasrc->photo_capture_phase = GST_CAMERA_VIEWFINDER;
 
+  g_mutex_lock(camerasrc->second_lock);
+  camerasrc->first_started = FALSE;
+  g_mutex_unlock(camerasrc->second_lock);
+
   return TRUE;
 }
 
index 0d467d4..2632fe3 100644 (file)
@@ -187,6 +187,7 @@ typedef struct
   GstCameraSrc3a_window aaa_window;
 } GstCameraControlInt;
 
+#define GST_CAMERA_SRC_SECOND_PAD(obj)     (GST_CAMERA_SRC_CAST(obj)->second_pad)
 
 /**
  * GstCameraSrc:
@@ -247,8 +248,21 @@ struct _GstCameraSrc {
   guint8 requested_af_mode;
   gboolean     maker_note;
   gboolean enable_torch;
-};
 
+  /* Private: second pad*/
+  GstPad  *second_pad;
+  GstCaps *second_caps;
+  gboolean second_started;
+  gboolean second_stoped;
+  /* sync up 1st and 2nd streams */
+  GMutex  *second_lock;
+  GCond   *first_done_cond;
+  gboolean first_started;
+  guint   second_w, second_h;    /* second stream capture frame size */
+  guint   second_fps_n, second_fps_d; /* second stream framerate if device is open */
+  guint32 second_fourcc;         /* second stream color format */
+  GstClockTime second_duration;  /* second stream duration of one frame */
+};
 
 /**
  * GstCameraSrcClass:
@@ -334,6 +348,23 @@ struct _GstCameraSrcClass
 
   gboolean   (*event)           (GstCameraSrc *camsrc, GstEvent *event);
 
+  /* second pad functions */
+  /* from active push */
+  gboolean (*open_second)       (GstCameraSrc *camsrc);
+  gboolean (*is_second_open)    (GstCameraSrc *camsrc);
+  gboolean (*close_second)      (GstCameraSrc *camsrc);
+
+  /* from task loop */
+  GstFlowReturn (*create_second_buffer) (GstCameraSrc *camsrc, GstBuffer **buf);
+
+  /* from set caps */
+  gboolean (*set_second_capture_mode) (GstCameraSrc *camsrc);
+  gboolean (*set_second_capture) (GstCameraSrc *camsrc,
+                                  guint32 *pixelformat,
+                                  guint *width, guint32 *height,
+                                  guint *fps_n, guint *fps_d);
+  gboolean (*start_second)       (GstCameraSrc *camsrc, GstCaps *caps);
+
   /* FORMER DRIVER-API */
 
   GstPhotoCaps
index d4e673c..18d3551 100644 (file)
@@ -52,6 +52,8 @@
 GST_DEBUG_CATEGORY_EXTERN (gst_v4l2camsrc_debug);
 #define GST_CAT_DEFAULT gst_v4l2camsrc_debug
 
+#define GST_V4L2CAMSRC_SECOND_VIDEO_DEFAULT_NAME "/dev/video1"
+
 extern guint gst_camerasrc_signals[CAMERA_IN_LAST_SIGNAL];
 
 static const gint gst_v4l2camsrc_capture_map[] = {
@@ -235,16 +237,17 @@ gst_v4l2camsrc_buffer_get_type (void)
 
 static GstV4l2Buffer *
 gst_v4l2camsrc_buffer_new (GstMFLDV4l2CamSrcBufferPool * pool,
-    GstCameraSrc * camsrc, guint index, GstCaps * caps)
+    GstMFLDV4l2CamSrc *v4l2camsrc, guint index, GstCaps * caps,
+    gboolean use_mmap, gboolean is_second, guint frame_byte_size,
+    GstPad *pad)
 {
-  GstMFLDV4l2CamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
   GstV4l2Buffer *ret = NULL;
   GstFlowReturn flow_ret;
   GstBuffer *buf_cap_signal2 = NULL;      /*output main buffer for capture signal*/
   struct v4l2_buffer *vbuffer;
 
   ret = (GstV4l2Buffer *) gst_mini_object_new (GST_TYPE_V4L2CAMSRC_BUFFER);
-  ret->use_mmap = v4l2camsrc->use_mmap;
+  ret->use_mmap = use_mmap;
   vbuffer = ret->vbuffer = g_new0 (struct v4l2_buffer, 1);
   GST_LOG ("creating buffer %u, %p in pool %p", index, ret, pool);
   ret->pool =
@@ -254,18 +257,18 @@ gst_v4l2camsrc_buffer_new (GstMFLDV4l2CamSrcBufferPool * pool,
   vbuffer->index = index;
   vbuffer->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
-  if (v4l2camsrc->use_mmap)
+  if (use_mmap)
     vbuffer->memory = V4L2_MEMORY_MMAP;
   else
     vbuffer->memory = V4L2_MEMORY_USERPTR;
 
-  vbuffer->length = v4l2camsrc->frame_byte_size;
+  vbuffer->length = frame_byte_size;
   ret->gbuffer = NULL;
 
   if (ioctl (pool->video_fd, VIDIOC_QUERYBUF, vbuffer) < 0)
     goto querybuf_failed;
 
-  if (v4l2camsrc->use_mmap) {
+  if (use_mmap) {
     void *data;
     data = (guint8 *) mmap (0, vbuffer->length,
         PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, vbuffer->m.offset);
@@ -274,7 +277,7 @@ gst_v4l2camsrc_buffer_new (GstMFLDV4l2CamSrcBufferPool * pool,
     GST_BUFFER_DATA (ret) = (guint8 *) data;
   } else {
 
-    if (v4l2camsrc->capture_mode == GST_CAMERA_SRC_CAPTURE_MODE_STILL) {
+    if (!is_second && v4l2camsrc->capture_mode == GST_CAMERA_SRC_CAPTURE_MODE_STILL) {
 
         /*call signal*/
         /* alloc buffer for capture callback */
@@ -288,8 +291,8 @@ gst_v4l2camsrc_buffer_new (GstMFLDV4l2CamSrcBufferPool * pool,
           "height", G_TYPE_INT,v4l2camsrc->capture_h,
           NULL);
 
-      GST_LOG_OBJECT (camsrc, "CALL: usrptr callback");
-      g_signal_emit( G_OBJECT (camsrc),
+      GST_LOG_OBJECT (v4l2camsrc, "CALL: usrptr callback");
+      g_signal_emit( G_OBJECT (v4l2camsrc),
           gst_camerasrc_signals[CAMERA_IN_SIGNAL_STILL_USRPTR_BUFFER],
           0,
           buf_cap_signal2);
@@ -297,19 +300,19 @@ gst_v4l2camsrc_buffer_new (GstMFLDV4l2CamSrcBufferPool * pool,
       if (GST_BUFFER_DATA(buf_cap_signal2) == NULL)
         goto usrptr_alloc_failed;
 
-      GST_LOG_OBJECT (camsrc, "RETURN: usrptr callback: buf=%p, size=%d",
+      GST_LOG_OBJECT (v4l2camsrc, "RETURN: usrptr callback: buf=%p, size=%d",
           GST_BUFFER_DATA(buf_cap_signal2), GST_BUFFER_SIZE(buf_cap_signal2));
       GST_BUFFER_DATA (ret) = GST_BUFFER_DATA(buf_cap_signal2);
       gst_buffer_unref(buf_cap_signal2);
 
     } else {
-      if (gst_pad_is_linked (GST_BASE_SRC_PAD (v4l2camsrc))) {
-        GST_LOG ("using pad_alloc, size=%d", v4l2camsrc->frame_byte_size);
+      if (gst_pad_is_linked (pad)) {
+        GST_LOG ("using pad_alloc, size=%d", frame_byte_size);
         GST_LOG ("ALLOC CAPS: %" GST_PTR_FORMAT, caps);
 
         flow_ret =
-            gst_pad_alloc_buffer_and_set_caps (GST_BASE_SRC_PAD (v4l2camsrc), 0LL,
-            v4l2camsrc->frame_byte_size, caps, &ret->gbuffer);
+            gst_pad_alloc_buffer_and_set_caps (pad, 0LL,
+            frame_byte_size, caps, &ret->gbuffer);
         if (flow_ret != GST_FLOW_OK)
           goto pad_alloc_failed;
         GST_BUFFER_DATA (ret) = ret->gbuffer->data;
@@ -325,20 +328,20 @@ gst_v4l2camsrc_buffer_new (GstMFLDV4l2CamSrcBufferPool * pool,
     }
   }
 
-  GST_BUFFER_SIZE (ret) = v4l2camsrc->frame_byte_size;
+  GST_BUFFER_SIZE (ret) = frame_byte_size;
   GST_BUFFER_FLAG_SET (ret, GST_BUFFER_FLAG_READONLY);
   gst_buffer_set_caps (GST_BUFFER (ret), caps);
 
 #ifdef USE_MLOCK
   GST_DEBUG ("mlocking buffer data");
-  if (mlock ((void *) GST_BUFFER_DATA (ret), v4l2camsrc->frame_byte_size) == -1)
+  if (mlock ((void *) GST_BUFFER_DATA (ret), frame_byte_size) == -1)
     goto mlock_failed;
 #endif
 
   /* mlocking succeeded, now we can set the pointer to vbuffer. The existence
    * of this pointer will be used later to determine if the munlock() is
    * needed */
-  if (!v4l2camsrc->use_mmap)
+  if (!use_mmap)
     vbuffer->m.userptr = (unsigned int) GST_BUFFER_DATA (ret);
 
 
@@ -453,6 +456,7 @@ gst_v4l2camsrc_buffer_pool_init (GstMFLDV4l2CamSrcBufferPool * pool,
   pool->num_live_buffers = 0;
   pool->data_cond = g_cond_new ();
   pool->is_vaapi_sharing = FALSE;
+  pool->frame_byte_size = 0;
 }
 
 /*
@@ -498,10 +502,11 @@ gst_v4l2camsrc_buffer_pool_get_type (void)
 /*
  */
 static GstMFLDV4l2CamSrcBufferPool *
-gst_v4l2camsrc_buffer_pool_new (GstCameraSrc * camsrc, gint fd,
-    GstCaps * caps)
+gst_v4l2camsrc_buffer_pool_new (GstMFLDV4l2CamSrc *v4l2camsrc, gint fd,
+    guint buf_count, GstCaps * caps,
+    gboolean use_mmap, gboolean is_second,
+    guint frame_byte_size, GstPad *pad)
 {
-  GstMFLDV4l2CamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
   GstMFLDV4l2CamSrcBufferPool *pool;
   gint n;
 
@@ -516,12 +521,15 @@ gst_v4l2camsrc_buffer_pool_new (GstCameraSrc * camsrc, gint fd,
   if (structure && gst_structure_has_name(structure, "video/x-vaapi-sharing"))
     pool->is_vaapi_sharing = TRUE;
 
-  pool->buffer_count = v4l2camsrc->num_buffers;
+  pool->buffer_count = buf_count;
   pool->buffers = g_new0 (GstV4l2Buffer *, pool->buffer_count);
   pool->queued = g_new0 (guint, pool->buffer_count);
+  pool->frame_byte_size = frame_byte_size;
 
   for (n = 0; n < pool->buffer_count; n++) {
-    pool->buffers[n] = gst_v4l2camsrc_buffer_new (pool, camsrc, n, caps);
+    pool->buffers[n] = gst_v4l2camsrc_buffer_new (
+                           pool, v4l2camsrc, n, caps,
+                           use_mmap, is_second, frame_byte_size, pad);
     GST_LOG ("buffer ref is %d", GST_MINI_OBJECT_REFCOUNT (pool->buffers[n]));
     if (!pool->buffers[n])
       goto buffer_new_failed;
@@ -589,7 +597,7 @@ queue_failed:
         ("Could not enqueue buffers in device '%s'.",
             v4l2camsrc->videodev),
         ("enqueing buffer %d/%d failed: %s",
-            n, v4l2camsrc->num_buffers, g_strerror (errno)));
+            n, pool->buffer_count, g_strerror (errno)));
     g_mutex_unlock (pool->lock);
     return FALSE;
   }
@@ -600,7 +608,7 @@ queue_failed:
  * when they are finalized, so there is no need to wait for them separately */
 static gboolean
 gst_v4l2_buffer_pool_update (GstMFLDV4l2CamSrcBufferPool * pool,
-    GstMFLDV4l2CamSrc * v4l2camsrc)
+    GstMFLDV4l2CamSrc * v4l2camsrc, guint num_buffers)
 {
   gint n;
   gint ref = 0;
@@ -615,14 +623,14 @@ gst_v4l2_buffer_pool_update (GstMFLDV4l2CamSrcBufferPool * pool,
   }
 
   /* if all the buffers are dequeued, wait */
-  if (ref == v4l2camsrc->num_buffers) {
+  if (ref == num_buffers) {
     GST_LOG ("no free buffers available");
     g_cond_wait (pool->data_cond, pool->lock);
   }
 
   g_mutex_unlock (pool->lock);
 
-  return (ref != v4l2camsrc->num_buffers) ? TRUE : FALSE;
+  return (ref != num_buffers) ? TRUE : FALSE;
 }
 
 /*
@@ -657,7 +665,7 @@ gst_v4l2camsrc_buffer_pool_destroy (GstMFLDV4l2CamSrcBufferPool * pool,
       if (pool->buffers[n].m.userptr) {
         GST_DEBUG ("munlocking buffer data");
         munlock ((void *) pool->buffers[n].m.userptr,
-            v4l2camsrc->frame_byte_size);
+            pool->frame_byte_size);
       }
 #endif
       /* we own the ref if the buffer is in pool->buffers; drop it. */
@@ -2185,7 +2193,7 @@ gst_v4l2camsrc_grab_frame (GstCameraSrc * camsrc, GstBuffer ** buf,
 
   /* wait if all buffers are DQBuf */
   g_mutex_lock (v4l2camsrc->device_mutex);
-  gst_v4l2_buffer_pool_update (v4l2camsrc->pool, v4l2camsrc);
+  gst_v4l2_buffer_pool_update (v4l2camsrc->pool, v4l2camsrc, v4l2camsrc->num_buffers);
   g_mutex_unlock (v4l2camsrc->device_mutex);
 
   memset (&buffer, 0x00, sizeof (buffer));
@@ -2640,7 +2648,10 @@ gst_v4l2camsrc_capture_start (GstCameraSrc * camsrc, GstCaps * caps)
   GST_LOG_OBJECT (v4l2camsrc, "initiating buffer pool");
 
   if (!(v4l2camsrc->pool =
-          gst_v4l2camsrc_buffer_pool_new (camsrc, fd, caps)))
+       gst_v4l2camsrc_buffer_pool_new (v4l2camsrc, fd,
+           v4l2camsrc->num_buffers, caps,
+           v4l2camsrc->use_mmap, FALSE,
+           v4l2camsrc->frame_byte_size, GST_BASE_SRC_PAD(v4l2camsrc))))
     goto buffer_pool_new_failed;
 
   GST_INFO_OBJECT (v4l2camsrc, "capturing buffers");
@@ -3850,3 +3861,353 @@ gst_v4l2camsrc_libmfldcam_deinit (GstMFLDV4l2CamSrc * v4l2camsrc)
   v4l2camsrc->is_open = FALSE;
   return TRUE;
 }
+
+gboolean
+gst_v4l2camsrc_open_second(GstCameraSrc *base)
+{
+  struct stat st;
+  GstPollFD pollfd = GST_POLL_FD_INIT;
+  const gchar *video_name = GST_V4L2CAMSRC_SECOND_VIDEO_DEFAULT_NAME;
+  GstMFLDV4l2CamSrc *src = GST_V4L2CAMSRC_CAST (base);
+
+  GST_DEBUG_OBJECT (src, "Trying to open %s", video_name);
+
+  if (GST_V4L2CAMSRC_IS_SECOND_OPEN(src)) {
+    GST_WARNING("second video already opened");
+    return FALSE;
+  }
+
+  /* check if it is a device */
+  if (stat (video_name, &st) == -1)
+    goto failed;
+
+  if (!S_ISCHR (st.st_mode))
+    goto failed;
+
+  /* open the device */
+  src->second_video_fd =
+      open (video_name, O_RDWR /* | O_NONBLOCK */ );
+
+  if (!GST_V4L2CAMSRC_IS_SECOND_OPEN (src))
+    goto failed;
+
+  pollfd.fd = src->second_video_fd;
+  gst_poll_add_fd (src->second_poll, &pollfd);
+  gst_poll_fd_ctl_read (src->second_poll, &pollfd, TRUE);
+  return TRUE;
+
+failed:
+  GST_WARNING("open second video %s failed", video_name);
+
+
+}
+
+gboolean
+gst_v4l2camsrc_close_second(GstCameraSrc *base)
+{
+  GstMFLDV4l2CamSrc *src = GST_V4L2CAMSRC_CAST (base);
+  const gchar *video_name = GST_V4L2CAMSRC_SECOND_VIDEO_DEFAULT_NAME;
+
+  GstPollFD pollfd = GST_POLL_FD_INIT;
+
+  GST_DEBUG_OBJECT (src, "Trying to close %s", video_name);
+
+  if (!GST_V4L2CAMSRC_IS_SECOND_OPEN(src)) {
+    return TRUE;
+  }
+
+  close (src->second_video_fd);
+  pollfd.fd = src->second_video_fd;
+  gst_poll_remove_fd (src->second_poll, &pollfd);
+  src->second_video_fd = -1;
+
+  return TRUE;
+}
+
+gboolean
+gst_v4l2camsrc_set_second_capture_mode(GstCameraSrc *base)
+{
+  GstMFLDV4l2CamSrc *src = GST_V4L2CAMSRC_CAST (base);
+  struct v4l2_streamparm parm;
+  guint fd = src->second_video_fd;
+  int ret = 0;
+
+  memset(&parm, 0, sizeof(parm));
+  parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+  g_mutex_lock (src->device_mutex);
+  if ((ret = ioctl(fd, VIDIOC_G_PARM, &parm)) < 0) {
+    GST_DEBUG_OBJECT(src, "Unable to get second video param: %s (%d).",
+        strerror(errno), errno);
+    goto done;
+  }
+  parm.parm.capture.capturemode = CI_MODE_VIDEO;
+
+  if ((ret = ioctl (fd, VIDIOC_S_PARM, &parm)) < 0) {
+    GST_DEBUG_OBJECT(src, "Unable to set second video param: %s (%d).",
+        strerror(errno), errno);
+  }
+
+done:
+  g_mutex_unlock (src->device_mutex);
+  return (ret == 0);
+}
+
+gboolean
+gst_v4l2camsrc_set_second_capture(
+    GstCameraSrc *base,
+    guint32 *pixelformat,
+    guint *width, guint32 *height,
+    guint *fps_n, guint *fps_d
+)
+{
+  GstMFLDV4l2CamSrc *src = GST_V4L2CAMSRC_CAST (base);
+  gint fd = src->second_video_fd;
+  struct v4l2_format format;
+  struct v4l2_streamparm stream;
+
+  GST_DEBUG_OBJECT(src, "try set second capture");
+
+  memset (&format, 0, sizeof (struct v4l2_format));
+  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+  if (ioctl (fd, VIDIOC_G_FMT, &format) < 0)
+    goto failed;
+
+  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  format.fmt.pix.width = *width;
+  format.fmt.pix.height = *height;
+  format.fmt.pix.pixelformat = *pixelformat;
+  format.fmt.pix.field = V4L2_FIELD_ANY;
+
+  if (ioctl (fd, VIDIOC_S_FMT, &format) < 0) {
+    if (errno != EINVAL)
+      goto failed;
+
+    /* try again with progressive video */
+    format.fmt.pix.width = *width;
+    format.fmt.pix.height = *height;
+    format.fmt.pix.pixelformat = *pixelformat;
+    format.fmt.pix.field = V4L2_FIELD_NONE;
+    if (ioctl (fd, VIDIOC_S_FMT, &format) < 0)
+      goto failed;
+  }
+
+  if (format.fmt.pix.width != *width || format.fmt.pix.height != *height
+      || format.fmt.pix.pixelformat != *pixelformat)
+    goto invalid_info;
+
+  memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
+  stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  if (ioctl (fd, VIDIOC_G_PARM, &stream) < 0) {
+    GST_DEBUG_OBJECT(src,"second video get param failed");
+    goto done;
+  }
+
+  if (fps_n == NULL || fps_d == NULL) {
+    goto done;
+  }
+
+  /* Note: V4L2 provides the frame interval, we have the frame rate */
+  if (stream.parm.capture.timeperframe.denominator &&
+      fractions_are_equal (stream.parm.capture.timeperframe.numerator,
+          stream.parm.capture.timeperframe.denominator, *fps_d, *fps_n)) {
+    goto done;
+  }
+
+  /* We want to change the frame rate, so check whether we can. Some cheap USB
+   * cameras don't have the capability */
+  if ((stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
+    GST_DEBUG_OBJECT (src, "Not setting framerate (second video not supported)");
+    goto done;
+  }
+
+  stream.parm.capture.timeperframe.numerator = *fps_d;
+  stream.parm.capture.timeperframe.denominator = *fps_n;
+
+  /* some cheap USB cam's won't accept any change */
+  if (ioctl (fd, VIDIOC_S_PARM, &stream) < 0) {
+    GST_WARNING_OBJECT (src,
+        "Second video input device did not accept new frame rate setting");
+    goto done;
+  }
+
+done:
+  src->second_frame_byte_size = gst_v4l2camsrc_get_frame_size (*pixelformat,
+      width, height);
+  return TRUE;
+
+invalid_info:
+  GST_ERROR_OBJECT (src,
+      "tried to set format:%" GST_FOURCC_FORMAT " size: %dx%d, "
+      "but failed and device returned format:%" GST_FOURCC_FORMAT "size: %dx%d",
+      GST_FOURCC_ARGS (*pixelformat), *width, *height,
+      GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
+      format.fmt.pix.width,
+      format.fmt.pix.height);
+
+failed:
+  GST_WARNING_OBJECT(src, "set second capture failed");
+  return FALSE;
+}
+
+gboolean
+gst_v4l2camsrc_start_second(GstCameraSrc *base, GstCaps *caps)
+{
+  GstMFLDV4l2CamSrc *src = GST_V4L2CAMSRC_CAST (base);
+  gint fd = src->second_video_fd;
+  struct v4l2_requestbuffers breq;
+  gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+  memset (&breq, 0, sizeof (breq));
+  breq.count = src->second_num_buffers;
+  breq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  //if (src->use_mmap)
+  //  breq.memory = V4L2_MEMORY_MMAP;
+  //else
+    breq.memory = V4L2_MEMORY_USERPTR;
+
+  if (ioctl (fd, VIDIOC_REQBUFS, &breq) < 0)
+    goto failed;
+
+  GST_DEBUG_OBJECT(src,
+      "Second video request buffer, count:%d, type:%d, memory:%d",
+      breq.count, breq.type, breq.memory);
+
+  if (breq.count < GST_V4L2CAMSRC_MIN_BUFFERS)
+    goto failed;
+
+  if (src->second_num_buffers != breq.count) {
+    GST_WARNING_OBJECT (src, "second video using %u buffers instead", breq.count);
+    src->second_num_buffers = breq.count;
+  }
+
+  /*init second pool*/
+  if (!(src->second_pool =
+          gst_v4l2camsrc_buffer_pool_new (src, fd,
+              src->second_num_buffers, caps,
+              FALSE, TRUE,
+              src->second_frame_byte_size, GST_CAMERA_SRC_SECOND_PAD(src))))
+    goto failed;
+
+  GST_DEBUG_OBJECT (src, "second video capturing buffers");
+
+  if (!gst_v4l2camsrc_buffer_pool_activate (src->second_pool, src))
+    goto failed;
+
+  if (ioctl (fd, VIDIOC_STREAMON, &type) < 0)
+    goto failed;
+
+  GST_DEBUG_OBJECT (src, "second video STREAMON called");
+  return TRUE;
+
+failed:
+  GST_ERROR_OBJECT(src, "second video start failed.");
+  return FALSE;
+}
+
+GstFlowReturn
+gst_v4l2camsrc_create_second_buffer(GstCameraSrc *base, GstBuffer **buf)
+{
+  GstMFLDV4l2CamSrc *src = GST_V4L2CAMSRC_CAST (base);
+  gint fd = src->second_video_fd;
+  struct v4l2_buffer v4l2_buffer;
+  GstV4l2Buffer *pool_buf;
+  guint retry = 5;
+  gint index;
+  gint ret;
+
+  gst_v4l2_buffer_pool_update (src->second_poll, src, src->second_num_buffers);
+
+  for (;;) {
+    ret = gst_poll_wait (src->second_poll, V4L2CAMSRC_POLL_TIMEOUT);
+    if (G_UNLIKELY (ret < 0)) {
+      if (errno == EBUSY)
+        goto failed;
+      if (errno != EAGAIN && errno != EINTR)
+        goto failed;
+    }
+
+    if (G_UNLIKELY (ret == 0)) {
+      goto timeout;
+    }
+    //g_mutex_lock (src->device_mutex);
+    memset(&v4l2_buffer, 0, sizeof(v4l2_buffer));
+       v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       v4l2_buffer.memory = V4L2_MEMORY_USERPTR;
+       ret = ioctl(fd, VIDIOC_DQBUF, &v4l2_buffer);
+    //g_mutex_unlock (src->device_mutex);
+
+    if (ret >= 0)
+      break;
+
+    GST_WARNING_OBJECT (src,
+        "problem grabbing frame %d (ix=%d), trials=%d, pool-ct=%d, buf.flags=%d",
+        v4l2_buffer.sequence, v4l2_buffer.index, retry,
+        GST_MINI_OBJECT_REFCOUNT (src->pool), v4l2_buffer.flags);
+
+    /* if the sync() got interrupted, we can retry */
+    switch (errno) {
+      case EAGAIN:
+        GST_WARNING_OBJECT (src,
+            "Non-blocking I/O has been selected using O_NONBLOCK and"
+            " no buffer was in the outgoing queue. device /dev/video1");
+        break;
+      case EINVAL:
+        goto failed;
+      case ENOMEM:
+        goto failed;
+      case EIO:
+        GST_INFO_OBJECT (src,
+            "VIDIOC_DQBUF failed due to an internal error."
+            " Can also indicate temporary problems like signal loss."
+            " Note the driver might dequeue an (empty) buffer despite"
+            " returning an error, or even stop capturing."
+            " device /dev/video1");
+        /* have we de-queued a buffer ? */
+        break;
+      case EINTR:
+        GST_WARNING_OBJECT (src,
+            "could not sync on a buffer on device /dev/video1");
+        break;
+      default:
+        GST_WARNING_OBJECT (src,
+            "Grabbing frame got interrupted on /dev/video1. No expected reason.");
+        break;
+    }
+
+    if (++retry > 5)
+      goto failed;
+  }
+
+  index = v4l2_buffer.index;
+
+  g_mutex_lock (src->second_pool->lock);
+
+  pool_buf = src->second_pool->buffers[index];
+
+  if (G_UNLIKELY (pool_buf == NULL))
+    goto failed;
+
+  //GST_LOG_OBJECT (src, "grabbed buffer %p at index %d (refct = %d)",
+  //    pool_buffer, index, GST_MINI_OBJECT_REFCOUNT (pool_buffer));
+
+  /* ref the buffer and requeue, when if becomes writable again */
+  src->second_pool->buffers[index] = NULL;
+  src->second_pool->num_live_buffers++;
+  src->second_pool->queued[index] = 0;
+
+  g_mutex_unlock (src->second_pool->lock);
+
+  GST_BUFFER_SIZE (pool_buf) = src->second_frame_byte_size;
+
+  if (src->second_pool->is_vaapi_sharing)
+    GST_BUFFER_DATA(pool_buf) = (void*)((GST_V4L2CAMSRC_BUFFER(pool_buf))->gbuffer);
+  *buf = GST_BUFFER_CAST(pool_buf);
+
+  return GST_FLOW_OK;
+
+timeout:
+failed:
+  return GST_FLOW_ERROR;
+}
\ No newline at end of file
index e20a6ed..70cfcea 100644 (file)
     return FALSE;           \
 }
 
+#define GST_V4L2CAMSRC_IS_SECOND_OPEN(v4l2camsrc) \
+  (v4l2camsrc->second_video_fd != -1)
+
+
 
 #define GST_V4L2CAMSRC_MAX_BUFFERS 16
 #define GST_V4L2CAMSRC_MIN_BUFFERS 1
@@ -138,4 +142,24 @@ gst_v4l2camsrc_libmfldcam_get_makernote (GstMFLDV4l2CamSrc * v4l2camsrc, unsigne
 gboolean
 gst_v4l2camsrc_libmfldcam_get_focus_posi(GstMFLDV4l2CamSrc * v4l2camsrc, unsigned *posi);
 
+gboolean
+gst_v4l2camsrc_open_second(GstCameraSrc *base);
+
+gboolean
+gst_v4l2camsrc_close_second(GstCameraSrc *base);
+
+gboolean
+gst_v4l2camsrc_set_second_capture_mode(GstCameraSrc *base);
+
+gboolean
+gst_v4l2camsrc_set_second_capture(GstCameraSrc *base, guint32 *pixelformat,
+    guint *width, guint32 *height,
+    guint *fps_n, guint *fps_d);
+
+gboolean
+gst_v4l2camsrc_start_second(GstCameraSrc *base, GstCaps *caps);
+
+GstFlowReturn
+gst_v4l2camsrc_create_second_buffer(GstCameraSrc *camsrc, GstBuffer **buf);
+
 #endif /* __V4L2CAMSRC_CALLS_H__ */