According to the live options, add the live entrance
This commit is contained in:
parent
418a9c3e12
commit
915c8d0829
|
@ -1,6 +1,6 @@
|
|||
<!-- Describe the main content of this issue's open source and the estimated time and content of the next open source -->
|
||||
|
||||
# Contents of this open source
|
||||
# Contents of first open source
|
||||
|
||||
- Open source code for playing intermediate layer (including: instance management, interface calls, etc.)
|
||||
- RedPlayer is open source in the form of SDK this time
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||

|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
<!-- [GitHub issues](https://img.shields.io/github/issues/badges/RedPlayer/open) -->
|
||||
<!-- [GitHub pull requests](https://img.shields.io/bitbucket/pr/badge/RedPlayer?label=pull%20requests) -->
|
||||
|
||||
Platform | Build Status
|
||||
-------- | ------------
|
||||
|
@ -64,6 +64,9 @@
|
|||
|
||||
|
||||
### Open Content
|
||||
```bash
|
||||
# Describe the main contents of current open source and the estimated time and contents of the next open source
|
||||
```
|
||||
- [CONTENTS.md](CONTENTS.md)
|
||||
|
||||
### Usage
|
||||
|
|
|
@ -104,6 +104,8 @@ public interface IMediaPlayer {
|
|||
*/
|
||||
void setVideoCacheDir(String dir);
|
||||
|
||||
void setLiveMode(boolean enable);
|
||||
|
||||
void setDataSource(Context context, Uri uri) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
|
||||
|
||||
void setDataSource(Context context, Uri uri, Map<String, String> headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
|
||||
|
|
|
@ -138,6 +138,10 @@ public class AndroidMediaPlayer extends AbstractMediaPlayer {
|
|||
public void setVideoCacheDir(String dir) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLiveMode(boolean enable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAudioCodecInfo() {
|
||||
return "unknown";
|
||||
|
|
|
@ -323,6 +323,13 @@ public class RedMediaPlayer extends AbstractMediaPlayer {
|
|||
|
||||
private native void _setVideoCacheDir(String dir);
|
||||
|
||||
@Override
|
||||
public void setLiveMode(boolean enable) {
|
||||
_setLiveMode(enable);
|
||||
}
|
||||
|
||||
private native void _setLiveMode(boolean enable);
|
||||
|
||||
|
||||
@Override
|
||||
public String getAudioCodecInfo() {
|
||||
|
|
|
@ -27,7 +27,7 @@ android {
|
|||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
minifyEnabled false
|
||||
signingConfig signingConfigs.release
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
|
|
@ -47,6 +47,11 @@
|
|||
android:name=".input.XhsInputActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- 直播输入页 -->
|
||||
<activity
|
||||
android:name=".live.XhsLiveInputActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- 双列Feed页 -->
|
||||
<activity
|
||||
android:name=".feed.XhsFeedActivity"
|
||||
|
|
|
@ -155,6 +155,10 @@ val VIDEO_ONE =
|
|||
val VIDEO_TWO =
|
||||
Utils.decodeBase64("aHR0cDovL3Nucy12aWRlby1hbC54aHNjZG4uY29tL3NwZWN0cnVtLzAxZTI5NjRlNDE2YmUwNzcwMTgzNzAwMzgxMWI0ZTM5YzlfNTEzLm1wNA==")
|
||||
|
||||
val LIVE_VIDEO =
|
||||
Utils.decodeBase64("aHR0cDovL2xpdmUtcGxheS54aHNjZG4uY29tL2xpdmUvNTY5MDcyNTczNzk5OTkxNzI5LmZsdj91aWQ9NjQxMjkwNWUwMDAwMDAwMDEyMDEwNjIx")
|
||||
|
||||
|
||||
/** the json data source */
|
||||
val JSON_DATA_SOURCE = Utils.decodeBase64(
|
||||
"eyJzdHJlYW0iOnsiaDI2NCI6W3sid2lkdGgiOjcyMCwiaGVpZ2h0IjoxMjgwLCJhdmdfYml0cmF0ZSI6MTAzNTE1NCwibWFzdGVyX3VybCI6Imh0dHBzOi8vc25zLXZpZGVvLWFsLnhoc2Nkbi5jb20vc3RyZWFtLzExMC80MDUvMDFlNTgzY2I2ZTBmZWQ1YTAxMDM3MDAzOGM4YWQ5NjJmYl80MDUubXA0IiwiYmFja3VwX3VybHMiOlsiaHR0cHM6Ly9zbnMtdmlkZW8tYWwueGhzY2RuLmNvbS9zdHJlYW0vMTEwLzQwNS8wMWU1ODNjYjZlMGZlZDVhMDEwMzcwMDM4YzhhZDk2MmZiXzQwNS5tcDQiXX1dLCJoMjY1IjpbeyJ3aWR0aCI6NzIwLCJoZWlnaHQiOjEyODAsImF2Z19iaXRyYXRlIjo2ODcwMjYsIm1hc3Rlcl91cmwiOiJodHRwczovL3Nucy12aWRlby1hbC54aHNjZG4uY29tL3N0cmVhbS8xMTAvNDA1LzAxZTU4M2NiNmUwZmVkNWEwMTAzNzAwMzhjOGFkOTYyZmJfNDA1Lm1wNCIsImJhY2t1cF91cmxzIjpbImh0dHBzOi8vc25zLXZpZGVvLWFsLnhoc2Nkbi5jb20vc3RyZWFtLzExMC80MDUvMDFlNTgzY2I2ZTBmZWQ1YTAxMDM3MDAzOGM4YWQ5NjJmYl80MDUubXA0Il19LHsid2lkdGgiOjEwODAsImhlaWdodCI6MTkyMCwiYXZnX2JpdHJhdGUiOjkzOTU1NCwibWFzdGVyX3VybCI6Imh0dHBzOi8vc25zLXZpZGVvLWFsLnhoc2Nkbi5jb20vc3RyZWFtLzExMC80MDUvMDFlNTgzY2I2ZTBmZWQ1YTAxMDM3MDAzOGM4YWQ5NjJmYl80MDUubXA0IiwiYmFja3VwX3VybHMiOlsiaHR0cHM6Ly9zbnMtdmlkZW8tYWwueGhzY2RuLmNvbS9zdHJlYW0vMTEwLzQwNS8wMWU1ODNjYjZlMGZlZDVhMDEwMzcwMDM4YzhhZDk2MmZiXzQwNS5tcDQiXX1dfX0="
|
||||
|
|
|
@ -17,6 +17,7 @@ import com.xingin.openredplayer.feed.model.covertToVideoUrls
|
|||
import com.xingin.openredplayer.floating.XhsFloatingService
|
||||
import com.xingin.openredplayer.floating.XhsFloatingWindowHelper
|
||||
import com.xingin.openredplayer.input.XhsInputActivity
|
||||
import com.xingin.openredplayer.live.XhsLiveInputActivity
|
||||
import com.xingin.openredplayer.player.XhsPlayerActivity
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
import java.io.Serializable
|
||||
|
@ -24,6 +25,7 @@ import java.io.Serializable
|
|||
class XhsHomeFragment : Fragment() {
|
||||
private lateinit var rootView: View
|
||||
private lateinit var itemUrlView: View
|
||||
private lateinit var itemLiveUrlView: View
|
||||
private lateinit var itemAlbumView: View
|
||||
private lateinit var itemFeedView: View
|
||||
private lateinit var itemWindowView: View
|
||||
|
@ -53,6 +55,8 @@ class XhsHomeFragment : Fragment() {
|
|||
private fun initView() {
|
||||
itemUrlView = rootView.findViewById(R.id.layout_play_url)
|
||||
itemUrlView.setOnClickListener { openInputPage() }
|
||||
itemLiveUrlView = rootView.findViewById(R.id.layout_play_live_url)
|
||||
itemLiveUrlView.setOnClickListener { openLiveInputPage() }
|
||||
itemAlbumView = rootView.findViewById(R.id.layout_local_album)
|
||||
itemAlbumView.setOnClickListener { openAlbumPage() }
|
||||
itemFeedView = rootView.findViewById(R.id.layout_double_column)
|
||||
|
@ -68,6 +72,11 @@ class XhsHomeFragment : Fragment() {
|
|||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun openLiveInputPage() {
|
||||
val intent = Intent(this.activity, XhsLiveInputActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun openAlbumPage() {
|
||||
permissionDisposable = rxPermissions.request(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
|
|
|
@ -47,6 +47,7 @@ class XhsPlayerActivity : AppCompatActivity(), XhsSectionAdapter.OnSectionItemCl
|
|||
const val INTENT_KEY_URLS = "video_urls"
|
||||
const val INTENT_KEY_INDEX = "video_index"
|
||||
const val INTENT_KEY_SHOW_LOADING = "show_loading"
|
||||
const val INTENT_KEY_IS_LIVE = "is_live"
|
||||
}
|
||||
|
||||
/** DrawerLayout UI */
|
||||
|
@ -88,6 +89,7 @@ class XhsPlayerActivity : AppCompatActivity(), XhsSectionAdapter.OnSectionItemCl
|
|||
|
||||
/** data **/
|
||||
private var isShowLoading = false
|
||||
private var isLive = false
|
||||
private var videoUrls = arrayListOf<String>()
|
||||
private var playIndex = 0
|
||||
|
||||
|
@ -124,6 +126,7 @@ class XhsPlayerActivity : AppCompatActivity(), XhsSectionAdapter.OnSectionItemCl
|
|||
private fun initData() {
|
||||
playIndex = intent.getIntExtra(INTENT_KEY_INDEX, 0)
|
||||
isShowLoading = intent.getBooleanExtra(INTENT_KEY_SHOW_LOADING, false)
|
||||
isLive = intent.getBooleanExtra(INTENT_KEY_IS_LIVE, false)
|
||||
val list = intent.getSerializableExtra(INTENT_KEY_URLS) as List<String>
|
||||
videoUrls.addAll(list)
|
||||
// init config
|
||||
|
@ -236,26 +239,34 @@ class XhsPlayerActivity : AppCompatActivity(), XhsSectionAdapter.OnSectionItemCl
|
|||
/** update the video play progress */
|
||||
private fun initVideoProgressView() {
|
||||
progressSeekBar = findViewById(R.id.video_view_seekbar)
|
||||
progressSeekBar.setOnProgressChangedListener(object :
|
||||
XhsProgressBar.OnProgressChangedListener {
|
||||
override fun onProgressChanged(
|
||||
signSeekBar: XhsProgressBar, progress: Int, progressFloat: Float, fromUser: Boolean
|
||||
) {
|
||||
}
|
||||
if (!isLive) {
|
||||
progressSeekBar.setOnProgressChangedListener(object :
|
||||
XhsProgressBar.OnProgressChangedListener {
|
||||
override fun onProgressChanged(
|
||||
signSeekBar: XhsProgressBar,
|
||||
progress: Int,
|
||||
progressFloat: Float,
|
||||
fromUser: Boolean
|
||||
) {
|
||||
}
|
||||
|
||||
override fun getProgressOnActionUp(
|
||||
signSeekBar: XhsProgressBar, progress: Int, progressFloat: Float
|
||||
) {
|
||||
val percentage = progress / 1000.0
|
||||
videoPlayerView.seekTo((percentage * videoPlayerView.duration).toInt())
|
||||
progressSeekBar.setProgress(progressFloat)
|
||||
}
|
||||
override fun getProgressOnActionUp(
|
||||
signSeekBar: XhsProgressBar, progress: Int, progressFloat: Float
|
||||
) {
|
||||
val percentage = progress / 1000.0
|
||||
videoPlayerView.seekTo((percentage * videoPlayerView.duration).toInt())
|
||||
progressSeekBar.setProgress(progressFloat)
|
||||
}
|
||||
|
||||
override fun getProgressOnFinally(
|
||||
signSeekBar: XhsProgressBar, progress: Int, progressFloat: Float, fromUser: Boolean
|
||||
) {
|
||||
}
|
||||
})
|
||||
override fun getProgressOnFinally(
|
||||
signSeekBar: XhsProgressBar,
|
||||
progress: Int,
|
||||
progressFloat: Float,
|
||||
fromUser: Boolean
|
||||
) {
|
||||
}
|
||||
})
|
||||
}
|
||||
// update the seekbar
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
var position: Int
|
||||
|
@ -342,7 +353,10 @@ class XhsPlayerActivity : AppCompatActivity(), XhsSectionAdapter.OnSectionItemCl
|
|||
}
|
||||
videoPlayerView.setOnErrorListener { _, what, extra -> handleVideoErrorEvent(what, extra) }
|
||||
// 1.1 set the video url and wait play
|
||||
videoPlayerView.setVideoPath(getCurrentPlayUrl())
|
||||
videoPlayerView.setVideoPath(getCurrentPlayUrl(), isLive)
|
||||
if (isLive) {
|
||||
playPauseButton.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
/** init the video debug info view */
|
||||
|
@ -539,7 +553,7 @@ class XhsPlayerActivity : AppCompatActivity(), XhsSectionAdapter.OnSectionItemCl
|
|||
|
||||
/** handle video speed play: support 0.75,1.0,1.25,1.5,2.0 */
|
||||
private fun handleVideoSpeedPlay(speed: Float, isShow: Boolean) {
|
||||
if (!videoPlayerView.isPlaying) {
|
||||
if (!videoPlayerView.isPlaying || isLive) {
|
||||
return
|
||||
}
|
||||
videoPlayerView.setSpeed(speed)
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.io.IOException;
|
|||
public class XhsVideoPlayerView extends FrameLayout implements MediaController.MediaPlayerControl {
|
||||
private String TAG = "VideoPlayerView";
|
||||
private String mUrl;
|
||||
private Boolean mIsLive;
|
||||
private static final int STATE_ERROR = -1;
|
||||
private static final int STATE_IDLE = 0;
|
||||
private static final int STATE_PREPARING = 1;
|
||||
|
@ -136,6 +137,11 @@ public class XhsVideoPlayerView extends FrameLayout implements MediaController.M
|
|||
}
|
||||
}
|
||||
|
||||
public void setVideoPath(String path, boolean isLive) {
|
||||
mIsLive = isLive;
|
||||
setVideoPath(path);
|
||||
}
|
||||
|
||||
public void setVideoPath(String path) {
|
||||
mUrl = path;
|
||||
mSeekWhenPrepared = 0;
|
||||
|
@ -217,10 +223,11 @@ public class XhsVideoPlayerView extends FrameLayout implements MediaController.M
|
|||
|
||||
private IMediaPlayer createMediaPlayer() {
|
||||
IMediaPlayer mediaPlayer = mSettings.getEnableAndroidMediaPlayer() ? new AndroidMediaPlayer() : new RedMediaPlayer();
|
||||
// 设置播放器使用硬解: 具体是否有硬解可用,内核来决定
|
||||
mediaPlayer.setEnableMediaCodec(mSettings.getUsingMediaCodec());
|
||||
// 设置视频缓存路径: 边播边下的视频缓存路径,设置后无网可播播过的视频
|
||||
// set video cache url: downloading when playing, if network error, can also play
|
||||
mediaPlayer.setVideoCacheDir(Utils.INSTANCE.getVideCacheDir());
|
||||
// set whether url is live
|
||||
mediaPlayer.setLiveMode(mIsLive);
|
||||
return mediaPlayer;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class XhsPlayerSettings(context: Context) {
|
|||
val usingMediaCodec: Boolean
|
||||
get() {
|
||||
val key = mAppContext.getString(R.string.pref_key_using_media_codec)
|
||||
return mSharedPreferences.getBoolean(key, false)
|
||||
return mSharedPreferences.getBoolean(key, true)
|
||||
}
|
||||
|
||||
val enableAndroidMediaPlayer: Boolean
|
||||
|
|
|
@ -30,6 +30,32 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_play_live_url"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/icon_live" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="13dp"
|
||||
android:text="@string/home_item_live_url"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_local_album"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/player_bottom_action_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:showIn="@layout/activity_xhs_player_layout">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<!-- 蒙层 -->
|
||||
<View
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<string name="pref_title_player_core">Media Player Setting</string>
|
||||
<string name="pref_key_using_media_codec">pref.using_media_codec</string>
|
||||
<string name="pref_title_using_media_codec">Use MediaCodec Decode</string>
|
||||
<string name="pref_summary_using_media_codec">Default, software decoding is used. opening, hardware decoder used"</string>
|
||||
<string name="pref_summary_using_media_codec">Default, MediaCodec decoding is used. opening, soft decoder used</string>
|
||||
|
||||
<string name="pref_key_using_android_media_player">pref.using_android_media_player</string>
|
||||
<string name="pref_title_using_android_media_player">Use System Media Player</string>
|
||||
|
@ -55,7 +55,8 @@
|
|||
<string name="home_tab_home_title">Home</string>
|
||||
<string name="home_tab_setting_title">Settings</string>
|
||||
<string name="home_title">Demo Of Video Feed Page</string>
|
||||
<string name="home_item_url">Play URL/JSON</string>
|
||||
<string name="home_item_url">URL/JSON</string>
|
||||
<string name="home_item_live_url">LIVE URL</string>
|
||||
<string name="home_item_album">Play Local Resource</string>
|
||||
<string name="home_item_feed">Online Samples</string>
|
||||
<string name="home_item_window">Pip Samples</string>
|
||||
|
@ -70,6 +71,10 @@
|
|||
<string name="input_clear">Clear</string>
|
||||
<string name="input_jump">Play</string>
|
||||
|
||||
<string name="input_live_url_title">Demo of Live URL Page</string>
|
||||
<string name="input_live_url_default">Live URL</string>
|
||||
<string name="input_live_url_hint">Input live url to play</string>
|
||||
|
||||
<string name="play_section">All</string>
|
||||
<string name="play_speed">Playing Speed</string>
|
||||
<string name="play_show_or_hide">Show/Hide</string>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
<PreferenceCategory android:title="@string/pref_title_player_core">
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:defaultValue="true"
|
||||
android:key="@string/pref_key_using_media_codec"
|
||||
android:persistent="true"
|
||||
android:summary="@string/pref_summary_using_media_codec"
|
||||
|
|
Binary file not shown.
|
@ -88,7 +88,13 @@ self.player.notPauseGlviewBackground = NO;
|
|||
- Set whether to use hardware decoding (VideoToolbox). **The default is software decoding (NO**):
|
||||
|
||||
```objective-c
|
||||
[self.player setEnableVTB:![RedPlayerSettings sharedInstance].softDecoder];
|
||||
[self.player setEnableVTB:YES];
|
||||
```
|
||||
|
||||
- **Be sure** to set it to YES if it is a **live broadcast** scene. **The default is NO**:
|
||||
|
||||
```objective-c
|
||||
[self.player setLiveMode:YES];
|
||||
```
|
||||
|
||||
- Set the cache path. **The default is no caching**:
|
||||
|
|
|
@ -184,6 +184,9 @@ typedef NS_ENUM(NSUInteger, RedRenderType) {
|
|||
/// Sets whether Video Toolbox is enabled.
|
||||
- (void)setEnableVTB:(BOOL)enable;
|
||||
|
||||
/// Sets whether video is live source.
|
||||
- (void)setLiveMode:(BOOL)enable;
|
||||
|
||||
/// Returns whether Video Toolbox is open.
|
||||
- (BOOL)isVideoToolboxOpen;
|
||||
|
||||
|
|
Binary file not shown.
|
@ -3,7 +3,7 @@
|
|||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 51;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
|
@ -428,7 +428,7 @@
|
|||
CODE_SIGN_STYLE = Manual;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WA7K45T45A;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = B92R44VSX2;
|
||||
EXCLUDED_ARCHS = "armv7 armv7s";
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -484,7 +484,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WA7K45T45A;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = B92R44VSX2;
|
||||
EXCLUDED_ARCHS = "armv7 armv7s";
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
|
|
@ -82,14 +82,14 @@ class MainViewController: UIViewController,
|
|||
|
||||
}
|
||||
|
||||
func playURLResource() {
|
||||
func playURLResource(isLive: Bool) {
|
||||
inputAlertViewBgView = UIView(frame: self.view.bounds)
|
||||
if let bgView = inputAlertViewBgView {
|
||||
bgView.backgroundColor = UIColor.gray.withAlphaComponent(0.2)
|
||||
self.view.addSubview(bgView)
|
||||
}
|
||||
|
||||
inputAlertView = RedAlertView(frame: CGRect(x: self.view.bounds.size.width / 2, y: self.view.bounds.size.height / 2, width: 0, height: 0))
|
||||
inputAlertView = RedAlertView(frame: CGRect(x: self.view.bounds.size.width / 2, y: self.view.bounds.size.height / 2, width: 0, height: 0), isLive: isLive)
|
||||
inputAlertView?.translatesAutoresizingMaskIntoConstraints = false
|
||||
if let alertView = inputAlertView {
|
||||
alertView.playButtonTapped = { [weak self] input, isJSON in
|
||||
|
@ -109,7 +109,7 @@ class MainViewController: UIViewController,
|
|||
self?.present(alertController, animated: true, completion: nil)
|
||||
return
|
||||
}
|
||||
RedDemoPlayerViewController.present(from: self, withTitle: "", url: input, isJson: isJSON, playList: nil, playListIndex: 0, completion: nil, close: nil)
|
||||
RedDemoPlayerViewController.present(from: self, withTitle: "", url: input, isJson: isJSON, isLive: isLive, playList: nil, playListIndex: 0, completion: nil, close: nil)
|
||||
}
|
||||
alertView.closeButtonTapped = { [weak self] in
|
||||
self?.closeAlertView()
|
||||
|
@ -249,7 +249,7 @@ class MainViewController: UIViewController,
|
|||
|
||||
DispatchQueue.main.async {
|
||||
self.dismiss(animated: true) {
|
||||
RedDemoPlayerViewController.present(from: self, withTitle: "", url: firstUrl, isJson: false, playList: videoDictArray, playListIndex: 0, completion: nil, close: nil)
|
||||
RedDemoPlayerViewController.present(from: self, withTitle: "", url: firstUrl, isJson: false, isLive: false, playList: videoDictArray, playListIndex: 0, completion: nil, close: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ class MainViewController: UIViewController,
|
|||
extension MainViewController: UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return 3
|
||||
return 4
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
@ -324,12 +324,15 @@ extension MainViewController: UITableViewDataSource {
|
|||
|
||||
switch indexPath.row {
|
||||
case 0:
|
||||
cell.iconImageView.image = UIImage(named: "link")?.withRenderingMode(.alwaysTemplate)
|
||||
cell.titleLabel.text = "Play URL / Json"
|
||||
cell.iconImageView.image = UIImage(named: "vod_link")?.withRenderingMode(.alwaysTemplate)
|
||||
cell.titleLabel.text = "VOD URL / Json"
|
||||
case 1:
|
||||
cell.iconImageView.image = UIImage(named: "live_link")?.withRenderingMode(.alwaysTemplate)
|
||||
cell.titleLabel.text = "LIVE URL"
|
||||
case 2:
|
||||
cell.iconImageView.image = UIImage(named: "album")?.withRenderingMode(.alwaysTemplate)
|
||||
cell.titleLabel.text = "Play Local Resources"
|
||||
case 2:
|
||||
case 3:
|
||||
cell.iconImageView.image = UIImage(named: "flow_icon")?.withRenderingMode(.alwaysTemplate)
|
||||
cell.titleLabel.text = "Video Samples"
|
||||
default:
|
||||
|
@ -352,10 +355,12 @@ extension MainViewController: UITableViewDelegate {
|
|||
|
||||
switch indexPath.row {
|
||||
case 0:
|
||||
playURLResource()
|
||||
playURLResource(isLive: false)
|
||||
case 1:
|
||||
playLocalVideo()
|
||||
playURLResource(isLive: true)
|
||||
case 2:
|
||||
playLocalVideo()
|
||||
case 3:
|
||||
showRedFlowViewController()
|
||||
default:
|
||||
break
|
||||
|
|
|
@ -17,6 +17,7 @@ typedef void(^DemoCloseBlock)(void);
|
|||
withTitle:(NSString *)title
|
||||
URL:(NSString *)url
|
||||
isJson:(BOOL)isJson
|
||||
isLive:(BOOL)isLive
|
||||
playList:(NSArray *)playList
|
||||
playListIndex:(NSInteger)playListIndex
|
||||
completion:(void(^)(void))completion
|
||||
|
|
|
@ -34,6 +34,7 @@ typedef NS_ENUM(NSUInteger, RedTipsPosition) {
|
|||
@interface RedDemoPlayerViewController () <RedMediaControlDelegate>
|
||||
@property (nonatomic, strong) NSString *url;
|
||||
@property (nonatomic, assign) BOOL isJson;
|
||||
@property (nonatomic, assign) BOOL isLive;
|
||||
@property (nonatomic, strong) NSArray *playList;
|
||||
@property (nonatomic, assign) NSInteger playListIndex;
|
||||
@property (nonatomic, assign) RedScalingMode scaleMode;
|
||||
|
@ -88,13 +89,14 @@ typedef NS_ENUM(NSUInteger, RedTipsPosition) {
|
|||
withTitle:(NSString *)title
|
||||
URL:(NSString *)url
|
||||
isJson:(BOOL)isJson
|
||||
isLive:(BOOL)isLive
|
||||
playList:(NSArray *)playList
|
||||
playListIndex:(NSInteger)playListIndex
|
||||
completion:(void (^)(void))completion
|
||||
closeBlock:(void (^)(void))closeBlock {
|
||||
|
||||
[RedDemoPlayerViewController setupLogCallback];
|
||||
RedDemoPlayerViewController *demoPlayerVC = [[RedDemoPlayerViewController alloc] initWithURL:url isJson:isJson];
|
||||
RedDemoPlayerViewController *demoPlayerVC = [[RedDemoPlayerViewController alloc] initWithURL:url isJson:isJson isLive:isLive];
|
||||
demoPlayerVC.playList = [playList copy];
|
||||
demoPlayerVC.playListIndex = playListIndex;
|
||||
demoPlayerVC.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
|
@ -103,11 +105,12 @@ typedef NS_ENUM(NSUInteger, RedTipsPosition) {
|
|||
demoPlayerVC.closeBlock = closeBlock;
|
||||
}
|
||||
|
||||
- (instancetype)initWithURL:(NSString *)url isJson:(BOOL)isJson {
|
||||
- (instancetype)initWithURL:(NSString *)url isJson:(BOOL)isJson isLive:(BOOL)isLive {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.url = url;
|
||||
self.isJson = isJson;
|
||||
self.isLive = isLive;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -216,7 +219,9 @@ typedef NS_ENUM(NSUInteger, RedTipsPosition) {
|
|||
[self.player setMute:NO];
|
||||
[self.player setEnableVTB:![RedPlayerSettings sharedInstance].softDecoder];
|
||||
[self.player setVideoCacheDir:[RedMediaUtil cachePath]];
|
||||
|
||||
if (self.isLive) {
|
||||
[self.player setLiveMode:YES]; // config live mode
|
||||
}
|
||||
[self.view addSubview:self.player.view];
|
||||
[self.view sendSubviewToBack:self.player.view];
|
||||
[self installMovieNotificationObservers];
|
||||
|
@ -417,6 +422,9 @@ typedef NS_ENUM(NSUInteger, RedTipsPosition) {
|
|||
- (void)closeClick:(id)sender {
|
||||
[self shutdown];
|
||||
[self stopLoading];
|
||||
[self.mediaControl removeFromSuperview];
|
||||
[self.mediaControl stopRefresh];
|
||||
self.mediaControl = nil;
|
||||
[self dismissViewControllerAnimated:NO completion:^{
|
||||
if (self.closeBlock) {
|
||||
self.closeBlock();
|
||||
|
@ -498,7 +506,7 @@ typedef NS_ENUM(NSUInteger, RedTipsPosition) {
|
|||
self.mediaControl.delegatePlayer = nil;
|
||||
self.mediaControl = nil;
|
||||
}
|
||||
self.mediaControl = [[RedMediaControl alloc] initWithFrame:CGRectZero viewController:self playList:[self.playList copy] isLoop:self.isLoop];
|
||||
self.mediaControl = [[RedMediaControl alloc] initWithFrame:CGRectZero viewController:self playList:[self.playList copy] isLoop:self.isLoop isLive:self.isLive];
|
||||
self.mediaControl.playListIndex = _playListIndex;
|
||||
self.mediaControl.layer.cornerRadius = 10;
|
||||
self.mediaControl.layer.masksToBounds = YES;
|
||||
|
@ -526,7 +534,6 @@ typedef NS_ENUM(NSUInteger, RedTipsPosition) {
|
|||
}
|
||||
|
||||
- (void)hideMediaControl {
|
||||
[self.mediaControl stopRefresh];
|
||||
self.mediaControl.hidden = YES;
|
||||
self.closeButton.hidden = YES;
|
||||
self.scaleModeButton.hidden = YES;
|
||||
|
@ -597,21 +604,25 @@ typedef NS_ENUM(NSUInteger, RedTipsPosition) {
|
|||
|
||||
// MARK: Gestures
|
||||
- (void)addGestureControls {
|
||||
// Long Press - 2x Playback Speed
|
||||
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
|
||||
[self.view addGestureRecognizer:longPress];
|
||||
|
||||
// Double Tap
|
||||
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
|
||||
doubleTap.numberOfTapsRequired = 2;
|
||||
[self.view addGestureRecognizer:doubleTap];
|
||||
UITapGestureRecognizer *doubleTap = nil;
|
||||
if (!self.isLive) {
|
||||
// Long Press - 2x Playback Speed
|
||||
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
|
||||
[self.view addGestureRecognizer:longPress];
|
||||
|
||||
// Double Tap
|
||||
doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
|
||||
doubleTap.numberOfTapsRequired = 2;
|
||||
[self.view addGestureRecognizer:doubleTap];
|
||||
}
|
||||
|
||||
// Single Tap - Show/Hide tips
|
||||
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
|
||||
singleTap.numberOfTapsRequired = 1;
|
||||
[self.view addGestureRecognizer:singleTap];
|
||||
|
||||
[singleTap requireGestureRecognizerToFail:doubleTap];
|
||||
if (doubleTap) {
|
||||
[singleTap requireGestureRecognizerToFail:doubleTap];
|
||||
}
|
||||
|
||||
// Pan - Volume/Brightness
|
||||
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
|
||||
|
@ -962,5 +973,9 @@ typedef NS_ENUM(NSUInteger, RedTipsPosition) {
|
|||
[self performSelector:@selector(hideMediaControl) withObject:nil afterDelay:5];
|
||||
}
|
||||
|
||||
- (void)mediaControlLiveRefresh {
|
||||
[self shutdown];
|
||||
[self setupPlayer];
|
||||
}
|
||||
@end
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
- (void)switchPrevious:(id)sender;
|
||||
- (void)switchNext:(id)sender;
|
||||
- (void)onClickMute:(id)sender;
|
||||
- (void)mediaControlLiveRefresh;
|
||||
- (void)didSliderTouchUpInside;
|
||||
- (void)slideCancelMediaControlHide;
|
||||
- (void)slideContinueMediaControlHide;
|
||||
|
@ -35,7 +36,8 @@
|
|||
- (id)initWithFrame:(CGRect)frame
|
||||
viewController:(UIViewController *)viewController
|
||||
playList:(NSArray *)playList
|
||||
isLoop:(BOOL)isLoop;
|
||||
isLoop:(BOOL)isLoop
|
||||
isLive:(BOOL)isLive;
|
||||
- (float)progressValue;
|
||||
- (void)updatePlayPauseBtn:(BOOL)isPlaying;
|
||||
- (void)updateMuteBtn:(BOOL)isMute;
|
||||
|
|
|
@ -26,10 +26,13 @@
|
|||
@property (nonatomic, strong) UIButton *muteButton;
|
||||
|
||||
@property (nonatomic, strong) UIButton *loopButton;
|
||||
@property (nonatomic, assign) BOOL isLoop;
|
||||
@property (nonatomic, strong) UIButton *listButton;
|
||||
@property (nonatomic, strong) UIButton *liveRefreshButton;
|
||||
|
||||
@property (nonatomic, strong) NSArray *playList;
|
||||
|
||||
@property (nonatomic, assign) BOOL isLoop;
|
||||
@property (nonatomic, assign) BOOL isLive;
|
||||
@end
|
||||
|
||||
@implementation RedMediaControl {
|
||||
|
@ -45,7 +48,8 @@
|
|||
- (id)initWithFrame:(CGRect)frame
|
||||
viewController:(UIViewController *)viewController
|
||||
playList:(NSArray *)playList
|
||||
isLoop:(BOOL)isLoop {
|
||||
isLoop:(BOOL)isLoop
|
||||
isLive:(BOOL)isLive {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
_viewController = viewController;
|
||||
|
@ -54,6 +58,7 @@
|
|||
self.playListIndex = 0;
|
||||
self.playList = playList;
|
||||
self.isLoop = isLoop;
|
||||
self.isLive = isLive;
|
||||
[self setupSubviews];
|
||||
[self startRefresh];
|
||||
|
||||
|
@ -71,56 +76,71 @@
|
|||
#define kTimeLabelWidth 50
|
||||
#define kTimeLabelHeight 30
|
||||
- (void)setupSubviews {
|
||||
if (!self.playButton) {
|
||||
self.playButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
[self.playButton setImage:[UIImage imageNamed:@"btn_player_pause"] forState:UIControlStateNormal];
|
||||
[self.playButton addTarget:self action:@selector(playAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.playButton];
|
||||
}
|
||||
[self.playButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.centerY.mas_equalTo(self);
|
||||
make.width.height.mas_equalTo(kPlayButtonWidth);
|
||||
}];
|
||||
|
||||
if (self.playList.count > 0) {
|
||||
if (!self.preButton) {
|
||||
self.preButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
[self.preButton setImage:[UIImage imageNamed:@"icon_pre"] forState:UIControlStateNormal];
|
||||
[self.preButton addTarget:self action:@selector(preAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.preButton];
|
||||
if (!_isLive) {
|
||||
if (!self.playButton) {
|
||||
self.playButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
[self.playButton setImage:[UIImage imageNamed:@"btn_player_pause"] forState:UIControlStateNormal];
|
||||
[self.playButton addTarget:self action:@selector(playAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.playButton];
|
||||
}
|
||||
self.preButton.enabled = (self.playListIndex > 0);
|
||||
[self.preButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.mas_equalTo(self);
|
||||
make.right.mas_equalTo(self.playButton.mas_left).offset(-20);
|
||||
[self.playButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.centerY.mas_equalTo(self);
|
||||
make.width.height.mas_equalTo(kPlayButtonWidth);
|
||||
}];
|
||||
if (!self.nextButton) {
|
||||
self.nextButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
[self.nextButton setImage:[UIImage imageNamed:@"icon_next"] forState:UIControlStateNormal];
|
||||
[self.nextButton addTarget:self action:@selector(nextAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.nextButton];
|
||||
|
||||
if (self.playList.count > 0) {
|
||||
if (!self.preButton) {
|
||||
self.preButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
[self.preButton setImage:[UIImage imageNamed:@"icon_pre"] forState:UIControlStateNormal];
|
||||
[self.preButton addTarget:self action:@selector(preAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.preButton];
|
||||
}
|
||||
self.preButton.enabled = (self.playListIndex > 0);
|
||||
[self.preButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.mas_equalTo(self);
|
||||
make.right.mas_equalTo(self.playButton.mas_left).offset(-20);
|
||||
make.width.height.mas_equalTo(kPlayButtonWidth);
|
||||
}];
|
||||
if (!self.nextButton) {
|
||||
self.nextButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
[self.nextButton setImage:[UIImage imageNamed:@"icon_next"] forState:UIControlStateNormal];
|
||||
[self.nextButton addTarget:self action:@selector(nextAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.nextButton];
|
||||
}
|
||||
self.nextButton.enabled = (self.playListIndex < self.playList.count - 1);
|
||||
[self.nextButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.mas_equalTo(self);
|
||||
make.left.mas_equalTo(self.playButton.mas_right).offset(20);
|
||||
make.width.height.mas_equalTo(kPlayButtonWidth);
|
||||
}];
|
||||
}
|
||||
self.nextButton.enabled = (self.playListIndex < self.playList.count - 1);
|
||||
[self.nextButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.mas_equalTo(self);
|
||||
make.left.mas_equalTo(self.playButton.mas_right).offset(20);
|
||||
} else { // Live refresh
|
||||
if (!self.liveRefreshButton) {
|
||||
self.liveRefreshButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
[self.liveRefreshButton setImage:[UIImage imageNamed:@"icon_refresh"] forState:UIControlStateNormal];
|
||||
[self.liveRefreshButton addTarget:self action:@selector(refreshButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.liveRefreshButton];
|
||||
}
|
||||
[self.liveRefreshButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.centerY.mas_equalTo(self);
|
||||
make.width.height.mas_equalTo(kPlayButtonWidth);
|
||||
}];
|
||||
}
|
||||
|
||||
if (!self.mediaProgressSlider) {
|
||||
self.mediaProgressSlider = [[UISlider alloc] initWithFrame:CGRectZero];
|
||||
self.mediaProgressSlider.maximumTrackTintColor = UIColor.grayColor;
|
||||
self.mediaProgressSlider.tintColor = UIColor.redColor;
|
||||
[self.mediaProgressSlider setThumbImage:[UIImage imageNamed:@"slider"] forState:UIControlStateNormal];
|
||||
[self addSubview:self.mediaProgressSlider];
|
||||
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideTouchDown) forControlEvents:UIControlEventTouchDown];
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideTouchUpInside) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideValueChanged) forControlEvents:UIControlEventValueChanged];
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideTouchUpOutside) forControlEvents:UIControlEventTouchUpOutside];
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideTouchCancel) forControlEvents:UIControlEventTouchCancel];
|
||||
if (!_isLive) {
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideTouchDown) forControlEvents:UIControlEventTouchDown];
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideTouchUpInside) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideValueChanged) forControlEvents:UIControlEventValueChanged];
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideTouchUpOutside) forControlEvents:UIControlEventTouchUpOutside];
|
||||
[self.mediaProgressSlider addTarget:self action:@selector(slideTouchCancel) forControlEvents:UIControlEventTouchCancel];
|
||||
} else {
|
||||
self.mediaProgressSlider.userInteractionEnabled = NO;
|
||||
}
|
||||
}
|
||||
[self.mediaProgressSlider mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(self);
|
||||
|
@ -184,56 +204,61 @@
|
|||
make.height.mas_equalTo(30);
|
||||
}];
|
||||
|
||||
|
||||
if (!self.listButton) {
|
||||
self.listButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
self.listButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
[self.listButton setImage:[UIImage imageNamed:@"list"] forState:UIControlStateNormal];
|
||||
[self.listButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
|
||||
if (self.playList.count == 0) {
|
||||
self.listButton.enabled = NO;
|
||||
if (!_isLive) {
|
||||
if (!self.listButton) {
|
||||
self.listButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
self.listButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
[self.listButton setImage:[UIImage imageNamed:@"list"] forState:UIControlStateNormal];
|
||||
if (self.playList.count == 0) {
|
||||
self.listButton.enabled = NO;
|
||||
}
|
||||
[self.listButton addTarget:self action:@selector(listButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.listButton];
|
||||
}
|
||||
[self.listButton addTarget:self action:@selector(listButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.listButton];
|
||||
}
|
||||
[self.listButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self).offset(-kSliderMargin);
|
||||
make.centerY.mas_equalTo(self.hudButton);
|
||||
make.width.mas_equalTo(20);
|
||||
make.height.mas_equalTo(20);
|
||||
}];
|
||||
[self.listButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self).offset(-kSliderMargin);
|
||||
make.centerY.mas_equalTo(self.hudButton);
|
||||
make.width.mas_equalTo(20);
|
||||
make.height.mas_equalTo(20);
|
||||
}];
|
||||
|
||||
if (!self.loopButton) {
|
||||
self.loopButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
self.loopButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
[self.loopButton setImage:[UIImage imageNamed:self.isLoop ? @"loop" : @"sequence"] forState:UIControlStateNormal];
|
||||
[self.loopButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
|
||||
[self.loopButton addTarget:self action:@selector(loopButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.loopButton];
|
||||
if (!self.loopButton) {
|
||||
self.loopButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
self.loopButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
[self.loopButton setImage:[UIImage imageNamed:self.isLoop ? @"loop" : @"sequence"] forState:UIControlStateNormal];
|
||||
[self.loopButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
|
||||
[self.loopButton addTarget:self action:@selector(loopButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.loopButton];
|
||||
}
|
||||
[self.loopButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self.listButton.mas_left).offset(-20);
|
||||
make.centerY.mas_equalTo(self.hudButton);
|
||||
make.width.mas_equalTo(20);
|
||||
make.height.mas_equalTo(20);
|
||||
}];
|
||||
|
||||
if (!self.speedButton) {
|
||||
self.speedButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
self.speedButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
[self.speedButton setTitle:@"1.0x" forState:UIControlStateNormal];
|
||||
[self.speedButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
|
||||
self.speedButton.titleLabel.font = [UIFont boldSystemFontOfSize:18];
|
||||
[self.speedButton addTarget:self action:@selector(speedButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.speedButton];
|
||||
}
|
||||
[self.speedButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self.loopButton.mas_left).offset(-10);
|
||||
make.centerY.mas_equalTo(self.hudButton);
|
||||
make.width.mas_equalTo(50);
|
||||
make.height.mas_equalTo(30);
|
||||
}];
|
||||
}
|
||||
[self.loopButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self.listButton.mas_left).offset(-20);
|
||||
make.centerY.mas_equalTo(self.hudButton);
|
||||
make.width.mas_equalTo(20);
|
||||
make.height.mas_equalTo(20);
|
||||
}];
|
||||
|
||||
if (!self.speedButton) {
|
||||
self.speedButton = [[UIButton alloc] initWithFrame:CGRectZero];
|
||||
self.speedButton.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
[self.speedButton setTitle:@"1.0x" forState:UIControlStateNormal];
|
||||
[self.speedButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
|
||||
self.speedButton.titleLabel.font = [UIFont boldSystemFontOfSize:18];
|
||||
[self.speedButton addTarget:self action:@selector(speedButtonClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:self.speedButton];
|
||||
}
|
||||
[self.speedButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.mas_equalTo(self.loopButton.mas_left).offset(-10);
|
||||
make.centerY.mas_equalTo(self.hudButton);
|
||||
make.width.mas_equalTo(50);
|
||||
make.height.mas_equalTo(30);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)refreshButtonClick:(UIButton *)sender {
|
||||
if ([self.delegatePlayer respondsToSelector:@selector(mediaControlLiveRefresh)]) {
|
||||
[self.delegatePlayer mediaControlLiveRefresh];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loopButtonClick:(UIButton *)sender {
|
||||
|
|
|
@ -8,19 +8,18 @@
|
|||
|
||||
import UIKit
|
||||
class RedAlertView: UIView {
|
||||
let urlDefault = "aHR0cDovL3Nucy12aWRlby1hbC54aHNjZG4uY29tL3NwZWN0cnVtLzAxZTI5NjRlNDE2YmUwNzcwMTgzNzAwMzgxMWI0ZTM5YzlfNTEzLm1wNA=="
|
||||
let urlVodDefault = "aHR0cDovL3Nucy12aWRlby1hbC54aHNjZG4uY29tL3NwZWN0cnVtLzAxZTI5NjRlNDE2YmUwNzcwMTgzNzAwMzgxMWI0ZTM5YzlfNTEzLm1wNA=="
|
||||
let urlLiveDefault = "aHR0cDovL2xpdmUtcGxheS54aHNjZG4uY29tL2xpdmUvNTY5MDcxNDQ3Mjc2ODQwMjY4LmZsdg=="
|
||||
let jsonDefault = "ewogICAgInN0cmVhbSI6IHsKICAgICAgICAiYXYxIjogW10sCiAgICAgICAgImgyNjUiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJtYXN0ZXJfdXJsIjogImh0dHA6Ly9zbnMtdmlkZW8tYmQueGhzY2RuLmNvbS9zdHJlYW0vMTEwLzgvMDFlNTgzY2I2ZTBmZWQ1YTAxMDM3MDAzOGM4YWQ2NTM3OV84Lm1wNCIsCiAgICAgICAgICAgICAgICAid2VpZ2h0IjogNjIsCiAgICAgICAgICAgICAgICAiYmFja3VwX3VybHMiOiBbCiAgICAgICAgICAgICAgICAgICAgImh0dHA6Ly9zbnMtdmlkZW8tcWMueGhzY2RuLmNvbS9zdHJlYW0vMTEwLzgvMDFlNTgzY2I2ZTBmZWQ1YTAxMDM3MDAzOGM4YWQ2NTM3OV84Lm1wND9zaWduPTgxMzQyZGQwZGM1YjViYmViY2I0N2NmYTVmNzQ1YmY1JnQ9NjViNTI3NTQiLAogICAgICAgICAgICAgICAgICAgICJodHRwOi8vc25zLXZpZGVvLWh3Lnhoc2Nkbi5jb20vc3RyZWFtLzExMC84LzAxZTU4M2NiNmUwZmVkNWEwMTAzNzAwMzhjOGFkNjUzNzlfOC5tcDQiLAogICAgICAgICAgICAgICAgICAgICJodHRwOi8vc25zLXZpZGVvLWFsLnhoc2Nkbi5jb20vc3RyZWFtLzExMC84LzAxZTU4M2NiNmUwZmVkNWEwMTAzNzAwMzhjOGFkNjUzNzlfOC5tcDQiLAogICAgICAgICAgICAgICAgICAgICJodHRwOi8vc25zLXZpZGVvLWh3Lnhoc2Nkbi5uZXQvc3RyZWFtLzExMC84LzAxZTU4M2NiNmUwZmVkNWEwMTAzNzAwMzhjOGFkNjUzNzlfOC5tcDQiCiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgImhlaWdodCI6IDk2MCwKICAgICAgICAgICAgICAgICJ3aWR0aCI6IDcyMCwKICAgICAgICAgICAgICAgICJhdmdfYml0cmF0ZSI6IDM4MDYzNAogICAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiaDI2NCI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgIm1hc3Rlcl91cmwiOiAiaHR0cDovL3Nucy12aWRlby1iZC54aHNjZG4uY29tL3N0cmVhbS8xMTAvMjU4LzAxZTU4M2NiNmUwZmVkNWEwMTAzNzAwMzhjOTVmODg0MmJfMjU4Lm1wNCIsCiAgICAgICAgICAgICAgICAid2VpZ2h0IjogNjIsCiAgICAgICAgICAgICAgICAiYmFja3VwX3VybHMiOiBbCiAgICAgICAgICAgICAgICAgICAgImh0dHA6Ly9zbnMtdmlkZW8tcWMueGhzY2RuLmNvbS9zdHJlYW0vMTEwLzI1OC8wMWU1ODNjYjZlMGZlZDVhMDEwMzcwMDM4Yzk1Zjg4NDJiXzI1OC5tcDQ/c2lnbj0yOGUxMzk3OWE2MGJhMjRiODk4ZGE0NzEyM2M5NmRkMiZ0PTY1YjUyNzU0IiwKICAgICAgICAgICAgICAgICAgICAiaHR0cDovL3Nucy12aWRlby1ody54aHNjZG4uY29tL3N0cmVhbS8xMTAvMjU4LzAxZTU4M2NiNmUwZmVkNWEwMTAzNzAwMzhjOTVmODg0MmJfMjU4Lm1wNCIsCiAgICAgICAgICAgICAgICAgICAgImh0dHA6Ly9zbnMtdmlkZW8tYWwueGhzY2RuLmNvbS9zdHJlYW0vMTEwLzI1OC8wMWU1ODNjYjZlMGZlZDVhMDEwMzcwMDM4Yzk1Zjg4NDJiXzI1OC5tcDQiLAogICAgICAgICAgICAgICAgICAgICJodHRwOi8vc25zLXZpZGVvLWh3Lnhoc2Nkbi5uZXQvc3RyZWFtLzExMC8yNTgvMDFlNTgzY2I2ZTBmZWQ1YTAxMDM3MDAzOGM5NWY4ODQyYl8yNTgubXA0IgogICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICJoZWlnaHQiOiA5NjAsCiAgICAgICAgICAgICAgICAid2lkdGgiOiA3MjAsCiAgICAgICAgICAgICAgICAiYXZnX2JpdHJhdGUiOiA1ODA4MTQKICAgICAgICAgICAgfQogICAgICAgIF0KICAgIH0KfQ=="
|
||||
var playButtonTapped: ((String, Bool) -> Void)?
|
||||
var closeButtonTapped: (() -> Void)?
|
||||
|
||||
var isLive = false
|
||||
let titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .boldSystemFont(ofSize: 18)
|
||||
label.text = "Enter URL or JSON"
|
||||
label.textAlignment = .center
|
||||
label.heightAnchor.constraint(equalToConstant: 20).isActive = true
|
||||
return label
|
||||
}()
|
||||
}()
|
||||
|
||||
let urlTextView: UITextView = {
|
||||
let textView = UITextView()
|
||||
|
@ -29,7 +28,6 @@ class RedAlertView: UIView {
|
|||
textView.layer.borderWidth = 1
|
||||
textView.layer.borderColor = UIColor.gray.cgColor
|
||||
textView.layer.cornerRadius = 5
|
||||
textView.heightAnchor.constraint(equalToConstant: 60).isActive = true
|
||||
|
||||
return textView
|
||||
}()
|
||||
|
@ -41,7 +39,6 @@ class RedAlertView: UIView {
|
|||
textView.layer.borderWidth = 1
|
||||
textView.layer.borderColor = UIColor.gray.cgColor
|
||||
textView.layer.cornerRadius = 5
|
||||
textView.heightAnchor.constraint(equalToConstant: 140).isActive = true
|
||||
return textView
|
||||
}()
|
||||
|
||||
|
@ -94,41 +91,52 @@ class RedAlertView: UIView {
|
|||
return button
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
public init(frame: CGRect, isLive: Bool) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.isLive = isLive
|
||||
self.backgroundColor = .systemBackground
|
||||
self.layer.cornerRadius = 10
|
||||
self.layer.shadowColor = UIColor.lightGray.cgColor
|
||||
self.layer.shadowOffset = CGSize(width: 0, height: 1)
|
||||
self.layer.shadowOpacity = 0.3
|
||||
self.layer.shadowRadius = 4.0
|
||||
let stackViewH1 = UIStackView(arrangedSubviews: [urlButton, jsonButton, clearButton])
|
||||
let stackViewH1 = UIStackView(arrangedSubviews: isLive ? [urlButton, clearButton] : [urlButton, jsonButton, clearButton])
|
||||
let stackViewH2 = UIStackView(arrangedSubviews: [closeButton, playButton])
|
||||
let stackView = UIStackView(arrangedSubviews: isLive ? [titleLabel, urlTextView, stackViewH1, stackViewH2] : [titleLabel, urlTextView, jsonTextView, stackViewH1, stackViewH2])
|
||||
|
||||
stackViewH1.axis = .horizontal
|
||||
stackViewH1.distribution = .fillEqually
|
||||
stackViewH1.spacing = 10
|
||||
stackViewH1.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
let stackViewH2 = UIStackView(arrangedSubviews: [closeButton, playButton])
|
||||
stackViewH2.axis = .horizontal
|
||||
stackViewH2.distribution = .fillEqually
|
||||
stackViewH2.spacing = 10
|
||||
stackViewH2.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
let stackView = UIStackView(arrangedSubviews: [titleLabel, urlTextView, jsonTextView, stackViewH1, stackViewH2])
|
||||
stackView.axis = .vertical
|
||||
stackView.distribution = .fillProportionally
|
||||
stackView.spacing = 10
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.addSubview(stackView)
|
||||
|
||||
if isLive {
|
||||
titleLabel.text = "Enter Live URL"
|
||||
urlTextView.heightAnchor.constraint(equalToConstant: 200).isActive = true
|
||||
} else {
|
||||
titleLabel.text = "Enter VOD URL or JSON"
|
||||
urlTextView.heightAnchor.constraint(equalToConstant: 60).isActive = true
|
||||
jsonTextView.heightAnchor.constraint(equalToConstant: 140).isActive = true
|
||||
}
|
||||
titleLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.topAnchor.constraint(equalTo: self.topAnchor, constant: 10),
|
||||
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -10),
|
||||
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10),
|
||||
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -10)
|
||||
])
|
||||
|
||||
|
||||
urlTextView.delegate = self
|
||||
jsonTextView.delegate = self
|
||||
urlButton.addTarget(self, action: #selector(urlButtonAction), for: .touchUpInside)
|
||||
|
@ -147,7 +155,7 @@ class RedAlertView: UIView {
|
|||
|
||||
@objc func urlButtonAction() {
|
||||
disableInput(textView: jsonTextView, content: "Please clear the JSON field first")
|
||||
enableInput(textView: urlTextView, content: RedMediaUtil.decodeBase64(base64EncodedString: urlDefault) ?? "")
|
||||
enableInput(textView: urlTextView, content: RedMediaUtil.decodeBase64(base64EncodedString: isLive ? urlLiveDefault : urlVodDefault) ?? "")
|
||||
}
|
||||
|
||||
@objc func jsonButtonAction() {
|
||||
|
|
|
@ -245,7 +245,7 @@ open class RedFlowViewController: UIViewController, RedFlowLayoutDelegate, UICol
|
|||
videoDictArray.append(videoDict)
|
||||
}
|
||||
|
||||
RedDemoPlayerViewController.present(from: self, withTitle: "", url: playUrl, isJson: item.isJson, playList: videoDictArray, playListIndex: indexPath.item, completion: nil) {
|
||||
RedDemoPlayerViewController.present(from: self, withTitle: "", url: playUrl, isJson: item.isJson, isLive: false, playList: videoDictArray, playListIndex: indexPath.item, completion: nil) {
|
||||
self.playingCell = nil
|
||||
self.scrollViewEndDecelerating()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue