Hello I'm try to play my hls stream http://81.25.234.43:8083/tv/1plus1HD/playlist.m3u8?wmsAuthSign=c2VydmVyX3RpbWU9Mi8xNi8yMDIxIDI6MTE6MjcgUE0maGFzaF92YWx1ZT1GYjhMdlVJdUh1OHVsQ05hSVFTWjBBPT0mdmFsaWRtaW51dGVzPTYwNDgwMCZpZD0zMQ==
via LibVLC android
api "org.videolan.android:libvlc-all:3.3.0-eap17"
but video is always freezing while playing and i got in logs
libvlc video output: picture is too late to be displayed (missing 53 ms)
My codes
class VlcMediaPlayer(context: Context) : IVLCVout.Callback {
private val libVLCFactory = FactoryManager.getFactory(ILibVLCFactory.factoryId) as ILibVLCFactory
private val factory = FactoryManager.getFactory(IMediaFactory.factoryId) as IMediaFactory
private val options = ArrayList<String>().apply {
add("-vvv");
add("--avcodec-dr");
add("--clock-jitter=1500");
add("--live-caching=1500");
add("--network-caching=1500");
add("--file-caching=3000");
add("--no-drop-late-frames");
add("--no-skip-frames");
add("--no-sout-smem-time-sync");
add("--sout-mp4-faststart");
add("--sout-x264-partitions=fast");
add("--adaptive-logic=nearoptimal");
add("--adaptive-use-access");
add("--avcodec-threads=10");
add("--sout-x264-psy");
add("--aout=opensles");
add("--demuxdump-append");
add("--avcodec-hw=d3d11va");
}
private val sLibVLC = libVLCFactory.getFromOptions(context, VLCOptions.libOptions)
private val mediaPlayer = MediaPlayer(sLibVLC).apply {
vlcVout.addCallback(this#VlcMediaPlayer)
}
override fun onSurfacesCreated(vlcVout: IVLCVout?) {
}
override fun onSurfacesDestroyed(vlcVout: IVLCVout?) {
}
#MainThread
fun setVideoScale(scale: Float) {
mediaPlayer.scale = scale
}
fun setVideoAspectRatio(aspect: String?) {
mediaPlayer.aspectRatio = aspect
}
#MainThread
fun setSurface(surface: Surface, holder: SurfaceHolder?) {
// mediaPlayer.stop()
//mediaPlayer.release()
mediaPlayer.vlcVout.apply {
setVideoSurface(surface, holder)
attachViews(null)
}
//release()
}
fun setWindowsSize(width: Int, height: Int) {
mediaPlayer.vlcVout.setWindowSize(width, height)
}
fun setMedia(uri: Uri) {
val media = factory.getFromUri(sLibVLC, uri)
options.forEach {
media.addOption(it)
}
mediaPlayer.media = media
}
fun play() = mediaPlayer.play()
fun stop() = mediaPlayer.stop()
fun release() {
mediaPlayer.release()
}
}
Related
I am using Exoplayer in my dialog. I want the video to play automatically when dialog opens. When
simpleExoPlayer.prepare() snippet is active I am able to do autoplay but when I close the dialog audio keeps playing. Before activating simpleExoPlayer.prepare() audio stops when I dismiss dialog. Is there another method to autoplay exoplayer or stop the audio when dialog dismiss?
class VideoViewDialog (context: Context) : BaseDialog<LayoutDialogVideoViewBinding>(context) {
private var videoUrl : String = ""
private lateinit var simpleExoPlayer: ExoPlayer
override fun populateUi() {
setCanceledOnTouchOutside(true)
mBinding?.apply {
initializePlayer()
}
}
private fun initializePlayer() {
val mediaDataSourceFactory: DataSource.Factory = DefaultDataSource.Factory(context)
val mediaSource = ProgressiveMediaSource.Factory(mediaDataSourceFactory).createMediaSource(
MediaItem.fromUri(videoUrl))
val mediaSourceFactory: MediaSource.Factory = DefaultMediaSourceFactory(mediaDataSourceFactory)
simpleExoPlayer = ExoPlayer.Builder(context)
.setMediaSourceFactory(mediaSourceFactory)
.build()
simpleExoPlayer.addMediaSource(mediaSource)
simpleExoPlayer.playWhenReady = true
simpleExoPlayer.prepare()
mBinding?.apply {
playerView.player = simpleExoPlayer
playerView.requestFocus()
}
simpleExoPlayer.play()
}
private fun releasePlayer() {
simpleExoPlayer.release()
}
public override fun onStart() {
super.onStart()
if (Util.SDK_INT > 23) initializePlayer()
}
public override fun onStop() {
super.onStop()
if (Util.SDK_INT > 23) releasePlayer()
}
override fun getLayoutRes(): Int {
return R.layout.layout_dialog_video_view
}
companion object{
fun newInstance(
context: Context,
videoUrl : String,
) : VideoViewDialog{
val dialog = VideoViewDialog(context)
dialog.also {
it.videoUrl = videoUrl
}
return dialog
}
}
}
I tried .stop, clearVideoSurface(), playerView.player = null before .release(). Didn't work
Seems like you called initializePlayer() twice. resulting in two Exoplayer instances playing; you're only able to release the one the simpleExoPlayer variable holds a reference to.
I am building a video player app for Android TV. I am using Exoplayer leanback dependency as explained in https://developer.android.com/training/tv/playback/transport-controls.
So far I've been able to display the video title, which is static, but I need to display a subtitle that is dynamic, it changes whenever the video playing changes. How can I do it?
The image below shows how the video player looks like. I've used a subtitle phrase as a placeholder on where it should appear.
I was able to solve the problem. I added a listener in the VideoSupportFragment class, Player.EventListener.
This way:
class VideoFragment(mediaItems: Map<String, Any>) : VideoSupportFragment(), Player.EventListener {
private var playerAdapter: ExoPlayerAdapter? = null
private var _mediaItems: Map<String, Any>? = null
private lateinit var mMediaPlayerGlue: VideoMediaPlayerGlue<ExoPlayerAdapter>
private var mItems: List<*>? = null
init {
_mediaItems = mediaItems
}
private val mHost: VideoSupportFragmentGlueHost = VideoSupportFragmentGlueHost(this)
private fun playWhenReady(glue: PlaybackGlue) {
if (glue.isPrepared) {
glue.play()
} else {
glue.addPlayerCallback(object : PlaybackGlue.PlayerCallback() {
override fun onPreparedStateChanged(glue: PlaybackGlue) {
if (glue.isPrepared) {
glue.removePlayerCallback(this);
glue.play()
}
}
})
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val mediaSource = _mediaItems?.get("media_source") as Map<*, *>
playerAdapter = ExoPlayerAdapter(activity!!, _mediaItems!!)
mMediaPlayerGlue =
VideoMediaPlayerGlue(activity, playerAdapter!!)
mMediaPlayerGlue.host = mHost;
mMediaPlayerGlue.isControlsOverlayAutoHideEnabled = true
mItems = mediaSource["media_items"] as List<*>
mMediaPlayerGlue.title = mediaSource["title"] as CharSequence?
mMediaPlayerGlue.playerAdapter.setDataSource()
mMediaPlayerGlue.isSeekEnabled = true
playerAdapter?.player?.addListener(this);
playWhenReady(mMediaPlayerGlue)
}
override fun onPause() {
super.onPause()
playerAdapter?.player?.pause()
}
override fun onResume() {
super.onResume()
playerAdapter?.player?.play()
}
override fun onDestroy() {
super.onDestroy()
playerAdapter?.player?.removeListener(this);
}
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
if (mItems?.size!! > 1){
val item : Map<*, *> = mItems!![playerAdapter?.player?.currentWindowIndex!!] as Map<*, *>
mMediaPlayerGlue.subtitle = item["subtitle"] as String
}
}
}
I have a viewPager with CubeTransformer, which is transforming every fragment. And inside every fragment is Image or Video view (with Exoplayer). And when you are trying to change a framgnet with transformation, exoplayer losses preview (I've got a black screen), even it's not playing. But after you changing condition to normal, preview is coming back
Ohterwise, if you will remove pageTransformer, review is not dissapears. How to keep preview always on screen?
CubeTransformer
class CubeTransformer : ViewPager.PageTransformer {
override fun transformPage(view: View, position: Float) {
if (view.visibility != View.VISIBLE) return
view.apply {
cameraDistance = (view.width * distanceMultiplier).toFloat()
pivotX = if (position < 0f) view.width.toFloat() else 0f
pivotY = view.height * 0.5f
rotationY = 90f * position
if (position < -1 || position > 1) {
alpha = 0f // item not visible
} else {
alpha = 1f
}
}
}
private companion object {
private const val distanceMultiplier: Int = 20
}
}
VideoView
class VideoView(context: Context) : ConstraintLayout(context, null) {
private val player = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector(), DefaultLoadControl())
private val dataSourceFactory = DefaultDataSourceFactory(context, "android")
private lateinit var model: Model
init {
inflate(context, R.layout.story_item_video, this)
video_view.player = player
video_view.keepScreenOn = true
video_view.setBackgroundColor(Color.TRANSPARENT)
video_view.setShutterBackgroundColor(Color.TRANSPARENT)
}
fun setData(model: Model?) {
if (model== null) return
this.model = model
val mediaSource = HlsMediaSource
.Factory(dataSourceFactory)
.setExtractorFactory(DefaultHlsExtractorFactory())
.createMediaSource(Uri.parse(model.streamLink))
player.playWhenReady = true
player.prepare(mediaSource)
player.addListener(object: Player.EventListener {
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {
}
override fun onSeekProcessed() {}
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {
}
override fun onPlayerError(error: ExoPlaybackException?) {
}
override fun onLoadingChanged(isLoading: Boolean) {
}
override fun onPositionDiscontinuity(reason: Int) {
}
override fun onRepeatModeChanged(repeatMode: Int) {
}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
}
})
}
}
After a day of searching, I've found an answer to my question. You just need to add app:surface_type="texture_view" to your PlayerView
I'm trying to detect a QR code with the google mobile vision api.
The problem is that after detecting a QR code, the api calls continiously the "receiveDetections" function as long as the QR code is visible to the camera.
I need to stop after the first detection and send the result to my server to validate this code.
How can I stop the process after the first detection?
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.qrcode_scanner)
detector = BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.ALL_FORMATS).build()
detector.setProcessor(object: Detector.Processor<Barcode> {
override fun release() {
override fun receiveDetections(detections: Detector.Detections<Barcode>?) {
val barcodes = detections?.detectedItems
if(barcodes!!.size()>0) {
Log.e("qrcode",barcodes.valueAt(0).displayValue)
sendQRCodeToServer(url,barcodes.valueAt(0).displayValue)
}
}
})
cameraSource = CameraSource.Builder(this,detector).setRequestedPreviewSize(1920,1080).setRequestedFps(25f).setAutoFocusEnabled(true).build()
svBarcode.holder.addCallback(object: SurfaceHolder.Callback2 {
override fun surfaceRedrawNeeded(holder: SurfaceHolder?) {
}
override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) {
}
override fun surfaceDestroyed(holder: SurfaceHolder?) {
cameraSource.stop()
}
override fun surfaceCreated(holder: SurfaceHolder?) {
if(ContextCompat.checkSelfPermission(this#Scanner,
Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
cameraSource.start(holder)
startAnimation()
} else ActivityCompat.requestPermissions(this#Scanner, arrayOf(Manifest.permission.CAMERA),123)
}
})
}
}
override fun onDestroy() {
super.onDestroy()
detector.release()
cameraSource.stop()
cameraSource.release()
}
you can create function to stop camera,ex
private fun stopCamera(){
cameraSource.stop()
}
detector = BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.ALL_FORMATS).build()
detector.setProcessor(object: Detector.Processor<Barcode> {
override fun release() {
override fun receiveDetections(detections: Detector.Detections<Barcode>?) {
val barcodes = detections?.detectedItems
if(barcodes!!.size()>0) {
Log.e("qrcode",barcodes.valueAt(0).displayValue)
sendQRCodeToServer(url,barcodes.valueAt(0).displayValue)
//add this to stop camera
stopCamera()
}
}
})
edit:
create variable for flag detection at first like
//to flag first detection
private var firstDetection=true
override fun onCreate(savedInstanceState: Bundle?) {
///.......
detector = BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.ALL_FORMATS).build()
detector.setProcessor(object: Detector.Processor<Barcode> {
override fun release() {
}
override fun receiveDetections(detections: Detector.Detections<Barcode>?) {
val barcodes = detections?.detectedItems
//check firstDetection
if(barcodes!!.size()>0 && firstDetection) {
sendQRCodeToServer(url,barcodes.valueAt(0).displayValue)
//set firstDetection
firstDetection=false
}
}
})
}
}
hope this help....
I'm trying to use Exoplayer inside the ViewPager. It will play only when I open it by clicking on the thumbnail which I'm using to display the videos. But it won't play when I reach the page by Scrolling.
I tried calling seekTo(0, 0) & playWhenReady = true inside onPageSelected() and playWhenReady = false inside the onScrolled() methods of the VPAdapter using the Lambdas but didn't work.
Here is the Adapter I'm using for the viewPager.
class MediaVPAdapter(
val context: Context,
#LayoutRes val layoutRes: Int,
val medias: List<MediaFiles> = listOf()
) : PagerAdapter() {
private var player: SimpleExoPlayer? = null
override fun isViewFromObject(view: View, o: Any): Boolean {
return view == o
}
override fun getCount() = medias.size
override fun instantiateItem(container: ViewGroup, position: Int): Any {
return LayoutInflater.from(context).inflate(layoutRes, container, false).apply {
if (medias.isNotEmpty()) {
when (medias[position].mediaType) {
MediaType.PHOTO -> {
// Display the Image
}
MediaType.VIDEO -> {
ssImageView.makeInvisible(true)
exoPlayerView.makeVisible()
player = ExoPlayerFactory.newSimpleInstance(
DefaultRenderersFactory(context),
DefaultTrackSelector(),
DefaultLoadControl()
)
if (medias[position].uri != null)
initPlayer(this, medias[position].uri!!)
}
null -> {
}
}
}
container.addView(this, 0)
}
}
private fun initPlayer(view: View, uri: Uri) {
Timber.i("initPlayer: uri: $uri")
with(view) {
player!!.let {
exoPlayerView.player = it
it.prepare(buildMediaSource(uri), true, false)
it.playWhenReady = false
}
}
}
private fun buildMediaSource(uri: Uri) = ExtractorMediaSource.Factory(
DefaultDataSourceFactory(context, Util.getUserAgent(context, context.getString(R.string.app_name)))
)
.setExtractorsFactory(DefaultExtractorsFactory())
.createMediaSource(uri)
override fun destroyItem(container: ViewGroup, position: Int, obj: Any) {
releasePlayer()
}
private fun releasePlayer() {
if (player != null) {
playWhenReady = false
player!!.release()
player = null
}
}
}
val mediaAdapter = MediaVPAdapter(
this,
R.layout.fragment_media,
true,
medias?.toList() ?: listOf()
)
vpMedia.adapter = mediaAdapter
vpMedia.currentItem = position ?: 0
vpMedia.offscreenPageLimit = 1
If I click on a Video, the selected Video could be played but when I scroll to some other item, none of them were playing. When I try to toggle the Play/Pause button, only the button was toggling.
As far i can see you you code misses the setPlayWhenReady listener.
You should fix it by adding it.setPlayWhenReady(playWhenReady) in the initPlayer method.