我在下载过程中使用此代码播放视频,但是当我尝试播放视频时,我无法播放视频

时间:2017-06-13 13:56:29

标签: video-streaming android-mediaplayer android-videoview mediacontroller

我正在使用此代码但是当我尝试在下载视频期间播放视频时,video_view显示我无法播放视频

    private String videoPath="http://codechair.com/video/1496139752333.mp4";
    private String outFilePath="/sdcard/file_name_soniji.mp4";
    //My Mobile Ip
    private String serverPath="10.92.234.117";
    private VideoDownloadAndPlayService videoService;
    public class Testing extends AppCompatActivity {
    VideoView videoView;
    MediaController mediaController;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_testing);
        videoView = (VideoView) findViewById(R.id.vid258);
        mediaController = new MediaController(this);
     startServer();
     }

       private void startServer()
       {
        videoService = VideoDownloadAndPlayService.startServer(Testing.this, videoPath,outFilePath, serverPath, new VideoDownloadAndPlayService.VideoStreamInterface()
        {
            @Override
            public void onServerStart(String videoStreamUrl)
            {
                      // try to play 

                videoView.setVideoPath(outFilePath);
                videoView.requestFocus();
                videoView.setMediaController(mediaController);
                videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        //mp.setLooping(true);
                        videoView.start();
                    }
                });


                // use videoStreamUrl to play video through media player
            }
        });
    }

和VideoDownloadAndPlayService在这里

    public class VideoDownloadAndPlayService
{
    final static String TAG="VideoDown";
    private static LocalFileStreamingServer server;

    public VideoDownloadAndPlayService(LocalFileStreamingServer server)
    {
        this.server = server;
    }

    public static VideoDownloadAndPlayService startServer(final Activity activity,  String videoUrl, String pathToSaveVideo, final String ipOfServer, final VideoStreamInterface callback)
    {
        new VideoDownloader().execute(videoUrl, pathToSaveVideo);
        server = new LocalFileStreamingServer(new File(pathToSaveVideo));
        server.setSupportPlayWhileDownloading(true);
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                server.init(ipOfServer);

                activity.runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                       // Log.d(TAG,"videourl "+String.valueOf(videoUrl));
                        server.start();
                        callback.onServerStart(server.getFileUrl());

                    }
                });
            }
        }).start();

        return new VideoDownloadAndPlayService(server);
    }

    public void start(){
        server.start();
    }

    public void stop(){
        server.stop();
    }

    public static interface VideoStreamInterface{
        public void onServerStart(String videoStreamUrl);
    }
}

LocalFileStreamingServer类文件在这里

 public class LocalFileStreamingServer implements Runnable
{
    private static final String TAG = LocalFileStreamingServer.class.getName();
    private int port = 0;
    private boolean isRunning = false;
    private ServerSocket socket;
    private Thread thread;
    private long cbSkip;
    private boolean seekRequest;
    private File mMovieFile;

    private boolean supportPlayWhileDownloading = false;

    /**
     * This server accepts HTTP request and returns files from device.
     */
    public LocalFileStreamingServer(File file)
    {
        mMovieFile = file;
    }

    /**
     * @return A port number assigned by the OS.
     */
    public int getPort()
    {
        return port;
    }

    /**
     * Prepare the server to start.
     * <p>
     * This only needs to be called once per instance. Once initialized, the
     * server can be started and stopped as needed.
     */
    public String init(String ip)
    {
        String url = null;
        try
        {
            InetAddress inet = InetAddress.getByName(ip);
            byte[] bytes = inet.getAddress();
            socket = new ServerSocket(port, 0, InetAddress.getByAddress(bytes));

            socket.setSoTimeout(10000);
            port = socket.getLocalPort();
            url = "http://" + socket.getInetAddress().getHostAddress() + ":"
                    + port;
            Log.e(TAG, "Server started at " + url);
        } catch (UnknownHostException e)
        {
            Log.e(TAG, "Error UnknownHostException server", e);
        } catch (IOException e)
        {
            Log.e(TAG, "Error IOException server", e);
        }
        return url;
    }

    public String getFileUrl()
    {
        return "http://" + socket.getInetAddress().getHostAddress() + ":"
                + port + "/" + mMovieFile.getName();
    }

