Local Subtitles For Windows Media Player

  • Download plugin release x64 (64 bit) – 484.4 KB
  • Download plugin release x86 (32 bit) – 534.iv KB
  • Download source projection x64 (64 bit) – 48.9 KB
  • Download source project x86 (32 bit) – 48.seven KB

Table of Contents

  • Introduction
    • The Problem
  • Groundwork
    • Popular Solutions using Other Players
    • Popular Solutions using WMP Directshow
    • WMP ‘Native’ Solution (Main focus of this article)
  • Developing plugin for Windows Media Player
    • Setting upward Plugin Wizard with Visual Studio
    • Choosing Plugin Blazon
  • Lawmaking Analysis
    • Core Logic
    • Basic Functions and Apply of Code
  • SubRip to SAMI Conversion
    • Introduction
    • Conversion – Core Logic
    • Handling Text Encoding Formats During File I/O
    • Where are encoding and decoding procedures?
  • Plugin Properties/Configuration Dialog Box
    • Implementation
  • How does the Plugin Support Other Languages and Unicode?
  • Features yet to implement
  • Source and Builds
    • Acquiring Source
    • 64 scrap builds
    • 32 bit builds
  • Enabling Explanation/Subtitle
  • Installing Plugin without building from Code
  • Tips and Tricks
  • Decision

Introduction

Here’s a screenshot of Windows Media Player with the plugin running:

Image 1

This article discusses implementation, logic, source code and building process of a Subtitle Plug-in for Windows Media Role player. If yous are interested in understanding the source-code y’all can go through the lawmaking related discussions. Otherwise, to install this plugin you can skip to the section, Installing Plug-in without building from Lawmaking. Updated source-code of the project is available at Google Lawmaking

The Problem

While virtually of the players support common formats (srt, sub, ssa/ass) of captions/subtitles, nevertheless now Windows Media Player (WMP) does not support them or feature has not been implemented to render captions directory from them. For this reason, we don’t notice a mode to enable subtitles for common formats in WMP. All the same, it supports SAMI captions. In this article, we are going develop a plugin to support other types of captions such as subrip (srt).

Allow’s briefly talk nearly solutions that are available.

Background

Popular Solutions using Other Players

One of the near popular alternative is DirectVobSub. Forked from VobSub and previously known as VSFilter it supports 8 popular formats of subtitles/captions. Players such every bit VLC, Media Player Archetype and KMPlayer uses it to render subtitles and uses directshow to display them in Windows.

One interesting player is DivX Histrion which uses Microsoft Media Foundation to render Videos and Captions and, therefore, they don’t use DirectVobSub.

Popular Solutions using WMP Directshow

With updates to WMP information technology still includes directshow along with Media Foundation. Therefore, it is possible to enable subtitles using directshow filters. Following directshow filter based projects can enable subtitle on WMP:

  • Win8Codec by Shark007 (for Windows 7 and eight)
  • K-Calorie-free Codec (Works well on WMP nine and earlier)
  • Combined Community Codec Pack
  • DirectVobSub

WMP ‘Native’ Solution

Contempo editions of Windows Media Player uses Microsoft Media Foundation. Media Foundation has some advantages and performance improvements. Using a directshow filter to return captions with Media Foundation hurts that advancement. Performance issue is noticeable sometimes. It is why, our target is to enable captions in WMP for some unsupported subtitle formats without altering media foundation pipeline. Hither is a projection that does not employ direct-show: http://sourceforge.net/projects/wmpsub/files/ and meets mentioned goals. However, this project is not open-source and does non requite us interesting development scenario.

Our target is to build a plugin for Windows Media Player that will:

  • Create supported SAMI caption from unsupported format
  • Enable displaying this caption while playing the video
  • Provide settings to configure this plugin

Because of the plugin nosotros’ll exist able to load captions with Video when opened with Media Player.

Developing plugin for Windows Media Player

Setting up Plugin Wizard with Visual Studio

Windows Media Player SDK on msdn provides documentation on development of Windows Media Thespian Plug-ins. Therefore, for detailed documentation on the subject field please navigate to Windows Media Actor Plug-ins on msdn.

First step in developing WMP Plugin is to install plugin magician. Please follow instructions at Getting Started with the Plug-in Wizard. The webpage suggests that you install “Windows SDK, which includes the Windows Media Player SDK”. Regarding this, not all Windows SDK include Windows Media Player SDK. Specifically, Windows SDK 7.0 provides this. I accept not been able find one with Windows SDK 8.

