protofunc()

Das Problem mit dem HTML 5 Video Element

Tags: HTML 5, deutsch, javascript, video

Ich arbeite in letzter Zeit immer wieder mit dem HTML 5 Video Element. Bis auf einige kleinen Problemchen mit der API sowie einigen grausamen Implementierungsbug im Safari (betrifft nicht Chrome), bin ich eigentlich ganz zufrieden.

Es gibt aber letztendlich eine Sache die mich extrem rasend macht. Schaut man sich die Youtube HTML5 Demo an und vergleicht diese mit der Spezifikation wird einem klar, daß Youtube mit HTML5 nie so aussehen kann, wie diese Demo einem glauben machen will.

Die Demo zeigt einen Fullscreen-Button. Leider ist die HTML5 Spezifikation hier sehr einduetig. Einerseits ist keine API für einen möglichen Fullscreen-Modus definiert andererseits werden Browserhersteller mit fetter, roter Schrift ausdrücklich davor gewarnt, eine solche zu implementieren. Als Begründung wird auf mögliche “Nervigkeiten” sowie Angst vor Sicherheitsproblemen, genauer Phishing Attacken, abgestellt.

Letztendlich ist die Begründung vollkommen überholt und daneben. Das Security Argument stimmt nicht, da

  • ein Videoelement beim Starten des Vollbildmous grundsätzlich einen entsprechenden Hinweis zeigen soll
  • ein Videoelement im Vollbildmodus, unabhängig vom Vorhandensein des controls-Attribut, die Kontrollelemente anzeigen muß
  • es im Vollbildmodus gar nicht möglich ist – und das wäre das eigentliche Sicherheitsrisiko – Tastaturevents abzufangen

Auch das Risiko einer Belästigung des Users ist gering, wenn man es mit ähnlichen Einschränkungen implementieren würde wie dies bei Adobe Flash getan wurde. Gerade Flash, welches häufig für nervige Dinge wie Werbebanner eingesetzt wird, hat eine API für den Fullscreenmodus, anstatt daß dies mich nervt, empfinde ich es als extrem nützlich.

Hier lag wohl auch augenscheinlich das Problem. Eine API für den Fullscreenmodus wurde mit Methoden wie window.open oder window.resize verglichen, ohne zu erkennen, daß das Anschauen von Videos im Vollbildmodus ein wesentlich nützlicheres Feature ist als das ungefragte Öffnen von Popups und Verschieben von Browserfenstern.

Meine große Hoffnung liegt nun darin, daß entweder irgendein Browser (zum Beispiel: Chrome 4 oder 5 oder Internet Explorer 9) aus der Reihe tanzt und zeigt wie man ein cooles, sicheres Feature implementiert oder daß bei der Zugänglichkeits- (oder vielleicht auch Usability-) überarbeitung des Elements auffällt, daß ein Fullscreenmodus nicht allein mit der rechten Maustaste als Kontextmenü realisiert werden darf.

Ich kotze.

Written January 19, 2010 by
alexander farkas

Animation-Ajax-Queue erstellen

Tags: ajax, deutsch, javascript, jquery, tutorial, video

Eine häufigere Aufgabe ist es bei Ajax Requests den alten Content durch eine Animation zu verstecken, dann den Content auszutauschen und diesen dann durch eine weitere Animation anzuzeigen.

Hierbei stellt sich das Problem, daß die genaue Dauer der Ajax-Response unbekannt ist. Ist die Response deutlich kürzer als die Verstecken-Animation, kann der Inhalt nicht ausgetauscht werden, da der User dann während dieser Animation plötzlich bereits den neuen Content sieht.

Um dieses Problem zu lösen, eignet sich jQuery´s queue Methode sehr gut, welche bereits genutzt wird, um Animationen in eine Warteschlange zu stellen. Um diesen Animationsqueue zu nutzen, muß der Ajax-Callback sich zu diesem Queue hinzufügen. Wird die Animation noch ausgeführt, wird dessen Ende abgewartet ansonsten wird die Callback-Funktion sofort ausgeführt.

