H5流式播放(FMP4转封装与mediaSource)

H5流式播放(FMP4转封装与mediaSource)

2023年6月27日发(作者:)

H5流式播放(FMP4转封装与mediaSource)mediaSource接⼝的介绍W3C上有明确关于mediaSource 扩展接⼝的⽂档。mediaSource 扩展⽂档中是这么定义的, 它允许JS脚本动态构建媒体流⽤于和,允许JS传送媒体块到H5媒体元素。这种接⼝的应⽤可以让h5播放器实现持续添加数据进⾏播放。做as的朋友都知道as中的appendBytes⽅法,⼀种添加⼆进制数据进⾏播放的⽅式。这两种接⼝在概念上是类似的。只是⾥⾯的定义和对媒体⽂件的要求有所不同。对于mediaSource扩展接⼝我只介绍我们主要应⽤的⼏个。判断是否存在mediaSource扩展类该语句决定了整个播放⽅式是否可以使⽤meidaSource接⼝控制播放。ource = ource || MediaSource;//分为pc和移动两种isTypeSupported判断是否⽀持要解码播放的视频⽂件编码和类型。Supported('video/webm; codecs=“vorbis,vp8”’);//是否⽀持Supported('video/mp4; codecs=“avc1.42E01E,mp4a.40.2”’);//是否⽀持Supported('video/mp2t; codecs=“avc1.42E01E,mp4a.40.2”’);//是否⽀持tsaddSourceBuffer该事件是在触发sourceopen监听时进⾏的,该动作会创建⼀个sourceBuffer对象⽤于数据流的播放处理。如果mediaSource对象⽆法触发该事件,则⽆法通过该扩展进⾏播放的。sourceBuffer = rceBuffer(DOM string);如:rceBuffer('video/mp4; codecs=“avc1.42E01E,mp4a.40.2”’);appendBuffersourceBuffer对象的⽅法,⽤于持续数据的添加播放。Buffer(Uint8array);// Uint8array:媒体⼆进制数据buffered类型为TimeRanges,描述了添加进去的所有媒体数据的range信息。为⼀个数组,⾥⾯标⽰了持续或间断的时间信息列表。如:for(var i=0;i<;i++){ start = (i);//第i个range信息的开始时间 end = (i);//第i个range信息的结束时间}如果播放的媒体数据是连续的则只有⼀个开始时间点和⼀个结束时间点。所以如果要计算缓冲中还存在多少时间则可以通过该描信息与当前播放时间点进⾏换算。/** * Created by YL on 2016/5/21. */function play() { if (!ource) { ource = new MediaSource(); var me = this; ntListener('sourceopen', function () { aSourceOpen(); aSourceOpen(); }); ntListener('sourceended', function () { aSourceEnded(); }); ntListener('sourceclose', function () { aSourceClosed(); }); ntListener('error', function () { teError(); }); = NewVideo();//创建HTMLMediaElement; = ObjectURL(ource); (); } if (!Buffer) { return; } if (ng)//上⼀块数据还在添加中 { return; } try { Buffer(dataBytes);//添加数据 } catch (err) { }}function createNewVideo() { var newVideo = Element("video"); = "player"; = idth; = eight; return newVideo;}//事件侦听onMediaSourceOpen: function () {//DOMString 可以通过转码获得; var typeName = 'video/mp2t; codecs=“avc1.64001f”’; var issurpport = Supported(typeName);//是否⽀持 on = uration;//设置视频总时长 Buffer = rceBuffer(typeName);}onMediaSourceEnded:function () { ("source ended!");}onMediaSourceClosed:function () { ("source closed!");}FMP4封装格式要求在W3C⾮官⽅标准⽂档ISO BMFF Byte Stream Format中明确规定了fmp4媒体⽂件封装的具体要求。