According to the documentation page, you lot have to modify wmpwiz.vsz to fix Sorcerer Version and absolute path for Magician location to brand the Wizard for your Visual Studio. Wizard version has to exist set up according to your Visual Studio Version. For example, 11.0 is for Visual Studio 2012 and, 12.0 is for Visual Studio 2013. Absolute path tin be fix to the location where your wizard setup files exist and can exist dissimilar based on where have extracted the SDK. If yous have installed the SDK, default location works well. Hither’south a sample wmpwiz.vsz I am using for Visual Studio 2013.

VSWIZARD
        vii.0
        Magician=VsWizard.VsWizardEngine.12.0
        Param="
        WIZARD_NAME = Windows Media Thespian Plug-in Sorcerer"
        Param="
        ABSOLUTE_PATH = F:\WinSDK seven.0\multimedia\WMP\Wizards\wmpwiz"
        Param="
        FALLBACK_LCID = 1033"
      

I copied 3 files to “C:\Programme Files (x86)\Microsoft Visual Studio 12.0\VC\vcprojects”. Afterwards, we are able to create a new plugin project following Using the Plug-in Wizard with Visual Studio. Here’s a screenshot that displays Windows Media Histrion Plugin in New Projection dialog box.

Image 2

Choosing Plugin Type

At that place are 4 types of WMP Plugin:

  • Visualization Plugin
  • UI Plugin
  • DSP Plugin
  • Rendering Plugin (Deprecated)

UI Plugins are several types

  • Brandish Expanse Plug-ins (deprecated)
  • Settings Area Plug-ins
  • Metadata Expanse Plug-ins (deprecated)
  • Split Window Plug-ins
  • Background Plug-ins

We are going to work on Groundwork Plug-in equally our plugin does some operations in the background to prepare the caption when a media file is opened. For this reason, when Media Thespian Plugin Wizard dialog appears we select UI Plugin as displayed on the screen-shot below,

Image 3

Afterwards, Visual Studio creates required files and templates for the project that are ready to alter.

Code Analysis

Cadre Logic

Our Plugin application precisely does following things:

  • When a file is opened on Windows Media Player it is an result named wmposMediaOpen. When this event occurs nosotros perform following:
  • Check the extension of opened media file if it tin can support captions. For example, audio files and some video formats don’t support captions.
  • If caption is supported then we check if sami (.smi) caption file already exists. SAMI caption support is built-in. Hence if such a caption for the media file already exists information technology is automatically loaded by WMP.
  • When such a supported caption file is not found, in this stage, we wait for unsupported explanation file such as subrip (.srt). We convert such file when we observe one. Currently, this application simply supports converting explanation files with .srt extension. Withal, it is easy to update this application to support conversion from other formats as well.

Too that, I have also tried to optimize code and follow standard procedure to ignore any kind of retentivity leak equally I am using C++.

Basic Functions and Use of Code

Post-obit functions implement the operations mentioned in ‘core logic’ section:

UpdateMediaFilePath
– gets the path of opened media file.

FileExtNotSupportedByPlugin
– for file extensions not supported this function returns true. Following file extensions are listed not to be supported primarily considering they are audio files.

  1. .m4a
  2. .mp3
  3. .wma
  4. .wav
  5. .mp2
  6. .ivf
  7. .mpa
  8. .m3u
  9. .wax
  10. .cda
  11. .mid
  12. .midi
  13. .rmi
  14. .au
  15. .aac

CaptionAlreadyAvailable
– this function returns true when SAMI caption file for the media file is found.

EnableCaptionFromSubtitle
– finds existing subtitle in unsupported format, converts it and loads it. –

We add our lawmaking inside events cpp file (WMPNativeSubtitleevents.cpp)

        case
        wmposMediaOpen: {   UpdateMediaFilePath();   
        if
        (FileExtNotSupportedByPlugin(m_sFilePath))
        break;   
        if
        (CaptionAlreadyAvailable())
        break;
        if
        (EnableCaptionFromSubtitle() == FALSE) {   
        break;  }
        break; }

