gstreamer avidemux增加h265支持
avi格式简介
AVI文件采用的是RIFF文件结构方式,RIFF(Resource Interchange File Format,资源互换文件格式)是微软公司定义的一种用户管理Windows环境中多媒体数据的文件格式,波形音频wave,MIDI和数字视频AVI都采用这种格式存储。RIFF文件的实际数据中,使用了列表(List)和块(Chunk)的形式来组织。列表可以嵌套列表和块。整个RIFF文件可以看成一个数据库,其数据块ID为RIFF ,称为RIFF块。一个RIFF文件中只允许存在一个RIFF块。RIFF块中包含一系列的子块,其中有一种子块的ID为“List”,称为LIST块,LIST块中可以再包含一系列的子块,但除了LIST块外的其他所有的子块都不能再包含子块。
块标识符ID为’RIFF’的chunk是比较特殊的,每一个RIFF文件首先存放的必须是一个RIFF chunk,并且只能有一个标识符为’RIFF’的chunk。RIFF chunk的数据域的起始位置是一个4字节的FormType(FourCC格式),用于标识RIFF chunk数据域中所包含的chunk的数据类型。紧接着FormType之后的数据域的内容则是RIFF chunk所包含的subchunk。
上图中的RIFF chunk包含有两个subchunk,可以看出RIFF chunk的数据域首先是4字节的FormType,接着是两个subchunk,每一个subchunk又包含有自己的标识符、数据域的大小以及数据域。 除了RIFF chunk可以嵌套其他的chunk外,另一个可以包含subchunk的就是LIST chunk,其示意图如下所示:
avi的文件头结构
ID为hdrl
的LIST块,定义AVI文件的数据格式,hdrl
LIST块包含两个子块,一个是ID为avih
的子块和一个是ID为strl
的LIST块。
- avih块结构:用于记录AVI文件的全局信息,比如流的数量,视频图像的宽和高等,包含一个或多个strl子列表
- 每个
strl
字列表至少包含一个strh
块和一个strf
块
strh
块结构:用于说明这个strl
LIST块对应的数据流的头信息
strf
块结构:strf
子块紧跟在strh
子块之后,其结构是strh子块的类型而定
- 如果strh子块是视频数据流,则strf子块的内容是一个BITMAPINFO结构
- 如果strh子块是音频数据流,则strf子块的内容是一个WAVEFORMAT结构
RIFF
- hdrl LIST
- avih
- strl
- strh (vids)
- strf
- JUNK
- info LIST
- JUNK (填充)
- movi LIST
实例分析gsreamer-1.16.3 avi解析h265
在gstreamer网站搜索avidemux,看到avidemux最新的版本支持很全,已经包含h265的caps,所以No decoder available for type 'video/x-avi-unknown
,这个log大致判断是对codec识别错误导致:
https://gstreamer.freedesktop.org/documentation/
gst-launch播放命令:
gst-launch-1.0 filesrc location=test.avi ! avidemux name=demux demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_00 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
avidemux sinkpad
gst-plugins-good/gst/avi/gstavidemux.c
avidemux的sink pad是caps为video/x-msvideo
的类型:
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-msvideo")
);
sink pad的创建自然在gst_avi_demux_init中:
gst_avi_demux_init (GstAviDemux * avi)
{
avi->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
gst_pad_set_activate_function (avi->sinkpad,
GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate));
hexdump可以看到文件头,和log中的输出一致:
$ hexdump -C hbc9_h265.avi | more
00000000 52 49 46 46 8e fc 73 00 41 56 49 20 4c 49 53 54 |RIFF..s.AVI LIST|
00000010 ca 22 00 00 68 64 72 6c 61 76 69 68 38 00 00 00 |."..hdrlavih8...|
00000020 56 82 00 00 00 00 00 00 00 00 00 00 10 09 00 00 |V...............|
00000030 48 19 00 00 00 00 00 00 02 00 00 00 00 00 10 00 |H...............|
00000040 c0 02 00 00 60 01 00 00 00 00 00 00 00 00 00 00 |....`...........|
00000050 00 00 00 00 00 00 00 00 4c 49 53 54 e0 10 00 00 |........LIST....|
00000060 73 74 72 6c 73 74 72 68 38 00 00 00 76 69 64 73 |strlstrh8...vids|
00000070 68 76 63 31 00 00 00 00 00 00 00 00 00 00 00 00 |hvc1............|
00000080 e9 03 00 00 30 75 00 00 00 00 00 00 48 19 00 00 |....0u......H...|
00000090 92 42 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 |.B..............|
000000a0 c0 02 60 01 73 74 72 66 28 00 00 00 28 00 00 00 |..`.strf(...(...|
000000b0 c0 02 00 00 60 01 00 00 01 00 18 00 68 76 63 31 |....`.......hvc1|
行号为00000070: 68 76 63 31
十六进制数就是0x31637668,对应的十进制是828601960
与log中输出的fourcc值一样,说明hvc1没有被正确识别:
avidemux gstavidemux.c:2390:gst_avi_demux_parse_stream:<avidemux0> caps=video/x-avi-unknown, fourcc=(int)828601960
在python中也可以将log中的这个值转成hex对比,前面hexdump中的第9行
>>> hex(828601960)
'0x31637668'
ubuntu播放
gst-launch-1.0 filesrc location=/home/hui/dload/h265.avi ! avidemux ! fakesink -v
ubuntu上升级到1.19.3播放正常,分析log输出,前面的判断正确,avi中的h265没有被识别,增加h265的支持,成功创建caps就可以了。
vids解析正常
case GST_RIFF_FCC_vids:{
guint32 fourcc;
fourcc = (stream->strf.vids->compression) ?
stream->strf.vids->compression : stream->strh->fcc_handler;
caps = gst_riff_create_video_caps (fourcc, stream->strh,
stream->strf.vids, stream->extradata, stream->initdata, &codec_name);
gst_riff_create_video_caps
从gstreamer高版本里面找到h265的部分patch加上就可以了:
$ cat 0001-riff-media-add-H.265.patch
From f98f8340140a2e6b8a7fb3c21823c348778ddff4 Mon Sep 17 00:00:00 2001
From: Nicola Murino <nicola.murino@gmail.com>
Date: Fri, 25 Jan 2019 22:48:17 +0100
Subject: [PATCH] riff-media: add H.265
Closes #359
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/43>
---
gst-libs/gst/riff/riff-media.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/gst-libs/gst/riff/riff-media.c b/gst-libs/gst/riff/riff-media.c
index 6feda84a74..4bb723bf5b 100644
--- a/gst-libs/gst/riff/riff-media.c
+++ b/gst-libs/gst/riff/riff-media.c
@@ -353,6 +353,17 @@ gst_riff_create_video_caps (guint32 codec_fcc,
*codec_name = g_strdup ("ITU H.264");
break;
+ case GST_MAKE_FOURCC ('X', '2', '6', '5'):
+ case GST_MAKE_FOURCC ('x', '2', '6', '5'):
+ case GST_MAKE_FOURCC ('H', '2', '6', '5'):
+ case GST_MAKE_FOURCC ('h', '2', '6', '5'):
+ case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
+ case GST_MAKE_FOURCC ('H', 'V', 'C', '1'):
+ caps = gst_caps_new_empty_simple ("video/x-h265");
+ if (codec_name)
+ *codec_name = g_strdup ("H.265");
+ break;
+
case GST_RIFF_VSSH:
caps = gst_caps_new_simple ("video/x-h264",
"variant", G_TYPE_STRING, "videosoft", NULL);
@@ -1887,6 +1898,7 @@ gst_riff_create_video_template_caps (void)
GST_MAKE_FOURCC ('H', '2', '6', '3'),
GST_MAKE_FOURCC ('V', 'X', '1', 'K'),
GST_MAKE_FOURCC ('H', '2', '6', '4'),
+ GST_MAKE_FOURCC ('H', '2', '6', '5'),
GST_MAKE_FOURCC ('H', 'F', 'Y', 'U'),
GST_MAKE_FOURCC ('I', '2', '6', '3'),
GST_MAKE_FOURCC ('I', '4', '2', '0'),
--
2.17.1