前言
入职新公司,刚接手的AndroidTV项目,初次接触TV开发,被各种骚东西搞得头皮发麻,写点东西记录一下。
正文
MediaMetadataRetriever
1. 获取视频帧的关键类:MediaMetadataRetriever
(1) 属于在android api的那个包下:android.media.MediaMetadataRetriever
(2) 类简单介绍: MediaMetadataRetriever类提供了用于从输入媒体文件检索帧和元数据的统一接口。
(3) 这个是android提供的类,用来获取本地和网络media相关文件的信息。
2. 大概使用:
public void getThumbs(SipaTvPlayer player, String url) {
long duration = player.getDuration();
int divisor = 0;
if (duration > 1000 * 60 * 2) {//如果视频时长超过两分钟
divisor = 10;
} else {
divisor = 2;
}
int finalDivisor = divisor;
io.reactivex.Observable<Bitmap> observable = io.reactivex.Observable.create(new ObservableOnSubscribe<Bitmap>() {
@Override
public void subscribe(ObservableEmitter<Bitmap> e) throws Exception {
mRetriever = new MediaMetadataRetriever();
if (Build.VERSION.SDK_INT >= 14) {
mRetriever.setDataSource(url, new HashMap<String, String>());
} else {
mRetriever.setDataSource(url);
}
for (int i = 1 * 1000; i < duration; i += finalDivisor * 1000) {//获取每隔divisor秒的视频帧预览图
Bitmap bitmap = mRetriever.getFrameAtTime(i * 1000, MediaMetadataRetriever.OPTION_CLOSEST);
e.onNext(bitmap);
Log.i(TAG, "bitmap---i: " + i / 1000);
}
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
observable.subscribe(new Consumer<Bitmap>() {
@Override
public void accept(Bitmap bitmap) throws Exception {
if (bitmap != null) {
mThumbs.add(bitmap);
mAdapter.notifyDataSetChanged();
}
}
});
}
复制代码
注意: 使用MediaMetadataRetriever在移动端能获取到本地或网络视频的对应微秒值的帧截图,但过程相当耗时,很有可能会ANR,所以一般异步方式获取,因为过于耗时(能力有限,不知道能不能解决这个问题),所以不建议用于TV开发中的快进帧预览功能,可用于视频列表获取关键帧预览等对实时性要求不高的使用场景。
后台截取返回组图
- 经过尝试,MediaMetadataRetriever获取帧耗时emmm...真的慢,然后观察鹅厂还有Yk等主流TV的快进帧预览效果那叫一个流畅,后面通过抓包发现YK的请求返回的数据里面包含一张10*10的小图组成的大图,对比视频帧预览图发现跟小图一直,然后猜想其实现方式就是后台返回帧预览组图,然后TV端将大图截成100张小图,也就是帧预览图然后列表展示。真相大白,大鹅厂还是吊,各种加密,能力有限看不出来,估计也差不多。
(1) 将网络图片转Bitmap(网上随便找的)
public class BitmapUtils {
/**
* 得到本地或者网络上的bitmap url - 网络或者本地图片的绝对路径,比如:
* <p>
* A.网络路径: url="http://blog.foreverlove.us/girl2.png" ;
* <p>
* B.本地路径:url="file://mnt/sdcard/photo/image.png";
* <p>
* C.支持的图片格式 ,png, jpg,bmp,gif等等
*
* @param url
* @return
*/
public static Bitmap GetLocalOrNetBitmap(String url) {
Bitmap bitmap = null;
InputStream in = null;
BufferedOutputStream out = null;
try {
// 说明:Constant.IO_BUFFER_SIZE 是一个常量而已,可以改成常数,比如2*1024,其实取决于你的图片大小,自己根据图片的大小自己设定吧。。。。
in = new BufferedInputStream(new URL(url).openStream(), Constant.IO_BUFFER_SIZE);
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
out = new BufferedOutputStream(dataStream, Constant.IO_BUFFER_SIZE);
copy(in, out);
out.flush();
byte[] data = dataStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
data = null;
return bitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
复制代码
(2)截取小图
/**
*
* @param bitmap 源图(要截取的帧预览组图)
* @return 截取的图片列表
*/
private List<Bitmap> getThumbBitmaps(Bitmap bitmap) {
//MAX_COLUMNS 列数 MAX_LINES 行数 一般10*10 跟后台定好
int width = bitmap.getWidth() / MAX_COLUMNS;
int height = bitmap.getHeight() / MAX_LINES;
ArrayList<Bitmap> bitmaps = new ArrayList<>();
for (int y = 0; y < MAX_LINES; y++) {
for (int x = 0; x < MAX_COLUMNS; x++) {
bitmaps.add(Bitmap.createBitmap(bitmap, x * width, y * height, width, height));
}
}
return bitmaps;
}
复制代码
好了,关于AndroidTV帧预览,就发现这么点东西,水平有限,代码不好就凑合看吧。