Hi I want to display video in exo player . on link I have basic authorize a link look like : http://login:pass#xxx.xxx.x.xxx:port/...
this is how I init a exo player :
private fun initializePlayer() {
if (player == null) {
val trackSelector = DefaultTrackSelector(this)
trackSelector.setParameters(
trackSelector.buildUponParameters().setMaxVideoSizeSd())
player = SimpleExoPlayer.Builder(this)
.setTrackSelector(trackSelector)
.build()
}
playerView!!.player = player
videoViewModel.videoUrlList.forEach {
val mediaItem = MediaItem.fromUri(videoViewModel.getMedia(it)!!)
player!!.addMediaItem(mediaItem)
}
player!!.playWhenReady = videoViewModel.videoStarted
player!!.seekTo(videoViewModel.currentVideoIndex,
videoViewModel.currentVideoPosition.toLong())
player!!.addListener(this)
player!!.addAnalyticsListener(this)
player!!.prepare()
}
And in log I have Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$InvalidResponseCodeException: Response code: 401
this url works correct in webView
fun getMedia(mediaName: String): Uri? {
return if (URLUtil.isValidUrl(mediaName))
Uri.parse(mediaName)
else
null
}
Related
I have HLS stream. When I trying insert VAST tag into stream :
exoplayer not show AD with any errors and warnings in logcat
exoplayer throwing exception, and after re-init with HlsMediaSource.Factory(..) works well
How i build ExoPlayer instance:
private fun initPlayer() {
adsLoader = ImaAdsLoader.Builder(requireContext())
.setAdEventListener { adEvent ->
// SOME LISTENER
}
.build()
val httpDataSource = DefaultHttpDataSource.Factory().createDataSource().apply {
setRequestProperty("Referer", "*some referer*")
}
// Set up the factory for media sources, passing the ads loader and ad view providers.
val httpDataSourceFactory = DataSource.Factory { httpDataSource }
val mediaSourceFactory: MediaSource.Factory =
DefaultMediaSourceFactory(httpDataSourceFactory)
.setLocalAdInsertionComponents(
{ unusedAdTagUri: MediaItem.AdsConfiguration? -> adsLoader }
) { //some view for ad
binding.unsafe.adView
}
// some buffering settings
val loadControlBuilder = DefaultLoadControl.Builder()
loadControlBuilder.setBufferDurationsMs(
AppConstants.Player.PLAYER_BUFFER_DURATION,
AppConstants.Player.PLAYER_BUFFER_DURATION,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
)
// init player
playerInstance =
ExoPlayer.Builder(
requireContext(),
DefaultRenderersFactory(requireContext()),
mediaSourceFactory,
DefaultTrackSelector(requireContext()),
loadControlBuilder.build(),
DefaultBandwidthMeter.Builder(requireContext()).build(),
DefaultAnalyticsCollector(Clock.DEFAULT)
).setSeekBackIncrementMs(AppConstants.Player.PLAYER_SEEK_FORWARD)
.setSeekForwardIncrementMs(AppConstants.Player.PLAYER_SEEK_FORWARD)
.build()
}
How i setup my player for HLS stream:
private fun setupExoPlayer(source: String, adLink: String? = null) {
if (playerInstance == null) initPlayer()
binding {
player.playerView.player = playerInstance
adsLoader?.setPlayer(playerInstance)
player.playerView.subtitleView?.visibility = View.GONE
}
val adsConfig = adLink?.let { MediaItem.AdsConfiguration.Builder(Uri.parse(adLink)).build() }
val mediaItem = MediaItem.Builder()
.setUri(source)
.setAdsConfiguration(adsConfig)
.build()
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
val hlsMediaSource: HlsMediaSource = HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItem)
playerInstance?.apply {
setMediaSource(hlsMediaSource)
prepare()
addListener(playerErrorHandler) // adding some listeners here
playWhenReady = true
}
}
How i insert AD VAST tag after some playing time, difference in setMediaSource or setMediaItem of this source:
private fun injectAdIntoExoPlayer(adLink: String) {
val adsConfig = MediaItem.AdsConfiguration.Builder(Uri.parse(adLink)).build()
val mediaItemWithAd = playerInstance?.currentMediaItem?.buildUpon()?.setAdsConfiguration(
adsConfig
)?.build()
mediaItemWithAd?.let {
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
val hlsMediaSource: HlsMediaSource = HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItemWithAd)
// - first case behavior (not showing ad !!!)
playerInstance?.setMediaSource(hlsMediaSource)
// - second case behavior (showing ad !!!)
// playerInstance?.setMediaItem(hlsMediaSource.mediaItem)
}
}
In second case behaviour exoplayer throws this. Same exceptions I have when init player without HlsMediaSource factory:
E/LoadTask: Unexpected exception loading stream
java.lang.ArrayIndexOutOfBoundsException: size=9400 offset=0 byteCount=-940
at com.android.okhttp.okio.Util.checkOffsetAndCount(Util.java:30)
at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:368)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.readInternal(DefaultHttpDataSource.java:768)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.read(DefaultHttpDataSource.java:478)
at com.google.android.exoplayer2.upstream.StatsDataSource.read(StatsDataSource.java:92)
at com.google.android.exoplayer2.extractor.DefaultExtractorInput.readFromUpstream(DefaultExtractorInput.java:291)
at com.google.android.exoplayer2.extractor.DefaultExtractorInput.read(DefaultExtractorInput.java:68)
at com.google.android.exoplayer2.extractor.ts.TsExtractor.fillBufferWithAtLeastOnePacket(TsExtractor.java:433)
at com.google.android.exoplayer2.extractor.ts.TsExtractor.read(TsExtractor.java:323)
at com.google.android.exoplayer2.source.hls.BundledHlsMediaChunkExtractor.read(BundledHlsMediaChunkExtractor.java:67)
at com.google.android.exoplayer2.source.hls.HlsMediaChunk.feedDataToExtractor(HlsMediaChunk.java:473)
at com.google.android.exoplayer2.source.hls.HlsMediaChunk.loadMedia(HlsMediaChunk.java:437)
at com.google.android.exoplayer2.source.hls.HlsMediaChunk.load(HlsMediaChunk.java:394)
at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
E/LoadTask: Unexpected exception loading stream
java.lang.ArrayIndexOutOfBoundsException: size=8192 offset=0 byteCount=-33
at com.android.okhttp.okio.Util.checkOffsetAndCount(Util.java:30)
at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:368)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.readInternal(DefaultHttpDataSource.java:768)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.read(DefaultHttpDataSource.java:478)
at com.google.android.exoplayer2.upstream.StatsDataSource.read(StatsDataSource.java:92)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:80)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:288)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:351)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:172)
at java.io.BufferedReader.read(BufferedReader.java:193)
at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.checkPlaylistHeader(HlsPlaylistParser.java:296)
at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parse(HlsPlaylistParser.java:259)
at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parse(HlsPlaylistParser.java:68)
at com.google.android.exoplayer2.upstream.ParsingLoadable.load(ParsingLoadable.java:176)
at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
So i need inject my AD Vast tag with exoplayer:extension-ima dependency without handling player error and reiniting with setMediaSource method and without my AD link
I've followed the instruction from Google on how to cast media metadata to chromecast, the initial loading is fine, it will show the title, image and play the stream, but my problem is that I am streaming a live audio stream and need to update the metadata from time to time without having to buffer the audio again.
This is a sample of my code:
override fun loadMediaLoadRequestData(request: PlatformBridgeApis.MediaLoadRequestData?)
{
if (request == null) return
val remoteMediaClient: RemoteMediaClient = remoteMediaClient ?: return
val mediaLoadRequest = getMediaLoadRequestData(request)
remoteMediaClient.load(mediaLoadRequest)
}
fun getMediaLoadRequestData(request: PlatformBridgeApis.MediaLoadRequestData): MediaLoadRequestData {
val mediaInfo = getMediaInfo(request.mediaInfo)
return MediaLoadRequestData.Builder()
.setMediaInfo(mediaInfo)
.setAutoplay(request.shouldAutoplay)
.setCurrentTime(request.currentTime)
.build()
}
fun getMediaInfo(mediaInfo: PlatformBridgeApis.MediaInfo?): MediaInfo? {
if (mediaInfo == null) return null
val streamType = getStreamType(mediaInfo.streamType)
val metadata = getMediaMetadata(mediaInfo.mediaMetadata)
val mediaTracks = mediaInfo.mediaTracks.map { getMediaTrack(it) }
val customData = JSONObject(mediaInfo.customDataAsJson ?: "{}")
return MediaInfo.Builder(mediaInfo.contentId)
.setStreamType(streamType)
.setContentType(mediaInfo.contentType)
.setMetadata(metadata)
.setMediaTracks(mediaTracks)
.setStreamDuration(mediaInfo.streamDuration)
.setCustomData(customData)
.build()
}
Does anyone have any suggestion on how to modify loadMediaLoadRequestData in order to trigger the Chromecast receiver to update only the MediaMetadata and not have the stream buffer again?
I am right now using FFMPEG to stream mp4 file using HLS.
I am using this link to enable encryption: https://hlsbook.net/how-to-encrypt-hls-video-with-ffmpeg/
To play video in my android app, I am using exoplayer, below is my source code to play video:
Player player;
private MediaSource buildMediaSource(Uri uri) {
TrackSelection.Factory adaptiveTrackSelection = new AdaptiveTrackSelection.Factory(new DefaultBandwidthMeter());
player = ExoPlayerFactory.newSimpleInstance(
this,
new DefaultTrackSelector(adaptiveTrackSelection));
playerView.setPlayer(player);
// These factories are used to construct two media sources.
DefaultBandwidthMeter defaultBandwidthMeter = DefaultBandwidthMeter.getSingletonInstance(this);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mContext,
Util.getUserAgent(mContext, "cookvid"), defaultBandwidthMeter);
//DataSource.Factory dataSourceFactory =
// new DefaultDataSourceFactory(this, "exoplayer-codelab");
HlsMediaSource.Factory mediaSourceFactory = new HlsMediaSource.Factory(dataSourceFactory);
return mediaSourceFactory.createMediaSource(uri);
//return new ProgressiveMediaSource.Factory(dataSourceFactory)
// .createMediaSource(uri);
}
private void initializePlayer() {
Uri uri = Uri.parse(getString(R.string.media_url_hls));
MediaSource mediaSource = buildMediaSource(uri);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPosition);
player.addListener(playbackStateListener);
player.prepare(mediaSource, false, false);
}
But with this code, I can not play video in app, If I am not using this encryption ,then exoplayer can play video without any issue.
Please help me on this, I am newbie on exoplayer side.
I created for you an example in Kotlin to make it work:
class MainActivity : AppCompatActivity() {
private var exoPlayer: SimpleExoPlayer? = null
private var trackSelector: DefaultTrackSelector? = null
var drmSessionManager: DefaultDrmSessionManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
trackSelector = DefaultTrackSelector(this)
exoPlayer = SimpleExoPlayer.Builder(this)
.setTrackSelector(trackSelector!!)
.build()
player_view.player = exoPlayer
var uri = Uri.fromFile( File("//android_asset/legend_enc.mp4"))
playVideo(uri, "zX65/4jzTK6wYYWwACTkwg", "Y8tfcYTdS2iaXF/xHuajKA")
}
private fun playVideo(url: Uri, id: String, value: String){
try {
drmSessionManager =
Util.getDrmUuid(C.CLEARKEY_UUID.toString())?.let { buildDrmSessionManager(
it,
true,
id,
value
) }
} catch (e: UnsupportedDrmException) {
e.printStackTrace()
}
exoPlayer?.setMediaSource(buildDashMediaSource(url))
exoPlayer?.prepare()
exoPlayer?.playWhenReady = true
}
private fun buildDashMediaSource(uri: Uri): MediaSource {
val dashChunkSourceFactory = DefaultDataSourceFactory(this, "agent")
return ProgressiveMediaSource.Factory(dashChunkSourceFactory)
.setDrmSessionManager(drmSessionManager ?: DrmSessionManager.DUMMY)
.createMediaSource(uri)
}
#Throws(UnsupportedDrmException::class)
private fun buildDrmSessionManager(uuid: UUID, multiSession: Boolean, id: String, value: String): DefaultDrmSessionManager {
val drmCallback = LocalMediaDrmCallback("{\"keys\":[{\"kty\":\"oct\",\"k\":\"${value}\",\"kid\":\"${id}\"}],\"type\":\"temporary\"}".toByteArray())
val mediaDrm = FrameworkMediaDrm.newInstance(uuid)
return DefaultDrmSessionManager(uuid, mediaDrm, drmCallback, null, multiSession)
}
}
here is two urls. First is "https://28api.haii.io/media/video/video_60_1.mp4",and Second is "https://28api.haii.io/media/video/video_70_1.mp4". When I load first video url, it load and play well. But when I load second url, the second video is broken. I can here only audio. So I tried comparing this two video by download.. but I can't understand the difference between this two url. Both are mp4 encoded video. But Exoplayer only load well at first but not at second.... how can I solve this... help me...
private fun initializePlayer() {
if (player == null) {
val trackSelector = DefaultTrackSelector()
trackSelector.setParameters(
trackSelector.buildUponParameters().setMaxVideoSizeSd()
)
player = ExoPlayerFactory.newSimpleInstance(context,trackSelector)
binding.videoPlayer.player = player
binding.videoPlayer.useController=false
binding.playerControl.player = binding.videoPlayer.player
mediaSource = mediaSourceFactory.createMediaSource(Uri.parse(mediaList[currentIndex].url))
player!!.prepare(mediaSource,false,false)
player!!.seekTo(currentWindow, playbackPosition)
player!!.playWhenReady = playWhenReady
setAudioFocus()
player!!.addListener(object : Player.EventListener {
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
when (playbackState) {
Player.STATE_IDLE -> {
}
Player.STATE_BUFFERING -> {
}
Player.STATE_READY -> {
}
Player.STATE_ENDED -> {
showPlayButton()
player!!.seekTo(currentWindow, 0)
showThumbnailImage()
player!!.playWhenReady = false
}
else -> {
}
}
}
})
}
}
private fun getVideoSource(url :String){
videoUrl = url
var mediaSource = mediaSourceFactory.createMediaSource(Uri.parse(url))
player!!.prepare(mediaSource)
playbackPosition=0
player!!.seekTo(currentWindow, playbackPosition)
player!!.playWhenReady = false
}
I implement exoplayer2 in my app for playing HLS Videos, but sometimes it plays just sound, and doesn't work correctly. What am I supposed to do? I couldn't find why this happens sometimes.
this is the code for initializing player :
fun initPalyer(){
val mainHandler = Handler()
val bandwidthMeter: BandwidthMeter = DefaultBandwidthMeter.Builder(context).build()
bandwidthMeter.addEventListener(mainHandler!!, this)
val trackSelectionFactory: TrackSelection.Factory = AdaptiveTrackSelection.Factory()
trackSelector = DefaultTrackSelector(context, trackSelectionFactory)
val builder = ParametersBuilder(context)
trackSelectorParameters = builder.build()
trackSelector!!.parameters = trackSelectorParameters
var rendersFactory: RenderersFactory = app.buildRenderersFactory(false)
player = SimpleExoPlayer.Builder(
context, renderersFactory
)
.setTrackSelector(trackSelector!!)
.setBandwidthMeter(bandwidthMeter)
//.setLoadControl(loadControl)
.build()
player!!.addListener(this)
loadState()
playerView.player = player!!
}
the code for preparing player :
private fun preparePlayer(uri: Uri) {
val mediaSource = MediaSourceBuilder().build(uri)
durationSet = false
player?.prepare(mediaSource, true, false)
}
and the code for creating mediaSources :
class MediaSourceBuilder {
//Build various MediaSource depending upon the type of Media for a given video/audio uri
fun build(uri: Uri): MediaSource {
val userAgent = PlayerConstants.USER_AGENT
val lastPath = uri.lastPathSegment?:""
val defaultHttpDataSourceFactory = DefaultHttpDataSourceFactory(userAgent)
if(lastPath.contains(PlayerConstants.FORMAT_MP3) || lastPath.contains(PlayerConstants.FORMAT_MP4)){
return ExtractorMediaSource.Factory(defaultHttpDataSourceFactory)
.createMediaSource(uri)
}else if(lastPath.contains(PlayerConstants.FORMAT_M3U8)){
return HlsMediaSource.Factory(defaultHttpDataSourceFactory)
.setAllowChunklessPreparation(true)
.createMediaSource(uri)
}else{
val dashChunkSourceFactory = DefaultDashChunkSource.Factory(defaultHttpDataSourceFactory)
return DashMediaSource.Factory(dashChunkSourceFactory, defaultHttpDataSourceFactory)
.createMediaSource(uri)
}
}
You might wanna change your DataSourceFactory, in case your URL are in HTTPS you might end up with an error, try using DefaultDataSourceFactory instead of DefaultHttpDataSourceFactory