A better Android VideoView with more Media Controller customization. 一个更好用的Android VideoView

Overview

Android UniversalVideoView

中文版说明请点击这里

UniversalVideoView is a Android widget helps playing video easier, which is similar with the Android system native VideoView, but providing more customization feature: fitXY or keeping aspect ratio fullscreen videoView, auto switch to fullscreen on landscape mode, customised control UI...

Sample Screenshot 1 Sample Screenshot 2

Usage

For a working implementation of this project see the sample app.

  1. add library dependency to your build.gradle file.
            dependencies {
                compile 'com.linsea:universalvideoview:1.1.0@aar'
            }
  1. Include the UniversalVideoView and UniversalMediaController widget in your layout. This should usually be placed in the same parent ViewGroup, which makes sense when in full screen state.
            <FrameLayout
                android:id="@+id/video_layout"
                android:layout_width="fill_parent"
                android:layout_height="200dp"
                android:background="@android:color/black">

                <com.universalvideoview.UniversalVideoView
                    android:id="@+id/videoView"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:layout_gravity="center"
                    app:uvv_autoRotation="true"
                    app:uvv_fitXY="false" />

                <com.universalvideoview.UniversalMediaController
                    android:id="@+id/media_controller"
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    app:uvv_scalable="true" />

            </FrameLayout>
  1. In your onCreate method, set the UniversalMediaController to the UniversalVideoView and implements the UniversalVideoView.VideoViewCallback Callback.
            View mBottomLayout;
            View mVideoLayout;
            UniversalVideoView mVideoView;
            UniversalMediaController mMediaController;

            mVideoView = (UniversalVideoView) findViewById(R.id.videoView);
            mMediaController = (UniversalMediaController) findViewById(R.id.media_controller);
            mVideoView.setMediaController(mMediaController);

            mVideoView.setVideoViewCallback(new UniversalVideoView.VideoViewCallback() {
                @Override
                public void onScaleChange(boolean isFullscreen) {
                    this.isFullscreen = isFullscreen;
                    if (isFullscreen) {
                        ViewGroup.LayoutParams layoutParams = mVideoLayout.getLayoutParams();
                        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
                        layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
                        mVideoLayout.setLayoutParams(layoutParams);
                        //GONE the unconcerned views to leave room for video and controller
                        mBottomLayout.setVisibility(View.GONE);
                    } else {
                        ViewGroup.LayoutParams layoutParams = mVideoLayout.getLayoutParams();
                        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
                        layoutParams.height = this.cachedHeight;
                        mVideoLayout.setLayoutParams(layoutParams);
                        mBottomLayout.setVisibility(View.VISIBLE);
                    }
                }

                @Override
                public void onPause(MediaPlayer mediaPlayer) { // Video pause
                    Log.d(TAG, "onPause UniversalVideoView callback");
                }

                @Override
                public void onStart(MediaPlayer mediaPlayer) { // Video start/resume to play
                    Log.d(TAG, "onStart UniversalVideoView callback");
                }

                @Override
                public void onBufferingStart(MediaPlayer mediaPlayer) {// steam start loading
                    Log.d(TAG, "onBufferingStart UniversalVideoView callback");
                }

                @Override
                public void onBufferingEnd(MediaPlayer mediaPlayer) {// steam end loading
                    Log.d(TAG, "onBufferingEnd UniversalVideoView callback");
                }

            });

Note

  • Support Android Gingerbread V2.3(API Level 9 and above).
  • UniversalVideoView does not retain its full state when going into the background. You should save or restore the state and take care of the Activity Lifecycle.
  • You may need to set the android:configChanges="orientation|keyboardHidden|screenSize" for your Activity in AndroidManifest.xml to prevent the system from recreate the Activity while phone rotation.

Customization

UniversalVideoView attribute

  • uvv_fitXY, Video scale to fill the VideoView's dimension or keep Aspect Ratio (default) likes Android framework VideoView.
  • uvv_autoRotation, auto switch to landscape(fullscreen) or portrait mode according to the orientation sensor.

UniversalMediaController attribute

  • uvv_scalable, show or hide the scale button. if you will not play the video in fullscreen.

TODO

  • Brightness control on UniversalMediaController.
  • Volume Control on UniversalMediaController.

