プログラムでmp3を再生し、それを防ぐこずができるもの

入門


むかしむかし、玄100幎前の10幎前、先延ばしだけが私の心を぀かみ始めたずき、私はただそれを䜿うこずができたのに私の心、私は救呜艇を建蚭し、延期された情事のownに沈たないようにする必芁があるず決めたした。 もちろん、その時点ではすでにかなりの数の異なるリマむンダヌ、アラヌム、シェダヌ、およびその他のさたざたな「スマヌト」りォッチがありたしたが、い぀ものように-メガバむトのヘルプファむルがあっおも、垞に他の誰かよりも近く、より理解しやすいです。 無駄に、圌は友人からベヌシックに関する本を借りたしたか

しかし、い぀ものように、順番にすべおに぀いお。


10-15幎前

ベヌシックの研究は、この玠晎らしいYPのさたざたなタむプを含むカヌトリッゞを䜿甚しお、Suborキヌボヌドを備えたダンディヌの時代に始たりたした。 次に、DOSのコンピュヌタヌで叀き良きブルヌスクリヌンqbを䜿甚したす。 さお、then然ずしたプログラマのように感じお、私は怪物に切り替えたしたはいボヌドに16MBの486プロセッサの堎合...VB5
すでに順序にうんざりしおいるあいたいなボタンの束でりィンドりを既に圫刻しおいるずき、私は有甚な䜕かを曞くこずにしたした。 さお、ここでそのような必芁性が珟れたした。 家の目芚たし時蚈に長い間慣れおいたので、たずえすべおが同時に鳎っおいたずしおも、静かに眠るこずができたした。
「たあ」ず思ったのは、「私のスピヌカヌ18ワットはおそらく私を育おおくれるでしょう。」
私はシンプルなものから始めたした。フォヌムにタむマヌを投げ、そこにいく぀かのテキストボックスず「Start」ボタンを持ち蟌みたした。 圌は私がレむズを開始できるようになるたでの時間、レむズする必芁がある回数、そしおフルボリュヌムでwinampで起動する必芁のあるmp3ファむルを蚭定したした。
長くおも短くおも、毎回、䞊昇する前に蚭定しなければならない分数に぀いお考えるのにうんざりしおいたす。 すべおのベルを鳎らし始める時間を蚭定するこずが決定されたした。 さらに、曜日ごずに立ち䞊がり時間を確保する必芁がありたした。 たた、画面にステッカヌを衚瀺しお、今日のスケゞュヌル、むベントのグルヌプをすぐにオフにする機胜倏䌑みの到来やセッションが終わった方法、さらには倜間にコンピュヌタヌをブロックする機胜を衚瀺したいず考えたした。 はい、圌自身はロックを解陀できたせんでした。 その他...

私は自分でmp3を再生したす


...そしお、これを行うために奇跡の目芚たし時蚈を教えるこずができるなら、なぜWinampでファむルを実行する必芁がありたすか りィナンプでは、音量を䞋げたり、削陀したりできたすが、さらに倚くのこずができ、最終的には眠るこずができたす。
MSDNが提䟛する最初の゜リュヌションであるMCIは 、私のような「クヌルな」プログラマにずっお完党にスポヌツマンらしくないずは芋なされたせんでしたが、逆に、BASIC mp3でのデコヌドはスポヌティすぎるず考えたした。 最終的に、圌はvb環境にうたく統合されたCOMオブゞェクトに萜ち着き、非垞に柔軟に再生を制埡し、再生の進行状況に関する必芁な情報を取埗するこずを可胜にしたした。 IGraphBuilderの時が来たした vbの腞内ではFilgraphManagerず呌ばれおいたした。完党に正確ではありたせんが、簡単にするためにそうしたす。

すべおのコヌドは陳腐化した
Dim mpl As New FilgraphManager, mplinfo As IMediaPosition Function OpenMP3(ByVal mp3file As String) As Boolean On Error Resume Next mpl.RenderFile mp3file If Err.Number <> 0 Then Set mplinfo = mpl Timer1.Enabled = True OpenMP3 = True Exit Function End If OpenMP3 = False End Function Sub Timer1_Timer() Label1.Caption = mplinfo.CurrentPosition End Sub 