    /**
     * Start the server.
     */
    public void start()
    {
        thread = new Thread(this);
        thread.start();
        isRunning = true;
    }

    /**
     * Stop the server.
     * <p>
     * This stops the thread listening to the port. It may take up to five
     * seconds to close the service and this call blocks until that occurs.
     */
    public void stop()
    {
        isRunning = false;
        if (thread == null)
        {
            Log.e(TAG, "Server was stopped without being started.");
            return;
        }
        Log.e(TAG, "Stopping server.");
        thread.interrupt();
    }

    /**
     * Determines if the server is running (i.e. has been <code>start</code>ed
     * and has not been <code>stop</code>ed.
     *
     * @return <code>true</code> if the server is running, otherwise
     * <code>false</code>
     */
    public boolean isRunning()
    {
        return isRunning;
    }

    /**
     * This is used internally by the server and should not be called directly.
     */
    @Override
    public void run()
    {
        Log.e(TAG, "running");
        while (isRunning)
        {
            try
            {
                Socket client = socket.accept();
                if (client == null)
                {
                    continue;
                }
                Log.e(TAG, "client connected at " + port);
                ExternalResourceDataSource data = new ExternalResourceDataSource(
                        mMovieFile);
                Log.e(TAG, "processing request...");
                processRequest(data, client);
            } catch (SocketTimeoutException e)
            {
                Log.e(TAG, "No client connected, waiting for client...", e);
                // Do nothing
            } catch (IOException e)
            {
                Log.e(TAG, "Error connecting to client", e);
                // break;
            }
        }
        Log.e(TAG, "Server interrupted or stopped. Shutting down.");
    }

    /**
     * Find byte index separating header from body. It must be the last byte of
     * the first two sequential new lines.
     **/
    private int findHeaderEnd(final byte[] buf, int rlen)
    {
        int splitbyte = 0;
        while (splitbyte + 3 < rlen)
        {
            if (buf[splitbyte] == '\r' && buf[splitbyte + 1] == '\n'
                    && buf[splitbyte + 2] == '\r' && buf[splitbyte + 3] == '\n')
                return splitbyte + 4;
            splitbyte++;
        }
        return 0;
    }

    /*
     * Sends the HTTP response to the client, including headers (as applicable)
     * and content.
     */
    private void processRequest(ExternalResourceDataSource dataSource,
                                Socket client) throws IllegalStateException, IOException
    {
        if (dataSource == null)
        {
            Log.e(TAG, "Invalid (null) resource.");
            client.close();
            return;
        }
        InputStream is = client.getInputStream();
        final int bufsize = 8192;
        byte[] buf = new byte[bufsize];
        int splitbyte = 0;
        int rlen = 0;
        {
            int read = is.read(buf, 0, bufsize);
            while (read > 0)
            {
                rlen += read;
                splitbyte = findHeaderEnd(buf, rlen);
                if (splitbyte > 0)
                    break;
                read = is.read(buf, rlen, bufsize - rlen);
            }
        }

        // Create a BufferedReader for parsing the header.
        ByteArrayInputStream hbis = new ByteArrayInputStream(buf, 0, rlen);
        BufferedReader hin = new BufferedReader(new InputStreamReader(hbis));
        Properties pre = new Properties();
        Properties parms = new Properties();
        Properties header = new Properties();

        try
        {
            decodeHeader(hin, pre, parms, header);
        } catch (InterruptedException e1)
        {
            Log.e(TAG, "Exception: " + e1.getMessage());
            e1.printStackTrace();
        }
        for (Entry<Object, Object> e : header.entrySet())
        {
            Log.e(TAG, "Header: " + e.getKey() + " : " + e.getValue());
        }
        String range = header.getProperty("range");
        cbSkip = 0;
        seekRequest = false;
        if (range != null)
        {
            Log.e(TAG, "range is: " + range);
            seekRequest = true;
            range = range.substring(6);
            int charPos = range.indexOf('-');
            if (charPos > 0)
            {
                range = range.substring(0, charPos);
            }
            cbSkip = Long.parseLong(range);
            Log.e(TAG, "range found!! " + cbSkip);
        }
        String headers = "";
        // Log.e(TAG, "is seek request: " + seekRequest);
        if (seekRequest)
        {// It is a seek or skip request if there's a Range
            // header
            headers += "HTTP/1.1 206 Partial Content\r\n";
            headers += "Content-Type: " + dataSource.getContentType() + "\r\n";
            headers += "Accept-Ranges: bytes\r\n";
            headers += "Content-Length: " + dataSource.getContentLength(false)
                    + "\r\n";
            headers += "Content-Range: bytes " + cbSkip + "-"
                    + dataSource.getContentLength(true) + "/*\r\n";
            headers += "\r\n";
        } else
        {
            headers += "HTTP/1.1 200 OK\r\n";
            headers += "Content-Type: " + dataSource.getContentType() + "\r\n";
            headers += "Accept-Ranges: bytes\r\n";
            headers += "Content-Length: " + dataSource.getContentLength(false)
                    + "\r\n";
            headers += "\r\n";
        }

        InputStream data = null;
        try
        {
            data = dataSource.createInputStream();
            byte[] buffer = headers.getBytes();
            Log.e(TAG, "writing to client");
            client.getOutputStream().write(buffer, 0, buffer.length);

            // Start sending content.

            byte[] buff = new byte[1024 * 50];
            Log.e(TAG, "No of bytes skipped: " + data.skip(cbSkip));
            int cbSentThisBatch = 0;
            while (isRunning)
            {
                if (supportPlayWhileDownloading)
                {
                    // Check if data is ready
                    while (!VideoDownloader.isDataReady())
                    {
                        if (VideoDownloader.dataStatus == VideoDownloader.DATA_READY)
                        {
                            Log.e(TAG, "error in reading bytess**********(Data ready)");
                            break;
                        } else if (VideoDownloader.dataStatus == VideoDownloader.DATA_CONSUMED)
                        {
                            Log.e(TAG, "error in reading bytess**********(All Data consumed)");
                            break;
                        } else if (VideoDownloader.dataStatus == VideoDownloader.DATA_NOT_READY)
                        {
                            Log.e(TAG, "error in reading bytess**********(Data not ready)");
                        } else if (VideoDownloader.dataStatus == VideoDownloader.DATA_NOT_AVAILABLE)
                        {
                            Log.e(TAG, "error in reading bytess**********(Data not available)");
                        }
                        // wait for a second if data is not ready
                        synchronized (this)
                        {
                            Thread.sleep(1000);
                        }
                    }
                    Log.e(TAG, "error in reading bytess**********(Data ready)");
                }

                int cbRead = data.read(buff, 0, buff.length);
                if (cbRead == -1)
                {
                    Log.e(TAG,
                            "readybytes are -1 and this is simulate streaming, close the ips and create another  ");
                    data.close();
                    data = dataSource.createInputStream();
                    cbRead = data.read(buff, 0, buff.length);
                    if (cbRead == -1)
                    {
                        Log.e(TAG, "error in reading bytess**********");
                        throw new IOException(
                                "Error re-opening data source for looping.");
                    }
                }
                client.getOutputStream().write(buff, 0, cbRead);
                client.getOutputStream().flush();
                cbSkip += cbRead;
                cbSentThisBatch += cbRead;

                if(supportPlayWhileDownloading)
                    VideoDownloader.consumedb += cbRead;
            }
            Log.e(TAG, "cbSentThisBatch: " + cbSentThisBatch);
            // If we did nothing this batch, block for a second
            if (cbSentThisBatch == 0)
            {
                Log.e(TAG, "Blocking until more data appears");
                Thread.sleep(1000);
            }
        } catch (SocketException e)
        {
            // Ignore when the client breaks connection
            Log.e(TAG, "Ignoring " + e.getMessage());
        } catch (IOException e)
        {
            Log.e(TAG, "Error getting content stream.", e);
        } catch (Exception e)
        {
            Log.e(TAG, "Error streaming file content.", e);
        } finally
        {
            if (data != null)
            {
                data.close();
            }
            client.close();
        }
    }