fmp4的封装可以分为Initialization Segments和media Segments两种,这两种的基本封装格式相差不多。关于Initialization Segments必须注意的以下⼏点:⽂件类型声明ftyp的box包含的major_brand或者compatible_brand⽤户代理⽅必须⽀持。mohd box⾥的任意box或者字段不能违背在ftyp box⾥定义的major_brand或者compatible_brands中的任何⼀个授权。mohd中包含的samples的track(如stts,stsc,或者stco 中的entry_count必须被设置成0);mvex box必须在moov中被包含,注:该box说明该视频包含moof需要解析。media Segments的封装要求基本类似,同时增加了以下⼏点:styp必须遵循ftyp;traf⾥⾯必须包含tfdt;mdat⾥的samples必须和trun⾥⾯的对应。不同浏览器的解析兼容有所不同,未按上述要求封装的fmp4有的浏览器也可解析,不过数据的播放会存在问题,如卡顿,不流畅等。FMP4封装主要box说明1.

2. BOX:这个box由长度信息和box类型两部分组成,即size,type。size为⼀个长度数据,描述type⾥⾯包含的数据长度。3. fullbox:继承BOX包含 version(8bit)和flags(24bit)两个数据,版本和格式描述;4. ftyp,styp:继承BOX,包含3个描述字段:major_brand,minor_version,compatible_brands.

如:0000001C 66747970 6D703432 00000001 69736F6D 6D703432 64617368其中

0000001C为size长度的16进制32位数据,计算结果为28,即该box的总字节长度;第⼆个4个字节66747970为ftyp的code码的16进制数;第三个4字节数6D703432为major_brand字段值,转化成字符串为mp42;第四个4字节数00000001为版本标⽰;第五,六,七分别描述了⼀个list数组(69736F6D6D703432 64617368)为compatible_brands转化为字符串为isommp42dash。moov:继承BOX,包含mvhd,mvex,trak,这⾥有⼏点需要注意。mvex必须包含,trak下⾯的stts,stsc,stco⾥⾯的entry_count设置成:包含:mehd,trex。trex:继承fullbox,包含字段:unsigned int(32) version;//0 unsigned int(32) track_ID;//1.视频,2.⾳频

unsigned int(32) default_sample_description_index;//sample描述索引

unsigned int(32) default_sample_duration; //默认sample时长 unsigned

int(32) default_sample_size;//默认sample⼤⼩ unsigned int(32)

default_sample_flags//默认sample标⽰。 以上default_的数据会在moof中没有声明时默认使⽤。trak:继承BOX,包含的box有tkhd,mdia。tkhd:继承fullbox,包含字段:unsigned int(32) version;//版本,这⾥默认写成0

unsigned int(32) creation_time;//创建时间

unsigned int(32) modification_time;//修改时间 unsigned int(32) modification_time;//修改时间

unsigned int(32) track_ID;//1:视频,2:⾳频

const unsigned int(32) reserved = 0;

unsigned int(32) duration;//时长,因为要封装成fmp4,这⾥写为0;

const unsigned int(32)[2] reserved = 0;

template int(16) layer = 0;

template int(16) alternate_group = 0;

template int(16) volume = {if track_is_audio 0x0100 else 0};

const unsigned int(16) reserved = 0;

template int(32)[9] matrix={ 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };

// unity matrix

unsigned int(32) width;

unsigned int(32) height;mdia:继承box,包含mdhd,hdlr,minf;mdhd:继承fullbox,包含字段:unsigned int(32) creation_time;//创建时间 unsigned int(32)

modification_time;//修改时间 unsigned int(32) timescale;//时间⽐例 unsigned

int(32) duration;//时长,fmp4可以写为0 bit(1) pad = 0; unsigned int(5)[3]

language; //写为:0x55C4 code unsigned int(16) pre_defined = 0;moof:继承BOX,包含mfhd,traf;mfhd:继承Fullbox,包含字段:

unsigned int(32) version and flags; unsigned int(32)

sequence_number;//fragment序列号:包含tfhd,trun,tfdt;

:继承fullbox,包含字段:

unsigned int(32) version and flags;

unsigned int(32) track_ID;

unsigned int(64) base_data_offset;

unsigned int(32) sample_description_index;

unsigned int(32) default_sample_duration;

unsigned int(32) default_sample_size;

unsigned int(32) default_sample_flags字段1版本和标识符值描述:

* 0x000001 base-data-offset-present//基本数据偏移位置是否出现

* 0x000002 sample-description-index-present//samplem描述索引是否出现

* 0x000008 default-sample-duration-present//默认sample时长是否出现

* 0x000010 default-sample-size-present//默认sample⼤⼩是否出现

