1.flv.js源码知识点(下) FLV格式解析
2.流媒体协议图解 FLV 协议 快速入门
3.flv.js源码知识点(中)
4.网页中进行在线播放Flv/mp4的码源码代码
5.流媒体客户端RTMP拉流保存h264(flv保存为h264)
flv.js源码知识点(下) FLV格式解析
flv.js系列三:FLV格式解析
此篇文章为flv.js源码知识点系列的终篇,旨在深入解析FLV文件的源码格式。在理解FLV文件数据结构及如何在JavaScript中读取特定二进制数据的码源码基础上,文章将引导读者逐步构建对FLV文件解析的源码全面认知。
FLV格式解析主要涉及两个关键部分:FLVHeader和FLVBody。码源码FLVHeader为文件的源码工具易语言源码前导部分,固定长度为9字节,码源码其结构定义了文件的源码后续部分。FLVBody包含多个Tag,码源码每个Tag由TagHeader和TagData组成,源码Tag的码源码结构为字节,体现了FLV文件的源码层次化和可扩展性。
在进行FLV文件解析时,码源码二进制数据读取API显得尤为重要,源码特别是码源码DateView类的使用。DateView允许以位级别访问ArrayBuffer中的数据,提供了读取、写入以及转换数据类型的能力,极大地简化了二进制数据的处理流程。
具体而言,DateView提供了构造函数new DataView,用于指定数组缓冲区、偏移量和长度。获取数据时,可以通过getUint8、getUint等方法,灵活地读取不同长度的整数。此外,了解字节序(大字节序与小字节序)的概念及其对数据读取的影响,对于正确解析FLV文件至关重要。
位操作是小游戏app源码二进制数据处理的另一大利器,包括按位非、按位与、按位或、按位异或以及位移操作等。这些操作允许在位级别上进行复杂的数据提取和重组,对于处理如FLV标签中的时间戳拼接等特定场景尤为关键。
最后,文章强调了结合FLV格式文档和二进制数据读取技术进行解析的重要性。通过解析每个字段,开发者可以有效地理解和处理FLV文件中的音视频数据,为后续的音视频解码、传输和播放提供坚实基础。
通过本系列文章的学习,读者不仅掌握了flv.js源码的解析原理,还深入理解了FLV文件格式的内在结构与处理方法,为音视频开发工作打下坚实的技术基础。
流媒体协议图解 FLV 协议 快速入门
FLV格式是随着Flash MX的推出发展而来的视频格式,其特点是文件体积小、加载速度快,使得网络视频观看成为可能。FLV协议由FLV头和FLV文件主体两部分组成,主体由多个FLV标签组成,每个标签包括标签头部和标签主体。FLV格式包含FLV头、FLV主体和多个标签,主体由一系列的TagSize和Tag组成。FLV标签分为三大类:Tag头部占个字节,视频标签表明Data存储视频数据,由视频头部(5个字节)和视频数据组成;音频标签表明Data存储音频数据,由音频头部(2个字节)和音频数据组成;脚本数据标签通常用于存放FLV中的股票分时线源码音视频相关元数据,采用AMF封装数据类型,如字符串、数值、数组等。FLV格式整体图清晰展示了其构成结构。在深入理解协议后,可对照obs打包FLV源码,更好地掌握FLV文件协议。打包过程涉及FLV头、脚本标签、视频标签和音频标签的打包,确保协议遵循性。掌握FLV协议并非难事,更多挑战来自音视频编解码知识,建议在学习过程中查阅相关资料,同时注意FLV的大端序字节序特性。
flv.js源码知识点(中)
本文续接上篇,深入探讨flv.js的内部机制,特别是网速计算和数据缓存处理。在播放过程中,用户网速的稳定性对体验至关重要。flv.js通过statistics_info事件实时反馈当前网速,speed字段以KB/s为单位。计算过程巧妙地利用时间差值,确保准确反映最近一秒的数据传输速率,而非上一秒。
网速计算的关键在于addBytes方法,它通过比较当前时间和上一次计算时间的差异,来动态调整网速估计。currentKBps属性仅在durationSeconds大于0.5时使用,冲销量指标源码以减少误差。平均网速averageKBps会在网络中断或暂停时受到影响。
数据缓存处理涉及loader获取数据后至FLVDemuxer的中间环节。FLV格式数据以TAG为单位,因此需要将连续字节缓存起来,直到遇到完整的TAG。这个过程在IOController中实现,涉及ArrayBuffer的二进制缓存操作,如使用Uint8Array存储和处理数据。文章详细介绍了缓存扩展和消费的方法,以及如何根据网速动态调整缓存大小。
后续内容将涉及FLV格式的解析和位操作。请继续关注,以了解更多flv.js源码的深层次知识。
原文链接已删除,如果你对C++音视频开发感兴趣,可以搜索相关资源进行学习。
网页中进行在线播放Flv/mp4的代码
在线播放Flv/mp4的代码,首先可以选择使用js.alixixi.com的资源,但是经过梦翔儿的研究,发现精简版同样可以满足需求。
需要注意的是,对于相对路径,应当确保其相对于播放器flvplayer.swf的位置。
更进一步的复杂操作,可以探索JWplayer。JW FLV MEDIA PLAYER是一款开源的网页视频、音频及播放器,支持Sliverlight播放。通过XML文件可使播放器自动切换显示一组并播放背景音乐。乐看5.0源码
为确保播放器正常工作,需要在线参数设置向导longtailvideo.com/suppo...
源码下载链接为developer.longtailvideo.com...
在本地测试无误后,将代码部署至服务器,却遇到了错误。梦翔儿意识到可能是mime头问题。在IIS中,对于相应的网站,右键选择“属性”,进入“HTTP头”选项卡,点击“MIME类型”,新建扩展名和MIME类型,分别为“mp4”和“application/octet-stream”。完成设置后,刷新页面,问题得到解决。
对于IIS环境的用户,在进行上述步骤后,确保问题得到解决。此外,需注意,之前的博客可能已经存在更好的解决方案。
流媒体客户端RTMP拉流保存h(flv保存为h)
librtmp是通过调用int RTMP_Read(RTMP *r, char *buf, int size); 来拉取流,直接得到的流是flv格式,保存后即可播放。
RTMP_Read内部调用Read_1_Packet,其功能是从网络上读取一个RTMPPacket的数据,RTMP_Read在此基础上增加了个字节的flv头。
在librtmp的源码中,可以看到flv头信息。
flv头实际只有9个字节,但为何是个字节?因为除了9个字节的flv头外,还有多个Tag,每个Tag的开头有4个字节表示上一个Tag的长度,即使是第一个Tag也需填充这4个字节,以匹配源码中的flvHeader。
srs_librtmp是通过srs v2.0-r6版本(v2.0-r7版本加入了ipv6功能,但连接rtmp服务器时总是失败,可能是个人使用不当)来拉流并保存为flv文件。
从srs导出的srs_librtmp客户端详情见github.com/ossrs/srs/wiki...,导出后,在research/librtmp下有作者编写的demo,其中srs_rtmp_dump.c用于从rtmp服务器拉流并保存为flv文件。
以下是简化版的demo源码,我注释了自己的理解,若有错误请指正。在vs下此代码能编译运行,但在linux下能正常播放。
主要讲述了flv头信息的结构,srs_librtmp源码中srs_flv_write_tag通过data封装成Tag并写入flv文件,srs_rtmp_read_packet读取的数据是flv文件中的tag data。
Tag data分为Audio、Video、Script三种,这里仅讲解Video Tag Data。
VideoTagHeader的第一个字节包含了视频帧类型及视频CodecID的基本信息。VideoTagHeader之后跟着的是VIDEODATA数据,即video payload,对于H.格式的视频,VideoTagHeader会额外包含4个字节的信息。
AVCPacketType和CompositionTime。AVCPacketType表示VIDEODATA的内容类型:若AVCPacketType为0,则为AVCDecoderConfigurationRecord(H.序列头);若为1,则为一个或多个NALU(完整帧是必需的)。
AVCDecoderConfigurationRecord包含H.解码相关的sps和pps信息,解码器在送数据流之前必须送出sps和pps信息,否则解码器不能正常解码。在解码器停止后再次开始之前,如seek、快进快退状态切换等,都需要重新送出sps和pps的信息。AVCDecoderConfigurationRecord在FLV文件中通常只出现一次,即第一个video tag,但有些视频流的sps和pps可能会发生变化,所以可能会出现多次。
Composition Time用于告知渲染器视频帧进入解码器后多长时间在设备上显示。在flv格式中,timestamp用于告知帧何时提供给解码器,单位为毫秒。Composition Time告诉渲染器视频帧显示的时间,因此compositionTime = (PTS - DTS) / .0。
总结如下:使用srs_librtmp拉流,拉取的数据为一个又一个的Tag Data,可通过type与宏值比较判断Tag Data是否为Video Tag Data。连接rtmp服务器拉流时收到的第一个Video Tag Data通常包含PPS和SPS信息。对于每个h编码的Video Tag Data,会多出4个字节的AVCPacketType和CompositionTime,其中CompositionTime用于B帧,这里暂时忽略它,我们仅支持P帧和I帧。Frame Type在h编码中只能是1或2,Frame Type == 1表示关键帧或包含PPS和SPS信息的Video Tag Data。CodecID在h编码中只能是7(AVC)。当AVCPacketType == 0时,Video Tag Data包含SPS和PPS信息;当AVCPacketType == 1时,为帧数据。
获取PPS和SPS信息非常关键,如果不告知解码器,根本无法播放视频。我写了一段代码,虽然技术有限,但希望能帮助到您。
AVCPacketType为1表示Video Tag Body的内容是NALU。Frame Type为1表示NALU内容是关键帧,Frame Type为2表示NALU内容是非关键帧。NALU的开头的4个字节表示NALU的长度(nalu_length),nalu_length之后是一个字节的nalu header。
nalu header中nal_ref_idc表示优先级,范围在~(2进制),值越大表示越重要。值指示NAL单元的内容不用于重建影响图像的帧间图像预测。对于nal_unit_type为6、9、、、的NAL单元,H.规范要求NRI的值应该为0。对于nal_unit_type等于7、8(指示顺序参数集或图像参数集)的NAL单元,H.编码器应设置NRI为(二进制格式)。nal_unit_type表示nalu类型,SPS开头是0x(nal_ref_idc为3,nal_unit_type为7),PPS开头是0x(nal_ref_idc为3,nal_unit_type为8),关键帧开头是0x(nal_ref_idc为3,nal_unit_type为5),非关键帧开头是0x(nal_ref_idc为2,nal_unit_type为1)。nal_unit_type为5表示idr帧,idr帧具有随机访问能力,所以每个idr帧前需要加上sps和pps。startcode起始码。
H.原始码流由一个一个的NALU组成,其结构包括起始码(0x或0x,取决于编码器实现)和数据。具体何时使用3个字节的起始码,何时使用4个字节的起始码,这个我没有完全弄明白,资料中提到具体哪种开头取决于编码器实现。0x是NAL起始前缀码,解码器检测每个起始码,作为NAL的起始标识,当检测到下一个起始码时,当前NAL结束。同时H.规定,当检测到0x时,也可以表示当前NAL的结束。对于NAL中数据出现0x或0x时,H.引入了防止竞争机制,如果编码器检测到NAL数据存在0x或0x时(非起始码,而是真正的音视频数据),编码器会在最后个字节前插入一个新的字节0x,这样当遇到0x或0x时就一定是起始码了。解码器检测到0x时,把抛弃,恢复原始数据。因此,组装H的步骤如下:读取tag data并判断是否是video tag data,判断frameType和AVCPacketType,区分video tag data是AVCDecoderConfigurationRecord还是NALU,如果是AVCDecoderConfigurationRecord则解析PPS和SPS保存在内存中并加上startcode(我这里加的是0x),如果是NALU,则判断nal_unit_type(有些NALU的流比较奇怪,依然包含PPS、SPS信息,甚至还有SEI信息)。switch case根据不同的nal_unit_type来解析,并加上startcode。如果nal_unit_type == 0x,则是idr帧,需要加上PPS和SPS信息(即一个idr通常包含3个startcode,SPS一个PPS一个idr帧数据一个)。
以下是完整代码:
rtmpTo.h
rtmpTo.cpp
main.cpp
原文链接:blog.csdn.net/qq_...
2024-11-25 09:33
2024-11-25 09:01
2024-11-25 08:46
2024-11-25 08:37
2024-11-25 08:19
2024-11-25 07:05