Monday, November 21, 2011

Video Player Plugin for PhoneGap Android

One of the more annoying problems when using an Android WebView is that the <video/> tag is not well supported. In fact it is pretty much broken. To that end I spent some time writing a VideoPlayer plugin to help work around the issue. As of the weekend I put in a fix making playing YouTube videos easier so I figured I'd share it with all of you.

Installation of the plugin is pretty simple:

1. To install the plugin, move www/video.js to your project's www folder and include a reference to it in your html file after phonegap.{ver}.js.

<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>

<script type="text/javascript" charset="utf-8" src="video.js"></script>

2. Create a directory within your project called "src/com/phonegap/plugins/video" and copy "src/com/phonegap/plugins/video/VideoPlayer.java" into it.

3. In your res/xml/plugins.xml file add the following line:
<plugin name="VideoPlayer" value="com.phonegap.plugins.video.VideoPlayer"/>

Once installed you will be able to play a video by calling:
window.plugins.videoPlayer.play(url);
The url parameter can be one of three types:

1. The file:// protocol to play something native to the device such as:
window.plugins.videoPlayer.play("file:///sdcard/MyMovie.mp4");
2. The http:// protocol to play something on the internet such as:
window.plugins.videoPlayer.play("http://path.to.my/file.mp4");
3. The http:// protocol pointing to a video on YouTube such as:
window.plugins.videoPlayer.play("http://www.youtube.com/watch?v=E0UV5i5jY50");
As long as your url has "youtube.com" and contains the video ID (i.e. the v parameter) the VideoPlayer should be able to start the YouTube app on your phone to play the video without any additional user interaction. However, if the phone does not have the YouTube app you are out of luck. In the future I may add a check for this that will ask the user to install the YouTube app first.

Sadly at this point in time the VideoPlayer does not support playing videos from your android asset directory. That is an enhancement for a later date.

So, there you go a pretty simple and easy to use plugin which can get you unstuck if you really need to play a video in your Android PhoneGap application. Lemme know you feedback.

52 comments:

JFFortierQc said...

Hi
We did the 3 step installation process, so the video.js is beside the phonegap-1.2.0.js, the XML file is update with the plugin line, and the folder src/com/phonegap/plugins/video with the java file is beside the Eclipse project (We also test is in the www folder just in case).

Well we always get this error
11-22 21:33:34.009: D/PhoneGapLog(416): TypeError: Result of expression 'window.plugins' [undefined] is not an object.
11-22 21:33:34.009: D/PhoneGapLog(416): undefined: Line 1 : TypeError: Result of expression 'window.plugins' [undefined] is not an object.
11-22 21:33:34.009: E/Web Console(416): TypeError: Result of expression 'window.plugins' [undefined] is not an object. at undefined:1

We tested on Android 2.3.3 and Android 3.2
We develop on a Mac using Eclipse

Any idea why we can't make it works?

Simon Mac Donald said...

@JFFortierQc

Hmm..it sounds like you are setup correctly. Are you waiting for the "deviceready" event before trying to call window.plugins.videoPlayer.play()?

A sample project would look like:

src\com\test\TestActivity.java
src\com\phonegap\plugins\video\VideoPlayer.java
www\index.html
www\phonegap-1.2.0.js
www\video.js

JFFortierQc said...

Hi again Simon
I remove the JAR of phonegap, configure de Build Path, add the JAR file again, I did a Project > clean...

Now the error is
11-23 13:19:45.452: D/PhoneGapLog(390): TypeError: 'undefined' is not an object (evaluating 'window.plugins.videoPlayer')
11-23 13:19:45.452: D/PhoneGapLog(390): undefined: Line 1 : TypeError: 'undefined' is not an object (evaluating 'window.plugins.videoPlayer')
11-23 13:19:45.452: E/Web Console(390): TypeError: 'undefined' is not an object (evaluating 'window.plugins.videoPlayer') at undefined:1

Same Kind, but the 'window.plugins' is now 'window.plugins.videoPlayer'.

I can't make it works, but the message change so just want to let you know.

