分类目录归档:程序猿

终于整完了mp4 demuxer

想了挺久分段mp4的播放有什么解决方案,看着flvjs眼馋,然后一直想坑,但是又懒于开工

于是趁着这个五一,刚好前两周学校里的好几科期中也考完了,开坑!

QQ截图20170501003619

说是五一开坑,其实二十多号复制了个segment-mp4-player的时候就已经开始去翻着找mp4格式说明了。

以前听过song神说过mp4的box地狱,但是并不特别懂。正式看资料以后才算是真正理解。

具体细节就不说了,真的好奇就看文档

读取moov的时候,为了省事,我直接上了一个递归函数,一劳永逸,然后只要把boxName给switch一下具体parse就可以了。

其实mp4的格式真正读起来不会特别复杂,理清层级关系,明白自己在做什么,要获取什么,也就能顺路完成。

相比起读数据,我倒是觉得读完后整理数据才是真正的大头,比如把关键帧梳理出一个timestamp->fileposition的表才是最考验逻辑的。写的时候整个人脑子处于一种混乱的状态,最后是在顶不住选择了稳妥的列逻辑,一步步理出数据

QQ截图20170501003659

至于主要数据流的mdat部分,这部分完全就是一整片数据堆砌。同样,这里是另一个需要强逻辑的地方,每次读sample都需要先在已有的moov数据里面找到对应offset是谁的采样、采样时间戳是多少、采样有多大。我在这里直接选择了提前生成一个chunkMap,读取起来那叫一个爽快

QQ图片20170501003806

一路写代码的途中也是经常和xqq大佬交流(骚扰),也学到了很多

大概也就是这么些,说到底写出来还是个自用的东西,这年头自己做视频播放谁还专门整分段mp4

QQ图片20170501004141

gayhub

关于b站新弹幕格式.pb

格式为google protocol buffer (protobuf)

地址格式为{cid}-{part}.pb,每part包含3分钟的弹幕内容,即边播放边加载模式,如-3.pb包含第6-9分弹幕

在bilibiliPlayer.min.js中有大部分field id的定义,但文件中出现了id12-14

pb格式弹幕 Field常量
1  row (Row)
2  chat_server (string)
3  chat_id (varint32)
4  mission (varint32)
5  max_limit (varint32)
6  source (string)
7  ds (varint32)
8  de (varint32)
9  max_count (varint32)
10 realname (varint32)
11 sectionlen (varint32)(一般为180)
//猜测id
12 duration (float)
13 total_count (varint32)
14 pb_version (varint32)(目前常量1)

pb格式弹幕row Field常量
1  playtime (float)
2  mode (varint32)
3  fontsize (varint32)
4  color (varint32)
5  times (varint32)
6  poolid (varint32)
7  hash (string)
8  dmid (varint32)
9  msg (string)
10 uid (varint32)(暂未出现)
11 uname (string)(暂未出现)

其中varint32为变长度int32格式,具体为每字节只有后7位存储数据,第1位为指示位,为1时继续读取下一字节

function readVarInt32($fp){
	$b=0;
	$result=0;
	
	do{
		$b=unpack('C',fread($fp,1))[1];
		$result  = $b & 0x7f;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<7;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<14;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<21;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<28;
		if(!( $b & 0x80 ))
			break;
		
		for($i=0;$i<5;$i++){
			$b=unpack('C',fread($fp,1))[1];
			if(!( $b & 0x80 ))
				break;
		}
	}while(false);
	return $result;
}

文件读取代码样本

<?php
/*
 BiliBili pb danmaku reader
 @author esterTion(esterTionCN@gmail.com)
*/
$pb=fopen('http://comment.bilibili.com/14328539-1.pb','r');

function readVarInt32($fp){
	$b=0;
	$result=0;
	
	do{
		$b=unpack('C',fread($fp,1))[1];
		$result  = $b & 0x7f;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<7;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<14;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<21;
		if(!( $b & 0x80 ))
			break;
		
		$b=unpack('C',fread($fp,1))[1];
		$result |= ($b & 0x7f)<<28;
		if(!( $b & 0x80 ))
			break;
		
		for($i=0;$i<5;$i++){
			$b=unpack('C',fread($fp,1))[1];
			if(!( $b & 0x80 ))
				break;
		}
	}while(false);
	return $result;
}
function readString($fp){
	$strLength=readVarInt32($fp);
	return fread($fp,$strLength);
}
$types=array(
	'VARINT'=>0,
	'FIXED64'=>1,
	'DELIMITED'=>2,
	'START_GROUP'=>3,
	'END_GROUP'=>4,
	'FIXED32'=>5
);
$rowCount=0;
while(true){
	$id=fread($pb,1);
	if($id==='')
		break;
	$id=unpack('C',$id)[1];
	$type = $id & 7;
	$id = $id >> 3;
	switch($id){
		case 1:
			$rowLength=readVarInt32($pb);
			echo 'row length:'.$rowLength.' ';
			$end=ftell($pb)+$rowLength;
			$row=array();
			while(ftell($pb) < $end){
				$id=unpack('C',fread($pb,1))[1];
				$id = $id >> 3;
				switch($id){
					case 1:
						$row['playtime']=unpack('f',fread($pb,4))[1];
					break;
					case 2:
						$row['mode']=readVarInt32($pb);
					break;
					case 3:
						$row['fontsize']=readVarInt32($pb);
					break;
					case 4:
						$row['color']=substr(pack('N', readVarInt32($pb) ),2);
					break;
					case 5:
						$row['timestamp']=readVarInt32($pb);
					break;
					case 6:
						$row['poolid']=readVarInt32($pb);
					break;
					case 7:
						$row['hash']=readString($pb);
					break;
					case 8:
						$row['dmid']=readVarInt32($pb);
					break;
					case 9:
						$row['msg']=readString($pb);
					break;
					case 10:
						$row['uid']=readVarInt32($pb);
					break;
					case 11:
						$row['uname']=readString($pb);
					break;
				}
			}
			print_r($row);
			$rowCount++;
		break;
		case 2:
			echo '[chat_server] => '.readString($pb)."\n";
		break;
		case 3:
			echo '[chat_id] => '.readVarInt32($pb)."\n";
		break;
		case 4:
			echo '[mission] => '.readVarInt32($pb)."\n";
		break;
		case 5:
			echo '[max_limit] => '.readVarInt32($pb)."\n";
		break;
		case 6:
			echo '[source] => '.readString($pb)."\n";
		break;
		case 7:
			echo '[ds] => '.readVarInt32($pb)."\n";
		break;
		case 8:
			echo '[de] => '.readVarInt32($pb)."\n";
		break;
		case 9:
			echo '[max_count] => '.readVarInt32($pb)."\n";
		break;
		case 10:
			echo '[realname] => '.readVarInt32($pb)."\n";
		break;
		case 11:
			echo '[sectionlen] => '.readVarInt32($pb)."\n";
		break;
		default:
			switch($type){
				case 0:
					echo '--Unknown ID '.$id.' with varint32 value '.readVarInt32($pb)."\n";
				break;
				case 1:
					echo '--Unknown ID '.$id.' with fixed 64bit data hex '.bin2hex(fread($pb,8))."\n";
				break;
				case 5:
					echo '--Unknown ID '.$id.' with fixed 32bit data hex '.bin2hex(fread($pb,4))."\n";
				break;
				default:
					echo '--Unknown ID '.$id.' with type '.$type."\n";
			}
	}
}
echo $rowCount.' rows in file'."\n";

 

腾讯视频c___key

写了两天

看到了某被无辜挂上去的源码后就动了心思,这两天到处翻文档,lua的,php的

起初只是使用string直接充当byteArray,但是后面发现局限性后引入了byteArray和byteArrayPtr类,于是之前的各种问题都解决了

听说腾讯这套变种tea enc从99年就开始在使用了

总之可喜可贺,可喜可贺

ckey


结果过了两天准备实际用的时候发现用不了……

闹心

继续一些关于ios编译的

在找到某个被挂出来的lua源之前,我准备自己整个lua调用一下bili.utility翻翻key的

win上打不开编译版本lua,搜后说是高低位不同导致

于是又打开了黑mac搞一搞编译

本来lua编译非常简单,把一堆c一起扔给编译器就可以出binary,然后codesign一下就可以跑了

此处强烈鄙视一下BigBoss那个lua(com.deltaman.lua),不codesign就往上扔真是好意思啊

问题在于第三方的c库,比如LuaSocket

首先需要启用动态载入,编译器定义常量LUA_USE_MACOSX或LUA_USE_LINUX好像都可以,此时lua需要-lreadline -lncurses

其次,编译第三方c库时必须不使用static链接

lua会报错“multiple Lua VMs detected”

所以需要先把lua下所有基础c一起,指定-dynamiclib输出liblua.dylib,然后

xcrun -sdk iphoneos clang -arch armv7 -L. -llua lua.c -o lua

然后编译第三方库的时候同理编译就可以出.so

image

后记:原本有所期待这个key会不会有点特权什么的,比如不限速,然而依旧是rate=400(默哀客户端用户)

