采用faplayer播放EPUB书中的mp4视频
视频播放的工作终于告一段落了,由于之前对ffmpeg, vlc,流媒体这些东西完全没有接触过,所以很辛苦的查找资料,艰难的理解一点点的概念,还好,总算有了一个可行的解决方法,算是最简单的,不用对解码库有深入的了解,算是入门的方法。
一、应用场景:
EPUB书中嵌入视频,要求点击图片时能够打开相应的视频进行播放,视频的格式为mp4
二、解决方法:
1.选用播放器,最开始采用github上的开源工程 havlenapetr/ffmpeg 使用cygwin + NDK r8编译通过,在真机和模拟器上播放都正常,但是这个库有几个缺陷,最致命的是它运行需要依赖android的libjniaudio.so和libjnivideo.so两个基础库,而这两个库是与系统版本有关的,这就意味着要针对不同的版本编译不同的基础库,这给将来的应用带来了很大麻烦,另一个缺陷是大屏幕播放图像倾斜的问题,但是这个问题在网上有人已经解决了,修改onVideoSizeChangedListener的实现即可解决,具体参照havlenapetr-FFMpeg OnVideoSizeChangedListener接口的实现 这篇博文。
最后找到了vlc这个解码库,它比ffmpeg还要庞大,ffmpeg只是它的一部分而已,但是它的好处是各种android版本都支持的比较好,所以就采用它了。在ubuntu 10 + ruby 1.9.2 + NDK r5c下编译通过,播放本地视频一切正常。代码下载地址 https://github.com/tewilove/faplayer
完成了这一步,整个工作就完成了一半,另外一半是如何播放EPUB书中的mp4视频? 这里边有两个问题:
1. 我们知道,EPUB其实就是一个zip文件,那么为了减少缓冲时间,最好的方式是把mp4不压缩存储在zip文件中,播放时直接把文件指针seek到mp4开始的位置开始加载,用播放本地文件的方式来解码,但是看了faplayer提供的接口后我放弃了,faplayer提供了类似android自带的MediaPlayer的接口,数据加载只有一个setDataSource(String path)的接口。完全没有办法加载文件指针,所以我们退一步,把mp4缓存到本地来播放,这样的话为了减少播放前的等待时间,我们不能等到Mp4加载全部完成后再来播放,只能边缓冲边播放,这就带来了第二个问题:
2.我们知道,mp4的结构信息存储在一个叫moov的box中,我们至少要等到moov这个box被加载后(当然还得有一部分真实的音视频数据也得被加载)后,才能正常进行播放,而真实的mp4中,有很多是吧moov放置在文件的尾部的,我猜测是便于生成数据,避免产生moov box对后面数据的偏移产生影响。这就需要预先对mp4进行调整(预先我指的是在制作EPUB书的时候),在参考http://blog.zhourunsheng.com上的一篇博文后,我找到了qt-faststart 这个工具,它可以把moov box调整到文件的前部,后来我找到了一个更好的工具,我们在后面再说。
调整完moov后还有一个问题:moov中记录了mp4有多少个track,track中记录的是真实的音视频数据存储的位置,而真实数据存储在mdat中,而且经常是音频,视频分开放置的,而且有可能相隔的比较远,这样的话就会出现一个问题:在播放的时候音频或是视频数据被丢掉了,要避免这个问题,我们需要对mp4做一个处理,这个处理就叫做"流化",经过搜索,我找到了一个很好的工具,那就是VLC Media Player 下载地址 http://www.videolan.org/vlc/download-windows.html 它提供了很好的流化视频的功能,在流化的时候会把moov提到文件前面去,所以它比qt-faststart这个工具要强很多,完成这个后我们的播放就基本上没有技术难题了
好了,说了这么多,放出示例代码,代码参照faplayer:
1 public class VideoPlayerActivity extends Activity implements 2 AbsMediaPlayer.OnBufferingUpdateListener, 3 AbsMediaPlayer.OnCompletionListener, AbsMediaPlayer.OnErrorListener, 4 AbsMediaPlayer.OnInfoListener, AbsMediaPlayer.OnPreparedListener, 5 AbsMediaPlayer.OnProgressUpdateListener, 6 AbsMediaPlayer.OnVideoSizeChangedListener, OnTouchListener, 7 OnClickListener, OnSeekBarChangeListener { 8 9 static final String LOGTAG = "DANMAKU-PlayerActivity"; 10 11 private static final int SURFACE_NONE = 0; 12 private static final int SURFACE_FILL = 1; 13 private static final int SURFACE_ORIG = 2; 14 private static final int SURFACE_4_3 = 3; 15 private static final int SURFACE_16_9 = 4; 16 private static final int SURFACE_16_10 = 5; 17 private static final int SURFACE_MAX = 6; 18 19 private static final int MEDIA_PLAYER_BUFFERING_UPDATE = 0x4001; 20 private static final int MEDIA_PLAYER_COMPLETION = 0x4002; 21 private static final int MEDIA_PLAYER_ERROR = 0x4003; 22 private static final int MEDIA_PLAYER_INFO = 0x4004; 23 private static final int MEDIA_PLAYER_PREPARED = 0x4005; 24 private static final int MEDIA_PLAYER_PROGRESS_UPDATE = 0x4006; 25 private static final int MEDIA_PLAYER_VIDEO_SIZE_CHANGED = 0x4007; 26 27 private static final int VIDEO_STATE_UPDATE = 0x4008; 28 private static final int VIDEO_CACHE_READY = 0x4009; 29 private static final int VIDEO_CACHE_UPDATE = 0x400A; 30 private static final int VIDEO_CACHE_FINISH = 0x400B; 31 32 public static final String REMOTE_URL = "url"; 33 34 private static final int READY_BUFFER_LENGTH = 0; 35 36 private static final int CACHE_BUFFER_LENGTH = 0; 37 38 /* the media player */ 39 private AbsMediaPlayer mMediaPlayer = null; 40 41 /* GUI evnet handler */ 42 private Handler mEventHandler; 43 44 /* player misc */ 45 private ProgressBar mProgressBarPreparing; 46 47 /* player controls */ 48 private TextView mTextViewTime; 49 private SeekBar mSeekBarProgress; 50 private TextView mTextViewLength; 51 private ImageButton mImageButtonToggleMessage; 52 private ImageButton mImageButtonSwitchAudio; 53 private ImageButton mImageButtonSwitchSubtitle; 54 private ImageButton mImageButtonPrevious; 55 private ImageButton mImageButtonTogglePlay; 56 private ImageButton mImageButtonNext; 57 private ImageButton mImageButtonSwitchAspectRatio; 58 59 private LinearLayout mLinearLayoutControlBar; 60 61 /* player video */ 62 private SurfaceView mSurfaceViewVlc; 63 private SurfaceHolder mSurfaceHolderVlc; 64 65 /* misc */ 66 private boolean mMediaPlayerLoaded = false; 67 private boolean mMediaPlayerStarted = false; 68 69 /* misc */ 70 private int mTime = -1; 71 private int mLength = -1; 72 private boolean mCanSeek = true; 73 private int mAspectRatio = 0; 74 75 private int mAudioTrackIndex = 0; 76 private int mAudioTrackCount = 0; 77 private int mSubtitleTrackIndex = 0; 78 private int mSubtitleTrackCount = 0; 79 80 private String localUri = null; 81 private String remoteUrl = null; 82 private long mediaLength = 0; 83 84 private int readSize; 85 private boolean isReady; 86 private int errorCount; 87 88 protected boolean isError; 89 90 protected int curPosition; 91 92 private String cacheFilePath; 93 94 protected void initializeEvents() { 95 mEventHandler = new Handler() { 96 public void handleMessage(Message msg) { 97 switch (msg.what) { 98 case MEDIA_PLAYER_BUFFERING_UPDATE: { 99 if (mMediaPlayerLoaded) { 100 mProgressBarPreparing 101 .setVisibility(msg.arg1 < 100 ? View.VISIBLE 102 : View.GONE); 103 } 104 } 105 break; 106 case MEDIA_PLAYER_COMPLETION: { 107 curPosition = 0; 108 mMediaPlayer.pause(); 109 } 110 break; 111 case MEDIA_PLAYER_ERROR: { 112 mMediaPlayerLoaded = true; 113 isError = true; 114 errorCount++; 115 mMediaPlayer.pause(); 116 mProgressBarPreparing.setVisibility(View.VISIBLE); 117 } 118 break; 119 case MEDIA_PLAYER_INFO: { 120 if (msg.arg1 == MediaPlayer.MEDIA_INFO_NOT_SEEKABLE) { 121 mCanSeek = false; 122 } 123 } 124 break; 125 case MEDIA_PLAYER_PREPARED: { 126 mProgressBarPreparing.setVisibility(View.GONE); 127 mMediaPlayerLoaded = true; 128 mMediaPlayer.seekTo(curPosition); 129 startMediaPlayer(); 130 } 131 break; 132 case MEDIA_PLAYER_PROGRESS_UPDATE: { 133 if (mMediaPlayer != null) { 134 int length = msg.arg2; 135 if (length >= 0) { 136 mLength = length; 137 mTextViewLength.setText(SystemUtility 138 .getTimeString(mLength)); 139 mSeekBarProgress.setMax(mLength); 140 } 141 int time = msg.arg1; 142 if (time >= 0) { 143 mTime = time; 144 mTextViewTime.setText(SystemUtility 145 .getTimeString(mTime)); 146 mSeekBarProgress.setProgress(mTime); 147 } 148 } 149 } 150 break; 151 case MEDIA_PLAYER_VIDEO_SIZE_CHANGED: { 152 AbsMediaPlayer player = (AbsMediaPlayer) msg.obj; 153 SurfaceView surface = mSurfaceViewVlc; 154 int ar = mAspectRatio; 155 changeSurfaceSize(player, surface, ar); 156 } 157 break; 158 159 case VIDEO_STATE_UPDATE: // 缓冲启动 160 break; 161 case VIDEO_CACHE_READY: { // 缓冲完成最低限度 162 isReady = true; 163 mMediaPlayer.setDataSource(localUri); 164 mMediaPlayer.prepareAsync(); 165 } 166 break; 167 case VIDEO_CACHE_UPDATE: { // 缓冲加载 168 if (isError) { 169 mMediaPlayer.setDataSource(localUri); 170 mMediaPlayer.prepareAsync(); 171 isError = false; 172 } 173 } 174 break; 175 case VIDEO_CACHE_FINISH: { // 缓冲结束 176 if (isError) { 177 mMediaPlayer.setDataSource(localUri); 178 mMediaPlayer.prepareAsync(); 179 isError = false; 180 } 181 } 182 break; 183 default: 184 break; 185 } 186 187 super.handleMessage(msg); 188 } 189 }; 190 } 191 192 protected void initializeControls() { 193 /* SufaceView used by VLC is a normal surface */ 194 mSurfaceViewVlc = (SurfaceView) findViewById(R.id.player_surface_vlc); 195 mSurfaceHolderVlc = mSurfaceViewVlc.getHolder(); 196 mSurfaceHolderVlc.setType(SurfaceHolder.SURFACE_TYPE_NORMAL); 197 mSurfaceHolderVlc.addCallback(new SurfaceHolder.Callback() { 198 @Override 199 public void surfaceCreated(SurfaceHolder holder) { 200 createMediaPlayer(false, localUri, mSurfaceHolderVlc); 201 } 202 203 @Override 204 public void surfaceChanged(SurfaceHolder holder, int format, 205 int width, int height) { 206 mMediaPlayer.setDisplay(holder); 207 } 208 209 @Override 210 public void surfaceDestroyed(SurfaceHolder holder) { 211 destroyMediaPlayer(false); 212 } 213 214 }); 215 mSurfaceViewVlc.setOnTouchListener(this); 216 217 mTextViewTime = (TextView) findViewById(R.id.player_text_position); 218 mSeekBarProgress = (SeekBar) findViewById(R.id.player_seekbar_progress); 219 mSeekBarProgress.setOnSeekBarChangeListener(this); 220 mTextViewLength = (TextView) findViewById(R.id.player_text_length); 221 mImageButtonToggleMessage = (ImageButton) findViewById(R.id.player_button_toggle_message); 222 mImageButtonToggleMessage.setOnClickListener(this); 223 mImageButtonSwitchAudio = (ImageButton) findViewById(R.id.player_button_switch_audio); 224 mImageButtonSwitchAudio.setOnClickListener(this); 225 mImageButtonSwitchSubtitle = (ImageButton) findViewById(R.id.player_button_switch_subtitle); 226 mImageButtonSwitchSubtitle.setOnClickListener(this); 227 mImageButtonPrevious = (ImageButton) findViewById(R.id.player_button_previous); 228 mImageButtonPrevious.setOnClickListener(this); 229 mImageButtonTogglePlay = (ImageButton) findViewById(R.id.player_button_toggle_play); 230 mImageButtonTogglePlay.setOnClickListener(this); 231 mImageButtonNext = (ImageButton) findViewById(R.id.player_button_next); 232 mImageButtonNext.setOnClickListener(this); 233 mImageButtonSwitchAspectRatio = (ImageButton) findViewById(R.id.player_button_switch_aspect_ratio); 234 mImageButtonSwitchAspectRatio.setOnClickListener(this); 235 236 mLinearLayoutControlBar = (LinearLayout) findViewById(R.id.player_control_bar); 237 238 mProgressBarPreparing = (ProgressBar) findViewById(R.id.player_prepairing); 239 } 240 241 protected void initializeData() throws IOException { 242 Intent intent = getIntent(); 243 remoteUrl = intent.getStringExtra(REMOTE_URL); 244 if (remoteUrl == null) { 245 finish(); 246 } 247 248 if (remoteUrl.startsWith("file:")) { 249 localUri = remoteUrl; 250 } else { 251 cacheFilePath = App.getInstance().getMediaCachePath() + "cache.mp4"; 252 File cacheFile = new File(cacheFilePath); 253 if (cacheFile.exists()) { 254 cacheFile.delete(); 255 } 256 257 cacheFile.getParentFile().mkdirs(); 258 cacheFile.createNewFile(); 259 localUri = Uri.fromFile(cacheFile).toString(); 260 261 new Thread(new Runnable() { 262 263 @Override 264 public void run() { 265 startBufferData(); 266 } 267 }).start(); 268 } 269 } 270 271 private void startBufferData() { 272 InputStream is = null; 273 FileOutputStream out = null; 274 try { 275 out = new FileOutputStream(cacheFilePath); 276 if (URLUtil.isNetworkUrl(remoteUrl)) { 277 URL url = new URL(remoteUrl); 278 HttpURLConnection httpConnection = (HttpURLConnection) url 279 .openConnection(); 280 is = httpConnection.getInputStream(); 281 mediaLength = httpConnection.getContentLength(); 282 } else { 283 // TODO fix this, very very bad idea 284 Book book = App.getInstance().getBook(); 285 is = book.getEntryInputStream(remoteUrl); 286 mediaLength = book.getEntrySize(remoteUrl); 287 } 288 289 if (is == null || mediaLength == -1) { 290 return; 291 } 292 293 byte[] buf = new byte[4 * 1024]; 294 int size = 0; 295 int lastReadSize = 0; 296 297 mEventHandler.sendEmptyMessage(VIDEO_STATE_UPDATE); 298 299 while ((size = is.read(buf)) != -1) { 300 try { 301 out.write(buf, 0, size); 302 readSize += size; 303 } catch (IOException e) { 304 e.printStackTrace(); 305 } 306 307 if (!isReady) { 308 if (readSize - lastReadSize > READY_BUFFER_LENGTH 309 || readSize - lastReadSize == mediaLength) { 310 lastReadSize = readSize; 311 int timeCount = 0; 312 while (timeCount < 10) { 313 if (mMediaPlayer != null) { 314 mEventHandler 315 .sendEmptyMessage(VIDEO_CACHE_READY); 316 break; 317 } else { 318 try { 319 Thread.sleep(1000); 320 } catch (InterruptedException e) { 321 // TODO Auto-generated catch block 322 e.printStackTrace(); 323 } 324 timeCount++; 325 } 326 } 327 } 328 } else { 329 if (readSize - lastReadSize > CACHE_BUFFER_LENGTH 330 * (errorCount + 1)) { 331 lastReadSize = readSize; 332 mEventHandler.sendEmptyMessage(VIDEO_CACHE_UPDATE); 333 } 334 } 335 } 336 337 mEventHandler.sendEmptyMessage(VIDEO_CACHE_FINISH); 338 } catch (IOException e) { 339 e.printStackTrace(); 340 } finally { 341 if (out != null) { 342 try { 343 out.close(); 344 } catch (IOException e) { 345 // TODO Auto-generated catch block 346 e.printStackTrace(); 347 } 348 } 349 350 if (is != null) { 351 try { 352 is.close(); 353 } catch (IOException e) { 354 // TODO Auto-generated catch block 355 e.printStackTrace(); 356 } 357 } 358 } 359 } 360 361 protected void resetMediaPlayer() { 362 int resource = -1; 363 /* initial status */ 364 mMediaPlayerLoaded = false; 365 mTime = -1; 366 mLength = -1; 367 mCanSeek = true; 368 mAspectRatio = 0; 369 /* */ 370 mImageButtonToggleMessage.setVisibility(View.GONE); 371 mImageButtonSwitchAudio.setVisibility(View.GONE); 372 mImageButtonSwitchSubtitle.setVisibility(View.GONE); 373 mImageButtonPrevious.setVisibility(View.GONE); 374 mImageButtonTogglePlay.setVisibility(View.VISIBLE); 375 resource = SystemUtility.getDrawableId("btn_play_0"); 376 mImageButtonTogglePlay.setBackgroundResource(resource); 377 mImageButtonNext.setVisibility(View.GONE); 378 mImageButtonSwitchAspectRatio.setVisibility(View.VISIBLE); 379 resource = SystemUtility.getDrawableId("btn_aspect_ratio_0"); 380 mImageButtonSwitchAspectRatio.setBackgroundResource(resource); 381 /* */ 382 mLinearLayoutControlBar.setVisibility(View.GONE); 383 } 384 385 protected void selectMediaPlayer(String uri, boolean forceVlc) { 386 /* TODO: do this through configuration */ 387 boolean useDefault = true; 388 int indexOfDot = uri.lastIndexOf('.'); 389 if (indexOfDot != -1) { 390 String extension = uri.substring(indexOfDot).toLowerCase(); 391 if (extension.compareTo(".flv") == 0 392 || extension.compareTo(".hlv") == 0 393 || extension.compareTo(".m3u8") == 0 394 || extension.compareTo(".mkv") == 0 395 || extension.compareTo(".rm") == 0 396 || extension.compareTo(".rmvb") == 0) { 397 useDefault = false; 398 } 399 } 400 if (forceVlc) { 401 useDefault = false; 402 } 403 mSurfaceViewVlc.setVisibility(useDefault ? View.GONE : View.VISIBLE); 404 } 405 406 protected void createMediaPlayer(boolean useDefault, String uri, 407 SurfaceHolder holder) { 408 Log.d(LOGTAG, "createMediaPlayer() " + uri); 409 /* */ 410 resetMediaPlayer(); 411 /* */ 412 mMediaPlayer = AbsMediaPlayer.getMediaPlayer(useDefault/* false */); 413 mMediaPlayer.setOnBufferingUpdateListener(this); 414 mMediaPlayer.setOnCompletionListener(this); 415 mMediaPlayer.setOnErrorListener(this); 416 mMediaPlayer.setOnInfoListener(this); 417 mMediaPlayer.setOnPreparedListener(this); 418 mMediaPlayer.setOnProgressUpdateListener(this); 419 mMediaPlayer.setOnVideoSizeChangedListener(this); 420 mMediaPlayer.reset(); 421 mMediaPlayer.setDisplay(holder); 422 mMediaPlayer.setDataSource(uri); 423 mMediaPlayer.prepareAsync(); 424 } 425 426 protected void destroyMediaPlayer(boolean isDefault) { 427 if (!isDefault) { 428 mMediaPlayer.setDisplay(null); 429 mMediaPlayer.release(); 430 mMediaPlayer = null; 431 } 432 } 433 434 protected void startMediaPlayer() { 435 if (mMediaPlayerStarted || !mMediaPlayerLoaded) 436 return; 437 if (mMediaPlayer != null) { 438 mMediaPlayer.start(); 439 mMediaPlayerStarted = true; 440 } 441 } 442 443 protected void changeSurfaceSize(AbsMediaPlayer player, 444 SurfaceView surface, int ar) { 445 int videoWidth = player.getVideoWidth(); 446 int videoHeight = player.getVideoHeight(); 447 if (videoWidth <= 0 || videoHeight <= 0) { 448 return; 449 } 450 SurfaceHolder holder = surface.getHolder(); 451 holder.setFixedSize(videoWidth, videoHeight); 452 int displayWidth = getWindowManager().getDefaultDisplay().getWidth(); 453 int displayHeight = getWindowManager().getDefaultDisplay().getHeight(); 454 int targetWidth = -1; 455 int targetHeight = -1; 456 switch (ar) { 457 case SURFACE_NONE: { 458 targetWidth = videoWidth; 459 targetHeight = videoHeight; 460 break; 461 } 462 case SURFACE_FILL: { 463 break; 464 } 465 case SURFACE_ORIG: { 466 displayWidth = videoWidth; 467 displayHeight = videoHeight; 468 break; 469 } 470 case SURFACE_4_3: { 471 targetWidth = 4; 472 targetHeight = 3; 473 break; 474 } 475 case SURFACE_16_9: { 476 targetWidth = 16; 477 targetHeight = 9; 478 break; 479 } 480 case SURFACE_16_10: { 481 targetWidth = 16; 482 targetHeight = 10; 483 break; 484 } 485 default: 486 break; 487 } 488 if (targetWidth > 0 && targetHeight > 0) { 489 double ard = (double) displayWidth / (double) displayHeight; 490 double art = (double) targetWidth / (double) targetHeight; 491 if (ard > art) { 492 displayWidth = displayHeight * targetWidth / targetHeight; 493 } else { 494 displayHeight = displayWidth * targetHeight / targetWidth; 495 } 496 } 497 LayoutParams lp = surface.getLayoutParams(); 498 lp.width = displayWidth; 499 lp.height = displayHeight; 500 surface.setLayoutParams(lp); 501 surface.invalidate(); 502 } 503 504 @Override 505 public void onCreate(Bundle savedInstanceState) { 506 super.onCreate(savedInstanceState); 507 initializeEvents(); 508 setContentView(R.layout.player); 509 initializeControls(); 510 mProgressBarPreparing.setVisibility(View.VISIBLE); 511 try { 512 initializeData(); 513 } catch (IOException e) { 514 e.printStackTrace(); 515 finish(); 516 } 517 518 if (localUri == null) { 519 finish(); 520 } 521 selectMediaPlayer(localUri, true); 522 } 523 524 @Override 525 public void onDestroy() { 526 super.onDestroy(); 527 } 528 529 @Override 530 public void onStart() { 531 super.onStart(); 532 } 533 534 @Override 535 public void onStop() { 536 super.onStop(); 537 if (mMediaPlayer != null) { 538 mMediaPlayer.pause(); 539 } 540 } 541 542 @Override 543 public boolean onTouch(View v, MotionEvent event) { 544 if (!mMediaPlayerLoaded) { 545 return true; 546 } 547 int action = event.getAction(); 548 if (action == MotionEvent.ACTION_DOWN) { 549 int visibility = mLinearLayoutControlBar.getVisibility(); 550 if (visibility != View.VISIBLE) { 551 mLinearLayoutControlBar.setVisibility(View.VISIBLE); 552 } else { 553 mLinearLayoutControlBar.setVisibility(View.GONE); 554 } 555 return true; 556 } 557 return false; 558 } 559 560 @Override 561 public void onClick(View v) { 562 if (!mMediaPlayerLoaded) 563 return; 564 int id = v.getId(); 565 switch (id) { 566 case R.id.player_button_switch_audio: { 567 568 break; 569 } 570 case R.id.player_button_switch_subtitle: { 571 572 break; 573 } 574 case R.id.player_button_previous: { 575 576 break; 577 } 578 case R.id.player_button_toggle_play: { 579 boolean playing = false; 580 if (mMediaPlayer != null) 581 playing = mMediaPlayer.isPlaying(); 582 if (playing) { 583 if (mMediaPlayer != null) 584 mMediaPlayer.pause(); 585 } else { 586 if (mMediaPlayer != null) 587 mMediaPlayer.start(); 588 } 589 String name = String.format("btn_play_%d", !playing ? 1 : 0); 590 int resouce = SystemUtility.getDrawableId(name); 591 mImageButtonTogglePlay.setBackgroundResource(resouce); 592 break; 593 } 594 case R.id.player_button_next: { 595 break; 596 } 597 case R.id.player_button_switch_aspect_ratio: { 598 mAspectRatio = (mAspectRatio + 1) % SURFACE_MAX; 599 if (mMediaPlayer != null) 600 changeSurfaceSize(mMediaPlayer, mSurfaceViewVlc, mAspectRatio); 601 String name = String.format("btn_aspect_ratio_%d", mAspectRatio); 602 int resource = SystemUtility.getDrawableId(name); 603 mImageButtonSwitchAspectRatio.setBackgroundResource(resource); 604 break; 605 } 606 default: 607 break; 608 } 609 } 610 611 @Override 612 public void onProgressChanged(SeekBar seekBar, int progress, 613 boolean fromUser) { 614 /* not used */ 615 } 616 617 @Override 618 public void onStartTrackingTouch(SeekBar seekBar) { 619 /* not used */ 620 } 621 622 @Override 623 public void onStopTrackingTouch(SeekBar seekBar) { 624 if (!mMediaPlayerLoaded) 625 return; 626 int id = seekBar.getId(); 627 switch (id) { 628 case R.id.player_seekbar_progress: { 629 if (mCanSeek && mLength > 0) { 630 int position = seekBar.getProgress(); 631 if (mMediaPlayer != null) 632 mMediaPlayer.seekTo(position); 633 } 634 break; 635 } 636 default: 637 break; 638 } 639 } 640 641 @Override 642 public void onBufferingUpdate(AbsMediaPlayer mp, int percent) { 643 Message msg = new Message(); 644 msg.obj = mp; 645 msg.what = MEDIA_PLAYER_BUFFERING_UPDATE; 646 msg.arg1 = percent; 647 mEventHandler.sendMessage(msg); 648 } 649 650 @Override 651 public void onCompletion(AbsMediaPlayer mp) { 652 Message msg = new Message(); 653 msg.obj = mp; 654 msg.what = MEDIA_PLAYER_COMPLETION; 655 mEventHandler.sendMessage(msg); 656 } 657 658 @Override 659 public boolean onError(AbsMediaPlayer mp, int what, int extra) { 660 Message msg = new Message(); 661 msg.obj = mp; 662 msg.what = MEDIA_PLAYER_ERROR; 663 msg.arg1 = what; 664 msg.arg2 = extra; 665 mEventHandler.sendMessage(msg); 666 return true; 667 } 668 669 @Override 670 public boolean onInfo(AbsMediaPlayer mp, int what, int extra) { 671 Message msg = new Message(); 672 msg.obj = mp; 673 msg.what = MEDIA_PLAYER_INFO; 674 msg.arg1 = what; 675 msg.arg2 = extra; 676 mEventHandler.sendMessage(msg); 677 return true; 678 } 679 680 @Override 681 public void onPrepared(AbsMediaPlayer mp) { 682 Message msg = new Message(); 683 msg.obj = mp; 684 msg.what = MEDIA_PLAYER_PREPARED; 685 mEventHandler.sendMessage(msg); 686 } 687 688 @Override 689 public void onProgressUpdate(AbsMediaPlayer mp, int time, int length) { 690 Message msg = new Message(); 691 msg.obj = mp; 692 msg.what = MEDIA_PLAYER_PROGRESS_UPDATE; 693 msg.arg1 = time; 694 msg.arg2 = length; 695 mEventHandler.sendMessage(msg); 696 } 697 698 @Override 699 public void onVideoSizeChangedListener(AbsMediaPlayer mp, int width, 700 int height) { 701 Message msg = new Message(); 702 msg.obj = mp; 703 msg.what = MEDIA_PLAYER_VIDEO_SIZE_CHANGED; 704 msg.arg1 = width; 705 msg.arg2 = height; 706 mEventHandler.sendMessage(msg); 707 } 708 }