License

Copyright 2015 The UniversalVideoView author <[email protected]>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • 自动旋转不完善

    自动旋转不完善

    在手机里,手机开启自动旋转之后旋转不能全屏。 模拟器里旋转屏幕也不能全屏。我修改了下OrientationDetector里判断方向的代码

      if (orientation > 350 || orientation < 10) { //0度
                            if (currentOrientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
                                Log.d(TAG, "switch to SCREEN_ORIENTATION_PORTRAIT");
                                currentOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                                if (listener != null) {
                                    listener.onOrientationChanged(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, currDirection);
                                }
                            }
                        } else if (orientation > 80 && orientation < 100) { //90度
                            currentOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                            if (listener != null) {
                                listener.onOrientationChanged(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, currDirection);
                            }
                        } else if (orientation > 170 && orientation < 190) { //180度
                            if (currentOrientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {
                                Log.d(TAG, "switch to SCREEN_ORIENTATION_REVERSE_PORTRAIT");
                                currentOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
                                if (listener != null) {
                                    listener.onOrientationChanged(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, currDirection);
                                }
                            }
                        } else if (orientation > 260 && orientation < 280) { //270度
                            if (currentOrientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) {
                                Log.d(TAG, "switch to SCREEN_ORIENTATION_REVERSE_LANDSCAPE");
                                currentOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
                                if (listener != null) {
                                    listener.onOrientationChanged(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE, currDirection);
                                }
                            }
                        }
    

    然后在AndroidManifest里screenOrientation改成sensor。就可以真自动旋转全屏了。 不知道这样改对不对,可是却是可以自动旋转全屏

    opened by JcmeLs 4
  • Fullscreen button has to be pressed twice to enter full screen

    Fullscreen button has to be pressed twice to enter full screen

    Im trying to use your video view but when i press the full screen button, the orientation changes but it is a not truly full screen. The bottom and top layouts are off screen, and then when i press the fullscreen button again the video goes full screen as expected.

    Iv tried to debug the code but can't see where this is happening, the setfullscreen method is called as usual but it seems that it needs to be called twice.

    Help would be appreciated

    opened by nicwhitts 3
  • Loading progress title

    Loading progress title

    Hi @linsea , thanks for your awesome lib. Can you please provide me instruction how to change progress loading title. To see image please check attachments. Thanks! title_player

    opened by prossik 2
  • some video url is not play

    some video url is not play

    https://media011.blob.core.windows.net/000/SampleVideo_1080x720_5mb_13d4df3c-e931-4a7f-bc0e-4ad985b97524.mp4

    Above URL is not playing,what is the reason?

    opened by dineshswaas 2
  • 当按下home键的时候

    当按下home键的时候

    视频正在播放的时候 按下home键 并不能保存当前状态 在onSaveInstanceState中调用的 时候 mVideoView.getCurrentPosition() 为 0 在surfaceholder 的 ondestory中调用的 时候 mVideoView.getCurrentPosition() 也为 0

    opened by ilpanda 2
  • How to check end time of video when video is pause and activity pause,destroyed,stop

    How to check end time of video when video is pause and activity pause,destroyed,stop

    How to check end time of video when the video is pause and activity pause, destroyed, stop. When the user starts the video, if he pauses the video and go back(pause, stop, destroyed activity,pause video).after this video should start from last timestamp.

    opened by rssumit 1
  • 播放器隐藏时可能出现mMediaController为null

    播放器隐藏时可能出现mMediaController为null

    UniversalVideoView line 844 mMediaController.toggleButtons(fullscreen); 这里mMediaController有可能为null 具体场景:有些页面需要播放视频,有些页面不需要.通过是否有是否有视频url决定是否隐藏播放器.当隐藏播放器时,mMediaController值并没有被设置,当屏幕选择时,mMediaController为null,导致程序崩溃.

    opened by liongoodvery 1
  • Could not find com.linsea:universalvideoview:1.10..

    Could not find com.linsea:universalvideoview:1.10..

    This library not found in following repos

    • https://dl.google.com/dl/android/maven2/com/linsea/universalvideoview/1.10./universalvideoview-1.10..pom - https://repo.maven.apache.org/maven2/com/linsea/universalvideoview/1.10./universalvideoview-1.10..pom
    opened by grvsingh44 0
  • Click Controller's fullscreen icon. will pop nullpointerexception,please help to resolved it, thank you

    Click Controller's fullscreen icon. will pop nullpointerexception,please help to resolved it, thank you

    MainActivity.java: package com.example.helloandroid;

    import android.media.MediaPlayer; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView;

    import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity;

    import com.universalvideoview.UniversalMediaController; import com.universalvideoview.UniversalVideoView;

    public class MainActivity16 extends AppCompatActivity implements UniversalVideoView.VideoViewCallback {

    // uvv_fitXY:视频拉伸适配video_view的尺寸
    // uvv_autoRotation:根据方向传感器自动切换横竖屏
    // uvv_scalable:显示或隐藏缩放按钮
    
    private FrameLayout video_layout;
    private LinearLayout button_layout;
    private UniversalVideoView video_view;
    private UniversalMediaController media_controller;
    private Button start;
    private TextView introduction;
    
    private static final String TAG = "MainActivity16";
    private static final String SEEK_POSITION_KEY = "SEEK_POSITION_KEY";
    private static final String VIDEO_URL = "https://media.w3.org/2010/05/sintel/trailer.mp4";
    
    private int mSeekPosition;
    private int cachedHeight;
    private boolean isFullScreen;
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main16);
        getSupportActionBar().hide();
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
        initView();
        setVideoAreaSize();
        video_view.setVideoViewCallback(this);
    
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mSeekPosition > 0) {
                    video_view.seekTo(mSeekPosition);
                }
                video_view.start();
                media_controller.setTitle("Game trailer video playing……");
            }
        });
    
        video_view.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                Log.d(TAG, "Video On Completion……");
            }
        });
    
    }
    
    /**
     * 设置视频区域大小
     */
    private void setVideoAreaSize() {
        video_layout.post(new Runnable() {
            @Override
            public void run() {
                int width = video_layout.getWidth();
                cachedHeight = (int) (width * 405f / 720f);
    

    // cachedHeight = (int) (width * 3f / 4f); // cachedHeight = (int) (width * 9f / 16f); ViewGroup.LayoutParams videoLayoutParams = video_layout.getLayoutParams(); videoLayoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; videoLayoutParams.height = cachedHeight; video_layout.setLayoutParams(videoLayoutParams); video_view.setVideoPath(VIDEO_URL); video_view.requestFocus(); } }); }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "Video On Pause……");
        if (video_view != null && video_view.isPlaying()) {
            mSeekPosition = video_view.getCurrentPosition();
            Log.d(TAG, "Video On Pause mSeekPosition……" + mSeekPosition);
            video_view.pause();
        }
    }
    
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "Video On Save Instance State Position=" + video_view.getCurrentPosition());
        outState.putInt(SEEK_POSITION_KEY, mSeekPosition);
    }
    
    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        mSeekPosition = savedInstanceState.getInt(SEEK_POSITION_KEY);
        Log.d(TAG, "Video On Restore Instance State Position=" + mSeekPosition);
    }
    
    private void initView() {
        video_layout = findViewById(R.id.video_layout);
        video_view = findViewById(R.id.video_view);
        media_controller = findViewById(R.id.media_controller);
        start = findViewById(R.id.start);
        introduction = findViewById(R.id.introduction);
        button_layout = findViewById(R.id.button_layout);
    
    }
    
    @Override
    public void onScaleChange(boolean isFullscreen) {
        this.isFullScreen = isFullscreen;
        if (isFullscreen) {
            ViewGroup.LayoutParams layoutParams = video_layout.getLayoutParams();
            layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
            layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
            video_layout.setLayoutParams(layoutParams);
            button_layout.setVisibility(View.GONE);
        } else {
            ViewGroup.LayoutParams layoutParams = video_layout.getLayoutParams();
            layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
            layoutParams.height = this.cachedHeight;
            video_layout.setLayoutParams(layoutParams);
            button_layout.setVisibility(View.VISIBLE);
        }
        switchTitleBar(!isFullscreen);
    }
    
    private void switchTitleBar(boolean b) {
        ActionBar supportActionBar = getSupportActionBar();
        if (supportActionBar != null) {
            if (b) {
                supportActionBar.show();
            } else {
                supportActionBar.hide();
            }
        }
    }
    
    
    @Override
    public void onPause(MediaPlayer mediaPlayer) {
        Log.d(TAG, "Video On Pause UniversalVideoView callback");
    }
    
    @Override
    public void onStart(MediaPlayer mediaPlayer) {
        Log.d(TAG, "Video On Start UniversalVideoView callback");
    }
    
    @Override
    public void onBufferingStart(MediaPlayer mediaPlayer) {
        Log.d(TAG, "Video On Buffering Start UniversalVideoView callback");
    }
    
    @Override
    public void onBufferingEnd(MediaPlayer mediaPlayer) {
        Log.d(TAG, "Video On Buffering End UniversalVideoView callback");
    }
    
    @Override
    public void onBackPressed() {
        if (this.isFullScreen) {
            video_view.setFullscreen(false);
        } else {
            super.onBackPressed();
        }
    }
    

    }

    2022-02-16 19:25:06.702 6812-6812/com.example.helloandroid D/MediaPlayer: setSubtitleAnchor in MediaPlayer 2022-02-16 19:25:07.792 6812-6812/? D/AndroidRuntime: Shutting down VM 2022-02-16 19:25:07.793 6812-6812/? E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.helloandroid, PID: 6812 java.lang.NullPointerException: Attempt to invoke interface method 'void com.universalvideoview.UniversalMediaController$MediaPlayerControl.setFullscreen(boolean)' on a null object reference at com.universalvideoview.UniversalMediaController$4.onClick(UniversalMediaController.java:499) at android.view.View.performClick(View.java:5204) at android.view.View$PerformClick.run(View.java:21153) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5647) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635) 2022-02-16 19:25:07.797 6812-6812/? I/Process: Sending signal. PID: 6812 SIG: 9

    opened by 792607724 0
  • Is it possible to set up a click or touch event for a UniversalVideoView ?

    Is it possible to set up a click or touch event for a UniversalVideoView ?

    I want to handle the click or touch event for the UniversalVideoView. I tried the below:

    `
    
        <FrameLayout
            android:id="@+id/video_layout"
            android:layout_width="0dp"
            android:layout_height="200dp"
            android:background="@android:color/black"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">
    
            <com.universalvideoview.UniversalVideoView
                android:id="@+id/videoView"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_gravity="center"
                app:uvv_autoRotation="true"
                app:uvv_fitXY="false" />
    
            <com.universalvideoview.UniversalMediaController
                android:id="@+id/media_controller"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                app:uvv_scalable="true" />
    
        </FrameLayout>
    
    
    videoView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(ImgVideoViewerActivity.this, "bien", Toast.LENGTH_SHORT).show();
                }
            });
    
            video_layout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(ImgVideoViewerActivity.this, "bien", Toast.LENGTH_SHORT).show();
                }
            });`
    

    Bbut not work.

    Thanks.

    opened by BoumBam 0
  • Issue when we play multiple videos at a time. Should play only single video at a time

    Issue when we play multiple videos at a time. Should play only single video at a time

    When I am using this UniversalVideoView in a recycler view. There are multiple videos on the list, If I tap any video from the list it is playing fine but while playing this if I tap on another video then both videos are playing at the same time. I want to stop the previous one and start the current one Any solution for it?

    opened by shylendramadda 0
