首页 > 插件开发 > ATS插件-视频拖拽抛砖引玉土鳖版

ATS插件-视频拖拽抛砖引玉土鳖版

2013年11月26日     浏览数:3,784 发表评论 阅读评论

现在先只讨论优酷视频的拖拽,而且现在也只测试了优酷的,还只做了MP4/FLV格式的…

几种URL名称的自定义和示例:
  • 实际请求的url:
http://60.217.251.13/youku/677395829164A83FD52924414B/03000807005264E326092B055DF5316FC5CED4-3430-C4BD-95EC-A20F7AA746AB.mp4?nk=66995490785_23085119593&ns=X_2Y       //命名为OriginUrl1
http://60.217.251.13/youku/677395829164A83FD52924414B/03000807005264E326092B055DF5316FC5CED4-3430-C4BD-95EC-A20F7AA746AB.mp4?start=XXX       //命名为OriginUrl2
  • 回源Url:
    http://60.217.251.13/youku/677395829164A83FD52924414B/03000807005264E326092B055DF5316FC5CED4-3430-C4BD-95EC-A20F7AA746AB.mp4   //命名为SourceUrl
  • ATS缓存中的url:
    http://www.youku.com/03000807005264E326092B055DF5316FC5CED4-3430-C4BD-95EC-A20F7AA746AB.mp4       //命名为CacheUrl
当时为什么想要做这个插件

如果直接用ATS代理上面的url,也可以缓存,不过意义不大,因为你缓存之后需要保证url完全相同(包括ip,key,参数)才能够命中。这些url中有一些变化部分,ip,key,params,可以将这些去掉,归纳为CacheUrl,用来标识这一类变化的url所对应的完整的不变的内容。

然后有人了解到ATS有一种叫插件的东西,也有一个类似功能的插件可以处理这种问题,cacheurl.so,然后就把cacheurl.so下载安装,发现不完全满足要求。看了cacheurl.so的代码之后发现一个接口TSCacheUrlSet,功能是让某一类url统一设置为寻找固定的一个key对应的资源。
了解了这些之后,有了一些自己的想法,想做一个插件来解决这个问题,大概是这样一个摸索过程:

插件发现来了一个请求OriginUrl1,这种按位置拖拽的可以直接根据url处理为range请求,
即插件中将请求改写,url去掉参数,然后带上range:

http://60.217.251.13/youku/677395829164A83FD52924414B/03000807005264E326092B055DF5316FC5CED4-3430-C4BD-95EC-A20F7AA746AB.mp4和range:X-X+Y-1(大概是这个公式)两部分。之后,ATS自己根据range请求的自身逻辑去处理。插件有了这个功能之后,可以正常处理OriginUrl1的拖拽方式。

但是不好处理的是OriginUrl2请求,优酷这种请求不多,不过也存在,而且其他视频网站也有类似时间拖拽的方式,是需要支持的。如果要支持这种请求方式,需要解析视频,根据拖拽时间来算出对应的位置,然后再按照上面的做法改为range请求,不过这种时间拖拽的请求,在回复的时候还需要将视频头先发送回客户端,不然播放不出来。

这就涉及到transform操作,借鉴了example/append_transform,将视频头放在拖拽部分前面先返回给客户端。

做完上面这些之后,已经完成大部分插件功能了,后来又添加了HIT的情况,现在不管是上述哪种方式,都是缓存MISS的情况,如果HIT的话,需要自己操作缓存,这块儿其实还是用example/append_transform那几个接口,只不过操作复杂一点。

加上这个之后还做了一些工作,就是如果一个新的拖拽请求,一开始是MISS,通过插件会带上range,那么永远都不会缓存并且HIT,所以就加了一个模块,就是发现这种请求,就主动的向ATS主动发送一个完整请求,然后下载超过配置比例之后断开。

(records.config的配置项CONFIG proxy.config.http.background_fill_completed_threshold FLOAT,和CONFIG proxy.config.http.background_fill_active_timeout INT这个配合使用)

这块儿没想到好的处理方法,拖拽请求缓存的话没用,改为range不缓存的话,又需要主动再发送一个完整请求,感觉这样有些浪费。
插件具体流程:

  • 添加hook

TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(ReadRequesthdrHookHandle, NULL));
TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, TSContCreate(CacheLookupCompleteHookHandle, NULL));

  • TS_HTTP_READ_REQUEST_HDR_HOOK 规范处理请求URL,并设置CacheUrl
    TSHttpTxnClientReqGet(txnp, &req_bufp, &req_loc)取出url,然后调用lua脚本(插件中如何调用lua可以参照ts-lua中的使用方式),返回拖拽方式,拖拽start,拖拽end,CacheUrl,SourceUrl,内部Url(将原有url修改为内部Url)
    TSCacheUrlSet(txnp, CacheUrl, CacheUrl.length()) //TSCacheUrlSet,参照cacheurl.so中的做法
  • TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK 在CacheLookUpHook时判断是MISS还是HIT,MISS就不多介绍了,HIT操作更复杂点
    从内部Url中获取拖拽参数和方式,然后初始化transform要带的自定义的结构体(纯模仿example/append_transform)将这些数据赋值给结构体中的变量

    TransformUserData pUserData = TransformUserDataAlloc();
    connp = TSTransformCreate(CacheTransformHookHandle, txnp);
    TSContDataSet(connp, (void
    )pUserData);
    TSHttpTxnUntransformedRespCache(txnp, 1);//这一句和下面一句是告诉TS只缓存transform之前的数据,不缓存transform之后的数据(折磨了我两天,在此感谢阕寒大大和豪哥)
    TSHttpTxnTransformedRespCache(txnp, 0);
    TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);

  • transform过程

    pUserData = (TransformUserData*)TSContDataGet(contp); //取出要携带的数据

    初始化TransformUserData中的buffer,reader,vio等

    然后从缓存中读取数据,解析视频头信息

    然后consume不需要的数据,发送需要的数据

    如果是MISS的话,现在的做法是回源下载源文件,调用解析视频的接口,解析完毕关闭下载(只需要下载一个视频头信息,很小)。通过视频解析接口得到视频拖拽的位置和根据起始位置改写之后的视频头信息。在ATS返回客户端之前将改写之后的视频头信息通过transform添加进去即可。

写代码的时候感觉步履维艰,不过现在说着说着又感觉已经没啥可说了,其实现在看来,做的过程中只是将example/append_transform这个例子中的文本操作变成了视频操作,再加上那两句API,。那就到此结束!

最后感谢豪哥,阕寒大大的指点,还有纸鸢同学的总结,以及群里的各路英雄。

代码就不上传了,领导说接触ATS时间太短,而且这只是练习ATS插件的一个小题目,刚刚自测通过,建议就不要发布出来贻笑大方、误人子弟、丢人现眼,and so on…

不过有兴趣的,咱们私下交流,呵呵。

分类: 插件开发 标签:
  1. 水中捞月
    2015年7月13日11:27 | #1

    我的做法是先参考background_getch先缓存视频片段,然后在用transform返回range,这样对于优酷测试过是可以的

  1. 本文目前尚无任何 trackbacks 和 pingbacks.