Are you usign phonegap-1.2.0.js or a previous version? Are you on Mac or PC? I'm trying to find little difference between you and I to get closer to the bug.

JFFortierQc said...

Hi Simon
Sorry to butter you again.

I apologize. I said that PhoneGap was loaded, because I did the click manually after a long delay. That's true. But seams like PhoneGap never call the On Ready. The file JS is there and an alert at the end of the file is triggered. It means that the path is ok. But I don't know why but it's like it doesn't want to start.

I search on Google and found this
http://www.philliprhodes.com/content/phonegap-deviceready-not-called-android

I test it, I put an alert there to and I know that the listener is set. But deviceready is never triggered.

I'm more then confuse now. No Idea why.

Have you an idea on what can be the problem?

JFFortierQc said...

Hi Simon
Forget about my bug. I just restart from scratch the test project. Now it works.

I really don't understand where was the problem. I did the same, but now the Phonegap instantiate normally. So your plugin too.

Thanks for your help. Also, your plugin is really perfect. I have to test it a bit more to understand what are the video limitation, but I think this is not about your plugin, but more about Androïd itself. I found information there : http://developer.android.com/guide/appendix/media-formats.html#recommendations

Thank again

Simon Mac Donald said...

@JFFortierQc glad to hear it is working for you.

Corrado said...

Hi Simon

I have a problem with a local video, if i try to load a video from internet it works fine.
When I try to load the same file as local video, I get an error message "file not supported"

Simon Mac Donald said...

@Corrado what is the path you are trying to play the file from?

Corrado said...

Tried
"file:///android_asset/www/video/file.mp4"
&
"file:///assets/www/video/file.mp4"

Then I read: "Sadly at this point in time the VideoPlayer does not support playing videos from your android asset directory"

Sudheer said...

I am also getting error 'Sorry this video cannot be played' while reading video locally (window.plugins.videoPlayer.play("file:///android_asset/www/VTD04_Centrifugal.mp4");)

Simon Mac Donald said...

@Sudheer

Yes, I mentioned that problem right in my post:

Sadly at this point in time the VideoPlayer does not support playing videos from your android asset directory. That is an enhancement for a later date.

ccabral said...

Can you play videos using rtmp with this plugin?

Simon Mac Donald said...

@ccabral

I've not tried. Do you have an example?

Juan Ceh said...

:]

Simon Mac Donald - thx !!

I did all the process of instalation, but now i don´t know where tu put the code.

window.plugins.videoPlayer.play("http://path.to.my/file.mp4");

In my page there is a button linked to a video.html where the video will be launched on full screen, play, stop n give a option to replay or to come back to the button´s page.

for instance:

< li id="XY " >< a href="video.html" target="_self" id="menubt" >< span >goods< /span>< /a >< / li >

goods

Thx for the attention. sorry if its a stupid question, i´m new at java, css, html. i´m studying

ccabral said...

I am using your plugin to try and play video via a rtmp streaming server. Here is how I am calling the plugin:

window.plugins.videoPlayer.play("rtmp://myURL);
//window.plugins.videoPlayer.play("http://video-js.zencoder.com/oceans-clip.mp4");

The commented out line works perfectly but now I am trying to replicate that with rtmp and I can not.

Would you have any general suggestions?

Simon Mac Donald said...

@ccabral Hmm...now that I look it problem won't do rtmp. Do you have a URL I can use to test?

Simon Mac Donald said...

@Juan

The probably isn't much point to you have a second video.html file. The player launches full screen and has the stop/pause/play controls. Then if the users wants to go back to your app they just click the back button.

So replace the href to video.html with a javascript call to window.plugins.videoPlayer.play()

Juan Ceh said...

hi Simon! Thx for the attention.

i don´t know if video.js works with dreamweaver cs5.5. I´m working with the latest phonegap. When i compile the app , the emulator goes ok, but i can´t see my video. On AVD i setup a sdcard , opened with DDMS and put my file on that.

< a href="javascript:window.plugins.videoPlayer.play("file:///sdcard/Marcello.mp4");" >test < /a >

The process of instalation for Dreamweaver the same? Thx anyways. =]

