Android 实现视频字幕Subtitle和横竖屏切换

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

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

       最近有个需求就是需要给视频添加字幕,其实也挺简单的。字幕比较常用的格式是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;
			}

		}
	};
	@Override
	protected 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 block
			e.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() {

			//@Override
			public 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 {

		@Override
		public 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() {

					@Override
					public 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() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
				Log.d("gaolei", "SCREEN_ORIENTATION_FULL_SENSOR");				}
		}, 5000);
	}
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		// TODO Auto-generated method stub
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN: {
				showOrHideController();
				break;
			}
		}
		return false;
	}
	@Override
	public void onClick(View view) {
		// TODO Auto-generated method stub
		switch(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 block
            BufferedReader 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);
                // 设置SRT
                srt.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 block
            e.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;//找到后就没必要继续遍历下去,节约资源
            }
        }
    }
}

运行效果图:
   



  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要给视频添加字幕,可以使用 Android Studio 中的 ExoPlayer 播放器库。ExoPlayer 是由 Google 推出的一款高性能、可扩展的媒体播放器库,支持多种媒体格式和功能,包括字幕显示。 以下是实现视频添加字幕的步骤: 1. 导入 ExoPlayer 库 在 build.gradle 文件中添加以下依赖: ``` implementation 'com.google.android.exoplayer:exoplayer:2.X.X' ``` 其中,2.X.X 是 ExoPlayer 库的版本号。 2. 准备字幕文件 将字幕文件保存在应用的 assets 目录下或者其他任意位置。ExoPlayer 支持多种字幕格式,包括 SRT、TTML、WebVTT 等。 3. 创建 ExoPlayer 实例 在布局文件中添加一个 SurfaceView 或者 TextureView,用于显示视频内容。然后在 Activity 或者 Fragment 中创建 ExoPlayer 实例,并将 SurfaceView 或者 TextureView 绑定到 ExoPlayer 实例上。 ``` playerView = findViewById(R.id.player_view); player = ExoPlayerFactory.newSimpleInstance(this); playerView.setPlayer(player); ``` 4. 准备视频字幕数据源 使用 ExoPlayer 的 DataSource.Factory 类创建视频字幕的数据源,其中字幕数据源需要指定字幕文件的 URI 和格式。 ``` String videoUri = "http://example.com/video.mp4"; String subtitleUri = "file:///android_asset/subtitle.srt"; DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, "MyApp"); MediaSource videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(videoUri)); Format subtitleFormat = Format.createTextSampleFormat(null, MimeTypes.APPLICATION_SUBRIP, Format.NO_VALUE, "en"); MediaSource subtitleSource = new SingleSampleMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(subtitleUri), subtitleFormat, C.TIME_UNSET); ``` 5. 将字幕数据源和视频数据源合并 使用 ExoPlayer 的 MergingMediaSource 类将字幕数据源和视频数据源合并为一个媒体数据源。 ``` MediaSource mediaSource = new MergingMediaSource(videoSource, subtitleSource); ``` 6. 播放视频 使用 ExoPlayer 的 prepare 方法将媒体数据源准备好,并使用 ExoPlayer 的 setPlayWhenReady 方法开始播放视频。 ``` player.prepare(mediaSource); player.setPlayWhenReady(true); ``` 至此,你已经成功地在 Android Studio 中实现了给视频添加字幕的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值