Releases(v1.1.0)
The androidx.media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android

AndroidX Media AndroidX Media is a collection of libraries for implementing media use cases on Android, including local playback (via ExoPlayer) and m

Android Jetpack 310 Dec 29, 2022
Cache wrapper for standart android VideoView

Android VideoView cache Cache wrapper for standart android VideoView It uses okhttp and rxjava inside. Nothing special is needed to use. Setup: Add ma

Andrew0000 4 Aug 25, 2022
VideoView that plays video only when :eyes: are open and :boy: is detected with various other features

LookAtMe VideoView that plays video only when ?? are open and ?? is detected with various other features GIF AndroidPub (Medium) Post You can read the

Pradyuman Dixit 186 Dec 13, 2022
To play video on layout background (textureview videoview for layout designs)

The normal videoview on Android is very costly in terms of performance. Also, due to the video resolution ratio and apk size, most developers don't want to include videos in the project. With this library, developers will have a performance-friendly video background with a few lines of code.

Egemen ÖZOGUL 324 Nov 29, 2022
A white noise app developed with Kotlin. It helps to mediate, sleep better, focus, relax and be calm.

A white noise app developed with Kotlin. It helps to mediate, sleep better, focus, relax and be calm.

mantu kumar ojha 5 Dec 10, 2022
An extensible media player for Android

