背景:去掉v4l2videodec的MPEG4的caps
MPEG4 caps的初始化调用栈
plugin_init在gst-plugins-good/sys/v4l2/gstv4l2.c文件中,是v4l2相关plugin的init函数,通过gst-inspect可以看到video4linux2对应一系列插件
video4linux2: v4l2src: Video (video4linux2) Source
video4linux2: v4l2sink: Video (video4linux2) Sink
video4linux2: v4l2radio: Radio (video4linux2) Tuner
video4linux2: v4l2deviceprovider (GstDeviceProviderFactory)
video4linux2: v4l2jpegdec: V4L2 JPEG Decoder
video4linux2: v4l2mpeg4dec: V4L2 MPEG4 Decoder
video4linux2: v4l2h264dec: V4L2 H264 Decoder
video4linux2: v4l2h265dec: V4L2 H265 Decoder
video4linux2: v4l2vp9dec: V4L2 VP9 Decoder
plugin_init函数,v4l2videodec的调用栈:
plugin_init
- gst_v4l2_probe_and_register
- gst_v4l2_video_dec_register
- gst_v4l2_probe_template_caps
- gst_v4l2_object_v4l2fourcc_to_structure
- gst_v4l2_object_v4l2fourcc_to_bare_struct
在gst_v4l2_object_v4l2fourcc_to_bare_struct中可以看到MPEG4的caps定义:
case V4L2_PIX_FMT_MPEG4:
case V4L2_PIX_FMT_XVID:
structure = gst_structure_new ("video/mpeg",
"mpegversion", G_TYPE_INT, 4, "systemstream",
G_TYPE_BOOLEAN, FALSE, NULL);
break;
分析
gst_caps_merge调用gst_v4l2_probe_template_caps
生成cpas
sink_caps = gst_caps_merge (gst_v4l2_probe_template_caps (it->device_path,
video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT),
gst_v4l2_probe_template_caps (it->device_path, video_fd,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE));
gst_v4l2_probe_template_caps中,通过ioctl查询支持的format,format是多个,format的原型定义如下:
struct v4l2_fmtdesc {
__u32 index; /* Format number */
__u32 type; /* enum v4l2_buf_type */
__u32 flags;
__u8 description[32]; /* Description string */
__u32 pixelformat; /* Format fourcc */
__u32 reserved[4];
};
ioctl查询支持的format
if (ioctl (video_fd, VIDIOC_ENUM_FMT, &format) < 0)
break; /* end of enumeration */
然后根据format.pixelformat创建template
template = gst_v4l2_object_v4l2fourcc_to_structure (format.pixelformat);
可以看到V4L2_PIX_FMT_MPEG4部分创建template
static GstStructure *
gst_v4l2_object_v4l2fourcc_to_bare_struct (guint32 fourcc)
{
GstStructure *structure = NULL;
switch (fourcc) {
case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */
case V4L2_PIX_FMT_PJPG: /* Progressive-JPEG */
case V4L2_PIX_FMT_JPEG: /* JFIF JPEG */
structure = gst_structure_new_empty ("image/jpeg");
break;
case V4L2_PIX_FMT_MPEG4:
case V4L2_PIX_FMT_XVID:
structure = gst_structure_new ("video/mpeg",
"mpegversion", G_TYPE_INT, 4, "systemstream",
G_TYPE_BOOLEAN, FALSE, NULL);
break;
ERROR1
sh-5.0# GST_DEBUG=5 gst-inspect v4l2mpeg4dec
westeros-sink: discover decoder: /dev/video26
(gst-plugin-scanner:9700): GStreamer-CRITICAL **: 14:47:48.527: gst_debug_log_valist: assertion 'category != NULL' failed
(gst-plugin-scanner:9708): GStreamer-CRITICAL **: 14:47:48.930: gst_debug_log_valist: assertion 'category != NULL' failed
这个错误是因为加了一句log输出导致:
+++ b/sys/v4l2/gstv4l2videodec.c
@@ -1183,6 +1183,7 @@ G_STMT_START { \
}
if (codec_name) {
+ GST_WARNING ("plugin '%s'", codec_name);
type_name = g_strdup_printf ("v4l2%sdec", codec_name);
if (g_type_from_name (type_name) != 0) {
g_free (type_name);
正确的做法应该是定义default category,不然GST_WARNING用的时候发现category为null,就报前面的错了。GST_WARNING在有些地方可以直接用,有些地方不可以,原因取决于有没有有效的GST_CAT_DEFAULT定义。
这个地方也可以用g_warning增加调试信息:
g_warning ("plugin codec name-: '%s'", codec_name);
$ gst-inspect v4l2mpeg4dec
plugin codec name: 'jpeg'
plugin codec name: 'mpeg4'
plugin codec name: 'h264'
plugin codec name: 'h265'
plugin codec name: 'vp9'
v4l2mpeg4dec
Factory Details:
Rank primary + 1 (257)
Long-name V4L2 MPEG4 Decoder
Klass Codec/Decoder/Video/Hardware
Description Decodes MPEG4 streams via V4L2 API
Author Nicolas Dufresne <nicolas.dufresne@collabora.com>
对应代码:
cdata->longname = "V4L2 " codec " Decoder"; \
cdata->description = "Decodes " codec " streams via V4L2 API"; \
codec_name = g_ascii_strdown (codec, -1); \
这部分是和v4l2video26mpeg4dec共用的。
继承关系:
GObject
+----GInitiallyUnowned
+----GstObject
+----GstElement
+----GstVideoDecoder
+----GstV4l2VideoDec
+----v4l2mpeg4dec
v4l2video26mpeg4dec
Factory Details:
Rank primary + 1 (257)
Long-name V4L2 MPEG4 Decoder
Klass Codec/Decoder/Video/Hardware
Description Decodes MPEG4 streams via V4L2 API
Author Nicolas Dufresne <nicolas.dufresne@collabora.com>
继承关系:
GObject
+----GInitiallyUnowned
+----GstObject
+----GstElement
+----GstVideoDecoder
+----GstV4l2VideoDec
+----v4l2video26mpeg4dec
v4l2video26mpeg4dec为什么加了就不见了?
v4l2video26mpeg4dec是video4linux2的一个feature
GST_REGISTRY gstregistrychunks.c:729:gst_registry_chunks_load_feature:
Added feature v4l2mpeg4dec, plugin 0x1b23008 video4linux2
GST_REGISTRY gstregistrychunks.c:571:gst_registry_chunks_load_feature:
Plugin 'video4linux2' feature 'v4l2video26mpeg4dec' typename : 'GstElementFactory'
上面打印log的地方:
GST_DEBUG ("Plugin '%s' feature '%s' typename : '%s'", plugin_name, feature_name, type_name);
registry里面对应的代码
gstreamer/gst/gstregistrychunks.c
_priv_gst_registry_chunks_load_plugin中load插件的feature
/* Load plugin features */
for (i = 0; i < n; i++) {
if (G_UNLIKELY (!gst_registry_chunks_load_feature (registry, in, end,
plugin))) {
GST_ERROR ("Error while loading binary feature for plugin '%s'",
GST_STR_NULL (plugin->desc.name));
gst_registry_remove_plugin (registry, plugin);
goto fail;
}
}
ERROR2
如果代码有错误,后面是0 features
gstregistrychunks.c:850:_priv_gst_registry_chunks_load_plugin: read strings for name='libgstvideo4linux2.so'
gstregistrychunks.c:851:_priv_gst_registry_chunks_load_plugin: desc.description='Plugin for blacklisted file'
gstregistrychunks.c:852:_priv_gst_registry_chunks_load_plugin: filename='/usr/lib/gstreamer-1.0/libgstvideo4linux2.so'
gstregistrychunks.c:853:_priv_gst_registry_chunks_load_plugin: desc.version='0.0.0'
gstregistrychunks.c:854:_priv_gst_registry_chunks_load_plugin: desc.license='BLACKLIST'
gstregistrychunks.c:855:_priv_gst_registry_chunks_load_plugin: desc.source='BLACKLIST'
gstregistrychunks.c:856:_priv_gst_registry_chunks_load_plugin: desc.package='BLACKLIST'
gstregistrychunks.c:857:_priv_gst_registry_chunks_load_plugin: desc.origin='BLACKLIST'
gstregistrychunks.c:858:_priv_gst_registry_chunks_load_plugin: desc.datetime=
gstregistry.c:474:gst_registry_add_plugin:<registry0> adding plugin 0xf46008 for filename "/usr/lib/gstreamer-1.0/libgstvideo4linux2.so"
gstregistry.c:487:gst_registry_add_plugin:<registry0> emitting plugin-added for filename "/usr/lib/gstreamer-1.0/libgstvideo4linux2.so"
gstregistrychunks.c:878:_priv_gst_registry_chunks_load_plugin: Added plugin 'libgstvideo4linux2.so' plugin with 0 features from binary regis
video4linux2
gst-inspect video4linux2
WARNING: terminal is not fully functional
Plugin Details:N)
Name video4linux2
Description elements for Video 4 Linux
Filename /usr/lib/gstreamer-1.0/libgstvideo4linux2.so
Version 1.16.3
License LGPL
Source module gst-plugins-good
Binary package GStreamer Good Plug-ins source release
Origin URL Unknown package origin
v4l2src: Video (video4linux2) Source
v4l2sink: Video (video4linux2) Sink
v4l2radio: Radio (video4linux2) Tuner
v4l2deviceprovider: Video (video4linux2) Device Provider
v4l2jpegdec: V4L2 JPEG Decoder
v4l2mpeg4dec: V4L2 MPEG4 Decoder
v4l2video26mpeg4dec: V4L2 MPEG4 Decoder
v4l2h264dec: V4L2 H264 Decoder
v4l2h265dec: V4L2 H265 Decoder
v4l2vp9dec: V4L2 VP9 Decoder
10 features:
+-- 9 elements
+-- 1 device providers
增加log输出v4l2dec注册的type_name
+GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
+#define GST_CAT_DEFAULT v4l2_debug
+
void
gst_v4l2_video_dec_register (GstPlugin * plugin, const gchar * basename,
const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
@@ -1210,6 +1214,7 @@ gst_v4l2_video_dec_register (GstPlugin * plugin, const gchar * basename,
GType type, subtype;
gchar *type_name;
+
s = gst_caps_get_structure (sink_caps, i);
cdata = g_new0 (GstV4l2VideoDecCData, 1);
@@ -1222,7 +1227,7 @@ gst_v4l2_video_dec_register (GstPlugin * plugin, const gchar * basename,
gst_caps_set_features_simple(cdata->src_caps, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
gst_caps_append(cdata->src_caps, gst_caps_copy (src_caps));
type_name = gst_v4l2_video_dec_set_metadata (s, cdata, basename);
-
+ GST_CAT_WARNING (GST_CAT_DEFAULT, "shizh: type_name: %s, caps size: %d", type_name, gst_caps_get_size (sink_caps));
去掉mpeg4的caps
v4l2 gstv4l2videodec.c:1230:gst_v4l2_video_dec_register: type_name: v4l2jpegdec, caps size: 5
v4l2 gstv4l2videodec.c:1230:gst_v4l2_video_dec_register: type_name: v4l2mpeg4dec, caps size: 5
v4l2 gstv4l2videodec.c:1230:gst_v4l2_video_dec_register: type_name: v4l2h264dec, caps size: 5
v4l2 gstv4l2videodec.c:1230:gst_v4l2_video_dec_register: type_name: v4l2h265dec, caps size: 5
v4l2 gstv4l2videodec.c:1230:gst_v4l2_video_dec_register: type_name: v4l2vp9dec, caps size: 5
所以通过ENABLE_MPEG4PART2去掉mpeg4的caps是可行的:
#ifdef ENABLE_MPEG4PART2
structure = gst_structure_new ("video/mpeg",
"mpegversion", G_TYPE_INT, 4, "systemstream",
G_TYPE_BOOLEAN, FALSE, NULL);
#endif
v4l2video26mpeg4dec的出处
因为g_type_from_name通过mpeg4
的name去取,发现已经有了,所以又用basename和codec_name组合了一个新的name,basename为video26。codec_name为mpeg4
,即新的名字v4l2+video26+mpeg4dec,就是v4l2video26mpeg4dec,去掉mpeg4的caps之后,就不会有v4l2video26mpeg4dec。
if (codec_name) {
type_name = g_strdup_printf ("v4l2%sdec", codec_name);
if (g_type_from_name (type_name) != 0) {
g_free (type_name);
GST_WARNING ("plugin codec name: v4l2 %s %s dec'", basename, codec_name);
type_name = g_strdup_printf ("v4l2%s%sdec", basename, codec_name);
}
加上前面的log会输出:
gst_v4l2_video_dec_set_metadata: plugin codec name: v4l2 video26 mpeg4 dec'
mpeg1和mpeg2
V4L2_PIX_FMT_MPEG1和V4L2_PIX_FMT_MPEG2应该merge caps的时候被merge到一块了:
case V4L2_PIX_FMT_MPEG1:
structure = gst_structure_new ("video/mpeg",
"mpegversion", G_TYPE_INT, 1, NULL);
break;
case V4L2_PIX_FMT_MPEG2:
structure = gst_structure_new ("video/mpeg",
"mpegversion", G_TYPE_INT, 2, NULL);
v4l2通过ioctl查询format信息
在gst-plugins-good/sys/v4l2/gstv4l2.c的gst_v4l2_probe_template_caps函数中,通过ioctl调用得到format:
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));
输出log如下:
v4l2 gstv4l2.c:75:gst_v4l2_probe_template_caps: Getting /dev/video26 format enumerations
v4l2 gstv4l2.c:75:gst_v4l2_probe_template_caps: Getting /dev/video26 format enumerations
v4l2 gstv4l2.c:89:gst_v4l2_probe_template_caps: index: 0
v4l2 gstv4l2.c:90:gst_v4l2_probe_template_caps: type: 10
v4l2 gstv4l2.c:91:gst_v4l2_probe_template_caps: flags: 00000001
v4l2 gstv4l2.c:92:gst_v4l2_probe_template_caps: description: 'H.264'
v4l2 gstv4l2.c:93:gst_v4l2_probe_template_caps: pixelformat: H264
v4l2 gstv4l2.c:89:gst_v4l2_probe_template_caps: index: 1
v4l2 gstv4l2.c:90:gst_v4l2_probe_template_caps: type: 10
v4l2 gstv4l2.c:91:gst_v4l2_probe_template_caps: flags: 00000001
v4l2 gstv4l2.c:92:gst_v4l2_probe_template_caps: description: 'HEVC'
v4l2 gstv4l2.c:93:gst_v4l2_probe_template_caps: pixelformat: HEVC
v4l2 gstv4l2.c:89:gst_v4l2_probe_template_caps: index: 2
v4l2 gstv4l2.c:90:gst_v4l2_probe_template_caps: type: 10
v4l2 gstv4l2.c:91:gst_v4l2_probe_template_caps: flags: 00000001
v4l2 gstv4l2.c:92:gst_v4l2_probe_template_caps: description: 'VP9'
v4l2 gstv4l2.c:93:gst_v4l2_probe_template_caps: pixelformat: VP90
v4l2 gstv4l2.c:89:gst_v4l2_probe_template_caps: index: 3
v4l2 gstv4l2.c:90:gst_v4l2_probe_template_caps: type: 10
v4l2 gstv4l2.c:91:gst_v4l2_probe_template_caps: flags: 00000001
v4l2 gstv4l2.c:92:gst_v4l2_probe_template_caps: description: 'MPEG-1 ES'
v4l2 gstv4l2.c:93:gst_v4l2_probe_template_caps: pixelformat: MPG1
v4l2 gstv4l2.c:89:gst_v4l2_probe_template_caps: index: 4
v4l2 gstv4l2.c:90:gst_v4l2_probe_template_caps: type: 10
v4l2 gstv4l2.c:91:gst_v4l2_probe_template_caps: flags: 00000001
v4l2 gstv4l2.c:92:gst_v4l2_probe_template_caps: description: 'MPEG-2 ES'
v4l2 gstv4l2.c:93:gst_v4l2_probe_template_caps: pixelformat: MPG2
v4l2 gstv4l2.c:89:gst_v4l2_probe_template_caps: index: 5
v4l2 gstv4l2.c:90:gst_v4l2_probe_template_caps: type: 10
v4l2 gstv4l2.c:91:gst_v4l2_probe_template_caps: flags: 00000001
v4l2 gstv4l2.c:92:gst_v4l2_probe_template_caps: description: 'MPEG-4 Part 2 ES'
v4l2 gstv4l2.c:93:gst_v4l2_probe_template_caps: pixelformat: MPG4
v4l2 gstv4l2.c:89:gst_v4l2_probe_template_caps: index: 6
v4l2 gstv4l2.c:90:gst_v4l2_probe_template_caps: type: 10
v4l2 gstv4l2.c:91:gst_v4l2_probe_template_caps: flags: 00000001
v4l2 gstv4l2.c:92:gst_v4l2_probe_template_caps: description: 'Motion-JPEG'
v4l2 gstv4l2.c:93:gst_v4l2_probe_template_caps: pixelformat: MJPG
v4l2 gstv4l2.c:89:gst_v4l2_probe_template_caps: index: 7
v4l2 gstv4l2.c:90:gst_v4l2_probe_template_caps: type: 10
v4l2 gstv4l2.c:91:gst_v4l2_probe_template_caps: flags: 00000001
v4l2 gstv4l2.c:92:gst_v4l2_probe_template_caps: description: 'AV1'
v4l2 gstv4l2.c:93:gst_v4l2_probe_template_caps: pixelformat: AV10
v4l2 gstv4l2object.c:1573:gst_v4l2_object_v4l2fourcc_to_bare_struct: Unsupported fourcc 0x30315641 AV10
通过v4l2插件播放
GST_DEBUG=v4l2*:5 gst-launch-1.0 filesrc location=/data/hbc9_h264.avi ! avidemux ! h264parse ! v4l2h264dec ! autovideosink
通过property控制
想了下如果通过property控制不可行,因为caps已经关掉了,没法在通过property增加caps,需要重新registry。
void gst_v4l2_object_install_properties_helper (
GObjectClass * gobject_class, const char *default_device)
{
g_object_class_install_property (gobject_class, PROP_DEVICE,
g_param_spec_string ("device", "Device", "Device location",
default_device, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
g_param_spec_string ("device-name", "Device name",
"Name of the device", DEFAULT_PROP_DEVICE_NAME,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
添加property
在gst-plugins-good/sys/v4l2/gstv4l2object.c中搜索g_object_class_install_property函数,可以参考添加property的代码
g_object_class_install_property (gobject_class, PROP_FLAGS,
g_param_spec_flags ("flags", "Flags", "Device type flags",
GST_TYPE_V4L2_DEVICE_FLAGS, DEFAULT_PROP_FLAGS,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
测试播放命令:
DISABLE_MPEG4_DECODE=1 gst-play-1.0 /data/mpeg4.ts