The functions that have been called from this source file are divers in WMPNativeSubtitle.cpp. Let’southward mention what we add in that source file and header file. Post-obit declarations are added to header file “WMPNativeSubtitle.h” inside annunciation of class CWMPNativeSubtitle:

        class
        ATL_NO_VTABLE CWMPNativeSubtitle :
        public
        CComObjectRootEx<CComSingleThreadModel>,
        public
        CComCoClass<CWMPNativeSubtitle, &CLSID_WMPNativeSubtitle>,
        public
        IWMPEvents,
        public
        IWMPPluginUI { public:     CWMPNativeSubtitle();     ~CWMPNativeSubtitle();  DECLARE_REGISTRY_RESOURCEID(IDR_WMPNativeSubtitle)  DECLARE_PROTECT_FINAL_CONSTRUCT()  BEGIN_COM_MAP(CWMPNativeSubtitle)     COM_INTERFACE_ENTRY(IWMPEvents)     COM_INTERFACE_ENTRY(IWMPPluginUI) END_COM_MAP()      private:  LPTSTR  m_sFilePath;   BOOL EnableCaptionFromSubtitle();  BOOL CaptionAlreadyAvailable();  LPTSTR GetSubtitleFilePath();
        void
        UpdateMediaFilePath(); };

At the cease of aforementioned header file we add following declarations:

BOOL FAILMSG(HRESULT hr); BOOL FileExists(TCHAR * file); BOOL FileExtNotSupportedByPlugin(LPCTSTR sFile); BOOL StringEndsWith(LPCTSTR str, LPCTSTR suffix);

Nosotros include header file for conversion from srt to SAMI in cpp file (WMPNativeSubtitle.cpp).

        #include
        
          "
          SAMIConversion.h"
        
      

Afterwards, we add role definitions into the same cpp file:

        void
        CWMPNativeSubtitle::UpdateMediaFilePath() {  
        if
        (m_sFilePath)
        delete
        m_sFilePath;    BSTR sFileName;  HRESULT hr = m_spCore->get_URL(&sFileName);
        if
        (FAILMSG(hr))
        return;  
        const
        int
        sfnSize = SysStringLen(sFileName)+1;   m_sFilePath =
        new
        TCHAR[sfnSize];  _tcscpy_s(m_sFilePath, sfnSize, sFileName);  ::SysFreeString(sFileName); }

The function allocates necessary infinite and acquires media file path using get_URL method of COM interface IWMPCore.