ExoPlayer ExoPlayer is an application level media player for Android. It provides an alternative to Android’s MediaPlayer API for playing audio and vi

Google 20.2k Jan 1, 2023
Sandbox project for practice: Media Streaming with Exoplayer (via Android Development tutorial)

Media streaming with ExoPlayer The code in this repository accompanies the Media streaming with ExoPlayer codelab. If you are looking to get started w

Jeannille Hiciano 1 Nov 29, 2021
ExoPlayer - an application level media player for Android

ExoPlayer is an application level media player for Android. It provides an alternative to Android’s MediaPlayer API for playing audio and video both locally and over the Internet. ExoPlayer supports features not currently supported by Android’s MediaPlayer API, including DASH and SmoothStreaming adaptive playbacks.

Halil Özel 6 Oct 31, 2022
Fermata Media Player is a free, open source audio and video player with a simple and intuitive interface.

Fermata Media Player About Fermata Media Player is a free, open source audio and video player with a simple and intuitive interface. It is focused on

Andrey 227 Jan 6, 2023
LNSocial is a social media app dedicated to short-form videos created for and consumed by users.

LNSocial is a social media app dedicated to short-form videos created for and consumed by users. The length of videos is between 15-30 second

null 10 Jan 5, 2023
The Madman library (Media Ads Manager) enables you to advertise video contents with video ads.

