Android videoview 可以播放存储在内部存储器上的视频吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3038474/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:25:37  来源:igfitidea点击:

Can a videoview play a video stored on internal storage?

androidinternalandroid-videoview

提问by shellman

I'm trying to provide my users with the ability to use either external or internal storage. I'm displaying both images and videos (of a scientific nature). When storing the media on the SD card, all is fine. But when I store the media internally, only the images will display. No matter what I try I get various errors when trying to load and display the media stored under the applicationcontext.getFilesDir().

我正在尝试为我的用户提供使用外部或内部存储的能力。我正在显示图像和视频(具有科学性质)。将媒体存储在 SD 卡上时,一切正常。但是当我在内部存储媒体时,只会显示图像。无论我尝试什么,在尝试加载和显示存储在 applicationcontext.getFilesDir() 下的媒体时都会遇到各种错误。

Is there a trick to setting a videoview's content to such a file?

将视频视图的内容设置为这样的文件有什么技巧吗?

Can a ContentResolver help me?

ContentResolver 可以帮助我吗?

On a related note, is it considered bad form to assume that external storage exists?

在相关说明中,假设存在外部存储是否被认为是不好的形式?

Thanks in advance,

提前致谢,

Sid

锡德

Below is one version that fails with "Cannot play video. Sorry, this video cannot be played". But I have many other modes of failure. I can copy the internal video to temp storage (external) and play it, so this copy to internal does indeed create a valid movie. It only fails when I try to play it directly from the internal storage.

以下是因“无法播放视频。抱歉,无法播放此视频”而失败的一个版本。但我还有很多其他的失败模式。我可以将内部视频复制到临时存储(外部)并播放它,所以这个复制到内部确实创建了一个有效的电影。只有当我尝试直接从内部存储播放它时才会失败。

videoFile = new File(this.getFilesDir() + File.separator + "test.mp4");


InputStream data = res.openRawResource(R.raw.moviegood);


try {
    OutputStream myOutputStream = new FileOutputStream(videoFile);


    byte[] buffer = new byte[8192];
    int length;
    while ( (length = data.read(buffer)) > 0 ) {
        myOutputStream.write(buffer);
    }

    //Close the streams
    myOutputStream.flush();
    myOutputStream.close();
    data.close();
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}




vview.setKeepScreenOn(true);
vview.setVideoPath(videoFile.getAbsolutePath());
vview.start();

回答by gtkandroid

MediaPlayer requires that the file being played has world-readable permissions. You can view the permissions of the file with the following command in adb shell:

MediaPlayer 要求正在播放的文件具有全球可读的权限。您可以在 adb shell 中使用以下命令查看文件的权限:

ls -al /data/data/com.mypackage/myfile

You will probably see "-rw------", which means that only the owner (your app, not MediaPlayer) has read/write permissions.

您可能会看到“-rw------”,这意味着只有所有者(您的应用程序,而不是 MediaPlayer)具有读/写权限。

Note: Your phone must be rooted in order to use the ls command without specifying the file (in the internal memory).

注意:您的手机必须root 才能使用ls 命令而不指定文件(在内存中)。

If your phone is rooted, you can add world-read permissions in adb shell with the following command:

如果您的手机已root,则可以使用以下命令在 adb shell 中添加全局读取权限:

chmod o+r /data/data/com.mypackage/myfile

If you need to modify these permissions programmatically (requires rooted phone!), you can use the following command in your app code:

如果您需要以编程方式修改这些权限(需要root手机!),您可以在您的应用程序代码中使用以下命令:

Runtime.getRuntime().exec("chmod o+r /data/data/com.mypackage/myfile");

Which is basically a linux command. See https://help.ubuntu.com/community/FilePermissionsfor more on chmod.

这基本上是一个linux命令。有关chmod 的更多信息,请参阅https://help.ubuntu.com/community/FilePermissions

EDIT: Found another simple approach here(useful for those without rooted phones). Since the application owns the file, it can create a file descriptor and pass that to mediaPlayer.setDataSource():

编辑:在这里找到了另一种简单的方法(对于没有root手机的人很有用)。由于应用程序拥有该文件,它可以创建一个文件描述符并将其传递给 mediaPlayer.setDataSource():

