- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我有一个 Activity ,其中有
视频查看 -- 从网络服务器流式传输视频。
按钮 -- 将用户带到下一个要显示的 Activity 。
当应用程序启动时, VideoView 用于播放来自网络服务器的视频。
现在假设
Total Video length is 60 Minutes
Current Video progress is 20 Minutes
Current Buffered progress 30 Minutes
现在,当我单击上面提到的按钮时,它会将用户带到下一个 Activity 。
如果我按下后退按钮,则从该 Activity 中,上一个 Activity (带有 VideoView 和按钮)出现在用户面前。但是当恢复时,视频的所有缓冲部分都丢失了,因此 VideoView 从头开始播放视频,这真的很糟糕。 <-- 实际问题
问题
当 Activity 恢复时,视频的缓冲部分会丢失,因此会再次开始缓冲。那么如何克服重新缓冲视频的缓冲部分呢?
甚至是官方的 Youtube 安卓应用。有同样的问题。
编辑 1:
我在 Activity 中尝试了以下代码,但它不起作用。
@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();
}
任何人都可以指导我解决这个问题吗?还是我错过了使这项工作完美的东西?
当前解决方法
我已经在 onPause()
方法和 onResume()
方法中保存了视频的当前播放位置,我已经使用该位置将视频搜索到该持续时间.这工作正常。但是视频缓冲从头开始,它从搜索位置开始视频。
非常感谢任何帮助。
最佳答案
我花了几个小时试图破解原始 VideoView 源代码,现在我可以确认 VideoView 可以被破解以执行您想要的操作 - 在表面被破坏后保留缓冲。我已经在我的三星 Galaxy S2 上进行了测试,它按预期工作,在我的情况下,当我打开一个新 Activity 并返回时,视频缓冲(从远程 http 服务器流式传输 m4v 视频)成功保留。
基本上,解决方法是创建您自己的 VideoView 类(通过复制源代码),并破解 SurfaceHolder.Callback() 实现。请记住,VideoView 使用一些内部/隐藏 API,因此如果您想在自己的项目中创建 VideoView 的副本,您必须遵循 inazaruk's article启用使用内部/隐藏 API。作为一个快速破解,我只需从 here 下载 inazaruk 的构建。并使用 inazaruk-android-sdk-dbd50d4/platforms/android-15-internals/android.jar 替换我的 android-sdk/platforms/android-15/中的原始 android.jar。
VideoView源码可以从GrepCode下载.成功创建自己的副本且没有编译错误后,将 SurfaceHolder.Callback() 更改为如下内容:
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.
}
};
并确保不要像这样在 MediaPlayerActivity 中显式调用 videoView.resume()、videoView.setVideoURI()、videoView.suspend() 和 videoView.stopPlayback():
@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 类以避免任何副作用。
更新:
作为替代方案,您应该能够使用普通的 MediaPlayer 创建您的 MediaPlayerActivity 来实现相同的效果,如果您不想执行 interal/hide API 的东西您可以从 ApiDemos 示例中的 MediaPlayerDemo_Video.java 开始。关键是确保在 SurfaceHolder 回调方法和 Activity 生命周期方法中正确处理准备(结果缓冲)和释放方法,以避免每次创建/销毁表面以及启动、恢复/暂停 Activity 时准备/释放视频,停了下来。我创建了一个虚拟的 BufferedMediaPlayerActivity(高度简化,以便在此处发布),它只包含关键部分,可用于快速演示,它没有 MediaController,但是,您可以从 Logcat 中查看缓冲区百分比实际上是保持的每次打开新 Activity 并返回时,都会增加而不是从 0 滚动。
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:
<?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>
关于android - VideoView onResume 丢失视频的缓冲部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9987042/
我在 Ubuntu 10.04 LTS 上运行 Eclipse Galileo。今天 Ubuntu 在我身上崩溃了,重新启动后,我发现 Eclipse 已经完全失去了 Java Perspective
我使用配置了 sonata_user 的 SonataAdminBundle在 config.yml : sonata_user: impersonating: route:
我有 ubuntu 14.04 但它不见了 docker exec sudo docker exec -it ubuntu_bash bash 我希望在现有正在运行的 docker 容器中运行交互式
我正在使用 Ubuntu 8.04/32 位(作为虚拟机)。在一个不是 min 的项目上执行一些 make 时,我得到了错误: g++:/usr/lib/libstdc++.a: 没有这样的文件或目录
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许在 Stack Overflow 上提出有关通用计算硬件和软件的问题。您可以编辑问题,使其成为
我正在尝试获取有关我在 UIImagePicker 中选择的视频的一些数据。 因此,当它进入 UIImagePicker 委托(delegate)方法(如下)时,我知道我需要使用信息字典中的 UIIm
我的网站最近被可能的黑客行为删除了。我上传了备份的文件夹和数据库,但现在我的 View 没有显示。其他一切都有效。我想不出有什么变化,只是上传了几天前的备份。 这些字段在 admin/build/vi
我执行以下操作来设置我的 session ,这是有效的,因为 echo 出现了。但是当我转到下一页或另一页时, session 不存在吗?我做错了什么? $session_start(); if ($
我试图在 BigQuery 中使用这段代码,显然是从 GA 中获取数据,但 _TABLE_SUFFIX 似乎有问题。错误显示“错误:无法识别的名称:_TABLE_SUFFIX at [12:3]”您能
输入:8(2 5 6 9 10 2 7 4)预期输出:(2 7 9 9 12 5 7 6)实际输出:(2 7 9 9) 这是我的大学作业,也是我第一次在这里提问。我不知道为什么,但 10 没有扫描,有
$('div'); // 我在上面的代码中遇到错误。在检查 .js 代码时,我找不到名为 $ 的函数,但根据文档,应该有一个。 最佳答案 试试 http://ajax.googleapis.co
以下简单代码的输出对我来说有点奇怪。它错过了在控制台上打印的 0 到 100 之间的一些数字。 谁能解释一下为什么省略打印?我对并发编程完全陌生。 import java.util.concurren
我正在学习 xamarin 以构建移动应用程序,但我对 Xamarin 和移动应用程序一无所知。我打开了一个空白的移动应用程序,其中有“Hello world”示例并编辑了一些文本,但我的应用程序图标
我正在将一些值存储到 sqlite 数据库中。因此,数据是作为字符串从文本字段收集的,然后转换为 double 并持久化。 这是我试过的 NSDecimalNumber 答案; value.answe
我有一个奇怪的案例。突然,其中一个表中的一些记录(这么多记录)丢失了。首先,我认为这是由我的 PHP 脚本中的错误引起的。但是,我检查了一下,我的脚本中没有DELETE操作,只有UPDATE。有谁知道
我正在复制 NSString来自 NSDictionary进入本地NSString使用 [[NSString alloc] initWithString:] ,对其进行处理(删除一些字符),然后将其发
当保存在根文件夹中时,我的非常基本的 html 页面保持样式。为一个组创建了一个新文件夹,但是当我将页面移动到该文件夹时,它们似乎失去了与 css 文件的连接。 认为问题可能出在链接上,因为它现在
我需要使用 OpenCV 训练一些图像。但问题是,我找不到 opencv_createsamples 程序。我以正常方式安装了 OpenCV,因为我使用的是 Windows 7。这个 opencv_c
我有一个绑定(bind)到 JTable 的 ArrayList。之后 bindingGroup.unbind(); bindingGroup.bind(); (完成刷新数据)我丢失了表格单元格渲
所以基本上我们只是丢失了一个 keystore 和备份 keystore 。但是我们可能知道原始 keystore 的密码。 我的问题是,如果我们知道原始 keystore 的密码,我们可以重新生成
我是一名优秀的程序员,十分优秀!