簡體   English   中英

帶有NodeJS API的Android VideoView seekTo效果不佳

[英]Android VideoView seekTo With NodeJS API doesn't work well

我正在將視頻流式傳輸到VideoView上,為了旋轉電話,我保存了視頻位置並使用seekTo來同時播放視頻,但遇到了一些麻煩。

當我直接在不使用NodeJS中的API的情況下直接放置視頻的URI時,seekTo可以完美地工作:

videovvw.setVideoURI(Uri.parse("http://exemple.com/video.mp4"));

但是,當我使用API​​時,經過1/2轉后,我得到了一個深色的VideoView屏幕和一條錯誤消息,告訴我“無法播放此視頻”。 奇怪的是,發生此錯誤時,應用程序執行了很多請求將視頻發送到API。

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

謝謝你的幫助

我終於找到了答案,我認為問題來自服務器端的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()正確設置標頭。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM