Android + Arduino + 4ホイール。 パート3-ビデオとサウンドの送信

最後に、前進します。 これで、家族はあえてロボットミティアを「無線制御マシン」と呼ぶことはなくなります。

AndroidガジェットからPCのリモートコントロールアプリケーションにビデオおよびオーディオストリームを転送するための比較的簡単で実用的な方法を見つけることは困難であることが判明しました。 このステップがなければ、私は断固として先に進むことを望まなかったので、長い間頑固さに立ち往生しました。


私を助けてくれたすべての人に感謝します。助けがなければ、私はこのタスクをマスターできなかったでしょう。 志を同じくする人々との通信は、私を非常に楽しくて面白い人々と一緒に連れて来ました。 ロボットMityaは、私が精神的に近い人を見つけるのを助けてくれたことがわかりました。 そして、それは私にとって全く予想外のボーナスでした。 おそらくこれが趣味の主な「利益」でしょうか? たった今、私はコミュニケーションが単なる「針仕事」よりも重要であることに気付きました。 共有する人、相談する人、自慢する人がいないのに、なぜこれがすべて必要なのでしょうか?

最愛の叙情詩的な要素で締めくくります。 この記事は、Mityaロボットに関する物語の続きです。 最初の部分では、ロボットをどのように構築したか説明し、 2番目の 部分では、プログラミングに必要なもの説明しました。 この記事では、ロボットからオペレーターにビデオと音声を送信する問題に集中します。 ここでは、特にプロジェクト全体とそのソフトウェアアーキテクチャについては繰り返しません。これらの問題については、最初の部分で詳しく説明します。

最もエキサイティングな質問:結果は何ですか、画像と音はどれくらい遅くなりますか? これが私のビデオレスポンスです。



干渉をおaびしますが、私は間違いなくオリジナルのサウンドとPCで再生されるサウンドの両方を実証しなければなりませんでした。 もちろん、遅れがあります。 さらに、再生中、音は写真よりわずかに遅れます。 ビデオは現実にほんの少し遅れています(結局、これはアナログシステムではないことを考慮し、すべてを強力な電話で実行できるようにする必要があります)。 私はロボットを制御しようとしましたが、ビデオはそのような遅延で不快感を経験しませんでした。 だから私は結果に非常に満足していました-音にわずかな遅れがあるので、私はそれを我慢する準備ができています。

オペレーターに表示される画像の品質は、HTC Sensationのフロントカメラが対応できるものに対応しています。 メインカメラを使用することもできますが、その後はミティアの表情を放棄しなければならず、それはできません。

ナビゲーションを簡単にするために、記事のさらなるコンテンツの計画を提供します。
1. ソリューションの進化(好奇心urious盛な人のみ)
2. IPウェブカメラ
3. Windowsアプリケーションでビデオを再生する
4. Windowsアプリケーションでサウンドを再生する
5. まとめ

ソリューションの進化(好奇心のためだけ)


「複数文字」で私を責めないために、妥協案を提示します:好奇心が強い、またはプロジェクトに同情する、または単に思いやりのある人(私がこれをすべて書いたわけではない)は、私がどのように出て、私が見つけて拒否した解決策を読むことができます。

真剣に、私は得られたすべての経験を可能な限り共有したいと思います。なぜなら、価値はポジティブな経験であるだけでなく、ネガティブな経験でもあると確信しているからです。 他人の過ちから学ぶことができる人がいたらどうなるでしょうか? さらに、誰かが出会った行き止まりから抜け出す方法を見つけたり見せたりしてくれたら、とてもありがたいです。 そして、それは経験の交換になるでしょう。

このセクションでは、行き止まりについて書いています。 ビデオとサウンドをロボットからPCに転送するためのレシピを探しているだけなら、次のセクションに進むことができます。

アイデアはシンプルでした。Androidアプリケーションのレベルでビデオおよびオーディオストリームの翻訳を実装するコードを埋め込み、Windowsコントロールアプリケーションのレベルでこれらのストリームを受信および再生するコードを埋め込みます。

私のコードに統合されていない既製の製品を使用するあらゆる種類の「ニーハイ」ソリューションは、すぐに却下されました。

