fbpx
Writing playout app using Medialooks

What is Playout app?

In simple words, playout is a type of application that allows to play video files and output it
via different ways to receivers. The main feature of playout is that it is working all time without any breaks. There cannot be any crashes or issues that stop application. Thus, during the implementing of such an application, you have to write code very carefully. The problem is that in real-world it is really difficult to write from scratch stable app that covers every aspect of video coding, streaming, etc., and it is so because the community usually relies on the open-source libraries that are constantly under development. It seems that if you want to have your solution fast, the best option is to base on a ready-made professional library. On the market there are a lot of libraries that make writing playout app easier for you and provide you a lot of different ready to use components. One of them is Medialooks software.

What is Medialooks?

Medialooks is a powerful library that specializes in software development kits and APIs for
everything from ingest to contribution and distribution of high-quality video content. Their kits
are perfect for wiring apps in C#, C++, VB.NET, and Delphi.

What components do you need from ML to start developing playout app?

Medialooks are split into several parts that are suitable for different solutions so you can
choose only stuffs that you are interested in. The easiest and most common way to start
implementing the playout app with Medialooks is to use their component MPlatform SDK. The
MPlatform includes high-level objects so you can do sophisticated things with video streams simple by calling a single method.

First glance at COM and ML objects

When you know which component of the library you should use, now you have to get to know what objects should be used and how to employ them. Of course, firstly you have to include all the necessary headers. In our case it will be:

#include “MIDL/MPlatform.h” // for all operations on playlist
#include “MIDL/MLCharGen.h” // for displaying CG

After including Medialooks’s headers we can start creating objects that help us in manipulating streams.
The first is MPlalylist object. MPlalylist is an object that is responsible for handling your playlist. You can add to it different items (videos), change the behavior of the playlist, change the order of clips, change transitions between them, etc. To declare Medialooks’s object in C++ you need to use COM (Component Object Model) mechanism. In a quick summary, COM is a platform-independent, distributed, object-oriented system for creating binary software components that can interact. COM is the foundation technology for Microsoft’s OLE (compound documents) and ActiveX (Internet-enabled components) technologies. COM objects can be created with a variety of programming languages. Object-oriented languages, such as C++, provide programming mechanisms that simplify the implementation of COM objects. These objects can be created within a single process, in other processes, or even on a remote computer. In our case, we use MFC library so we have to use some different versions of COM – CComPtr . Here is the code snipped how to do this:

CComPtr<IMObject> m_objPlaylist;
HRESULT mPlaylistRes =
m_objPlaylist . CoCreateInstance ( __uuidof (MPlaylist));

After creating successfully MPlaylist object you can set its settings. To do that, firstly you have to find out from which interface is a property that you want to set. After that, you should create CComQIPtr from CComPtr. CComQIPtr is a special type of COM pointer that allows you to use methods from interfaces implemented by your object. Again, below is a code of how to do this in C++. In this example we set audio and video format for our playlist:

//set audio and video format
M_VID_PROPS vidProps = {};
CComQIPtr < IMFormat > qpFormats ( m_objPlaylist );
vidProps . eVideoFormat = eMVideoFormat ::eMVF_HD1080_50i;
qpFormats -> FormatVideoSet (eMFT_Convert, &vidProps);
M_AUD_PROPS audProps = { 4 , 48000 , 16 };
qpFormats -> FormatAudioSet (eMFT_Convert, &audProps);

After setting initial properties we can add some video to our playlist. In this case, again, we have to use CComQIPtr and the right interface.

// add file
CComQIPtr < IMPlaylist > qpPlaylist ( m_objPlaylist );
CComBSTR cbsFileName = L”example.mp4″ ;
CComPtr<IMItem> pItem;
HRESULT hr = qpPlaylist -> PlaylistAdd ( nullptr , cbsFileName, nullptr , nullptr , &pItem);

Clocked, follow playlist

One really important thing to remember when implementing a playout is to specify if the playlist should be clocked or follow. What does it mean? Clocked playlist is a playlist where each element has its own specified start time. In this case, the duration of the video from the file doesn’t matter. On the opposite, follow means that we don’t specify start time. We start playing one file and the following’s ones start times are computed from the duration of a currently played file.
By default in Medialooks playlist is set to follow. To set it as clocked we have to specify the start time for each file that we add to playlist:

M_DATETIME date;
date . nYear = 2020 ;
date . nMonth = 7 ;
date . nDay = 27 ;
date . nHour = 16 ;
date . nMinute = 33 ;
date . nSecond = 10 );
date . nMilliseconds = 500 ;
// pItem is item from previous example with PlaylistAdd
pItem -> ItemStartTimeSet (&date, eMStartType ::eMST_Specified);

How to transmit the video(mp://links, NDI)

Now, when your playlist is playing incorrect video and sound format, you probably want to transmit it further (for example, to encoder app that is responsible for dvb streaming). For this scenario, Medialooks offers some powerful solutions. One of them is a solution developed by NewTek – NDI. NDI enables video-compatible products to communicate, deliver, and receive broadcast-quality video in a high-quality, low-latency manner that is frame-accurate and suitable for switching in a live production environment. It is really widely used way of transporting video in playout app. One of the best features of NDI is that it also works in your private network. It means that you don’t have to have a playout and encoder on the same machine. It is enough that both machines are in the same network. So bellow is the code of how to send your video in C++ via NDI :

//NDI
CComPtr m_objRenderer_HD;
// to use NDI we have to create MRenderer object
HRESULT hrRendererHD =
m_objRenderer_HD . CoCreateInstance ( __uuidof (MRenderer));
// then we want receive frames from our playlist
m_objRenderer_HD -> ObjectStart (m_objPlaylist);
CComQIPtr < IMDevice > q_pDevice ( m_objRenderer_HD );
CComBSTR ndiName = L”NDI name” ;
// select NDI
q_pDevice -> DeviceSet ( CComBSTR ( L”renderer” ), CComBSTR ( L”NDI Renderer” ), L”” );
// ndi set custom name
q_pDevice -> DeviceSet ( CComBSTR ( L”renderer::line-out” ), ndiName, L”” );

Medialooks also offers their own protocol for video transporting – mp://link. If your playout and encoder app are on the same machine, it is better to use mp://link over NDI . If you have a machine that isn’t powerful, it saves you a lot of resources because NDI demand some additional operations and it does one more encoding to get desired resolution. In case of mp://link you don’t have to do additional stuffs because, by default, MPlaylist always streams via mp://link (is switched on by default). All you have to do is to set unique name to your playlist:

//mp://link
m_objPlaylist -> ObjectNameSet ( CComBSTR ( L”playlistName” ));

After that, your object is visible in the system under this name. You can connect to it from any app that uses mp://link. You have to only specify right url ( mp:// + name = mp://lplaylistName) and connect to it in the receiver app. That’s all!

Summary

Medialooks is really good commercial library to handle streams. It has much more options than simply making playout applications – for example, it supports many operations directly on streams like adding tags and so on. On the other hand, it is a very high-level library where you get closed black box functionality and you cannot really change much on the lower level of abstraction. Thus, we propose a very close lookup at the specification before you invest in it. But when you invest, you will get well documented (for C# much better than for C++) library and good support.

Let us know, what do you think or share with us your knowledge: