一、直播流

1.1 视频流

1.1.1 分辨率(FMP4)

  • 实际观测:如果不切换fmp4流中的 #EXT-X-MAP:URI="h1xxxxxxxx.m4s" 文件,并且持续接收m4s流,如果遇到主播切换视频分辨率,那么录制出的视频会有多个分辨率。但是元信息中显示的分辨率会是第一次接收#EXT-X-MAP:URI="h1xxxxxxxx.m4s"时返回的分辨率。

  • 依据:

    • 在B站直播中确实可以随时切换分辨率,流不断开。

    • B站直播时可以与其他主播连麦,合并两路视频流。此时的分辨率会变成近似正方形的分辨率。

  • 后果^note01:系统自带播放器会把画面拉伸。但是视频不会因此损坏,使用MPV可以正常播放。

1.1.2 mdat中的BVCLIVESTREAMHOP

  • 实际观测:只要是以原始流(指不二次压缩转码)录制的视频文件,在数据块(此处以MPEG-4的mdat为例)中,会看到:

BVCLIVESTREAMHOP[{"author":"pc_link","author_ver":"6.24.0.8301","clock_max_error_ms":52,"curr_ms":1742864076071},{"author":"mg","author_ver":"v1.8.34","host":"edge-computing-bvc-self-cn-jsyz-ct-03-07-585fff6d76-8shft","cluster":"bvc-self-cn-jsyz-ct-03","curr_ms":1742864076699}]

类似的ASCII字符串。

  • 依据:

    • 目前未知这东西的具体用途,但是貌似包含了B站直播流编码服务器的一些元数据。

    • 目前发现,所有的直播都会有这个,并且基本上是每一个(或者隔几个)m4s分片(flv是隔一段时间)之后都会掺杂这个字符串。

  • 后果:数据位于mdat数据块中,所以除了ASCII编辑器以外,没有软件能读到这个信息。

1.1.3 mdat中的其他不常见数据

  • 实际观测:部分直播由于使用了B站的某些功能,导致使用功能时会在视频流中有记录。

一些未知用途的数据如下(采集于视频中,未改动):

IRCA_SEI_PC_LINK{"MULIT_VIDEO_LINK":{"data":[],"invoking_time":2,"is_deprecated":1,"layout":"left1_right1","room_start_at_ts":643,"version":1742788235942}}
BVCLIVETIMESTAMP{"author":"nginx","curr_ms":1742817624296}
// 这个看名字是记录直播的unix时间
IRCA_SEI_PC_LINK{"MULIT_VIDEO_LINK":{"data":[{"avatar":"https://i0.hdslb.com/bfs/face/aa90d66509d2525a874c40190d886e062bb01703.jpg","gender":-1,"nickname":"\u5C0F\u96EA\u597D\u8FD0\u8FDE\u8FDE","pos_index":1,"price":0,"price_text":"0","room_id":1920035951,"uid":3546714107545875,"volume":0},{"avatar":"https://i2.hdslb.com/bfs/face/b69f844ffe78b042c5bd750d1eec53c17e578ec6.jpg","gender":-1,"nickname":"\u5C0F\u4E5D28\u53F7\u5468\u5E74\u5566","pos_index":2,"price":0,"price_text":"0","room_id":32309229,"uid":3546649739659622,"volume":19335}],"invoking_time":2,"is_deprecated":1,"layout":"left1_right1","room_start_at_ts":1051,"version":1742734541531}}
//这个是在双屏连麦时候会出现,此时会改变视频分辨率。
  • 后果:数据位于mdat数据块中,所以除了ASCII编辑器以外,没有软件能读到这个信息。但是好处是多了一些和直播相关的数据以便分析。

1.1.4 HLS流的M3U8自定义参数(FMP4)

  • 实际观测:目前获取fmp4格式的m3u8索引文件,会发现这个文件是被B站加了自定义参数的,并且有一些含义。

m3u8样例:

#EXTM3U
#EXT-X-VERSION:7
#EXT-X-START:TIME-OFFSET=0
#EXT-X-MEDIA-SEQUENCE:6743230
#EXT-X-TARGETDURATION:1
#EXT-X-MAP:URI="h1742371280.m4s"
#EXT-BILI-AUX:1f3b9f1|K|e19ac|b1c64b4f
#EXTINF:1.00,e19ac|b1c64b4f
6743230.m4s
#EXT-BILI-AUX:1f3bdb8|N|96232|9ebe7f7f
#EXTINF:1.00,96232|9ebe7f7f
6743231.m4s
#EXT-BILI-AUX:1f3c1c1|K|10703d|5d47057f
#EXTINF:1.00,10703d|5d47057f
6743232.m4s
#EXT-BILI-AUX:1f3c588|N|90f1e|70dc1956
#EXTINF:1.00,90f1e|70dc1956
6743233.m4s
#EXT-BILI-AUX:1f3c991|K|ddf41|50726259
#EXTINF:1.00,ddf41|50726259
6743234.m4s
#EXT-BILI-AUX:1f3cd58|N|963a5|23b3c9fe
#EXTINF:1.00,963a5|23b3c9fe
6743235.m4s