私はビデオから始めました。 そして、何らかの理由で、ビデオストリームの形成と変換に問題はないと確信しました。 XXI世紀、結局のところ、誰かのスマートフォンはすでにクアッドコアです... 各携帯電話には2台のカメラが搭載されているという事実にもかかわらず、携帯電話からWebカメラを作成するのはそれほど簡単ではありません。 驚くべきことに、この問題を解決するための既製のソフトウェアツールがAndroidに組み込まれていません。 この問題は携帯電話メーカーにとって技術的な問題ではないため、理由はわかりませんが、一部の国ではこのようなソフトウェアを搭載したデバイスの認証の複雑さが原因であると考えられます。 突然、これはすでにスパイ機器ですか? これが私が思いつく唯一の説明です。 しかし、ミティアはモーターで鳴り響くので、彼からの偵察はカバからの風船のようです。 したがって、不眠症の良心は私を苦しめません。

google、code.google、stackoverflow、android developers、all-all-allを掘り下げてみると、非常に興味深いが、どこにも来ないソリューションが見つかりました。 そして、私はそれらに多くの時間を費やしました。 念のため、それらとそれらをそれぞれ拒否した理由を説明します。 経験が役立つ場合があります。 一部のタスクでは、これらのソリューションは非常に適していますが、私はそれらと友達になりませんでした。 完全にデッドロックオプションを省略します。 チャンスがある人だけを残します。

オプション1:Androidの一部であるMediaRecorderクラスを使用します。 私はここに、すべての問題の解決策だと思っていました-ここにビデオとオーディオの両方があります。 出力で3gpストリームを受信し、UDP経由でPCに送信します。 しかし、悲しいかな。 MediaRecorderはストリームで動作しないため、ファイルの処理方法のみを知っています。 グーグル、 groups.google.comフォーラムで非常に興味深い議論を見つけました。 同様のタスクがここで議論され、その議論の中で、別の興味深い投稿へのリンクが浮上しました。 MediaRecorderにファイルを操作していると思わせ、出力ストリームを実際にソケットに挿入して記録する方法を「ハッキング」する方法について説明します。 実装の説明は繰り返さず、すべてがそこに書かれています。 このオプションは、ディスカッションの参加者に非常に適していました。 タスクは、電話のメモリカードをバイパスして、電話からリモートコンピューター上のファイルにビデオを記録することでした。 それはファイルの中にありました-このオプションをより深く研究して、私はそれがウェブキャストに適していないと確信しました。 実際、私のデバイスのMediaRecorderは次のように機能します。ビデオが開始されると、ファイルが作成され、その先頭部分にストリームサイズを記録するための場所が予約されます。 このフィールドは、ビデオが完了したときにのみ入力されます。 このため、MediaPlayer出力ストリームはポジショニング(シーク操作)をサポートする必要があります。 たとえば、ファイルストリームはこれに対応しており、ネットワーク経由でブロードキャストする場合、ストリームはもちろん厳密にシーケンシャルであり、最初にジャンプしてフィールドを最終サイズで埋めることはできません。 しかし、彼らにはリモートコンピューター上のファイルに書き込むタスクがありました。 したがって、彼らは最初にストリームをファイルに「注ぎ」、次にこのファイルを記録のために開き、適切な場所にそのサイズを入力しました。 その後、そのようなファイルはすでに何でも再生できます。

私のプロジェクトのタスクは異なります。録音を完了する時間がありません。 そして、私はビデオストリームのサイズを決定することはできません。 つまり MediaPlayerの出力ストリームは、ウェブキャスト用ではありません。 少なくとも私のデバイスでは。 このオプションは捨てなければなりませんでした。

さて、私は自分ですべてをしようとすることにしました。 Androidは、デバイスのカメラから生のフレームを取得する機能を提供します。 この機能はどこでも顕著に説明されています。インターネットには、デバイスのカメラからのフレームを含む受信ストリームをjpegファイルに変換し、このファイルをメモリカードに保存する例がたくさんあります。 私の場合、jpegフレームのストリームは、PCのUDPで駆動できます。 しかし、ストリームが壊れている場合はどうなりますか(結局、UDPです)? フレームをラベルで何らかの形で分離するか、このためにjpegヘッダーを使用する必要があります。 PCでは、何らかの方法でフレームをストリームから分離する必要があります。 これはなんとなく低レベルであり、したがって、私はそれがまったく好きではありませんでした。 間違いなく既製のコーデックを使用する必要があります。 何らかの種類の標準メディアプロトコルを使用することも素晴らしいでしょう。 そして、私はこの方向で情報を収集し始めました。 そのため、2番目のオプションは生まれずに落ち、3番目のオプションはffmpegを使用します。

