MCI Player v C++– další rozšíření

V minulém článku jsme si vytvořili ten nejjednodušší přehrávač multimediálních souborů. V tomto pokračování si ho již trochu vylepšíme s tím, že především se naučíme, jak zachytávat informace o „změně stavu“ přehrávání a také o aktuální hodnotě některých parametrů, jako je rychlost přehrávání, zoom apod.

Jak být informováni o stavu přehrávání ?

Pokud vytvoříme MCI okno tak, že jeho rodičem bude některé okno naší aplikace, máme možnost jednoduchým způsobem dostávat zprávy o „změně stavu“ přehrávání. Tím mám na mysli například přerušení přehrávání, dosažení konce klipu, opětné spuštění atd. Řekněme si více o dvou důležitých zprávách, které MCI okno přehrávače posílá svému rodičovskému oknu. První z nich je zpráva informující o změně „pozice“ v klipu:

MCIWNDM_NOTIFYPOS
wParam = (WPARAM) (HWND) hwnd;
lParam = (LPARAM) (LONG) pos;

Tato zpráva je posílána rodičovskému oknu přehrávače při změně pozice v klipu. Podmínkou je, aby MCI okno mělo ve svém stylu obsažen příznak MCIWNDM_NOTIFYPOS. Ten můžeme specifikovat samostatně, nebo jako „součást“ příznaku MCIWNDF_NOTIFYALL, který aktivuje všechny „notifikační“ vlastnosti okna přehrávače. Dále je třeba vědět, že tato pozice může být v zásadě v milisekundách nebo v obrázcích (frames) – v případě videoklipu. Určit měrnou jednotku můžeme pomocí zprávy

MCIWNDM_SETTIMEFORMAT
wParam = 0;
lParam = (LPARAM) (LPSTR) lp;

kde pokud jako parametr uvedeme řetězec „ms“, bude pozice měřena v milisekundách, pokud uvedeme „frames“, bude pozice v obrázcích (frames) videoklipu.

Druhou informativní zprávou, o které si zde řekneme, je zpráva

MCIWNDM_NOTIFYMODE
wParam = (WPARAM) (HWND) hwnd;
lParam = (LPARAM) (LONG) mode;

která nás informuje o „změně stavu“ přehrávání klipu, popřípadě o chybě zařízení. Parametr mode může nabývat některé z těchto hodnot

MCI_MODE_NOT_READY Zařízení není připraveno
MCI_MODE_OPEN Zařízení je otevřeno
MCI_MODE_PAUSE Bylo přerušeno přehrávání
MCI_MODE_PLAY Bylo spuštěno přehrávání
MCI_MODE_RECORD Byl spuštěn záznam
MCI_MODE_SEEK Probíhá vyhledávání (např. pozice v klipu)
MCI_MODE_STOP Zastaveno přehrávání
Již v minulém článku jsme si vytvořili členské funkce našeho přehrávače, kterými jsme mohli nastavit zoom, hlasitost a rychlost přehrávání. Nyní si ukážeme, jak získat aktuální hodnoty těchto parametrů přímo od MCI okna přehrávače. K tomu nám slouží následující zprávy posílané MCI oknu:

MCIWNDM_GETSPEED
wParam = 0;
lParam = 0;

Tato zpráva nám vrátí rychlost přehrávání, přičemž normální (100%) rychlost odpovídá hodnotě 1000.

MCIWNDM_GETZOOM
wParam = 0;
lParam = 0;

Tato zpráva vrátí aktuální zoom videoklipu, přičemž normální velikost odpovídá hodnotě 100.

MCIWNDM_GETVOLUME
wParam = 0;
lParam = 0;

Tato zpráva vrací aktuální hodnotu hlasitosti, normální hlasitost odpovídá hodnotě 1000.

Získání informací o klipu

Řekněme si dále, jak získat některé informace o klipu. Například pro získání rozměrů videoklipu (v pixelech) můžeme použít zprávu.

MCIWNDM_GET_DEST
wParam = 0;
lParam = (LPARAM) (LPRECT) prc;

kde prc je RECT určující obdélník, ve kterém je klip přehráván. Tyto rozměry jsou rozměry v nichž je klip aktuálně přehráván, tedy mění se změnou zoomu. Není to tedy výchozí velikost videoklipu. Tu samozřejmě zjistíme, když tuto hodnotu získáme při nastaveném 100% zoomu.

Pro získání délky klipu použijeme zprávu

MCIWNDM_GETLENGTH
wParam = 0;
lParam = 0;

