google / ExoPlayer

This project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media
https://developer.android.com/media/media3/exoplayer
Apache License 2.0
21.7k stars 6.02k forks source link

How to use ExoPlayer in a ListvVew or RecyclerView? #867

Open NatsumeReiko opened 8 years ago

NatsumeReiko commented 8 years ago

I want to use ExoPlayer in a RecyclerView as a part of row item. I want to make a customer view and wrap the ExoPlayer in that view.

Do you have some advice?

Thank you!

RikHeijdens commented 8 years ago

You should keep track of a reference to the ExoPlayer and try to reuse the player for every item in the ListView by just loading new media on the player.

NatsumeReiko commented 8 years ago

Thank you RikHeijdens.

Do you mean, I should make only one instance of ExoPlayer and switch the video link at properly timing?

What should I do, If I want to play two or three videos at the same time, because the height of the surfaceView is fixed and how many rows will be showed on the screen at the same depends on the height of the devices.

RikHeijdens commented 8 years ago

If you want to play multiple video's, for instance two at the same time you should instantiate 2 ExoPlayers, with 2 different SurfaceViews. And yes you switch the video as soon as the 'recycled' item moves out of the screen.

chodison commented 8 years ago

@RikHeijdens Supports two hard decoding at the same time for the device?

RikHeijdens commented 8 years ago

On my Nexus 5 I can play up to 6 video's at the same time, however you don't want to instantiate so many players because the performance will degrade pretty quickly after two instances.

chodison commented 8 years ago

BTW: In this case, not all devices are supported.

NatsumeReiko commented 8 years ago

Thank you for your advice, I decided to try to use only one ExoPlayer. And I will upload some sample code, and hope get more advice.

NatsumeReiko commented 8 years ago

Here is my source code, although it doesn't work very well, but I think it's the right way to do this. And hoping and appreciating get more advice to complete this.

In this customized RecyclerView(ExoPlayerVideoRecyclerView), I make only one SurfaceView for video play, and add to the row root view and remove it every time I need.

At this time I got these 3 problems.

  1. The ratio of the video is not correct. The height of the video surface view is fiexed to 200dp, and the width is match the device.
  2. I want to show a progress bar before real play, and how can I set the listener to get the play start event.
  3. I keep getting this alarm: E/OMXMaster: A component of name 'OMX.qcom.audio.decoder.aac' already exists, ignoring this one.

About problem 1, I tried this code to reset the ration, but it doesn't seem work.

MediaCodecVideoTrackRenderer.EventListener

    @Override
    public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
        if (videoFrame != null) {
            videoFrame.setAspectRatio(
                    height == 0 ? 1 : (width * pixelWidthHeightRatio) / height);
        }
    }

From here is the code abstracted form next sample: https://github.com/NatsumeReiko/ExoPlayerInRecyclerView

