Android VideoView seekTo使用NodeJS API并不能很好地运行

时间:2014-10-26 21:14:26

标签: java android node.js android-mediaplayer android-videoview

我在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);
            });
        });
    });

感谢您的帮助

1 个答案:

答案 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()正确设置标题。