BOOL FileExtNotSupportedByPlugin(LPCTSTR sFile) {
        if
        (StringEndsWith(sFile, TEXT("
        .m4a")) || StringEndsWith(sFile, TEXT("
        .mp3")) || StringEndsWith(sFile, TEXT("
        .wma")) || StringEndsWith(sFile, TEXT("
        .wav")) || \   StringEndsWith(sFile, TEXT("
        .mp2")) || StringEndsWith(sFile, TEXT("
        .ivf")) || StringEndsWith(sFile, TEXT("
        .mpa")) || StringEndsWith(sFile, TEXT("
        .m3u")) || \   StringEndsWith(sFile, TEXT("
        .wax")) || StringEndsWith(sFile, TEXT("
        .cda")) || StringEndsWith(sFile, TEXT("
        .mid")) || StringEndsWith(sFile, TEXT("
        .midi")) || \   StringEndsWith(sFile, TEXT("
        .rmi")) || StringEndsWith(sFile, TEXT("
        .au")) || StringEndsWith(sFile, TEXT("
        .aac")))
        render
        TRUE;
        return
        FALSE; }
      

Office FileExtNotSupportedByPlugin returns false encountering whatever of the mentioned extension.

BOOL CWMPNativeSubtitle::CaptionAlreadyAvailable() {     CComPtr<IWMPClosedCaption>
        spWMPClosedCaption;   HRESULT hr = E_FAIL;   hr = m_spCore->get_closedCaption(&spWMPClosedCaption);
        if
        (FAILMSG(60 minutes))
        return
        true;
        if
        (spWMPClosedCaption)     {   BSTR smiFileName;   60 minutes = spWMPClosedCaption->get_SAMIFileName(&smiFileName);
        if
        (FAILMSG(hr))
        return
        True;
        if
        (smiFileName != Nada) {    BOOL isNotEmpty = (BOOL) wcscmp(smiFileName, L"
        ");    ::SysFreeString(smiFileName);
        return
        isNotEmpty;   }     }
        return
        Simulated; }

This function uses get_closedCaption method of COM interface IWMPCore. and get_SAMIFileName method of COM interface IWMPClosedCaption to check whether a SAMI explanation has been loaded.

BOOL CWMPNativeSubtitle::EnableCaptionFromSubtitle() {    LPTSTR subInputName = GetSubtitleFilePath();
        if
        (subInputName == Aught)
        return
        FALSE;    SubToSAMIConverter subToSAMIConverter(subInputName);
        if
        (subToSAMIConverter.convert_to_sami()) {   BSTR mediaFileName;   HRESULT hr = m_spCore->get_URL(&mediaFileName);
        if
        (FAILMSG(hr))
        return
        Imitation;   m_spCore->close();   m_spCore->put_URL(mediaFileName);   ::SysFreeString(mediaFileName);
        return
        TRUE;  }
        render
        FALSE; }
      

Afterwards, we add part definitions in cpp file (WMPNativeSubtitle.cpp). We go srt subtitle file path in a pointer variable using part GetSubtitleFilePath.

Function GetSubtitleFilePath acquires the media file path and replaces its extension with srt. It as well checks whether this last path exists. If file does not exist the role returns NULL.

After getting subtitle file path we pass information technology to a member part of course SubToSAMIConverter. Nosotros discuss about the conversion procedure on next section. This part returns truthful if conversion process is successful. On success we close the media file and reopen to load caption using put_URL method of IWMPCore interace.

SubRip to SAMI Conversion

Introduction

Function convert_to_sami which is a public member of class SubToSAMIConverter does required conversion from subrip to SAMI. To sympathise this conversion procedure we need cognition on post-obit topics:

  • SubRip – it is the input format for convert_to_sami
  • SAMI – it is the output format for convert_to_sami

You tin can visit Wikipedia’due south entry on SubRip for detail information. Basically, a subrip text file is a collection of structured caption text such as following:

  • A numeric number that increments by one for each caption
  • Time Postage
  • Text

Additionally, SubRip supports some basic html formatting.

To know about SAMI (Microsoft Synchronized Accessible Media Interchange) format and its specification please go through Understanding SAMI 1.0 on msdn In brief, a SAMI file looks like a html document (though not really html) which contains caption texts inside body tag

  • A sync tag mentioning starting time in milliseconds
  • Caption text under a p tag mentioning class and id to apply required formatting

Before body tag formatting style classes and ids are defined for p tag. SAMI captioning has limited html support and it allows captions in multiple languages.

Conversion – Core Logic

When an object of the class SubToSAMIConverter is created passing the input subtitle file (.srt) path using constructor information technology creates following files:

  • Output SAMI Document(smi text file )
  • Log file (if specified), it helps debugging

Subsequently, convert_to_sami function does follow:

Writes initial way description and header to the smi file which looks like this:

        <SAMI>
        <head>
        <STYLE Blazon="
        text/css"
        >
        <!--    P {    font-size:1.2em;    font-family unit: Arial, Sans-Serif;    font-weight: normal;    color: #FFFFFF;    background-color: transparent;    text-marshal: eye; }    .SACAPTION { proper name: English; lang: EN-U.s.a.; }  -->
        </Mode>
        </head>
        <body>
      

Name of our paragraph tag form for english caption is ‘SACAPTION’.And then it takes each line from srt file every bit input and recognizes line blazon. Line input is taken using post-obit function,

BOOL SubToSAMIConverter::get_sub_line(LPTSTR *lineStr,
        int
        *length);
      

and line blazon is determined by following office,

LINETYPE get_line_type(LPTSTR line, SubToSAMIConverter* pSamiConverter);
      

Post-obit types of lines are considered in an srt file:

  • New line
    – when a newline is encountered starting time we verify whether we got this newline after caption in that case w he n east
  • Number Counter
    – is named seqeuence in the program; nil is written to output smi file when it is encountered. However, in future, we tin can do a checking whether number counter is correct and may write a warning to the log file when such event occurs.
  • TimeStamp
    – 2 timestamps are found in these lines in srt file because standard is followed. Hence, we save starting and ending time and perform necessary logging.
  • Caption Text
    – when texts are institute I do some checking such as whether timestamps and string pointer are valid. If everything is okay, program does following for each of the ii timestamps.

    • for kickoff postage stamp, text is printed with sync time, see following example,
                      <SYNC Commencement="
                      8705"
                      >
                      <p
                      class="
                      SACAPTION"
                      >
                      I'
                      thousand so alone, broken angel </p> </SYNC>
                      
                    
    • for ending fourth dimension postage, a white infinite is written to file with sync fourth dimension. Following example illustrates this:
                      <SYNC Kickoff="
                      12178"
                      >
                      <p
                      course="
                      SACAPTION"
                      >
                      &nbsp;
                      </p>
                      </SYNC>
                    
  • The reason behind this is that, Windows Media Player keeps displaying the same explanation till next sync time is found. This tin can exist irritating. Imagine: a short judgement from the speaker in the video, then other events can occur and next sentence might exist uttered in a long time.
  • Default – whatever garbage: is considered as an error and should return failure. This is strict. Usually, this case is not satisfied.

Handling Text Encoding During File I/O

While reading from subtitle text files it should be considered that input text file can be encoded in following formats:

  • ANSI Text File
  • UTF-viii Text with BOM
  • UTF-8 Text without BOM
  • UTF-xvi Text File (BOM is default)
  • UTF-32 Text File (BOM is default)

Where are encoding stuffs happening?

There are ii functions where encoding is being taken cared of:

  • part

    read_data_into_buffer

    which is used/called by

    get_sub_line

    – reads BYTEs from file and converts them to Unicode buffers

  • writeSmiText

    and

    writeLog

    – writes texts past encoding them into utf-8.

get_sub_line function is giving us a string pointer to the line read from file and length of the line in an integer pointer variable using read_data_into_buffer read_data_into_buffer reads 1024 bytes from specified file using win32 ReadFile function (file handles for ReadFile and WriteFile were created in constructor of the grade). Due west east

All text encoding related functions are defined in encoding.cpp and declared in encoding.h

        enum
        TEXT_ENCODE_FORMAT { ANSI_TEXT, UTF8_TEXT_WITHOUT_BOM, UTF8_TEXT_WITH_BOM, UTF16_TEXT, UTF32_TEXT, UNKNOWN_TEXT_TYPE };  LPTSTR ConvertUTF8ToUTF16( __in LPCSTR pszTextUTF8 ); LPTSTR ConvertANSIToUTF16( __in LPCSTR pszTextANSI ); LPSTR ConvertUTF16ToUTF8( __in LPCWSTR pszTextUTF16 ); BOOL is_utf8_encoded(__in
        const
        unsigned
        char* inStr); TEXT_ENCODE_FORMAT get_text_file_encoding(__in
        const
        unsigned
        char* inStr);
      

Primarily function get_text_file_encoding is giving the states blazon of encoding used by the input text file. Here’s how code of this part looks like:

TEXT_ENCODE_FORMAT get_text_file_encoding(__in
        const
        unsigned
        char* inStr) {    BYTE firstByte = inStr[0];  BYTE secondByte = inStr[1];  BYTE thirdByte = inStr[two];     
        if
        ((firstByte ==
        0x00
        && secondByte ==
        0x00
        && thirdByte ==
        0xFE
        && inStr[3] ==
        0xFF) || (firstByte ==
        0xFF
        && secondByte ==
        0xFE
        && thirdByte ==
        0x00
        && inStr[iii] ==
        0x00))
        render
        UTF32_TEXT;   
        if
        ((firstByte ==
        0xFE
        && secondByte ==
        0xFF) || (firstByte ==
        0xFF
        && secondByte ==
        0xFE))
        render
        UTF16_TEXT;   
        if
        ((firstByte ==
        0xEF
        && secondByte ==
        0xBB
        && thirdByte ==
        0xBF) && is_utf8_encoded(&inStr[3]))
        return
        UTF8_TEXT_WITH_BOM;
        if
        (is_ANSI_encoded(inStr) == FALSE)
        return
        UTF8_TEXT_WITHOUT_BOM;
        return
        ANSI_TEXT; }
      

Input to this function, inStr is commonly starting time 1024 bytes of data from the file.

Plugin Backdrop/Configuration Dialog Box

Image 4

There are several issues to deal with while including a plugin configuration/property dialog box

  • Keeping upwardly to date state in the plugin class
  • Persistently storing the settings applied by user
  • Properly updating the dialog for display with upward to date settings

Our plugin property dialog is pretty sample and to demonstrate all the issues to deal successfully.

How is information technology implemented?

We maintain a single property. It is used to know whether logging should be enabled or not. At first we declare a variable as individual member of class CWMPNativeSubtitle inside WMPNativeSubtitle.h

BOOL m_bLogSetting;
      

This variable is used to keep upward to date information nearly log setting. By default it is disabled and plugin will not create a log file along side creating an SMI file. Have a look at constructor,

CWMPNativeSubtitle::CWMPNativeSubtitle():   m_sFilePath(Nix),   m_bLogSetting(Faux) { ... }
      

For example, user has enabled logging using Properties Dialog Box of the plugin. In that example, it is read from Windows Registry in same constructor,

CRegKey primal; LONG    lResult;  lResult = key.Open(HKEY_CURRENT_USER, kwszPrefsRegKey, KEY_READ);
        if
        (ERROR_SUCCESS == lResult) {  DWORD   dwValue =
        0;  DWORD dwType =
        0;  ULONG uLength =
        sizeof(dwValue);  lResult = key.QueryValue(kwszPrefsLogging, &dwType, &dwValue, &uLength);
        if
        (ERROR_SUCCESS == lResult)  {   m_bLogSetting = (BOOL) (dwValue &
        0x0001);  } }
      

As you can encounter for the first time plugin is enabled it volition not be able read it from registry as relevant registry keys have non been created yet. In that case, Primal Open procedure will neglect and variable m_bLogSetting’south disabled state volition not exist inverse. Registry Key Path and Name is declared in header file (WMPNativeSubtitle.h)

        const
        WCHAR kwszPrefsRegKey[] = L"
        Software\\Microsoft\\MediaPlayer\\UIPlugins\\{52738E25-987F-4CA8-A674-5154267BF422}\\WmpNativeSubtitle";
        const
        WCHAR kwszPrefsLogging[] = L"
        LogSettings";
      

This information needs to be propagated to the dialog grade so that when user clicks they tin can see it in updated state. It is why OnInitDialog part of the dialog grade retrieves it and updates check button,

        if
        (m_pPlugin) {  m_pPlugin->get_log_status(&bLogStatus);
        if
        (bLogStatus)   SendDlgItemMessage(IDC_CHECK_LOG, BM_SETCHECK, BST_CHECKED, (int) bLogStatus);
        else
        SendDlgItemMessage(IDC_CHECK_LOG, BM_SETCHECK, BST_UNCHECKED, (int) bLogStatus); }

In that location are two method implemented inside course CWMPNativeSubtitle to retrieve and update log status from other classes,

STDMETHODIMP CWMPNativeSubtitle::get_log_status(BOOL *pVal) {
        if
        (NULL == pVal)  {
        return
        E_POINTER;  }  *pVal = m_bLogSetting;
        return
        S_OK; }  STDMETHODIMP CWMPNativeSubtitle::set_log_status(BOOL newVal) {  m_bLogSetting = newVal;
        return
        S_OK; }
      

When user enables/disables logging from dialog box it is updated both in registry and CWMPNativeSubtitle grade member,

LRESULT OnOK(WORD wNotifyCode, Give-and-take wID, HWND hwndCtl, BOOL& fHandled) {
        int
        logStatus =
        0;  UINT32 country = IsDlgButtonChecked(IDC_CHECK_LOG);
        if
        (state == BST_CHECKED)  {   logStatus =
        1;  }
        else
        {   logStatus =
        0;  }   CRegKey key;  LONG    lResult;   lResult = cardinal.Create(HKEY_CURRENT_USER, kwszPrefsRegKey);
        if
        (ERROR_SUCCESS == lResult)  {   DWORD dwValue = (DWORD) logStatus;   lResult = cardinal.SetValue(kwszPrefsLogging, REG_DWORD, &dwValue,
        sizeof(dwValue));  }   
        if
        (m_pPlugin)  {   m_pPlugin->set_log_status(logStatus);  }   EndDialog( IDOK );
        return
        0; }
      

Nonetheless, there is scope of improvement, such as, to:

  • Ensure registry write is done only when value has inverse.
  • Eliminate unnecessary registry read when grade member is already updated.

This can be of import when you have a number of property members in the class.

How does the Plugin Support Other Languages and Unicode?

Our output SAMI files are encoded in utf-8. Hence, information technology can exist speculated that writing Unicode characters for languages other than English should work and that Windows Media Thespian should by default be able to display them properly. Even so, this is simply a speculation.

Please accept a look at following caption record in an smi file,

        <SYNC Start="
        272000"
        >
        <p
        class="
        SACAPTION"
        >
        Long,
        long
        live the walls we crashed through<br>
        زنده.زنده باد دیوارهایی که در هم شکستیم
        </p>
      

When we load it with the relevant media file the rendering of explanation looks like the one in screenshot,

Image 5

Reason can be one of the two. One is that Windows Media Histrion does not really support utf-eight. It only parses ANSI. In that case, when you lot split a 2 byte Unicode character into ii you get ii ANSI characters. Media Player is displaying those separated ANSI characters. Other reason can exist that, probably we have missed something in documentation, only putting Unicode chars is non probably the selection. Probably, an expert in the field can shed light on information technology.

SAMI certificate has express html back up. If Unicode characters are encoded in html format Windows Media Actor displays them correctly. Have a wait at post-obit caption tape in the smi file,

        <SYNC Offset="
        272000"
        >
        <p
        class="
        SACAPTION"
        >
        Long,
        long
        live the walls we crashed through<br>
        &#1586;&#1606;&#1583;&#1607;.&#1586;&#1606;&#1583;&#1607; &#1576;&#1575;&#1583; &#1583;&#1740;&#1608;&#1575;&#1585;&#1607;&#1575;&#1740;&#1740; &#1705;&#1607; &#1583;&#1585; &#1607;&#1605; &#1588;&#1705;&#1587;&#1578;&#1740;&#1605;
        </p>
        </SYNC>
      

Hither’s the screenshot when this smi is loaded with relevant media file,

Image 6

1586, 1606, 1586 etc are the decimal Unicode value for the respective Arabic alphabetic character. Let’due south have a peek into the implementation in source file (SAMIConversion.cpp),

        void
        SubToSAMIConverter::EmbedUnicodeSymbols(LPWSTR pSubStr, LPWSTR pLine) {
        size_t
        pSubLen = wcslen(pSubStr);
        for
        (int
        i =
        0; pLine[i] != _T('
        \0'); i++) {
        if
        ((unsigned
        int)pLine[i]
        <=
        0xFF) {    pSubStr[pSubLen++] = pLine[i];   }
        else
        {    pSubStr[pSubLen++] = L'
        &';    pSubStr[pSubLen++] = L'
        #';     WCHAR numbuf[12];    _itow_s((int)pLine[i], numbuf,
        x,
        ten);
        for
        (int
        j =
        0; numbuf[j] != L'
        \0'; j++)     pSubStr[pSubLen++] = numbuf[j];    pSubStr[pSubLen++] = L'
        ;';   }  }  pSubStr[pSubLen] = 50'
        \0'; }

To optimize the plugin, we merely phone call EmbedUnicodeSymbols function just when Unicode character has been encountered before. First string pointer in the parameters of the function is the one that nosotros write to smi file later and second parameter string pointer is the ane nosotros found originally in subrip file and converted to Unicode string. And so what information technology basically does, is that, the part,

  • Iterates till null terminating graphic symbol of pLine is encountered
  • For each of the characters in pLine string information technology checks whether information technology is in ansi char range (ASCII code 0 to 255)
  • If the character is in range it is appended to the get-go string.
  • Otherwise, information technology appends ‘&#’ Then appends decimal number institute past converting the Unicode value of the grapheme and finally appends a ‘;’

Features yet to implement

Here is a tentative list of features to implement,

  • Currently smi file is created in the same location of media file. If the directory is not writeable Plugin won’ exist able display caption. Solution is to change smi file location to a temporary directory which volition always exist writeable. This feature has been implemented and has been discussed on next part of the commodity.
  • Add option in properties dialog box to change font, colour and other style of subtitle/explanation (currently we are doing this by modifying registry manually)
  • Add choice in properties dialog box to alter explanation height (currently we take to modify registry manually to attain this)
  • Create Installer and release both 64 bit and 32 bit

Source and Builds

Acquiring Source

There are 2 ways to go the source code of the project.

  • Using the download link from the top of the article page – after downloading extract the zip archive
  • Using github:
    Project is located at https://github.com/atiq-cs/wmp-native-subtitle-plugin. For updated source code y’all can checkout source post-obit instructions at: https://github.com/atiq-cs/wmp-native-subtitle-plugin

64 bit builds

If you wish to use 64 flake plugin please set 64 bit Windows Media Player as default. Y’all tin can find instructions on Microsoft Answers page on how to gear up 64 bit Windows Media Histrion every bit default. If you have downloaded source using fastened nil please use the zip annal mentioning x64. Open the solution file with Visual Studio. Subsequently building the projection we get an output dll file. msdn documentation suggests running plugin project using Visual Studio with administrator privilege. UI Plugin Projection generates a dll file which has to exist registered into the system using regsvr32 control that requires admin privilege. Yet, I built the project as regular user. Later, I applied the control manually using a command prompt with admin privilege. Note, you have to provide correct path of the dll file in the command,

regsvr32
        "
        F:\Sourcecodes\Plugin-App\WMPNativeSubtitle\x64\Release\WMPNativeSubtitle_plugin_x64.dll"
      

When information technology is successful a dialog box confirms it.

Image 7

Afterward that y’all have to ensure whether local caption is enabled in Windows Media Thespian. Please refer to section:
Enabling Caption/Subtitle
and follow all of the step to enable the plugin finally.

32 scrap builds

Instructions for 32 builds are almost same as for 64 scrap builds. Except, if you download source attached cipher you must download the one mentioning x86. Note, if you learn the source using github.com’s project page you will find that in that location are two directories containing Visual Studio Project configuration files: one name x64 and other one is x86. x86 directory contains Visual Studio solution and project files for 32 bit. Copy this files and overwrite files in x64 which requite you required files for 32 flake build.

After edifice dll from the lawmaking use regsvr32 control to register the dll. regsvr32 works for 32 bit dlls as well. Hence, registering the dll will be an easy work of utilise a control with privilege elevated.

Enabling Caption/Subtitle

By default local captions are not enabled in Windows Media Player.

Footstep i – Turn Local Captions On

To enable captions to exist shown from local source, you have to go to options,

Image 8

And so navigate to “Security” tab and tick the check box saying “Show local captions when present” as displayed in screenshot below,

Image 9

And click ok to save settings.

Pace 2 – Enable English Caption

This step to enable default English caption, lyrics, subtitle is also important. Without enabling it captions won’t be displayed.

Image 10

At this stage subtitle/explanation will exist displayed if smi file is available with same name as of video file name. Yet, to enable captions for subrip (.srt) files we accept to go along to side by side step.

Footstep 3 – Enable WmpNativeSubtitle Plugin

Our final step is to enable the plugin. To do that, we have to navigate to Plug-Ins tab from More than options. And and then select “Groundwork” from Category. So, we must enable the plugin past checking the tick box on the left of the Plugin Name.

Image 11

At this stage, With all these steps properfly followed Windows Media Histrion is now capable of displaying Captions for both .srt and .smi files.

Installing Plugin without building from Code

Delight download proper release dll zip annal (x64 for 64 bit plugin and x86 for 32 bit plugin). A 64 Windows Os (except probably Server 2012) tin can run both 32 flake and 64 chip application. If y’all want to use the 64 fleck plugin you must gear up Windows Media Player default following education from http://answers.microsoft.com/en-us/windows/forum/windows_7-windows_programs/making-windows-media-histrion-64-chip-default/bd4872b3-75e8-4d81-ae8a-df50798d5113

After downloading extract the nothing archive. There are two dll files inside the extracted directory:

  • WMPNativeSubtitle_plugin.dll or WMPNativeSubtitle_plugin_x64.dll
  • msvcr120.dll

For instance, if directory path is:

F:\Plugin

and so following command will install/register the 64 bit dll into system (requires elevated/admin command prompt):

regsvr32
        "
        F:\Plugin\WMPNativeSubtitle_plugin_x64.dll"
      

To install the 32 bit plugin, modify the file name to exclude “_x64”,

regsvr32
        "
        F:\Plugin\WMPNativeSubtitle_plugin.dll"
      

Finally, yous must follow instructions from section Enabling Caption/Subtitle to enable caption.

Tips and Tricks

How to change caption superlative

Windows Media Players explanation rendering system, you may notation, is bit different. There is a darker background around caption text though transparency is enabled. Default caption superlative seems to be large. All the same, it is easy to modify information technology. If you navigate to following registry path,

[HKEY_CURRENT_USER\Software\Microsoft\MediaPlayer\Player\Tasks\NowPlaying]
        "
        CaptionsHeight"=dword:00000064
      

There is a key named CaptionsHeight nether information technology. 0x64 is large. I use hexadecimal value 0x48, which is comfy for me.

Determination

While in that location are enough of sound/video player projects around in that location is appeal of Windows Media Histrion to some people. It’s clean and unproblematic; coming with the Os this software is nonetheless classic favorite to many. While Windows Media Role player supports many of the latest video file formats and encoding information technology provides ameliorate hardware acceleration and clarity having advantage of the support from the OS. I hope this commodity will be useful to fans of Windows Media Player.

Points of Interest

Any kind of proffer, review to improve this commodity are welcome. While developing the plugin to make an optimal solution and to implement some components from scratch yous might notice I have reinvented some of the wheels (whether this has been ameliorate or worse, experts can tell).

Side-note: I created this awarding almost 8 months ago. I am sorry that I am late to reproduce it here. Sharing is caring. There are other sides to the original app but they should be in different topic, in different article.

I should too mention that while typing this into code-projection editor I institute a few irritating bugs of the editor such as unnecessary white infinite coming automatically at finish of lines and crash of spider web-page on Internet Explorer xi while copy pasting some elements in editor (later, when I reopened the commodity editor I found almost 700 lines of aforementioned content!). Had the technical squad have looked into it could make our future experience better.

Cheers everyone.

History

October 2013 –
Plug-In developed

May 8, 2014 – article, kickoff revision

June 16, 2014 – article, 2d revision

June 21, 2014 – article, third revision

Interested in mathematics and english literature.

Source: https://www.codeproject.com/articles/766246/windows-media-player-native-subtitle-plugin-cplusp