{"id":13848169,"url":"https://github.com/danylovolokh/VideoPlayerManager","last_synced_at":"2025-07-12T12:30:43.757Z","repository":{"id":34851709,"uuid":"38846351","full_name":"danylovolokh/VideoPlayerManager","owner":"danylovolokh","description":"This is a project designed to help controlling Android MediaPlayer class. It makes it easier to use MediaPlayer ListView and RecyclerView. Also it tracks the most visible item in scrolling list. When new item in the list become the most visible, this library gives an API to track it.","archived":false,"fork":false,"pushed_at":"2020-05-02T12:54:48.000Z","size":236448,"stargazers_count":3151,"open_issues_count":93,"forks_count":747,"subscribers_count":116,"default_branch":"master","last_synced_at":"2024-11-21T03:52:13.323Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"xiachufang/Flask-Statsd","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danylovolokh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-09T21:32:15.000Z","updated_at":"2024-11-15T10:40:00.000Z","dependencies_parsed_at":"2022-08-08T02:01:20.614Z","dependency_job_id":null,"html_url":"https://github.com/danylovolokh/VideoPlayerManager","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danylovolokh%2FVideoPlayerManager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danylovolokh%2FVideoPlayerManager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danylovolokh%2FVideoPlayerManager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danylovolokh%2FVideoPlayerManager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danylovolokh","download_url":"https://codeload.github.com/danylovolokh/VideoPlayerManager/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225820303,"owners_count":17529138,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T19:00:44.303Z","updated_at":"2024-11-21T23:31:07.773Z","avatar_url":"https://github.com/danylovolokh.png","language":"Java","readme":"# VideoPlayerManager\nThis is a project designed to help controlling Android MediaPlayer class. It makes it easier to use MediaPlayer ListView and RecyclerView.\nAlso it tracks the most visible item in scrolling list. When new item in the list become the most visible, this library gives and API to track it.\n\nIt consists from two libraries:\n\n1. Video-Player-Manager - it gives the ability to invoke MediaPlayer methods in a background thread. It has utilities to have only one playback when multiple media files are in the list.\nBefore new playback starts, it stops the old playback and releases all the resources.\n\n2. List-Visibility-Utils - it's a library that tracks the most visible item in the list and notifies when it changes.\nNOTE: there should be the most visible item.\nIf there will be 3 or more items with the same visibility percent the result might be unpredictable.\nRecommendation is to have few views visible on the screen. View that are big enough so that only one view is the most visible, look at the demo below.\n\nThese two libraries combined are the tool to get a Video Playback in the scrolling list: ListView, RecyclerView.\n\n# Details of implementation\n\n[![Medium](https://img.shields.io/badge/Meduim-Implementing%20video%20playback%20in%20a%20scrolled%20list%20(ListView%20%26%20RecyclerView)-blue.svg)](https://medium.com/@v.danylo/implementing-video-playback-in-a-scrolled-list-listview-recyclerview-d04bc2148429)\n\n[![Android_weekly](https://img.shields.io/badge/Android%20Weekly-%09Implementing%20video%20playback%20in%20a%20scrolled%20list-green.svg)](http://androidweekly.net/issues/issue-189)\n\n[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-VideoPlayerManager-green.svg?style=true)](https://android-arsenal.com/details/1/3073)\n\n\n# Problems with video list\n1. We cannot use usual VideoView in the list. VideoView extends SurfaceView, and SurfaceView doesn't have UI synchronization buffers. All this will lead us to the situation where video that is playing is trying to catch up the list when you scroll it. Synchronization buffers are present in TextureView but there is no VideoView that is based on TextureView in Android SDK version 15. So we need a view that extends TextureView and works with Android MediaPlayer.\n\n2. Almost all methods (prepare, start, stop etc...) from MediaPlayer are basically calling native methods that work with hardware. Hardware can be tricky and if will do any work longer than 16ms (And it sure will) then we will see a lagging list. That's why need to call them from background thread.\n\n\n# Usage\nAdd this snippet to your project build.gradle file:\n```\nbuildscript {\n    repositories {\n        jcenter()\n    }\n}\n```\n\n# Usage of Video-Player-Manager\n```\ndependencies {\n    compile 'com.github.danylovolokh:video-player-manager:0.2.0'\n}\n```\nPut multiple VideoPlayerViews into your xml file.\nIn most cases you also need a images above that will be shown when playback is stopped.\n```\n\u003cLinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\u003e\n        \u003c!-- Top Player--\u003e\n        \u003ccom.volokh.danylo.video_player_manager.ui.VideoPlayerView\n            android:id=\"@+id/video_player_1\"\n            android:layout_height=\"0dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_weight=\"1\"\n            /\u003e\n\n        \u003ccom.volokh.danylo.video_player_manager.ui.VideoPlayerView\n            android:id=\"@+id/video_player_2\"\n            android:layout_height=\"0dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_weight=\"1\"\n            /\u003e\n    \u003c/LinearLayout\u003e\n\n    \u003cLinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\u003e\n        \u003c!-- Top Player--\u003e\n        \u003cImageView\n            android:id=\"@+id/video_cover_1\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:scaleType=\"centerCrop\"\n            android:layout_weight=\"1\"/\u003e\n\n        \u003cImageView\n            android:id=\"@+id/video_cover_2\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:scaleType=\"centerCrop\"\n            android:layout_weight=\"1\"/\u003e\n    \u003c/LinearLayout\u003e\n```\n\nNow you can use SingleVideoPlayerManager to playback only a single video at once:\n```\n//... some code\nprivate VideoPlayerManager\u003cMetaData\u003e mVideoPlayerManager = new SingleVideoPlayerManager(new PlayerItemChangeListener() {\n    @Override\n    public void onPlayerItemChanged(MetaData metaData) {\n\n    }\n});\n//... some code\n\nmVideoPlayer_1 = (VideoPlayerView)root.findViewById(R.id.video_player_1);\nmVideoPlayer_1.addMediaPlayerListener(new SimpleMainThreadMediaPlayerListener(){\n   @Override\n   public void onVideoPreparedMainThread() {\n    // We hide the cover when video is prepared. Playback is about to start\n    mVideoCover.setVisibility(View.INVISIBLE);\n   }\n\n   @Override\n   public void onVideoStoppedMainThread() {\n   // We show the cover when video is stopped\n    mVideoCover.setVisibility(View.VISIBLE);\n   }\n\n   @Override\n   public void onVideoCompletionMainThread() {\n       // We show the cover when video is completed\n       mVideoCover.setVisibility(View.VISIBLE);\n   }\n});\nmVideoCover = (ImageView)root.findViewById(R.id.video_cover_1);\nmVideoCover.setOnClickListener(this);\n\nmVideoPlayer_2 = (VideoPlayerView)root.findViewById(R.id.video_player_2);\nmVideoPlayer_2.addMediaPlayerListener(new SimpleMainThreadMediaPlayerListener(){\n   @Override\n   public void onVideoPreparedMainThread() {\n       // We hide the cover when video is prepared. Playback is about to start\n        mVideoCover2.setVisibility(View.INVISIBLE);\n   }\n\n   @Override\n   public void onVideoStoppedMainThread() {\n        // We show the cover when video is stopped\n      mVideoCover2.setVisibility(View.VISIBLE);\n   }\n\n   @Override\n   public void onVideoCompletionMainThread() {\n      // We show the cover when video is completed\n      mVideoCover2.setVisibility(View.VISIBLE);\n   }\n});\nmVideoCover2 = (ImageView)root.findViewById(R.id.video_cover_2);\nmVideoCover2.setOnClickListener(this);\n\n// some code\n@Override\npublic void onClick(View v) {\n        switch (v.getId()){\n            case R.id.video_cover_1:\n                mVideoPlayerManager.playNewVideo(null, mVideoPlayer_1, \"http:\\\\url_to_you_video_1_source\");\n                break;\n            case R.id.video_cover_2:\n                mVideoPlayerManager.playNewVideo(null, mVideoPlayer_2, \"http:\\\\url_to_you_video_2_source\");\n                break;\n        }\n}\n```\n# The Demo of Video-Player-Manager:\n![video_player_manager_demo](https://cloud.githubusercontent.com/assets/2686355/12434458/6f677ae4-bf0f-11e5-8fa9-b3d3b8a30165.gif)\n\n# Usage of List-Visibility-Utils\n```\ndependencies {\n    compile 'com.github.danylovolokh:list-visibility-utils:0.2.0'\n}\n```\nThe models of your adapter need to implement ListItem\n\n```\npublic interface ListItem {\n    int getVisibilityPercents(View view);\n    void setActive(View newActiveView, int newActiveViewPosition);\n    void deactivate(View currentView, int position);\n}\n```\nThis messes up a bit with separating model from the logic.\nHere you need to handle the login in the model.\n\nThe ListItemsVisibilityCalculator will call according methods to:\n\n1. Get view visibility\n \n2. Set this item to active\n\n3. Deactivate the item\n\n```\n// some code...\nprivate final ListItemsVisibilityCalculator mListItemVisibilityCalculator =\n            new SingleListViewItemActiveCalculator(new DefaultSingleItemCalculatorCallback(), mList);\n// some code...\n\nmRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {\n\n            @Override\n            public void onScrollStateChanged(RecyclerView recyclerView, int scrollState) {\n                mScrollState = scrollState;\n                if(scrollState == RecyclerView.SCROLL_STATE_IDLE \u0026\u0026 !mList.isEmpty()){\n\n                    mListItemVisibilityCalculator.onScrollStateIdle(\n                            mItemsPositionGetter,\n                            mLayoutManager.findFirstVisibleItemPosition(),\n                            mLayoutManager.findLastVisibleItemPosition());\n                }\n            }\n\n            @Override\n            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {\n                if(!mList.isEmpty()){\n                    mListItemVisibilityCalculator.onScroll(\n                            mItemsPositionGetter,\n                            mLayoutManager.findFirstVisibleItemPosition(),\n                            mLayoutManager.findLastVisibleItemPosition() - mLayoutManager.findFirstVisibleItemPosition() + 1,\n                            mScrollState);\n                }\n            }\n        });\n\nmItemsPositionGetter = new RecyclerViewItemPositionGetter(mLayoutManager, mRecyclerView);\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if(!mList.isEmpty()){\n            // need to call this method from list view handler in order to have filled list\n\n            mRecyclerView.post(new Runnable() {\n                @Override\n                public void run() {\n\n                    mListItemVisibilityCalculator.onScrollStateIdle(\n                            mItemsPositionGetter,\n                            mLayoutManager.findFirstVisibleItemPosition(),\n                            mLayoutManager.findLastVisibleItemPosition());\n\n                }\n            });\n        }\n    }\n\t\n```\n# The Demo of List-Visibility-Utils:\n![visibility_utils_demo](https://cloud.githubusercontent.com/assets/2686355/12434552/1b33be00-bf10-11e5-9bf1-fd2276058a58.gif)\n\n# Usage in scrolling list (ListView, RecyclerView)\n\nAdd this snippet to your module build.gradle file:\n\n```\ndependencies {\n    compile 'com.github.danylovolokh:video-player-manager:0.2.0'\n    compile 'com.github.danylovolokh:list-visibility-utils:0.2.0'\n}\n```\n\nHere is the relevant code combanation of two libraries fro implementing Video Playback in scrolling list.\n```\n// Code of your acitivty\n    /**\n     * Only the one (most visible) view should be active (and playing).\n     * To calculate visibility of views we use {@link SingleListViewItemActiveCalculator}\n     */\n    private final ListItemsVisibilityCalculator mVideoVisibilityCalculator =\n            new SingleListViewItemActiveCalculator(new DefaultSingleItemCalculatorCallback(), mList);\n\n    /**\n     * ItemsPositionGetter is used by {@link ListItemsVisibilityCalculator} for getting information about\n     * items position in the RecyclerView and LayoutManager\n     */\n    private ItemsPositionGetter mItemsPositionGetter;\n\n    /**\n     * Here we use {@link SingleVideoPlayerManager}, which means that only one video playback is possible.\n     */\n    private final VideoPlayerManager\u003cMetaData\u003e mVideoPlayerManager = new SingleVideoPlayerManager(new PlayerItemChangeListener() {\n        @Override\n        public void onPlayerItemChanged(MetaData metaData) {\n\n        }\n    });\n\n    private int mScrollState = AbsListView.OnScrollListener.SCROLL_STATE_IDLE;\n    \n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n\n\t// fill the list of items with an items\n\n\t// some initialization code here\n\n        VideoRecyclerViewAdapter videoRecyclerViewAdapter = new VideoRecyclerViewAdapter(mVideoPlayerManager, getActivity(), mList);\n\n        mRecyclerView.setAdapter(videoRecyclerViewAdapter);\n        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {\n\n            @Override\n            public void onScrollStateChanged(RecyclerView recyclerView, int scrollState) {\n                mScrollState = scrollState;\n                if(scrollState == RecyclerView.SCROLL_STATE_IDLE \u0026\u0026 !mList.isEmpty()){\n\n                    mVideoVisibilityCalculator.onScrollStateIdle(\n                            mItemsPositionGetter,\n                            mLayoutManager.findFirstVisibleItemPosition(),\n                            mLayoutManager.findLastVisibleItemPosition());\n                }\n            }\n\n            @Override\n            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {\n                if(!mList.isEmpty()){\n                    mVideoVisibilityCalculator.onScroll(\n                            mItemsPositionGetter,\n                            mLayoutManager.findFirstVisibleItemPosition(),\n                            mLayoutManager.findLastVisibleItemPosition() - mLayoutManager.findFirstVisibleItemPosition() + 1,\n                            mScrollState);\n                }\n            }\n        });\n        mItemsPositionGetter = new RecyclerViewItemPositionGetter(mLayoutManager, mRecyclerView);\n\n        return rootView;\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if(!mList.isEmpty()){\n            // need to call this method from list view handler in order to have filled list\n\n            mRecyclerView.post(new Runnable() {\n                @Override\n                public void run() {\n\n                    mVideoVisibilityCalculator.onScrollStateIdle(\n                            mItemsPositionGetter,\n                            mLayoutManager.findFirstVisibleItemPosition(),\n                            mLayoutManager.findLastVisibleItemPosition());\n\n                }\n            });\n        }\n    }\n\n    @Override\n    public void onStop() {\n        super.onStop();\n        // we have to stop any playback in onStop\n        mVideoPlayerManager.resetMediaPlayer();\n    }    \n```\nWhen visibility utils calls method \"setActive\" on your implementation of ListItem you have to call \"playNewVideo\".\nPlease find the working code on this Demo application.\n```\n    /**\n     * When this item becomes active we start playback on the video in this item\n     */\n    @Override\n    public void setActive(View newActiveView, int newActiveViewPosition) {\n        VideoViewHolder viewHolder = (VideoViewHolder) newActiveView.getTag();\n        playNewVideo(new CurrentItemMetaData(newActiveViewPosition, newActiveView), viewHolder.mPlayer, mVideoPlayerManager);\n    }\n    \n    @Override\n    public void playNewVideo(MetaData currentItemMetaData, VideoPlayerView player, VideoPlayerManager\u003cMetaData\u003e videoPlayerManager) {\n        videoPlayerManager.playNewVideo(currentItemMetaData, player, mDirectUrl);\n    }\n```\n\n# Demo of usage in scrolling list (ListView, RecyclerView)\n![recycler_view_demo](https://cloud.githubusercontent.com/assets/2686355/12434342/d4d53570-bf0e-11e5-9c4c-d7d701ca9d5f.gif) ![list_view_demo](https://cloud.githubusercontent.com/assets/2686355/12434566/318f5a10-bf10-11e5-96b5-3060c36b0a00.gif)\n\n# AndroidX support\nMigration to AndroidX gladly provided by https://github.com/prensmiskin\n\n# License\n\nCopyright 2015 Danylo Volokh\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","funding_links":[],"categories":["Java","HarmonyOS","etc"],"sub_categories":["Windows Manager"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanylovolokh%2FVideoPlayerManager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanylovolokh%2FVideoPlayerManager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanylovolokh%2FVideoPlayerManager/lists"}