ffmpegは当然この分野で最も人気があり人気のある製品です。 開発されたコミュニティのおかげで、彼に頼ることは非常に可能であり、私は今後の作業の方向性を決定することにしました。 そして、私は2ヶ月間掛けました。 ffmpeg for Android自体をコンパイルする必要があることがわかりました。 同時に、ffmpegはCで記述されているため、Android NDKに精通する必要があります。Android向けのffmpegの構築は、Windowsでは非常に困難です。 「難しい」、これは完全に誠実ではありません。実際、Windowsでのコンパイルの成功について言及したことは一度もありません。 このテーマについては多くの質問がありますが、彼らはすべてのフォーラムにLinuxを1つの声で展開することを推奨しています。 さて、おそらく状況は変わったでしょう。ここに私のブログの記事に対する質問と私の答えがあります。 Linuxの使用経験はありません。 しかし、そのような獣がUbuntuインストールしなければならないという好奇心に戸惑いました。 さらに、インターネット上のffmpegのコンパイルに関する関連情報はないことが判明しました。 かなり苦しみましたが、彼はまだ切望されたffmpegを集めることができました。 アセンブリプロセスについては、ブログで詳しく説明しました。

この瞬間までに、ミティアは長い間隅にほこりを集めていました。 そして、Android NDKとの新しくて完全に喜びのない戦い、ffmpeg APIのドキュメントの完全な欠如、コーデックの謎とffserver(これはffmpegプロジェクトの一部であるストリーミングビデオサーバーです)の没入に私の目の前に迫りました。 ffserverを使用すると、ロボットからネットワーク上の任意のPCへのビデオとオーディオのブロードキャストを整理できます。 友達はすでにロボット工学で燃え尽きたと思って、泣き、刺しましたが、花崗岩をかじり続けました。 この方法で最後まで行けるかどうかはわかりません。

そして、助けが来ました。 覚えておいて、私は私が共通の趣味を共有した素晴らしい志を同じくする人々について話していたのですか? ロボットミティアはこの時点で一人ではなかったと言わなければなりません。 別の都市では、彼はすでに外見は非常に似ているように見えましたが、いくつかの場所では内心で異なっていました。 このロボットの作者であるLuke_Skypewalkerに対応します。 彼からの次の手紙には、 IP Webcamと呼ばれるAndroidアプリケーションを見るためのアドバイスがあります。 また、このアプリケーションがAndroidデバイスからHTTPビデオとサウンドをブロードキャストし、APIを備えており、バックグラウンドで動作することもわかります。

Mityaロボットに関する記事の最初の部分をプロジェクトのWebサイトで公開した後、IP Webcamを見てユーザーkib.demonからコメントを受け取ったことを認めなければなりません。 私は見ましたが、ひどく、主なものを見ませんでした-このアプリケーションにはソフトウェアAPIがあります。 ウェブカメラをそれ自体に実装するアプリケーションは必要ないと考え、すぐにその存在を忘れました。 また、記事自体へのコメントもありました。 APIについては言われていませんが、私も見逃しました。 このミスにより、ミティアはコーナーで3か月かかりました。

ffmpegで無駄に掘ったとは思わない。 私の投稿(まだ英語版がありました)の後、彼らは私に多くの質問を送ってくれました。 私は最高の知識に答えようとしますが、ほとんどの質問は空中に浮かんでいます。 トピックはまだ関連しています。 誰かがこの仕事を続けて説明してくれたらとてもうれしいです。 それでも、ffmpegとのソフトウェアの相互作用については、インターネット上にはほとんど何もありません。 そして、何年かは時代遅れです。 適切なコーデックを使用することにより、ffmpegを使用すると、最小のトラフィックから最大のビデオを絞り出すことができます。 多くのプロジェクトでは、これは非常に便利です。

