v4l2object: Workaround bad TRY_FMT colorimetry implementation
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / gstv4l2object.c
index 9b50c16..8c3c95b 100644 (file)
@@ -158,10 +158,10 @@ static const GstV4L2FormatDesc gst_v4l2_formats[] = {
   {V4L2_PIX_FMT_NV42, TRUE, GST_V4L2_RAW},
 
   /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
-  {V4L2_PIX_FMT_SBGGR8, TRUE, GST_V4L2_CODEC},
-  {V4L2_PIX_FMT_SGBRG8, TRUE, GST_V4L2_CODEC},
-  {V4L2_PIX_FMT_SGRBG8, TRUE, GST_V4L2_CODEC},
-  {V4L2_PIX_FMT_SRGGB8, TRUE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_SBGGR8, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_SGBRG8, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_SGRBG8, TRUE, GST_V4L2_RAW},
+  {V4L2_PIX_FMT_SRGGB8, TRUE, GST_V4L2_RAW},
 
   /* compressed formats */
   {V4L2_PIX_FMT_MJPEG, FALSE, GST_V4L2_CODEC},
@@ -169,9 +169,11 @@ static const GstV4L2FormatDesc gst_v4l2_formats[] = {
   {V4L2_PIX_FMT_PJPG, FALSE, GST_V4L2_CODEC},
   {V4L2_PIX_FMT_DV, FALSE, GST_V4L2_TRANSPORT},
   {V4L2_PIX_FMT_MPEG, FALSE, GST_V4L2_TRANSPORT},
+  {V4L2_PIX_FMT_FWHT, FALSE, GST_V4L2_CODEC},
   {V4L2_PIX_FMT_H264, FALSE, GST_V4L2_CODEC},
   {V4L2_PIX_FMT_H264_NO_SC, FALSE, GST_V4L2_CODEC},
   {V4L2_PIX_FMT_H264_MVC, FALSE, GST_V4L2_CODEC},
+  {V4L2_PIX_FMT_HEVC, FALSE, GST_V4L2_CODEC},
   {V4L2_PIX_FMT_H263, FALSE, GST_V4L2_CODEC},
   {V4L2_PIX_FMT_MPEG1, FALSE, GST_V4L2_CODEC},
   {V4L2_PIX_FMT_MPEG2, FALSE, GST_V4L2_CODEC},
@@ -1386,6 +1388,10 @@ gst_v4l2_object_v4l2fourcc_is_rgb (guint32 fourcc)
     case V4L2_PIX_FMT_BGR32:
     case V4L2_PIX_FMT_ABGR32:
     case V4L2_PIX_FMT_ARGB32:
+    case V4L2_PIX_FMT_SBGGR8:
+    case V4L2_PIX_FMT_SGBRG8:
+    case V4L2_PIX_FMT_SGRBG8:
+    case V4L2_PIX_FMT_SRGGB8:
       ret = TRUE;
       break;
     default:
@@ -1408,7 +1414,7 @@ gst_v4l2_object_v4l2fourcc_to_bare_struct (guint32 fourcc)
       break;
     case V4L2_PIX_FMT_MPEG1:
       structure = gst_structure_new ("video/mpeg",
-          "mpegversion", G_TYPE_INT, 2, NULL);
+          "mpegversion", G_TYPE_INT, 1, NULL);
       break;
     case V4L2_PIX_FMT_MPEG2:
       structure = gst_structure_new ("video/mpeg",
@@ -1420,6 +1426,9 @@ gst_v4l2_object_v4l2fourcc_to_bare_struct (guint32 fourcc)
           "mpegversion", G_TYPE_INT, 4, "systemstream",
           G_TYPE_BOOLEAN, FALSE, NULL);
       break;
+    case V4L2_PIX_FMT_FWHT:
+      structure = gst_structure_new_empty ("video/x-fwht");
+      break;
     case V4L2_PIX_FMT_H263:
       structure = gst_structure_new ("video/x-h263",
           "variant", G_TYPE_STRING, "itu", NULL);
@@ -1434,6 +1443,11 @@ gst_v4l2_object_v4l2fourcc_to_bare_struct (guint32 fourcc)
           "stream-format", G_TYPE_STRING, "avc", "alignment",
           G_TYPE_STRING, "au", NULL);
       break;
+    case V4L2_PIX_FMT_HEVC:    /* H.265 */
+      structure = gst_structure_new ("video/x-h265",
+          "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
+          G_TYPE_STRING, "au", NULL);
+      break;
     case V4L2_PIX_FMT_VC1_ANNEX_G:
     case V4L2_PIX_FMT_VC1_ANNEX_L:
       structure = gst_structure_new ("video/x-wmv",
@@ -1801,6 +1815,8 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
             break;
         }
       }