我继续老实用player=1吧

IPv6 & DNS64 & NAT64

又开学了

回来用u2b的时候发现用了一年的dns6to4的服务器dns64.litnet.lt (2001:778::37)停了

google的dns6 (2001:4860:4860::8888)可以获取googlevideo.com的各种正常v6地址,但是以前用这个dns64的时候是有代理能力的,可以利用6to4 tunnel

找了找以前可用的另一个  2001:df8:0:7::1 也是timed out

最终翻到了一个 totd.aa.net.uk (2001:8b0:6464::1)可行

谨此记录,以供网络之需

 

后记:aa.net.uk也死了,起初只是dns死了,自己加后缀可以正常用,结果后来整个系统都unreachable了

万能的google帮我又挖出了一个:2001:67c:2b0::4

prefix 2001:67c:2b0:db32:0:1::/96

【设想】由ffmpeg打造的点歌姬

群里的几个人在聊的这个的可行性

然后目前几方在整理可能的问题和解决方案

1、视频流上如何动态改变文字

ffmpeg的drawtext可以选择读取textfile,并且设置为reload:1时会持续重载

2、如何连续播放音频流

(未解决)目前设想测试hls兼容性,未尝试ffmpeg是否能够自动重读live型的hls

3、网络问题会导致推流失败从而ffmpeg会退出,如何连续

计划通过中间层解决,即:第一个ffmpeg实例负责读取下载到本地的音频、读取图片及文字,生成完成的流;由此ffmpeg推送到本地一个服务器,可以是ffserver或nginx;运行第二个ffmpeg负责将server的流copy至rtmp。如果rtmp发送失败只会导致第二个ffmpeg退出,重运行时不会影响到压制用实例,故可形成较为连续的流

历物语 – AWS Signature Version 4

终于把伤1看了

转着发现我漏了几天的客户端里的特殊图,找之前几位帮忙的也都没有

然后发现原来它的key是现获取的临时密钥……

难怪之前在binary里找不到


对照着官方文档摆弄了一下午,最终终于搞成了

最坑的地方是构建标准请求的时候在Header区后有两个\n


高高兴兴的直接把1/1到今天的所有信息全部获取下来了

有点小想法搭个镜像站,图+音总共似乎也不超过70M


然后就真的去弄了

顺便初接触了一下svg绘图,画了俩箭头,感觉挺简单的

https://www.biliplus.com/koyomi/

论整别人的项目有多痛苦

辣鸡svp的x86版本疑似不干活


bililocal想重编译x64

为了使用体验,clone后回滚到用的150223时的版本

配置qt,qt5.7编译出来崩溃

 

降级qt5.4,不认vs2015

下载vs2013安装,编译

出来的只能播放mp4,加载不上dsengine.dll

…………

厉害

真叼

可以的

输了,看着四个x64下了个151124用起来可以接受

自己慢慢改binary吧,远离别人的工程


本来都不想弄了

但是可以下到的那四个版本都是有问题,不算大但也是影响使用体验

在网上到处翻解决

  • dsengine.dll

官方预编译版本DirectShow只存有摄像头采集功能,需要自己下载QtMultimedia模块源码修改后编译dsengine插件

–此处我先前下载的版本是qt-5.4.0-msvc2013_x64,需要qt-5.4.0-msvc2013_x64_opengl才能编译ds插件

参考:解决Qt5.3.1不能播放mp4以及其它格式的问题

  • svp出现崩溃

这里不太清楚什么原因,似乎是碰到了什么设置,崩的时候wmp也会崩,后来改着就好了……

  • 设置界面导致退出崩溃

似乎是ssl库的原因

重新用pexports+dlltool重新导出dll入口lib后问题没了


对源码做了一些改动,包括miniLogin登录,分P识别,tucao域名


Release Custom Build on 160722 – x64


各站域名优先读取Config.txt,位于/Network/Url,直接复制旧配置会导致tucao依旧是.cc

为什么你会那么熟练啊

之前终于弄到了youku ct=10

想着看能不能用老办法dump内存搞出ac那边的key

试了很久没有效果

后来在as中畅游的时候,发现了一些东西,然后就变得熟练了起来

QQ图片20160708134104 QQ图片20160708134135 QQ图片20160708134143 QQ图片20160708134154

顺便去翻了翻土豆,土豆新ctype=11始终没翻到,倒是看到了优酷ct=60

QQ图片20160708134219 QQ图片20160708134228

至于B这边……我最早得到key是dump后撞大运刚好看到。今天翻了翻……藏的也挺浅


对话发生于7/10

QQ图片20160713121319