Madman (Media ads manager) is a high performance alternative to Google's standard IMA android SDK. If you have your own VAST server and want to render video ads and have full control over the UI, then this library is for you.

Flipkart Incubator 65 Nov 10, 2022
Blade is an open source music player for Android, allowing you to play music from multiple services : files on your phone, Spotify, and more.

Blade Player Blade is an open source music player for Android, allowing you to play music from multiple services : files on your phone, Spotify, and m

Valentin HAUDIQUET 72 Jan 5, 2023
Wynncraft API Wrapper - Simple wrapper to get Wynncraft Stats of a player or a guild and more in Java

WynncraftAPIWrapper Simple wrapper to get Wynncraft Stats of a player or a guild

byBackfish 3 Sep 27, 2022
Is an All in One app for Muslims with lots of features such as Prayer Times & Adhan, Collections of Dhikr and Prayer sourced from Authentic Hadith, The Holy Qur'an, Qibla, Notes and many more!

Is an All in One app for Muslims with lots of features such as Prayer Times & Adhan, Collections of Dhikr and Prayer sourced from Authentic Hadith, The Holy Qur'an, Qibla, Notes and many more!

DzikirQu 112 Dec 26, 2022
:sound: [Android Library] Easily generate pure audio tone of any frequency in android

Android library to easily generate audio tone in android. Generating pure tone of an specific frequency was never that easy. ZenTone does all the heav

Nishant Srivastava 102 Dec 19, 2022
mpv-android is a video player for Android based on libmpv.

mpv-android is a video player for Android based on libmpv.

null 1.1k Jan 6, 2023
FFmpeg compiled for Android. Execute FFmpeg commands with ease in your Android app.

FFMPEG video operations FFmpeg compiled for Android. Execute FFmpeg commands with ease in your Android app. Getting Started This project is provide in

Simform Solutions 277 Jan 2, 2023
Echo is a lightweight and minimal music player for Android, built with Android Studio and written in Kotlin

Echo - Echo, A light-weight, minimal music player for Android, with shuffle, favorites and audio visualization

Divins Mathew 0 Feb 7, 2022
Youtube Android Clone 🚀an Android Youtube Clone made out of XML and Kotlin

Youtube Android Clone ?? This app consumes The Youtube Api to fetch and display a list of popular videos, The app uses MVVM design pattern to allow se

Breens Robert 38 Dec 13, 2022