Simon Mac Donald said...

@Juan

I have no idea on Dreamweaver as I've never used it. If you aren't getting an error in "adb logcat" then it may just be an emulator issue. Have you tried it on a phone?

ccabral said...

http://flowplayer.org/plugins/streaming/rtmp.html

Flowplayer has a sample rtmp video to demonstrate their streaming support. You could use that.

rtmp://dk2isqp3f.rtmphost.com/flowplayer

flowplayer.rtmp-3.2.3.swf

Juan Ceh said...

Hi again Simon! I´ve tested on my asus pad n nothing seems to work. I move my project to eclipse n run it in debug mode. when i click at the buttons with the herf calling the javascript i got this error on console:

Uncaught SyntaxError: Unexpected token } at file:///android_asset/www/menu.html:216 or

Uncaught SyntaxError: Unexpected end of input


Sorry about bothering you. You know a place where can i see a html using the video.js? Maybe i´m missing somth with java... Thx anyway .. I'm ashamed. I´m stcuked about one month!!

sash said...

Hey Simon,

where in my Android project do I put a video thst i´d like to call via your plugin?

I´m able to use your plugin with videos in the web but as i´m not allowed to put local videos in the asset folder where can I put them and how can i call that path?

file:///

cheers, sash

Simon Mac Donald said...

@sash

You'll need to copy the file from the assets directory to the /sdcard when your app first starts up. Possibly over the break I can try and get things playing directly from the assets directory.

Simon Mac Donald said...

@Juan

I just posted this gist.

https://gist.github.com/1507162

You'll have to change the path but it should work fine. Also you may have to change to the phonegap version you are using.

Simon Mac Donald said...

@ccabral

We'd have to write some extra code into the VideoPlayer to support it. Check out this StackOverflow answer:

http://stackoverflow.com/questions/6006043/how-to-stream-over-rtmp-on-android

Juan Ceh said...

Hi Simon!!! I was make some mistakes with java! With your example now everything is working!!!

The plugin is working fine with the phonegap 1.3! No need to rollback!

Really thx! Helped me a lot! SUPER!

Yeong said...

Help! How can i configure the video plugin to hide the video controls or disable the pause, backward, or forward button?

Simon Mac Donald said...

@Yeong

The way I wrote the plugin it isn't possible as I just use an Intent to play the video.

samar said...

Hello Simon,
I have an error with playing the video
"This video cannot be played". It's a remote mp4 video. I installed the plugin as you stated

Simon Mac Donald said...

@samar

What url are you using?

Vishal Lakhmapurkar said...

Hi, I am vishal
i want to load video from my local storage /data/data/video.3gp . Please reply ASAP.

Simon Mac Donald said...

@Vishal

The url should be:

file:///data/data/video.3gp

but you may have a problem if you application does not have access to read files from that directory. Most Android apps store files on their internal file system at /data/data/

Unknown said...

The video couldn't be played.

Remote URL, file .mp4, http.

Works fine with in Chrome, but not with your plugin. What im doing wrong?

This video issues killing me T_T

Simon Mac Donald said...

@Unknown

I don't really know as you haven't given me much to go on. What do you see in "adb logcat"? Are you doing this on a device or emulator? etc. etc.

Unknown said...

Sorry, Simon. Is runned on emulator, now is playing only sound not video.

Simon Mac Donald said...

@Unknown

I don't really trust the emulator for playing video. You are better off testing this on a device if you have one available.

samar said...

Hello Again Simon,
Well, while running more mp4 files I got some files that kept loading then were buffered but did not actually run.
Here is the logCat debug:

