Java Android 分段下载视频并播放

Java Android download video in parts and Play combined

我不知道该怎么做。请建议如何分段下载大型视频文件并逐个播放所有部分。 实际上我必须在 Android VideoView 中传输 FTP 大文件。我搜索了很多,发现 android 不支持 FTP 流。

所以,我试着分多个部分下载文件,一个一个播放。但问题是只有文件的第一部分播放,其他部分不播放。请提出建议。

分段下载文件的代码。

URL url = new URL(fileUrl);
URLConnection ucon = url.openConnection();
InputStream is = ucon.getInputStream();
BufferedInputStream inStream = new BufferedInputStream(is, 1024 * 5);
FileOutputStream outStream = new FileOutputStream(fileName);
byte[] buff = new byte[5 * 1024];
int len;

int maxLenth = 10000;      //Some random value
int counter = 0;

//Read bytes (and store them) until there is nothing more to read(-1)
 while ((len = inStream.read(buff)) != -1) {
      outStream.write(buff, 0, len);
      counter ++;
      Log.d(TAG, "Counter: " + counter);

      if(counter == maxLenth) {
          counter = 0;
          outStream.flush();
          outStream.close();

          fileName = new File(directory.getAbsolutePath() + "/"
                        + context.getResources().getString(R.string.app_name) + "_"
                        + System.currentTimeMillis() + "." + format);
          fileName.createNewFile();
          outStream = new FileOutputStream(fileName);
      }
  }

下载文件后,我尝试更新列表以在至少下载 1 个文件时播放视频。 listFiles 包含所有下载文件的列表。

    Uri uri = Uri.parse(listFiles.get(0));
    videoView.setVideoURI(uri);
    videoView.start();

    videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            counter ++;
            if(counter < listFiles.size()) {
                Uri uri = Uri.parse(listFiles.get(counter));
                videoView.setVideoURI(uri);
                videoView.start();
            }
        }
    });

我不知道为什么下载的文件1之后的文件不能播放。他们甚至在 PC 上也玩不了。我不知道我做错了什么。

您可以创建用于流式传输视频的本地服务器 (ServerSocket)。

创建后台线程,您可以直接使用FTP获取流并将相同的日期写入本地服务器的输出流。当您完成一个文件的下载后,您可以打开第二个文件,但仍然使用本地服务器的相同输出流。

VideoView 中,您将使用您将为本地服务器打开的端口打开 127.0.0.1:PORT。我建议使用 IP 而不是 localhost,因为过去我遇到过某些设备无法识别域 localhost 的问题。使用 IP 我从来没有遇到过任何问题。

请注意,在您的本地服务器中,您需要在数据之前发送 HTTP header。

https://whosebug.com/a/34679964/5464100

我尝试了很多东西,其中 none 成功了。 Android API 目前不支持此功能。所以我必须依靠本机代码来解码视频然后编码。

要做到这一点,我必须先学习一些东西,例如 JNI and NDK. Then I will have to apply native code. I have heard of a good library that supports these features ffmpeg,它提供了许多功能。但是目前我正在从事另一个项目,所以我无法尝试那个库和所有这些东西。

如果将视图文件拆分为多个部分,则只有第一部分包含格式规范。这就是只有您的第一部分被播放的原因。所有其他部分都只是二进制文件。

下载完所有零件后,您必须按相同顺序合并它们。

private void mergeAfterDownload()
{
    Log.i(LOG_TAG, "Merging now");

    try {
        File destinationFile = new File("Path to the Merged File");
        if (destinationFile.exists()) destinationFile.delete();

        // Create the parent folder(s) if necessary
        destinationFile.getParentFile().mkdirs();
        // Create the file
        destinationFile.createNewFile();

        FileOutputStream destinationOutStream = new FileOutputStream(destinationFile);

        // Enumerate through all the Parts and Append them to the destinationFile
        for (File file : listFiles) {
            // Read the Part
            InputStream inStream = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(inStream);

            // Append the Part to the destinationFile
            byte[] buffer = new byte[1024];
            int read;
            while ((read = bis.read(buffer)) != -1) {
                destinationOutStream.write(buffer, 0, read);
            }

            bis.close();
            inStream.close();

            //Delete the Slice
            file.delete();
        }

        destinationOutStream.close();

        Log.i(LOG_TAG, "File Merge Complete");
    }
    catch (Exception e) {

        e.printStackTrace();
        Log.e(LOG_TAG, "Failed to merge file");
    }
}

您可以创建一个 ContentProvider 并使用其 Uri 来初始化 VideoView,而不是构建本地服务器。通常我们使用 ContentProvider 将一些数据传递给具有某种 SQL 访问权限的其他应用程序,但这里它将是一个提供二进制数据的应用程序内提供程序。

Here is a tutorial 展示了如何使用 ContentProvider 处理二进制数据。

用这种方式解码文件不会播放所有文件。因为它们只是二进制文件,而您正试图更改它们的扩展名。 android 无法以这种方式解码文件。但是有很多库可以用来将文件解码成多个部分,然后分别播放每个部分。其中一个图书馆是 ffmpeg.