YouTubeStreamFinder
Background
You Tube have a public Data API that allows you to pass a You Tube video id and get a streaming video URL that you can use to play a video in a VideoView.
Sounds Ok BUT they only make the URLs to low quality 3GP video streams avaialble.
You Tube have no official API to get URLs to the higher quality video streams.
Low quality 3GP dates back to the era of 2.5G connections and low power, low resolution handsets - it's 2012 and we have HSDPA, powerful handsets and high resolution displays - 3GP sucks big time!!
There exists an open source android-youtube-player which i was originally going to turn into a B4A library.
The android-youtube-player is actually an entire Activity that you'd add to your B4A (or native Android) project and call using an Intent.
The Intent would identify the video id to play.
android-youtube-player is a full screen landscape mode only Activity - you could not embed it within a B4A Activity as you can a VideoView.
android-youtube-player does however contain code which retrieves all available stream URLs for a video so what i have done is to to identify how the android-youtube-player gets these URLs and create the YouTubeStreamFinder library.
android-youtube-player is licensed under the Apache License, Version 2.0 so no problems there.
I think i'm obliged to make the library code publicly available so the library source code can be found here: Index of /b4a/youtubestreamfinder/src
Technical stuff!
YouTubeStreamFinder is not an Activity object, you should be able to use it as a Process Global with no problems.
The library adds three objects to the B4A IDE: YouTubeStreamFinder, YouTubeVideoInfo and YouTubeStreamInfo.
YouTubeStreamFinder is used to retrieve info about one or more videos using it's GetVideoInfo or GetVideoInfo2 methods.
Retrieval is done in a thread in the library - no blocking of the UI thread should occur.
When video info has been retrieved (or an error has occurred trying to retrieve video info) the YouTubeStreamFinder Ready event will be raised and passed the video id and a YouTubeVideoInfo object if retrieval was successful.
Version: 1.3
Some demo code:
I pass an Array of 3 video ids to the YouTubeStreamFinder GetVideoInfo2 method and the Sub YouTubeStreamFinder1_Ready is called each time YouTubeStreamFinder has finished requesting video info for each of these 3 videos.
VideoId1 passed to that Sub identifies which video the video info request has completed for and if the request was a success then YouTubeVideoInfo1 will contain the requested info.
Different videos will have different available streams and playback support for each available streams seems to vary widely depending on the device in use.
The stream with the FormatId of 18 seems to be available for all videos and also seems to be supported on all devices - but your mileage may vary lol!
This library makes use of an undocumented You Tube web service, i think this web service is used by the official Android You Tube application so it is unlikely to change or stop working as that would break all current versions of the Android You Tube application.
But the web service is an undocumented web service not intended for developer access so there is always a possibility that at some point in the future You Tube will make changes to the web service and the YouTubeStreamFinder library will then be broken.
Library and demo project attached.
Martin.
Background
You Tube have a public Data API that allows you to pass a You Tube video id and get a streaming video URL that you can use to play a video in a VideoView.
Sounds Ok BUT they only make the URLs to low quality 3GP video streams avaialble.
You Tube have no official API to get URLs to the higher quality video streams.
Low quality 3GP dates back to the era of 2.5G connections and low power, low resolution handsets - it's 2012 and we have HSDPA, powerful handsets and high resolution displays - 3GP sucks big time!!
There exists an open source android-youtube-player which i was originally going to turn into a B4A library.
The android-youtube-player is actually an entire Activity that you'd add to your B4A (or native Android) project and call using an Intent.
The Intent would identify the video id to play.
android-youtube-player is a full screen landscape mode only Activity - you could not embed it within a B4A Activity as you can a VideoView.
android-youtube-player does however contain code which retrieves all available stream URLs for a video so what i have done is to to identify how the android-youtube-player gets these URLs and create the YouTubeStreamFinder library.
android-youtube-player is licensed under the Apache License, Version 2.0 so no problems there.
I think i'm obliged to make the library code publicly available so the library source code can be found here: Index of /b4a/youtubestreamfinder/src
Technical stuff!
YouTubeStreamFinder is not an Activity object, you should be able to use it as a Process Global with no problems.
The library adds three objects to the B4A IDE: YouTubeStreamFinder, YouTubeVideoInfo and YouTubeStreamInfo.
YouTubeStreamFinder is used to retrieve info about one or more videos using it's GetVideoInfo or GetVideoInfo2 methods.
Retrieval is done in a thread in the library - no blocking of the UI thread should occur.
When video info has been retrieved (or an error has occurred trying to retrieve video info) the YouTubeStreamFinder Ready event will be raised and passed the video id and a YouTubeVideoInfo object if retrieval was successful.
Version: 1.3
- YouTubeStreamFinder
Events:- Ready (VideoId1 As String, YouTubeVideoInfo1 As YouTubeVideoInfo)
- GetLastError (VideoId As String) As String
Get the last error associated with this VideoId. - GetVideoInfo (VideoId As String)
Get VideoInfo for a single video.
The Ready(VideoId1 As String, YouTubeVideoInfo1 As YouTubeVideoInfo) event
will be raised when VideoInfo is available or an error occurs. - GetVideoInfo2 (VideoIds() As String)
Get VideoInfo for more than one video.
The Ready(VideoId1 As String, YouTubeVideoInfo1 As YouTubeVideoInfo) event
will be raised for each video when VideoInfo is available or an error occurs. - Initialize (EventName As String)
Initialize the YouTubeStreamFinder with an EventName.
- android.permission.INTERNET
- YouTubeStreamInfo
Properties:- FormatId As Int [read only]
- Height As Int [read only]
- StreamUrl As String [read only]
- Width As Int [read only]
- YouTubeVideoInfo
Properties:- Author As String [read only]
- Duration As Int [read only]
Get the duration of the video in seconds. - Keywords() As String [read only]
- Streams As Map [read only]
Get a Map where the Map keys are Int FormatIds and
the Map values are YouTubeStreamInfo objects. - ThumbnailUrl As String [read only]
- Timestamp As Long [read only]
Get the date this video was uploaded to You Tube as a PHP timestamp. - Title As String [read only]
- VideoId As String [read only]
Some demo code:
B4X:
'Activity module
Sub Process_Globals
End Sub
Sub Globals
Dim SelectedVideoTitle As String
Dim Streams As Map
Dim VideoStreamSpinner As Spinner
Dim VideoTitleSpinner As Spinner
Dim VideoView1 As VideoView
Dim YouTubeStreamFinder1 As YouTubeStreamFinder
End Sub
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("Main")
Streams.Initialize
VideoView1.Initialize("VideoView1")
VideoView1.MediaControllerEnabled=True
Activity.AddView(VideoView1, 0, VideoTitleSpinner.Height, 100%x, 100%y-VideoTitleSpinner.Height)
' Initialize the YouTubeStreamFinder with an EventName
YouTubeStreamFinder1.Initialize("YouTubeStreamFinder1")
' get video info for three videos, these Strings are the YouTube video ids
YouTubeStreamFinder1.GetVideoInfo2(Array As String("t56cHZymmvs", "0ZFhjLw6f_k", "HfT7cPI_mRc"))
ToastMessageShow("Waiting for YouTubeStreamFinder", False)
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub VideoTitleSpinner_ItemClick (Position As Int, Value As Object)
' the user has selected a video by it's title
' populate the VideoStreamSpinner with available streams for the selected video
If VideoView1.IsPlaying Then
VideoView1.Stop
End If
SelectedVideoTitle=Value
Activity.Title=SelectedVideoTitle
Dim SelectedVideoStreams As Map
SelectedVideoStreams=Streams.Get(SelectedVideoTitle)
Dim YouTubeStreamInfo1 As YouTubeStreamInfo
VideoStreamSpinner.Clear
Dim i As Int
For i=0 To SelectedVideoStreams.Size-1
YouTubeStreamInfo1=SelectedVideoStreams.GetValueAt(i)
VideoStreamSpinner.Add(YouTubeStreamInfo1.Width&" x "&YouTubeStreamInfo1.Height&" ("&YouTubeStreamInfo1.FormatId&")")
Next
ToastMessageShow("Now select video stream, 18 is recommended", False)
End Sub
Sub VideoStreamSpinner_ItemClick (Position As Int, Value As Object)
' the user has selected a video quality stream - try to play the selected stream
' note that playback of the selected quality/format varies according to the device
' quality/format 18 seems to work on all devices
Dim SelectedVideoStreams As Map
SelectedVideoStreams=Streams.Get(SelectedVideoTitle)
Dim YouTubeStreamInfo1 As YouTubeStreamInfo
YouTubeStreamInfo1=SelectedVideoStreams.GetValueAt(Position)
' uncomment if desired
' VideoView1.Height=YouTubeStreamInfo1.Height*1dip
' VideoView1.Width=YouTubeStreamInfo1.Width*1dip
VideoView1.LoadVideo("http", YouTubeStreamInfo1.StreamUrl)
VideoView1.Play
End Sub
Sub YouTubeStreamFinder1_Ready(VideoId1 As String, YouTubeVideoInfo1 As YouTubeVideoInfo)
' video info retrieval for a single video has completed
If YouTubeVideoInfo1=Null Then
' YouTubeVideoInfo1 will be Null if an error has occurred
ToastMessageShow("Failed to find streams for "&VideoId1, False)
Log(YouTubeStreamFinder1.GetLastError(VideoId1))
Else
' save the Streams property as a global so we can use it when a Spinner item is clicked
Streams.Put(YouTubeVideoInfo1.Title, YouTubeVideoInfo1.Streams)
' add the video title to the VideoTitleSpinner
VideoTitleSpinner.Add(YouTubeVideoInfo1.Title)
End If
End Sub
I pass an Array of 3 video ids to the YouTubeStreamFinder GetVideoInfo2 method and the Sub YouTubeStreamFinder1_Ready is called each time YouTubeStreamFinder has finished requesting video info for each of these 3 videos.
VideoId1 passed to that Sub identifies which video the video info request has completed for and if the request was a success then YouTubeVideoInfo1 will contain the requested info.
Different videos will have different available streams and playback support for each available streams seems to vary widely depending on the device in use.
The stream with the FormatId of 18 seems to be available for all videos and also seems to be supported on all devices - but your mileage may vary lol!
This library makes use of an undocumented You Tube web service, i think this web service is used by the official Android You Tube application so it is unlikely to change or stop working as that would break all current versions of the Android You Tube application.
But the web service is an undocumented web service not intended for developer access so there is always a possibility that at some point in the future You Tube will make changes to the web service and the YouTubeStreamFinder library will then be broken.
Library and demo project attached.
Martin.
Attachments
Last edited: