转载请标明地址:http://blog.csdn.net/gaolei1201/article/details/62041478

系统自带的VideoView有些视频格式不支持,那么我们可以用第三方实现的VideoView替代系统的来播放视频,比较流行的有ijkplayer、vitamio。

最近有个需求就是需要给视频添加字幕,其实也挺简单的。字幕比较常用的格式是srt,实际它就是文本,把它解析出来,然后根据时间再展示就OK。还有就是实现了即使旋转按钮关闭,根据方向感应器也能做到横竖屏切换。

本文用的是系统VideoView,然后播放sd卡中的视频来作为演示(源码中带有f2.mp4和f2.srt,运行时拷贝到sd卡就行)。下面简单介绍一下源码:
MainActivity包括显示字幕和如何实现横竖屏如何切换:
public class SubtitleActivity extends Activity implements View.OnClickListener,OnTouchListener{private VideoView videoView ;TextView tvSrt, mCurrentTime,mTotalTime,resolution_switch,mediacontroller_file_name;ImageView mediacontroller_play_pause,switch_screen;private SeekBar progress_seekbar;private AudioManager mAM;private long totalDuration;private boolean mShowing = true, mDragging,isResolution;private static final int PARSE_SRT = 0;private static final int FADE_OUT = 1;private static final int SHOW_PROGRESS = 2;private static final int CHANGE_VIDEOVIEW_BG = 3;private static final int SCREEN_ORIENTATION_USER = 4;private static final int sDefaultTimeout = 3000;private RelativeLayout videoview_layout, mMediaController;private ListView resolution_listview;private boolean isPortraint = true;private static int LockScreen = -1;// 用于记录是否关闭屏幕旋转,0为关闭1为开启private int screenWidth,videoViewHeight;List<VideoPathObject> videopathList=new ArrayList<VideoPathObject>();Handler mHandler=new Handler(){public void handleMessage(Message msg){long pos;switch (msg.what) {case PARSE_SRT:SrtParser.showSRT(videoView,tvSrt) ;//每隔500ms执行一次showSRT(),根据时间匹配显示哪句字幕mHandler.sendEmptyMessageDelayed(0, 500);break;case FADE_OUT:showOrHideController();break;case SHOW_PROGRESS:pos = setControllerProgress();if (!mDragging && mShowing) {msg = obtainMessage(SHOW_PROGRESS);sendMessageDelayed(msg, 1000 - (pos % 1000));}break;case CHANGE_VIDEOVIEW_BG:videoView.setBackgroundColor(0x00000000);break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_subtitle);videoView = (VideoView)this.findViewById(R.id.videoView );mAM = (AudioManager) getSystemService(Context.AUDIO_SERVICE);screenWidth = APPApplication.screenWidth;videoViewHeight = screenWidth * 9 / 16;tvSrt = (TextView)findViewById(R.id.srt);//项目中显示字幕的控件mediacontroller_file_name= (TextView)findViewById(R.id.mediacontroller_file_name);
//      String[]splitStr=Constant.videoUrl1.split("/");
//      mediacontroller_file_name.setText(splitStr[splitStr.length-1]);mTotalTime = (TextView) findViewById(R.id.mediacontroller_time_total);mCurrentTime = (TextView) findViewById(R.id.mediacontroller_time_current);resolution_switch = (TextView) findViewById(R.id.resolution_switch);mediacontroller_play_pause = (ImageView) findViewById(R.id.mediacontroller_play_pause);switch_screen = (ImageView) findViewById(R.id.switch_screen);videoview_layout = (RelativeLayout) findViewById(R.id.videoview_layout);mediacontroller_play_pause.setOnClickListener(this);progress_seekbar = (SeekBar) findViewById(R.id.mediacontroller_seekbar);videoview_layout = (RelativeLayout) findViewById(R.id.videoview_layout);mMediaController = (RelativeLayout) findViewById(R.id.media_controller);resolution_listview = (ListView) findViewById(R.id.resolution_listview);resolution_switch.setOnClickListener(this);videoView.setOnTouchListener(this);progress_seekbar.setOnSeekBarChangeListener(mSeekListener);LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, videoViewHeight);videoview_layout.setLayoutParams(params);try {// 1代表开启自动旋转true,0代表未开启自动旋转false// Settings.System.getInt(mContext.getContentResolver(),Settings.System.ACCELEROMETER_ROTATION,0);LockScreen = Settings.System.getInt(getContentResolver(),Settings.System.ACCELEROMETER_ROTATION);} catch (SettingNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}
//      String rawUri = "android.resource://" + getPackageName() + "/" + R.raw.renwei;Uri uri = Uri.parse(Constant.videoUrl1);//设置视频控制器
//        videoView.setMediaController(new MediaController(this));//播放完成回调videoView.setOnCompletionListener( new MyPlayerOnCompletionListener());videoView.setOnPreparedListener(new OnPreparedListener() {//@Overridepublic void onPrepared(MediaPlayer mp) {totalDuration=videoView.getDuration();if (mTotalTime != null)mTotalTime.setText("/"+generateTime(totalDuration));}});//设置视频路径videoView.setVideoURI(uri);//开始播放视频videoView.start();SrtParser.parseSrt(this);SrtParser.showSRT(videoView,tvSrt) ;mHandler.sendEmptyMessageDelayed(0, 500);initVideoResolution();}private void initVideoResolution(){VideoPathObject object1=new VideoPathObject();object1.videoStatus="超清";videopathList.add(object1);VideoPathObject object2=new VideoPathObject();object2.videoStatus="高清";videopathList.add(object2);VideoPathObject object3=new VideoPathObject();object3.videoStatus="标清";videopathList.add(object3);switchResolution(videopathList);}class MyPlayerOnCompletionListener implements MediaPlayer.OnCompletionListener {@Overridepublic void onCompletion(MediaPlayer mp) {Toast.makeText( SubtitleActivity.this, "播放完成了", Toast.LENGTH_SHORT).show();}}private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {public void onStartTrackingTouch(SeekBar bar) {mDragging = true;mHandler.removeMessages(SHOW_PROGRESS);mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);}public void onProgressChanged(SeekBar bar, int progress,boolean fromuser) {if (!fromuser)return;int newposition = (int)(totalDuration * progress) / 1000;String time = generateTime(newposition);videoView.seekTo(newposition);mCurrentTime.setText(time);}public void onStopTrackingTouch(SeekBar bar) {videoView.seekTo(((int)totalDuration * bar.getProgress()) / 1000);hideMediaController(sDefaultTimeout);mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);mDragging = false;mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);}};private void switchResolution(final List<VideoPathObject> videopathList) {resolution_switch.setText(videopathList.get(videopathList.size() - 1).videoStatus);mediacontroller_play_pause.setImageResource(R.drawable.player_play);final ResolutionAdapter adapter = new ResolutionAdapter(videopathList,SubtitleActivity.this);resolution_listview.setAdapter(adapter);resolution_listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1,int position, long arg3) {// TODO Auto-generated method stub
//                      // currentPosition = videoView.getCurrentPosition();
//                      currentPosition = videoView.getCurrentPosition();
//                      Log.d("gaolei", "currentPosition---------1------"
//                              + currentPosition);VideoPathObject pathObject = videopathList.get(position);playVideo(pathObject.videoUrl);
//                      adapter.changePosition(position);resolution_switch.setText(pathObject.videoStatus);resolution_listview.setVisibility(View.GONE);}});}public void showOrHideController() {if (mShowing) {mHandler.removeMessages(SHOW_PROGRESS);mHandler.removeMessages(FADE_OUT);mMediaController.setVisibility(View.GONE);resolution_listview.setVisibility(View.GONE);mShowing = false;} else {mHandler.sendEmptyMessage(SHOW_PROGRESS);mMediaController.setVisibility(View.VISIBLE);hideMediaController(sDefaultTimeout);mShowing = true;}}public void hideMediaController(int sDefaultTimeout) {mHandler.sendEmptyMessageDelayed(FADE_OUT, sDefaultTimeout);}private long setControllerProgress() {if (videoView == null || mDragging)return 0;int position = videoView.getCurrentPosition();if (progress_seekbar != null) {if (totalDuration > 0) {long pos = 1000L * position / totalDuration;// Log.d("gaolei", "progress--------------" + pos);progress_seekbar.setProgress((int) pos);}int percent = videoView.getBufferPercentage();progress_seekbar.setSecondaryProgress(percent * 10);}if (mCurrentTime != null)mCurrentTime.setText(generateTime(position));return position;}private static String generateTime(long position) {int totalSeconds = (int) (position / 1000);int seconds = totalSeconds % 60;int minutes = (totalSeconds / 60) % 60;int hours = totalSeconds / 3600;if (hours > 0) {return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes,seconds).toString();} else {return String.format(Locale.US, "%02d:%02d", minutes, seconds).toString();}}private void updatePausePlay() {if (videoView.isPlaying()) {videoView.pause();mediacontroller_play_pause.setImageResource(R.drawable.player_pause);} else {videoView.start();mediacontroller_play_pause.setImageResource(R.drawable.player_play);}}public void showResolution(View view) {if (!isResolution) {resolution_listview.setVisibility(View.VISIBLE);isResolution = true;} else {resolution_listview.setVisibility(View.GONE);isResolution = false;}}public void onConfigurationChanged(Configuration newConfig) {super.onConfigurationChanged(newConfig);if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {changeToFullScreen();Log.d("gaolei", "ORIENTATION_LANDSCAPE-------------");}if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {changeToSmallScreen();Log.d("gaolei", "ORIENTATION_PORTRAIT-------------");}}public void switchScreen(View view) {if (isPortraint) {handToFullScreen();} else {handToSmallScreen();}}public void handToSmallScreen() {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);changeToSmallScreen();/*** 这里点击按钮转屏,用户5秒内不转屏幕,将自动识别当前屏幕方向*/autoSwitchScreenOrientation();}public void handToFullScreen() {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);changeToFullScreen();autoSwitchScreenOrientation();}private void changeToFullScreen() {isPortraint = false;LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, APPApplication.screenWidth);videoview_layout.setLayoutParams(params);videoView.setLayoutParams(params);WindowManager.LayoutParams windowparams = getWindow().getAttributes();windowparams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;getWindow().setAttributes(windowparams);getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);switch_screen.setImageResource(R.drawable.player_switch_small);}private void changeToSmallScreen() {isPortraint = true;LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, videoViewHeight);videoview_layout.setLayoutParams(params);videoView.setLayoutParams(params);WindowManager.LayoutParams windowparams = getWindow().getAttributes();windowparams.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);getWindow().setAttributes(windowparams);getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);switch_screen.setImageResource(R.drawable.player_switch_big);}public void autoSwitchScreenOrientation() {
//      手动旋转屏幕,5s后会执行感应的方向new Timer().schedule(new TimerTask() {@Overridepublic void run() {// TODO Auto-generated method stubsetRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);Log.d("gaolei", "SCREEN_ORIENTATION_FULL_SENSOR");               }}, 5000);}@Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubswitch (event.getAction()) {case MotionEvent.ACTION_DOWN: {showOrHideController();break;}}return false;}@Overridepublic void onClick(View view) {// TODO Auto-generated method stubswitch(view.getId()){case R.id.mediacontroller_play_pause:Log.d("gaolei", "mediacontroller_play_pause");updatePausePlay();break;case R.id.resolution_switch:resolution_listview.setVisibility(View.VISIBLE);break;}}public void jumpToMain(View view){startActivity(new Intent(this, MainActivity.class));}public void onRestart(){super.onRestart();videoView.start();mediacontroller_play_pause.setImageResource(R.drawable.player_play);}public void onStop(){super.onStop();videoView.pause();mediacontroller_play_pause.setImageResource(R.drawable.player_pause);}
}