public class ExoPlayerVideoRecyclerView extends RecyclerView
        implements AudioCapabilitiesReceiver.Listener, MediaCodecVideoTrackRenderer.EventListener,
        SurfaceHolder.Callback {

    public ExoPlayerVideoRecyclerView(Context context) {
        super(context);
        initialize(context);
    }

    private void initialize(Context context) {
        mainHandler = new Handler();

        appContext = context.getApplicationContext();

        allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
        dataSource =
                new DefaultUriDataSource(appContext,
                        new DefaultBandwidthMeter(mainHandler, null),
                        Util.getUserAgent(appContext, "ExoPlayerDemo"));

        videoSurfaceView = new SurfaceView(appContext);

        videoSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT,
                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                        getResources().getDimension(R.dimen.exoplayer_video_height)
                        , getResources().getDisplayMetrics())));

        videoSurfaceView.getHolder().addCallback(this);

        CookieHandler currentHandler = CookieHandler.getDefault();
        if (currentHandler != defaultCookieManager) {
            CookieHandler.setDefault(defaultCookieManager);
        }

        audioCapabilitiesReceiver = new AudioCapabilitiesReceiver(appContext, this);
        audioCapabilitiesReceiver.register();

        player = ExoPlayer.Factory.newInstance(2);
        player.addListener(new ExoPlayer.Listener() {
            @Override
            public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
                switch (playbackState) {
                    case ExoPlayer.STATE_BUFFERING:
                        break;
                    case ExoPlayer.STATE_ENDED:
                        player.seekTo(0);
                        break;
                    case ExoPlayer.STATE_IDLE:
                        break;
                    case ExoPlayer.STATE_PREPARING:
                        break;
                    case ExoPlayer.STATE_READY:
                        break;
                    default:
                        break;
                }
            }

            @Override
            public void onPlayWhenReadyCommitted() {
            }

            @Override
            public void onPlayerError(ExoPlaybackException error) {
            }
        });

        addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {

                    play(getPlayTargetPosition());
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
            }
        });
    }

    private void preparePlayer(int position) {

        Uri uri = Uri.parse(videoInfoList.get(position).videoUrl);

        // Build the sample source
        sampleSource =
                new ExtractorSampleSource(uri, dataSource, allocator, 10 * BUFFER_SEGMENT_SIZE);

        // Build the track renderers
        videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,
                MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, -1, mainHandler, this, -1);
        audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);

        // Build the ExoPlayer and start playback
        player.prepare(videoRenderer, audioRenderer);

        playVideo();
    }

    //method to really do the play
    private void playVideo() {
        if (surfaceViewViable) {
            player.sendMessage(videoRenderer,
                    MediaCodecVideoTrackRenderer.MSG_SET_SURFACE,
                    videoSurfaceView.getHolder().getSurface());
            player.setPlayWhenReady(true);
        }
    }

        private void releasePlayer() {
        if (player != null) {
            player.release();
            player = null;
        }
    }

    private void removeVideoView(SurfaceView videoView) {

        ViewGroup parent = (ViewGroup) videoView.getParent();

        if (parent == null) {
            return;
        }

        int index = parent.indexOfChild(videoView);
        if (index >= 0) {
            parent.removeViewAt(index);
        }

    }

    private void play(int position) {
        if (position == playPosition) {
            return;
        }

        playPosition = position;
        removeVideoView(videoSurfaceView);

        // get target View position in RecyclerView
        int at = position - ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition();

        View child = getChildAt(at);
        if (child == null) {
            return;
        }

        ExoPlayerVideoRecyclerViewAdapter.VideoViewHolder holder
                = (ExoPlayerVideoRecyclerViewAdapter.VideoViewHolder) child.getTag();
        if (holder == null) {
            playPosition = DEFAULT_PLAY_POSITION;
            return;
        }
        holder.videoContainer.addView(videoSurfaceView);
        videoFrame = holder.videoContainer;

        preparePlayer(playPosition);
    }
}

public class ExoPlayerVideoRecyclerViewAdapter
        extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

        public ExoPlayerVideoRecyclerViewAdapter(Context appContext, List<VideoInfo> videoInfoList) {
        this.videoInfoList = videoInfoList;
        inflater = LayoutInflater.from(appContext.getApplicationContext());

    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new VideoViewHolder(inflater
                .inflate(R.layout.exoplayer_recycler_view_row, parent, false));

    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof VideoViewHolder) {
            setVideoViewHolder((VideoViewHolder) holder);
        }
    }

    private void setVideoViewHolder(VideoViewHolder holder) {
        holder.parent.setTag(holder);
    }

    @Override
    public int getItemCount() {
        return videoInfoList.size();
    }

    public static class VideoViewHolder extends RecyclerView.ViewHolder {

        AspectRatioFrameLayout videoContainer;
        View parent;

        public VideoViewHolder(View v) {
            super(v);
            parent = v;
            videoContainer = (AspectRatioFrameLayout) v.findViewById(R.id.video_frame);
        }
    }

    public void onRelease() {
        if (videoInfoList != null) {
            videoInfoList.clear();
            videoInfoList = null;
        }
    }

}
qqli007 commented 8 years ago

@NatsumeReiko ,how to goto fullscreen when click the item of the listview? Do you have any idea?

jayshah123 commented 8 years ago

I have a use case (for multiple exoplayers) where there can be TextureViews in each page of viewpager, minimum 3 exoplayers would be allocated, one per textureview(in each page). Although I play only a single exoplayer at a time(the one belonging to textureview of focused page) and rest are in paused state, how does bandwidth/performance etc. get affected ? (Assume I am using simple MP4 over http - no adaptive streaming) What would be best practice in such cases?