其中,#EXT-X-MEDIA-SEQUENCE:6743230代表该m3u8的起始分片序号,但是当实际序号超过9999999时,这个序号就不可靠了。

#EXT-BILI-AUX:1f3b9f1|K|e19ac|b1c64b4f的解析:未知|应该是分片类型|未知|CRC32校验码

  • 后果:可以通过这些信息来判断当前m3u8中的流是否正确,以及校验分片完整性。

1.1.5 视频文件头中的直播推流客户端标识符

  • 实际观测:无论是flv还是fmp4原始流,文件头中都会有关于主播使用的推流软件的基本参数。

目前用的最多的是:BVC-SRT LiveHime/6.24.0(B站官方直播姬)和(libobs version 31.0.2)(OBS),版本号各有不同,此处只举例

  • 依据:

    • 每个直播都会有这个标识。

    • 如果流被压缩(不是原画),那么这个标识符就不再是原始的了,而是B站的直播视频编码器。可以通过这个特性判断下载的是不是原始画质的流。

  • 后果:可以知道主播在用什么(版本的)软件🤔。

1.1.6 高效压缩

  • 实际观测:一旦视频中有空白画面/无声音,那么对应的分片会很高效的压缩,压缩后的分片只有几十KB。

  • 依据:🤔B站肯定不想浪费流量(

  • 后果:节省部分存储空间。其余无影响(但是BVCxxx的数据仍然会有)

1.1.7 视频流TimeStamp offset(FMP4)

  • 实际观测:下载fmp4流时,无论以什么方法下载,存储在"h1xxxxxxxx.m4s"(也有可能是在m4s的元数据部分)中的时间偏移量永远等于客户端中显示的持续直播时长。

在视频下载完后,使用MPV播放时,进度条会从视频文件录制时获取的那个直播时长为起始,所以会看到一打开视频就显示在几个小时,并且这之前的进度条无法拖动(因为对应的分片根本没下载,如果补上之前的分片则可以拖动到对应位置。)

  • 后果:部分播放器的进度条组件会彻底失效。但是使用FFmpeg复制一次流就不再有这个问题。

二、直播流API

2.1 getRoomPlayInfo API的返回值

2.1.1 不返回真原画地址,但可手动拼接字符串

(部分JSON)
                "format_name": "fmp4",
                "codec": [
                  {
                    "codec_name": "avc",
                    "current_qn": 10000,
                    "accept_qn": [10000, 400, 250, 150],
                    "base_url": "/live-bvc/544181/live_392836434_52698792_bluray/index.m3u8?",
                    "url_info": [
                      {
                        "host": "https://cn-sxxa-cm-01-03.bilivideo.com",
                        "extra": "expires=1742921243&len=0&oi=0x24098a7002b33b3115e31bf02e960edf&pt=web&qn=10000&trid=10070275ba6278f6d722085c00632867e2d0&sigparams=cdn,expires,len,oi,pt,qn,trid&cdn=cn-gotcha01&sign=d3863355762738a257464c66380e94c7&site=7e9ea46673c899115640c608c2355a4a&free_type=0&mid=14120472&sche=ban&bvchls=1&sid=cn-sxxa-cm-01-03&chash=0&bmt=1&sg=lr&trace=65&isp=cm&rg=NorthWest&pv=Shaanxi&score=100&long_ab_flag_value=test&sl=3&strategy_id=24&hot_cdn=909701&source=puv3_onetier&pp=rtmp&suffix=origin&flvsk=1174fda3e37dc7adc04251e0e9785a49&deploy_env=prod&ld=gjz&strategy_version=latest&p2p_type=1&info_source=cache&long_ab_flag=live_default_longitudinal&origin_bitrate=692365&sk=a6a3deaaf651addb739bfb48c2f5bde0&long_ab_id=45&vd=nc&zoneid_l=151437315&sid_l=live_392836434_52698792&src=puv3&order=1",
                        "stream_ttl": 0
                      }
                    ],
                    "hdr_qn": null,
                    "dolby_type": 0,
                    "attr_name": "",
                    "hdr_type": 0
                  },

从中发现,直播流的base_url地址中会有_bluray后缀。类似的后缀还有:_prohevc _2500 _1500(可能还有更多但是并未发现)。

但是,如果把这些后缀删去,再访问URL,仍然可以获得原画的URL并且可以正常录制。

  • 依据:

    • 多个开发者早就发现了此问题,API根本不返回原画,导致画面糊,码率低。

    • 部分录播软件开发者可能不知道解决办法,就不再更新这方面的解决办法,导致录播软件无法正常使用。

  • 后果:无法正常获取原画,导致下载变得麻烦。

三、信息流

3.1 弹幕信息流

3.1.1 使用短链ID无法获取完整的数据

  • 实际观测:如果使用短链ID(比如5050)发送数据包并验证WebSocket连接,那么后续将不会获得完整的信息流数据包。

但是可以通过https://api.live.bilibili.com/room/v1/Room/get_info?room_id={roomid}获取到room_id这个值,是完整的ID。

这块神奇特性,短链ID和完整ID之间的不完全互通,估计是B站史山代码导致的,各个API行为不一致。

  • 后果:获取信息流的代码需要多加一步获取完整ID的方法。