SrtParser就是解析字幕文件的算法:

public class SrtParser {public static ArrayList<SRT>srtList;public static int lastEndTime;/*** 解析SRT字幕文件* 字幕路径*/public static void parseSrt(Context context) {InputStream inputStream = null;try {
//            inputStream=context.getResources().openRawResource(R.raw.renwei2);inputStream = new FileInputStream(Constant.srtUrl1);// TODO Auto-generated catch blockBufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"GB2312"));String line = null;srtList = new ArrayList<SRT>();StringBuffer sb = new StringBuffer();while ((line = br.readLine()) != null) {//   Log.d("gaolei", "br.readLine()-----------"+br.readLine());if (!line.equals("")) {Log.d("gaolei","line-------------------"+ line);sb.append(line).append("@");continue;}Log.d("gaolei", "sb.toString()-----------"+sb.toString());String[] parseStrs = sb.toString().split("@");// 该if为了适应一开始就有空行以及其他不符格式的空行情况if (parseStrs.length < 3) {sb.delete(0, sb.length());// 清空,否则影响下一个字幕元素的解析</i>continue;}SRT srt = new SRT();// 解析开始和结束时间String timeTotime = parseStrs[1];int begin_hour = Integer.parseInt(timeTotime.substring(0, 2));int begin_mintue = Integer.parseInt(timeTotime.substring(3, 5));int begin_scend = Integer.parseInt(timeTotime.substring(6, 8));int begin_milli = Integer.parseInt(timeTotime.substring(9, 12));int beginTime = (begin_hour * 3600 + begin_mintue * 60 + begin_scend)* 1000 + begin_milli;int end_hour = Integer.parseInt(timeTotime.substring(17, 19));int end_mintue = Integer.parseInt(timeTotime.substring(20, 22));int end_scend = Integer.parseInt(timeTotime.substring(23, 25));int end_milli = Integer.parseInt(timeTotime.substring(26, 29));int endTime = (end_hour * 3600 + end_mintue * 60 + end_scend)* 1000 + end_milli;System.out.println("开始:" + begin_hour + ":" + begin_mintue +":"+ begin_scend + ":" + begin_milli + "=" + beginTime+ "ms");System.out.println("结束:" + end_hour + ":" + end_mintue + ":"+ end_scend + ":" + end_milli + "=" + endTime + "ms");// 解析字幕文字String srtBody = "";// 可能1句字幕,也可能2句及以上。for (int i = 2; i < parseStrs.length; i++) {srtBody += parseStrs[i]+ "\n";}// 删除最后一个"\n"srtBody = srtBody.substring(0, srtBody.length() - 1);// 设置SRTsrt.setBeginTime(beginTime);srt.setEndTime(endTime);srt.setSrtBody(new String(srtBody.getBytes(), "UTF-8"));srtList.add(srt);sb.delete(0, sb.length());// 清空,否则影响下一个字幕元素的解析}lastEndTime=srtList.get(srtList.size()-1).getEndTime();br.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}//每隔500ms执行一次()取}public static void showSRT(VideoView videoView,TextView tvSrt) {//      Log.d("gaolei", "srt_map.size()--------------"+srt_map.size());int currentPosition = videoView.getCurrentPosition();//vv是VideoView播放器if(currentPosition>lastEndTime){tvSrt.setVisibility(View.GONE);return;}for(int i=0;i<srtList.size();i++){SRT srtbean =srtList.get(i);if (currentPosition > srtbean.getBeginTime()&& currentPosition < srtbean.getEndTime()) {tvSrt.setText(srtbean.getSrtBody());//显示过的就删掉,提高查询效率srtList.remove(i);break;//找到后就没必要继续遍历下去,节约资源}}}
}

运行效果图:

   
项目源码,点击下载......

Android 实现视频字幕Subtitle和横竖屏切换相关推荐