xingstarx commented 7 years ago

@jayshah123 I think you could see this repo https://github.com/xingstarx/InkeVerticalViewPagerLive

I hope that can help you

mufumbo commented 7 years ago

@NatsumeReiko that's an interesting solution, but if you move the SurfaceView to another container, you would lose the paused state thumbnail if you need to resume the video while the user scroll. Do you think reusing surfaceView is much more performant than just reusing the player?

escamoteur commented 7 years ago

I'm facing almost the same challenge.

So I would like to know if it is feasable to use multiple SurfaceViews in a ListView and just switch the Player between them or is it better to reuse the same surface when I need it?

Thanks Thomas

artworkad commented 7 years ago

Check out https://github.com/eneim/Toro

Sandeeppal1083 commented 7 years ago

NatsumReiko or anyone , please help me in playing Hls Video inside recyclerview , i want to play Hls videos inside recyclerview, Please help me with code, i would be thankful for you sooo much.

gregkorossy commented 7 years ago

I am facing the same problem with RecyclerView using ExoPlayer 2. I have multiple items representing either an audio or a video player and there might be an unknown number of items (probably more than 1) visible at the same time. I implemented the player reuse by delegating it to a service so it can keep playing in the background too, which is good. My main problem is that the SimpleExoPlayerView has a lot of restrictions based on whether the player is set, such as it won't display controls nor album artwork if the player is null, and the class is final so I cannot just override what I want... I have the video thumbnails separately available, so it shouldn't be a problem, but now I have to use a separate image view item to show them on top of the player view. Also, I have to display a separate play button on top of these in order to set the player to the current player view and start playing the media.

Another problem I noticed with the player instance reuse is that if 2 items are visible at the same time, item A is playing, and I start playing item B, then item A will be "reset" to a default state with the total time set to 00:00 and the current "thumbnail" image (video) removed along with the controllers, which seems like a really bad UX.

