From 1adb86a5d6b2f1bb96568f6135e1fdb4d451e4cd Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 12 Jan 2004 02:19:57 +0000 Subject: sys/v4l2/: add norm, channel and frequency properties. Original commit message from CVS: 2004-01-12 Benjamin Otte * sys/v4l2/gstv4l2element.c: (gst_v4l2element_class_init), (gst_v4l2element_dispose), (gst_v4l2element_set_property), (gst_v4l2element_get_property): * sys/v4l2/v4l2_calls.c: (gst_v4l2_set_defaults), (gst_v4l2_open): add norm, channel and frequency properties. * sys/v4l2/gstv4l2tuner.c: fixes for tuner interface changes * sys/v4l2/gstv4l2element.h: * sys/v4l2/gstv4l2src.c: * sys/v4l2/gstv4l2src.h: * sys/v4l2/v4l2src_calls.c: * sys/v4l2/v4l2src_calls.h: rework v4l2src to work with saa1734 cards and allow mmaped buffers. --- sys/v4l2/gstv4l2src.c | 1248 ++++++++++++++++++++++++------------------------- 1 file changed, 621 insertions(+), 627 deletions(-) (limited to 'sys/v4l2/gstv4l2src.c') diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 0c275b2c..edce2091 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -26,6 +26,9 @@ #include "v4l2src_calls.h" #include "gstv4l2tuner.h" +GST_DEBUG_CATEGORY (v4l2src_debug); +#define GST_CAT_DEFAULT v4l2src_debug + /* elementfactory details */ static GstElementDetails gst_v4l2src_details = { "Video (video4linux2) Source", @@ -51,15 +54,50 @@ enum { ARG_USE_FIXED_FPS }; +guint32 gst_v4l2_formats[] = { + /* from Linux 2.6.0 videodev2.h */ + V4L2_PIX_FMT_RGB332, /* 8 RGB-3-3-2 */ + V4L2_PIX_FMT_RGB555, /* 16 RGB-5-5-5 */ + V4L2_PIX_FMT_RGB565, /* 16 RGB-5-6-5 */ + V4L2_PIX_FMT_RGB555X, /* 16 RGB-5-5-5 BE */ + V4L2_PIX_FMT_RGB565X, /* 16 RGB-5-6-5 BE */ + V4L2_PIX_FMT_BGR24, /* 24 BGR-8-8-8 */ + V4L2_PIX_FMT_RGB24, /* 24 RGB-8-8-8 */ + V4L2_PIX_FMT_BGR32, /* 32 BGR-8-8-8-8 */ + V4L2_PIX_FMT_RGB32, /* 32 RGB-8-8-8-8 */ + V4L2_PIX_FMT_GREY, /* 8 Greyscale */ + V4L2_PIX_FMT_YVU410, /* 9 YVU 4:1:0 */ + V4L2_PIX_FMT_YVU420, /* 12 YVU 4:2:0 */ + V4L2_PIX_FMT_YUYV, /* 16 YUV 4:2:2 */ + V4L2_PIX_FMT_UYVY, /* 16 YUV 4:2:2 */ + V4L2_PIX_FMT_YUV422P, /* 16 YVU422 planar */ + V4L2_PIX_FMT_YUV411P, /* 16 YVU411 planar */ + V4L2_PIX_FMT_Y41P, /* 12 YUV 4:1:1 */ + V4L2_PIX_FMT_NV12, /* 12 Y/CbCr 4:2:0 */ + V4L2_PIX_FMT_NV21, /* 12 Y/CrCb 4:2:0 */ + V4L2_PIX_FMT_YUV410, /* 9 YUV 4:1:0 */ + V4L2_PIX_FMT_YUV420, /* 12 YUV 4:2:0 */ + V4L2_PIX_FMT_YYUV, /* 16 YUV 4:2:2 */ + V4L2_PIX_FMT_HI240, /* 8 8-bit color */ + V4L2_PIX_FMT_MJPEG, /* Motion-JPEG */ + V4L2_PIX_FMT_JPEG, /* JFIF JPEG */ + V4L2_PIX_FMT_DV, /* 1394 */ + V4L2_PIX_FMT_MPEG, /* MPEG */ + V4L2_PIX_FMT_WNVA /* Winnov hw compres */ +}; +#define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats)) + GST_FORMATS_FUNCTION (GstPad *, gst_v4l2src_get_formats, GST_FORMAT_TIME, GST_FORMAT_DEFAULT); GST_QUERY_TYPE_FUNCTION (GstPad *, gst_v4l2src_get_query_types, GST_QUERY_POSITION); /* init functions */ -static void gst_v4l2src_class_init (GstV4l2SrcClass *klass); -static void gst_v4l2src_base_init (GstV4l2SrcClass *klass); -static void gst_v4l2src_init (GstV4l2Src *v4l2src); +static void gst_v4l2src_class_init (gpointer g_class, + gpointer class_data); +static void gst_v4l2src_base_init (gpointer g_class); +static void gst_v4l2src_init (GTypeInstance * instance, + gpointer g_class); /* signal functions */ static void gst_v4l2src_open (GstElement *element, @@ -68,9 +106,12 @@ static void gst_v4l2src_close (GstElement *element, const gchar *device); /* pad/buffer functions */ -static GstPadLinkReturn gst_v4l2src_srcconnect (GstPad *pad, +static const GstCaps * gst_v4l2src_get_all_caps (void); +static GstPadLinkReturn gst_v4l2src_link (GstPad *pad, const GstCaps *caps); static GstCaps * gst_v4l2src_getcaps (GstPad *pad); +static GstCaps * gst_v4l2src_fixate (GstPad * pad, + const GstCaps * caps); static GstData * gst_v4l2src_get (GstPad *pad); static gboolean gst_v4l2src_src_convert (GstPad *pad, GstFormat src_format, @@ -100,8 +141,6 @@ static GstElementStateReturn static void gst_v4l2src_set_clock (GstElement *element, GstClock *clock); -static GstPadTemplate *src_template; - static GstElementClass *parent_class = NULL; static guint gst_v4l2src_signals[LAST_SIGNAL] = { 0 }; @@ -109,133 +148,127 @@ static guint gst_v4l2src_signals[LAST_SIGNAL] = { 0 }; GType gst_v4l2src_get_type (void) { - static GType v4l2src_type = 0; - - if (!v4l2src_type) { - static const GTypeInfo v4l2src_info = { - sizeof(GstV4l2SrcClass), - (GBaseInitFunc) gst_v4l2src_base_init, - NULL, - (GClassInitFunc) gst_v4l2src_class_init, - NULL, - NULL, - sizeof(GstV4l2Src), - 0, - (GInstanceInitFunc) gst_v4l2src_init, - NULL - }; - v4l2src_type = g_type_register_static(GST_TYPE_V4L2ELEMENT, - "GstV4l2Src", &v4l2src_info, 0); - } - return v4l2src_type; + static GType v4l2src_type = 0; + + if (!v4l2src_type) { + static const GTypeInfo v4l2src_info = { + sizeof (GstV4l2SrcClass), + gst_v4l2src_base_init, + NULL, + gst_v4l2src_class_init, + NULL, + NULL, + sizeof (GstV4l2Src), + 0, + gst_v4l2src_init, + NULL + }; + v4l2src_type = g_type_register_static(GST_TYPE_V4L2ELEMENT, + "GstV4l2Src", &v4l2src_info, 0); + GST_DEBUG_CATEGORY_INIT (v4l2src_debug, "v4l2src", 0, "v4l2src element"); + } + return v4l2src_type; } static void -gst_v4l2src_base_init (GstV4l2SrcClass *klass) +gst_v4l2src_base_init (gpointer g_class) { - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + GstPadTemplate *template; + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - gst_element_class_set_details (gstelement_class, - &gst_v4l2src_details); + gst_element_class_set_details (gstelement_class, &gst_v4l2src_details); - src_template = gst_pad_template_new ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - NULL); + template = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + gst_caps_copy (gst_v4l2src_get_all_caps ())); - gst_element_class_add_pad_template (gstelement_class, src_template); + gst_element_class_add_pad_template (gstelement_class, template); } static void -gst_v4l2src_class_init (GstV4l2SrcClass *klass) +gst_v4l2src_class_init (gpointer g_class, gpointer class_data) { - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstV4l2ElementClass *v4l2_class; - - gobject_class = (GObjectClass*)klass; - gstelement_class = (GstElementClass*)klass; - v4l2_class = (GstV4l2ElementClass*)klass; - - parent_class = g_type_class_ref(GST_TYPE_V4L2ELEMENT); - - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS, - g_param_spec_int("num_buffers","num_buffers","num_buffers", - G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE, - g_param_spec_int("buffer_size","buffer_size","buffer_size", - G_MININT,G_MAXINT,0,G_PARAM_READABLE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_USE_FIXED_FPS, - g_param_spec_boolean("use_fixed_fps", "Use Fixed FPS", - "Drop/Insert frames to reach a certain FPS (TRUE) " - "or adapt FPS to suit the number of frabbed frames", - TRUE, G_PARAM_READWRITE)); - - /* signals */ - gst_v4l2src_signals[SIGNAL_FRAME_CAPTURE] = - g_signal_new("frame_capture", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GstV4l2SrcClass, frame_capture), - NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - gst_v4l2src_signals[SIGNAL_FRAME_DROP] = - g_signal_new("frame_drop", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GstV4l2SrcClass, frame_drop), - NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - gst_v4l2src_signals[SIGNAL_FRAME_INSERT] = - g_signal_new("frame_insert", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GstV4l2SrcClass, frame_insert), - NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - gst_v4l2src_signals[SIGNAL_FRAME_LOST] = - g_signal_new("frame_lost", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GstV4l2SrcClass, frame_lost), - NULL, NULL, g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - - gobject_class->set_property = gst_v4l2src_set_property; - gobject_class->get_property = gst_v4l2src_get_property; - - gstelement_class->change_state = gst_v4l2src_change_state; - - v4l2_class->open = gst_v4l2src_open; - v4l2_class->close = gst_v4l2src_close; - - gstelement_class->set_clock = gst_v4l2src_set_clock; + GObjectClass *gobject_class = G_OBJECT_CLASS (g_class); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + GstV4l2ElementClass *v4l2_class = GST_V4L2ELEMENT_CLASS (g_class); + + parent_class = g_type_class_peek_parent (g_class); + + gobject_class->set_property = gst_v4l2src_set_property; + gobject_class->get_property = gst_v4l2src_get_property; + + g_object_class_install_property(gobject_class, ARG_NUMBUFS, + g_param_spec_int("num_buffers","num_buffers","num_buffers", + G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, ARG_BUFSIZE, + g_param_spec_int("buffer_size","buffer_size","buffer_size", + G_MININT,G_MAXINT,0,G_PARAM_READABLE)); + + g_object_class_install_property(gobject_class, ARG_USE_FIXED_FPS, + g_param_spec_boolean("use_fixed_fps", "Use Fixed FPS", + "Drop/Insert frames to reach a certain FPS (TRUE) " + "or adapt FPS to suit the number of frabbed frames", + TRUE, G_PARAM_READWRITE)); + + /* signals */ + gst_v4l2src_signals[SIGNAL_FRAME_CAPTURE] = + g_signal_new("frame_capture", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GstV4l2SrcClass, frame_capture), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + gst_v4l2src_signals[SIGNAL_FRAME_DROP] = + g_signal_new("frame_drop", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GstV4l2SrcClass, frame_drop), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + gst_v4l2src_signals[SIGNAL_FRAME_INSERT] = + g_signal_new("frame_insert", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GstV4l2SrcClass, frame_insert), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + gst_v4l2src_signals[SIGNAL_FRAME_LOST] = + g_signal_new("frame_lost", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GstV4l2SrcClass, frame_lost), + NULL, NULL, g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + + gstelement_class->change_state = gst_v4l2src_change_state; + + v4l2_class->open = gst_v4l2src_open; + v4l2_class->close = gst_v4l2src_close; + + gstelement_class->set_clock = gst_v4l2src_set_clock; } static void -gst_v4l2src_init (GstV4l2Src *v4l2src) +gst_v4l2src_init (GTypeInstance *instance, gpointer g_class) { - GST_FLAG_SET(GST_ELEMENT(v4l2src), GST_ELEMENT_THREAD_SUGGESTED); + GstV4l2Src *v4l2src = GST_V4L2SRC (instance); + + GST_FLAG_SET(GST_ELEMENT(v4l2src), GST_ELEMENT_THREAD_SUGGESTED); - v4l2src->srcpad = gst_pad_new_from_template(src_template, "src"); - gst_element_add_pad(GST_ELEMENT(v4l2src), v4l2src->srcpad); + v4l2src->srcpad = gst_pad_new_from_template( + gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (v4l2src), "src"), "src"); + gst_element_add_pad(GST_ELEMENT(v4l2src), v4l2src->srcpad); - gst_pad_set_get_function(v4l2src->srcpad, gst_v4l2src_get); - gst_pad_set_link_function(v4l2src->srcpad, gst_v4l2src_srcconnect); - gst_pad_set_getcaps_function (v4l2src->srcpad, gst_v4l2src_getcaps); - gst_pad_set_convert_function (v4l2src->srcpad, gst_v4l2src_src_convert); - gst_pad_set_formats_function (v4l2src->srcpad, - gst_v4l2src_get_formats); - gst_pad_set_query_function (v4l2src->srcpad, - gst_v4l2src_src_query); - gst_pad_set_query_type_function (v4l2src->srcpad, - gst_v4l2src_get_query_types); + gst_pad_set_get_function(v4l2src->srcpad, gst_v4l2src_get); + gst_pad_set_link_function(v4l2src->srcpad, gst_v4l2src_link); + gst_pad_set_getcaps_function (v4l2src->srcpad, gst_v4l2src_getcaps); + gst_pad_set_fixate_function (v4l2src->srcpad, gst_v4l2src_fixate); + gst_pad_set_convert_function (v4l2src->srcpad, gst_v4l2src_src_convert); + gst_pad_set_formats_function (v4l2src->srcpad, gst_v4l2src_get_formats); + gst_pad_set_query_function (v4l2src->srcpad, gst_v4l2src_src_query); + gst_pad_set_query_type_function (v4l2src->srcpad, gst_v4l2src_get_query_types); - v4l2src->breq.count = 0; + v4l2src->breq.count = 0; - v4l2src->formats = NULL; - v4l2src->format_list = NULL; + v4l2src->formats = NULL; - /* no clock */ - v4l2src->clock = NULL; + /* no clock */ + v4l2src->clock = NULL; - /* fps */ - v4l2src->use_fixed_fps = TRUE; + /* fps */ + v4l2src->use_fixed_fps = TRUE; } @@ -243,7 +276,7 @@ static void gst_v4l2src_open (GstElement *element, const gchar *device) { - gst_v4l2src_fill_format_list(GST_V4L2SRC(element)); + gst_v4l2src_fill_format_list (GST_V4L2SRC (element)); } @@ -251,7 +284,7 @@ static void gst_v4l2src_close (GstElement *element, const gchar *device) { - gst_v4l2src_empty_format_list(GST_V4L2SRC(element)); + gst_v4l2src_clear_format_list (GST_V4L2SRC (element)); } @@ -365,173 +398,154 @@ gst_v4l2src_src_query (GstPad *pad, return res; } - static GstStructure * -gst_v4l2src_v4l2fourcc_to_caps (guint32 fourcc, - gboolean compressed) +gst_v4l2src_v4l2fourcc_to_caps (guint32 fourcc) { - GstStructure *structure; + GstStructure *structure = NULL; - switch (fourcc) { - case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */ - case V4L2_PIX_FMT_JPEG: /* JFIF JPEG */ - structure = gst_structure_new ("video/x-jpeg", NULL); - break; + switch (fourcc) { + case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */ + case V4L2_PIX_FMT_JPEG: /* JFIF JPEG */ + structure = gst_structure_new ("video/x-jpeg", NULL); + break; + case V4L2_PIX_FMT_RGB332: + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: { + guint depth=0, bpp=0; + gint endianness = 0; + guint32 r_mask = 0, b_mask = 0, g_mask = 0; + + switch (fourcc) { case V4L2_PIX_FMT_RGB332: + bpp = depth = 8; + endianness = G_BYTE_ORDER; /* 'like, whatever' */ + r_mask = 0xe0; g_mask = 0x1c; b_mask = 0x03; + break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_RGB555X: + bpp = 16; depth = 15; + endianness = fourcc == V4L2_PIX_FMT_RGB555X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN; + r_mask = 0x7c00; + g_mask = 0x03e0; + b_mask = 0x001f; + break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: + bpp = depth = 16; + endianness = fourcc == V4L2_PIX_FMT_RGB565X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN; + r_mask = 0xf800; + g_mask = 0x07e0; + b_mask = 0x001f; case V4L2_PIX_FMT_RGB24: + bpp = depth = 24; + endianness = G_BIG_ENDIAN; + r_mask = 0xff0000; + g_mask = 0x00ff00; + b_mask = 0x0000ff; + break; case V4L2_PIX_FMT_BGR24: + bpp = depth = 24; + endianness = G_BIG_ENDIAN; + r_mask = 0x0000ff; + g_mask = 0x00ff00; + b_mask = 0xff0000; + break; case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_BGR32: { - guint depth=0, bpp=0; - gint endianness = 0; - guint32 r_mask = 0, b_mask = 0, g_mask = 0; - - switch (fourcc) { - case V4L2_PIX_FMT_RGB332: - bpp = depth = 8; - endianness = G_BYTE_ORDER; /* 'like, whatever' */ - r_mask = 0xe0; g_mask = 0x1c; b_mask = 0x03; - break; - case V4L2_PIX_FMT_RGB555: - case V4L2_PIX_FMT_RGB555X: - bpp = 16; depth = 15; - endianness = G_BYTE_ORDER; - if ((fourcc == V4L2_PIX_FMT_RGB555 && - G_BYTE_ORDER == G_LITTLE_ENDIAN) || - (fourcc == V4L2_PIX_FMT_RGB555X && - G_BYTE_ORDER == G_BIG_ENDIAN)) { - r_mask = 0x7c00; - g_mask = 0x03e0; - b_mask = 0x001f; - } else { - r_mask = 0x007c; - g_mask = 0xe003; - b_mask = 0x1f00; - } - break; - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - bpp = depth = 16; - endianness = G_BYTE_ORDER; - if ((fourcc == V4L2_PIX_FMT_RGB565 && - G_BYTE_ORDER == G_LITTLE_ENDIAN) || - (fourcc == V4L2_PIX_FMT_RGB565X && - G_BYTE_ORDER == G_BIG_ENDIAN)) { - r_mask = 0xf800; - g_mask = 0x07e0; - b_mask = 0x001f; - } else { - r_mask = 0x00f8; - g_mask = 0xe007; - b_mask = 0x1f00; - } - break; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - bpp = depth = 24; - endianness = G_BIG_ENDIAN; - if (fourcc == V4L2_PIX_FMT_RGB24) { - r_mask = 0xff0000; - g_mask = 0x00ff00; - b_mask = 0x0000ff; - } else { - r_mask = 0x0000ff; - g_mask = 0x00ff00; - b_mask = 0xff0000; - } - break; - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_BGR32: - bpp = depth = 32; - endianness = G_BIG_ENDIAN; - if (fourcc == V4L2_PIX_FMT_RGB32) { - r_mask = 0xff000000; - g_mask = 0x00ff0000; - b_mask = 0x0000ff00; - } else { - r_mask = 0x000000ff; - g_mask = 0x0000ff00; - b_mask = 0x00ff0000; - } - break; - default: - g_assert_not_reached(); - break; - } - - structure = gst_structure_new ("video/x-raw-rgb", - "bpp", G_TYPE_INT, bpp, - "depth", G_TYPE_INT, depth, - "red_mask", G_TYPE_INT, r_mask, - "green_mask", G_TYPE_INT, g_mask, - "blue_mask", G_TYPE_INT, b_mask, - "endianness", G_TYPE_INT, endianness, - NULL); - break; - } - case V4L2_PIX_FMT_YUV420: /* I420/IYUV */ + bpp = depth = 32; + endianness = G_BIG_ENDIAN; + r_mask = 0xff000000; + g_mask = 0x00ff0000; + b_mask = 0x0000ff00; + break; + case V4L2_PIX_FMT_BGR32: + bpp = depth = 32; + endianness = G_BIG_ENDIAN; + r_mask = 0x000000ff; + g_mask = 0x0000ff00; + b_mask = 0x00ff0000; + break; + default: + g_assert_not_reached(); + break; + } + structure = gst_structure_new ("video/x-raw-rgb", + "bpp", G_TYPE_INT, bpp, + "depth", G_TYPE_INT, depth, + "red_mask", G_TYPE_INT, r_mask, + "green_mask", G_TYPE_INT, g_mask, + "blue_mask", G_TYPE_INT, b_mask, + "endianness", G_TYPE_INT, endianness, + NULL); + break; + } + case V4L2_PIX_FMT_GREY: /* 8 Greyscale */ + case V4L2_PIX_FMT_YUV422P: /* 16 YVU422 planar */ + case V4L2_PIX_FMT_YUV411P: /* 16 YVU411 planar */ + case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */ + case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */ + case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */ + case V4L2_PIX_FMT_HI240: /* 8 8-bit color */ + /* FIXME: get correct fourccs here */ + break; + case V4L2_PIX_FMT_YVU410: + case V4L2_PIX_FMT_YUV410: + case V4L2_PIX_FMT_YUV420: /* I420/IYUV */ + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_Y41P: { + guint32 fcc = 0; + + switch (fourcc) { + case V4L2_PIX_FMT_YVU410: + fcc = GST_MAKE_FOURCC('Y','V','U','9'); + break; + case V4L2_PIX_FMT_YUV410: + fcc = GST_MAKE_FOURCC('Y','U','V','9'); + break; + case V4L2_PIX_FMT_YUV420: + fcc = GST_MAKE_FOURCC('I','4','2','0'); + break; case V4L2_PIX_FMT_YUYV: + fcc = GST_MAKE_FOURCC('Y','U','Y','2'); + break; case V4L2_PIX_FMT_YVU420: + fcc = GST_MAKE_FOURCC('Y','V','1','2'); + break; case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_Y41P: { - guint32 fcc = 0; - - switch (fourcc) { - case V4L2_PIX_FMT_YUV420: - fcc = GST_MAKE_FOURCC('I','4','2','0'); - break; - case V4L2_PIX_FMT_YUYV: - fcc = GST_MAKE_FOURCC('Y','U','Y','2'); - break; - case V4L2_PIX_FMT_YVU420: - fcc = GST_MAKE_FOURCC('Y','V','1','2'); - break; - case V4L2_PIX_FMT_UYVY: - fcc = GST_MAKE_FOURCC('U','Y','V','Y'); - break; - case V4L2_PIX_FMT_Y41P: - fcc = GST_MAKE_FOURCC('Y','4','1','P'); - break; - default: - g_assert_not_reached(); - break; - } - - structure = gst_structure_new ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, fcc, - NULL); - break; - } + fcc = GST_MAKE_FOURCC('U','Y','V','Y'); + break; + case V4L2_PIX_FMT_Y41P: + fcc = GST_MAKE_FOURCC('Y','4','1','B'); + break; default: - GST_DEBUG ( - "Unknown fourcc 0x%08x " GST_FOURCC_FORMAT ", trying default", + g_assert_not_reached(); + break; + } + structure = gst_structure_new ("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, fcc, + NULL); + break; + } + case V4L2_PIX_FMT_DV: + structure = gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE, NULL); + break; + case V4L2_PIX_FMT_MPEG: /* MPEG */ + /* someone figure out the MPEG format used... */ + break; + case V4L2_PIX_FMT_WNVA: /* Winnov hw compres */ + break; + default: + GST_DEBUG ("Unknown fourcc 0x%08x " GST_FOURCC_FORMAT, fourcc, GST_FOURCC_ARGS(fourcc)); - - /* add the standard one */ - if (compressed) { - guint32 print_format = GUINT32_FROM_LE(fourcc); - gchar *print_format_str = (gchar *) &print_format, *string_format; - gint i; - - for (i=0;i<4;i++) { - print_format_str[i] = - g_ascii_tolower(print_format_str[i]); - } - string_format = g_strdup_printf("video/%4.4s", - print_format_str); - structure = gst_structure_new (string_format, NULL); - g_free(string_format); - } else { - structure = gst_structure_new ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, fourcc, NULL); - } - break; - } - + break; + } #if 0 gst_caps_set_simple (caps, "width", G_TYPE_INT, width, @@ -539,351 +553,389 @@ gst_v4l2src_v4l2fourcc_to_caps (guint32 fourcc, "framerate", G_TYPE_DOUBLE, fps, NULL); #endif + return structure; +} + +static struct v4l2_fmtdesc * +gst_v4l2src_get_format_from_fourcc (GstV4l2Src *v4l2src, guint32 fourcc) +{ + struct v4l2_fmtdesc *fmt; + GSList *walk; + + if (fourcc == 0) + return NULL; + + walk = v4l2src->formats; + while (walk) { + fmt = (struct v4l2_fmtdesc *) walk->data; + if (fmt->pixelformat == fourcc) + return fmt; + /* special case for jpeg */ + if ((fmt->pixelformat == V4L2_PIX_FMT_MJPEG && fourcc == V4L2_PIX_FMT_JPEG) || + (fmt->pixelformat == V4L2_PIX_FMT_JPEG && fourcc == V4L2_PIX_FMT_MJPEG)) { + return fmt; + } + walk = g_slist_next (walk); + } - return structure; + return NULL; } -#define gst_v4l2src_v4l2fourcc_to_caps_fixed(f, width, height, fps, c) \ - gst_v4l2src_v4l2fourcc_to_caps(f, \ - gst_props_entry_new("width", \ - GST_PROPS_INT(width)), \ - gst_props_entry_new("height", \ - GST_PROPS_INT(height)), \ - gst_props_entry_new("framerate", \ - GST_PROPS_FLOAT(fps)), \ - c) - -#define gst_v4l2src_v4l2fourcc_to_caps_range(f, min_w, max_w, min_h, max_h, c) \ - gst_v4l2src_v4l2fourcc_to_caps(f, \ - gst_props_entry_new("width", \ - GST_PROPS_INT_RANGE(min_w, max_w)), \ - gst_props_entry_new("height", \ - GST_PROPS_INT_RANGE(min_h, max_h)), \ - gst_props_entry_new("framerate", \ - GST_PROPS_FLOAT_RANGE(0, G_MAXFLOAT)), \ - c) +static guint32 +gst_v4l2_fourcc_from_structure (GstStructure *structure) +{ + guint32 fourcc = 0; + const gchar *mimetype = gst_structure_get_name (structure); + + if (!strcmp(mimetype, "video/x-raw-yuv") || + !strcmp(mimetype, "video/x-raw-rgb")) { + if (!strcmp(mimetype, "video/x-raw-rgb")) + fourcc = GST_MAKE_FOURCC('R','G','B',' '); + else + gst_structure_get_fourcc (structure, "format", &fourcc); + + switch (fourcc) { + case GST_MAKE_FOURCC('I','4','2','0'): + case GST_MAKE_FOURCC('I','Y','U','V'): + fourcc = V4L2_PIX_FMT_YUV420; + break; + case GST_MAKE_FOURCC('Y','U','Y','2'): + fourcc = V4L2_PIX_FMT_YUYV; + break; + case GST_MAKE_FOURCC('Y','4','1','P'): + fourcc = V4L2_PIX_FMT_Y41P; + break; + case GST_MAKE_FOURCC('U','Y','V','Y'): + fourcc = V4L2_PIX_FMT_UYVY; + break; + case GST_MAKE_FOURCC('Y','V','1','2'): + fourcc = V4L2_PIX_FMT_YVU420; + break; + case GST_MAKE_FOURCC('R','G','B',' '): { + gint depth, endianness, r_mask; + + gst_structure_get_int (structure, "depth", &depth); + gst_structure_get_int (structure, "endianness", &endianness); + gst_structure_get_int (structure, "red_mask", &r_mask); + + switch (depth) { + case 8: + fourcc = V4L2_PIX_FMT_RGB332; + break; + case 15: + fourcc = (endianness == G_LITTLE_ENDIAN) ? + V4L2_PIX_FMT_RGB555 : + V4L2_PIX_FMT_RGB555X; + break; + case 16: + fourcc = (endianness == G_LITTLE_ENDIAN) ? + V4L2_PIX_FMT_RGB565 : + V4L2_PIX_FMT_RGB565X; + break; + case 24: + fourcc = (r_mask == 0xFF) ? + V4L2_PIX_FMT_BGR24 : + V4L2_PIX_FMT_RGB24; + break; + case 32: + fourcc = (r_mask == 0xFF) ? + V4L2_PIX_FMT_BGR32 : + V4L2_PIX_FMT_RGB32; + break; + } + default: + break; + } + } + } else if (strcmp (mimetype, "video/x-dv") == 0) { + fourcc = V4L2_PIX_FMT_DV; + } else if (strcmp (mimetype, "video/x-jpeg") == 0) { + fourcc = V4L2_PIX_FMT_JPEG; + } + + return fourcc; +} static struct v4l2_fmtdesc * -gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src *v4l2src, - GstStructure *structure) +gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src *v4l2src, GstStructure *structure) { - gint i; - guint32 fourcc = 0; - struct v4l2_fmtdesc *end_fmt = NULL; - const gchar *format = gst_structure_get_name (structure); - - if (!strcmp(format, "video/x-raw-yuv") || - !strcmp(format, "video/x-raw-rgb")) { - if (!strcmp(format, "video/x-raw-rgb")) - fourcc = GST_MAKE_FOURCC('R','G','B',' '); - else - gst_structure_get_fourcc (structure, "format", &fourcc); - - switch (fourcc) { - case GST_MAKE_FOURCC('I','4','2','0'): - case GST_MAKE_FOURCC('I','Y','U','V'): - fourcc = V4L2_PIX_FMT_YUV420; - break; - case GST_MAKE_FOURCC('Y','U','Y','2'): - fourcc = V4L2_PIX_FMT_YUYV; - break; - case GST_MAKE_FOURCC('Y','4','1','P'): - fourcc = V4L2_PIX_FMT_Y41P; - break; - case GST_MAKE_FOURCC('U','Y','V','Y'): - fourcc = V4L2_PIX_FMT_UYVY; - break; - case GST_MAKE_FOURCC('Y','V','1','2'): - fourcc = V4L2_PIX_FMT_YVU420; - break; - case GST_MAKE_FOURCC('R','G','B',' '): { - gint depth, endianness; - - gst_structure_get_int (structure, "depth", &depth); - gst_structure_get_int (structure, "endianness", &endianness); - - switch (depth) { - case 8: - fourcc = V4L2_PIX_FMT_RGB332; - break; - case 15: - fourcc = (endianness == G_LITTLE_ENDIAN) ? - V4L2_PIX_FMT_RGB555 : - V4L2_PIX_FMT_RGB555X; - break; - case 16: - fourcc = (endianness == G_LITTLE_ENDIAN) ? - V4L2_PIX_FMT_RGB565 : - V4L2_PIX_FMT_RGB565X; - break; - case 24: - fourcc = (endianness == G_LITTLE_ENDIAN) ? - V4L2_PIX_FMT_BGR24 : - V4L2_PIX_FMT_RGB24; - break; - case 32: - fourcc = (endianness == G_LITTLE_ENDIAN) ? - V4L2_PIX_FMT_BGR32 : - V4L2_PIX_FMT_RGB32; - break; - } - } - default: - break; - } - for (i=0;iformats);i++) { - struct v4l2_fmtdesc *fmt; - fmt = (struct v4l2_fmtdesc *) - g_list_nth_data(v4l2src->formats, i); - if (fmt->pixelformat == fourcc) { - end_fmt = fmt; - break; - } - } - } else { - /* compressed */ - if (strncmp(format, "video/", 6)) - return NULL; - format = &format[6]; - if (strlen(format) != 4) - return NULL; - fourcc = GST_MAKE_FOURCC(g_ascii_toupper(format[0]), - g_ascii_toupper(format[1]), - g_ascii_toupper(format[2]), - g_ascii_toupper(format[3])); - - switch (fourcc) { - case GST_MAKE_FOURCC('J','P','E','G'): { - struct v4l2_fmtdesc *fmt; - for (i=0;iformats);i++) { - fmt = g_list_nth_data(v4l2src->formats, i); - if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG || - fmt->pixelformat == V4L2_PIX_FMT_JPEG) { - end_fmt = fmt; - break; - } - } - break; - } - default: { - /* FIXME: check for fourcc in list */ - struct v4l2_fmtdesc *fmt; - for (i=0;iformats);i++) { - fmt = g_list_nth_data(v4l2src->formats, i); - if (fourcc == fmt->pixelformat) { - end_fmt = fmt; - break; - } - } - break; - } - } - } + return gst_v4l2src_get_format_from_fourcc (v4l2src, + gst_v4l2_fourcc_from_structure (structure)); +} + +static const GstCaps * +gst_v4l2src_get_all_caps (void) +{ + static GstCaps *caps = NULL; + + if (caps == NULL) { + GstStructure *structure; + guint i; + + caps = gst_caps_new_empty (); + for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) { + structure = gst_v4l2src_v4l2fourcc_to_caps (gst_v4l2_formats[i]); + if (structure) { + gst_structure_set (structure, + "width", GST_TYPE_INT_RANGE, 1, 4096, + "height", GST_TYPE_INT_RANGE, 1, 4096, + "framerate", GST_TYPE_DOUBLE_RANGE, (double) 0, G_MAXDOUBLE, + NULL); + + gst_caps_append_structure (caps, structure); + } + } + } - return end_fmt; + return caps; } -#define gst_caps_get_int_range(caps, name, min, max) \ - gst_props_entry_get_int_range(gst_props_get_entry((caps)->properties, \ - name), \ - min, max) +static GstCaps * +gst_v4l2src_fixate (GstPad *pad, const GstCaps *const_caps) +{ + gint i; + GstStructure *structure; + G_GNUC_UNUSED gchar *caps_str; + gboolean changed = FALSE; + GstCaps *caps = gst_caps_copy (const_caps); + + caps_str = gst_caps_to_string (caps); + GST_DEBUG_OBJECT (gst_pad_get_parent (pad), "fixating caps %s", caps_str); + g_free (caps_str); + + for (i = 0; i < gst_caps_get_size (caps); i++) { + structure = gst_caps_get_structure (caps, i); + changed |= gst_caps_structure_fixate_field_nearest_int (structure, "width", G_MAXINT); + } + if (changed) return caps; + for (i = 0; i < gst_caps_get_size (caps); i++) { + structure = gst_caps_get_structure (caps, i); + changed |= gst_caps_structure_fixate_field_nearest_int (structure, "height", G_MAXINT); + } + if (changed) return caps; + gst_caps_free (caps); + return NULL; +} static GstPadLinkReturn -gst_v4l2src_srcconnect (GstPad *pad, - const GstCaps *vscapslist) +gst_v4l2src_link (GstPad *pad, const GstCaps *caps) { - GstV4l2Src *v4l2src; - GstV4l2Element *v4l2element; - struct v4l2_fmtdesc *format; - int w, h; - GstStructure *structure; - - v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad)); - v4l2element = GST_V4L2ELEMENT(v4l2src); - - structure = gst_caps_get_structure (vscapslist, 0); - - /* clean up if we still haven't cleaned up our previous - * capture session */ - if (GST_V4L2_IS_ACTIVE(v4l2element)) { - if (!gst_v4l2src_capture_deinit(v4l2src)) - return GST_PAD_LINK_REFUSED; - } else if (!GST_V4L2_IS_OPEN(v4l2element)) { - return GST_PAD_LINK_DELAYED; - } + GstV4l2Src *v4l2src; + GstV4l2Element *v4l2element; + struct v4l2_fmtdesc *format; + int w, h; + GstStructure *structure; + + v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad)); + v4l2element = GST_V4L2ELEMENT(v4l2src); + + structure = gst_caps_get_structure (caps, 0); + + /* clean up if we still haven't cleaned up our previous + * capture session */ + if (GST_V4L2_IS_ACTIVE(v4l2element)) { + if (!gst_v4l2src_capture_deinit(v4l2src)) + return GST_PAD_LINK_REFUSED; + } else if (!GST_V4L2_IS_OPEN(v4l2element)) { + return GST_PAD_LINK_DELAYED; + } - /* we want our own v4l2 type of fourcc codes */ - if (!(format = gst_v4l2_caps_to_v4l2fourcc(v4l2src, structure))) { - return GST_PAD_LINK_REFUSED; - } + /* we want our own v4l2 type of fourcc codes */ + if (!(format = gst_v4l2_caps_to_v4l2fourcc(v4l2src, structure))) { + return GST_PAD_LINK_REFUSED; + } - gst_structure_get_int (structure, "width", &w); - gst_structure_get_int (structure, "height", &h); + gst_structure_get_int (structure, "width", &w); + gst_structure_get_int (structure, "height", &h); - /* we found the pixelformat! - try it out */ - if (gst_v4l2src_set_capture(v4l2src, format, w, h)) { - if (gst_v4l2src_capture_init(v4l2src)) { - return GST_PAD_LINK_OK; - } - } + /* we found the pixelformat! - try it out */ + if (gst_v4l2src_set_capture(v4l2src, format, w, h)) { + if (gst_v4l2src_capture_init(v4l2src)) { + return GST_PAD_LINK_OK; + } + } - return GST_PAD_LINK_REFUSED; + return GST_PAD_LINK_REFUSED; } static GstCaps * gst_v4l2src_getcaps (GstPad *pad) { - GstV4l2Src *v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad)); - GstCaps *caps; - gint i; - struct v4l2_fmtdesc *format; - int min_w, max_w, min_h, max_h; - - if (!GST_V4L2_IS_OPEN(GST_V4L2ELEMENT(v4l2src))) { - return gst_caps_new_any (); - } - - /* build our own capslist */ - caps = gst_caps_new_empty(); - for (i=0;iformats);i++) { - GstStructure *structure; - - format = g_list_nth_data(v4l2src->formats, i); - - /* get size delimiters */ - if (!gst_v4l2src_get_size_limits(v4l2src, format, - &min_w, &max_w, - &min_h, &max_h)) { - continue; - } - - /* add to list */ - structure = gst_v4l2src_v4l2fourcc_to_caps (format->pixelformat, - format->flags & V4L2_FMT_FLAG_COMPRESSED); - - gst_structure_set (structure, - "width", GST_TYPE_INT_RANGE, min_w, max_w, - "height", GST_TYPE_INT_RANGE, min_h, max_h, - "framerate", GST_TYPE_DOUBLE_RANGE, 0, G_MAXDOUBLE, - NULL); + GstV4l2Src *v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad)); + GstCaps *caps; + struct v4l2_fmtdesc *format; + int min_w, max_w, min_h, max_h; + GSList *walk; + GstStructure *structure; + + if (!GST_V4L2_IS_OPEN(GST_V4L2ELEMENT(v4l2src))) { + return gst_caps_new_any (); + } - gst_caps_append_structure (caps, structure); - } + /* build our own capslist */ + caps = gst_caps_new_empty(); + walk = v4l2src->formats; + while (walk) { + format = (struct v4l2_fmtdesc *) walk->data; + walk = g_slist_next (walk); + + /* get size delimiters */ + if (!gst_v4l2src_get_size_limits(v4l2src, format, + &min_w, &max_w, &min_h, &max_h)) { + continue; + } + + /* add to list */ + structure = gst_v4l2src_v4l2fourcc_to_caps (format->pixelformat); + + if (structure) { + gst_structure_set (structure, + "width", GST_TYPE_INT_RANGE, min_w, max_w, + "height", GST_TYPE_INT_RANGE, min_h, max_h, + "framerate", GST_TYPE_DOUBLE_RANGE, (double) 0, G_MAXDOUBLE, + NULL); + + gst_caps_append_structure (caps, structure); + } + } - return caps; + return caps; } - static GstData* gst_v4l2src_get (GstPad *pad) { - GstV4l2Src *v4l2src; - GstBuffer *buf; - gint num; - gdouble fps = 0; + GstV4l2Src *v4l2src; + GstBuffer *buf; + gint i, num = -1; + gdouble fps = 0; - g_return_val_if_fail (pad != NULL, NULL); + v4l2src = GST_V4L2SRC (gst_pad_get_parent (pad)); - v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad)); + if (v4l2src->use_fixed_fps && + (fps = gst_v4l2src_get_fps(v4l2src)) == 0) { + gst_element_error (GST_ELEMENT (v4l2src), "Could not get frame rate for element."); + return NULL; + } - if (v4l2src->use_fixed_fps && - (fps = gst_v4l2src_get_fps(v4l2src)) == 0) - return NULL; + if (v4l2src->need_writes > 0) { + /* use last frame */ + buf = v4l2src->cached_buffer; + v4l2src->need_writes--; + } else { + GstClockTime time; + /* grab a frame from the device */ + num = gst_v4l2src_grab_frame(v4l2src); + if (num == -1) + return NULL; + + /* to check if v4l2 sets the correct time */ + time = GST_TIMEVAL_TO_TIME(v4l2src->pool->buffers[num].buffer.timestamp); + if (v4l2src->clock && v4l2src->use_fixed_fps && time != 0) { + gboolean have_frame = FALSE; + + do { + /* FIXME: isn't this v4l2 timestamp its own clock?! */ + /* by default, we use the frame once */ + v4l2src->need_writes = 1; + + g_assert (time >= v4l2src->substract_time); + time -= v4l2src->substract_time; + + /* first check whether we lost any frames according to the device */ + if (v4l2src->last_seq != 0) { + if (v4l2src->pool->buffers[num].buffer.sequence - v4l2src->last_seq > 1) { + v4l2src->need_writes = v4l2src->pool->buffers[num].buffer.sequence - v4l2src->last_seq; + g_signal_emit(G_OBJECT(v4l2src), gst_v4l2src_signals[SIGNAL_FRAME_LOST], 0, + v4l2src->need_writes - 1); + } + } + v4l2src->last_seq = v4l2src->pool->buffers[num].buffer.sequence; + + /* decide how often we're going to write the frame - set + * v4lmjpegsrc->need_writes to (that-1) and have_frame to TRUE + * if we're going to write it - else, just continue. + * + * time is generally the system or audio clock. Let's + * say that we've written one second of audio, then we want + * to have written one second of video too, within the same + * timeframe. This means that if time - begin_time = X sec, + * we want to have written X*fps frames. If we've written + * more - drop, if we've written less - dup... */ + if (v4l2src->handled * (GST_SECOND/fps) - time > 1.5 * (GST_SECOND/fps)) { + /* yo dude, we've got too many frames here! Drop! DROP! */ + v4l2src->need_writes--; /* -= (v4l2src->handled - (time / fps)); */ + g_signal_emit(G_OBJECT(v4l2src), gst_v4l2src_signals[SIGNAL_FRAME_DROP], 0); + } else if (v4l2src->handled * (GST_SECOND/fps) - time < -1.5 * (GST_SECOND/fps)) { + /* this means we're lagging far behind */ + v4l2src->need_writes++; /* += ((time / fps) - v4l2src->handled); */ + g_signal_emit(G_OBJECT(v4l2src), gst_v4l2src_signals[SIGNAL_FRAME_INSERT], 0); + } if (v4l2src->need_writes > 0) { - /* use last frame */ - num = v4l2src->last_frame; - v4l2src->need_writes--; - } else if (v4l2src->clock && v4l2src->use_fixed_fps) { - GstClockTime time; - gboolean have_frame = FALSE; - - do { - /* by default, we use the frame once */ - v4l2src->need_writes = 1; - - /* grab a frame from the device */ - if (!gst_v4l2src_grab_frame(v4l2src, &num)) - return NULL; - - v4l2src->last_frame = num; - time = GST_TIMEVAL_TO_TIME(v4l2src->bufsettings.timestamp) - - v4l2src->substract_time; - - /* first check whether we lost any frames according to the device */ - if (v4l2src->last_seq != 0) { - if (v4l2src->bufsettings.sequence - v4l2src->last_seq > 1) { - v4l2src->need_writes = v4l2src->bufsettings.sequence - - v4l2src->last_seq; - g_signal_emit(G_OBJECT(v4l2src), - gst_v4l2src_signals[SIGNAL_FRAME_LOST], - 0, - v4l2src->bufsettings.sequence - - v4l2src->last_seq - 1); - } - } - v4l2src->last_seq = v4l2src->bufsettings.sequence; - - /* decide how often we're going to write the frame - set - * v4lmjpegsrc->need_writes to (that-1) and have_frame to TRUE - * if we're going to write it - else, just continue. - * - * time is generally the system or audio clock. Let's - * say that we've written one second of audio, then we want - * to have written one second of video too, within the same - * timeframe. This means that if time - begin_time = X sec, - * we want to have written X*fps frames. If we've written - * more - drop, if we've written less - dup... */ - if (v4l2src->handled * (GST_SECOND/fps) - time > - 1.5 * (GST_SECOND/fps)) { - /* yo dude, we've got too many frames here! Drop! DROP! */ - v4l2src->need_writes--; /* -= (v4l2src->handled - (time / fps)); */ - g_signal_emit(G_OBJECT(v4l2src), - gst_v4l2src_signals[SIGNAL_FRAME_DROP], 0); - } else if (v4l2src->handled * (GST_SECOND/fps) - time < - -1.5 * (GST_SECOND/fps)) { - /* this means we're lagging far behind */ - v4l2src->need_writes++; /* += ((time / fps) - v4l2src->handled); */ - g_signal_emit(G_OBJECT(v4l2src), - gst_v4l2src_signals[SIGNAL_FRAME_INSERT], 0); - } - - if (v4l2src->need_writes > 0) { - have_frame = TRUE; - v4l2src->use_num_times[num] = v4l2src->need_writes; - v4l2src->need_writes--; - } else { - gst_v4l2src_requeue_frame(v4l2src, num); - } - } while (!have_frame); + have_frame = TRUE; + v4l2src->need_writes--; } else { - /* grab a frame from the device */ - if (!gst_v4l2src_grab_frame(v4l2src, &num)) - return NULL; - - v4l2src->use_num_times[num] = 1; + if (!gst_v4l2src_queue_frame(v4l2src, num)) + return NULL; + num = gst_v4l2src_grab_frame(v4l2src); + if (num == -1) + return NULL; } + } while (!have_frame); + } + + g_assert (num != -1); + GST_LOG_OBJECT (v4l2src, "buffer %d needs %d writes", num, v4l2src->need_writes + 1); + i = v4l2src->pool->buffers[num].buffer.bytesused > 0 ? + v4l2src->pool->buffers[num].buffer.bytesused : + v4l2src->pool->buffers[num].length; + /* check if this is the last buffer in the queue. If so do a memcpy to put it back asap + to avoid framedrops and deadlocks because of stupid elements */ + if (gst_atomic_int_read (&v4l2src->pool->refcount) == v4l2src->breq.count) { + GST_LOG_OBJECT (v4l2src, "using memcpy'd buffer"); + buf = gst_buffer_new_and_alloc (i); + memcpy (GST_BUFFER_DATA (buf), v4l2src->pool->buffers[num].start, i); + if (!gst_v4l2src_queue_frame(v4l2src, num)) { + gst_data_unref (GST_DATA (buf)); + return NULL; + } + } else { + GST_LOG_OBJECT (v4l2src, "using mmap'd buffer"); + buf = gst_buffer_new (); + GST_BUFFER_DATA (buf) = v4l2src->pool->buffers[num].start; + GST_BUFFER_SIZE (buf) = i; + GST_BUFFER_FREE_DATA_FUNC (buf) = gst_v4l2src_free_buffer; + GST_BUFFER_PRIVATE (buf) = &v4l2src->pool->buffers[num]; + /* no need to be careful here, both are > 0, because the element uses them */ + gst_atomic_int_inc (&v4l2src->pool->buffers[num].refcount); + gst_atomic_int_inc (&v4l2src->pool->refcount); + } + GST_BUFFER_MAXSIZE (buf) = v4l2src->pool->buffers[num].length; + if (v4l2src->use_fixed_fps) { + GST_BUFFER_TIMESTAMP (buf) = v4l2src->handled * GST_SECOND / fps; + GST_BUFFER_DURATION (buf) = GST_SECOND / fps; + } else { + /* calculate time based on our own clock */ + GST_BUFFER_TIMESTAMP(buf) = GST_TIMEVAL_TO_TIME(v4l2src->pool->buffers[num].buffer.timestamp) - + v4l2src->substract_time; + } + if (v4l2src->need_writes > 0) { + v4l2src->cached_buffer = buf; + for (i = 0; i < v4l2src->need_writes; i++) { + gst_data_ref (GST_DATA (buf)); + } + } + } - buf = gst_buffer_new (); - GST_BUFFER_DATA(buf) = gst_v4l2src_get_buffer(v4l2src, num); - GST_BUFFER_SIZE(buf) = v4l2src->bufsettings.bytesused; - GST_BUFFER_FLAG_SET(buf, GST_BUFFER_READONLY); - if (v4l2src->use_fixed_fps) - GST_BUFFER_TIMESTAMP(buf) = v4l2src->handled * GST_SECOND / fps; - else /* calculate time based on our own clock */ - GST_BUFFER_TIMESTAMP(buf) = GST_TIMEVAL_TO_TIME(v4l2src->bufsettings.timestamp) - - v4l2src->substract_time; - - v4l2src->handled++; - g_signal_emit(G_OBJECT(v4l2src), - gst_v4l2src_signals[SIGNAL_FRAME_CAPTURE], 0); - - return GST_DATA (buf); -} + v4l2src->handled++; + g_signal_emit(G_OBJECT(v4l2src), gst_v4l2src_signals[SIGNAL_FRAME_CAPTURE], 0); + return GST_DATA (buf); +} static void gst_v4l2src_set_property (GObject *object, @@ -972,7 +1024,6 @@ gst_v4l2src_change_state (GstElement *element) case GST_STATE_READY_TO_PAUSED: v4l2src->handled = 0; v4l2src->need_writes = 0; - v4l2src->last_frame = 0; v4l2src->substract_time = 0; /* buffer setup moved to capsnego */ break; @@ -1013,60 +1064,3 @@ gst_v4l2src_set_clock (GstElement *element, GST_V4L2SRC(element)->clock = clock; } - -#if 0 -static GstBuffer* -gst_v4l2src_buffer_new (GstBufferPool *pool, - guint64 offset, - guint size, - gpointer user_data) -{ - GstBuffer *buffer; - GstV4l2Src *v4l2src = GST_V4L2SRC(user_data); - - if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) - return NULL; - - buffer = gst_buffer_new(); - if (!buffer) - return NULL; - - /* TODO: add interlacing info to buffer as metadata - * (height>288 or 240 = topfieldfirst, else noninterlaced) */ - GST_BUFFER_MAXSIZE(buffer) = v4l2src->bufsettings.length; - GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE); - - return buffer; -} -#endif - -#if 0 -static void -gst_v4l2src_buffer_free (GstBufferPool *pool, - GstBuffer *buf, - gpointer user_data) -{ - GstV4l2Src *v4l2src = GST_V4L2SRC(user_data); - int n; - - if (gst_element_get_state(GST_ELEMENT(v4l2src)) != GST_STATE_PLAYING) - return; /* we've already cleaned up ourselves */ - - for (n=0;nbreq.count;n++) - if (GST_BUFFER_DATA(buf) == gst_v4l2src_get_buffer(v4l2src, n)) { - v4l2src->use_num_times[n]--; - if (v4l2src->use_num_times[n] <= 0) { - gst_v4l2src_requeue_frame(v4l2src, n); - } - break; - } - - if (n == v4l2src->breq.count) - gst_element_error(GST_ELEMENT(v4l2src), - "Couldn\'t find the buffer"); - - /* free the buffer itself */ - gst_buffer_default_free(buf); -} -#endif - -- cgit v1.2.1