1668081540
SwiftySound is a simple library that lets you deal with Swift sounds easily.
Static methods
Sound.play(file: "dog.wav")
Sound.play(url: fileURL)
More advanced example:
Sound.play(file: "dog", fileExtension: "wav", numberOfLoops: 2)
The above will play the sound three times.
Specify a negative number of loops to play the sound continously in an infinite loop:
Sound.play(file: "dog", fileExtension: "wav", numberOfLoops: -1)
Stop currently playing sounds:
Sound.stopAll()
Enable/disable all sounds:
Sound.enabled = true
Sound.enabled = false
The value of Sound.enabled
property will be automatically persisted in UserDefaults
and restored on the next launch of your app.
Change sound categories. SwiftySound provides a simple way of changing sound category:
Sound.category = .ambient
This changes the category of the underlying shared AVAudioSession
instance. The default value is SoundCategory.ambient
. Due to AVAudioSession
architecture, this property is not available on macOS.
Creating instances of Sound class
You can also create an instance of a Sound class and store it somewhere in your app.
let mySound = Sound(url: fileURL)
mySound.play()
Creating an instance has more benefits like the ability to adjust the volume and playback callbacks.
Change the volume
You can change the volume of each Sound instance.
mySound.volume = 0.5
The value of volume property should be between 0.0 and 1.0, where 1.0 is the maximum.
Callbacks
You can pass a callback to the play
method. It will be played after the sound finished playing. For looped sounds, the callback will be called once after the last loop has been played.
mySound.play { completed in
print("completed: \(completed)")
}
The callback is not called if the sound was stopped, interrupted or in case of a playback error.
For Xcode 8 and Swift 3 support, please use SwiftySound version 0.7.0
. For Xcode 9 and Swift 4 support, please use SwiftySound version 1.0.0
.
CocoaPods is a dependency manager which automates and simplifies the process of using third-party libraries in your projects. See the Get Started section for more details.
platform :ios, '8.0'
use_frameworks!
pod 'SwiftySound'
Carthage is a lightweight dependency manager for Swift and Objective-C. It leverages CocoaTouch modules and is less invasive than CocoaPods.
To install with carthage, follow the instruction on Carthage
github "adamcichy/SwiftySound"
The Swift Package Manager is a tool for managing the distribution of Swift code. Just add the url of this repo to your Package.swift
file as a dependency:
import PackageDescription
let package = Package(
name: "YourPackage",
dependencies: [
.Package(url: "https://github.com/adamcichy/SwiftySound.git",
majorVersion: 0)
]
)
Then run swift build
and wait for SPM to install SwiftySound.
Drop the Sound.swift
file into your project, link against AVFoundation.framework
and you are ready to go.
Author: Adamcichy
Source Code: https://github.com/adamcichy/SwiftySound
License: MIT license
1667095020
A video player for iOS, based on AVPlayer, support the horizontal, vertical screen. support adjust volume, brightness and seek by slide, support subtitles.
You can support the project by checking out our sponsor page. It takes only one click:
This advert was placed by GitAds
Swift | podfile |
---|---|
Swift 5.0 | pod 'BMPlayer', '~> 1.3.0' |
Swift 4.2 | pod 'BMPlayer', '~> 1.2.0' |
Swift 4.0 | pod 'BMPlayer', '~> 1.0.0' |
Swift 3.0 | pod 'BMPlayer', '~> 0.9.1' |
Swift 2.2 | pod 'BMPlayer', '~> 0.3.3' |
To test the experimental caching support with VIMediaCache, use
pod 'BMPlayer/CacheSupport', :git => 'https://github.com/BrikerMan/BMPlayer.git'
Add BMPlayer
in your Cartfile.
github "BrikerMan/BMPlayer"
Run carthage to build the framework and drag the built BMPlayer.framework into your Xcode project.
run pod install
at Example
folder before run the demo.
Please add the View controller-based status bar appearance
field in info.plist and change it to NO
Direct drag IB to UIView, the aspect ratio for the 16:9 constraint (priority to 750, lower than the 1000 line), the code section only needs to achieve. See more detail on the demo.
import BMPlayer
player.playWithURL(URL(string: url)!)
player.backBlock = { [unowned self] (isFullScreen) in
if isFullScreen == true { return }
let _ = self.navigationController?.popViewController(animated: true)
}
import BMPlayer
player = BMPlayer()
view.addSubview(player)
player.snp.makeConstraints { (make) in
make.top.equalTo(self.view).offset(20)
make.left.right.equalTo(self.view)
// Note here, the aspect ratio 16:9 priority is lower than 1000 on the line, because the 4S iPhone aspect ratio is not 16:9
make.height.equalTo(player.snp.width).multipliedBy(9.0/16.0).priority(750)
}
// Back button event
player.backBlock = { [unowned self] (isFullScreen) in
if isFullScreen == true { return }
let _ = self.navigationController?.popViewController(animated: true)
}
let asset = BMPlayerResource(url: URL(string: "http://baobab.wdjcdn.com/14525705791193.mp4")!,
name: "风格互换:原来你我相爱")
player.setVideo(resource: asset)
let res0 = BMPlayerResourceDefinition(url: URL(string: "http://baobab.wdjcdn.com/1457162012752491010143.mp4")!,
definition: "高清")
let res1 = BMPlayerResourceDefinition(url: URL(string: "http://baobab.wdjcdn.com/1457162012752491010143.mp4")!,
definition: "标清")
let asset = BMPlayerResource(name: "周末号外丨中国第一高楼",
definitions: [res0, res1],
cover: URL(string: "http://img.wdjimg.com/image/video/447f973848167ee5e44b67c8d4df9839_0_0.jpeg"))
player.setVideo(resource: asset)
let header = ["User-Agent":"BMPlayer"]
let options = ["AVURLAssetHTTPHeaderFieldsKey":header]
let definition = BMPlayerResourceDefinition(url: URL(string: "http://baobab.wdjcdn.com/1457162012752491010143.mp4")!,
definition: "高清",
options: options)
let asset = BMPlayerResource(name: "Video Name",
definitions: [definition])
See more detail from the Example project
//Listen to when the player is playing or stopped
player?.playStateDidChange = { (isPlaying: Bool) in
print("playStateDidChange \(isPlaying)")
}
//Listen to when the play time changes
player?.playTimeDidChange = { (currentTime: TimeInterval, totalTime: TimeInterval) in
print("playTimeDidChange currentTime: \(currentTime) totalTime: \(totalTime)")
}
protocol BMPlayerDelegate {
func bmPlayer(player: BMPlayer ,playerStateDidChange state: BMPlayerState) { }
func bmPlayer(player: BMPlayer ,loadedTimeDidChange loadedDuration: TimeInterval, totalDuration: TimeInterval) { }
func bmPlayer(player: BMPlayer ,playTimeDidChange currentTime : TimeInterval, totalTime: TimeInterval) { }
func bmPlayer(player: BMPlayer ,playerIsPlaying playing: Bool) { }
}
Needs to change before the player alloc.
// should print log, default false
BMPlayerConf.allowLog = false
// should auto play, default true
BMPlayerConf.shouldAutoPlay = true
// main tint color, default whiteColor
BMPlayerConf.tintColor = UIColor.whiteColor()
// options to show header view (which include the back button, title and definition change button) , default .Always,options: .Always, .HorizantalOnly and .None
BMPlayerConf.topBarShowInCase = .Always
// loader type, see detail:https://github.com/ninjaprox/NVActivityIndicatorView
BMPlayerConf.loaderType = NVActivityIndicatorType.BallRotateChase
// enable setting the brightness by touch gesture in the player
BMPlayerConf.enableBrightnessGestures = true
// enable setting the volume by touch gesture in the player
BMPlayerConf.enableVolumeGestures = true
// enable setting the playtime by touch gesture in the player
BMPlayerConf.enablePlaytimeGestures = true
BMPlayerControlView
to create your personal control UI, check the Example.BMPlayerLayer
with your own player control view.This project heavily reference the Objective-C version of this project ZFPlayer, thanks for the generous help of ZFPlayer's author.
You are welcome to fork and submit pull requests.
Author: BrikerMan
Source Code: https://github.com/BrikerMan/BMPlayer
License: MIT license
1667013960
Player
is a simple iOS video player library written in Swift.
Need a different version of Swift?
5.0
- Target your Podfile to the latest release or master4.2
- Target your Podfile to the swift4.2
branch4.0
- Target your Podfile to the swift4.0
branchQuick Start
Player
is available for installation using the Cocoa dependency manager CocoaPods. Alternatively, you can simply copy the Player.swift
file into your Xcode project.
# CocoaPods
pod "Player", "~> 0.13.2"
# Carthage
github "piemonte/Player" ~> 0.13.2
The sample project provides an example of how to integrate Player
, otherwise you can follow these steps.
Allocate and add the Player
controller to your view hierarchy.
self.player = Player()
self.player.playerDelegate = self
self.player.playbackDelegate = self
self.player.view.frame = self.view.bounds
self.addChild(self.player)
self.view.addSubview(self.player.view)
self.player.didMove(toParent: self)
Provide the file path to the resource you would like to play locally or stream. Ensure you're including the file extension.
let videoUrl: URL = // file or http url
self.player.url = videoUrl
play/pause
self.player.playFromBeginning()
Adjust the fill mode for the video, if needed.
self.player.fillMode = .resizeAspectFit
Display video playback progress, if needed.
extension ViewController: PlayerPlaybackDelegate {
public func playerPlaybackWillStartFromBeginning(_ player: Player) {
}
public func playerPlaybackDidEnd(_ player: Player) {
}
public func playerCurrentTimeDidChange(_ player: Player) {
let fraction = Double(player.currentTime) / Double(player.maximumDuration)
self._playbackViewController?.setProgress(progress: CGFloat(fraction), animated: true)
}
public func playerPlaybackWillLoop(_ player: Player) {
self. _playbackViewController?.reset()
}
}
You can find the docs here. Documentation is generated with jazzy and hosted on GitHub-Pages.
Author: Piemonte
Source Code: https://github.com/piemonte/Player
License: MIT license
1666515720
A powerful and completely customizable media player for iOS.
Features
NSNotification
s.Installation
Add the following line in your Podfile
.
pod "MobilePlayer"
Add the following line to your Cartfile.
github "mobileplayer/mobileplayer-ios"
Usage
import MobilePlayer
let playerVC = MobilePlayerViewController(contentURL: videoURL)
playerVC.title = "Vanilla Player - \(videoTitle)"
playerVC.activityItems = [videoURL] // Check the documentation for more information.
presentMoviePlayerViewControllerAnimated(playerVC)
Customization
Initialize using local configuration file
let bundle = NSBundle.mainBundle()
let config = MobilePlayerConfig(fileURL: bundle.URLForResource(
"WatermarkedPlayer",
withExtension: "json")!)
let playerVC = MobilePlayerViewController(
contentURL: videoURL,
config: config)
playerVC.title = "Watermarked Player - \(videoTitle)"
playerVC.activityItems = [videoURL]
present(playerVC, animated: true, completion: nil)
Initialize using remote configuration data
guard let configURL = NSURL(string: "https://goo.gl/c73ANK") else { return }
let playerVC = MobilePlayerViewController(
contentURL: videoURL,
config: MobilePlayerConfig(fileURL: configURL))
playerVC.title = "Watermarked Player - \(videoTitle)"
playerVC.activityItems = [videoURL]
present(playerVC, animated: true, completion: nil)
Configuration data
{
"watermark": {
"image": "MovielalaLogo"
}
}
Without a configuration file URL
let playerVC = MobilePlayerViewController(
contentURL: videoURL,
config: MobilePlayerConfig(
dictionary: ["watermark": ["image": "MovielalaLogo"]]))
playerVC.title = "Watermarked Player - \(videoTitle)"
playerVC.activityItems = [videoURL]
present(playerVC, animated: true, completion: nil)
Result
{
"watermark": {
"image": "MovielalaLogo",
"position": "topRight"
},
"topBar": {
"backgroundColor": ["#a60500b0", "#a60500a0"],
"elements": [
{
"type": "button",
"identifier": "close"
},
{
"type": "slider",
"identifier": "playback",
"trackHeight": 6,
"trackCornerRadius": 3,
"minimumTrackTintColor": "#eee",
"availableTrackTintColor": "#9e9b9a",
"maximumTrackTintColor": "#cccccc",
"thumbTintColor": "#f9f9f9",
"thumbBorderWidth": 1,
"thumbBorderColor": "#fff",
"marginRight": 4
}
]
},
"bottomBar": {
"backgroundColor": ["#a60500a0", "#a60500b0"],
"elements": [
{
"type": "label",
"text": "Now Watching",
"font": "Baskerville",
"size": 12,
"marginLeft": 8,
"marginRight": 8
},
{
"type": "label",
"identifier": "title",
"size": 14
},
{
"type": "button",
"identifier": "action"
},
{
"type": "toggleButton",
"identifier": "play"
}
]
}
}
For all available identifier
s, check the documentation or here. Same identifier
value shouldn't be used more than once in a single configuration.
Result
Example designs
let playerVC = MobilePlayerViewController(contentURL: videoURL)
playerVC.title = videoTitle
playerVC.activityItems = [videoURL]
present(playerVC, animated: true, completion: nil)
ProductStore.getProduct("1", success: { product in
guard let product = product else { return }
playerVC.showOverlayViewController(
BuyOverlayViewController(product: product))
})
let playerVC = MobilePlayerViewController(contentURL: videoURL)
playerVC.title = videoTitle
playerVC.activityItems = [videoURL]
present(playerVC, animated: true, completion: nil)
ProductStore.getProductPlacementsForVideo(
videoID,
success: { productPlacements in
guard let productPlacements = productPlacements else { return }
for placement in productPlacements {
ProductStore.getProduct(placement.productID, success: { product in
guard let product = product else { return }
playerVC.showOverlayViewController(
BuyOverlayViewController(product: product),
startingAtTime: placement.startTime,
forDuration: placement.duration)
})
}
})
let playerVC = MobilePlayerViewController(
contentURL: videoURL,
prerollViewController: PrerollOverlayViewController())
playerVC.title = videoTitle
playerVC.activityItems = [videoURL]
present(playerVC, animated: true, completion: nil)
let playerVC = MobilePlayerViewController(
contentURL: videoURL,
pauseOverlayViewController: PauseOverlayViewController())
playerVC.title = videoTitle
playerVC.activityItems = [videoURL]
present(playerVC, animated: true, completion: nil)
Result
Example designs
let playerVC = MobilePlayerViewController(
contentURL: videoURL,
postrollViewController: PostrollOverlayViewController())
playerVC.title = videoTitle
playerVC.activityItems = [videoURL]
present(playerVC, animated: true, completion: nil)
Result
Example designs
Examples
After cloning the repo, run the MobilePlayerExamples
target to see examples for many use cases.
Documentation
The entire documentation for the library can be found here.
Author: sahin
Source Code: https://github.com/sahin/mobileplayer-ios
License: View license
1658329228
LosslessCut
The swiss army knife of lossless video/audio editing
LosslessCut aims to be the ultimate cross platform FFmpeg GUI for extremely fast and lossless operations on video, audio, subtitle and other related media files. The main feature is lossless trimming and cutting of video and audio files, which is great for saving space by rough-cutting your large video files taken from a video camera, GoPro, drone, etc. It lets you quickly extract the good parts from your videos and discard many gigabytes of data without doing a slow re-encode and thereby losing quality. Or you can add a music or subtitle track to your video without needing to encode. Everything is extremely fast because it does an almost direct data copy, fueled by the awesome FFmpeg which does all the grunt work.
First export each track as individual files. Then use Handbrake or similar to re-encode the audio file. Then use the Tools->Merge
in LosslessCut to merge the original video stream with your Handbrake output (or drag it into your original LosslessCut video to include it as a new track.)
Tip: you can use LosslessCut in multiple passes in order to achieve separate trimming of individual tracks:
If you want to support my continued work on LosslessCut, and you want the advantage of a secure and simple installation process with automatic updates, consider getting it from your favorite store:
If you prefer to download the executables manually, this will of course always be free:
If you find LosslessCut useful, I'm very thankful for donations.
They have exactly the same in-app features, except for a few platform limitations. Apple doesn't allow opening VOB files with App Store apps. Apple App Store apps need to prompt for output directory. LosslessCut version in the App Stores is a few versions behind the GitHub version, because I want to be sure that the new versions work perfectly before releasing in the App Stores. GitHub version can contain new, untested features and may contain some bugs. I consider the newest GitHub versions to be a public "beta" test.
Since LosslessCut is based on Chromium and uses the HTML5 video player, not all FFmpeg supported formats will be supported smoothly. The following formats/codecs should generally work: MP4, MOV, WebM, MKV, OGG, WAV, MP3, AAC, H264, Theora, VP8, VP9 For more information about supported formats / codecs, see https://www.chromium.org/audio-video.
Unsupported files can still be converted to a supported format/codec from the File
menu. (Try the "fastest" option first.) A low quality version of the file (with/without audio) will then be created and opened in the player. The actual cut/export operation will still be performed on the original file, so it will be lossless. This allows for potentially opening any file that FFmpeg is able to decode.
How to add a thumbnail to an MP4
How to add multi-language audio to a video
Your video here? If you would like to make a video showing off LosslessCut use cases, let me know and I can link it here!
Separate files
to Merge cuts
.Working dir unset
button (default: Input file folder)Tracks
button to customise and/or add new tracks from other files.Export
button (or E) to show an overview with export options.Export
again to confirm the exportKeyframe cut
vs Normal cut
. You may need to try both, depending on the video. ffmpeg also has documentation about these two seek/cut modes. Keyframe cut
means -ss
before -i
and Normal cut
means -ss
after -i
.tmcd
, fdsc
and gpmd
added by GoPro). These can however be losslessly exported to separate files.FATAL:setuid_sandbox_host.cc(157)] The SUID sandbox helper binary was found, but is not configured correctly. Rather than run without sandboxing I'm aborting now.
, try to run it as ./lossless-cut --no-sandbox
. See #258.exe
and .zip
downloads? .exe
will self-extract on startup to a temp folder and is therefore slower to start up. .zip
must be extracted manually but is very fast to start up.--disable-gpu
- See 781.If any other problem, check Known issues, or please search for existing issues before you file an issue here on GitHub. You can check the developer tools for any errors or clues. Menu: Tools
-> Toggle Developer Tools
. Also you are welcome to hang out on Discord 🤗
segment start
, segment end
, label
.segment start
and segment end
are expressed in seconds or left empty. Empty segment end
means segment ends at the duration of the video.,
to separate the fields (not semicolon ;
),56.9568,First segment starting at 0
70,842.33,"Another quoted label"
1234,,Last segment
LosslessCut only has limited support for automation through the CLI. Note that these examples assume that you have set up LosslessCut in your PATH
environment. Alternatively you can run it like this:
# First navigate to the folder containing the LosslessCut app
cd /path/to/directory/containing/app
# On Linux:
./LosslessCut arguments
# On Windows:
./LosslessCut.exe arguments
# On MacOS:
./LosslessCut.app/Contents/MacOS/LosslessCut arguments
LosslessCut file1.mp4 file2.mkv
See available settings. Note that this is subject to change in newer versions. ⚠️ If you specify incorrect values it could corrupt your configuration file. You may use JSON or JSON5:
LosslessCut --settings-json '{captureFormat:"jpeg", "keyframeCut":true}'
See the developer notes.
This project is maintained by me alone. The project will always remain free and open source, but if it's useful for you, consider supporting me. :) It will give me extra motivation to improve it. Or even better donate to ffmpeg because they are doing the world a big favor 🙏
Made with ❤️ in 🇳🇴
Follow me on GitHub, YouTube, IG, Twitter for more awesome content!
Thanks to my supporters and everyone who purchased LosslessCut!
Author: mifi
Source Code: https://github.com/mifi/lossless-cut
License: GPL-2.0 license
1657883160
The swiss army knife of lossless video/audio editing
LosslessCut aims to be the ultimate cross platform FFmpeg GUI for extremely fast and lossless operations on video, audio, subtitle and other related media files. The main feature is lossless trimming and cutting of video and audio files, which is great for saving space by rough-cutting your large video files taken from a video camera, GoPro, drone, etc. It lets you quickly extract the good parts from your videos and discard many gigabytes of data without doing a slow re-encode and thereby losing quality. Or you can add a music or subtitle track to your video without needing to encode. Everything is extremely fast because it does an almost direct data copy, fueled by the awesome FFmpeg which does all the grunt work.
First export each track as individual files. Then use Handbrake or similar to re-encode the audio file. Then use the Tools->Merge
in LosslessCut to merge the original video stream with your Handbrake output (or drag it into your original LosslessCut video to include it as a new track.)
Tip: you can use LosslessCut in multiple passes in order to achieve separate trimming of individual tracks:
If you want to support my continued work on LosslessCut, and you want the advantage of a secure and simple installation process with automatic updates, consider getting it from your favorite store:
If you prefer to download the executables manually, this will of course always be free:
If you find LosslessCut useful, I'm very thankful for donations.
They have exactly the same in-app features, except for a few platform limitations. Apple doesn't allow opening VOB files with App Store apps. Apple App Store apps need to prompt for output directory. LosslessCut version in the App Stores is a few versions behind the GitHub version, because I want to be sure that the new versions work perfectly before releasing in the App Stores. GitHub version can contain new, untested features and may contain some bugs. I consider the newest GitHub versions to be a public "beta" test.
Since LosslessCut is based on Chromium and uses the HTML5 video player, not all FFmpeg supported formats will be supported smoothly. The following formats/codecs should generally work: MP4, MOV, WebM, MKV, OGG, WAV, MP3, AAC, H264, Theora, VP8, VP9 For more information about supported formats / codecs, see https://www.chromium.org/audio-video.
Unsupported files can still be converted to a supported format/codec from the File
menu. (Try the "fastest" option first.) A low quality version of the file (with/without audio) will then be created and opened in the player. The actual cut/export operation will still be performed on the original file, so it will be lossless. This allows for potentially opening any file that FFmpeg is able to decode.
How to add a thumbnail to an MP4
How to add multi-language audio to a video
Your video here? If you would like to make a video showing off LosslessCut use cases, let me know and I can link it here!
Separate files
to Merge cuts
.Working dir unset
button (default: Input file folder)Tracks
button to customise and/or add new tracks from other files.Export
button (or E) to show an overview with export options.Export
again to confirm the exportKeyframe cut
vs Normal cut
. You may need to try both, depending on the video. ffmpeg also has documentation about these two seek/cut modes. Keyframe cut
means -ss
before -i
and Normal cut
means -ss
after -i
.tmcd
, fdsc
and gpmd
added by GoPro). These can however be losslessly exported to separate files.FATAL:setuid_sandbox_host.cc(157)] The SUID sandbox helper binary was found, but is not configured correctly. Rather than run without sandboxing I'm aborting now.
, try to run it as ./lossless-cut --no-sandbox
. See #258.exe
and .zip
downloads? .exe
will self-extract on startup to a temp folder and is therefore slower to start up. .zip
must be extracted manually but is very fast to start up.--disable-gpu
- See 781.If any other problem, check Known issues, or please search for existing issues before you file an issue here on GitHub. You can check the developer tools for any errors or clues. Menu: Tools
-> Toggle Developer Tools
. Also you are welcome to hang out on Discord 🤗
segment start
, segment end
, label
.segment start
and segment end
are expressed in seconds or left empty. Empty segment end
means segment ends at the duration of the video.,
to separate the fields (not semicolon ;
),56.9568,First segment starting at 0
70,842.33,"Another quoted label"
1234,,Last segment
Note that these exampels assume that you have set up LosslessCut in your PATH
environment. Alternatively you can run it like this:
# First navigate to the folder containing the LosslessCut app
cd /path/to/directory/containing/app
# On Linux:
./LosslessCut arguments
# On Windows:
./LosslessCut.exe arguments
# On MacOS:
./LosslessCut.app/Contents/MacOS/LosslessCut arguments
LosslessCut file1.mp4 file2.mkv
See available settings. Note that this is subject to change in newer versions. ⚠️ If you specify incorrect values it could corrupt your configuration file. You may use JSON or JSON5:
LosslessCut --settings-json '{captureFormat:"jpeg", "keyframeCut":true}'
See the developer notes.
This project is maintained by me alone. The project will always remain free and open source, but if it's useful for you, consider supporting me. :) It will give me extra motivation to improve it. Or even better donate to ffmpeg because they are doing the world a big favor 🙏
Made with ❤️ in 🇳🇴
Follow me on GitHub, YouTube, IG, Twitter for more awesome content!
Thanks to my supporters and everyone who purchased LosslessCut!
Author: Mifi
Source Code: https://github.com/mifi/lossless-cut
License: GPL-2.0 license
1655362860
Video player for flutter web & mobile devices, pod player supports playing video from `Youtube` and `Vimeo`
pod player is a simple and easy-to-use video player. Its video controls are similar to Youtube player (with customizable controls) and also can play videos from Youtube
and Vimeo
(By providing url/video_id).
This plugin built upon flutter's official video_player
plugin
PLATFORM | AVAILABLE |
---|---|
Android | ✅ |
IOS | ✅ |
WEB | ✅ |
youtube
videos (using video URL or ID)vimeo
videos (using video ID)Double tap
to seek video.playback speed
Change video quality
(for vimeo and youtube)Double tap on Video player to enable/disable fullscreen
Mute/unmute
volume
Video player integration with keyboard
SPACE
play/pause videoM
mute/unMute videoF
enable/disable fullscreenESC
enable/disable fullscreen->
seek video forward<-
seek video backwardDouble tap on video (enable/diables fullscreen)
Change quality and playback speed | Control video from any where |
---|---|
![]() | ![]() |
with overlay | without overlay (alwaysShowProgressBar = true) |
---|---|
![]() | ![]() |
On Double tap | Custom progress bar |
---|---|
![]() | ![]() |
In your pubspec.yaml
file within your Flutter Project:
dependencies:
pod_player: <latest_version>
If you are using network-based videos, ensure that the following permission is present in your Android Manifest file, located in <project root>/android/app/src/main/AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET"/>
If you need to access videos using http (rather than https) URLs.
Located inside application tag
<application
- - -
- - - - - -
android:usesCleartextTraffic="true"
Add permissions to your app's Info.plist file,
located in <project root>/ios/Runner/Info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
if u are using youtube
or vimeo
player on web, then there will be some issue with CORS
only in web, so use this flutter_cors
package
flutter_cors
package to enable or disable CORSTo Enable CORS (run this command )
dart pub global activate flutter_cors
fluttercors --enable
To Disable CORS (run this command )
fluttercors --disable
import 'package:pod_player/pod_player.dart';
import 'package:flutter/material.dart';
class PlayVideoFromNetwork extends StatefulWidget {
const PlayVideoFromNetwork({Key? key}) : super(key: key);
@override
State<PlayVideoFromNetwork> createState() => _PlayVideoFromNetworkState();
}
class _PlayVideoFromNetworkState extends State<PlayVideoFromNetwork> {
late final PodPlayerController controller;
@override
void initState() {
controller = PodPlayerController(
playVideoFrom: PlayVideoFrom.network(
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4',
),
)..initialise();
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PodVideoPlayer(controller: controller),
);
}
}
controller = PodPlayerController(
playVideoFrom: PlayVideoFrom.youtube('https://youtu.be/A3ltMaM6noM'),
podPlayerConfig: const PodPlayerConfig(
autoPlay: true,
isLooping: false,
initialVideoQuality: 360
)
)..initialise();
PodVideoPlayer(
controller: controller,
videoThumbnail: const DecorationImage(
/// load from asset: AssetImage('asset_path')
image: NetworkImage('https://images.unsplash.com/photo-1569317002804-ab77bcf1bce4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MXx8dW5zcGxhc2h8ZW58MHx8MHx8&w=1000&q=80',
),
fit: BoxFit.cover,
),
),
import 'package:pod_player/pod_player.dart';
import 'package:flutter/material.dart';
class PlayVideoFromYoutube extends StatefulWidget {
const PlayVideoFromYoutube({Key? key}) : super(key: key);
@override
State<PlayVideoFromYoutube> createState() => _PlayVideoFromYoutubeState();
}
class _PlayVideoFromYoutubeState extends State<PlayVideoFromYoutube> {
late final PodPlayerController controller;
@override
void initState() {
controller = PodPlayerController(
playVideoFrom: PlayVideoFrom.youtube('https://youtu.be/A3ltMaM6noM'),
)..initialise();
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PodVideoPlayer(controller: controller),
);
}
}
import 'package:pod_player/pod_player.dart';
import 'package:flutter/material.dart';
class PlayVideoFromVimeo extends StatefulWidget {
const PlayVideoFromVimeo({Key? key}) : super(key: key);
@override
State<PlayVideoFromVimeo> createState() => _PlayVideoFromVimeoState();
}
class _PlayVideoFromVimeoState extends State<PlayVideoFromVimeo> {
late final PodPlayerController controller;
@override
void initState() {
controller = PodPlayerController(
playVideoFrom: PlayVideoFrom.vimeo('518228118'),
)..initialise();
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PodVideoPlayer(controller: controller),
);
}
}
Normal player option | Vimeo player option | Change quality of video |
---|---|---|
![]() | ![]() | ![]() |
Run this command:
With Flutter:
$ flutter pub add pod_player
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
pod_player: ^0.0.6
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:pod_player/pod_player.dart';
example/lib/main.dart
import 'package:example/screens/from_asset.dart';
import 'package:example/screens/from_network.dart';
import 'package:example/screens/from_network_urls.dart';
import 'package:example/screens/from_youtube.dart';
import 'package:flutter/material.dart';
import 'package:pod_player/pod_player.dart';
import 'screens/cutom_video_controllers.dart';
import 'screens/from_vimeo_id.dart';
void main() {
PodVideoPlayer.enableLogs = true;
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'/fromVimeoId': (context) => const PlayVideoFromVimeoId(),
'/fromYoutube': (context) => const PlayVideoFromYoutube(),
'/fromAsset': (context) => const PlayVideoFromAsset(),
'/fromNetwork': (context) => const PlayVideoFromNetwork(),
'/fromNetworkQualityUrls': (context) =>
const PlayVideoFromNetworkQualityUrls(),
'/customVideo': (context) => const CustomVideoControlls(),
},
home: const MainPage(),
);
}
}
class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ListView(
shrinkWrap: true,
children: [
// _button('Play video from File'),
_button(
'Play video from Network',
onPressed: () => Navigator.of(context).pushNamed('/fromNetwork'),
),
_button(
'Play video from Youtube',
onPressed: () => Navigator.of(context).pushNamed('/fromYoutube'),
),
_button(
'Play video from Network quality urls',
onPressed: () =>
Navigator.of(context).pushNamed('/fromNetworkQualityUrls'),
),
_button(
'Play video from Asset',
onPressed: () => Navigator.of(context).pushNamed('/fromAsset'),
),
_button(
'Play video from Vimeo',
onPressed: () => Navigator.of(context).pushNamed('/fromVimeoId'),
),
_button(
'Custom Video player',
onPressed: () => Navigator.of(context).pushNamed('/customVideo'),
),
],
),
),
);
}
Widget _button(String text, {void Function()? onPressed}) {
return Center(
child: Padding(
padding: const EdgeInsets.all(20),
child: OutlinedButton(
onPressed: onPressed ?? () {},
child: Text(
text,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
),
);
}
}
Please run the app in the example/
folder to start playing!
Author: NewtaDev
Source Code: https://github.com/newtaDev/pod_player
License: MIT license
1647710592
TBIB Cached Video Player
A flutter plugin that has been forked from the official video_player package except that it supports caching in Android and iOS. Web plugin will work like official video_player i.e. without caching support.
First, add tbib cached_video_player
as a dependency in your pubspec.yaml file.
Follow the Android and iOS configuration steps of the official video_player package. This plugin won't work in Desktop.
maxFileSize
and maxCacheSize
are hardcoded at 100MiB and 1GiB respectively in Android. Run this command:
With Dart:
$ dart pub add tbib_cached_video_player
With Flutter:
$ flutter pub add tbib_cached_video_player
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
tbib_cached_video_player: ^0.0.1
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:tbib_cached_video_player/tbib_cached_video_player.dart';
// ignore_for_file: public_member_api_docs
/// An example of using the plugin, controlling lifecycle and playback of the
/// video.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:tbib_cached_video_player/tbib_cached_video_player.dart';
void main() {
runApp(
MaterialApp(
home: _App(),
),
);
}
class _App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
key: const ValueKey<String>('home_page'),
appBar: AppBar(
title: const Text('Video player example'),
actions: <Widget>[
IconButton(
key: const ValueKey<String>('push_tab'),
icon: const Icon(Icons.navigation),
onPressed: () {
Navigator.push<_PlayerVideoAndPopPage>(
context,
MaterialPageRoute<_PlayerVideoAndPopPage>(
builder: (BuildContext context) => _PlayerVideoAndPopPage(),
),
);
},
)
],
bottom: const TabBar(
isScrollable: true,
tabs: <Widget>[
Tab(
icon: Icon(Icons.cloud),
text: "Remote",
),
Tab(icon: Icon(Icons.insert_drive_file), text: "Asset"),
Tab(icon: Icon(Icons.list), text: "List example"),
],
),
),
body: TabBarView(
children: <Widget>[
_BumbleBeeRemoteVideo(),
_ButterFlyAssetVideo(),
_ButterFlyAssetVideoInList(),
],
),
),
);
}
}
class _ButterFlyAssetVideoInList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
const _ExampleCard(title: "Item a"),
const _ExampleCard(title: "Item b"),
const _ExampleCard(title: "Item c"),
const _ExampleCard(title: "Item d"),
const _ExampleCard(title: "Item e"),
const _ExampleCard(title: "Item f"),
const _ExampleCard(title: "Item g"),
Card(
child: Column(children: <Widget>[
Column(
children: <Widget>[
const ListTile(
leading: Icon(Icons.cake),
title: Text("Video video"),
),
Stack(
alignment: FractionalOffset.bottomRight +
const FractionalOffset(-0.1, -0.1),
children: <Widget>[
_ButterFlyAssetVideo(),
Image.asset('assets/flutter-mark-square-64.png'),
]),
],
),
])),
const _ExampleCard(title: "Item h"),
const _ExampleCard(title: "Item i"),
const _ExampleCard(title: "Item j"),
const _ExampleCard(title: "Item k"),
const _ExampleCard(title: "Item l"),
],
);
}
}
/// A filler card to show the video in a list of scrolling contents.
class _ExampleCard extends StatelessWidget {
const _ExampleCard({Key? key, required this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: const Icon(Icons.airline_seat_flat_angled),
title: Text(title),
),
ButtonBar(
children: <Widget>[
TextButton(
child: const Text('BUY TICKETS'),
onPressed: () {
/* ... */
},
),
TextButton(
child: const Text('SELL TICKETS'),
onPressed: () {
/* ... */
},
),
],
),
],
),
);
}
}
class _ButterFlyAssetVideo extends StatefulWidget {
@override
_ButterFlyAssetVideoState createState() => _ButterFlyAssetVideoState();
}
class _ButterFlyAssetVideoState extends State<_ButterFlyAssetVideo> {
late VideoPlayerController _controller;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.asset('assets/Butterfly-209.mp4');
_controller.addListener(() {
setState(() {});
});
_controller.setLooping(true);
_controller.initialize().then((_) => setState(() {}));
_controller.play();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(top: 20.0),
),
const Text('With assets mp4'),
Container(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(_controller),
_ControlsOverlay(controller: _controller),
VideoProgressIndicator(_controller, allowScrubbing: true),
],
),
),
),
],
),
);
}
}
class _BumbleBeeRemoteVideo extends StatefulWidget {
@override
_BumbleBeeRemoteVideoState createState() => _BumbleBeeRemoteVideoState();
}
class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> {
late VideoPlayerController _controller;
Future<ClosedCaptionFile> _loadCaptions() async {
final String fileContents = await DefaultAssetBundle.of(context)
.loadString('assets/bumble_bee_captions.vtt');
return WebVTTCaptionFile(
fileContents); // For vtt files, use WebVTTCaptionFile
}
@override
void initState() {
super.initState();
_controller = VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
closedCaptionFile: _loadCaptions(),
videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
);
_controller.addListener(() {
setState(() {});
});
_controller.setLooping(true);
_controller.initialize();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Container(padding: const EdgeInsets.only(top: 20.0)),
const Text('With remote mp4'),
Container(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(_controller),
ClosedCaption(text: _controller.value.caption.text),
_ControlsOverlay(controller: _controller),
VideoProgressIndicator(_controller, allowScrubbing: true),
],
),
),
),
],
),
);
}
}
class _ControlsOverlay extends StatelessWidget {
const _ControlsOverlay({Key? key, required this.controller})
: super(key: key);
static const _examplePlaybackRates = [
0.25,
0.5,
1.0,
1.5,
2.0,
3.0,
5.0,
10.0,
];
final VideoPlayerController controller;
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
AnimatedSwitcher(
duration: const Duration(milliseconds: 50),
reverseDuration: const Duration(milliseconds: 200),
child: controller.value.isPlaying
? const SizedBox.shrink()
: Container(
color: Colors.black26,
child: const Center(
child: Icon(
Icons.play_arrow,
color: Colors.white,
size: 100.0,
),
),
),
),
GestureDetector(
onTap: () {
controller.value.isPlaying ? controller.pause() : controller.play();
},
),
Align(
alignment: Alignment.topRight,
child: PopupMenuButton<double>(
initialValue: controller.value.playbackSpeed,
tooltip: 'Playback speed',
onSelected: (speed) {
controller.setPlaybackSpeed(speed);
},
itemBuilder: (context) {
return [
for (final speed in _examplePlaybackRates)
PopupMenuItem(
value: speed,
child: Text('${speed}x'),
)
];
},
child: Padding(
padding: const EdgeInsets.symmetric(
// Using less vertical padding as the text is also longer
// horizontally, so it feels like it would need more spacing
// horizontally (matching the aspect ratio of the video).
vertical: 12,
horizontal: 16,
),
child: Text('${controller.value.playbackSpeed}x'),
),
),
),
],
);
}
}
class _PlayerVideoAndPopPage extends StatefulWidget {
@override
_PlayerVideoAndPopPageState createState() => _PlayerVideoAndPopPageState();
}
class _PlayerVideoAndPopPageState extends State<_PlayerVideoAndPopPage> {
late VideoPlayerController _videoPlayerController;
bool startedPlaying = false;
@override
void initState() {
super.initState();
_videoPlayerController =
VideoPlayerController.asset('assets/Butterfly-209.mp4');
_videoPlayerController.addListener(() {
if (startedPlaying && !_videoPlayerController.value.isPlaying) {
Navigator.pop(context);
}
});
}
@override
void dispose() {
_videoPlayerController.dispose();
super.dispose();
}
Future<bool> started() async {
await _videoPlayerController.initialize();
await _videoPlayerController.play();
startedPlaying = true;
return true;
}
@override
Widget build(BuildContext context) {
return Material(
elevation: 0,
child: Center(
child: FutureBuilder<bool>(
future: started(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.data == true) {
return AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: VideoPlayer(_videoPlayerController),
);
} else {
return const Text('waiting for video to load');
}
},
),
),
);
}
}
Download Details:
Author: the-best-is-best
Source Code: https://github.com/the-best-is-best/tbib_cahched_video_player
1644463980
Clappr is an extensible media player for the web. Your architecture is projected primarily into plugins, adding low accoupling by design to the project and the possibility to add infinitely features easily.
Clappr uses by default the HTMLVideoElement which guarantees support to many platforms. You have the possibility to extends the default HTML5 playback or the playback interface to create one new media support just like a plugin!
Clappr is a composition of two other projects: @clappr/core and @clappr/plugins.
The @clappr/core
contains the basic functionalities from Clappr (plugin architecture, class abstractions, public interfaces, events handlers and etc) and the @clappr/plugins
are the repository where the plugins maintained by the Clappr team lives. More info about those projects into your repositories.
All Clappr projects are written in *.js
using the latest features of ECMAScript.
Clappr is under development but production-ready. Feel free to open issues and send pull requests.
Add the following script on your HTML:
<head>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@clappr/player@latest/dist/clappr.min.js"></script>
</head>
Now, create the player:
<body>
<div id="player"></div>
<script>
var player = new Clappr.Player({source: "http://your.video/here.mp4", parentId: "#player"});
</script>
</body>
Live demo to test, with a possibility to add external plugins.
You can check the current API doc via @clappr/core
here.
You can check the embed parameters supported by @clappr/core
here.
You can check the plugins used on Clappr player via @clappr/plugins
here.
Integration | Status | Compatible with latest Clappr | URL |
---|---|---|---|
P2P Media Loader | Ready | Yes | https://github.com/Novage/p2p-media-loader |
Format | HLS | MP4 | MP3 | WEBM | DASH | RTMP | JPG/PNG/GIF | FLV |
---|---|---|---|---|---|---|---|---|
IE10 | ✔ | ✔ | ✔ | ✘ | ✘ | ✔ | ✘ | |
IE11 | ✔ | ✔ | ✔ | ✘ | ✔ | |||
Microsoft Edge | ✔ | ✔ | ? | ? | ? | |||
Firefox | ✔ | ✔ | ✔ | ✔ | ||||
Chrome | ✔ | ✔ | ✔ | ✔ | ✔ | |||
Safari | ✔ | ✔ | ✔ | ✘ | ||||
iPhone | ✔ | ✔ | ✔ | ✘ | ✘ | ✘ | ✔ | ✘ |
iPad | ✔ | ✔ | ✔ | ✘ | ✘ | ✘ | ✔ | ✘ |
Android | ✔ | ✔ | ✔ | ✘ | ✘ | |||
WiiU Browser | ✔ | ✔ | ✘ | ? | ✘ | ? | ||
PS4 Browser | ✔ | ✔ | ✘ | ? | ✘ | ? |
means that the support is made by an external plugin.
Clappr has no control over autoplay
Browser Policy.
Therefore, we're not able to execute play and unmute actions sequentially in every situation. There are a series of scenarios where the Browser blocks these actions based on it’s own policy.
Each browser has their own different restrictions, and the usual behavior is to activate the sound only after an user interaction with the player.
For more infos about auto play video policy, you can read these docs:
See the wiki for more info.
Let's say you want to disable or override a plugin.
// let's disable the loading animation (the 'spinner' plugin)
var player = new Clappr.Player({ ... });
// after attach
player.getPlugin('spinner').disable();
// let's disable the loading animation (the 'spinner' plugin)
export default class NoSpinner extends UIContainerPlugin {
get name() { return 'spinner' }
}
new Clappr.Player({ plugins: [NoSpinner]})
https://medium.com/@bikegriffith/using-clappr-with-reactjs-14a338e3451f#.9a36w0dpj
https://github.com/clappr/clappr/issues/933#issuecomment-228540381
Add this snippet before you instantiate the player Clappr.Log.setLevel(0)
Very often people open issues related to stream not working, freezing, glitching, stopping, and so on. You can try the steps below, taking notes about the results:
http://www.streambox.fr/playlists/x36xhzz/x36xhzz.m3u8
mediainfo
(for instance you could: mediainfo http://www.example.com/my.m3u8
, Apple's mediastreamvalidator
too, hls-analyzer
and etc.//HLS-Analyzer usage example
pip install m3u8
git clone https://github.com/epiclabs-io/hls-analyzer.git
cd hls-analyzer
python hls-analyzer.py http://www.streambox.fr/playlists/x36xhzz/x36xhzz.m3u8
Player fatal errors can be handled using onError
API event.
var player = new Clappr.Player({
parent: '#myplayer',
source: 'http://path.to/my/video.mp4',
events: {
onError: function(e) {
// Here the code to handle the error
}
}
});
Note: the type of error event object depends on the type of the playback component resolved to play the video.
This is a simple example using the no_op
playback to display error messages.
You can try the following Javascript code on Clappr demo page:
var playerElement = document.getElementById("player-wrapper");
var r = 3; // Retry attempts
var player = new Clappr.Player({
// source: 'http://clappr.io/highline.mp4',
source: 'http://clappr.io/bad_highline.mp4',
disableErrorScreen: true, // Disable the internal error screen plugin
height: 360,
width: 640,
events: {
onError: function(e) {
r--;
var s = player.options.source;
// Replace previous line by the following line to simulate successful recovery
// var s = (r > 2) ? player.options.source : 'http://clappr.io/highline.mp4';
var t = 10;
var retry = function() {
if (t === 0) {
var o = player.options;
o.source = s;
player.configure(o);
return;
}
Clappr.$('#retryCounter').text(t);
t--;
setTimeout(retry, 1000);
};
player.configure({
autoPlay: true,
source: 'playback.error',
playbackNotSupportedMessage: 'Network fatal error.' + ((r > 0)
? ' Retrying in <span id="retryCounter"></span> seconds ...'
: ' All retry attempts failed'),
});
if (r > 0) {
retry();
}
}
}
});
player.attachTo(playerElement);
This example use a custom error container plugin to display error messages.
You can try the following Javascript code on Clappr demo page:
var playerElement = document.getElementById("player-wrapper");
var ErrorPlugin = Clappr.ContainerPlugin.extend({
name: 'error_plugin',
background: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAFoBAMAAAA1HFdiAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAG1BMVEX5+fn//wAA//8A/wD/AP//AAAAAP8XFxf///8H5gWfAAAAAWJLR0QIht6VegAAAAd0SU1FB98IBRIsAXmGk48AAAI5SURBVHja7dJBDYBADADBs4AFLGABC1iohbOPhv1BMvu+NLlp10odqTN1pe7Uk5pQ8wMIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDA/wKWxzM71T7ZZrfltNnppgACBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAL8B+ALjSfYzPnmdzgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0wOC0wNVQxODo0NDowMSswMTowMCL95a4AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTUtMDgtMDVUMTg6NDQ6MDErMDE6MDBToF0SAAAAAElFTkSuQmCC',
bindEvents: function() { this.listenTo(this.container, Clappr.Events.CONTAINER_ERROR, this.onError) },
hide: function() { this._err && this._err.remove() },
show: function() {
var $ = Clappr.$
this.hide();
var txt = (this.options.errorPlugin && this.options.errorPlugin.text) ? this.options.errorPlugin.text : 'A fatal error occured.';
this._err = $('<div>')
.css({
'position': 'absolute',
'z-index': '999',
'width': '100%',
'height': '100%',
'background-image': 'url(' + this.background + ')',
'background-size': 'contain',
'background-repeat': 'no-repeat',
'padding-top': '15%',
'text-align': 'center',
'font-weight': 'bold',
'text-shadow': '1px 1px #fff',
})
.append($('<h2>')
.text(txt)
.css({
'font-size': '200%',
}))
.append($('<p>').html('Retrying in <span class="retry-counter">10</span> seconds ...')
.css({
'font-size': '120%',
'margin': '15px',
}));
this.container && this.container.$el.prepend(this._err);
},
onError: function(e) {
if (!this.container) return;
this.show();
this.container.getPlugin('click_to_pause').disable();
var tid, t = 10, retry = function() {
clearTimeout(tid);
if (t === 0) {
this.container.getPlugin('click_to_pause').enable();
if (this.options.errorPlugin && this.options.errorPlugin.onRetry) {
this.options.errorPlugin.onRetry(e);
return;
} else {
this.container.stop();
this.container.play();
return;
}
}
$('.retry-counter').text(t);
t--;
tid = setTimeout(retry, 1000);
}.bind(this);
retry();
}
});
var player = new Clappr.Player({
disableErrorScreen: true, // Disable the internal error screen plugin
source: 'http://clappr.io/bad_highline.mp4',
plugins: [ErrorPlugin],
errorPlugin: {
// text: 'My custom error message.',
onRetry: function(e) {
// simulate successful recovery
// or decide here what to do between each retry
player.configure({
source: 'http://clappr.io/highline.mp4',
autoPlay: true,
});
}
},
height: 360,
width: 640
});
player.attachTo(playerElement);
https://github.com/clappr/clappr/issues/522
This project exists thanks to all the people who contribute.
Author: Clappr
Source Code: https://github.com/clappr/clappr
License: BSD-3-Clause License
1644441300
Video.js is a web video player built from the ground up for an HTML5 world. It supports HTML5 and Flash video, as well as YouTube and Vimeo (through plugins). It supports video playback on desktops and mobile devices. This project was started mid 2010, and the player is now used on over
50,000100,000200,000400,000 websites.
Thanks to the awesome folks over at Fastly, there's a free, CDN hosted version of Video.js that anyone can use. Add these tags to your document's <head>
:
<link href="//vjs.zencdn.net/7.8.2/video-js.min.css" rel="stylesheet">
<script src="//vjs.zencdn.net/7.8.2/video.min.js"></script>
For the latest version of video.js and URLs to use, check out the Getting Started page on our website.
Video.js version 7 (and newer) CDN builds do not send any data to Google Analytics.
In older versions of Video.js (6 and earlier), in the vjs.zencdn.net
CDN-hosted versions we include a stripped down Google Analytics pixel that tracks a random sampling (currently 1%) of players loaded from the CDN. This allows us to see (roughly) what browsers are in use in the wild, along with other useful metrics such as OS and device. If you'd like to disable analytics, you can simply include the following global before including Video.js via the free CDN:
<script>window.HELP_IMPROVE_VIDEOJS = false;</script>
Alternatively, you can include Video.js by getting it from npm, downloading from GitHub releases or by including it via unpkg or another JavaScript CDN like CDNjs. These releases do not include Google Analytics tracking at all.
<!-- unpkg : use the latest version of Video.js -->
<link href="https://unpkg.com/video.js/dist/video-js.min.css" rel="stylesheet">
<script src="https://unpkg.com/video.js/dist/video.min.js"></script>
<!-- unpkg : use a specific version of Video.js (change the version numbers as necessary) -->
<link href="https://unpkg.com/video.js@7.8.2/dist/video-js.min.css" rel="stylesheet">
<script src="https://unpkg.com/video.js@7.8.2/dist/video.min.js"></script>
<!-- cdnjs : use a specific version of Video.js (change the version numbers as necessary) -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.8.1/video-js.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.8.1/video.min.js"></script>
Next, using Video.js is as simple as creating a <video>
element, but with an additional data-setup
attribute. At a minimum, this attribute must have a value of '{}'
, but it can include any Video.js options - just make sure it contains valid JSON!
<video
id="my-player"
class="video-js"
controls
preload="auto"
poster="//vjs.zencdn.net/v/oceans.png"
data-setup='{}'>
<source src="//vjs.zencdn.net/v/oceans.mp4" type="video/mp4"></source>
<source src="//vjs.zencdn.net/v/oceans.webm" type="video/webm"></source>
<source src="//vjs.zencdn.net/v/oceans.ogv" type="video/ogg"></source>
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank">
supports HTML5 video
</a>
</p>
</video>
When the page loads, Video.js will find this element and automatically setup a player in its place.
If you don't want to use automatic setup, you can leave off the data-setup
attribute and initialize a <video>
element manually using the videojs
function:
var player = videojs('my-player');
The videojs
function also accepts an options
object and a callback to be invoked when the player is ready:
var options = {};
var player = videojs('my-player', options, function onPlayerReady() {
videojs.log('Your player is ready!');
// In this context, `this` is the player that was created by Video.js.
this.play();
// How about an event listener?
this.on('ended', function() {
videojs.log('Awww...over so soon?!');
});
});
If you're ready to dive in, the Getting Started page and documentation are the best places to go for more information. If you get stuck, head over to our Slack channel!
Video.js is a free and open source library, and we appreciate any help you're willing to give - whether it's fixing bugs, improving documentation, or suggesting new features. Check out the contributing guide for more!
Video.js uses BrowserStack for compatibility testing.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
Author: Videojs
Source Code: https://github.com/videojs/video.js
License: View license
1635658007
Based on TXLiteAVSDK_Player Tencent player package flutter sdk currently supports live broadcast, sdk only provides core functions, specific functions need to be customized, there is a set of attached ui in the example.
Left iOS Right Android
pub address https://pub.dev/packages/ftl_player
Simple to use
@override
void initState() {
super.initState();
FTLPlayer.init().then((value){
this.livePlayerController = value;
this.setState(() {});
});
}
Container(height: 200, child: FTLPlayerWidget(this.livePlayerController)),
Detailed use https://github.com/tion126/flutter_live
You can customize and modify the UI, and you can also play live broadcasts on other platforms without Tencent.
Currently known issues
1. Android needs to set the hls format to play normally
Run this command:
With Flutter:
$ flutter pub add ftl_player
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
ftl_player: ^2.0.0
Alternatively, your editor might support or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:ftl_player/ftl_player.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:ftl_player/ftl_player.dart';
void main() => runApp(app());
Widget app() {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.white,
statusBarIconBrightness: Brightness.dark,
));
return MaterialApp(initialRoute: "/", routes: {
"/": (context) => HomePage(),
"/page1": (context) => PlayerExample(),
});
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CupertinoButton(
child: Text("Player"),
onPressed: () {
Navigator.of(context).pushNamed("/page1");
},
),
),
);
}
}
class PlayerExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return PlayerExampleState();
}
}
class PlayerExampleState extends State<PlayerExample>{
FTLPlayerController? livePlayerController;
@override
void initState() {
super.initState();
FTLPlayer.init().then((value){
this.livePlayerController = value;
this.setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Column(children: [
Padding(padding: EdgeInsets.only(top: 50)),
Container(height: 200, child: FTLPlayerWidget(this.livePlayerController)),
Padding(padding: EdgeInsets.only(top: 30)),
_optBtn()
])),
);
}
Widget _optBtn() {
return Padding(
padding: const EdgeInsets.only(left: 45.0, right: 45.0, top: 0.0, bottom: 50.0),
child: Wrap(
children: <Widget>[
CupertinoButton(
onPressed: () {
this.livePlayerController!.start("http://1011.hlsplay.aodianyun.com/demo/game.flv");
},
child: new Text("Start"),
),
CupertinoButton(
onPressed: () {
this.livePlayerController!.pause();
},
child: Text("pause"),
),
CupertinoButton(
onPressed: () {
this.livePlayerController!.resume();
},
child: new Text("resume"),
),
CupertinoButton(
onPressed: () {
this.livePlayerController!.dispose();
},
child: new Text("dispose"),
),
CupertinoButton(
onPressed: () {
this.livePlayerController!.pause();
Navigator.of(context).pushNamed("/page1").then((value){
this.livePlayerController!.resume();
});
},
child: new Text("new page"),
)
],
),
);
}
}
Download Details:
Author: tion126
Source Code: https://github.com/tion126/ftl_player
1634310013
ogg_opus_player
a ogg opus file player for flutter.
platform | required os version | |
---|---|---|
iOS | ✅ | 10.0 |
macOS | ✅ | 10.12 |
ogg_opus_player
to your pubspec.yaml ogg_opus_player: $latest_version
OggOpusPlayer
final player = OggOpusPlayer("file_path");
player.play();
player.pause();
player.dipose();
see LICENSE file
Run this command:
With Flutter:
$ flutter pub add ogg_opus_player
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
ogg_opus_player: ^0.1.0
Alternatively, your editor might support or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:ogg_opus_player/ogg_opus_player.dart';
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:ogg_opus_player/ogg_opus_player.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _copyCompleted = false;
String _path = '';
@override
void initState() {
super.initState();
_copyAssets();
}
Future<void> _copyAssets() async {
final dir = await getApplicationDocumentsDirectory();
final dest = File(p.join(dir.path, "test.ogg"));
_path = dest.path;
if (await dest.exists()) {
setState(() {
_copyCompleted = true;
});
return;
}
final bytes = await rootBundle.load('audios/test.ogg');
await dest.writeAsBytes(bytes.buffer.asUint8List());
setState(() {
_copyCompleted = true;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: _copyCompleted
? PlayerBody(path: _path)
: const Center(
child: SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(),
),
),
),
);
}
}
class PlayerBody extends StatefulWidget {
const PlayerBody({Key? key, required this.path}) : super(key: key);
final String path;
@override
State<PlayerBody> createState() => _PlayerBodyState();
}
class _PlayerBodyState extends State<PlayerBody> {
late OggOpusPlayer _player;
Timer? timer;
double _playingPosition = 0;
@override
void initState() {
super.initState();
_player = OggOpusPlayer(widget.path);
timer = Timer.periodic(const Duration(milliseconds: 50), (timer) {
setState(() {
_playingPosition = _player.currentPosition;
});
});
}
@override
void dispose() {
timer?.cancel();
_player.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('position: ${_playingPosition.toStringAsFixed(2)}'),
const SizedBox(height: 8),
IconButton(
onPressed: () {
setState(() {
_player.dispose();
_player = OggOpusPlayer(widget.path);
});
},
icon: const Icon(Icons.refresh),
),
const SizedBox(height: 8),
ValueListenableBuilder(
valueListenable: _player.state,
builder: (context, state, child) {
if (state == PlayerState.playing) {
return IconButton(
onPressed: () {
_player.pause();
},
icon: const Icon(Icons.pause),
);
} else {
return IconButton(
onPressed: () {
if (state == PlayerState.ended) {
_player.dispose();
_player = OggOpusPlayer(widget.path);
_player.play();
} else {
_player.play();
}
},
icon: const Icon(Icons.play_arrow),
);
}
},
),
],
),
);
}
}
Download Details:
Author: flutter-plugins
Source Code: https://github.com/MixinNetwork/flutter-plugins/tree/main/packages/ogg_opus_player
1631622772
Chapayev 2: Best Checkers 3D board Game is a multiplayer online & offline board game that boosts the inner adrenaline rush.
In this thrilling, fast-paced, and competitive strategy game, you will fight for survival against your friend from all over the world to win tournaments and become a legend among your peers. You will have to use your wit, tactics, and cunning to formulate just the right strategy to outsmart your opponent in every battle.
It tests your intelligence, your strategy, and your knowledge. It will always be online multiplayer with great graphics and realistic physics – the game is designed to make you feel like you are fighting for your army.
The game is packed with new features never seen before in any other game of this genre. A brand new type of graphics engine renders even more stunning effects than any other checkers board game. Now the gameplay itself is even more exciting than ever before, with an increased number of players at the same time.
The game has recently launched the latest feature of Multiplayer Tourney. To know about the latest feature continue reading the article.
Win Multiplayer tourney and climb to the top of worldwide ranking tables or play for fun and win points!
Now let’s see how can you leverage the MultiPlayer Tourney update stepwise:
First, one player has to create a tournament using coins such as 500 coins, 1000 coins, etc.
Invite as many players as you want using your invite feature within the game.
#3dboardgame #boardgame #best3dboardgame #mobileboardgame #checkers #checkersboardgame #draughts #draughtsgame #checkers3dboardgame #onlineboardgame #mobilegame #mobilegaming #gaming #gamer #game #bestmobilegame #strategygame #play #players #gamelovers #mobilegamelovers #proplayers #challenge #chapayev2 #multiplayergame
1624684440
All businesses and people rely on the assistance of many varying technologies to improve efficiency in the workplace and home. Work and play processes, especially those relating to communication, are made easier through instant chats, VOIP and even video conferencing. Many industries relish the applicable nature offered by technology sciences and artificial technology not only captures the imagination but produces workable data.
The use of AI technology in the iGaming industry has almost become proverbial. However, there are differences in how this technology is received and used by players. Some players find instant problem-solving solutions offered by chatbots inviting, while others prefer the human touch.
Even gigantic iGaming groups are not immune to customer dissatisfaction. Handling the issues does not only rely on empathetic human approaches, but it also depends on acquiring necessary customer data.
#chatbots #latest news #how ai chatbot data is helping casinos customise their players’ needs #ai chatbot data #casinos #players
1602799200
NFL and NBA athletes whose social-media accounts were taken over have been thrown the ball of justice.
Multiple professional and semi-pro athletes were victimized by two men who infiltrated their personal accounts, according to testimony in federal court on Wednesday. Trevontae Washington of Thibodaux, La., and Ronnie Magrehbi, of Orlando, Fla., faced separate judges in the Eastern District of Louisiana and the Middle District of Florida, respectively, and were charged with one count of conspiracy to commit wire fraud, and one count of conspiracy to commit computer fraud and abuse.
Federal prosecutors alleged that between December 2017 and April 2019, Washington and Magrehbi actively took part in illegal schemes to gain access to social media and other personal online accounts of the players.
Washington allegedly specialized in NBA and NFL players, and phished for their credentials by taking advantage of public platforms like Instagram. He would send them messages with embedded links to what appeared to be legitimate social media log-in sites, prosecutors said, but these were actually phishing pages used to steal the athletes’ user names and passwords. Once the athletes entered their credentials, they would be sent to Washington, who, along with others allegedly locked the athletes out of their accounts. They also used the credentials against other accounts, banking on password reuse. Prosecutors claimed that Washington then sold access to the compromised accounts to others for amounts ranging from $500 to $1,000.
Magrehbi, meanwhile, is alleged to have obtained access to accounts belonging to one professional football player, including an Instagram account and personal email account. Magrehbi took a ransomware-like tack, prosecutors said, and extorted the player. He demanded payment in return for restoring access to the accounts – and was paid, according to Department of Justice documents. However, even though the player sent funds on at least one occasion, portions of which were transferred to a personal bank account controlled by Magrehbi – he was double-crossed and the athlete never regained access, prosecutors said.
The DoJ has not released the names of the affected players.
“Instagram is built as a mobile-first experience, which means that these attackers knew they could build a mobile-specific phishing campaign to increase the likelihood of success,” Hank Schless, senior manager of security solutions at Lookout, told Threatpost. “Since we carry our mobile devices with us all the time, we trust them to be inherently secure. Threat actors know this and socially engineer targets through SMS, social media and third-party messaging apps and convince them to click a malicious link.”
#government #hacks #web security #account takeover #charged #department of justice #extortion #federal court #federal crimes #hack #nba #nfl #players #ronnie magrehbi #social media accounts #trevontae washington