blob: dc5525edc4ac0c710d9e768937688942de264574 [file] [log] [blame] [edit]
/* GStreamer
* Copyright (C) 2022 <xuesong.jiang@amlogic.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
* Boston, MA 02110-1335, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gst/gst-i18n-plugin.h"
#include <gst/gst.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "ext/videodev2.h"
#include "aml-v4l2-utils.h"
#include "gstamlv4l2object.h"
#include "gstamlv4l2videodec.h"
/* used in gstamlv4l2object.c and aml_v4l2_calls.c */
GST_DEBUG_CATEGORY(aml_v4l2_debug);
#define GST_CAT_DEFAULT aml_v4l2_debug
#define DEFAULT_DEVICE_NAME "/dev/video26"
/* This is a minimalist probe, for speed, we only enumerate formats */
static GstCaps *
gst_aml_v4l2_probe_template_caps(const gchar *device, gint video_fd,
enum v4l2_buf_type type)
{
gint n;
struct v4l2_fmtdesc format;
GstCaps *caps;
GST_DEBUG ("Getting %s format enumerations", device);
caps = gst_caps_new_empty ();
for (n = 0;; n++)
{
GstStructure *template;
memset (&format, 0, sizeof (format));
format.index = n;
format.type = type;
if (ioctl (video_fd, VIDIOC_ENUM_FMT, &format) < 0)
break; /* end of enumeration */
GST_LOG ("index: %u", format.index);
GST_LOG ("type: %d", format.type);
GST_LOG ("flags: %08x", format.flags);
GST_LOG ("description: '%s'", format.description);
GST_LOG ("pixelformat: %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (format.pixelformat));
template = gst_aml_v4l2_object_v4l2fourcc_to_structure(format.pixelformat);
if (template)
{
GstStructure *alt_t = NULL;
switch (format.pixelformat)
{
case V4L2_PIX_FMT_RGB32:
alt_t = gst_structure_copy (template);
gst_structure_set (alt_t, "format", G_TYPE_STRING, "ARGB", NULL);
break;
case V4L2_PIX_FMT_BGR32:
alt_t = gst_structure_copy (template);
gst_structure_set (alt_t, "format", G_TYPE_STRING, "BGRA", NULL);
default:
break;
}
gst_caps_append_structure (caps, template);
if (alt_t)
gst_caps_append_structure (caps, alt_t);
}
}
return gst_caps_simplify (caps);
}
static gboolean
gst_aml_v4l2_register(GstPlugin *plugin)
{
gint video_fd = -1;
struct v4l2_capability vcap;
guint32 device_caps;
GstCaps *src_caps, *sink_caps;
GST_DEBUG("regist aml v4l2 device");
GST_DEBUG("open: %s", DEFAULT_DEVICE_NAME);
video_fd = open(DEFAULT_DEVICE_NAME, O_RDWR | O_CLOEXEC);
if (video_fd == -1)
{
GST_DEBUG("Failed to open %s: %s", DEFAULT_DEVICE_NAME, g_strerror(errno));
goto error_tag;
}
memset(&vcap, 0, sizeof(vcap));
if (ioctl(video_fd, VIDIOC_QUERYCAP, &vcap) < 0)
{
GST_DEBUG("Failed to get device capabilities: %s", g_strerror(errno));
goto error_tag;
}
if (vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
device_caps = vcap.device_caps;
else
device_caps = vcap.capabilities;
if (!GST_AML_V4L2_IS_M2M(device_caps)) {
goto error_tag;
}
/* get sink supported format (no MPLANE for codec) */
sink_caps = gst_caps_merge(gst_aml_v4l2_probe_template_caps(DEFAULT_DEVICE_NAME,
video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT),
gst_aml_v4l2_probe_template_caps(DEFAULT_DEVICE_NAME, video_fd,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE));
GST_DEBUG ("prob sink_caps %" GST_PTR_FORMAT, sink_caps);
/* get src supported format */
src_caps = gst_caps_merge(gst_aml_v4l2_probe_template_caps(DEFAULT_DEVICE_NAME,
video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE),
gst_aml_v4l2_probe_template_caps(DEFAULT_DEVICE_NAME, video_fd,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE));
GST_DEBUG ("prob src_caps %" GST_PTR_FORMAT, src_caps);
/* Skip devices without any supported formats */
if (gst_caps_is_empty(sink_caps) || gst_caps_is_empty(src_caps))
{
gst_caps_unref(sink_caps);
gst_caps_unref(src_caps);
goto error_tag;
}
/* Caps won't be freed if the subclass is not instantiated */
GST_MINI_OBJECT_FLAG_SET(sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
GST_MINI_OBJECT_FLAG_SET(src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
if (gst_aml_v4l2_is_video_dec(sink_caps, src_caps))
{
gst_aml_v4l2_video_dec_register(plugin, DEFAULT_DEVICE_NAME, DEFAULT_DEVICE_NAME,
sink_caps, src_caps);
}
gst_caps_unref(sink_caps);
gst_caps_unref(src_caps);
if (video_fd >= 0)
close (video_fd);
return TRUE;
error_tag:
if (video_fd >= 0)
close (video_fd);
return FALSE;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
//const gchar *paths[] = {"/dev", "/dev/v4l2", NULL};
//const gchar *names[] = {"video", NULL};
GST_DEBUG_CATEGORY_INIT(aml_v4l2_debug, "amlv4l2", 0, "aml V4L2 API calls");
/* Add some depedency, so the dynamic features get updated upon changes in
* /dev/video* */
//gst_plugin_add_dependency(plugin,
// NULL, paths, names, GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX);
if (!gst_aml_v4l2_register(plugin))
return FALSE;
return TRUE;
}
#ifndef VERSION
#define VERSION "0.1.0"
#endif
#ifndef PACKAGE
#define PACKAGE "aml_package"
#endif
#ifndef PACKAGE_NAME
#define PACKAGE_NAME "aml_media"
#endif
#ifndef GST_PACKAGE_ORIGIN
#define GST_PACKAGE_ORIGIN "http://amlogic.com"
#endif
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
GST_VERSION_MINOR,
amlv4l2,
"aml element for Video 4 Linux decoder",
plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)