ExoPlayer - 在SD卡中播放本地MP4文件

19

我正在使用Exoplayer Demo应用程序,并希望预加载SD卡中的MP4视频。 我尝试了这篇文章中的实现,但它不起作用。我的exoplayer Demo中没有名为DemoUtil.java的类。 而是使用:

public static final Sample[] LOCAL_VIDEOS = new Sample[] {
new Sample("Some User friendly name of video 1",
"/mnt/sdcard/video1.mp4", Util.TYPE_OTHER),
};

我也无法使用他们提到的SampleChooserActivity.java代码片段。(一直给我错误)

相反,我使用了:

group = new SampleGroup("Local Videos");
group.addAll(Samples.LOCAL_VIDEOS);
sampleGroups.add(group);

我做错了什么?每个设备的文件路径都会改变吗?


https://github.com/HamidrezaAmz/MagicalExoPlayer - Hamid Reza
8个回答

30

我没有尝试过演示应用程序,但我已经成功创建了自己的本地音频文件播放示例,并在此处发布了它: https://github.com/nzkozar/ExoplayerExample

这里是主要部分,它完成了从文件Uri准备播放器的所有工作:

private void prepareExoPlayerFromFileUri(Uri uri){
        exoPlayer = ExoPlayerFactory.newSimpleInstance(this, new DefaultTrackSelector(null), new DefaultLoadControl());
        exoPlayer.addListener(eventListener);

        DataSpec dataSpec = new DataSpec(uri);
        final FileDataSource fileDataSource = new FileDataSource();
        try {
            fileDataSource.open(dataSpec);
        } catch (FileDataSource.FileDataSourceException e) {
            e.printStackTrace();
        }

        DataSource.Factory factory = new DataSource.Factory() {
            @Override
            public DataSource createDataSource() {
                return fileDataSource;
            }
        };
        MediaSource audioSource = new ExtractorMediaSource(fileDataSource.getUri(),
                factory, new DefaultExtractorsFactory(), null, null);

        exoPlayer.prepare(audioSource);
    }

你可以像这样获取Uri:Uri.fromFile(file)

在按照上述方式准备好文件进行播放后,您只需要调用exoPlayer.setPlayWhenReady(true);开始播放。

对于视频文件,您可能只需要将一个SurfaceView附加到您的exoPlayer对象上,但我还没有真正使用ExoPlayer2完成这个操作。


1
完美的答案...毫无疑问地前进 :) - Ranjithkumar
4
为了将文件路径传递给ExoPlayer,需要编写这些代码,而用VideoView只需一行代码就能实现?我的天啊,ExoPlayer的设计者一定疯了或者有虐待倾向。此外,Android Studio提示ExtractorMediaSource已被弃用(SDK 29)。 - Damn Vegetables
我知道对吧。看着这个解决方案时,我感到愤怒和沮丧。而且,我很失望没有找到一个像我们使用 MediaPlayer 一样简单的一行API来播放媒体文件。我想我可能会寻找替代方案,唉。 - TheRealChx101
此功能已被弃用。 - larsaars

11

想要使用 ExoPlayer 2 播放来自资产的 视频 的人,这里有一种方法:

String playerInfo = Util.getUserAgent(context, "ExoPlayerInfo");
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(
        context, playerInfo
);
MediaSource mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory)
    .setExtractorsFactory(new DefaultExtractorsFactory())
    .createMediaSource(Uri.parse("asset:///your_video.mov"));
player.prepare(mediaSource);

5

这个方法适用于我。请尝试以下步骤:

获取文件路径并启动播放器。

File myFile = new File(extStore.getAbsolutePath() + "/folder/videos/" + video_name);  
videoUrl= String.valueOf(Uri.fromFile(myFile));  
initializePlayer(videoUrl);

初始化播放器

private void initializePlayer(String videoUrl) {
    player = ExoPlayerFactory.newSimpleInstance(
            new DefaultRenderersFactory(getActivity()),
            new DefaultTrackSelector(), new DefaultLoadControl());

    playerView.setPlayer(player);

    player.setPlayWhenReady(playWhenReady);
    player.seekTo(currentWindow, playbackPosition);

    Uri uri = Uri.parse(videoUrl);
    MediaSource mediaSource = buildMediaSource(uri);
    player.prepare(mediaSource, resetPositionBoolean, false);
}   

构建媒体来源。
  private MediaSource buildMediaSource(Uri uri) {
    return new ExtractorMediaSource.Factory(
            new DefaultDataSourceFactory(getActivity(),"Exoplayer-local")).
            createMediaSource(uri);
}

好复杂 :/ - TheRealChx101
在版本2.18.1中没有名为“ExoPlayerFactory”的类。 - Sambhav Khandelwal

1
对于那些希望从资产文件夹加载的人:

assets/xyz.mp4

它通过以下方式加载文件来运行:

"file:/android_asset/xyz.mp4"

并且使用DefaultDataSourceFactory。在ExoPlayer 2.4.4上进行验证。


问题是关于从SD卡访问的。 - Johann