* 0x000020 default-sample-flags-present//默认sample标志是否出现

* 0x010000 duration-is-empty 时长为空(default_sample_duration或者trex⾥的时长)

0x020000 default-base-is-moof//从每个moof的开始计算偏移在这⾥我们使⽤0x020000,即每个视频的偏移位置从moof算起。:继承Fullbox,包含字段:unsigned int(32) version //使⽤0;

if (version==1) {

unsigned int(64) baseMediaDecodeTime;

} else { // version==0

unsigned int(32) baseMediaDecodeTime;

}//所有添加进去的sample解码时长总和。:继承fullbox,这是⼀个主要字段,描述了各个sample 信息。

字段包括:

unsigned int(32) version and flags;//描述标⽰

unsigned int(32) sample_count;//sample数量。

signed int(32) data_offset;//sample开始偏移

unsigned int(32) first_sample_flags;//关键标⽰符

{

unsigned int(32) sample_duration;//sample时长

unsigned int(32) sample_size;//sample⼤⼩

unsigned int(32) sample_flags//sample标⽰

if (version == 0)//视频播放时间与解码时间偏移

{ unsigned int(32) sample_composition_time_offset; }

else

{ signed int(32) sample_composition_time_offset; }

}[ sample_count ]字段1说明:

* 0x000001:data-offset-present//数据偏移,从moof算起,到 mdat结束。

* 0x000004:first-sample-flags-present;//关键sample标⽰是否描述。

* 0x000100 sample-duration-present: 标⽰每⼀个sample有他⾃⼰的时长, 否则使⽤默认值.

* 0x000200 sample-size-present:每个sample拥有⼤⼩,否则使⽤默认值

* 0x000400 sample-flags-present:每个sample有他⾃⼰的标志,否则使⽤默认值

* 0x000800 sample-composition-time-offsets-present; 每个sample 有⼀个composition time offset

这⾥我们根据视频和⾳频分别采⽤不同值,标⽰符的值是有各个要使⽤的标⽰值相加获得。

:继承Box,视频和⾳频的主体数据。

字段:bit(8) data[];

以上是⼀些基本box的描述,具体细节可以参考INTERNATIONAL STANDARD ISO/IEC 14496-12 ⾥⾯的详细定义.

4封装中的问题和解决⽅式

在fmp4转封装的过程中最基本要注意的是box的描述尽量完整,每个代理⽅对box的兼容性不同,有的在缺失部分描述信息时依然可以完成播放,⽽有的则会直接出现解码错误退出播放。

我们这⾥主要注意⼏点:

gment 描述ftyp开头,包含moov,moof,mdat;

egment 描述styp开头,包含moov,moof,mdat;有的浏览器,如safari8.0在没有moov的情况下依然可以流畅的播放视频。但是在chorome浏览器下则会出现解码错误。

:tf_flags 这⾥使⽤0x020000,只说明如果base data offset为0时使⽤trun⾥⾯相对于moof的数据偏移信息。该标⽰在ios5以后的版本中⽀持。因为我们需要转封装成fmp4,所以应该使⽤相对于moof的偏移,这样每次append进去的数据才不会在计算起始位置上出现不准确的问题。

box的信息中baseMediaDecodeTime会决定mediaSource⾥的TimeRange信息的起始。这个值有3种途径获得,1.计算前⾯添加数据的总时长;2.提取要添加数据的第⼀个sample时间戳。3.根据ts数据的id信息。

box的描述:version和flags描述值根据⾃⼰的需要计算获得,⽐如视频数据我们需要描述实际数据偏移(data offset),关键帧标⽰(first sample flags)以及每个sample标⽰符,⼤⼩和时间偏移,⽽这些数据对应的开始标⽰分别为:0x000001(dataoffset),0x000004(first sample flags),0x000200(sample size present),0x000400(sample flagspresent),0x000800(sample-composition-time-offsets-present).把这些值相加为0xe05(version flags).所以说version flags的值决定了下⾯描述信息的分析⽅式。⽽对于⾳频数据我们使⽤0x201,描述信息中只包含数据偏移值和每个sample的⼤⼩。

发布者:admin,转转请注明出处:http://www.yc00.com/web/1687821800a48128.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信