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。
我尝试了很多东西,其中 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.
我不知道该怎么做。请建议如何分段下载大型视频文件并逐个播放所有部分。
实际上我必须在 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。
我尝试了很多东西,其中 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.