+    } else if (g_str_equal (mimetype, "video/x-fwht")) {
+      fourcc = V4L2_PIX_FMT_FWHT;
     } else if (g_str_equal (mimetype, "video/x-h263")) {
       fourcc = V4L2_PIX_FMT_H263;
     } else if (g_str_equal (mimetype, "video/x-h264")) {
@@ -1810,6 +1826,8 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
         fourcc = V4L2_PIX_FMT_H264_NO_SC;
       else
         fourcc = V4L2_PIX_FMT_H264;
+    } else if (g_str_equal (mimetype, "video/x-h265")) {
+      fourcc = V4L2_PIX_FMT_HEVC;
     } else if (g_str_equal (mimetype, "video/x-vp8")) {
       fourcc = V4L2_PIX_FMT_VP8;
     } else if (g_str_equal (mimetype, "video/x-vp9")) {
@@ -1909,8 +1927,6 @@ static gboolean
 gst_v4l2_object_get_interlace_mode (enum v4l2_field field,
     GstVideoInterlaceMode * interlace_mode)
 {
-  /* NB: If you add new return values, please fix mode_strings in
-   * gst_v4l2_object_add_interlace_mode */
   switch (field) {
     case V4L2_FIELD_ANY:
       GST_ERROR
@@ -1975,7 +1991,7 @@ gst_v4l2_object_get_colorspace (struct v4l2_format *fmt,
       cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
       cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
       break;
-    case V4L2_COLORSPACE_ADOBERGB:
+    case V4L2_COLORSPACE_OPRGB:
       cinfo->range = GST_VIDEO_COLOR_RANGE_16_235;
       cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601;
       cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
@@ -2094,7 +2110,7 @@ gst_v4l2_object_get_colorspace (struct v4l2_format *fmt,
     case V4L2_XFER_FUNC_SRGB:
       cinfo->transfer = GST_VIDEO_TRANSFER_SRGB;
       break;
-    case V4L2_XFER_FUNC_ADOBERGB:
+    case V4L2_XFER_FUNC_OPRGB:
       cinfo->transfer = GST_VIDEO_TRANSFER_ADOBERGB;
       break;
     case V4L2_XFER_FUNC_SMPTE240M:
@@ -2154,13 +2170,10 @@ gst_v4l2_object_add_interlace_mode (GstV4l2Object * v4l2object,
 {
   struct v4l2_format fmt;
   GValue interlace_formats = { 0, };
+  enum v4l2_field formats[] = { V4L2_FIELD_NONE, V4L2_FIELD_INTERLACED };
+  gsize i;
   GstVideoInterlaceMode interlace_mode, prev = -1;
 
-  const gchar *mode_strings[] = { "progressive",
-    "interleaved",
-    "mixed"
-  };
-
   if (!g_str_equal (gst_structure_get_name (s), "video/x-raw"))
     return;
 
@@ -2172,36 +2185,26 @@ gst_v4l2_object_add_interlace_mode (GstV4l2Object * v4l2object,
   g_value_init (&interlace_formats, GST_TYPE_LIST);
 
   /* Try twice - once for NONE, once for INTERLACED. */
-  memset (&fmt, 0, sizeof (fmt));
-  fmt.type = v4l2object->type;
-  fmt.fmt.pix.width = width;
-  fmt.fmt.pix.height = height;
-  fmt.fmt.pix.pixelformat = pixelformat;
-  fmt.fmt.pix.field = V4L2_FIELD_NONE;
-
-  if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0 &&
-      gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode)) {
-    GValue interlace_enum = { 0, };
-    g_value_init (&interlace_enum, G_TYPE_STRING);
-    g_value_set_string (&interlace_enum, mode_strings[interlace_mode]);
-    gst_value_list_append_and_take_value (&interlace_formats, &interlace_enum);
-    prev = interlace_mode;
-  }
-
-  memset (&fmt, 0, sizeof (fmt));
-  fmt.type = v4l2object->type;
-  fmt.fmt.pix.width = width;
-  fmt.fmt.pix.height = height;
-  fmt.fmt.pix.pixelformat = pixelformat;
-  fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
-
-  if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0 &&
-      gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode) &&
-      prev != interlace_mode) {
-    GValue interlace_enum = { 0, };
-    g_value_init (&interlace_enum, G_TYPE_STRING);
-    g_value_set_string (&interlace_enum, mode_strings[interlace_mode]);
-    gst_value_list_append_and_take_value (&interlace_formats, &interlace_enum);
+  for (i = 0; i < G_N_ELEMENTS (formats); i++) {
+    memset (&fmt, 0, sizeof (fmt));
+    fmt.type = v4l2object->type;
+    fmt.fmt.pix.width = width;
+    fmt.fmt.pix.height = height;
+    fmt.fmt.pix.pixelformat = pixelformat;
+    fmt.fmt.pix.field = formats[i];
+
+    if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0 &&
+        gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode)
+        && prev != interlace_mode) {
+      GValue interlace_enum = { 0, };
+      const gchar *mode_string;
+      g_value_init (&interlace_enum, G_TYPE_STRING);
+      mode_string = gst_video_interlace_mode_to_string (interlace_mode);
+      g_value_set_string (&interlace_enum, mode_string);
+      gst_value_list_append_and_take_value (&interlace_formats,
+          &interlace_enum);
+      prev = interlace_mode;
+    }
   }
 
   if (gst_v4l2src_value_simplify (&interlace_formats)
@@ -3205,11 +3208,13 @@ gst_v4l2_video_colorimetry_matches (const GstVideoColorimetry * cinfo,
 {
   GstVideoColorimetry ci;
   static const GstVideoColorimetry ci_likely_jpeg = {
-      GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
-      GST_VIDEO_TRANSFER_UNKNOWN, GST_VIDEO_COLOR_PRIMARIES_UNKNOWN };
+    GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
+    GST_VIDEO_TRANSFER_UNKNOWN, GST_VIDEO_COLOR_PRIMARIES_UNKNOWN
+  };
   static const GstVideoColorimetry ci_jpeg = {
-      GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
-      GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT709 };
+    GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601,
+    GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT709
+  };
 
   if (!gst_video_colorimetry_from_string (&ci, color))
     return FALSE;
@@ -3246,6 +3251,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
   enum v4l2_ycbcr_encoding matrix = 0;
   enum v4l2_xfer_func transfer = 0;
   GstStructure *s;
+  gboolean disable_colorimetry = FALSE;
 
   g_return_val_if_fail (!v4l2object->skip_try_fmt_probes ||
       gst_caps_is_writable (caps), FALSE);
@@ -3567,23 +3573,35 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps,
   if (is_mplane && format.fmt.pix_mp.num_planes != n_v4l_planes)
     goto invalid_planes;
 
-  if ((is_mplane && format.fmt.pix_mp.field != field)
-      || format.fmt.pix.field != field)
-    goto invalid_field;
+  /* used to check colorimetry and interlace mode fields presence */
+  s = gst_caps_get_structure (caps, 0);
 
-  gst_v4l2_object_get_colorspace (&format, &info.colorimetry);
+  if (!gst_v4l2_object_get_interlace_mode (format.fmt.pix.field,
+          &info.interlace_mode))
+    goto invalid_field;
+  if (gst_structure_has_field (s, "interlace-mode")) {
+    if (format.fmt.pix.field != field)
+      goto invalid_field;
+  }
 
-  s = gst_caps_get_structure (caps, 0);
-  if (gst_structure_has_field (s, "colorimetry")) {
-    if (!gst_v4l2_video_colorimetry_matches (&info.colorimetry,
-            gst_structure_get_string (s, "colorimetry")))
-      goto invalid_colorimetry;
+  if (gst_v4l2_object_get_colorspace (&format, &info.colorimetry)) {
+    if (gst_structure_has_field (s, "colorimetry")) {
+      if (!gst_v4l2_video_colorimetry_matches (&info.colorimetry,
+              gst_structure_get_string (s, "colorimetry")))
+        goto invalid_colorimetry;
+    }
+  } else {
+    /* The driver (or libv4l2) is miss-behaving, just ignore colorimetry from
+     * the TRY_FMT */
+    disable_colorimetry = TRUE;
+    if (gst_structure_has_field (s, "colorimetry"))
+      gst_structure_remove_field (s, "colorimetry");
   }
 
   /* In case we have skipped the try_fmt probes, we'll need to set the
    * colorimetry and interlace-mode back into the caps. */
   if (v4l2object->skip_try_fmt_probes) {
-    if (!gst_structure_has_field (s, "colorimetry")) {
+    if (!disable_colorimetry && !gst_structure_has_field (s, "colorimetry")) {
       gchar *str = gst_video_colorimetry_to_string (&info.colorimetry);
       gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL);
       g_free (str);
@@ -4148,9 +4166,11 @@ gst_v4l2_object_stop (GstV4l2Object * v4l2object)
     goto done;
 
   if (v4l2object->pool) {
-    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "deactivating pool");
-    gst_buffer_pool_set_active (v4l2object->pool, FALSE);
-    gst_object_unref (v4l2object->pool);
+    if (!gst_v4l2_buffer_pool_orphan (&v4l2object->pool)) {
+      GST_DEBUG_OBJECT (v4l2object->dbg_obj, "deactivating pool");
+      gst_buffer_pool_set_active (v4l2object->pool, FALSE);
+      gst_object_unref (v4l2object->pool);
+    }
     v4l2object->pool = NULL;
   }
 
@@ -4182,7 +4202,7 @@ gst_v4l2_object_probe_caps (GstV4l2Object * v4l2object, GstCaps * filter)
         GST_WARNING_OBJECT (v4l2object->dbg_obj,
             "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",
             g_strerror (errno));
-    } else {
+    } else if (cropcap.pixelaspect.numerator && cropcap.pixelaspect.denominator) {
       v4l2object->par = g_new0 (GValue, 1);
       g_value_init (v4l2object->par, GST_TYPE_FRACTION);
       gst_value_set_fraction (v4l2object->par, cropcap.pixelaspect.numerator,
@@ -4555,8 +4575,16 @@ gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query)
   if (caps == NULL)
     goto no_caps;
 
-  if ((pool = obj->pool))
-    gst_object_ref (pool);
+  switch (obj->mode) {
+    case GST_V4L2_IO_MMAP:
+    case GST_V4L2_IO_DMABUF:
+      if ((pool = obj->pool))
+        gst_object_ref (pool);
+      break;
+    default:
+      pool = NULL;
+      break;
+  }
 
   if (pool != NULL) {
     GstCaps *pcaps;