01-19 13:10:06.384: D/DroidGap(332): DroidGap.startActivityForResult(intent,-1)
01-19 13:10:06.384: I/ActivityManager(61): Starting: Intent { act=android.intent.action.VIEW dat=http://66.197.168.70/droidanime/Anime/Clannad/7_1_clannad7.mp4 typ=video/* cmp=com.android.gallery/com.android.camera.MovieView } from pid 332
01-19 13:10:06.464: I/WindowManager(61): Setting rotation to 1, animFlags=1
01-19 13:10:06.474: I/ActivityManager(61): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=2/1/2 nav=3/1 orien=2 layout=17 uiMode=17 seq=5}
01-19 13:10:06.574: I/Ads(332): Received ad url: <"url": "http://googleads.g.doubleclick.net:80/mads/gma?preqs=2&u_sd=1.5&slotname=a14d46113b14470&u_w=160&msid=Objects.Company.DroidAnime&cap=m%2Ca&js=afma-sdk-a-v4.3.1&isu=B3EEABB8EE11C2BE770B684D95219ECB&cipa=0&format=320x50_mb&net=ed&app_name=1.android.Objects.Company.DroidAnime&hl=en&u_h=213&u_audio=4&prl=2945&u_so=p&output=html&region=mobile_app&u_tz=0&ex=1&client_sdk=1&askip=2&pto=0&jsv=1", "afmaNotifyDt": "null">
01-19 13:10:06.933: I/ActivityManager(61): Displayed com.android.gallery/com.android.camera.MovieView: +550ms (total +831ms)
01-19 13:10:07.033: D/MediaPlayer(361): Couldn't open file on client side, trying server side
01-19 13:10:07.043: I/StagefrightPlayer(34): setDataSource('http://66.197.168.70/droidanime/Anime/Clannad/7_1_clannad7.mp4')
01-19 13:10:07.063: I/NuHTTPDataSource(34): connect to 66.197.168.70:80/droidanime/Anime/Clannad/7_1_clannad7.mp4 @0
01-19 13:10:07.224: W/InputManagerService(61): Starting input on non-focused client com.android.internal.view.IInputMethodClient$Stub$Proxy@406084f0 (uid=10034 pid=332)
01-19 13:10:07.284: W/IInputConnectionWrapper(332): showStatusIcon on inactive InputConnection
01-19 13:10:09.274: D/dalvikvm(61): GC_EXPLICIT freed 363K, 48% free 4225K/8071K, external 3173K/4373K, paused 77ms
01-19 13:10:10.324: W/webcore(332): Can't get the viewWidth after the first layout
01-19 13:10:11.234: I/Ads(332): onReceiveAd()
01-19 13:10:11.234: W/Ads(332): Not enough space to show ad! Wants: <480, 75>, Has: <240, 282>
01-19 13:10:11.234: D/SoftKeyboardDetect(332): Ignore this event
01-19 13:10:28.904: I/NuCachedSource2(34): new range: offset= 71374979
01-19 13:10:28.904: I/NuHTTPDataSource(34): connect to 66.197.168.70:80/droidanime/Anime/Clannad/7_1_clannad7.mp4 @71374979
01-19 13:10:34.286: I/NuCachedSource2(34): new range: offset= 94946210
01-19 13:10:34.286: I/NuHTTPDataSource(34): connect to 66.197.168.70:80/droidanime/Anime/Clannad/7_1_clannad7.mp4 @94946210
01-19 13:10:47.684: D/dalvikvm(332): GC_CONCURRENT freed 1188K, 56% free 3103K/6983K, external 2379K/2971K, paused 4ms+5ms
01-19 13:10:47.724: D/webviewglue(332): nativeDestroy view: 0x60dce0
01-19 13:10:47.734: D/webviewglue(332): nativeDestroy view: 0x566c40
01-19 13:11:09.224: I/NuCachedSource2(34): ERROR_END_OF_STREAM
01-19 13:11:10.324: D/MediaPlayer(361): getMetadata
01-19 13:11:10.354: I/NuCachedSource2(34): new range: offset= 71374987
01-19 13:11:10.440: I/NuHTTPDataSource(34): connect to 66.197.168.70:80/droidanime/Anime/Clannad/7_1_clannad7.mp4 @71374987
01-19 13:11:13.803: D/AudioSink(34): bufferCount (4) is too small and increased to 12
01-19 13:11:13.803: I/AwesomePlayer(34): cache is running low (0.51 secs) , pausing.

Thanks Simon

ccabral said...

Hey Simon,

Video Plugin works great. Now that I have videos playing full screen, I was wondering if you would know how to get the videos to play on a portion of the screen, i.e. a defined box. Is this possible with your plugin or the native player?

I have done some reading on Android VideoView but haven't been able to get that to work with phone gap.

If you had any insight on how to play video inside phone gap in only a portion of the screen that would be great.

Thanks.

Simon Mac Donald said...

@ccabral

Well that is what the video tag is supposed to be for but as we know it is broken in WebView right now. However, there is light at the end of the tunnel. We are working on an update to PhoneGap for late February which will allow you to embedded PhoneGap into your Android app. This way you can have two (or more) views in the same activity 1 is the PhoneGap view and the other is whatever you want and in your case a VideoView. So, in summary we can't do it right now but the capabilities are coming.

ccabral said...

Simon,

Thank you for response and I appreciate you help. Sorry for the sake of redundancy here, but at this time there is no way to write a plugin or something similar within Phone Gap to play a video not in full screen. Sorry to ask again but I need a definitive no.

Thanks again.

Simon Mac Donald said...

@ccabral

It is possible but not trivial. You would need to modify the source of the PhoneGap framework in order to do it though. Yay open source.

What I am saying is that it'll be much easier once 1.5 is released at the end of February.

Simon Mac Donald said...

@samar

Sorry for not seeing your comment earlier. I actually have no idea why you can't play that mp4 perhaps it is an encoding error.

Dragos Matei said...

Hello. I have written an app for kids and I need to open a youtube video in a way that doees not allow kids to access other potetial harmful content on youtube (now they can put the phone in portrait mode and search or see related videos that may not be for kids...).
I would appreciate any sollution, maybe a parameter send to youtube, a builtin player that could play the youtube videos as well or a webview embedded video?
Thank you very much. :)

Simon Mac Donald said...

@Dragos

Sorry, I don't know how to do what you want. For the VideoPlayer plugin I only fire off the intent to start the YouTube app. I'm not sure if there is anyway you can prevent people from going to other videos once it is started.

alzika said...

How do I add a button, for example, to the top left corner that overlays on top of any playing video? This would be a "back" button and takes me back to the app from the video.

Thanks

Simon Mac Donald said...

@alzika

It is best just to use the back button provided by Android. The way I wrote the plugin it just starts an intent so you get whatever that intent provides. If you really want a back button you may need to write your own Java code to setup the correct View with a back button.

ccabral said...

Hi Simon,

I noticed that there is a new version of Phone Gap, 1.4.1. Is this the release you were referring to that will support multiple views?

Thanks.

Simon Mac Donald said...

@ccabral

No, not 1.4.1. 1.5 will have some support for embedding PhoneGap as a component in your Android app.

alzika said...

How do I include the video plugin in with the PhoneGap build service where I upload a zip file?

I'm confused since I don't know where the java file for this would go.

I'm trying desperately to get an app launched for a client who came up to me last minute needing video capabilities cross-platform. Sometimes they truly don't understand what all is involved, especially since I'm a PHP coder and not an app developer.

Thanks

Simon Mac Donald said...

@alzika

I don't have anything to do with the PhoenGap Build Service. You are better off asking your question at:

http://community.phonegap.com/nitobi/products/nitobi_phonegap_build?from_gsfn=true

MB said...

Hi,
i'm italian so i'm sorry for my english. First of all i wanna say that your plugin is wonderfull and provides the only important thing that phonegap doesn't have: video support on android.
I've notice a problem in some device. Using my HTC Desire if i play video and then press back button it's return in the page where i click button (that call playvideo method).. but in some device, like xperia x10 and galaxy tab, if i press the back button it's back in the home of the application and restart it. I can notice that it's restart because i load the second page by ajax, and in that device it's reload the page as it was just start the app. Do you know why it appens?
Thank's a lot

Simon Mac Donald said...

@MB

Sorry, I'm not sure why the app is restarting when you return to it. Perhaps you get low on memory while the video is playing so Android clears out your app so when you return to it on the stack it has to be restarted.

The other thing you want to check is that you have the following attribute in your AndroidManifest.xml file:

android:configChanges="orientation|keyboardHidden|screenSize"