Stream YouTube video from extracted url - wpf

I am trying to find solution to play YouTube video from http stream. Not as embedded player or via website. The reason of that as I need to play some clips locally in app that prevented to be embedded.
So the first task to obtain http stream is easy to solve, e.g. using YouTubeExtractor. For example from this youtube url
https://www.youtube.com/watch?v=31crA53Dgu0
YouTubeExtractor extracts such url for downloading video. As you can see there is no piece of path to concrete .mp4 or .mov file. There is also binding to IP, so the url won't work on your side.
https://r3---sn-puu8-3c2e.googlevideo.com:443/videoplayback?sparams=dur,gcr,id,initcwndbps,ip,ipbits,itag,lmt,mime,mm,mn,ms,mv,pl,ratebypass,requiressl,source,upn,expire&source=youtube&initcwndbps=3147500&pl=19&upn=oYYkSNBwoc8&fexp=9412913,9416126,9416891,9422596,9428398,9429016,9431012,9431364,9431901,9432206,9432825,9433096,9433424,9433623,9433946,9434085,9435504,9435703,9435937&id=o-AGanAaajMgOmp4VrXIwo9jewJnqlsvZecDxCcRpSN3lS&expire=1462821352&gcr=ua&ip=12.34.56.149&lmt=1458705532562546&ms=au&mt=1462799507&mv=m&dur=217.849&sver=3&itag=22&key=yt6&mn=sn-puu8-3c2e&mm=31&ipbits=0&mime=video/mp4&ratebypass=yes&requiressl=yes&signature=A142619EBA90D00CC46FF05B9CF1E3469B0EF196.072B532670A4D833582F94CF9C46F1F7D298F230&fallback_host=tc.v1.cache5.googlevideo.com
private string ExtractVideoUrl(string youtubeUrl)
{
IEnumerable<VideoInfo> videoInfos = DownloadUrlResolver.GetDownloadUrls(youtubeUrl, false);
var video = videoInfos.First();
if (video.RequiresDecryption)
{
DownloadUrlResolver.DecryptDownloadUrl(video);
}
return video.DownloadUrl; // videoInfos.First().DownloadUrl;
}
Then to download video this lib uses the code below. The interesting moment is in reading stream and writing to file the contents of youtube video.
var request = (HttpWebRequest)WebRequest.Create(this.Video.DownloadUrl);
if (this.BytesToDownload.HasValue)
{
request.AddRange(0, this.BytesToDownload.Value - 1);
}
// the following code is alternative, you may implement the function after your needs
using (WebResponse response = request.GetResponse())
{
using (Stream source = response.GetResponseStream())
{
**// HOW to Play source stream???**
using (FileStream target = File.Open(this.SavePath, FileMode.Create, FileAccess.Write))
{
var buffer = new byte[1024];
bool cancel = false;
int bytes;
int copiedBytes = 0;
while (!cancel && (bytes = source.Read(buffer, 0, buffer.Length)) > 0)
{
target.Write(buffer, 0, bytes);
....
So the general question is how to play video from that open stream? For example Chrome, Firefox and KMPlayer are doing this easily. The browsers generate a simple page with video tag, so it will be trivial to manage the player through JS. But...internal WebBrowser control can't, it suggests to download file. I tried CEFSharp (Chrome Embeded Framework) and no luck there. Maybe anybody know good video player WPF library which can streaming video? I also tried VLC.wpf and Shockwave Flash, but still unhappy with this extracted url. A lot of searching but results insufficient for now.

After 2 days researching I found the solution of how to play youtube video url directly from WPF application.
Some notes before:
WebBrowser component for WPF and the same for WinForms does not support HTML5. So no way to play video using <video> tag there
Chrome Embeded Framework (CEF)and its CEFSharp wrapper does not support <audio> and <video> tags by default. As I found on SO it is needed to recompile CEF to support audio and it seems video too. --enable-multimedia-streams option didn't work on my side at all to play video
WPF MediaElement component does not support playing video from streams. However there are workaroung exists, they are unsuitable to play youtube url's.
No .NET media player found which could play video from Stream object returned by HttpWebRequest
So the solution is in using GeckoFx webbrowser which is also available via nuget. As it is WinForms based component it is needed to use WinFormsHosting to use it in WPF. Final solution is:
<xmlns:gecko="clr-namespace:Gecko;assembly=Geckofx-Winforms">
....
<WindowsFormsHost Width="400" Height="300" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<gecko:GeckoWebBrowser x:Name="_geckoBrowser"/>
</WindowsFormsHost>
And simple code to use:
public void PlayVideo(string videoId)
{
var url = string.Format("https://www.youtube.com/watch?v={0}", videoId);
var videoUrl = ExtractVideoUrl(url);
_geckoBrowser.Navigate(videoUrl);
}
GeckoFx is depeneded on XulRunner runtime sdk. It is installed with nuget package though. One cons in this solution is the size of all app dependencies increased for over +70mb.

Related

Playing Background Music From Bundled File in Codenameone

I'm trying to have a background sound play in codenameone from an mp3 file that's packaged with the app (beep-07.mp3 is just in the src folder).
I can make it work using MediaManager.createMedia, with code borrowed from this post: How to bundle sounds with Codename One?
But the MediaManager.createBackgroundMedia function only takes in a uri, so I try using MediaManager.createBackgroundMedia("file://beep-07.mp3"); but no sound plays.
Am I doing something wrong in the file string?
The src directory doesn't exist on the device. The files that are there are packaged as resources into the equivalent of a jar. So you need to extract them if you want a URL. Notice this might work with "jar://beep-07.mp3" but I'm not sure.
A more correct approach would be to extract it from the jar on first use then use this URL (the code below assumes static import of the CN class):
String fileName = getAppHomePath() + "beep-07.mp3";
if(!existsInFileSystem(fileName)) {
try(InputStream i = getResourceAsStream("/beep-07.mp3");
OutputStream o = openFileOutputStream(fileName)) {
copy(i, o);
}
}
Media m = MediaManager.createBackgroundMedia(fileName);
FYI since your app is running you don't need background media only foreground media.

Video/3gpp in MediaPlayer on device

I am building a chat app. I am trying to add support for videos.
the URL for the video is https://api.twilio.com/2010-04-01/Accounts/AC5c869939f6863233a73ac697207c3697/Messages/MMf01fb40e39c41feafbc0967590f161e8/Media/MEbd3e3d9a0c2be95e01de341889e8cfbb
Container container = new Container(new BorderLayout());
Media video = com.codename1.media.MediaManager.createMedia(url, true); // url is the url above
video.setNativePlayerMode(true);
MediaPlayer mp = new MediaPlayer(video);
//place the media player in the container
container.add(BorderLayout.CENTER, mp);
Component component = Container.encloseIn(new FlowLayout(Container.RIGHT), container);
When I make a debug build and put this on my iPhone, I just get a black box where I would expect the video player to be.
In the simulator, I got playback controls, but no video either.
What am I doing incorrectly?
Something like this should work on the device although the simulator might be a bit flaky:
Form hi = new Form("Player", new BorderLayout());
try {
Media video = MediaManager.createMedia("https://api.twilio.com/2010-04-01/Accounts/AC5c869939f6863233a73ac697207c3697/Messages/MMf01fb40e39c41feafbc0967590f161e8/Media/MEbd3e3d9a0c2be95e01de341889e8cfbb", true);
hi.add(CENTER, video.getVideoComponent());
video.setNativePlayerMode(true);
hi.show();
hi.addShowListener(e -> video.play());
} catch(IOException err) {
Log.e(err);
hi.add(CENTER, "Failed to load video");
hi.show();
}
Notice a few things:
the simulator doesn't support HTTPS URL's for media due to limitations of JavaFX. It doesn't support some video stream types and might not support 3gp properly
iOS requires an HTTPS URL
I placed the video component in the center of the border layout in a form. This forces a specific size for the video which is important.
3gp is not supported. I convert the video to mp4 and supply the url to that file to the Media Manager and it works fine.

Silverlight MP3 Playing Library

I'm trying to play MP3 files in SilverSprite, and it's super buggy. Is there an alternative library I can use to play MP3s in Silverlight?
Edit: Now that there's a bounty, I'm specifically looking for something that:
Works with SL 3-4
Is a separate project/DLL
Will work in SilverSprite projects (I'm using a layer on top of SS) -- no GUI, just methods I can call to play sounds
Works with content that has the build action set to Content. I cannot use embedded resources due to a bug in SilverSprite. My app will not run.
Plays MP3s.
Can play multiple audio files at the same time
I hope it's clear what I'm trying to find. I would like something I can embed in my own game engine, which sits on top of SilverSprite. I will supply all the audio files in the XAP. (The SilverSprite audio is quite broken and doesn't work.)
Update: The specific direction I would probably like to go in is to instantiate a new MediaElement, set the source, and play it. I have some code below, but a) NaturalDuration.TimeSpan.TotalMilliseconds reports 0, and b) the .MediaOpened never triggers.
MediaElement m = new MediaElement();
m.Source = new Uri("Content/Audio/chimes.mp3", UriKind.Relative);
m.Stop(); // useless?
//m.SetSource(new FileStream("Content/Audio/chimes.mp3", FileMode.Open)); // "Permission denied" exception, is it even finding the file?
m.Volume = 1; // Max
m.Position = TimeSpan.FromMilliseconds(0);
while (m.CurrentState != System.Windows.Media.MediaElementState.Closed)
{
Thread.Sleep(10);
}
m.MediaOpened += (sender, e) =>
{
m.Play();
};
m.Play();
For some working code rather similar to your updated approach see http://www.wiredprairie.us/blog/index.php/archives/577 . Beware that the MediaElement needs to be added to the control/component tree - see http://www.michaelsnow.com/2010/12/17/playing-sound-effects-on-windows-phone-7/.
Two very interesting options for your requirements is this library and this one.
For this kind of stuff you could also implement/use a custom MediaStreamSource like this one... see here and here.
EDIT - some other options:
Playing multiple sounds in parallel via XNA see source code at http://create.msdn.com/en-US/education/catalog/sample/silverlightsound
Using MediaPlayer class from XNA 4 for example:
MediaPlayer.Stop();
MediaPlayer.Volume = 1;
MediaPlayer.Play(Song.FromUri("TestSound", new Uri("/Content/Audio/chimes.mp3", UriKind.Relative)));
As for playing multiple sound files at the same time:
IIRC this is something which could cause your app to fail validation.

YouTube on Windows Phone with MediaElement

This blog post suggests that it might be possible to play YouTube videos with the Silverlight MediaEelement directly.
<MediaElement HorizontalAlignment="Left"
VerticalAlignment="Top"
Source="http://www.youtube.com/get_video?
video_id=8yuIw_0ejLs&t=vjVQa1PpcFPrX3tFoahhu4DbniDIqTLkwybdm8xuCt8%3D&fmt=22"/>
I was wondering if this holds true for the Windows Phone 7. I have an application that is based on playing videos hosted on YouTube, and it would be nice to be able to have more control over the video experience other than just launching the browser with the YouTube video URL.
Unless you have a direct link to video content, you cannot display YouTube videos on Windows Phone 7. As far as I know, get_video is no longer available for public access.
Quoting from the Windows Phone Developer FAQ
How can I play youtube videos in my app?
Use the WebBrowserTask and open the target URL in the browser; if the youtube app is installed, it will play, if not installed, it will prompt the user to install and then play.
For everyone else still curious the problem to overcome is getting a direct link to the video which does require a small hack but it's very reliable and easy to do. Firstly you need the video id so you can get the youtube url which you can use the youtube api for. Then do something like this. I pretty much converted a userscript to silverlight.
WebClient client = new WebClient();
string url = "http://www.youtube.com/watch?v=HLQqOpILDcI";
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(ClientDownloadStringCompleted);
client.DownloadStringAsync(new Uri(url, UriKind.Absolute));
the next bit looks bad.
private void ClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
rx = new Regex("(?<=url_encoded_fmt_stream_map=)([^(\\\\)]*)(?=\\\\)", RegexOptions.IgnoreCase);
match = rx.Matches(flashvars);
string video_format = match[0].ToString();
string sep1="%2C";
string sep2="%26";
string sep3="%3D";
string link = "";
string[] videoFormatsGroup = Regex.Split(video_format, sep1);
for (var i=0;i<videoFormatsGroup.Length;i++){
string[] videoFormatsElem = Regex.Split(videoFormatsGroup[i], sep2);
if (videoFormatsElem.Length<5) continue;
string[] partialResult1 = Regex.Split(videoFormatsElem[0], sep3);
if (partialResult1.Length<2) continue;
string url = partialResult1[1];
url = HttpUtility.UrlDecode(HttpUtility.UrlDecode(url));
string[] partialResult2 = Regex.Split(videoFormatsElem[4], sep3);
if (partialResult2.Length<2) continue;
int itag = Convert.ToInt32(partialResult2[1]);
if (itag == 18){
link = url;
}
}
}
the last bit itag==18 selects the quality according to this
{'5':'FLV 240p','18':'MP4 360p','22':'MP4 720p (HD)','34':'FLV 360p','35':'FLV 480p','37':'MP4 1080p (HD)','38':'MP4 4K (HD)','43':'WebM 360p','44':'WebM 480p','45':'WebM 720p (HD)','46':'WebM 1080p (HD)'};
now you can do whatever you want with the link like open it with mediaplayerlauncher or mediaelement. personally i'd love to download it to isolated storage and play it at the same time but at the moment that seems easier said than done. thanks for your time sorry for the long post.
I am sure you can adjust it for Windows Phone http://www.codeproject.com/KB/WPF/YouViewer.aspx

WPF MediaElement, change audio track

I'm writing a Media Player using WPF and the MediaElement.
I was playing a video i have that has several audio tracks. But they are both playing at the same time :(
How do i just play one of them ? is it at all possible ?
I think this problem is in the audio and video DirectShow codecs you use. Can you play the video correct in the Windows Media Player? If no, please re-install the appropriated codecs.
Some months ago I have completely prototyped the requirements to switch audio tracks in order to show the video-help in our multi-language software.
My experience shows some alternatives:
Use the WMP-control via WinForms host, and then change the language like:
var control = ((IWMPControls3)wmpControl.Ctlcontrols);
control.currentAudioLanguage = 9; // english
The Complete list of the LCID you can find here.
To list all audio tracks in the video you can use something like:
wmpControl.PlayStateChange += (o, args) => {
if(args.newState == 3) {
var control = ((IWMPControls3)wmpControl.Ctlcontrols);
for(int i = 1; i <= control.audioLanguageCount; i++) {
MessageBox.Show(control.getAudioLanguageID(i) + ": " + control.getAudioLanguageDescription(i));
}
}
};
Use the separate audio tracks and play it synchronously to the video using the MediaPlayer. The main problem of this method is, that you must synchronize audio and video playback, start, stop, seeking,.. manually.
I hope this helps you to choose your solution.
It is not possible with the WPF MediaElement. If you have some DirectShow know-how, you can try my WPF MediaKit and either modify the MediaUriElement/Player or create your own.

Resources