diff --git a/sys/v4l2/Makefile.am b/sys/v4l2/Makefile.am index e4099bc4a5..1c311018b8 100644 --- a/sys/v4l2/Makefile.am +++ b/sys/v4l2/Makefile.am @@ -5,6 +5,7 @@ include $(top_srcdir)/common/gst-glib-gen.mak libgstvideo4linux2_la_SOURCES = gstv4l2.c \ gstv4l2allocator.c \ gstv4l2colorbalance.c \ + gstv4l2codec.c \ gstv4l2deviceprovider.c \ gstv4l2object.c \ gstv4l2bufferpool.c \ @@ -18,11 +19,16 @@ libgstvideo4linux2_la_SOURCES = gstv4l2.c \ gstv4l2fwhtenc.c \ gstv4l2h263enc.c \ gstv4l2h264enc.c \ + gstv4l2h264codec.c \ + gstv4l2h265codec.c \ gstv4l2h265enc.c \ gstv4l2jpegenc.c \ gstv4l2mpeg4enc.c \ + gstv4l2mpeg4codec.c \ gstv4l2vidorient.c \ + gstv4l2vp8codec.c \ gstv4l2vp8enc.c \ + gstv4l2vp9codec.c \ gstv4l2vp9enc.c \ v4l2_calls.c \ v4l2-utils.c \ @@ -64,14 +70,20 @@ noinst_HEADERS = \ gstv4l2transform.h \ gstv4l2videodec.h \ gstv4l2videoenc.h \ + gstv4l2codec.h \ gstv4l2fwhtenc.h \ + gstv4l2h264codec.h \ gstv4l2h263enc.h \ gstv4l2h264enc.h \ + gstv4l2h265codec.h \ gstv4l2h265enc.h \ gstv4l2jpegenc.h \ gstv4l2mpeg4enc.h \ + gstv4l2mpeg4codec.h \ gstv4l2vidorient.h \ + gstv4l2vp8codec.h \ gstv4l2vp8enc.h \ + gstv4l2vp9codec.h \ gstv4l2vp9enc.h \ v4l2-utils.h \ tuner.h \ diff --git a/sys/v4l2/gstv4l2.c b/sys/v4l2/gstv4l2.c index c2c1d21b21..e1888804d2 100644 --- a/sys/v4l2/gstv4l2.c +++ b/sys/v4l2/gstv4l2.c @@ -192,7 +192,7 @@ gst_v4l2_probe_and_register (GstPlugin * plugin) if (gst_v4l2_is_video_dec (sink_caps, src_caps)) { gst_v4l2_video_dec_register (plugin, basename, it->device_path, - sink_caps, src_caps); + video_fd, sink_caps, src_caps); } else if (gst_v4l2_is_video_enc (sink_caps, src_caps, NULL)) { if (gst_v4l2_is_fwht_enc (sink_caps, src_caps)) gst_v4l2_fwht_enc_register (plugin, basename, it->device_path, @@ -200,15 +200,15 @@ gst_v4l2_probe_and_register (GstPlugin * plugin) if (gst_v4l2_is_h264_enc (sink_caps, src_caps)) gst_v4l2_h264_enc_register (plugin, basename, it->device_path, - sink_caps, src_caps); + video_fd, sink_caps, src_caps); if (gst_v4l2_is_h265_enc (sink_caps, src_caps)) gst_v4l2_h265_enc_register (plugin, basename, it->device_path, - sink_caps, src_caps); + video_fd, sink_caps, src_caps); if (gst_v4l2_is_mpeg4_enc (sink_caps, src_caps)) gst_v4l2_mpeg4_enc_register (plugin, basename, it->device_path, - sink_caps, src_caps); + video_fd, sink_caps, src_caps); if (gst_v4l2_is_h263_enc (sink_caps, src_caps)) gst_v4l2_h263_enc_register (plugin, basename, it->device_path, @@ -220,11 +220,11 @@ gst_v4l2_probe_and_register (GstPlugin * plugin) if (gst_v4l2_is_vp8_enc (sink_caps, src_caps)) gst_v4l2_vp8_enc_register (plugin, basename, it->device_path, - sink_caps, src_caps); + video_fd, sink_caps, src_caps); if (gst_v4l2_is_vp9_enc (sink_caps, src_caps)) gst_v4l2_vp9_enc_register (plugin, basename, it->device_path, - sink_caps, src_caps); + video_fd, sink_caps, src_caps); } else if (gst_v4l2_is_transform (sink_caps, src_caps)) { gst_v4l2_transform_register (plugin, basename, it->device_path, sink_caps, src_caps); diff --git a/sys/v4l2/gstv4l2codec.c b/sys/v4l2/gstv4l2codec.c new file mode 100644 index 0000000000..696ba3c052 --- /dev/null +++ b/sys/v4l2/gstv4l2codec.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2019 Igalia S.L. + * Author: Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "gstv4l2codec.h" +#include "ext/videodev2.h" + +#include + +static GValue * +probe_controls (gint video_fd, guint32 cid, + const gchar * (transform_control) (gint)) +{ + GValue *controls = NULL; + struct v4l2_queryctrl query_ctrl; + + memset (&query_ctrl, 0, sizeof (query_ctrl)); + query_ctrl.id = cid; + + if (ioctl (video_fd, VIDIOC_QUERYCTRL, &query_ctrl) == 0) { + if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED) { + return NULL; + } + + if (query_ctrl.type == V4L2_CTRL_TYPE_MENU) { + struct v4l2_querymenu query_menu; + + memset (&query_menu, 0, sizeof (query_menu)); + query_menu.id = query_ctrl.id; + + controls = g_new0 (GValue, 1); + g_value_init (controls, GST_TYPE_LIST); + for (query_menu.index = query_ctrl.minimum; + query_menu.index <= query_ctrl.maximum; query_menu.index++) { + if (ioctl (video_fd, VIDIOC_QUERYMENU, &query_menu) >= 0) { + GValue value = G_VALUE_INIT; + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, transform_control (query_menu.index)); + gst_value_list_append_and_take_value (controls, &value); + } + } + if (gst_value_list_get_size (controls) == 0) { + g_value_unset (controls); + controls = NULL; + } + } + } + + return controls; +} + +GValue * +gst_v4l2_codec_probe_profiles (const GstV4l2Codec * codec, gint video_fd) +{ + return probe_controls (video_fd, codec->profile_cid, + codec->profile_to_string); +} + +GValue * +gst_v4l2_codec_probe_levels (const GstV4l2Codec * codec, gint video_fd) +{ + GValue *controls = NULL; + struct v4l2_queryctrl query_ctrl; + + memset (&query_ctrl, 0, sizeof (query_ctrl)); + query_ctrl.id = codec->level_cid; + + if (ioctl (video_fd, VIDIOC_QUERYCTRL, &query_ctrl) == 0) { + if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED) { + return NULL; + } + + if (query_ctrl.type == V4L2_CTRL_TYPE_MENU) { + struct v4l2_querymenu query_menu; + + memset (&query_menu, 0, sizeof (query_menu)); + query_menu.id = query_ctrl.id; + query_menu.index = query_ctrl.maximum; + + if (ioctl (video_fd, VIDIOC_QUERYMENU, &query_menu) >= 0) { + controls = g_new0 (GValue, 1); + g_value_init (controls, GST_TYPE_LIST); + + /* Assume that all levels below the highest one reported by the driver are supported. */ + for (gint32 i = query_ctrl.minimum; i <= query_ctrl.maximum; i++) { + GValue value = G_VALUE_INIT; + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, codec->level_to_string (i)); + gst_value_list_append_and_take_value (controls, &value); + } + } + } + } + + return controls; +} diff --git a/sys/v4l2/gstv4l2codec.h b/sys/v4l2/gstv4l2codec.h new file mode 100644 index 0000000000..47161dc9ca --- /dev/null +++ b/sys/v4l2/gstv4l2codec.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2017 Collabora Inc. + * Author: Nicolas Dufresne + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __GST_V4L2_CODEC_H__ +#define __GST_V4L2_CODEC_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstV4l2Codec GstV4l2Codec; + +struct _GstV4l2Codec { + guint32 profile_cid; + const gchar * (*profile_to_string) (gint v4l2_profile); + gint (*profile_from_string) (const gchar * profile); + + guint32 level_cid; + const gchar * (*level_to_string) (gint v4l2_level); + gint (*level_from_string) (const gchar * level); + +}; + +GValue * gst_v4l2_codec_probe_profiles(const GstV4l2Codec * codec, gint video_fd); +GValue * gst_v4l2_codec_probe_levels(const GstV4l2Codec * codec, gint video_fd); + +G_END_DECLS + +#endif /* __GST_V4L2_CODEC_H__ */ diff --git a/sys/v4l2/gstv4l2fwhtenc.c b/sys/v4l2/gstv4l2fwhtenc.c index 9be9eca2f0..973993ec42 100644 --- a/sys/v4l2/gstv4l2fwhtenc.c +++ b/sys/v4l2/gstv4l2fwhtenc.c @@ -114,6 +114,6 @@ gst_v4l2_fwht_enc_register (GstPlugin * plugin, const gchar * basename, const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps) { gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_FWHT_ENC, - "fwht", basename, device_path, sink_caps, + "fwht", basename, device_path, NULL, -1, sink_caps, gst_static_caps_get (&src_template_caps), src_caps); } diff --git a/sys/v4l2/gstv4l2h263enc.c b/sys/v4l2/gstv4l2h263enc.c index e29fa648f1..b930986eae 100644 --- a/sys/v4l2/gstv4l2h263enc.c +++ b/sys/v4l2/gstv4l2h263enc.c @@ -111,6 +111,6 @@ gst_v4l2_h263_enc_register (GstPlugin * plugin, const gchar * basename, const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps) { gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_H263_ENC, - "h263", basename, device_path, sink_caps, + "h263", basename, device_path, NULL, -1, sink_caps, gst_static_caps_get (&src_template_caps), src_caps); } diff --git a/sys/v4l2/gstv4l2h264codec.c b/sys/v4l2/gstv4l2h264codec.c new file mode 100644 index 0000000000..020c64c607 --- /dev/null +++ b/sys/v4l2/gstv4l2h264codec.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2017 Collabora Inc. + * Author: Nicolas Dufresne + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstv4l2h264codec.h" + +#include +#include "ext/v4l2-controls.h" + + +static gint +v4l2_profile_from_string (const gchar * profile) +{ + gint v4l2_profile = -1; + + if (g_str_equal (profile, "baseline")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + } else if (g_str_equal (profile, "constrained-baseline")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE; + } else if (g_str_equal (profile, "main")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; + } else if (g_str_equal (profile, "extended")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED; + } else if (g_str_equal (profile, "high")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + } else if (g_str_equal (profile, "high-10")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10; + } else if (g_str_equal (profile, "high-4:2:2")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422; + } else if (g_str_equal (profile, "high-4:4:4")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE; + } else if (g_str_equal (profile, "high-10-intra")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA; + } else if (g_str_equal (profile, "high-4:2:2-intra")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA; + } else if (g_str_equal (profile, "high-4:4:4-intra")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA; + } else if (g_str_equal (profile, "cavlc-4:4:4-intra")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA; + } else if (g_str_equal (profile, "scalable-baseline")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE; + } else if (g_str_equal (profile, "scalable-high")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH; + } else if (g_str_equal (profile, "scalable-high-intra")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA; + } else if (g_str_equal (profile, "stereo-high")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH; + } else if (g_str_equal (profile, "multiview-high")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH; + } else { + GST_WARNING ("Unsupported profile string '%s'", profile); + } + + return v4l2_profile; +} + +static const gchar * +v4l2_profile_to_string (gint v4l2_profile) +{ + switch (v4l2_profile) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + return "baseline"; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + return "constrained-baseline"; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + return "main"; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + return "extended"; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + return "high"; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: + return "high-10"; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: + return "high-4:2:2"; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: + return "high-4:4:4"; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA: + return "high-10-intra"; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA: + return "high-4:2:2-intra"; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA: + return "high-4:4:4-intra"; + case V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA: + return "cavlc-4:4:4-intra"; + case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE: + return "scalable-baseline"; + case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH: + return "scalable-high"; + case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA: + return "scalable-high-intra"; + case V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH: + return "stereo-high"; + case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH: + return "multiview-high"; + default: + GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); + break; + } + + return NULL; +} + +static gint +v4l2_level_from_string (const gchar * level) +{ + gint v4l2_level = -1; + + if (g_str_equal (level, "1")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0; + else if (g_str_equal (level, "1b")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1B; + else if (g_str_equal (level, "1.1")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_1; + else if (g_str_equal (level, "1.2")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_2; + else if (g_str_equal (level, "1.3")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_3; + else if (g_str_equal (level, "2")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_0; + else if (g_str_equal (level, "2.1")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_1; + else if (g_str_equal (level, "2.2")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_2; + else if (g_str_equal (level, "3")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_0; + else if (g_str_equal (level, "3.1")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_1; + else if (g_str_equal (level, "3.2")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_2; + else if (g_str_equal (level, "4")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; + else if (g_str_equal (level, "4.1")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; + else if (g_str_equal (level, "4.2")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2; + else if (g_str_equal (level, "5")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0; + else if (g_str_equal (level, "5.1")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1; + else + GST_WARNING ("Unsupported level '%s'", level); + + return v4l2_level; +} + +static const gchar * +v4l2_level_to_string (gint v4l2_level) +{ + switch (v4l2_level) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return "1"; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return "1b"; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return "1.1"; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return "1.2"; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return "1.3"; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return "2"; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return "2.1"; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return "2.2"; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return "3.0"; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return "3.1"; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return "3.2"; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return "4"; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return "4.1"; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return "4.2"; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return "5"; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + return "5.1"; + default: + GST_WARNING ("Unsupported V4L2 level %i", v4l2_level); + break; + } + + return NULL; +} + +const GstV4l2Codec * +gst_v4l2_h264_get_codec (void) +{ + static GstV4l2Codec *codec = NULL; + if (g_once_init_enter (&codec)) { + static GstV4l2Codec c; + c.profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE; + c.profile_to_string = v4l2_profile_to_string; + c.profile_from_string = v4l2_profile_from_string; + c.level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL; + c.level_to_string = v4l2_level_to_string; + c.level_from_string = v4l2_level_from_string; + g_once_init_leave (&codec, &c); + } + return codec; +} diff --git a/sys/v4l2/gstv4l2h264codec.h b/sys/v4l2/gstv4l2h264codec.h new file mode 100644 index 0000000000..001ac4005e --- /dev/null +++ b/sys/v4l2/gstv4l2h264codec.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 SUMOMO Computer Association. + * Author: ayaka + * Factored out from gstv4l2h264enc by Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __GST_V4L2_H264_CODEC_H__ +#define __GST_V4L2_H264_CODEC_H__ + +#include "gstv4l2codec.h" + +G_BEGIN_DECLS + +const GstV4l2Codec * gst_v4l2_h264_get_codec (void); + +G_END_DECLS + +#endif diff --git a/sys/v4l2/gstv4l2h264enc.c b/sys/v4l2/gstv4l2h264enc.c index ee160b3a02..535725ba4e 100644 --- a/sys/v4l2/gstv4l2h264enc.c +++ b/sys/v4l2/gstv4l2h264enc.c @@ -31,6 +31,7 @@ #include "gstv4l2object.h" #include "gstv4l2h264enc.h" +#include "gstv4l2h264codec.h" #include #include @@ -88,185 +89,6 @@ gst_v4l2_h264_enc_get_property (GObject * object, /* TODO */ } -static gint -v4l2_profile_from_string (const gchar * profile) -{ - gint v4l2_profile = -1; - - if (g_str_equal (profile, "baseline")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; - } else if (g_str_equal (profile, "constrained-baseline")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE; - } else if (g_str_equal (profile, "main")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; - } else if (g_str_equal (profile, "extended")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED; - } else if (g_str_equal (profile, "high")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; - } else if (g_str_equal (profile, "high-10")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10; - } else if (g_str_equal (profile, "high-4:2:2")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422; - } else if (g_str_equal (profile, "high-4:4:4")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE; - } else if (g_str_equal (profile, "high-10-intra")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA; - } else if (g_str_equal (profile, "high-4:2:2-intra")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA; - } else if (g_str_equal (profile, "high-4:4:4-intra")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA; - } else if (g_str_equal (profile, "cavlc-4:4:4-intra")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA; - } else if (g_str_equal (profile, "scalable-baseline")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE; - } else if (g_str_equal (profile, "scalable-high")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH; - } else if (g_str_equal (profile, "scalable-high-intra")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA; - } else if (g_str_equal (profile, "stereo-high")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH; - } else if (g_str_equal (profile, "multiview-high")) { - v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH; - } else { - GST_WARNING ("Unsupported profile string '%s'", profile); - } - - return v4l2_profile; -} - -static const gchar * -v4l2_profile_to_string (gint v4l2_profile) -{ - switch (v4l2_profile) { - case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: - return "baseline"; - case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: - return "constrained-baseline"; - case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: - return "main"; - case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: - return "extended"; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: - return "high"; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: - return "high-10"; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: - return "high-4:2:2"; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: - return "high-4:4:4"; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA: - return "high-10-intra"; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA: - return "high-4:2:2-intra"; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA: - return "high-4:4:4-intra"; - case V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA: - return "cavlc-4:4:4-intra"; - case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE: - return "scalable-baseline"; - case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH: - return "scalable-high"; - case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA: - return "scalable-high-intra"; - case V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH: - return "stereo-high"; - case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH: - return "multiview-high"; - default: - GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); - break; - } - - return NULL; -} - -static gint -v4l2_level_from_string (const gchar * level) -{ - gint v4l2_level = -1; - - if (g_str_equal (level, "1")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0; - else if (g_str_equal (level, "1b")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1B; - else if (g_str_equal (level, "1.1")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_1; - else if (g_str_equal (level, "1.2")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_2; - else if (g_str_equal (level, "1.3")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_3; - else if (g_str_equal (level, "2")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_0; - else if (g_str_equal (level, "2.1")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_1; - else if (g_str_equal (level, "2.2")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_2_2; - else if (g_str_equal (level, "3")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_0; - else if (g_str_equal (level, "3.1")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_1; - else if (g_str_equal (level, "3.2")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_3_2; - else if (g_str_equal (level, "4")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; - else if (g_str_equal (level, "4.1")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; - else if (g_str_equal (level, "4.2")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2; - else if (g_str_equal (level, "5")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0; - else if (g_str_equal (level, "5.1")) - v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1; - else - GST_WARNING ("Unsupported level '%s'", level); - - return v4l2_level; -} - -static const gchar * -v4l2_level_to_string (gint v4l2_level) -{ - switch (v4l2_level) { - case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: - return "1"; - case V4L2_MPEG_VIDEO_H264_LEVEL_1B: - return "1b"; - case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: - return "1.1"; - case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: - return "1.2"; - case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: - return "1.3"; - case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: - return "2"; - case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: - return "2.1"; - case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: - return "2.2"; - case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: - return "3.0"; - case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: - return "3.1"; - case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: - return "3.2"; - case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: - return "4"; - case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: - return "4.1"; - case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: - return "4.2"; - case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: - return "5"; - case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: - return "5.1"; - default: - GST_WARNING ("Unsupported V4L2 level %i", v4l2_level); - break; - } - - return NULL; -} - static void gst_v4l2_h264_enc_init (GstV4l2H264Enc * self) { @@ -299,12 +121,6 @@ gst_v4l2_h264_enc_class_init (GstV4l2H264EncClass * klass) GST_DEBUG_FUNCPTR (gst_v4l2_h264_enc_get_property); baseclass->codec_name = "H264"; - baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE; - baseclass->profile_to_string = v4l2_profile_to_string; - baseclass->profile_from_string = v4l2_profile_from_string; - baseclass->level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL; - baseclass->level_to_string = v4l2_level_to_string; - baseclass->level_from_string = v4l2_level_from_string; } /* Probing functions */ @@ -317,9 +133,11 @@ gst_v4l2_is_h264_enc (GstCaps * sink_caps, GstCaps * src_caps) void gst_v4l2_h264_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps) + const gchar * device_path, gint video_fd, GstCaps * sink_caps, + GstCaps * src_caps) { + const GstV4l2Codec *codec = gst_v4l2_h264_get_codec (); gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_H264_ENC, - "h264", basename, device_path, sink_caps, + "h264", basename, device_path, codec, video_fd, sink_caps, gst_static_caps_get (&src_template_caps), src_caps); } diff --git a/sys/v4l2/gstv4l2h264enc.h b/sys/v4l2/gstv4l2h264enc.h index 3bfa343460..269028049d 100644 --- a/sys/v4l2/gstv4l2h264enc.h +++ b/sys/v4l2/gstv4l2h264enc.h @@ -54,7 +54,7 @@ GType gst_v4l2_h264_enc_get_type (void); gboolean gst_v4l2_is_h264_enc (GstCaps * sink_caps, GstCaps * src_caps); void gst_v4l2_h264_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps); + const gchar * device_path, gint video_fd, GstCaps * sink_caps, GstCaps * src_caps); G_END_DECLS #endif /* __GST_V4L2_H264_ENC_H__ */ diff --git a/sys/v4l2/gstv4l2h265codec.c b/sys/v4l2/gstv4l2h265codec.c new file mode 100644 index 0000000000..7186da8cdd --- /dev/null +++ b/sys/v4l2/gstv4l2h265codec.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2018 NVIDIA CORPORATION. + * Author: Amit Pandya + * Factored out from gstv4l2h264enc by Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstv4l2h265codec.h" + +#include +#include "ext/v4l2-controls.h" + + +static gint +v4l2_profile_from_string (const gchar * profile) +{ + gint v4l2_profile = -1; + + if (g_str_equal (profile, "main")) { + v4l2_profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; + } else if (g_str_equal (profile, "mainstillpicture")) { + v4l2_profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; + } else if (g_str_equal (profile, "main10")) { + v4l2_profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10; + } else { + GST_WARNING ("Unsupported profile string '%s'", profile); + } + + return v4l2_profile; +} + +static const gchar * +v4l2_profile_to_string (gint v4l2_profile) +{ + switch (v4l2_profile) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + return "main"; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + return "mainstillpicture"; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: + return "main10"; + default: + GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); + break; + } + return NULL; +} + +static gint +v4l2_level_from_string (const gchar * level) +{ + gint v4l2_level = -1; + + if (g_str_equal (level, "1")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_1; + else if (g_str_equal (level, "2")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_2; + else if (g_str_equal (level, "2.1")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1; + else if (g_str_equal (level, "3")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_3; + else if (g_str_equal (level, "3.1")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1; + else if (g_str_equal (level, "4")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4; + else if (g_str_equal (level, "4.1")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1; + else if (g_str_equal (level, "5")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5; + else if (g_str_equal (level, "5.1")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1; + else if (g_str_equal (level, "5.2")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2; + else if (g_str_equal (level, "6")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_6; + else if (g_str_equal (level, "6.1")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1; + else if (g_str_equal (level, "6.2")) + v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2; + else + GST_WARNING ("Unsupported level '%s'", level); + + return v4l2_level; +} + +static const gchar * +v4l2_level_to_string (gint v4l2_level) +{ + switch (v4l2_level) { + case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: + return "1"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: + return "2"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: + return "2.1"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: + return "3"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: + return "3.1"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: + return "4"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: + return "4.1"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: + return "5"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: + return "5.1"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: + return "5.2"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_6: + return "6"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1: + return "6.1"; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2: + return "6.2"; + default: + GST_WARNING ("Unsupported V4L2 level %i", v4l2_level); + break; + } + + return NULL; +} + +const GstV4l2Codec * +gst_v4l2_h265_get_codec (void) +{ + static GstV4l2Codec *codec = NULL; + if (g_once_init_enter (&codec)) { + static GstV4l2Codec c; + c.profile_cid = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE; + c.profile_to_string = v4l2_profile_to_string; + c.profile_from_string = v4l2_profile_from_string; + c.level_cid = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL; + c.level_to_string = v4l2_level_to_string; + c.level_from_string = v4l2_level_from_string; + g_once_init_leave (&codec, &c); + } + return codec; +} diff --git a/sys/v4l2/gstv4l2h265codec.h b/sys/v4l2/gstv4l2h265codec.h new file mode 100644 index 0000000000..78d91c51ef --- /dev/null +++ b/sys/v4l2/gstv4l2h265codec.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 NVIDIA CORPORATION. + * Author: Amit Pandya + * Factored out from gstv4l2h264enc by Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __GST_V4L2_H265_CODEC_H__ +#define __GST_V4L2_H265_CODEC_H__ + +#include "gstv4l2codec.h" + +G_BEGIN_DECLS + +const GstV4l2Codec * gst_v4l2_h265_get_codec (void); + +G_END_DECLS + +#endif diff --git a/sys/v4l2/gstv4l2h265enc.c b/sys/v4l2/gstv4l2h265enc.c index 763f0bf323..4e4797bf83 100644 --- a/sys/v4l2/gstv4l2h265enc.c +++ b/sys/v4l2/gstv4l2h265enc.c @@ -31,6 +31,7 @@ #include "gstv4l2object.h" #include "gstv4l2h265enc.h" +#include "gstv4l2h265codec.h" #include #include @@ -66,116 +67,6 @@ gst_v4l2_h265_enc_get_property (GObject * object, /* TODO */ } -static gint -v4l2_profile_from_string (const gchar * profile) -{ - gint v4l2_profile = -1; - - if (g_str_equal (profile, "main")) { - v4l2_profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; - } else if (g_str_equal (profile, "mainstillpicture")) { - v4l2_profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; - } else if (g_str_equal (profile, "main10")) { - v4l2_profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10; - } else { - GST_WARNING ("Unsupported profile string '%s'", profile); - } - - return v4l2_profile; -} - -static const gchar * -v4l2_profile_to_string (gint v4l2_profile) -{ - switch (v4l2_profile) { - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: - return "main"; - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: - return "mainstillpicture"; - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: - return "main10"; - default: - GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); - break; - } - return NULL; -} - -static gint -v4l2_level_from_string (const gchar * level) -{ - gint v4l2_level = -1; - - if (g_str_equal (level, "1")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_1; - else if (g_str_equal (level, "2")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_2; - else if (g_str_equal (level, "2.1")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1; - else if (g_str_equal (level, "3")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_3; - else if (g_str_equal (level, "3.1")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1; - else if (g_str_equal (level, "4")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4; - else if (g_str_equal (level, "4.1")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1; - else if (g_str_equal (level, "5")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5; - else if (g_str_equal (level, "5.1")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1; - else if (g_str_equal (level, "5.2")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2; - else if (g_str_equal (level, "6")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_6; - else if (g_str_equal (level, "6.1")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1; - else if (g_str_equal (level, "6.2")) - v4l2_level = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2; - else - GST_WARNING ("Unsupported level '%s'", level); - - return v4l2_level; -} - -static const gchar * -v4l2_level_to_string (gint v4l2_level) -{ - switch (v4l2_level) { - case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: - return "1"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: - return "2"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: - return "2.1"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: - return "3"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: - return "3.1"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: - return "4"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: - return "4.1"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: - return "5"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: - return "5.1"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: - return "5.2"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_6: - return "6"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1: - return "6.1"; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2: - return "6.2"; - default: - GST_WARNING ("Unsupported V4L2 level %i", v4l2_level); - break; - } - - return NULL; -} - static void gst_v4l2_h265_enc_init (GstV4l2H265Enc * self) { @@ -209,12 +100,6 @@ gst_v4l2_h265_enc_class_init (GstV4l2H265EncClass * klass) GST_DEBUG_FUNCPTR (gst_v4l2_h265_enc_get_property); baseclass->codec_name = "H265"; - baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE; - baseclass->profile_to_string = v4l2_profile_to_string; - baseclass->profile_from_string = v4l2_profile_from_string; - baseclass->level_cid = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL; - baseclass->level_to_string = v4l2_level_to_string; - baseclass->level_from_string = v4l2_level_from_string; } /* Probing functions */ @@ -227,9 +112,11 @@ gst_v4l2_is_h265_enc (GstCaps * sink_caps, GstCaps * src_caps) void gst_v4l2_h265_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps) + const gchar * device_path, gint video_fd, GstCaps * sink_caps, + GstCaps * src_caps) { + const GstV4l2Codec *codec = gst_v4l2_h265_get_codec (); gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_H265_ENC, - "h265", basename, device_path, sink_caps, + "h265", basename, device_path, codec, video_fd, sink_caps, gst_static_caps_get (&src_template_caps), src_caps); } diff --git a/sys/v4l2/gstv4l2h265enc.h b/sys/v4l2/gstv4l2h265enc.h index 6ead493935..a8d7824b6b 100644 --- a/sys/v4l2/gstv4l2h265enc.h +++ b/sys/v4l2/gstv4l2h265enc.h @@ -54,7 +54,7 @@ GType gst_v4l2_h265_enc_get_type (void); gboolean gst_v4l2_is_h265_enc (GstCaps * sink_caps, GstCaps * src_caps); void gst_v4l2_h265_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps); + const gchar * device_path, gint video_fd, GstCaps * sink_caps, GstCaps * src_caps); G_END_DECLS #endif /* __GST_V4L2_H265_ENC_H__ */ diff --git a/sys/v4l2/gstv4l2jpegenc.c b/sys/v4l2/gstv4l2jpegenc.c index 6ed3e72296..f99218a8a2 100644 --- a/sys/v4l2/gstv4l2jpegenc.c +++ b/sys/v4l2/gstv4l2jpegenc.c @@ -114,6 +114,6 @@ gst_v4l2_jpeg_enc_register (GstPlugin * plugin, const gchar * basename, const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps) { gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_JPEG_ENC, - "jpeg", basename, device_path, sink_caps, + "jpeg", basename, device_path, NULL, -1, sink_caps, gst_static_caps_get (&src_template_caps), src_caps); } diff --git a/sys/v4l2/gstv4l2mpeg4codec.c b/sys/v4l2/gstv4l2mpeg4codec.c new file mode 100644 index 0000000000..34ba3af207 --- /dev/null +++ b/sys/v4l2/gstv4l2mpeg4codec.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2017 Collabora Inc. + * Author: Nicolas Dufresne + * Factored out from gstv4l2mpeg4enc by Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "gstv4l2mpeg4codec.h" + +#include +#include "ext/v4l2-controls.h" + +static gint +v4l2_profile_from_string (const gchar * profile) +{ + gint v4l2_profile = -1; + + if (g_str_equal (profile, "simple")) + v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE; + else if (g_str_equal (profile, "advanced-simple")) + v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE; + else if (g_str_equal (profile, "core")) + v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE; + else if (g_str_equal (profile, "simple-scalable")) + v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE; + else if (g_str_equal (profile, "advanced-coding-efficiency")) + v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; + else + GST_WARNING ("Unsupported profile string '%s'", profile); + + return v4l2_profile; +} + +static const gchar * +v4l2_profile_to_string (gint v4l2_profile) +{ + switch (v4l2_profile) { + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: + return "simple"; + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: + return "advanced-simple"; + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE: + return "core"; + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE: + return "simple-scalable"; + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY: + return "advanced-coding-efficiency"; + default: + GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); + break; + } + + return NULL; +} + +static gint +v4l2_level_from_string (const gchar * level) +{ + gint v4l2_level = -1; + + if (g_str_equal (level, "0")) + v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0; + else if (g_str_equal (level, "0b")) + v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B; + else if (g_str_equal (level, "1")) + v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_1; + else if (g_str_equal (level, "2")) + v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_2; + else if (g_str_equal (level, "3")) + v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_3; + else if (g_str_equal (level, "3b")) + v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B; + else if (g_str_equal (level, "4")) + v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_4; + else if (g_str_equal (level, "5")) + v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + else + GST_WARNING ("Unsupported level '%s'", level); + + return v4l2_level; +} + +static const gchar * +v4l2_level_to_string (gint v4l2_level) +{ + switch (v4l2_level) { + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0: + return "0"; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B: + return "0b"; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1: + return "1"; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2: + return "2"; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3: + return "3"; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B: + return "3b"; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4: + return "4"; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5: + return "5"; + default: + GST_WARNING ("Unsupported V4L2 level %i", v4l2_level); + break; + } + + return NULL; +} + +const GstV4l2Codec * +gst_v4l2_mpeg4_get_codec (void) +{ + static GstV4l2Codec *codec = NULL; + if (g_once_init_enter (&codec)) { + static GstV4l2Codec c; + c.profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; + c.profile_to_string = v4l2_profile_to_string; + c.profile_from_string = v4l2_profile_from_string; + c.level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL; + c.level_to_string = v4l2_level_to_string; + c.level_from_string = v4l2_level_from_string; + g_once_init_leave (&codec, &c); + } + return codec; +} diff --git a/sys/v4l2/gstv4l2mpeg4codec.h b/sys/v4l2/gstv4l2mpeg4codec.h new file mode 100644 index 0000000000..e003c42938 --- /dev/null +++ b/sys/v4l2/gstv4l2mpeg4codec.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2017 Collabora Inc. + * Author: Nicolas Dufresne + * Factored out from gstv4l2mpeg4enc by Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __GST_V4L2_MPEG4_CODEC_H__ +#define __GST_V4L2_MPEG4_CODEC_H__ + +#include "gstv4l2codec.h" + +G_BEGIN_DECLS + +const GstV4l2Codec * gst_v4l2_mpeg4_get_codec (void); + +G_END_DECLS + +#endif diff --git a/sys/v4l2/gstv4l2mpeg4enc.c b/sys/v4l2/gstv4l2mpeg4enc.c index 9333fd0f0e..af18688af2 100644 --- a/sys/v4l2/gstv4l2mpeg4enc.c +++ b/sys/v4l2/gstv4l2mpeg4enc.c @@ -31,6 +31,7 @@ #include "gstv4l2object.h" #include "gstv4l2mpeg4enc.h" +#include "gstv4l2mpeg4codec.h" #include #include @@ -65,104 +66,6 @@ gst_v4l2_mpeg4_enc_get_property (GObject * object, /* TODO */ } -static gint -v4l2_profile_from_string (const gchar * profile) -{ - gint v4l2_profile = -1; - - if (g_str_equal (profile, "simple")) - v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE; - else if (g_str_equal (profile, "advanced-simple")) - v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE; - else if (g_str_equal (profile, "core")) - v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE; - else if (g_str_equal (profile, "simple-scalable")) - v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE; - else if (g_str_equal (profile, "advanced-coding-efficiency")) - v4l2_profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; - else - GST_WARNING ("Unsupported profile string '%s'", profile); - - return v4l2_profile; -} - -static const gchar * -v4l2_profile_to_string (gint v4l2_profile) -{ - switch (v4l2_profile) { - case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: - return "simple"; - case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: - return "advanced-simple"; - case V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE: - return "core"; - case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE: - return "simple-scalable"; - case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY: - return "advanced-coding-efficiency"; - default: - GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); - break; - } - - return NULL; -} - -static gint -v4l2_level_from_string (const gchar * level) -{ - gint v4l2_level = -1; - - if (g_str_equal (level, "0")) - v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0; - else if (g_str_equal (level, "0b")) - v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B; - else if (g_str_equal (level, "1")) - v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_1; - else if (g_str_equal (level, "2")) - v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_2; - else if (g_str_equal (level, "3")) - v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_3; - else if (g_str_equal (level, "3b")) - v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B; - else if (g_str_equal (level, "4")) - v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_4; - else if (g_str_equal (level, "5")) - v4l2_level = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; - else - GST_WARNING ("Unsupported level '%s'", level); - - return v4l2_level; -} - -static const gchar * -v4l2_level_to_string (gint v4l2_level) -{ - switch (v4l2_level) { - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0: - return "0"; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B: - return "0b"; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1: - return "1"; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2: - return "2"; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3: - return "3"; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B: - return "3b"; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4: - return "4"; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5: - return "5"; - default: - GST_WARNING ("Unsupported V4L2 level %i", v4l2_level); - break; - } - - return NULL; -} - static void gst_v4l2_mpeg4_enc_init (GstV4l2Mpeg4Enc * self) { @@ -196,12 +99,6 @@ gst_v4l2_mpeg4_enc_class_init (GstV4l2Mpeg4EncClass * klass) GST_DEBUG_FUNCPTR (gst_v4l2_mpeg4_enc_get_property); baseclass->codec_name = "MPEG4"; - baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; - baseclass->profile_to_string = v4l2_profile_to_string; - baseclass->profile_from_string = v4l2_profile_from_string; - baseclass->level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL; - baseclass->level_to_string = v4l2_level_to_string; - baseclass->level_from_string = v4l2_level_from_string; } /* Probing functions */ @@ -214,9 +111,11 @@ gst_v4l2_is_mpeg4_enc (GstCaps * sink_caps, GstCaps * src_caps) void gst_v4l2_mpeg4_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps) + const gchar * device_path, gint video_fd, GstCaps * sink_caps, + GstCaps * src_caps) { + const GstV4l2Codec *codec = gst_v4l2_mpeg4_get_codec (); gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_MPEG4_ENC, - "mpeg4", basename, device_path, sink_caps, + "mpeg4", basename, device_path, codec, video_fd, sink_caps, gst_static_caps_get (&src_template_caps), src_caps); } diff --git a/sys/v4l2/gstv4l2mpeg4enc.h b/sys/v4l2/gstv4l2mpeg4enc.h index 84941037fc..9e4c884b7a 100644 --- a/sys/v4l2/gstv4l2mpeg4enc.h +++ b/sys/v4l2/gstv4l2mpeg4enc.h @@ -54,7 +54,7 @@ GType gst_v4l2_mpeg4_enc_get_type (void); gboolean gst_v4l2_is_mpeg4_enc (GstCaps * sink_caps, GstCaps * src_caps); void gst_v4l2_mpeg4_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps); + const gchar * device_path, gint video_fd, GstCaps * sink_caps, GstCaps * src_caps); G_END_DECLS #endif /* __GST_V4L2_MPEG4_ENC_H__ */ diff --git a/sys/v4l2/gstv4l2videodec.c b/sys/v4l2/gstv4l2videodec.c index 6338884e8f..99a04e303e 100644 --- a/sys/v4l2/gstv4l2videodec.c +++ b/sys/v4l2/gstv4l2videodec.c @@ -32,6 +32,12 @@ #include "gstv4l2object.h" #include "gstv4l2videodec.h" +#include "gstv4l2h264codec.h" +#include "gstv4l2h265codec.h" +#include "gstv4l2mpeg4codec.h" +#include "gstv4l2vp8codec.h" +#include "gstv4l2vp9codec.h" + #include #include @@ -45,6 +51,7 @@ typedef struct GstCaps *src_caps; const gchar *longname; const gchar *description; + const GstV4l2Codec *codec; } GstV4l2VideoDecCData; enum @@ -1081,6 +1088,7 @@ G_STMT_START { \ SET_META ("MPEG2"); } else { SET_META ("MPEG4"); + cdata->codec = gst_v4l2_mpeg4_get_codec (); } } else if (gst_structure_has_name (s, "video/x-h263")) { SET_META ("H263"); @@ -1088,14 +1096,18 @@ G_STMT_START { \ SET_META ("FWHT"); } else if (gst_structure_has_name (s, "video/x-h264")) { SET_META ("H264"); + cdata->codec = gst_v4l2_h264_get_codec (); } else if (gst_structure_has_name (s, "video/x-h265")) { SET_META ("H265"); + cdata->codec = gst_v4l2_h265_get_codec (); } else if (gst_structure_has_name (s, "video/x-wmv")) { SET_META ("VC1"); } else if (gst_structure_has_name (s, "video/x-vp8")) { SET_META ("VP8"); + cdata->codec = gst_v4l2_vp8_get_codec (); } else if (gst_structure_has_name (s, "video/x-vp9")) { SET_META ("VP9"); + cdata->codec = gst_v4l2_vp9_get_codec (); } else if (gst_structure_has_name (s, "video/x-bayer")) { SET_META ("BAYER"); } else if (gst_structure_has_name (s, "video/x-sonix")) { @@ -1130,7 +1142,8 @@ G_STMT_START { \ void gst_v4l2_video_dec_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps) + const gchar * device_path, gint video_fd, GstCaps * sink_caps, + GstCaps * src_caps) { gint i; @@ -1157,6 +1170,20 @@ gst_v4l2_video_dec_register (GstPlugin * plugin, const gchar * basename, continue; } + if (cdata->codec != NULL) { + GValue *value = gst_v4l2_codec_probe_levels (cdata->codec, video_fd); + if (value != NULL) { + gst_caps_set_value (cdata->sink_caps, "level", value); + g_value_unset (value); + } + + value = gst_v4l2_codec_probe_profiles (cdata->codec, video_fd); + if (value != NULL) { + gst_caps_set_value (cdata->sink_caps, "profile", value); + g_value_unset (value); + } + } + type = gst_v4l2_video_dec_get_type (); g_type_query (type, &type_query); memset (&type_info, 0, sizeof (type_info)); diff --git a/sys/v4l2/gstv4l2videodec.h b/sys/v4l2/gstv4l2videodec.h index be97d10aa8..6696fcb35e 100644 --- a/sys/v4l2/gstv4l2videodec.h +++ b/sys/v4l2/gstv4l2videodec.h @@ -76,7 +76,7 @@ GType gst_v4l2_video_dec_get_type (void); gboolean gst_v4l2_is_video_dec (GstCaps * sink_caps, GstCaps * src_caps); void gst_v4l2_video_dec_register (GstPlugin * plugin, const gchar *basename, - const gchar *device_path, + const gchar *device_path, gint video_fd, GstCaps * sink_caps, GstCaps * src_caps); G_END_DECLS diff --git a/sys/v4l2/gstv4l2videoenc.c b/sys/v4l2/gstv4l2videoenc.c index 8a86e4af05..e0b0150860 100644 --- a/sys/v4l2/gstv4l2videoenc.c +++ b/sys/v4l2/gstv4l2videoenc.c @@ -45,6 +45,7 @@ typedef struct gchar *device; GstCaps *sink_caps; GstCaps *src_caps; + const GstV4l2Codec *codec; } GstV4l2VideoEncCData; enum @@ -419,8 +420,9 @@ negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s, GQueue profiles = G_QUEUE_INIT; GQueue levels = G_QUEUE_INIT; gboolean failed = FALSE; + const GstV4l2Codec *codec = klass->codec; - if (klass->profile_cid && get_string_list (s, "profile", &profiles)) { + if (codec->profile_cid && get_string_list (s, "profile", &profiles)) { GList *l; for (l = profiles.head; l; l = l->next) { @@ -430,8 +432,9 @@ negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s, GST_TRACE_OBJECT (ctx->self, "Trying profile %s", profile); - control.id = klass->profile_cid; - control.value = v4l2_profile = klass->profile_from_string (profile); + control.id = codec->profile_cid; + + control.value = v4l2_profile = codec->profile_from_string (profile); if (control.value < 0) continue; @@ -442,7 +445,7 @@ negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s, break; } - profile = klass->profile_to_string (control.value); + profile = codec->profile_to_string (control.value); if (control.value == v4l2_profile) { ctx->profile = profile; @@ -462,7 +465,7 @@ negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s, g_queue_clear (&profiles); } - if (!failed && klass->level_cid && get_string_list (s, "level", &levels)) { + if (!failed && codec->level_cid && get_string_list (s, "level", &levels)) { GList *l; for (l = levels.head; l; l = l->next) { @@ -472,8 +475,8 @@ negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s, GST_TRACE_OBJECT (ctx->self, "Trying level %s", level); - control.id = klass->level_cid; - control.value = v4l2_level = klass->level_from_string (level); + control.id = codec->level_cid; + control.value = v4l2_level = codec->level_from_string (level); if (control.value < 0) continue; @@ -484,7 +487,7 @@ negotiate_profile_and_level (GstCapsFeatures * features, GstStructure * s, break; } - level = klass->level_to_string (control.value); + level = codec->level_to_string (control.value); if (control.value == v4l2_level) { ctx->level = level; @@ -518,6 +521,7 @@ gst_v4l2_video_enc_negotiate (GstVideoEncoder * encoder) struct ProfileLevelCtx ctx = { self, NULL, NULL }; GstVideoCodecState *state; GstStructure *s; + const GstV4l2Codec *codec = klass->codec; GST_DEBUG_OBJECT (self, "Negotiating %s profile and level.", klass->codec_name); @@ -543,26 +547,26 @@ gst_v4l2_video_enc_negotiate (GstVideoEncoder * encoder) } } - if (klass->profile_cid && !ctx.profile) { + if (codec->profile_cid && !ctx.profile) { struct v4l2_control control = { 0, }; - control.id = klass->profile_cid; + control.id = codec->profile_cid; if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) goto g_ctrl_failed; - ctx.profile = klass->profile_to_string (control.value); + ctx.profile = codec->profile_to_string (control.value); } - if (klass->level_cid && !ctx.level) { + if (codec->level_cid && !ctx.level) { struct v4l2_control control = { 0, }; - control.id = klass->level_cid; + control.id = codec->level_cid; if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) goto g_ctrl_failed; - ctx.level = klass->level_to_string (control.value); + ctx.level = codec->level_to_string (control.value); } GST_DEBUG_OBJECT (self, "Selected %s profile %s at level %s", @@ -571,10 +575,10 @@ gst_v4l2_video_enc_negotiate (GstVideoEncoder * encoder) state = gst_video_encoder_get_output_state (encoder); s = gst_caps_get_structure (state->caps, 0); - if (klass->profile_cid) + if (codec->profile_cid) gst_structure_set (s, "profile", G_TYPE_STRING, ctx.profile, NULL); - if (klass->level_cid) + if (codec->level_cid) gst_structure_set (s, "level", G_TYPE_STRING, ctx.level, NULL); if (!GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder)) @@ -1122,6 +1126,7 @@ gst_v4l2_video_enc_subclass_init (gpointer g_class, gpointer data) GstV4l2VideoEncCData *cdata = data; klass->default_device = cdata->device; + klass->codec = cdata->codec; /* Note: gst_pad_template_new() take the floating ref from the caps */ gst_element_class_add_pad_template (element_class, @@ -1160,8 +1165,9 @@ gst_v4l2_is_video_enc (GstCaps * sink_caps, GstCaps * src_caps, void gst_v4l2_video_enc_register (GstPlugin * plugin, GType type, - const char *codec, const gchar * basename, const gchar * device_path, - GstCaps * sink_caps, GstCaps * codec_caps, GstCaps * src_caps) + const char *codec_name, const gchar * basename, const gchar * device_path, + const GstV4l2Codec * codec, gint video_fd, GstCaps * sink_caps, + GstCaps * codec_caps, GstCaps * src_caps) { GstCaps *filtered_caps; GTypeQuery type_query; @@ -1170,12 +1176,27 @@ gst_v4l2_video_enc_register (GstPlugin * plugin, GType type, gchar *type_name; GstV4l2VideoEncCData *cdata; + if (codec != NULL && video_fd != -1) { + GValue *value = gst_v4l2_codec_probe_levels (codec, video_fd); + if (value != NULL) { + gst_caps_set_value (src_caps, "level", value); + g_value_unset (value); + } + + value = gst_v4l2_codec_probe_profiles (codec, video_fd); + if (value != NULL) { + gst_caps_set_value (src_caps, "profile", value); + g_value_unset (value); + } + } + filtered_caps = gst_caps_intersect (src_caps, codec_caps); cdata = g_new0 (GstV4l2VideoEncCData, 1); cdata->device = g_strdup (device_path); cdata->sink_caps = gst_caps_ref (sink_caps); cdata->src_caps = gst_caps_ref (filtered_caps); + cdata->codec = codec; g_type_query (type, &type_query); memset (&type_info, 0, sizeof (type_info)); @@ -1189,11 +1210,11 @@ gst_v4l2_video_enc_register (GstPlugin * plugin, GType type, * v4l2h264enc, for any additional encoders, we create unique names. Encoder * names may change between boots, so this should help gain stable names for * the most common use cases. */ - type_name = g_strdup_printf ("v4l2%senc", codec); + type_name = g_strdup_printf ("v4l2%senc", codec_name); if (g_type_from_name (type_name) != 0) { g_free (type_name); - type_name = g_strdup_printf ("v4l2%s%senc", basename, codec); + type_name = g_strdup_printf ("v4l2%s%senc", basename, codec_name); } subtype = g_type_register_static (type, type_name, &type_info, 0); diff --git a/sys/v4l2/gstv4l2videoenc.h b/sys/v4l2/gstv4l2videoenc.h index f03acd5231..3659cb51dd 100644 --- a/sys/v4l2/gstv4l2videoenc.h +++ b/sys/v4l2/gstv4l2videoenc.h @@ -29,6 +29,7 @@ #include #include +#include G_BEGIN_DECLS #define GST_TYPE_V4L2_VIDEO_ENC \ @@ -73,14 +74,7 @@ struct _GstV4l2VideoEncClass gchar *default_device; const char *codec_name; - - guint32 profile_cid; - const gchar * (*profile_to_string) (gint v4l2_profile); - gint (*profile_from_string) (const gchar * profile); - - guint32 level_cid; - const gchar * (*level_to_string) (gint v4l2_level); - gint (*level_from_string) (const gchar * level); + const GstV4l2Codec *codec; }; GType gst_v4l2_video_enc_get_type (void); @@ -90,7 +84,8 @@ gboolean gst_v4l2_is_video_enc (GstCaps * sink_caps, GstCaps * src_caps, GstCaps * codec_caps); void gst_v4l2_video_enc_register (GstPlugin * plugin, GType type, - const char *codec, const gchar * basename, const gchar * device_path, + const char *codec_name, const gchar * basename, const gchar * device_path, + const GstV4l2Codec * codec, gint video_fd, GstCaps * sink_caps, GstCaps *codec_caps, GstCaps * src_caps); G_END_DECLS diff --git a/sys/v4l2/gstv4l2vp8codec.c b/sys/v4l2/gstv4l2vp8codec.c new file mode 100644 index 0000000000..7181af6d97 --- /dev/null +++ b/sys/v4l2/gstv4l2vp8codec.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 Collabora Inc. + * Author: Nicolas Dufresne + * Factored out from gstv4l2vp8enc by Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstv4l2vp8codec.h" + +#include +#include "ext/v4l2-controls.h" + +static gint +v4l2_profile_from_string (const gchar * profile) +{ + gint v4l2_profile = -1; + + if (g_str_equal (profile, "0")) + v4l2_profile = 0; + else if (g_str_equal (profile, "1")) + v4l2_profile = 1; + else if (g_str_equal (profile, "2")) + v4l2_profile = 2; + else if (g_str_equal (profile, "3")) + v4l2_profile = 3; + else + GST_WARNING ("Unsupported profile string '%s'", profile); + + return v4l2_profile; +} + +static const gchar * +v4l2_profile_to_string (gint v4l2_profile) +{ + switch (v4l2_profile) { + case 0: + return "0"; + case 1: + return "1"; + case 2: + return "2"; + case 3: + return "3"; + default: + GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); + break; + } + + return NULL; +} + +const GstV4l2Codec * +gst_v4l2_vp8_get_codec (void) +{ + static GstV4l2Codec *codec = NULL; + if (g_once_init_enter (&codec)) { + static GstV4l2Codec c; + c.profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE; + c.profile_to_string = v4l2_profile_to_string; + c.profile_from_string = v4l2_profile_from_string; + g_once_init_leave (&codec, &c); + } + return codec; +} diff --git a/sys/v4l2/gstv4l2vp8codec.h b/sys/v4l2/gstv4l2vp8codec.h new file mode 100644 index 0000000000..42c23be26e --- /dev/null +++ b/sys/v4l2/gstv4l2vp8codec.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2017 Collabora Inc. + * Author: Nicolas Dufresne + * Factored out from gstv4l2vp8enc by Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __GST_V4L2_VP8_CODEC_H__ +#define __GST_V4L2_VP8_CODEC_H__ + +#include "gstv4l2codec.h" + +G_BEGIN_DECLS + +const GstV4l2Codec * gst_v4l2_vp8_get_codec (void); + +G_END_DECLS + +#endif diff --git a/sys/v4l2/gstv4l2vp8enc.c b/sys/v4l2/gstv4l2vp8enc.c index eadac8ff50..8bf9086727 100644 --- a/sys/v4l2/gstv4l2vp8enc.c +++ b/sys/v4l2/gstv4l2vp8enc.c @@ -31,6 +31,7 @@ #include "gstv4l2object.h" #include "gstv4l2vp8enc.h" +#include "gstv4l2vp8codec.h" #include #include @@ -65,45 +66,6 @@ gst_v4l2_vp8_enc_get_property (GObject * object, /* TODO */ } -static gint -v4l2_profile_from_string (const gchar * profile) -{ - gint v4l2_profile = -1; - - if (g_str_equal (profile, "0")) - v4l2_profile = 0; - else if (g_str_equal (profile, "1")) - v4l2_profile = 1; - else if (g_str_equal (profile, "2")) - v4l2_profile = 2; - else if (g_str_equal (profile, "3")) - v4l2_profile = 3; - else - GST_WARNING ("Unsupported profile string '%s'", profile); - - return v4l2_profile; -} - -static const gchar * -v4l2_profile_to_string (gint v4l2_profile) -{ - switch (v4l2_profile) { - case 0: - return "0"; - case 1: - return "1"; - case 2: - return "2"; - case 3: - return "3"; - default: - GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); - break; - } - - return NULL; -} - static void gst_v4l2_vp8_enc_init (GstV4l2Vp8Enc * self) { @@ -138,9 +100,6 @@ gst_v4l2_vp8_enc_class_init (GstV4l2Vp8EncClass * klass) GST_DEBUG_FUNCPTR (gst_v4l2_vp8_enc_get_property); baseclass->codec_name = "VP8"; - baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE; - baseclass->profile_to_string = v4l2_profile_to_string; - baseclass->profile_from_string = v4l2_profile_from_string; } /* Probing functions */ @@ -153,9 +112,11 @@ gst_v4l2_is_vp8_enc (GstCaps * sink_caps, GstCaps * src_caps) void gst_v4l2_vp8_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps) + const gchar * device_path, gint video_fd, GstCaps * sink_caps, + GstCaps * src_caps) { + const GstV4l2Codec *codec = gst_v4l2_vp8_get_codec (); gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_VP8_ENC, - "vp8", basename, device_path, sink_caps, + "vp8", basename, device_path, codec, video_fd, sink_caps, gst_static_caps_get (&src_template_caps), src_caps); } diff --git a/sys/v4l2/gstv4l2vp8enc.h b/sys/v4l2/gstv4l2vp8enc.h index 3e82b4b79e..41a6cdaadb 100644 --- a/sys/v4l2/gstv4l2vp8enc.h +++ b/sys/v4l2/gstv4l2vp8enc.h @@ -54,7 +54,7 @@ GType gst_v4l2_vp8_enc_get_type (void); gboolean gst_v4l2_is_vp8_enc (GstCaps * sink_caps, GstCaps * src_caps); void gst_v4l2_vp8_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps); + const gchar * device_path, gint video_fd, GstCaps * sink_caps, GstCaps * src_caps); G_END_DECLS #endif /* __GST_V4L2_VP8_ENC_H__ */ diff --git a/sys/v4l2/gstv4l2vp9codec.c b/sys/v4l2/gstv4l2vp9codec.c new file mode 100644 index 0000000000..b4f2d5cf04 --- /dev/null +++ b/sys/v4l2/gstv4l2vp9codec.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2017 Collabora Inc. + * Author: Nicolas Dufresne + * Factored out from gstv4l2vp9enc by Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstv4l2vp9codec.h" + +#include +#include "ext/v4l2-controls.h" + + +static gint +v4l2_profile_from_string (const gchar * profile) +{ + gint v4l2_profile = -1; + + if (g_str_equal (profile, "0")) + v4l2_profile = 0; + else if (g_str_equal (profile, "1")) + v4l2_profile = 1; + else if (g_str_equal (profile, "2")) + v4l2_profile = 2; + else if (g_str_equal (profile, "3")) + v4l2_profile = 3; + else + GST_WARNING ("Unsupported profile string '%s'", profile); + + return v4l2_profile; +} + +static const gchar * +v4l2_profile_to_string (gint v4l2_profile) +{ + switch (v4l2_profile) { + case 0: + return "0"; + case 1: + return "1"; + case 2: + return "2"; + case 3: + return "3"; + default: + GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); + break; + } + + return NULL; +} + +const GstV4l2Codec * +gst_v4l2_vp9_get_codec (void) +{ + static GstV4l2Codec *codec = NULL; + if (g_once_init_enter (&codec)) { + static GstV4l2Codec c; + c.profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE; + c.profile_to_string = v4l2_profile_to_string; + c.profile_from_string = v4l2_profile_from_string; + g_once_init_leave (&codec, &c); + } + return codec; +} diff --git a/sys/v4l2/gstv4l2vp9codec.h b/sys/v4l2/gstv4l2vp9codec.h new file mode 100644 index 0000000000..84a54ef8ff --- /dev/null +++ b/sys/v4l2/gstv4l2vp9codec.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2017 Collabora Inc. + * Author: Nicolas Dufresne + * Factored out from gstv4l2vp9enc by Philippe Normand + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __GST_V4L2_VP9_CODEC_H__ +#define __GST_V4L2_VP9_CODEC_H__ + +#include "gstv4l2codec.h" + +G_BEGIN_DECLS + +const GstV4l2Codec * gst_v4l2_vp9_get_codec (void); + +G_END_DECLS + +#endif diff --git a/sys/v4l2/gstv4l2vp9enc.c b/sys/v4l2/gstv4l2vp9enc.c index 69eedca8dc..f26a2ebc78 100644 --- a/sys/v4l2/gstv4l2vp9enc.c +++ b/sys/v4l2/gstv4l2vp9enc.c @@ -31,6 +31,7 @@ #include "gstv4l2object.h" #include "gstv4l2vp9enc.h" +#include "gstv4l2vp9codec.h" #include #include @@ -65,45 +66,6 @@ gst_v4l2_vp9_enc_get_property (GObject * object, /* TODO */ } -static gint -v4l2_profile_from_string (const gchar * profile) -{ - gint v4l2_profile = -1; - - if (g_str_equal (profile, "0")) - v4l2_profile = 0; - else if (g_str_equal (profile, "1")) - v4l2_profile = 1; - else if (g_str_equal (profile, "2")) - v4l2_profile = 2; - else if (g_str_equal (profile, "3")) - v4l2_profile = 3; - else - GST_WARNING ("Unsupported profile string '%s'", profile); - - return v4l2_profile; -} - -static const gchar * -v4l2_profile_to_string (gint v4l2_profile) -{ - switch (v4l2_profile) { - case 0: - return "0"; - case 1: - return "1"; - case 2: - return "2"; - case 3: - return "3"; - default: - GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); - break; - } - - return NULL; -} - static void gst_v4l2_vp9_enc_init (GstV4l2Vp9Enc * self) { @@ -137,9 +99,6 @@ gst_v4l2_vp9_enc_class_init (GstV4l2Vp9EncClass * klass) GST_DEBUG_FUNCPTR (gst_v4l2_vp9_enc_get_property); baseclass->codec_name = "VP9"; - baseclass->profile_cid = V4L2_CID_MPEG_VIDEO_VPX_PROFILE; - baseclass->profile_to_string = v4l2_profile_to_string; - baseclass->profile_from_string = v4l2_profile_from_string; } /* Probing functions */ @@ -152,9 +111,11 @@ gst_v4l2_is_vp9_enc (GstCaps * sink_caps, GstCaps * src_caps) void gst_v4l2_vp9_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps) + const gchar * device_path, gint video_fd, GstCaps * sink_caps, + GstCaps * src_caps) { + const GstV4l2Codec *codec = gst_v4l2_vp9_get_codec (); gst_v4l2_video_enc_register (plugin, GST_TYPE_V4L2_VP9_ENC, - "vp9", basename, device_path, sink_caps, + "vp9", basename, device_path, codec, video_fd, sink_caps, gst_static_caps_get (&src_template_caps), src_caps); } diff --git a/sys/v4l2/gstv4l2vp9enc.h b/sys/v4l2/gstv4l2vp9enc.h index b768cced26..f9b8ad7689 100644 --- a/sys/v4l2/gstv4l2vp9enc.h +++ b/sys/v4l2/gstv4l2vp9enc.h @@ -54,7 +54,7 @@ GType gst_v4l2_vp9_enc_get_type (void); gboolean gst_v4l2_is_vp9_enc (GstCaps * sink_caps, GstCaps * src_caps); void gst_v4l2_vp9_enc_register (GstPlugin * plugin, const gchar * basename, - const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps); + const gchar * device_path, gint video_fd, GstCaps * sink_caps, GstCaps * src_caps); G_END_DECLS #endif /* __GST_V4L2_VP9_ENC_H__ */ diff --git a/sys/v4l2/meson.build b/sys/v4l2/meson.build index 61cd618c28..bae955a3d6 100644 --- a/sys/v4l2/meson.build +++ b/sys/v4l2/meson.build @@ -1,6 +1,7 @@ v4l2_sources = [ 'gstv4l2.c', 'gstv4l2allocator.c', + 'gstv4l2codec.c', 'gstv4l2colorbalance.c', 'gstv4l2deviceprovider.c', 'gstv4l2object.c', @@ -14,12 +15,17 @@ v4l2_sources = [ 'gstv4l2videoenc.c', 'gstv4l2fwhtenc.c', 'gstv4l2h263enc.c', + 'gstv4l2h264codec.c', 'gstv4l2h264enc.c', + 'gstv4l2h265codec.c', 'gstv4l2h265enc.c', 'gstv4l2jpegenc.c', + 'gstv4l2mpeg4codec.c', 'gstv4l2mpeg4enc.c', 'gstv4l2vidorient.c', + 'gstv4l2vp8codec.c', 'gstv4l2vp8enc.c', + 'gstv4l2vp9codec.c', 'gstv4l2vp9enc.c', 'v4l2_calls.c', 'v4l2-utils.c',