My question is: what are the performance / networking / bandwidth effects of using more than 1 players, but playing only one at the same time (it would use some kind of an "obtain" mechanism by creating new player if there isn't an available one)? So if the user starts playing item B by pressing the play button, item A would pause. I'm afraid that pausing the players would not be enough because they would still keep buffering / holding data, but stopping them resets the current state, which means back to square one.

eneim commented 7 years ago

Thank @ArtworkAD for mentioning my library :D. FYI @Gericop I have been struggling a long time with the same idea with you. I finally end up with the belief that ExoPlayer instance will not consume your CPU and much of your network as long as you don't ask it to (= calling player.setPlayWhenReady(true)). It may start fetching some meta data at preparing, but it should be fine with just that.

Having a Singleton Player will be scary (good for performance though). You can learn from how Youtube Player API doing so (closed source, yep, but enough study may turn to something I guess).

mpainenz commented 6 years ago

Your Toro library @eneim suffers from thread locking and slow performance when scrolling the recycler. Particularly when you fling the RecyclerView.

In my own testing, I have found that using a single player instance is much better. It removed all my issues with thread locking. I guess the players are contending for Codec access, or some other issue is occuring. This happens even if only one player is playing at a time.

The best approach I've found is to:

  1. Generate your own thumbnails. In my case, I am downloading the MP4's I want to play to disk, and using the ThumbnailUtils.createVideoThumbnail function to store the Thumbnail to disk, and display an ImageView in the RecyclerView.

  2. In each ViewHolder, store a separate MediaSource object, and create it during Bind, and release it during the Recycle event.

  3. In each ViewHolder layout, use a separate SimpleExoPlayerView object with no SimpleExoPlayer attached during Bind Time.

  4. Hold a single instance of a SimpleExoPlayer in the Adapter, or somewhere else in your project.

  5. Listen to the RecyclerView's LayoutManager OnScroll event, and in each scroll event, work out which item is in focus and needs to be in a play state. Prepare the player, attach the SimpleExoPlayer to the ViewHolders SimpleExoPlayerView and hide the Thumbnail overlay.

This method is working very well for me, I get a very fast experience.

eneim commented 6 years ago

You are right about the issue of having multi ExoPlayer instance in the library. Lately I also investigate in the case of using Single/Limited ExoPlayer instances. Your approach gonna be so much helpful. (It turns out that, to make it highly abstraction and easy to integrate, many works need to be done).

mpainenz commented 6 years ago

I have also found that you can further increase performance by using a TextureView instead of SimpleExoPlayerView, and only create one TextureView object instead of one per viewholder.

In your Adapter or Activity, store a single TextureView object, and pass it to the ViewHolder that is playing at runtime. Reuse the same TextureView item for each viewholder that is playing.

I cannot believe how much smoother my application runs this way.

mpainenz commented 6 years ago

Just an update to TextureView re-use in RecyclerView, it seems to be quite buggy when removing a TextureView from it's parent and moving it to a new View.

If you want to get that working, the better approach is to hold the TextureView inside the Activity view, and overlay the recyclerview on top. It's a difficult approach, but if you move the TextureView between parents, it seems to end up displaying a black screen on resize or program resume.

It's actually still quite fast to have a TextureView for each Viewholder, so that seems to be a simpler option.

dishantkawatra commented 6 years ago

Hi, when i switch the exoplayer from recycler view to a dialog with the help of getplayer() and setplayer() method then frames are hang for some sec and sometimes audio is audible but frames are not see please tell me how to resolve this issue with toro

https://github.com/eneim/toro/issues/286

sandeepyohans commented 6 years ago

It's this very old issue which is still open. Is there a proper solution for using ExoPlayer is ListView or RecyclerView? A working sample would be great help for a beginner like me. @ojw28 @andrewlewis

dishantkawatra commented 6 years ago

Please download BeautyKingdom application then know how to exoplayer is playing if you interested then reply me I will give you code

On Mon 18 Jun, 2018, 2:03 PM Sandeep Yohans, notifications@github.com wrote:

It's this very old issue which is still open. Is there a proper solution for using ExoPlayer is ListView or RecyclerView? A working sample would be great help for a beginner like me. @ojw28 https://github.com/ojw28 @andrewlewis https://github.com/andrewlewis

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/google/ExoPlayer/issues/867#issuecomment-397980844, or mute the thread https://github.com/notifications/unsubscribe-auth/Abbnyos4nyfJpce5DVbuw8Le23OCZ23Kks5t92XcgaJpZM4GPU6m .

sandeepyohans commented 6 years ago

@dishantkawatra Sure, will do that.

sandeepyohans commented 6 years ago

@dishantkawatra I checked the layout, looks nice. Seems you are displaying a list of thumbnails and on onClick event playing the video in new Activity. I had the thought of doing the same. screenshot_1529923322

dishantkawatra commented 6 years ago

Hi,

ok i will update you with code how to play a video in next activity with exoplayer.

Thanks Dishant Kawatra Android Developer

On Mon, Jun 25, 2018 at 4:13 PM Sandeep Yohans notifications@github.com wrote:

@dishantkawatra https://github.com/dishantkawatra I checked the layout, looks nice. Seems you are displaying a list of thumbnails and on onClick event playing the video in new Activity. I had the thought of doing the same. [image: screenshot_1529923322] https://user-images.githubusercontent.com/3971485/41845881-a6552b20-7892-11e8-8cfc-a408fc5fe119.png

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/ExoPlayer/issues/867#issuecomment-399909454, or mute the thread https://github.com/notifications/unsubscribe-auth/Abbnyu00QOV4NKgabMA-4tqNVeIhahN-ks5uAL7mgaJpZM4GPU6m .

sandeepyohans commented 6 years ago

Thanks @dishantkawatra, your help is much appreciated!

herotha-sompom commented 6 years ago

@dishantkawatra could you give that source code to me?

dishantkawatra commented 6 years ago

Sure, I give you code Tommorow

On Tue 24 Jul, 2018, 4:28 PM herotha-sompom, notifications@github.com wrote:

@dishantkawatra https://github.com/dishantkawatra could you give that source code to me?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/ExoPlayer/issues/867#issuecomment-407366038, or mute the thread https://github.com/notifications/unsubscribe-auth/AbbnyhlnjIwGUcizHO6vCkMJRwKyJzLYks5uJv3GgaJpZM4GPU6m .

herotha-sompom commented 6 years ago

@dishantkawatra thanks for your help

sandeepyohans commented 6 years ago

@dishantkawatra I am still waiting for your reply.

herotha-sompom commented 6 years ago

@dishantkawatra do you send the source code to me yet?

dishantkawatra commented 6 years ago

Implement this dependecy

compile 'com.google.android.exoplayer:exoplayer-core:r2.4.3'

DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter); TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); player = ExoPlayerFactory.newSimpleInstance(this, trackSelector); playerView.setPlayer(player); DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "beautyKingdom"), bandwidthMeter); ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory(); MediaSource videoSource = new ExtractorMediaSource("Your url here ", dataSourceFactory, extractorsFactory, null, null); LoopingMediaSource loopingSource = new LoopingMediaSource(videoSource, 1); player.prepare(loopingSource); player.setPlayWhenReady(true);