すぐに倧孊でのすべおのセッションに合栌し、すでに終了したかのように、私は幞せになりたした。
VB5のモンスタヌアラヌム
画像


さお、C ++はどこにありたすか

しかし、すぐに、コンピュヌタヌが速すぎたか、このモンスタヌを曞いおいる限り私はそれほどクヌルなプログラマヌではなかったが、目芚たし時蚈はしばしば私を倱望させた。 圌は詊隓のために目を芚たさず、むベントの時間をスキップし、次のむベントを埅぀こずに移りたす。そしお、rog慢な人の䞭で、圌は私に目を芚たしおいるこずを瀺したすが、圌は音を出したせん。 「クヌルな」プログラマヌの堎合によくあるこずですが私は、今は自分に比べお間違いなくクヌルだず決め、C ++で曞き盎したす Straustrupによる著者の本をクレむゞヌな金額で買ったのは無駄だったのでしょうか

圓時、私はwinapiをかなり容認しおおり、時にはクラスを挿入し、Straustrupが執筆した本の目次を読みたした。 数日埌、目芚たし時蚈のスケルトンを投げお、私は圌が自分でmp3を再生する必芁があるず決めたした。メディアプレヌダヌ、winampなどはありたせん。 通垞どおり、MCIも拒吊されたした。

おそらく、以前、私は党胜ではなかったが、ただ䜕かを考えおいたず思いたした。 そしお、同じFilterGraphを䜿甚しお、簡単なクラスをすばやく䜜成し、研究を続けたす。 はい、 MSDNの䟋はそのシンプルさに満ちおいたす。

すぐにクラスを䜜り、むベントの実行を芁求し、蟛抱匷く埅っお...

「プログラムは無効な操䜜を実行したため、閉じられたす...」
なんおナンセンス コピヌアンドペヌストコヌドの数行でどうすれば間違いを犯すこずができたすか ファむルが同じではないのでしょうか オブゞェクトが初期化されなかったのでしょうか 段階的なチェックにより、RenderFileメ゜ッドの呌び出しで䟋倖が安定しおスロヌされたした。

叀い祖父のGoogleメ゜ッド

コヌドを曞く代わりに、コヌドを曞く代わりに、私はすべおをクラッシュするスタック、質問䞭のコヌドの゚ラヌなどを枛らす怜玢ク゚リを曞き始めたしたが、私が芋たものではありたせんでした。 すべおの人に有効なコヌドは私には機胜したせん。 「これらの䞍可解なgrafbildersをドロップし、MCIを手に取り、行っおください」ずいうアドバむスを読んで、圌の゚ゎを敎理し、MCIで歯を噛みながらコピヌしたした。

再びF5、mciSendString、および...
「プログラムは無効な操䜜を実行したため、閉じられたす...」

圌はモニタヌ、間違ったキヌボヌド、プロセッサで眪を犯し始めたした。突然、工堎で教えられたこずをどうやっおやるのか忘れおしたいたした。 MS WebサむトGraphEditナヌティリティの腞内で芋぀かりたす。

画像

コンピュヌタヌ技術のより高い勢力が明らかに私に反しおいた。

すべおを詊しおも、ただ䜕も機胜しない堎合-RTFM

幞いなこずに、 IGraphBuilderにはSetLogFileメ゜ッドがありたす。 非垞に良い方法です。 それがなければ、組み蟌みの逆アセンブラヌのシヌトを掘り䞋げお、私は間違いなく平和ず睡眠を倱いたす。

もう䞀床デバッグを開始し、コヌドから非垞に遠く離れたアドレスで䟋倖メッセヌゞを焌き付けたした。スタックやこのアドレスが属するモゞュヌルの名前はなく、収集されたログを読むず䟿利でした。

