转自 http://blog.sina.com.cn/foreverlovelost
测试一项http livestreaming的流媒体,提示无法播放,底层解码器直接报错,打开解码器相关的log开关,问题一目了然,播放的视频时720P的,而我们的手机最大支持分辨率为840*480左右,所以无法播放。
由于这项测试必须通过,所以我们先后采取了一下两种方法去规避
1:使用谷歌的软解去解码;
调用谷歌软解去解码视频帧的时候都是没有图像的,无法正常播放;
2:使用codec vendor的软解去解码;
codecvendor软解虽然支持720P,但是也仅仅是支持h264 baseline以及必须是mainprofile,而正好我们测试的视频是720P high profile的。
就在看似毫无办法的情况下,去看了下http live streaming的协议相关文档,发现一个重要的线索,就是httplivestreaming是自适应的流媒体,视频提供商针对每一个视频链接会提供几套分辨率不同的视频,这些视频内容是一模一样的,客户端播放前,或首先计算自己侧的网络带宽,客户端根据自身侧带宽允许的情况下选择了最高分辨率的视频去播放,我们这项测试的时候网络带宽允许的情况下选择了720P的视频
有了这个背景之后问题变得简单了,直接找到相关代码,代码如下:
android/frameworks/av/media/libstagefright/httplive/LiveSession.cpp
size_t LiveSession::getBandwidthIndex() {
#if 1
int32_tbandwidthBps;
首先估计client侧的网络带宽
if (mHTTPDataSource !=NULL
&&mHTTPDataSource->estimateBandwidth(&bandwidthBps)){
ALOGV("bandwidth estimated at %.2f kbps",bandwidthBps / 1024.0f);
} else {
ALOGV("no bandwidth estimate.");
return 0;
// Pick the lowestbandwidth stream by default.
}
charvalue[PROPERTY_VALUE_MAX];
if(property_get("media.httplive.max-bw", value, NULL)) {
char *end;
long maxBw = strtoul(value,&end, 10);
if (end > value&& *end == '\0') {
if (maxBw> 0 && bandwidthBps> maxBw) {
ALOGV("bandwidth capped to%ld bps", maxBw);
bandwidthBps = maxBw;
}
}
}
// Consider only 80% ofthe available bandwidth usable.
bandwidthBps =(bandwidthBps * 8) / 10;
// Pick the highestbandwidth stream below or equal to estimated bandwidth.
mBandwidthItems保存了不同带宽对应的视频链接url,并且按照从小到大的顺序排序
size_t index =mBandwidthItems.size() - 1;
直接定位到最后一个,也就是带宽要求最大,分辨率最高的视频
while (index> 0 &&mBandwidthItems.itemAt(index).mBandwidth
>(size_t)bandwidthBps) {
如果对应的带宽超过了client侧的带宽要求,则index减一,取较小带宽的视频源
--index;
}
找到合适的视频源
}
最后的修改比较暴力,在下面if分支里面:
if(playlist->isVariantPlaylist()) {
如果是自适应的流媒体,也就是给了多套视频源
for (size_t i = 0; i <playlist->size(); ++i) {
BandwidthItem item;
spmeta;
playlist->itemAt(i, &item.mURI,&meta);
unsignedlong bandwidth;
CHECK(meta->findInt32("bandwidth", (int32_t*)&item.mBandwidth));
取出当前这个playlist对应的带宽要求,并且存入到mBandwidthItems容器中
mBandwidthItems.push(item);
}
CHECK_GT(mBandwidthItems.size(), 0u);
最后对存入到容器中的各个playlist按照带宽的大小排序,顺序从小到大
mBandwidthItems.sort(SortByBandwidth);
}
sort的规则如下:
// static
int LiveSession::SortByBandwidth(const BandwidthItem *a, constBandwidthItem *b) {
if (
a->mBandwidth <b->mBandwidth) {
return -1;
} else if(a->mBandwidth == b->mBandwidth){
return 0;
}
return 1;
}
按照其中元素的bandwidth进行排序,小的在前面。
最后修改比较暴力:1和-1挪动一个位置。
以上重在问题分析过程,修改方法不是非常完美,遭到一群人拍板,各种受鄙视,呵呵。。。。。。。。。