player.addListener(new ExoPlayer.EventListener() { @Override public void onTimelineChanged(Timeline timeline, Object manifest) {

}

@Override
public void onTracksChanged(TrackGroupArray trackGroups,

TrackSelectionArray trackSelections) {

}

@Override
public void onLoadingChanged(boolean isLoading) {

}

@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState)
{
    switch (playbackState)
    {
        case ExoPlayer.STATE_BUFFERING:
            progressBar.setVisibility(View.VISIBLE);

            break;
        case ExoPlayer.STATE_ENDED:
            progressBar.setVisibility(View.VISIBLE);

            if (ivPlayPause != null) {
                ivPlayPause.setVisibility(View.VISIBLE);
            }
            if (player != null) {
                player.seekTo(0);

            }

            player.setPlayWhenReady(false);
            ivPlayPause.setImageResource(R.drawable.video_play);
            isPlay = false;
            break;
        case ExoPlayer.STATE_IDLE:

            break;
        case ExoPlayer.STATE_READY:
            ivThumbnail.setVisibility(View.GONE);
            progressBar.setVisibility(View.GONE);
            handler.postDelayed(runnable, 1000);
            break;
        default:
            break;
    }
}

@Override
public void onPlayerError(ExoPlaybackException error) {

}

@Override
public void onPositionDiscontinuity() {

}

@Override
public void onPlaybackParametersChanged(PlaybackParameters

playbackParameters) {

}

});

On Thu, Jul 26, 2018 at 6:37 AM herotha-sompom notifications@github.com wrote:

@dishantkawatra https://github.com/dishantkawatra do you send the source code yet?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/ExoPlayer/issues/867#issuecomment-407943700, or mute the thread https://github.com/notifications/unsubscribe-auth/AbbnysaVELGJUuS7DATJtMYG2t8ObbPMks5uKRZlgaJpZM4GPU6m .

dishantkawatra commented 6 years ago

<com.google.android.exoplayer2.ui.SimpleExoPlayerView android:id="@+id/player" android:layout_width="match_parent" android:layout_height="match_parent" app:resize_mode="fit" app:surface_type="texture_view" app:use_controller="false"/>

On Tue, Jul 31, 2018 at 7:25 PM Dishant Kawatra dishu101@gmail.com wrote:

Implement this dependecy

compile 'com.google.android.exoplayer:exoplayer-core:r2.4.3'

DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter); TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); player = ExoPlayerFactory.newSimpleInstance(this, trackSelector); playerView.setPlayer(player); DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "beautyKingdom"), bandwidthMeter); ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory(); MediaSource videoSource = new ExtractorMediaSource("Your url here ", dataSourceFactory, extractorsFactory, null, null); LoopingMediaSource loopingSource = new LoopingMediaSource(videoSource, 1); player.prepare(loopingSource); player.setPlayWhenReady(true);