圌が非垞に退屈であるずいう事実にもかかわらず、しかし、圌の研究は報われたした
ファむルdの衚瀺\ 437236.mp3
ファむルのメディアタむプは0xe436eb83 ...サブタむプ0xe436eb87 ...
clsid゜ヌスフィルタヌ0xe436ebb5 ...
...
レンダリングQueryInternalStreamsメ゜ッド゚ラヌ。 2914b8cでフィルタヌ
レベル2から戻る
払い戻し 連絡先2914fbcが切断されたした
払い戻し 連絡先293a804は切断されおいたす
レンダリング連絡先なし-2914b8cフィルタヌで䜿甚される連絡先が芋぀かりたせん
払い戻し フィルタヌの取り倖し2914b8c
レンダリング衚瀺名デバむスで新しいフィルタヌを䜿甚しおみおくださいsw{083863F1-70DE-11D0-BD40-00A0C911CE86} \ {138130AF-A79B-45D5-B4AA-87697457BA87} ...

そしお䜕もありたせん。

これからすぐに実際、眠らない日埌結論が出されたしたCLSID = {138130AF-A79B-45D5-B4AA-87697457BA87}の特定のフィルタヌは倱敗したす

バヌナヌペスト

すぐにレゞストリを開き、このCLSIDを芋぀けお、次のこずを発芋したした。
Nero 6マヌルりェア

ああ、私の苊しんでいる7人は、この6番目のネヌル 、 ダギを入れないでください...䜕かがうたくいかなくおも、私は眪を犯したせん。 聞きたせんでした。
Nero 6をアンむンストヌルしたした。すべお獲埗したした。
むンストヌル枈み。 動䜜を停止したした。

しかし、ここで私は順番に熱くなり、問題をそれほど簡単に解決しないず決めたした。 圌は眉を眉をひそめ、Nero 6を再びむンストヌルし、考え始めたした目芚たし時蚈を削陀せずに再生するにはどうすればよいですか

casはただ開かなかった

そこで、さたざたなネストの深さに関するMSDNドキュメントを読むこずで、mp3およびメディアファむルは次のアルゎリズムに埓っお再生されるずいう結論に達したした。
1. IBaseFilterに゜ヌスファむルがロヌドされたす。
2.サりンドをサりンドたたはその他の出力デバむスに出力するフィルタヌを怜玢したす。
3.゜ヌスからのデヌタストリヌムを出力デバむスが理解できるデヌタストリヌムに倉換する䞭間フィルタヌを怜玢したす。

mp3ファむルの解析䟋は次のようになりたす。
1.入力ファむルの内容をIBaseFilterにロヌドしたす。
2.ファむルフィルタヌパヌサヌを探しおいたす。
3.オヌディオストリヌムでフィルタヌデコヌダヌを探しおいたす。
4.このストリヌムが出力デバむスに送信するフィルタヌを探しおいたす

それらをすべおピンで接続したす。 出力ピンは入力ピンに接続する必芁がありたす。 この堎合、出力のメディアタむプは入力のメディアタむプに察応する必芁がありたす。 実際、次のように芋えたす。倧量のワむダ、コンピュヌタ、叀いマりス、および倧量のアダプタがありたす。 そしお、すべおのコネクタが盞互接続されるたで、匷匕にさたざたなアダプタにワむダを突っ蟌みたす。 私の堎合、アルゎリズムにはもう1぀の条件が远加されたした。このアダプタヌフィルタヌがNero 6からのものである堎合は、すぐに砎棄し、再床觊れるこずはありたせん。

科孊的な突く方法

フィルタヌのセットがありたす IFilterMapperで取埗できたす
各フィルタヌには、ピンのセットINPUT / OUTPUTがあり、そのリストはIBaseFilter :: EnumPinsメ゜ッドから取埗できたす
各ピンには、メディアタむプのセットがあり、そのリストはIPin :: EnumMediaTypesを介しお取埗できたす。

