我在VideoView上播放视频,为了手机旋转我保存视频位置并使用seekTo同时播放视频,但我遇到了一些麻烦。
当我直接放置视频的URI而不在NodeJS中使用我的API时,seekTo完美地工作:
videovvw.setVideoURI(Uri.parse("http://exemple.com/video.mp4"));
但是当我使用我的API时,经过1/2旋转后,我得到一个黑暗的VideoView屏幕和一条错误消息告诉我“无法播放此视频”。奇怪的是,当发生此错误时,应用程序会向视频提供大量请求。
GET /videoStream?idVideo=5433f07e073a384d324bb9cf 200 105ms - 5.26mb
GET /videoStream?idVideo=5433f07e073a384d324bb9cf 200 97ms - 5.26mb
GET /videoStream?idVideo=5433f07e073a384d324bb9cf 200 98ms - 5.26mb
...
这是android代码:
package com.stream.Activity;
import java.io.UnsupportedEncodingException;
import com.stream.R;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources.NotFoundException;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.Toast;
import android.widget.VideoView;
public class VideoActivityNew extends Activity {
private VideoView videovvw;
private int position = 0;
private MediaController mediaControls;
private ImageView fullScreenButton = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
setContentView(R.layout.activity_video_portrait);
videovvw = (VideoView)findViewById(R.id.videoVideoView);
fullScreenButton = new ImageView(getBaseContext());
fullScreenButton.setOnClickListener(clickListenerChangeScreenSize);
fullScreenButton.setImageResource(R.drawable.full_screen_icone);
} else {
setContentView(R.layout.activity_video_landscape);
videovvw = (VideoView)findViewById(R.id.videoVideoView);
fullScreenButton = new ImageView(getBaseContext());
fullScreenButton.setOnClickListener(clickListenerChangeScreenSize);
fullScreenButton.setImageResource(R.drawable.regular_screen_icone);
}
try {
streamVideo();
} catch (Exception e) {
Toast.makeText(VideoActivityNew.this, getResources().getString(R.string.ERROR_INVALID_PARAM), Toast.LENGTH_LONG).show();
}
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
if (videovvw != null) {
savedInstanceState.putInt("Position", videovvw.getCurrentPosition());
videovvw.pause();
}
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
position = savedInstanceState.getInt("Position");
}
private OnClickListener clickListenerChangeScreenSize = new OnClickListener() {
@Override
public void onClick(View v) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
else
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
};
private void streamVideo() throws NotFoundException, UnsupportedEncodingException {
new BackgroundAsyncTask()
.execute("http://exemple.com/videoStream?idVideo=5433f07e073a384d324bb9cf");
}
public class BackgroundAsyncTask extends AsyncTask<String, Uri, Void> {
ProgressDialog dialog;
protected void onPreExecute() {
dialog = new ProgressDialog(VideoActivityNew.this);
dialog.setMessage("Loading, Please Wait...");
dialog.setCancelable(false);
dialog.show();
}
@Override
protected void onProgressUpdate(final Uri... uri) {
try {
if (mediaControls == null)
mediaControls = new MediaController(VideoActivityNew.this) {
@Override
public void setAnchorView(View view) {
super.setAnchorView(view);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.RIGHT;
addView(fullScreenButton, params);
}
};
videovvw.setMediaController(mediaControls);
videovvw.setVideoURI(uri[0]);
videovvw.requestFocus();
videovvw.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
videovvw.seekTo(position);
mp.setOnSeekCompleteListener(new OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
dialog.dismiss();
videovvw.pause();
}
});
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected Void doInBackground(String... params) {
try {
publishProgress(Uri.parse(params[0]));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
}
和logcat消息:
10-26 22:10:29.881: E/InputEventReceiver(1161): channel '418aab78 Panel:com.test/com.test.Activity.VideoActivityNew (client)' ~ Publisher closed input channel or an error occurred. events=0x9
10-26 22:10:29.941: E/SurfaceTextureClient(1161): dequeueBuffer failed (No such device)
10-26 22:10:30.071: E/ViewRootImpl(1161): Could not lock surface
10-26 22:10:30.071: E/ViewRootImpl(1161): java.lang.IllegalArgumentException
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.Surface.lockCanvasNative(Native Method)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.Surface.lockCanvas(Surface.java:88)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.ViewRootImpl.drawSoftware(ViewRootImpl.java:2190)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.ViewRootImpl.draw(ViewRootImpl.java:2153)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2021)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1832)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4214)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.Choreographer.doCallbacks(Choreographer.java:555)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.Choreographer.doFrame(Choreographer.java:525)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.os.Handler.handleCallback(Handler.java:615)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.os.Handler.dispatchMessage(Handler.java:92)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.os.Looper.loop(Looper.java:137)
10-26 22:10:30.071: E/ViewRootImpl(1161): at android.app.ActivityThread.main(ActivityThread.java:4745)
10-26 22:10:30.071: E/ViewRootImpl(1161): at java.lang.reflect.Method.invokeNative(Native Method)
10-26 22:10:30.071: E/ViewRootImpl(1161): at java.lang.reflect.Method.invoke(Method.java:511)
10-26 22:10:30.071: E/ViewRootImpl(1161): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
10-26 22:10:30.071: E/ViewRootImpl(1161): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
10-26 22:10:30.071: E/ViewRootImpl(1161): at dalvik.system.NativeStart.main(Native Method)
10-26 22:10:30.391: D/MediaPlayer(1161): Couldn't open file on client side, trying server side
10-26 22:10:32.501: D/MediaPlayer(1161): getMetadata
10-26 22:11:05.701: E/MediaPlayer(1161): error (1, -1004)
10-26 22:11:05.841: E/MediaPlayer(1161): Error (1,-1004)
10-26 22:11:05.841: D/VideoView(1161): Error: 1,-1004
事实上,即使它正在工作,我也会得到这些错误,除了最后的3个。
我现在不知道错误是否来自我的API,因为流媒体路由非常简单:
app.get('/videoStream', function(req, res) {
Video.findOne({_id: req.query.idVideo}, function(err, video) {
if (err)
console.log("err: " + err);
if (video == null)
console.log("video not found");
res.setHeader('Content-Type', 'video/mp4');
fs.readFile('/home/video/video.mp4', function (err, data) {
res.send(data);
});
});
});
感谢您的帮助
答案 0 :(得分:0)
我终于找到了答案,我认为问题来自服务器端的http标头:
app.get('/videoStream', function(req, res) {
Video.findOne({_id: req.query.idVideo}, function(err, video) {
if (err)
console.log("err: " + err);
if (video == null)
console.log("video not found");
res.setHeader('Content-Type', 'video/mp4');
res.sendfile('/home/video/video.mp4', function (err) {
if (err)
console.log(err);
});
});
});
sendfile()正确设置标题。