【问题标题】:Downloaded Video File Can't be Played in Android下载的视频文件无法在 Android 中播放
【发布时间】:2016-10-13 19:52:00
【问题描述】:

问题:
我下载的视频文件无法从任何播放器播放,更不用说我的应用的 VideoView,但它从 URL 到 VideoView 播放效果很好。

做了什么:
我正在下载a video file,如果它不在外部存储中,否则直接从 URL 播放到 VideoView。
VideoView部分代码如下:

final VideoView vvPlayer = (VideoView) findViewById(R.id.vvPlayer);
MediaController mc = new MediaController(MainActivity.this);
mc.setAnchorView(vvPlayer);
vvPlayer.setMediaController(mc);

if (videoFile.exists()) {
    // vvPlayer.setVideoURI(Uri.fromFile(videoFile));  <-- Also Tried :(
    vvPlayer.setVideoPath(videoFile.getAbsolutePath());
    Toast.makeText(this, "Playing from local ...", Toast.LENGTH_SHORT).show();
} else {
    vvPlayer.setVideoPath(VIDEO_PATH);
    Toast.makeText(this, "Playing online & caching ...", Toast.LENGTH_SHORT).show();
    downloadVideoFile();
}

downloadVideoFile() 方法的 AsyncTask 的核心部分,即the doInBackground(),使用以下代码将文件内容作为字符串返回:

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

    URLConnection conn;
    try {
        URL httpFileUrl = new URL(fileUrl);
        conn = httpFileUrl.openConnection();
        conn.connect();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
    Log.d(TAG, "Connection opened");
    InputStream inputStream;
    try {
        inputStream = new BufferedInputStream(conn.getInputStream(), 4096);
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }

    BufferedReader bufferedReader = new BufferedReader(
                                 new InputStreamReader(inputStream));

    int responseLen = 0;
    StringBuilder stringBuilder = new StringBuilder();
    String responseStr;
    try {
        while ((responseStr = bufferedReader.readLine()) != null) {
            // Log.i(TAG, "Response read: " + responseStr);
            stringBuilder.append(responseStr.trim());
            // ...my progress-bar related codes
        }
        inputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }

    responseStr = stringBuilder.toString();
    return responseStr;
}

获取文件内容后,我使用以下代码将它们简单地保存在文件中:

        try {
            if (!APP_DIRECTORY.exists())
                APP_DIRECTORY.mkdirs();
            if (videoFile.createNewFile())
                Log.d(TAG, "Vide-file newly created");

            FileOutputStream fos = new FileOutputStream(videoFile);
            fos.write(fileContent.getBytes());
            fos.flush();
            fos.close();
        } catch (IOException e) {
            Log.d(TAG, "Exception for new creation of videoFile");
            e.printStackTrace();
        }

最终结果是一个 8.81 MB 的文件,用任何视频播放器都无法将其作为视频文件打开,更不用说我尝试过的 VideoView。

可能是我缺少诸如 codecencoding 甚至简单的 file-saving 部分之类的东西吗?

【问题讨论】:

  • 否,StringBuilder 无法处理二进制视频数据。您不应使用针对文本数据进行调整的 readLine()。从网络获取数据后,立即将数据直接写入 FileOutputStream。不要将其聚合到内存中:视频包含的字节数可能比 RAM 所能容纳的多得多。

标签: android video video-streaming android-videoview


【解决方案1】:
Replace your doInBackground with this:

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

    URLConnection conn;
    try {
        URL httpFileUrl = new URL(fileUrl);
        conn = httpFileUrl.openConnection();
        conn.connect();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
    Log.d(TAG, "Connection opened");
    InputStream inputStream;
    try {
        inputStream = new BufferedInputStream(httpFileUrl.openStream(), 8192);
OutputStream output = new FileOutputStream("/sdcard/downloadedfile.mp4");

byte data[] = new byte[1024];

            long total = 0;

            while ((count = input.read(data)) != -1) {
output.write(data, 0, count);
}
output.flush();
output.close();
            inputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }


    return null;
}


And in onPostExecute,

@Override
    protected void onPostExecute(String file_url) {

        String videoPath = Environment.getExternalStorageDirectory().toString() + "/downloadedfile.mp4";
        // Now pass this path for playing video.
    }

【讨论】:

  • 在方法的第一部分初始化的conn对象没有任何用处吗? ...我看到您已经直接使用httpFileUrl.openStream() 初始化了inputStream ...
  • conn 对象可用于获取文件的属性,例如,内容的长度,并使用它来验证下载的内容或显示文件下载的进度等。 int videofilelength = conn .getContentLength();
猜你喜欢
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多