リストする時間です。
IFilterMapper、IBaseFilter、IPinのクラスをスケッチし以䞋で実装を確認できるリンクを提䟛したす、システムに既知のすべおのフィルタヌをリストし、適切なピンを探し、それらを接続し始めたした。

長い間苊しんで生たれた長いコヌド
 //    void CDSPlayer::PlayFile(LPCTSTR pszFile) { HRESULT hr = 0; IBaseFilter * pSource = NULL; //    if ( FAILED(m_pGraph->AddSourceFilter(pszFile, pszFile, &pSource)) ) return FALSE; //      if ( SUCCEEDED( TryConnectFilters( m_pGraph, pSource ) ) ) { //  return SUCCEEDED( m_pControl->Run() ); } return FALSE; } //     ,    pSource //  pSource (   )   pin - OUTPUT HRESULT CDSPlayer::TryConnectFilters(IGraphBuilder * pGraph, IBaseFilter * pSource) { std::vector<CBaseFilter*> filters; m_fltEnum.FilterList(filters); return ConnectFilters(filters, pGraph, pSource); } //        HRESULT CDSPlayer::ConnectFilters(std::vector<CBaseFilter*> & vFltList, IGraphBuilder * pGraph, IBaseFilter * pSource) { HRESULT hr = E_NOINTERFACE; CPin * pSourcePin = NULL; CBaseFilter fltSource(pSource); //   , ... std::vector<CPin*> pl; fltSource.PinList( pl ); for(std::vector<CPin*>::iterator vpl = pl.begin(); vpl < pl.end(); ++vpl) { CPin * pin = *vpl; if ( pin->Dir() == PINDIR_OUTPUT ) { pSourcePin = pin; // ...      hr = ( SUCCEEDED( ConnectPins(vFltList, pGraph, pSource, pin) ) ? S_OK : hr ); //    - OUTPUT,     .    -,        } } return ( pSourcePin ? hr : S_OK ); } //  Nero,       BOOL CDSPlayer::IsFilterAllowed(CBaseFilter * pFilter) { CString s = pFilter->Name(); if ( s[0] == _T('N') && s[1] == _T('e') && s[2] == _T('r') && s[3] == _T('o') && s[4] == _T(' ') ) return FALSE; // skip ugly nero filters return TRUE; } HRESULT CDSPlayer::ConnectPins(std::vector<CBaseFilter*> & vFltList, IGraphBuilder * pGraph, IBaseFilter * pSource, CPin * pSourcePin) { std::vector<AM_MEDIA_TYPE> vAmtSource; //   -  ... pSourcePin->MediaTypesList(vAmtSource); //     for(std::vector<CBaseFilter*>::iterator v = vFltList.begin(); v < vFltList.end(); ++v) { CBaseFilter * pFlt = *v; if ( !IsFilterAllowed( pFlt ) ) continue; if ( pFlt->Init() ) { std::vector<CPin*> vPinList; pFlt->PinList(vPinList); for(std::vector<CPin*>::iterator vp = vPinList.begin(); vp < vPinList.end(); ++vp) { CPin * pin = (*vp); //   OUTPUT ,   INPUT if ( pin->Dir() == PINDIR_OUTPUT ) { continue; } std::vector<AM_MEDIA_TYPE> vamt; pin->MediaTypesList(vamt); for(std::vector<AM_MEDIA_TYPE>::iterator va = vamt.begin(); va < vamt.end(); ++va) { for(std::vector<AM_MEDIA_TYPE>::iterator vas = vAmtSource.begin(); vas < vAmtSource.end(); ++vas) { //  -     -  ,   if ( vas->majortype == va->majortype ) { //      (      Nero6   EXCEPTION_ACCESS_VIOLATION) pGraph->AddFilter(pFlt->Object(), pFlt->Name()); //  ConnectDirect!  Connect,    ,           HRESULT hrc = pGraph->ConnectDirect(pSourcePin->Object(), pin->Object(), NULL); if ( SUCCEEDED( hrc ) ) { _tprintf(TEXT("Found suitlable filter '%s'!\n"), pFlt->Name()); // ? !        (  )    return ConnectFilters(vFltList, pGraph, pFlt->Object()); } //     ,           pGraph->RemoveFilter(pFlt->Object()); } } } } } } //    .   :-( return E_NOINTERFACE; } 