    /**
     * Decodes the sent headers and loads the data into java Properties' key -
     * value pairs
     **/
    private void decodeHeader(BufferedReader in, Properties pre,
                              Properties parms, Properties header) throws InterruptedException
    {
        try
        {
            // Read the request line
            String inLine = in.readLine();
            if (inLine == null)
                return;
            StringTokenizer st = new StringTokenizer(inLine);
            if (!st.hasMoreTokens())
                Log.e(TAG,
                        "BAD REQUEST: Syntax error. Usage: GET /example/file.html");

            String method = st.nextToken();
            pre.put("method", method);

            if (!st.hasMoreTokens())
                Log.e(TAG,
                        "BAD REQUEST: Missing URI. Usage: GET /example/file.html");

            String uri = st.nextToken();

            // Decode parameters from the URI
            int qmi = uri.indexOf('?');
            if (qmi >= 0)
            {
                decodeParms(uri.substring(qmi + 1), parms);
                uri = decodePercent(uri.substring(0, qmi));
            } else
                uri = decodePercent(uri);

            // If there's another token, it's protocol version,
            // followed by HTTP headers. Ignore version but parse headers.
            // NOTE: this now forces header names lowercase since they are
            // case insensitive and vary by client.
            if (st.hasMoreTokens())
            {
                String line = in.readLine();
                while (line != null && line.trim().length() > 0)
                {
                    int p = line.indexOf(':');
                    if (p >= 0)
                        header.put(line.substring(0, p).trim().toLowerCase(),
                                line.substring(p + 1).trim());
                    line = in.readLine();
                }
            }

            pre.put("uri", uri);
        } catch (IOException ioe)
        {
            Log.e(TAG,
                    "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
        }
    }

    /**
     * Decodes parameters in percent-encoded URI-format ( e.g.
     * "name=Jack%20Daniels&pass=Single%20Malt" ) and adds them to given
     * Properties. NOTE: this doesn't support multiple identical keys due to the
     * simplicity of Properties -- if you need multiples, you might want to
     * replace the Properties with a Hashtable of Vectors or such.
     */
    private void decodeParms(String parms, Properties p)
            throws InterruptedException
    {
        if (parms == null)
            return;

        StringTokenizer st = new StringTokenizer(parms, "&");
        while (st.hasMoreTokens())
        {
            String e = st.nextToken();
            int sep = e.indexOf('=');
            if (sep >= 0)
                p.put(decodePercent(e.substring(0, sep)).trim(),
                        decodePercent(e.substring(sep + 1)));
        }
    }

    /**
     * Decodes the percent encoding scheme. <br/>
     * For example: "an+example%20string" -> "an example string"
     */
    private String decodePercent(String str) throws InterruptedException
    {
        try
        {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < str.length(); i++)
            {
                char c = str.charAt(i);
                switch (c)
                {
                    case '+':
                        sb.append(' ');
                        break;
                    case '%':
                        sb.append((char) Integer.parseInt(
                                str.substring(i + 1, i + 3), 16));
                        i += 2;
                        break;
                    default:
                        sb.append(c);
                        break;
                }
            }
            return sb.toString();
        } catch (Exception e)
        {
            Log.e(TAG, "BAD REQUEST: Bad percent-encoding.");
            return null;
        }
    }

    public boolean isSupportPlayWhileDownloading()
    {
        return supportPlayWhileDownloading;
    }

    public void setSupportPlayWhileDownloading(boolean supportPlayWhileDownloading)
    {
        this.supportPlayWhileDownloading = supportPlayWhileDownloading;
    }

    /**
     * provides meta-data and access to a stream for resources on SD card.
     */
    protected class ExternalResourceDataSource
    {

        private final File movieResource;
        long contentLength;
        private FileInputStream inputStream;

        public ExternalResourceDataSource(File resource)
        {
            movieResource = resource;
            Log.e(TAG, "respurcePath is: " + mMovieFile.getPath());
        }

        /**
         * Returns a MIME-compatible content type (e.g. "text/html") for the
         * resource. This method must be implemented.
         *
         * @return A MIME content type.
         */
        public String getContentType()
        {
            // TODO: Support other media if we need to
            return "video/mp4";
        }

        /**
         * Creates and opens an input stream that returns the contents of the
         * resource. This method must be implemented.
         *
         * @return An <code>InputStream</code> to access the resource.
         * @throws IOException If the implementing class produces an error when opening
         *                     the stream.
         */
        public InputStream createInputStream() throws IOException
        {
            // NB: Because createInputStream can only be called once per asset
            // we always create a new file descriptor here.
            getInputStream();
            return inputStream;
        }