IPウェブカメラ


そこで、MitiロボットのAndroid部分のレベルを決定しました。IPWebcamは、ビデオとオーディオのブロードキャストに使用されます。
開発者のサイトには、APIで使用可能な機能を説明するページがあります。 そこで、プログラムでIP Webcamと対話する方法を示す小さなAndroidプロジェクトのソースコードをダウンロードできます。

実際、この例の重要な部分は次のとおりです。

Intent launcher = new Intent().setAction(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME); Intent ipwebcam = new Intent() .setClassName("com.pas.webcam", "com.pas.webcam.Rolling") .putExtra("cheats", new String[] { "set(Photo,1024,768)", // set photo resolution to 1024x768 "set(DisableVideo,true)", // Disable video streaming (only photo and immediate photo) "reset(Port)", // Use default port 8080 "set(HtmlPath,/sdcard/html/)", // Override server pages with ones in this directory }) .putExtra("hidebtn1", true) // Hide help button .putExtra("caption2", "Run in background") // Change caption on "Actions..." .putExtra("intent2", launcher) // And give button another purpose .putExtra("returnto", new Intent().setClassName(ApiTest.this,ApiTest.class.getName())); // Set activity to return to startActivity(ipwebcam); 

注目すべきことは、放送ビデオの向き、解像度、および画質を制御できることです。 背面カメラと前面カメラを切り替え、フラッシュLEDをオンまたはオフにすることができます。 これはすべて、ブロードキャストを開始する前に設定で制御するか、プロジェクトの作成者が提供するチートコードを使用してプログラムで制御できます。
これは例に示されています。

少し気を散らす:残念ながらフラッシュ(ヘッドライトミティア)で私はパンクしています。 これはIP Webcamには適用されません。 私は以前に自分のコードですでにこの問題に遭遇しています。 私のデバイスでは、フロントカメラをアクティブにすると、フラッシュを制御できなくなります。 これはHTC Sensationだけではないようです。

IP Webcamアプリケーションでは、ブロードキャストを開始した後、アクティブなカメラからのビデオが画面に表示され始めます。 ビデオの上部に、2つのカスタムボタンが表示されます。 デフォルトでは、1つはヘルプダイアログを開始し、2つ目は利用可能なアクションのメニューを開きます。 この例では、作成者は最初のボタンを非表示にし、2番目のボタンを設定して、アプリケーションをバックグラウンドで翻訳します。

たとえば、ブラウザまたはVLCメディアプレーヤーアプリケーションで、オーディオ/ビデオブロードキャストを確認できます。 ブラウザのアドレスhttp:// <IP phone>:<port>でブロードキャストIPウェブカメラを開始すると、「スマートフォンカメラサービス」が利用可能になります。 ここでは、個々のフレームを表示し、ビデオとサウンドの再生を有効にすることができます。 たとえば、VLCメディアプレーヤーでビデオストリームを表示するには、URL http:// <phone IP>:<port> / videofeedを開く必要があります。 オーディオの再生には、http:// <phone IP>:<port> /audio.wavとhttp:// <phone IP>:<port> /audio.oggの2つのURLを使用できます。 サウンドにはかなりの遅延がありますが、後で判明したように、これは再生中のキャッシュによるものです。 VLCメディアプレーヤーでは、キャッシュを20ミリ秒に設定でき、サウンドの遅延はわずかになります。

それは良いニュースであり、今では悪いニュースでした。もちろん、私は困難を見つけました。 バックグラウンドでデバイス上で、IP Webcamがビデオのブロードキャストを停止しました。 Google Playのコメントを読んで、これが4番目のAndroidのすべてのラッキーな人に起こることがわかりました。 3日については知りません。 そして、IPウェブカメラの「発見」の少し前に、Androidのバージョンを2.3.4から4.0.3に更新しました。 バックグラウンドの作業が不可能であることは致命的でした。ビデオを放送するアクティビティを開いたままにしておくことができなかったためです。 銃口をアクティブにすると、IP Webcamアクティビティがバックグラウンドになり、ブロードキャストが停止しました。 はい、ロボットを制御するアプリケーションのその部分は、サービスとして整理できますが、ミティアの顔はどうですか?

自分で解決策を見つけられなかったので、IP Webcamプロジェクトの作者に手紙を書くことにしました。 著者は「私たち」であり、書くという意味ではロシア語でもよい。 次の3つのことが気になりました。

  1. バックグラウンドでブロードキャストを停止します。
  2. 画像からの音の遅れ。
  3. IP Webcamで電話のIPアドレスが誤って表示されました。 これは重要ではありませんが、最初は混乱します。 これはナンセンスではありますが、ここでの質問は電話画面の間違ったテキストにのみあります。

IP Webcamの作者(Pavel Khlebovich)に感謝します。 別の素晴らしい会議。 私たちからの通信中に、彼は私のすべての質問に答えただけでなく、別のデモプロジェクトも送信しました。これは、バックグラウンドモードと私のAndroid 4.0.3を使用する方法を示しています。

もちろん何よりも、最初の2つの質問が心配でした。 2つ目は、PavelがブラウザとVLCメディアプレーヤーでサウンドをキャッシュすることについてすべてを教えてくれました。

そして、ここに彼が最初の質問で私に書いたものがあります:「すべての4.x電話はすでにV4Lドライバを使用しているようです。 したがって、バックグラウンドでは、ビデオは機能しません。 回避策として、自分のアクティビティの上に独自のものを作成し、IP Webcamの表面が破壊されないように半透明であると説明することができますが、実際は不透明にして必要なものを表示します。

理解しやすいように思えますが、あるアクティビティを別のアクティビティよりも開くと、両方が機能するようになります。 単位時間あたりアクティブにできるアクティビティは1つだけだと思っていました(しゃれは残念です)。 私はいくつかの実験を行いましたが、「低い」アクティビティでは常にonPauseがトリガーされました。 パベルは再び助けてくれました。彼は私のために特別にデモプロジェクトを作成しました。 驚くべきことに、1つのアクティビティを別のアクティビティの上に配置するというアイデアは機能します。 Pavelのデモプロジェクトを(美容的に)少し変更して、Robot MityaのWebサイトに投稿しました。

このデモで行われたことを説明します。

1. Button1がメインアクティビティのレイアウトに追加されました。
2.画像​​「some_picture.png」を含む別のレイアウト「imageoverlay.xml」を追加しました。 それ以上のものはありません。
3. imageoverlay.xmlコンテンツを表示するOverlayActivity.javaを追加しました。 IP Webcamビデオの上部に表示されるのはこのアクティビティです。 私のメインプロジェクトでは、この場所でロボットをアクティブにするアクティビティがあります。 彼女はミティアの顔です。
4.マニフェストに次を追加する必要があります。

a)OverlayActivityの説明:

 <activity android:name="OverlayActivity" android:launchMode="singleInstance" android:theme="@android:style/Theme.Dialog"> </activity> 

launchModeおよびtheme属性には、指定された値を入力する必要があります。

b)デバイスのカメラにアクセスする権利:

 <uses-permission android:name="android.permission.CAMERA"/> 

5. MainActivity.javaを補足します。

 package ru.ipwebcam.android4.demo; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { static String TAG = "IP Webcam demo"; Handler h = new Handler(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final Button videoButton = (Button)findViewById(R.id.button1); videoButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { Intent launcher = new Intent().setAction(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME); Intent ipwebcam = new Intent() .setClassName("com.pas.webcam", "com.pas.webcam.Rolling") .putExtra("hidebtn1", true) // Hide help button .putExtra("caption2", "Run in background") // Change caption on "Actions..." .putExtra("intent2", launcher); // And give button another purpose h.postDelayed(new Runnable() { public void run() { startActivity(new Intent(MainActivity.this, OverlayActivity.class)); Log.i(TAG, "OverlayActivity started"); } }, 4000); startActivityForResult(ipwebcam, 1); h.postDelayed(new Runnable() { public void run() { sendBroadcast(new Intent("com.pas.webcam.CONTROL").putExtra("action", "stop")); Log.i(TAG, "Video is stopped"); } }, 20000); Log.i(TAG, "Video is started"); } }); } } 

ボタンをクリックすると、IP Webカメラが起動し、4秒後に写真付きのアクティビティがその上に開きます。 両方のアクティベーションが表示されるように、画像サイズは特別に画面解像度よりも小さくなります(少なくともHTC Sensationの場合)。 そして、起動後20秒で、バックグラウンドでのIPウェブカメラは動作を停止しますが、「メイン」アクティビティは動作し続けます。

電話での表示は次のとおりです。

私とロボットミティア

その後、MityaのAndroidアプリケーションを少し変更するだけで、PCのブラウザーでカメラでそれを確認し、マイクでそれを聞くことができました。

Windowsアプリケーションでビデオを再生する


これについては以前は考えていませんでしたが、この段階で初めてIP Webcamのビデオは実際にはビデオではないことに気付きました。 これはMJPEGです。 つまり ブロードキャストストリームは、JPEG形式のフレームの順次送信です。 私は、ビデオ伝送に関連する問題が非常に弱いため、MJPEGからの俊敏性は期待していませんでした。 そして無駄に-結果は私に非常に適していました。

MJPEGストリームを再生するために、すばらしい無料製品MJPEG Decoderを見つけました。 MJPEGを表示する手段の検索は、Windows Mitya管理アプリケーションがXNAフレームワークを使用するという事実により複雑になりました。 MJPEG DecoderはXNA 4.0をサポートし、WinForms、WPF、Silverlight、およびWindows Phone 7アプリケーションでも動作します。

Mityaのソースはまだ開いていますが、すべてがたくさんあるので、ここではXNAアプリケーションでMJPEG Decoderを使用してIP Webcamからビデオストリームを再生するデモ例を紹介します。 次のセクションでは、IP Webcamからサウンドを再生するためのコードでこの例を補足します。

そこで、Windows Game(4.0)プロジェクトを作成します。 ライブラリ「MjpegProcessorXna4」をこのプロジェクトのリンクに追加します( プロジェクトWebサイトまたは鉱山からダウンロードします)。

Game1.csファイルで、MjpegProcessor名前空間の使用を宣言します。

 using MjpegProcessor; 

プライベートmjpegフィールドを宣言します。

 private MjpegDecoder mjpeg; 

ビデオ出力のテクスチャを宣言します:

 private Texture2D videoTexture; 

Initializeメソッドを補足します。

 this.mjpeg = new MjpegDecoder(); 

Updateメソッドを補足します。
1.スペースバーを押すと、ビデオストリームの再生が開始されます。

 this.mjpeg.ParseStream(new Uri(@"http://192.168.1.40/videofeed")); 

2. Escを押すと、再生が停止します。

 this.mjpeg.StopStream(); 

3. Updateを呼び出すときに、次のフレームを受け入れます。

 this.videoTexture = this.mjpeg.GetMjpegFrame(this.GraphicsDevice); 

Drawメソッドを補足します。

 if (this.videoTexture != null) { this.spriteBatch.Begin(); Rectangle rectangle = new Rectangle( 0, 0, this.graphics.PreferredBackBufferWidth, this.graphics.PreferredBackBufferHeight); this.spriteBatch.Draw(this.videoTexture, rectangle, Color.White); this.spriteBatch.End(); } 

ほとんどすべてです。 ほとんどすべてがすでに機能しているため、再生中のフレームはほとんど変化しないためです。 私は1〜2秒ごとにそれを持っています。 これを修正するには、次のようにクラスコンストラクターを修正します。

 public Game1() { this.IsFixedTimeStep = false; this.graphics = new GraphicsDeviceManager(this); this.graphics.SynchronizeWithVerticalRetrace = false; Content.RootDirectory = "Content"; } 

Game1.csファイルの内容は、ストリーミングオーディオ再生コードで補足するときに、次のセクションの最後で提供します。

Windowsアプリケーションでサウンドを再生する


標準のXNAまたは.NETツールを使用してIP Webcamからオーディオストリームを再生する方法を見つけることができませんでした。 「audio.wav」も「audio.ogg」もありません。 XNAフレームワークの静的MediaPlayerクラスを使用してストリーミングオーディオが再生される例を見つけましたが、私たちのストリームは彼にとっては強すぎました。

NAUDIOおよびSlimDXプロジェクトを開くためのWeb上の多くのリンク。 しかし、最初はデモアプリケーションを起動しましたが、それも失敗し、2番目はマスターしませんでした。 私は本当にDirectXレベルまでスライドダウンしたくありませんでした。 偶然、素晴らしい方法を見つけました。 非常に同じ素晴らしいVLCメディアプレーヤーと共にActiveXライブラリが付属していることがわかりました。 つまり Windowsでは、COMインターフェイスを使用してVLCを操作できます。 インターフェイスの説明は非常に意味が高く、VLCプロジェクトのWLCには一般的に古い情報が含まれています。 不快ですが、すべてがうまくいきました。

ActiveXライブラリインターフェイスを使用するには、最初に登録する必要があります。 VLCメディアプレーヤーをインストールすると、登録されず、私が理解するように、Vlcフォルダーに重荷が置かれます。 これを行うには、コンソール(cmd.exe)を実行し、次を入力します。

regsvr32 "c:\Program Files (x86)\VideoLAN\VLC\axvlc.dll"

もちろん、パスを指定します。 Windows VistaまたはWindows 7を使用している場合は、管理者としてコンソールを実行します。

これで、IP Webcamのサウンドをどこからでも再生できます。 Excelでトレーニングしました。 VBScriptでは可能ですが、VBAクラスでは、メンバーはプロンプトでクロールします。 必要に応じて、簡単な例を示します。 Excelを開き、Alt + F11を押します。 Microsoft Visual Basic for Applicationsウィンドウで、メニューツール->参照...リンクを「VideoLAN VLC ActiveXプラグイン」に接続します。 これで、モジュールを追加し、そこにマクロテキストを入力できます。

 Sub TestAxLib() Dim vlc As New AXVLC.VLCPlugin2 vlc.Visible = False vlc.playlist.items.Clear vlc.AutoPlay = True vlc.Volume = 200 vlc.playlist.Add "http://192.168.1.40:8080/audio.wav", Null, Array(":network-caching=5") vlc.playlist.playItem (0) MsgBox "Hello world!" vlc.playlist.stop End Sub 

IP Webcamを起動し、マクロを実行します-音がします! ところで、ビデオを再生することもできます。

テストXNAアプリケーションに戻り、ストリーミングサウンドを再生するには、次の手順を実行します。

プロジェクトのCOMコンポーネント「VideoLAN VLC ActiveXプラグイン」へのリンクを追加します。 「ソリューションエクスプローラー」では、「AXVLC」と表示されます。 「AXVLC」リンクを選択し、「プロパティ」ウィンドウで「相互作用タイプを埋め込む」プロパティをFalseに設定します。

AXVLC名前空間の使用を宣言します。

 using AXVLC; 

オブジェクトの宣言:

 private AXVLC.VLCPlugin2 audio; 

Initializeメソッドを補完します。

 this.audio = new AXVLC.VLCPlugin2Class(); 

更新方法を補足します。
1.スペースバーを押すと、オーディオストリームの再生が開始されます。

 this.audio.Visible = false; this.audio.playlist.items.clear(); this.audio.AutoPlay = true; this.audio.Volume = 200; string[] options = new string[] { @":network-caching=20" }; this.audio.playlist.add( @"http://192.168.1.40:8080/audio.wav", null, options); this.audio.playlist.playItem(0); 

2. Escを押すことにより、オーディオストリームの再生を停止します。

 if (this.audio.playlist.isPlaying) { this.audio.playlist.stop(); } 

だからここにあなたが得るべきものがあります:

 using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using AXVLC; using MjpegProcessor; namespace WindowsGame1 { /// <summary> ///   . /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; /// <summary> ///    . /// </summary> private Texture2D videoTexture; /// <summary> ///  MJPEG. ///      (, MJPEG),   IP Webcam. /// </summary> /// <remarks> ///   .NET  "MjpegProcessorXna4". /// </remarks> private MjpegDecoder mjpeg; /// <summary> ///  VLC. ///     ,   IP Webcam. /// </summary> /// <remarks> ///   ActiveX- VLC (www.videolan.org). ///   VLC,  ActiveX- axvlc.dll,       COM- "VideoLAN VLC ActiveX Plugin" (     "AXVLC"). /// </remarks> private AXVLC.VLCPlugin2 audio; /// <summary> ///  . /// </summary> public Game1() { this.IsFixedTimeStep = false; this.graphics = new GraphicsDeviceManager(this); this.graphics.SynchronizeWithVerticalRetrace = false; Content.RootDirectory = "Content"; } /// <summary> ///    . /// </summary> protected override void Initialize() { base.Initialize(); //   : this.mjpeg = new MjpegDecoder(); //  COM-   : this.audio = new AXVLC.VLCPlugin2Class(); } /// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); } /// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { //          : if (Keyboard.GetState().IsKeyDown(Keys.Space)) { //   : this.mjpeg.ParseStream(new Uri(@"http://192.168.1.40:8080/videofeed")); //   : this.audio.Visible = false; this.audio.playlist.items.clear(); this.audio.AutoPlay = true; this.audio.Volume = 200; string[] options = new string[] { @":network-caching=20" }; this.audio.playlist.add( @"http://192.168.1.40:8080/audio.wav", null, options); this.audio.playlist.playItem(0); } //    Esc   : if (Keyboard.GetState().IsKeyDown(Keys.Escape)) { //   : this.mjpeg.StopStream(); //   : if (this.audio.playlist.isPlaying) { this.audio.playlist.stop(); } } //  : this.videoTexture = this.mjpeg.GetMjpegFrame(this.GraphicsDevice); base.Update(gameTime); } /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); if (this.videoTexture != null) { this.spriteBatch.Begin(); Rectangle rectangle = new Rectangle( 0, 0, this.graphics.PreferredBackBufferWidth, this.graphics.PreferredBackBufferHeight); this.spriteBatch.Draw(this.videoTexture, rectangle, Color.White); this.spriteBatch.End(); } base.Draw(gameTime); } } } 

まとめ


この段階を終えて、技術的な結論と非技術的な結論の両方がありました。

これで、友人は家を出ずにミティアの「アパート」内の私のアパートを旅することができます。 より正確には、ゲームパッドがあれば可能です。 より人気のある入力ツールを作成することに成功したようです。

ミティアはすべてを見て聞いていますが、何も言えません。 まず、彼の顔の表情を広げ、「はい」、「いいえ」、「尾を振る」などの基本的なジェスチャーを教える必要があります。 次に、オペレータからロボットまで、反対方向にサウンドを再生する必要があります。

もう1つの疑問は、ミティアの頭を駆動する垂直サーボの絶え間ないブザー音の動作です。 電話の重量により、サーボドライブは所定の角度を維持するように強制され、絶えずハミングと微振動を続けています。 これはビデオには影響しませんが、マイクが目詰まりします。 その結果、オペレーターには、うなり音以外は何も聞こえません。 頭のある位置では、音が止まり、すべてが完全に聞こえます。 この問題を解決する方法すら知りません。

私の非技術的な経験は、趣味の新しい側面を発見することです。 隅に立って、ミティアのロボットは自分の人生を生きているようです。彼は私に興味を持ち、いくつかの点で私に非常に似ている人々に私を紹介します。まだこのプロジェクトに。 私は精神科医がいないことを願っています...一言で言えば、私は夕方の娯楽からそのような復帰を期待していませんでした(私の側とミティナの両方で)。

そして、ここに私が思い出そうとする別の結論があります。 勝利ほど動機付けられるものはないことを完全に理解しています。 そして、何も勝利の長い不在ほど興味を殺しません。 誰もが私のような頑固な退屈さを持っているとは限りません。 そして、私もこのすべてを落とす寸前でした。 当分の間、私は別のプロジェクトを取り上げ、これから休憩を取ってから、間違いなく戻ると自分に言いました。 しかし、深く私はそれが何を意味するかを知っていて、その角度を調べないようにしました。 ビデオの送信の問題を解決することは、このプロジェクトでの私にとって大きな一歩でした。そして、私はもう大きな一歩を踏み出さないようにします。 大きな一歩は大きなリスクです。 別の仕事に就くところだったので、より魅力的に思えましたが、今ではそのことすら覚えていません。 私の頭の中では、ミティアの計画が大勢います。 だから今、私は自分で小さなタスクを設定します。 たくさんの勝利を望んでいます。これは私の喜びの糧です! 将来は大きな勝利なしでやろうと思います。 私はたくさんの小さなものを選びます。

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


All Articles