Windows Media Player in Delphi

Delphi ships with a component ‘TMediaPlayer’ for playing media files such as video and audio. This component remains in Delphi for the sake of compatibility with older versions, but is quite out-dated and, due to a decreasing number of compatible codecs, it is becoming difficult to maintain. There is however an alternative component for Windows, the Microsoft Windows Media Player ActiveX component.
In this post, I’m going to show you how to import and make use of the Windows Media Player using Delphi.

For as long as I can remember, certainly as far back as Delphi 5 if not earlier versions, the RAD Studio IDE has had an import wizard built in which allows you to import ActiveX components. Note that ActiveX has been known as COM, COM+, OLE and possibly other names over the years, Microsoft doesn’t seem to have been able to settle on a name for this technology. Regardless of what it’s called, it’s a technology for turning some technologies into components, and provides a language agnostic interface to those components. Many components of the windows system are available in ActiveX form, including the web browser which Delphi wraps as it’s TWebBrowser component for VCL, and the Windows Media Player component.

*Note: I’ll be using screen shots to describe the component import wizard and to show you how to set the search path in the project options window, but from there on I assume you are familiar enough with the IDE to set properties, event handlers and so on.

Installing the media player component.

Lets take a walk through the import wizard for ActiveX components.
From the “Component” menu in your IDE, select “Import Component”

As we’re importing this component for Delphi, select the “VCL for Delphi Win32” option from the next page on the wizard and click “Next”

On the next wizard page, we’re invited to specify which type of component or library we’d like to import. On this page we’re going to select “Import ActiveX Control”, but notice also that we could import a .NET assembly. If you have interest in importing a .NET assembly, you may find my blog post on importing C# COM objects interesting. For now though, go ahead and select the option to import an ActiveX control, and click Next.

You’ll now be presented with a list of ActiveX controls which are registered on your Windows system. You’ll likely have to resize the wizard page and adjust the column widths at this point to see everything. Most importantly, stretch open the column named “Description” so that you can see what you’re importing. You’re looking for “Windows Media Player” and on my system this appears very close to the bottom of the list. Highlight the media player and click next.

The next page of the wizard asks for information about the Delphi component that will be created. It’s important to understand here that the Delphi component is a wrapper around the ActiveX component. The code for the media player is not being imported and bundled into a Delphi component which may be linked into your application, but rather, a Delphi component which is able to reach into the Windows API’s to find and operate the Windows Media Player component is created. This means that your application will only work if the Windows Media Player component is already installed and available on the machine on which it runs.

Fortunately, in the case of the Windows Media Player component, it’s installed by default with Microsoft Windows and has been since Windows 7 (and maybe earlier?), so you need not deploy dependencies with your application. The reason I mention this however, is that it’s entirely possible that Microsoft stop shipping the Windows Media Player component at some point in the future, perhaps because they replace it with some other component, or perhaps because they change the underlying technology or API. It’s not overly likely, but it is possible, so be aware of this risk before using the component.

Okay, so on the wizard there are only two options that may need to be changed from their defaults. The first is the palette page, which I’ll be leaving as default “ActiveX”, this parameter specifies the palette page (or rather, in newer versions of RAD IDE the “tool palette page”) on which the Windows Media Player component will be placed in the IDE.

The second parameter to alter is the “Unit Dir Name” to specify where the component source code will be placed after it is generated by the wizard. Select a location on your disk for the source code to be written to, and click next. (Note, I’m selecting a location within my source code attached directory, so that the sources will be uploaded to my repository for future use and so that I don’t need to run the import wizard again for this component.)

On the next page of the wizard, you’re asked if you’d like to create only the source code unit, or if you’d like to install that source code into a package which may be installed into the IDE. You also have the option of adding the component to an existing package. I’m going to select “Install into New Package”, and I’ll assume you’re doing the same. Make the change and click the “next” button.

The wizard is now asking what you’d like to name the component package, I’m going to name mine “pkg_windowsmediaplayer” but you can name it just about anything you like. The package name box actually requires a complete file-path to the location that you wish to store the package. Go ahead and select a location on your disk, you can place it in the same directory as you selected for the component source code for convenience.

Be sure to put something in the box for the component description too, such as “Windows Media Player” for example.
When you’ve selected an appropriate package name and location, the “Finish” button will become enabled, go ahead and click it.

Depending on your version of Delphi / RAD, you may now be presented with a warning dialog asking if you wish to add the VCL as a reference framework to the package. Go ahead and click “Yes” to import the VCL reference and dismiss the dialog.

You’ll now see the component being built, and if all goes well you’ll be presented with this dialog…

The dialog tells you that many component classes have been installed. What has happened is the Windows Media Player component has been imported as “TWindowsMediaPlayer”, but also, several other related components have been imported. This is necessary, the windows media player component is a composite of each of these other components. You could modify the source code which has been generated so that only the TWindowsMediaPlayer component is registered if you wish, however, you may find some of these other components useful so why not leave them where they are for now, you can explore them for yourself later.

Click “Ok” to dismiss the dialog if you’ve not already done so.

Lets see this new component.

Select “File / New / VCL Forms Application – Delphi” to close the source code which was generated by the import wizard, and to start a new VCL project.

Now, in the search box above your “Tool Palette” type “TWindowsMediaPlayer” and you’ll see the “ActiveX” tab showing the new TWindowsMediaPlayer component. Go ahead and drop one of these components onto your application form.

Congratulations, you have a fully functional media player component which is capable of playing any media file for which there is an appropriate codec installed.

Configuring the control and your project.

Lets go ahead and configure our project in preparation for playing a video file.
First, notice that if you double click the component within the IDE you’ll be presented with an options dialog:

You could go ahead and select the file you wish the media player to play in the “File Name or URL” box, and because the “Auto start” check box is marked, it would begin playing when you start your application. I’m more interested in doing this from code, because that way we get more control over what the component is doing.

So, leave the “File Name or URL” box empty and clear the “Auto start” check box.
Now alter the drop down box named “Select a mode” and set it to “None”. This is going to remove the control buttons from the control, which of course is optional for your future projects, leave them enabled if you wish, but for now we’re going to replace the controls with code, so go ahead and select “None” to remove them.

With the changes made, click “Apply” and “OK” to dismiss the dialog.

If you try to run your application at this point, you may get an error. Depending upon where you saved the sources of the media component when using the import wizard, they may not be on the search path for your project. Lets correct that.

From the menu, select “Project / Options”

Click the ellipses button to the right of the search path option.
In the next dialog, click on the browse button and browse to the location in which you saved the component sources while importing them.

When you’ve found the location, click “Select Location” to be returned to the above dialog, and then click the “Add” button, to add the directory to your project’s search path…

Now click “OK” on each of the open dialogs, and run your project.

Not overly impressive yet, it’s just a black box. Lets go ahead and have it load and play a media file.
Before we do, go ahead and adjust the “Align” property of the control to “alClient” so that it fills the form.

Playing a video.

Select your form and begin editing the “OnCreate” event.
Enter the following code:

procedure TForm1.FormCreate(Sender: TObject);
begin
  WindowsMediaPlayer1.URL := 'file://C:\BigBuckBunny.mp4';
  WindowsMediaPlayer1.controls.play;
end;

You will need to alter the path ‘file://C:\BigBuckBunny.mp4″ to point to an appropriate media file on your system. You can download the BigBuckBunny.mp4 video here.

Now when you run your application, you should see the video playing…

If you look at the available methods on “WindowsMediaPlayer1.Controls.” you’ll find play(), pause(), stop(), fastforward(), fastreverse() and several other useful control methods which you can turn into control buttons and use to control the media playback.

Monitoring State Changes.

When you play a media file in the Windows Media Player control, the control goes through several state changes. From it’s initial state it enters a “transitioning” state as the media is loaded and before it begins playing, at which point the control transitions to a “playing” state, and then as the video ends (or is stopped) it’ll enter the “transitioning” state again before entering the “stopped” state, and so on.

A list of the states can be found in the constants beginning at line 327 in the WMPLib_TLB.pas file which was generated by the component import wizard…

const
  wmppsUndefined = $00000000;
  wmppsStopped = $00000001;
  wmppsPaused = $00000002;
  wmppsPlaying = $00000003;
  wmppsScanForward = $00000004;
  wmppsScanReverse = $00000005;
  wmppsBuffering = $00000006;
  wmppsWaiting = $00000007;
  wmppsMediaEnded = $00000008;
  wmppsTransitioning = $00000009;
  wmppsReady = $0000000A;
  wmppsReconnecting = $0000000B;
  wmppsLast = $0000000C;

Lets use the state change information to present a progress bar as the video plays.

  • Add a TProgressBar control to your main form and set it’s ‘Align’ property to ‘alBottom’ so that it appears aligned to the bottom of the form beneath the media player control.
  • Also drop a TTimer component on the form, set its “Enabled” property to false, and then set it’s interval to something reasonably small, say 200ms.
  • Now set the “OnPlayStateChange” event of the TWindowsMediaPlayer control to read as follows…
procedure TForm1.WindowsMediaPlayer1PlayStateChange(ASender: TObject; NewState: Integer);
begin
  case NewState of
    wmppsPlaying: begin
      Timer1.Enabled := True;
    end;
    wmppsStopped,
    wmppsPaused: begin
      Timer1.Enabled := False;
    end;
  end;
end;
  • And set the OnTimer event of the timer component as follows..
procedure TForm1.Timer1Timer(Sender: TObject);
var
  Duration: double;
  Position: double;
begin
  Form1.Caption := WindowsMediaPlayer1.controls.currentPositionString
                   + ' of '
                   + WindowsMediaPlayer1.currentMedia.durationString;

  Duration := WindowsMediaPlayer1.currentMedia.duration;
  Position := WindowsMediaPlayer1.controls.currentPosition;
  ProgressBar1.Position := Trunc( Position*(Duration/ProgressBar1.Max) );
end;

Go ahead and run your application (In the debugger).

You should see a progress bar updating as the video progresses and you should see the progress updating in the main form caption.
If you’re using the BuckBunny video, give it a minute or so to see the first update to the progress bar, it’s a long video and the Progress Bar default maximum is only 100 units…

Congratulations! You have a working media player.
However, if you close the application while the video is playing you’ll get an error, something like this…

Hit the “Break” button to escape the dialog onslaught which would otherwise follow, and then stop the debugger in the IDE.
The problem we’ve come across here is that the Windows Media Player does not like being disposed of while it’s playing some media, and our application is more than happy to dispose of it.

The simplest solution is to stop the media playing as soon as the form begins to close. Add this code to your forms OnCloseQuery event handler…

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  WindowsMediaPlayer1.controls.stop;
end;

That should take care of the problem by ensuring the media is not playing as the application closes.

Source Code

A working sample source code can be checked out from my public repository at svn://public.chapmanworld.com/public/ModernizingDelphiApps/VCL/TaskbarMediaPlayer

Conclusion

The Windows Media Player control has a huge amount of functionality packed into it, including streaming, playlist support, and a huge array of supported media formats (extensible through the installation of codecs).  You now have the ability to add all of this functionality into your Delphi applications!

Thanks for Reading!