  1. android 视频播放器 加载字幕,Android 实现视频字幕Subtitle和横竖屏切换示例

    系统自带的VideoView有些视频格式不支持,那么我们可以用第三方实现的VideoView替代系统的来播放视频,比较流行的有ijkplayer.vitamio. 最近有个需求就是需要给视频添加字幕, ...

  2. android dialog横屏,解决dialog在横竖屏切换时消失

    以AlertDialog为例 一.将AlertDialog视图封装在dialogfragment(fragmentdeAlertDialog子类)实例中 package com.example.t; ...

  3. android电视横竖屏切换在哪里,Android横竖屏切换总结

    之前在网上看到博客说Activity横竖屏切换的规律如下: (1)不设置android:configChanges,竖屏切换到横屏调用一次生命周期,横屏切竖屏调用两次生命周期. (2)设置 andro ...

  4. android横竖屏切换函数,Android横竖屏切换小结.PDF

    Android横竖屏切换小结 Android横竖屏切换小结 Android手机或平板都会存在横竖屏切换的功能,通常是由物理重力感应触发的,但是 有时候也不尽然,通常在设置里面我们可以对手机的横竖屏切换 ...

  5. Android横竖屏切换小结

    (老样子,图片啥的详细文档,可以下载后观看 http://files.cnblogs.com/franksunny/635350788930000000.pdf) Android手机或平板都会存在横竖 ...

  6. Android横竖屏切换相关知识点

    转载自:http://www.cnblogs.com/franksunny/p/3714442.html (老样子,图片啥的详细文档,可以下载后观看 http://files.cnblogs.com/ ...

  7. Android横竖屏切换小结(重建、非重建Activity)

    来自:http://www.cnblogs.com/franksunny/p/3714442.html (老样子,图片啥的详细文档,可以下载后观看 http://files.cnblogs.com/f ...

  8. Android 横竖屏切换小结

    (自己体会:每次横竖屏自动切时都会run Activity的onCreate,即相当后重新进入Activity初始化一样:) 转自:http://www.cnblogs.com/franksunny/ ...

  9. Android横竖屏切换

    尊重原创,本文转载自 http://www.cnblogs.com/franksunny/p/3714442.html Android横竖屏切换小结 (老样子,图片啥的详细文档,可以下载后观看 htt ...

最新文章

  1. Linux那些事儿 之 戏说USB(5)我是谁
  2. Interview:人工智能岗位面试—人工智能岗位求职之机器学习算法工程师必备知识框架结构图
  3. git回退的四种操作
  4. leetcode875.KokoEatingBananas
  5. 仿复制粘贴功能,长按弹出tips的实现
  6. c语言数据结构单链表输出链表操作,单链表一系列操作c语言实现(按照严蔚敏那本数据结构编写)...
  7. vi/vim替换字符
  8. 关于Win10系统的封装
  9. 人工神经网络概念及组成,人工神经网络基本概念
  10. C——识别键盘按下模拟键盘按下
  11. 【转载】TextView源码解析
  12. CSS3 设置模糊背景图片
  13. 指尖检测的新方法几种
  14. python起笔落笔_书法讲究的是起笔和落笔落是什么意思
  15. 【论文阅读】改进的基于均值滤波的单幅图像去雾算法研究
  16. HADOOP与HDFS数据压缩格式
  17. 基于jsp(java)网络教学平台系统的设计和开发(含源文件)
  18. python进行图像滤波_Python图像滤波处理操作示例【基于ImageFilter类】
  19. 科全可拓展免费进销存系统
  20. 献给86,87,88,89年出生的80后

热门文章

  1. Jsoup,一款超好用的HTML文本解析Java工具
  2. (四十六:2021.08.17)《医疗物联网单导联心电波心房颤动检测研究》
  3. 个人喜欢的小于100K的迷你绿色软件合集
  4. Python 实用爬虫-04-使用 BeautifulSoup 去水印下载 CSDN 博客图片
  5. 数字图像处理基础知识
  6. 关于BitmapFactory.decodeStream(is)方法无法正常解码为Bitmap对象的解决方法
  7. 计算机 继续教育培训心得体会,继续教育培训学习心得
  8. Beego脱坑(一)Beego简介和安装
  9. Vue设置部分页面缓存,设置部分页面不缓存
  10. 面试阿里P6,过关斩将直通2面,结果3面找了个架构师来吊打我?