Podobně jako při získávání informace o pozici zde platí, že výsledná hodnota může být uvedena v milisekundách nebo obrázcích (frames), v závislosti na nastaveném časovém formátu, jak jsem si řekli o zprávě MCIWNDM_SETTIMEFORMAT.

Nakonec si uvedeme zprávu pro získání informace o použitém zařízení

MCIWNDM_GETDEVICE
wParam = (WPARAM) (UINT) len;
lParam = (LPARAM) (LPVOID) lp;

parametr lp je buffer (o délce len), který nám systém naplní názvem použitého zařízení. Může to být například „MPEGVideo“ a podobně. Přehrávač automaticky vybere příslušné zařízení podle zjištěného typu souboru. Znovu opakuji, že na různých počítačích můžeme dostat jiné výsledky podle aktuálně nainstalovaných kodeků. Některé soubory tedy nebude možno přehrát, zatímco na jiném počítači to možné bude. Dále zdůrazním, že tímto přehrávačem lze samozřejmě přehrávat i běžné zvukové CD. Jak jistě víte, jednotlivé skladby jsou z hlediska systému soubory s koncovkou .cda označené jako „Stopa zvukového disku CD“, pokud ovšem máte jako výchozí přehrávač Windows Media Player. Jiné přehrávače budou samozřejmě tento typ označovat jinak.

Jak na to prakticky?

Ukázková aplikace je MFC aplikace vytvořená jako „single dokument“, kde jsem odebral třídy dokumentu a pohledu. MCI okno budeme otvírat jako dceřiné okno hlavního okna (CMainFrame). Dále jsem přidal nemodální dialog (CInfoDialog), který bude ukotven v pravé části okna a bude zobrazovat uvedené informace o klipu a jeho přehrávání. Tento dialog vytvoříme při vytvoření hlavního okna, tedy ve funkci OnCreate:

// ….. funkce OnCreate
m_KlipInfo = new CInfoDialog();
m_KlipInfo->Create(IDD_INFO, this);
m_KlipInfo->ShowWindow(SW_SHOW);
return 0;

Jeho ukotvení při změně velikosti okna zajistíme v handlenu zprávy WM_SIZE:

void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
RECT rect, rect2;
m_wndToolBar.GetWindowRect(&rect);
m_wndStatusBar.GetWindowRect(&rect2);
m_KlipInfo->SetWindowPos(NULL, cx - 150, rect.bottom-rect.top,
150, cy - (rect.bottom - rect.top) - (rect2.bottom-rect2.top), SWP_NOZORDER);
}

Zde poznámka k optimalizaci: z hlediska rychlosti by bylo efektivnější získat výšku tool-baru a status-baru (které se nemění) při startu, někam si je uložit a nepočítat při každém „resizování“.

Při otevření souboru zjistíme a vypíšeme do uvedeného dialogu informace o klipu:

void CMainFrame::OnOtevriSoubor()
{
  CFileDialog openDialog(TRUE);
  if ( openDialog.DoModal() != IDOK )
    return;
  m_Player.m_ShowAll = TRUE;
  m_Player.Open(openDialog.GetPathName().GetBuffer(_MAX_PATH), m_hWnd);
  if ( m_PosInFrames )
  {
    m_Player.SendMessage(MCIWNDM_SETTIMEFORMAT, 0, (LPARAM)"frames");
    m_KlipInfo->SetDlgItemText(IDC_DELKA_LABEL, "Délka (frames)");
  }
  else
  {
    m_Player.SendMessage(MCIWNDM_SETTIMEFORMAT, 0, (LPARAM)"ms");
    m_KlipInfo->SetDlgItemText(IDC_DELKA_LABEL, "Délka (milisec.)");
  }

  TCHAR chText[60];
  RECT rect;
  LONG length;
  LONG speed;
  LONG zoom;
  LONG volume;
  m_Player.SendMessage(MCIWNDM_GET_DEST, 0, (LPARAM)(LPRECT)&rect);
  length = m_Player.SendMessage(MCIWNDM_GETLENGTH, 0, 0);
  speed = m_Player.SendMessage(MCIWNDM_GETSPEED, 0, 0)/10;
  zoom = m_Player.SendMessage(MCIWNDM_GETZOOM, 0, 0);
  volume = m_Player.SendMessage(MCIWNDM_GETVOLUME, 0, 0)/10;
  sprintf(chText, "%d x %d", rect.right - rect.left, rect.bottom - rect.top);
  m_KlipInfo->SetDlgItemText(IDC_ROZMERY, chText);
  m_KlipInfo->SetDlgItemInt(IDC_DELKA, length, FALSE);
  m_KlipInfo->SetDlgItemInt(IDC_RYCHLOST, speed, FALSE);
  m_KlipInfo->SetDlgItemInt(IDC_ZOOM, zoom, FALSE);
  m_KlipInfo->SetDlgItemInt(IDC_HLASITOST, volume, FALSE);
  m_Player.SendMessage(MCIWNDM_GETDEVICE, 60, (LPARAM)chText);
  m_KlipInfo->SetDlgItemText(IDC_ZARIZENI, chText);
}

