【问题标题】:Java Android download video in parts and Play combinedJava Android 下载视频部分和播放相结合
【发布时间】:2023-03-16 00:06:01
【问题描述】:

我不知道该怎么做。请建议如何分段下载大型视频文件并逐个播放所有部分。 实际上我必须在 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上也不玩。我不知道我做错了什么。

【问题讨论】:

  • 您是否尝试在您的视频视图 setOnCompletionListener 上设置断点以查看它是否进入?
  • 是的,它显示“无法播放此视频”
  • 除第一个文件外,所有文件的类型是什么?它们是视频文件还是二进制文件?你是如何分离视频文件的?你的视频文件头怎么样?
  • 所有文件的扩展名都是.mp4。请查看 while 循环以了解我是如何分离视频文件的,但它可能不会为我当前代码的最后一部分创建文件。我没有设置任何视频文件头。我只是在我的 FTP 服务器上尝试它,没有任何标题。
  • 分割文件的方式,视频文件是手动分割的,扩展名为.mp4,但不是视频文件。您不能将二进制文件作为视频文件播放。

标签: java android ftp video-streaming multipart


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 感谢您的建议,但您知道 Android 不提供 FTP 视频流。
  • 这里没问题,因为假服务器使用 HTTP 将组合视频流式传输到 VideoView。 FTP 用于下载您之前尝试过的片段。
【解决方案2】:

以这种方式解码文件不会播放所有文件。因为它们只是二进制文件,而您正在尝试更改它们的扩展名。 android中没有办法以这种方式解码文件。但是有许多库可用于将文件解码为多个部分,然后分别播放每个部分。其中一个库是ffmpeg

【讨论】:

  • 你是对的。我已经指出了这个问题,但还没有尝试过。
【解决方案3】:

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

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

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

【讨论】:

  • 这意味着在所有 5KB 部分下载完成之前,您无法开始播放。
  • 这意味着在下载所有部分之前我将无法进行流式传输。所以这不符合要求。
  • @RakeshYadav,您的代码没有执行流式传输。而且您的问题也没有要求流式传输的解决方案。在您的问题中,您专门询问下载后播放文件的解决方案,以及我的回答提供了一个可行的解决方案。
  • 只是将问题标题带到您的注意“Java Android 下载视频部分和播放组合”
【解决方案4】:

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

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

【讨论】:

    【解决方案5】:

    我尝试了很多东西,但都没有奏效。 Android API 目前不支持此功能。所以我必须依靠本机代码来解码视频然后编码。

    为此,我必须先学习一些东西,例如 JNINDK。然后我将不得不应用本机代码。我听说有一个很好的库支持这些功能ffmpeg,它提供了许多功能。但目前我正在从事另一个项目,所以我无法尝试那个库和所有这些东西。

    【讨论】:

    • 很抱歉让您失望了,但无论是 JNI 还是 ffmpeg 都不会比 Mills 提出的 solution 更好地帮助您实现目标。
    • 两个问题都是我不能使用服务器,否则我会毫无问题地使用http。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-14
    • 1970-01-01
    • 1970-01-01
    • 2019-02-22
    • 2011-12-14
    • 2011-01-24
    相关资源
    最近更新 更多