Eine kleine Funktion, die aus einer Callback-Funktion eine sich in die Effekt-Warteschlange “anstellende” Funktion macht, könnte wie folgt aussehen:

$.createQueueCallback = function(jElm, fn, type){
	type = type ||
		'fx';
	return function(){
		var that = this,
			args = arguments;

		jElm = $(jElm);
		jElm.queue(type, function(){
			fn.apply(that, args);
			jElm.dequeue(type);
		});
	};
};

Dieser Methode wird als 1. Parameter ein jQuery-DOM-Object, ein DOM-Objekt selbst oder ein CSS-Selektor, als 2. Parameter die Callback-Funktion und als 3. optionaler Parameter der Name der Warteschlange übergeben. Die Benutzung könnte so aussehen:

function requestContent(){
	var live = $('#live')
		.hide(500);

	$.ajax({
		url: 'htmlsnippet.txt',
		success: $.createQueueCallback(live, function(data){
			live
				.html(data)
				.show(200);
		}),
		error: function(){
			//immer errors handeln
		}
	});
	return false;
}

Folgend findet ihr eine Ajax-FX-Queue-Demo als Download.

Written March 15, 2009 by
alexander farkas

Controlling Embedded Video with Javascript Part I: Quicktime

Tags: english, javascript, tutorial, video

This is the first part in a little series of articles about scripting the controls of video with Javascript. I worked on a project recently where using flash for video was not an option, but instead all other major formats/plugins had to be supported (quicktime, windows media player, real player, vlc player). While researching for this project, I noticed that there was a certain lack of easily accesible information about this topic, especially concerning cross-plugin and cross-browser functionality. That’s why I decided to write these articles, maybe they can help someone who’s trying to do something similar.

Javascript can be used to control nearly every aspect of the mentioned plugins’ behaviour. Usually the reason for scripting video plugins will be to create a custom control interface, while the standard controls are hidden. One should think very carefully about this from a usability perspective, because most users will be more familiar with the standard controls. Also there will always be certain (older) browsers-plugin-combinations that will not behave as expected, possibly preventing certain users from accessing the content. Therefore it’s always a good idea to have some sort of fallback plan (i.e. show standard controls if Javascript is deactivated… think graceful degradation).

This first article will cover the Quicktime plugin, followed shortly by WMP, Real, and VLC. Below is a list of desired features that should ideally work across all plugins and browsers. The approach I want to take is to create a common interface of functions covering the desired features and implement the interface for each plugin (view the interface functions – Note: This is an interface by convention only, it is not enforced through code). That way the underlying plugin can be easily swapped without changing much code. See the Quicktime scripting demo page for a working example.

List of desired features:

  1. cross-browser embedding with standard interface deactivated
  2. basic playback controls: play, pause, stop
  3. display current time, duration, and status information
  4. jump to specified time within movie
  5. volume control
  6. change/load movie
  7. buffering
  8. fullscreen display

Embedding Quicktime

To begin with we must embed the quicktime plugin properly so that it works in all major browsers (Quicktime version 7.4 as of writing). I won’t go into much detail here, since this has been covered sufficiently elsewhere (i.e. here or here). This is the method that I’ve used:

<object id="moviename"
    classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
    codebase="http://www.apple.com/qtactivex/qtplugin.cab"
    width="320" height="260">
    <param name="src" value="url/to/movie.mov" />
    <param name="controller" value="false" />
    <param name="autoplay" value="false" />
    <!--[if !IE]-->
    <EMBED name="moviename"
        height="260"
        width="320"
        src="url/to/movie.mov"
        type="video/quicktime"
        pluginspage="www.apple.com/quicktime/download"
        controller="false"
        autoplay="false"
    />
    <!--![endif]-->
</object>

In order to avoid the <embed> tag, which is non-standard (i.e. won’t validate), there are ways to use nested <object> tags instead (see A List Apart Articles: Bye Bye Embed), but I could not get the scripting to work properly in that case (any evidence of the contrary would be greatly appreciated…).