player.addListener(new ExoPlayer.EventListener() { @Override public void onTimelineChanged(Timeline timeline, Object manifest) {

}

@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {

}

@Override
public void onLoadingChanged(boolean isLoading) {

}

@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState)
{
    switch (playbackState)
    {
        case ExoPlayer.STATE_BUFFERING:
            progressBar.setVisibility(View.VISIBLE);

            break;
        case ExoPlayer.STATE_ENDED:
            progressBar.setVisibility(View.VISIBLE);

            if (ivPlayPause != null) {
                ivPlayPause.setVisibility(View.VISIBLE);
            }
            if (player != null) {
                player.seekTo(0);

            }

            player.setPlayWhenReady(false);
            ivPlayPause.setImageResource(R.drawable.video_play);
            isPlay = false;
            break;
        case ExoPlayer.STATE_IDLE:

            break;
        case ExoPlayer.STATE_READY:
            ivThumbnail.setVisibility(View.GONE);
            progressBar.setVisibility(View.GONE);
            handler.postDelayed(runnable, 1000);
            break;
        default:
            break;
    }
}

@Override
public void onPlayerError(ExoPlaybackException error) {

}

@Override
public void onPositionDiscontinuity() {

}

@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {

}

});

On Thu, Jul 26, 2018 at 6:37 AM herotha-sompom notifications@github.com wrote:

@dishantkawatra https://github.com/dishantkawatra do you send the source code yet?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/ExoPlayer/issues/867#issuecomment-407943700, or mute the thread https://github.com/notifications/unsubscribe-auth/AbbnysaVELGJUuS7DATJtMYG2t8ObbPMks5uKRZlgaJpZM4GPU6m .

adapana commented 6 years ago

@mpainenz

Your Toro library @eneim suffers from thread locking and slow performance when scrolling the recycler. Particularly when you fling the RecyclerView.

In my own testing, I have found that using a single player instance is much better. It removed all my issues with thread locking. I guess the players are contending for Codec access, or some other issue is occuring. This happens even if only one player is playing at a time.

The best approach I've found is to:

  1. Generate your own thumbnails. In my case, I am downloading the MP4's I want to play to disk, and using the ThumbnailUtils.createVideoThumbnail function to store the Thumbnail to disk, and display an ImageView in the RecyclerView.
  2. In each ViewHolder, store a separate MediaSource object, and create it during Bind, and release it during the Recycle event.
  3. In each ViewHolder layout, use a separate SimpleExoPlayerView object with no SimpleExoPlayer attached during Bind Time.
  4. Hold a single instance of a SimpleExoPlayer in the Adapter, or somewhere else in your project.
  5. Listen to the RecyclerView's LayoutManager OnScroll event, and in each scroll event, work out which item is in focus and needs to be in a play state. Prepare the player, attach the SimpleExoPlayer to the ViewHolders SimpleExoPlayerView and hide the Thumbnail overlay.

This method is working very well for me, I get a very fast experience.

Can you provide code for this? I tried but could not manage to make it fully working.

sanketmthakare commented 6 years ago

@mpainenz Can you provide code for this? I tried but could not manage to make it fully working.

sanketmthakare commented 6 years ago

You should keep track of a reference to the ExoPlayer and try to reuse the player for every item in the ListView by just loading new media on the player.

How can i achieve this? Whenever i create instance in adapter constructor and reuse it, recycle view row became blank.

droidwave commented 5 years ago

ExoPlayer in RecyclerView, First we have to write a custom component for ExoPlayer. Get a sample app and source code here (Complete Solution )
https://androidwave.com/exoplayer-in-recyclerview-in-android/

mpainenz commented 5 years ago

I've improved apon my initial solutions to this, and now just use a single PlayerView but move it around in the view hierarchy. Much simpler.

sanketmthakare commented 5 years ago

Can you please share the code? Thank you

On Thu 13 Dec, 2018, 3:57 AM Mark Paine <notifications@github.com wrote:

I've improved apon my initial solutions to this, and now just use a single PlayerView but move it around in the view hierarchy. Much simpler.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/google/ExoPlayer/issues/867#issuecomment-446767782, or mute the thread https://github.com/notifications/unsubscribe-auth/AQV74r6X8fGisYkwApPpzomdBb0uxfO2ks5u4YK8gaJpZM4GPU6m .

CatalystNZ commented 5 years ago

Hi @sanketmthakare, if you post a specific question on stackoverflow with a bounty, I can provide code for you. You would need to be quite specific about how you want your layout displayed, and the behavior you want. It's recommended not to play video while scrolling, and not to play video while the Player is being resized.

Try to provide as much information as possible if you, or anyone else, needs help.

sanketmthakare commented 5 years ago