V proceduře okna (přepíšeme funkci WindowProc) pak budeme zachytávat a zpracovávat zprávy informující o „změně stavuL přehrávače:

LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR chText[40];
int pos;
switch ( message )
{
case MCIWNDM_NOTIFYPOS:
if ( wParam != (WPARAM)m_Player.GetHWND() )
break;
if ( m_PosInFrames )
{
pos = (LONG)lParam;
itoa(pos, chText, 10);
lstrcat(chText, " obrázků");
}
else
{
pos = (LONG)lParam / 1000;
itoa(pos, chText, 10);
lstrcat(chText, " sekund");
}
SetWindowText(chText);
break;
case MCIWNDM_NOTIFYMODE:
if ( wParam != (WPARAM)m_Player.GetHWND() )
break;
switch ( lParam )
{
case MCI_MODE_PAUSE:
m_KlipInfo->SetDlgItemText(IDC_STAV, "PŘERUŠENO");
break;
case MCI_MODE_PLAY:
m_KlipInfo->SetDlgItemText(IDC_STAV, "SPUŠTĚNO");
break;
case MCI_MODE_STOP:
m_KlipInfo->SetDlgItemText(IDC_STAV, "ZASTAVENO");
break;
}
break;
}
return CFrameWnd::WindowProc(message, wParam, lParam);
}

Do hlavního menu si přidáme položky pro ovládání zoomu, hlasitosti a rychlosti tím způsobem, že tyto hodnoty budeme zvětšovat nebo zmenšovat vždy o 10 % pomocí již připravených (viz předchozí článek) členských funkcí a po jejich změně pomocí výše uvedených zpráv získáme a vypíšeme příslušnou hodnotu do informačního dialogu. Alternativní volání těchto příkazů jsem umístil také na tool-bar.

void CMainFrame::OnZmensit()
{
m_Player.ZoomOut();
m_KlipInfo->SetDlgItemInt(IDC_ZOOM, m_Player.SendMessage(MCIWNDM_GETZOOM, 0, 0), FALSE);
}

void CMainFrame::OnZvetsit()
{
TCHAR chText[60];
RECT rect;
m_Player.SendMessage(MCIWNDM_GET_DEST, 0, (LPARAM)(LPRECT)&rect);
m_Player.ZoomIn();
m_KlipInfo->SetDlgItemInt(IDC_ZOOM, m_Player.SendMessage(MCIWNDM_GETZOOM, 0, 0), FALSE);
sprintf(chText, "%d x %d", rect.right - rect.left, rect.bottom - rect.top);
m_KlipInfo->SetDlgItemText(IDC_ROZMERY, chText);
}

void CMainFrame::OnZrychlit()
{
m_Player.SpeedUp();
m_KlipInfo->SetDlgItemInt(IDC_RYCHLOST,
m_Player.SendMessage(MCIWNDM_GETSPEED, 0, 0)/10, FALSE);
}

void CMainFrame::OnZpomalit()
{
m_Player.SpeedDown();
m_KlipInfo->SetDlgItemInt(IDC_RYCHLOST,
m_Player.SendMessage(MCIWNDM_GETSPEED, 0, 0)/10, FALSE);
}

void CMainFrame::OnZtisit()
{
m_Player.VolumeDown();
m_KlipInfo->SetDlgItemInt(IDC_HLASITOST,
m_Player.SendMessage(MCIWNDM_GETVOLUME, 0, 0)/10, FALSE);
}

void CMainFrame::OnHlastiteji()
{
m_Player.VolumeUp();
m_KlipInfo->SetDlgItemInt(IDC_HLASITOST,
m_Player.SendMessage(MCIWNDM_GETVOLUME, 0, 0)/10, FALSE);
}

Zde si můžete stáhnout ukázkový projekt mci_player_II.zip (46 kB)

Váš názor Další článek: UPC zdvojnásobila počet zákazníků připojených na Internet

Témata článku: , , , , , , , , , , , , , , ,