Note: This method of embedding the Quicktime plugin does not address the ActiveX activation issue in Internet Explorer – therefore you will currently need to click on the video once in order to activate it. It seems though that Microsoft is finally going to change the behaviour of embedded controls so that this won’t be an issue any longer after April 2008 (see: IEBlog: IE Automatic Component Activation (Changes to IE ActiveX Update)).

Basic Scripting

So let’s get started with the scripting, this is going to be pretty basic stuff – I might cover more advanced topics in separate articles. Note that the presented code is not fully optimized and I’ve ommited safety checks in order to preserve simplicity.

The first thing we need to do is to get a reference to the video object. The easiest way to do this, assuming the embed technique described above is being used, is to give the object tag an ID and the embed tag a NAME with identical values. That way the video can simply be accessed by its name:

var movie = document.moviename;

In this case Internet Explorer will use the ID attribute and all other browsers the NAME attribute. Once we have a reference to the actual video, we can start manipulating it – the basic playback controls would look something like this:

function playVideo() {
	movie.Play();
}

function pauseVideo() {
	movie.Stop();
}

function stopVideo() {
	movie.Stop();
	movie.Rewind();
}

Before actually manipulating the movie it is usually a good idea to check the status of the movie to make sure that it is ready for action. Otherwise if you try to access the video too early before it has loaded, Javascript errors can occur. The following method will return a string with the status of the movie:

function getStatus() {
	return movie.GetPluginStatus();
}

It’s safe to access the movie, if the status is either “Playable” or “Complete”. The returned string will have one of these values:
“Waiting” – waiting for the movie data stream to begin
“Loading” – data stream has begun, not able to play/display the movie yet
“Playable” – movie is playable, although not all data has been downloaded
“Complete” – all data has been downloaded
“Error: ” – the movie failed with the specified error number

The next two functions show how to access the current playback time and the duration of the movie. The thing to note here is that the time returned by “GetTime()” and “GetDuration()” are in the movie’s time scale units. In order to convert this to seconds one needs to divide it by the time scale (units per second). This will then give you the time in seconds, usually you will then want to convert this into a nicely readable string format (something like: hh:mm:ss).

function getTime() {
	return movie.GetTime() / movie.GetTimeScale();
}

function getDuration() {
	return movie.GetDuration() / movie.GetTimeScale();
}

In order to set the movie to a specific position, one basically has to do the opposite – multiply the movie’s timeScale with the desired position in seconds. Note that the time cannot be set beyond what has currently been buffered – if you attempt to do this it will set the time to the last buffered frame.

function setTime(sec) {
      movie.SetTime( sec * movie.GetTimeScale() );
}

The volume within Quicktime has a range of 0 – 255. I will convert this to be within a range of 0 – 100, because I think it is easier to work with in that range.

function getVolume() {
	return parseInt( movie.GetVolume() * 100 / 255 );
}

function setVolume(vol) {
	movie.SetVolume( vol * 255 / 100 );
}

To swap the movie that’s being played, just set a new URL. For some reason Quicktime will show the default controller again if you change the URL – so in order to keep it hidden, you will need to manually hide it again.

function loadURL(url) {
	movie.SetURL(url);
	movie.SetControllerVisible(false);
}

When a new movie is initially loaded it will be buffered into memory. It can be useful to give some feedback about the buffering status of a movie. The following function will return the percentage of the movie that has been buffered (0 – 100%):

function getBufferStatus() {
	var timeLoaded = movie.GetMaxTimeLoaded()
	var duration = movie.GetDuration();
	return parseInt( timeLoaded * 100 / duration );
}

As for full screen mode, it is currently (to my knowledge) not possible to invoke Quicktime’s internal full screen mode for embedded movies – even though since version 7.2 it has become a feature of the free standalone player.

That about wraps it up, check out the demo page and feel free to post any questions or feedback.

Links

Written February 1, 2008 by
boris