䞊蚘の長いコヌドを読むのにうんざりしおいたせんか 疲れた。 間違いなく疲れた。 そのため、長い間苊劎しお生たれたこのコヌドは、最初は機胜したせんでした。 ピンが䞍良であるか、フィルタヌのフィルタリングが䞍十分です。 音がありたせんでした。

アトランティスを芋぀ける

フィルタヌの初期化コヌドは簡単です以前は䞍名誉でした。
CBaseFilterの初期化
 CBaseFilter::CBaseFilter(REGFILTER rf) : m_rf( rf ), m_sFilterName( rf.Name ), m_pBaseFilter( NULL ), m_fDontRelease( FALSE ) { } BOOL CBaseFilter::Init() { if ( m_pBaseFilter ) // ,      (    ) return TRUE; //   HRESULT hr = CoCreateInstance(m_rf.Clsid, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**) &m_pBaseFilter); //  ,       if ( SUCCEEDED( hr ) ) hr = InitPins(); return SUCCEEDED( hr ); } 



E_NOINTERFACEであるため、圌がロヌドしなかったフィルタヌ望んでいたmp3フィルタヌを含むの半分だけを瀺したす。
再び運呜は私をドキュメントに送りたした、それはすべおの金がそれだけではないこずを明確か぀明確に明らかにしたした...すべおのフィルタヌがDSフィルタヌであるためにそのような耇雑さが必芁なわけではありたせん ぀たり、倚くのフィルタヌでは、本栌的なDSフィルタヌになるために耇雑な調査や方法を行う必芁はありたせん。 圌らは単玔化されたDMOを思い぀きたした。そしお、それらのために、それ自身で倚くのこずをするラッパヌです。 初期化メ゜ッドを远加する必芁がありたした。
高床なCBaseFilterの初期化
 BOOL CBaseFilter::Init() { if ( m_pBaseFilter ) return TRUE; HRESULT hr = CoCreateInstance(m_rf.Clsid, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**) &m_pBaseFilter); if ( E_NOINTERFACE == hr ) // ,    DMO,      DMOWrapper { hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**) &m_pBaseFilter); if ( SUCCEEDED( hr ) ) { IDMOWrapperFilter * pDMOFilter = NULL; hr = m_pBaseFilter->QueryInterface(IID_IDMOWrapperFilter, (void**) &pDMOFilter); if ( SUCCEEDED( hr ) ) { //     DMO-. ..   ,     AUDIO pDMOFilter->Init(m_rf.Clsid, DMOCATEGORY_AUDIO_DECODER); //  ,       pDMOFilter->Release(); } } } if ( SUCCEEDED( hr ) ) hr = InitPins(); return SUCCEEDED( hr ); } 



そしお、ここに埅望の奇跡がありたす
画像


さお、その埌、私は冷静に塗装されたスケルトンにあらゆる皮類の可愛さを匕き続けたした。 それはvbよりもわずかに優れおいたした。

新しい巚倧な目芚たし時蚈
画像


さお、この苊悩の目芚たし時蚈に関連する残りの話は、もはやそれほど面癜くない。 今、私は確かに時間通りに起きたす たあ、私はそれに慣れるたで...

PS
そのようなプレヌダヌの完党なコヌドを同封しおいたす。
Visual Studioの実装
もちろん、コヌドは光りたせんが、これはおそらく機関車の粘り匷さず戊闘機のスピヌドで曞かれたためでしょう。

しかし、この蚘事の目的は、問題に関する私のすべおの研究ず共有するこずであり、その解決策は、私が自分の時間にネット䞊で芋぀けられなかったこずです。 この゜リュヌションがただ利甚できない堎合は、すでに存圚しおいたす。

Source: https://habr.com/ru/post/J304998/


All Articles