`/** * 本实例演示如何在Android中播放网络上的视频,这里牵涉到视频传输协议,视频编解码等知识点 * @author Administrator *Android当前支持两种协议来传输视频流一种是Http协议,另一种是RTSP协议 *Http协议最常用于视频下载等,但是目前还不支持边传输边播放的实时流媒体 *同时,在使用Http协议 传输视频时,需要根据不同的网络方式来选择合适的编码方式, *比如对于GPRS网络,其带宽只有20kbps,我们需要使视频流的传输速度在此范围内。 *比如,对于GPRS来说,如果多媒体的编码速度是400kbps,那么对于一秒钟的视频来说,就需要20秒的时间。这显然是无法忍受的 *Http下载时,在设备上进行缓存,只有当缓存到一定程度时,才能开始播放。 * *所以,在不需要实时播放的场合,我们可以使用Http协议 * *RTSP:Real Time Streaming Protocal,实时流媒体传输控制协议。 *使用RTSP时,流媒体的格式需要是RTP。 *RTSP和RTP是结合使用的,RTP单独在Android中式无法使用的。 * *RTSP和RTP就是为实时流媒体设计的,支持边传输边播放。 * *同样的对于不同的网络类型(GPRS,3G等),RTSP的编码速度也相差很大。根据实际情况来 * *使用前面介绍的三种方式,都可以播放网络上的视频,唯一不同的就是URI * *本例中使用VideoView来播放网络上的视频 */ `
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
videoview = (VideoView) findViewById(R.id.videoview) Uri uri = Uri.parse("http://7sbsl4.com1.z0.glb.clouddn.com/gogogo.mp4") videoview.setVideoURI(uri) videoview.requestFocus() videoview.start()
没有管理MediaPalyer的各种状态,这些状态都让VideoView给封装了,并且,当VideoView创建的时候,MediaPalyer对象将会创建,当VideoView对象销毁的时候,MediaPlayer对象将会释放。
/** * 视频或者音频到结尾时触发的方法 */ videoview.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { Log.i("通知", "完成"); } });/** * 注册一个错误监听,这个全部写出来了,只是为了当遇到错误时做个参考吧,第一次用SurfaceView做的时候遇到了问题 */ videoview.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { Log.i("通知", "播放中出现错误"); switch (what) { case -1004: Log.d("Streaming Media", "MEDIA_ERROR_IO"); break; case -1007: Log.d("Streaming Media", "MEDIA_ERROR_MALFORMED"); break; case 200: Log.d("Streaming Media", "MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK"); break; case 100: Log.d("Streaming Media", "MEDIA_ERROR_SERVER_DIED"); break; case -110: Log.d("Streaming Media", "MEDIA_ERROR_TIMED_OUT"); break; case 1: Log.d("Streaming Media", "MEDIA_ERROR_UNKNOWN"); break; case -1010: Log.d("Streaming Media", "MEDIA_ERROR_UNSUPPORTED"); break; } switch (extra) { case 800: Log.d("Streaming Media", "MEDIA_INFO_BAD_INTERLEAVING"); break; case 702: Log.d("Streaming Media", "MEDIA_INFO_BUFFERING_END"); break; case 701: Log.d("Streaming Media", "MEDIA_INFO_METADATA_UPDATE"); break; case 802: Log.d("Streaming Media", "MEDIA_INFO_METADATA_UPDATE"); break; case 801: Log.d("Streaming Media", "MEDIA_INFO_NOT_SEEKABLE"); break; case 1: Log.d("Streaming Media", "MEDIA_INFO_UNKNOWN"); break; case 3: Log.d("Streaming Media", "MEDIA_INFO_VIDEO_RENDERING_START"); break; case 700: Log.d("Streaming Media", "MEDIA_INFO_VIDEO_TRACK_LAGGING"); break; } return false; } });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
下面是新增的。因为videoview刚进入界面太挫了一片漆黑。。个人技术太菜就找了一个获取网络视频缩略图的方法给他设置个背景:
鉴于多数人都用过ThumbnailUtils.createVideoThumbnail()方法,该方法在2.x系统下可用,API LEVEL > 14时却只能返回null,以下为解决该问题方案:
之后再自己的后台线程中调用该方法得到网络视频的缩略图bitmap然后在主线程中调用imageView.setImageBitmap(bitmap)即可;
获取缩略图代码:
private Bitmap createVideoThumbnail(String url, int width, int height) { Bitmap bitmap = null; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); int kind = MediaStore.Video.Thumbnails.MINI_KIND; try { if (Build.VERSION.SDK_INT >= 14) { retriever.setDataSource(url, new HashMap<String, String>()); } else { retriever.setDataSource(url); } bitmap = retriever.getFrameAtTime(); } catch (IllegalArgumentException ex) { } catch (RuntimeException ex) { } finally { try { retriever.release(); } catch (RuntimeException ex) { } } if (kind == Images.Thumbnails.MICRO_KIND && bitmap != null) { bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT); } return bitmap; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
方案二:
方案一在自己的tablet上测试不通过,于是又在github上找到了另一个扩展版的 FFMPEG MediaMetadataRetriever ,提供了一个可以获取视频详细信息和缩略图的统一接口,支持API 7+,(android 自带MediaMetadataRetriever仅支持API 10+),同时支持Uri
,支持的文件类型 file, http, https, mms and mmsh 支持的编码格式(音频&视频): aac, acc+, avi, flac, mp2, mp3, mp4, ogg, 3gp and more! 扩展支持: ICY Metadata (SHOUTcast metadata) 使用方法异常简单,只需将下边的包下载到本地解压然后把libs中的文件拷贝到自己项目的libs目录下即可 https://github.com/wseemann/FFmpegMediaMetadataRetriever/blob/master/fmmr-library/prebuilt-libs.tar.gz.
FFmpegMediaMetadataRetriever fmmr = new FFmpegMediaMetadataRetriever(); try { fmmr.setDataSource(params[0]); bitmap = fmmr.getFrameAtTime(); if (bitmap != null) { Bitmap b2 = fmmr .getFrameAtTime( 4000000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST_SYNC); if (b2 != null) { bitmap = b2; } if (bitmap.getWidth() > 640) { bitmap = ThumbnailUtils.extractThumbnail(bitmap, 640, 480, ThumbnailUtils.OPTIONS_RECYCLE_INPUT); } } } catch (IllegalArgumentException ex) { ex.printStackTrace(); } finally { fmmr.release(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
这样就可以很方便的获取到缩略图bitmap了。
另:可能有朋友下载了prebuilt-libs.tar.gz之后会惊讶的发现,解压之后的libs文件竟然多达11MB!! 这么庞大的体积对我来说是不能接受的。。。原本2MB的apk瞬间膨胀了5倍之多啊尼玛!
但仔细研究libs一番,发现对于我这种MMR的轻度用户,只需缩略图的功能的话,完全可以简化那些用不到的编码库和多平台库,同时无视mips和x86平台的话,只需libffmpeg_mediametadataretriever_jni.so和fmmr.jar两个文件就可以了,瞬间<30kb了有木有!
其实官方也说了,demo中给的是全部编码格式,可以按照自己的需求重新编译相应编码的lib就可以。