VideoView onResume输了球缓冲视频的部分 [英] VideoView onResume loses buffered portion of the video

查看:376
本文介绍了VideoView onResume输了球缓冲视频的部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个活动,其中有

  1. VideoView     - 从网络服务器流的视频

  1. VideoView -- Streams a video from a webserver.

按钮 -    把用户带到下一个活动被证明。

Button -- Takes the user to the next activity to be shown.

在应用程序启动后,    VideoView是由从Web服务器播放视频。

When the application starts, VideoView is made to play the Video from a webserver.

现在假设

 Total Video length is 60 Minutes

 Current Video progress is 20 Minutes

 Current Buffered progress 30 Minutes 

现在,当我点击上述按钮,用户将进入到下一个活动。

Now when I click on the above mentioned Button which takes user to the next activity.

这是我是否preSS后退按钮,previous活动(与VideoView和Button)的活动出现在用户面前。 但恢复时该视频的所有的缓冲部分丢失,因此VideoView始于这是非常糟糕的开始播放视频。 < - 实际的问题

From that Activity if i press the back button, Previous Activity(with VideoView and Button) appears in front of the user. But when resumed all the Buffered Portion of the video is lost and hence the VideoView starts playing the video from the beginning which is really bad. <-- Actual Problem

问题

当活动恢复回来,视频的缓冲部分丧失,并因此再次开始缓冲它。因此,如何克服重缓冲视频的缓冲部分?

When Activity is resumed back, the buffered portion of the video is lost and hence starts buffering it again. So how to overcome re-buffering the buffered portion of the Video ?

即使YouTube官方Android应用程序。有同样的问题。

Even official Youtube android app. has the same problem.

修改1:

我想下面的code的活性,但它不工作。

I tried the below code in Activity but its not working.

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    videoView.suspend();
}

@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    videoView.resume();
}

任何人都可以指导我关于这个问题?还是我失去了一些东西,使这项工作完美?

Can anyone guide me regarding this problem ?. Or am I missing something to make this work perfectly ?

当前解决方法

我已经保存了视频的当前播放位置的onPause()方法和 onResume()方法我已经使用这个位置来寻找视频的时长。这工作得很好。但图象缓冲开始从头寿它开始从寻求位置的视频

I have saved the current playing position of the video in onPause() method and in onResume() method I have used that position to seek the video to that duration. This works fine. But the video buffering starts from the beginning tho it starts the video from the seek position.

任何帮助深表AP preciated。

Any help is deeply appreciated.

推荐答案

我已经花了几个小时试图破解原VideoView源$ C ​​$ c和现在,我可以确认VideoView你想要什么都可以砍死行为 - 保留缓冲表面被破坏后。我已经在我的三星Galaxy S2,预期其工作,在我的情况进行测试,视频缓冲(流从远程HTTP服务器M4V视频)已成功地保留,当我打开一个新的活动,回去吧。

I've spent several hours trying to hack the original VideoView source code and Now I can confirm VideoView can be hacked to behavior what you want - retain buffering after surface destroyed. I've tested on my Samsung Galaxy S2, which works as expected, in my case, the video buffering (streaming m4v video from remote http server) is successfully retained when I open a new activity and go back.

基本上,解决办法是创建你自己的VideoView类(通过复制源$ C ​​$ C),和黑客的SurfaceHolder.Callback()实现。请记住,VideoView使用一些内部/隐藏的API,所以如果你想在自己的项目中创建VideoView的副本,你必须遵循的<一个href="http://devmaze.word$p$pss.com/2011/01/18/using-com-android-internal-part-1-introduction/">inazaruk's文章启用使用内部/隐藏API。作为一个快速黑客,我刚刚从下载inazaruk的构建这里和使用inazaruk,Android的SDK-dbd50d4 /平台/ android- 15内部/替换的android.jar我原来的android.jar在我的Andr​​oid的SDK /平台/ Android为15 /.

Basically, the workaround is create you own VideoView class (by copying the source code), and hack the SurfaceHolder.Callback() implementation. Bear in mind that VideoView use some internal/hide API, so if you want to create a copy of VideoView in your own project, you have to follow the inazaruk's article to enable using internal/hide API. As a quick hack, I just download inazaruk's build from here and use inazaruk-android-sdk-dbd50d4/platforms/android-15-internals/android.jar replace my original android.jar in my android-sdk/platforms/android-15/.

VideoView源$ C ​​$ C可以从<一个下载href="http://grep$c$c.com/file/repository.grep$c$c.com/java/ext/com.google.android/android/4.0.3_r1/android/widget/VideoView.java?av=f">Grep$c$c.一旦你成功地创建你没有编译错误自己的副本,SurfaceHolder.Callback()更改为类似这样的:

VideoView source code can be downloaded from GrepCode. Once you successfully create you own copy without compile error, change SurfaceHolder.Callback() to something like this:

private boolean videoOpened = false;

SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
{

    ... ...

    public void surfaceCreated(SurfaceHolder holder)
    {
        Log.i(TAG, "---------------------> surface created.");
        mSurfaceHolder = holder;
        if (!videoOpened) {
          openVideo(); // <-- if first time opened, do something as usual, video is buffered.
          /** 
           * openVideo() actually mMediaPlayer.prepareAsync() is the first key point, it is
           * also called in other two VideoView's public methods setVideoURI() and resume(), 
           * make sure you don't call them in your activity.
           */ 
          videoOpened = true;
        } else {
          start();  // <-- if back from another activity, simply start it again.
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder)
    {
        Log.i(TAG, "---------------------> surface destroyed.");
        // after we return from this we can't use the surface any more.
        mSurfaceHolder = null;
        if (mMediaController != null) mMediaController.hide();
        //release(true);
        /**
         * release() actually mMediaPlayer.release() is the second key point, it is also
         * called in other two VideoView's public methods stopPlayback() and suspend(), make
         * sure you don't call them in your activity.
         */
        pause(); // <-- don't release, just pause.
    }
};

和确保你不叫videoView.resume(),videoView.setVideoURI(),videoView.suspend()和videoView.stopPlayback()明确在你MediaPlayerActivity是这样的:

And make sure you don't call videoView.resume(), videoView.setVideoURI(), videoView.suspend() and videoView.stopPlayback() explicitly in you MediaPlayerActivity like this:

@Override
protected void onResume() {
  if (videoView != null)
    videoView.resume();  // <-- this will cause re-buffer.
    super.onResume();
}

@Override
protected void onPause() {
  if (videoView != null)
    videoView.suspend(); // <-- this will cause clear buffer.
    super.onPause();
}

请注意,我刚才做了一个肮脏的黑客来证明的可行性,在设计和正确实施的VideoView类,以避免任何副作用。

Note that I have just done a dirty hack to prove the feasibility, You should design and implement your VideoView class properly to avoid any side-effect.

更新:

作为一种替代方法,你应该能够使用普通的MediaPlayer创建MediaPlayerActivity,如果你不想做INTERAL /隐藏API的东西,你可以用MediaPlayerDemo_Video.java在ApiDemos样品开始达到同样的效果。关键的一点是要确保prepare(结果缓存)和释放方法在两个SurfaceHolder回调方法和活动的生命周期方法,妥善处理,以免prepare /发布视频,每次表面创建/破坏,活动是开始,重新开始/暂停,停止。我创建了一个虚拟BufferedMediaPlayerActivity(张贴在这里高度简化的),其中包括唯一的关键部件,可用于快速演示,它不具有的MediaController,但是,你可以检查的logcat地看到,缓冲区百分比实际上保持增加从0在每次打开新的活动,回去一次翻身的来代替。

As an alternative, you should able to achieve same effect using plain MediaPlayer create your MediaPlayerActivity if you don't want to do the interal/hide API stuff You can start with the MediaPlayerDemo_Video.java in ApiDemos sample. The key point is make sure prepare (result buffering) and release method is properly handled in both SurfaceHolder Callback methods and Activity life cycle method to avoid prepare/release video every time surface is created/destroyed, and Activity is started,resumed/paused,stopped. I've created a dummy BufferedMediaPlayerActivity (highly simplified for posting here) which contains only key parts and can be used for quick demonstration, it doesn't have MediaController, however, you can check from Logcat to see that the buffer percentage is actually keep increasing instead of rolling over from 0 every time you open new activity and go back.

BufferedMediaPlayerActivity.java:

BufferedMediaPlayerActivity.java:

package com.example;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class BufferedMediaPlayerActivity extends Activity implements OnPreparedListener, OnBufferingUpdateListener, SurfaceHolder.Callback {

  private static final String TAG = "BufferedMediaPlayerActivity";
  private int mVideoWidth;
  private int mVideoHeight;
  private MediaPlayer mMediaPlayer;
  private SurfaceView mPreview;
  private SurfaceHolder holder;
  private String path;
  private boolean mIsVideoReadyToBePlayed = false;

  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.buffered_media_player);
    mPreview = (SurfaceView) findViewById(R.id.surface);
    holder = mPreview.getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    holder.setFixedSize(mVideoWidth, mVideoHeight);
    // retrieve httpUrl passed from previous activity.
    path = getIntent().getExtras().getString("videoUrl");
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    if (mMediaPlayer != null) {
      mMediaPlayer.release();
      mMediaPlayer = null;
    }
    mIsVideoReadyToBePlayed = false;
  }

  private void playVideo() {
    mIsVideoReadyToBePlayed = false;
    try {
      // Create a new media player and set the listeners
      mMediaPlayer = new MediaPlayer();
      mMediaPlayer.setDataSource(path);
      mMediaPlayer.setDisplay(holder);
      mMediaPlayer.prepare();
      mMediaPlayer.setOnPreparedListener(this);
      mMediaPlayer.setOnBufferingUpdateListener(this);
      mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    } catch (Exception e) {
      Log.e(TAG, "error: " + e.getMessage(), e);
    }
  }

  @Override
  public void onPrepared(MediaPlayer mediaplayer) {
    Log.d(TAG, "onPrepared called");
    mIsVideoReadyToBePlayed = true;
    if (mIsVideoReadyToBePlayed) {
      mMediaPlayer.start();
    }
  }

  @Override
  public void onBufferingUpdate(MediaPlayer mp, int percent) {
    Log.i(TAG, "---------------> " + percent);
  }

  @Override
  public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) {
    Log.d(TAG, "surfaceChanged called");
  }

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    Log.d(TAG, "surfaceCreated called");
    if (!mIsVideoReadyToBePlayed)
      playVideo();
    else
      mMediaPlayer.start();
  }

  @Override
  public void surfaceDestroyed(SurfaceHolder surfaceholder) {
    Log.d(TAG, "surfaceDestroyed called");
    mMediaPlayer.pause();
  }

}

buffered_media_player.xml:

buffered_media_player.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <SurfaceView android:id="@+id/surface"
    android:layout_width="200dip"
    android:layout_height="160dip"
    android:layout_gravity="center">
  </SurfaceView>

</LinearLayout>

这篇关于VideoView onResume输了球缓冲视频的部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