hello Mark, i have run your code from this below link: https://androidwave.com/exoplayer-in-recyclerview-in-android/

It was working fine and i need same functionality. But, i found one issue in the code. Whenever i scroll up down, recycle view became blank. i will post a question on stack overflow and will share the link. But, i don't understand why black screen came whenever i scroll. i have notice you load cover page with glide. But it seems not working properly.

Thank you waiting for your reply

On Thu, Dec 20, 2018 at 4:14 AM CatalystNZ notifications@github.com wrote:

Hi @sanketmthakare https://github.com/sanketmthakare, if you post a specific question on stackoverflow with a bounty, I can provide code for you. You would need to be quite specific about how you want your layout displayed, and the behavior you want. It's recommended not to play video while scrolling, and not to play video while the Player is being resized.

Try to provide as much information as possible if you, or anyone else, needs help.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/ExoPlayer/issues/867#issuecomment-448770353, or mute the thread https://github.com/notifications/unsubscribe-auth/AQV74l96yEuKd-TXD44FgV2wXXmxwwpsks5u6sEvgaJpZM4GPU6m .

dishantkawatra commented 5 years ago

Hello sanket

Please use different toro helper it solves your problem Thanks Dishant Kawatra

CatalystNZ commented 5 years ago

Be sure to try using TextureView instead of Surface View. Often a black flash on the screen occurs because of the underlying surfaceview.

<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/player_view" app:surface_type="texture_view" android:layout_width="match_parent" android:layout_height="match_parent" />

xesun commented 5 years ago

Sure, I give you code Tommorow On Tue 24 Jul, 2018, 4:28 PM herotha-sompom, @.***> wrote: @dishantkawatra https://github.com/dishantkawatra could you give that source code to me? — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub <#867 (comment)>, or mute the thread https://github.com/notifications/unsubscribe-auth/AbbnyhlnjIwGUcizHO6vCkMJRwKyJzLYks5uJv3GgaJpZM4GPU6m .

@dishantkawatra could you give that source code to me?

eneim commented 5 years ago

For those who are interested in this topic, this is what I archive lately: reddit article. If you are curious about it, a feature request/issue or just a normal comment is welcome.

sahujaunpuri commented 5 years ago

ExoPlayer in RecyclerView, First we have to write a custom component for ExoPlayer. Get a sample app and source code here (Complete Solution ) https://androidwave.com/exoplayer-in-recyclerview-in-android/

Yes this code working perfectly. I have need get data from firebase. Anyone please guide me

pratikbutani commented 5 years ago

Your Toro library @eneim suffers from thread locking and slow performance when scrolling the recycler. Particularly when you fling the RecyclerView.

In my own testing, I have found that using a single player instance is much better. It removed all my issues with thread locking. I guess the players are contending for Codec access, or some other issue is occuring. This happens even if only one player is playing at a time.

The best approach I've found is to:

  1. Generate your own thumbnails. In my case, I am downloading the MP4's I want to play to disk, and using the ThumbnailUtils.createVideoThumbnail function to store the Thumbnail to disk, and display an ImageView in the RecyclerView.
  2. In each ViewHolder, store a separate MediaSource object, and create it during Bind, and release it during the Recycle event.
  3. In each ViewHolder layout, use a separate SimpleExoPlayerView object with no SimpleExoPlayer attached during Bind Time.
  4. Hold a single instance of a SimpleExoPlayer in the Adapter, or somewhere else in your project.
  5. Listen to the RecyclerView's LayoutManager OnScroll event, and in each scroll event, work out which item is in focus and needs to be in a play state. Prepare the player, attach the SimpleExoPlayer to the ViewHolders SimpleExoPlayerView and hide the Thumbnail overlay.

This method is working very well for me, I get a very fast experience.

It will be more good if you provide your adapter class.

pratikbutani commented 5 years ago

ExoPlayer in RecyclerView, First we have to write a custom component for ExoPlayer. Get a sample app and source code here (Complete Solution ) https://androidwave.com/exoplayer-in-recyclerview-in-android/

Yes this code working perfectly. I have need get data from firebase. Anyone please guide me

Did you get any solution? I am also stuck with Firestore Database. I wanted to load videos from Firestore Database.