        /**
         * Returns the length of resource in bytes.
         * <p>
         * By default this returns -1, which causes no content-type header to be
         * sent to the client. This would make sense for a stream content of
         * unknown or undefined length. If your resource has a defined length
         * you should override this method and return that.
         *
         * @return The length of the resource in bytes.
         */
        public long getContentLength(boolean ignoreSimulation)
        {
            if (!ignoreSimulation)
            {
                return -1;
            }
            return contentLength;
        }

        private void getInputStream()
        {
            try
            {
                inputStream = new FileInputStream(movieResource);
            } catch (FileNotFoundException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            // File temp = new File(respurcePath);
            contentLength = movieResource.length();
            Log.e(TAG, "file exists??" + movieResource.exists()
                    + " and content length is: " + contentLength);
        }

    }
}

最后一个VideoDownloader文件在这里

public class VideoDownloader extends AsyncTask<String, Integer, Void>
{
    public static final int DATA_READY = 1;
    public static final int DATA_NOT_READY = 2;
    public static final int DATA_CONSUMED = 3;
    public static final int DATA_NOT_AVAILABLE = 4;


    public static int dataStatus = -1;

    public static boolean isDataReady(){
        dataStatus = -1;
        boolean res = false;
        if(fileLength == readb){
            dataStatus = DATA_CONSUMED;
            res = false;
        }else if(readb > consumedb){
            dataStatus = DATA_READY;
            res = true;
        }else if(readb <= consumedb){
            dataStatus = DATA_NOT_READY;
            res = false;
        }else if(fileLength == -1){
            dataStatus = DATA_NOT_AVAILABLE;
            res = false;
        }
        return res;
    }

    /**
     * Keeps track of read bytes while serving to video player client from server
     */
    public static int consumedb = 0;

    /**
     * Keeps track of all bytes read on each while iteration
     */
    private static int readb = 0;

    /**
     * Length of file being downloaded.
     */
    static int fileLength = -1;

    @Override
    protected Void doInBackground(String... params)
    {


        BufferedInputStream input = null;
        try
        {
            final FileOutputStream out = new FileOutputStream(params[1]);

            try
            {
                URL url = new URL(params[0]);

                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.connect();
                if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
                {
                    throw new RuntimeException("response is not http_ok");
                }
                fileLength = connection.getContentLength();

                input = new BufferedInputStream(connection.getInputStream());
                byte data[] = new byte[1024 * 50];
                long readBytes = 0;
                int len;
                boolean flag = true;

                while ((len = input.read(data)) != -1)
                {
                    out.write(data, 0, len);
                    out.flush();
                    readBytes += len;
                    readb += len;
                    Log.w("download", (readb / 1024) + "kb of " + (fileLength / 1024) + "kb");
                }
            } catch (MalformedURLException e)
            {
                e.printStackTrace();
            } catch (IOException e)
            {
                e.printStackTrace();
            } finally
            {
                if (out != null)
                {
                    out.flush();
                    out.close();
                }
                if (input != null)
                    input.close();
            }
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid)
    {
        super.onPostExecute(aVoid);
        Log.w("download", "Done");
    }
} 

1 个答案:

答案 0 :(得分:0)

您拥有以下权限吗?

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

您还需要向用户请求权限:

public static final int REQUEST_EXTERNAL_PERMISSION_CODE = 666;

    public static final String[] PERMISSIONS_EXTERNAL_STORAGE = {
            READ_EXTERNAL_STORAGE,
            WRITE_EXTERNAL_STORAGE
    };

    public boolean checkExternalStoragePermission(Activity activity) {
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
            return true;
        }

        int readStoragePermissionState = ContextCompat.checkSelfPermission(activity, READ_EXTERNAL_STORAGE);
        int writeStoragePermissionState = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
        boolean externalStoragePermissionGranted = readStoragePermissionState == PackageManager.PERMISSION_GRANTED &&
                writeStoragePermissionState == PackageManager.PERMISSION_GRANTED;
        if (!externalStoragePermissionGranted) {
            requestPermissions(PERMISSIONS_EXTERNAL_STORAGE, REQUEST_EXTERNAL_PERMISSION_CODE);
        }

        return externalStoragePermissionGranted;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            if (requestCode == REQUEST_EXTERNAL_PERMISSION_CODE) {
                if (checkExternalStoragePermission(this)) {
                    // Continue with your action after permission request succeed
                }
            }
        }
    }

并加入onCreate:

checkExternalStoragePermission(this);