FileInputStream fileInputStream = new FileInputStream("/data/data/com.mypackage/myfile");
mediaPlayer.setDataSource(fileInputStream.getFD());

This approach avoids the permission issue completely.

这种方法完全避免了权限问题。

回答by HocineHamdi

You can use:

您可以使用:

videoView.setVideoURI(Uri.parse(file.getAbsolutePath()));

if the file is world readable

如果文件是世界可读的

Or you can use a content provider

或者您可以使用内容提供程序

回答by Jawad Zeb

For detail check this tutorial

有关详细信息,请查看本教程

public class AndroidVideoViewExample extends Activity {

    private VideoView myVideoView;
    private int position = 0;
    private ProgressDialog progressDialog;
    private MediaController mediaControls;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // set the main layout of the activity
        setContentView(R.layout.activity_main);

        //set the media controller buttons
        if (mediaControls == null) {
            mediaControls = new MediaController(AndroidVideoViewExample.this);
        }

        //initialize the VideoView
        myVideoView = (VideoView) findViewById(R.id.video_view);

        // create a progress bar while the video file is loading
        progressDialog = new ProgressDialog(AndroidVideoViewExample.this);
        // set a title for the progress bar
        progressDialog.setTitle("JavaCodeGeeks Android Video View Example");
        // set a message for the progress bar
        progressDialog.setMessage("Loading...");
        //set the progress bar not cancelable on users' touch
        progressDialog.setCancelable(false);
        // show the progress bar
        progressDialog.show();

        try {
            //set the media controller in the VideoView
            myVideoView.setMediaController(mediaControls);

            //set the uri of the video to be played
            myVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.kitkat));

        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }

        myVideoView.requestFocus();
        //we also set an setOnPreparedListener in order to know when the video file is ready for playback
        myVideoView.setOnPreparedListener(new OnPreparedListener() {

            public void onPrepared(MediaPlayer mediaPlayer) {
                // close the progress bar and play the video
                progressDialog.dismiss();
                //if we have a position on savedInstanceState, the video playback should start from here
                myVideoView.seekTo(position);
                if (position == 0) {
                    myVideoView.start();
                } else {
                    //if we come from a resumed activity, video playback will be paused
                    myVideoView.pause();
                }
            }
        });

    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        //we use onSaveInstanceState in order to store the video playback position for orientation change
        savedInstanceState.putInt("Position", myVideoView.getCurrentPosition());
        myVideoView.pause();
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        //we use onRestoreInstanceState in order to play the video playback from the stored position 
        position = savedInstanceState.getInt("Position");
        myVideoView.seekTo(position);
    }
}

回答by tuandroid

I posted a custom VideoView implementation there.

我在那里发布了一个自定义 VideoView 实现。

The VideoView implementation has the setVideoFD(FileDescriptor fd)method and solves this issue.

VideoView 实现有setVideoFD(FileDescriptor fd)方法并解决了这个问题。

回答by tutts

I came across this thread with the same problem, I'm downloading my videos from the web to the internal storage, turns out when saving you can specify the RW mode, i.e change from PRIVATEto WORLD_READABLE

我在这个线程遇到了同样的问题,我正在将我的视频从网络下载到内部存储,结果在保存时您可以指定 RW 模式,即更改PRIVATEWORLD_READABLE

URL url = new URL(_url);
InputStream input = null;
FileOutputStream output = null;

try {
String outputName = "video.mp4";

input = url.openConnection().getInputStream();
output = c.openFileOutput(outputName, Context.MODE_WORLD_READABLE);

int read;
byte[] data = new byte[5120]; //5MB byte array
while ((read = input.read(data)) != -1)
output.write(data, 0, read);

return true;

} finally {
if (output != null)
   output.close();
if (input != null)
   input.close();
    }
}

回答by HocineHamdi

You can't just play it directly.

你不能直接播放它。

You need to implement a ContentProvider then pass the defined Uri to setVideoUri(uri) method.

您需要实现一个 ContentProvider,然后将定义的 Uri 传递给 setVideoUri(uri) 方法。