0
在某些设备上,您可以直接使用此路径“/sdcard/nameoffile.mp4”。

0
如果您需要从assets字段获取数据,这将起作用。但是,如果数据来自SD卡,则无法使用此方法。
package com.studio.mattiaferigutti.exoplayertest

import android.annotation.SuppressLint
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.upstream.*
import com.google.android.exoplayer2.upstream.DataSource.Factory
import com.google.android.exoplayer2.util.Util
import kotlinx.android.synthetic.main.activity_main.*


class MainActivity : AppCompatActivity(), Player.EventListener {

    private var player: SimpleExoPlayer? = null
    private var playWhenReady = true
    private var currentWindow = 0
    private var playbackPosition: Long = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    public override fun onStart() {
        super.onStart()
        if (Util.SDK_INT > 23) {
            initializePlayer("assets:///your_file.your_extension")
        }
    }

    public override fun onResume() {
        super.onResume()
        hideSystemUi()
        if (Util.SDK_INT <= 23 || player == null) {
            initializePlayer("assets:///your_file.your_extension")
        }
    }

    public override fun onPause() {
        super.onPause()
        if (Util.SDK_INT <= 23) {
            releasePlayer()
        }
    }

    public override fun onStop() {
        super.onStop()
        if (Util.SDK_INT > 23) {
            releasePlayer()
        }
    }

    private fun initializePlayer(path: String) {
        if (player == null) {
            val trackSelector = DefaultTrackSelector(this)
            trackSelector.setParameters(
                trackSelector.buildUponParameters().setMaxVideoSizeSd())
            player = SimpleExoPlayer.Builder(this)
                .setTrackSelector(trackSelector)
                .build()
        }
        video_view?.player = player
        video_view?.requestFocus()

        val dataSourceFactory = Factory { AssetDataSource(this@MainActivity) }

        val videoSource = ProgressiveMediaSource.Factory(dataSourceFactory)
            .createMediaSource(Uri.parse(path))

        player?.playWhenReady = playWhenReady
        player?.seekTo(currentWindow, playbackPosition)
        player?.addListener(this)
        player?.prepare(videoSource)
    }

    private fun releasePlayer() {
        if (player != null) {
            playbackPosition = player?.currentPosition!!
            currentWindow = player?.currentWindowIndex!!
            playWhenReady = player?.playWhenReady!!
            player?.removeListener(this)
            player?.release()
            player = null
        }
    }

    /**
     * set fullscreen
     */
    @SuppressLint("InlinedApi")
    private fun hideSystemUi() {
        video_view?.systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE
                or View.SYSTEM_UI_FLAG_FULLSCREEN
                or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
    }

    override fun onPlayerError(error: ExoPlaybackException) {
        super.onPlayerError(error)

        //handle the error
    }

    override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
        val stateString: String = when (playbackState) {
            ExoPlayer.STATE_IDLE -> "ExoPlayer.STATE_IDLE      -"
            ExoPlayer.STATE_BUFFERING -> "ExoPlayer.STATE_BUFFERING -"
            ExoPlayer.STATE_READY -> "ExoPlayer.STATE_READY     -"
            ExoPlayer.STATE_ENDED -> "ExoPlayer.STATE_ENDED     -"
            else -> "UNKNOWN_STATE             -"
        }
        Log.d(TAG, "changed state to " + stateString
                + " playWhenReady: " + playWhenReady)
    }

    companion object {
        private val TAG = MainActivity::class.java.name
    }
}

-1

对于那些试图从< strong > res/raw*文件夹播放< strong >视频文件的人,这里有解决方案。请记住我使用的是< strong > ExoPlayer 的< strong > 2.8.0 版本。

public class MainActivity extends AppCompatActivity {

PlayerView playerView;
SimpleExoPlayer simpleExoPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    playerView=findViewById(R.id.playerView);
}

@Override
protected void onStart() {
    simpleExoPlayer= ExoPlayerFactory.newSimpleInstance(this,new DefaultTrackSelector());
    DefaultDataSourceFactory defaultDataSourceFactory=new DefaultDataSourceFactory(this, Util.getUserAgent(this,"YourApplicationName"));
    simpleExoPlayer.setPlayWhenReady(true);
    ExtractorMediaSource extractorMediaSource=new ExtractorMediaSource.Factory(defaultDataSourceFactory).createMediaSource(RawResourceDataSource.buildRawResourceUri(R.raw.video));
    simpleExoPlayer.prepare(extractorMediaSource);
    playerView.setPlayer(simpleExoPlayer);

    super.onStart();
}

@Override
protected void onStop() {
    playerView.setPlayer(null);
    simpleExoPlayer.release();
    simpleExoPlayer=null;
    super.onStop();
}

}


-2
视频播放从SD卡中使用以下代码工作。我的测试文件位于SD卡的Videos目录中。
public static final Sample[] LOCAL_VIDEOS = new Sample[] {
        new Sample("test",
            Environment.getExternalStorageDirectory()+"/Videos/test.mp4", Util.TYPE_OTHER),
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接