HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2015
0831
スペース録画ソフトを作りたいのですが・・・61解決


スペース

リンク

2015/8/31(Mon) 22:24:09|NO.71183

録画ソフトを作りたいのですが、処理速度の問題で躓いています。

まず、画面の取り込みに関してはBitBltで最低1000fps出るので全く問題ないのですが、
保存・エンコードに時間がかかってしまいます。

保存方法についてですが、
まずcvputaviでリアルタイムに保存し続ける方法を試しました。
ですが色々試した中で最も早いBandi MPEG-1ですら30fpsを維持するのが限界で、
他は20fps以下でした。
目標は60fps、最低30fpsを維持することなのでbandi MPEG-1で目標は達せられては居ますが、
ギリギリなのでスペック・起動するソフトによっては簡単に30FPSを切るでしょう。

次に、巨大なbufferを作成し毎フレームbufferに書き込む、という方法です。
まず課題としてメモリ(RAM)の問題です。

VRAMbufferは1pxで3バイト
仮に1920x1080のモニターだとして1枚は1920px*1080px*3=5.93mbです。
それが毎秒60枚・・・1秒で355.8mb、1分で20.84GB・・・何処のハイエンドPCでしょうか?

3つ目はjpgやpng等で一時的にHDDに保存する、という方法です。
保存にはこちらのモジュールを使用しました。GDIを使用しています。
https://goo.gl/atUU7E

結論から言うと、処理速度的に無理でした。20fps程度です。
画質を変えてみましたが結局対して変わりませんでした。

もう1つの方法として、一旦jpgのように圧縮し、バイナリデータを変数に保存する、というものです。
メモリストリームのような感じですね。ただ、jpgのバイナリデータを変数に保存する方法がわかりません。
jpgに限らず、データを圧縮できればそれで問題ありません。


画像(VRAMbuffer)を圧縮して変数に保存するにはどうすればいいのでしょうか?

最終的な目的はエンコードや保存をリアルタイムに行うことなので、
もし他に良い方法を知っている方が居ましたら、教えていただけると幸いです。



この記事に返信する


ZAP

リンク

2015/8/31(Mon) 23:01:02|NO.71188

HSPで組んだ時点で処理速度が犠牲になるので
自ら凄くハードルを上げているような気がします・・・



葡萄色

リンク

2015/8/31(Mon) 23:17:19|NO.71189

結構昔に自分もキャプチャソフトをHSPで作ろうと試みたのですが、自分のPCでは10fps行くか行かないかくらいの物しかできませんでした。
個人的には他の言語を検討することをおすすめします。
(でも解決策に期待)



スペース

リンク

2015/9/1(Tue) 00:03:40|NO.71193

やはりHSPでは処理速度的に難しいですかね・・・
「GIFや動画の基本は前のフレームと同じ部分は保存しない」というものですが、
これをVRAMを変数に保存する時に行い、どの程度メモリを節約&高速化出来るのか、
そして保存の処理のみを行うソフトを作り、メモリ共有で色々やりとりし並列処理っぽいことをしたり・・・
(もちろん、DLLで並列処理できる事は知っています。)

色々考えていますが、今日は遅いので明日試してみます。



(´ω`)

リンク

2015/9/1(Tue) 16:01:55|NO.71208

今だと多分、AVer Media あたりを使うのが一番楽ではありますよね。(u´ω`)
http://www.google.co.jp/shopping/product/10161775714165885094

HSPでやるなら、アマレココのコーデックを使う方法があるかも。
http://www.amarectv.com/hosoku/ren02.htm



スペース

リンク

2015/9/1(Tue) 17:41:08|NO.71218

>(´ω`)さん
ありがとうございます。
私自身はShadowPlayがあるので全く録画には困っていません。
ですので録画ソフトは好奇心で作ってみたいというだけです。
言葉足らずで申し訳ございません・・・

アマレココのコーデックとはAMV2、AMV3の事でしょうか?
実はスレを建てる前に試していたのですが、最も遅い設定で20fps以下でした。
ですが他の設定は試していなかったので今試した所、圧縮率を下げると40fps以上出たので、
これなら30fpsはある程度余裕を持って維持できそうです。



ブランク

リンク

2015/9/2(Wed) 01:22:04|NO.71239

利用目的は何ですか?
まさか有料のストリーミング動画を複製するためとか・・・



空気

リンク

2015/9/2(Wed) 09:45:08|NO.71245

横から口を挟ませて頂きますが、
有料のストリーミング放送を複製することについては
契約違反(民事)になるかもしれませんが、
著作権法上は問題ないと思うので、
あえてこの掲示板で問い正す必要は無いのでは、ないでしょうか?



空気

リンク

2015/9/2(Wed) 09:50:04|NO.71246

アマレコのコーディックには、最新のCPU命令セットを使った、
(Corei7 Sandy 以降対応?)
高速なAMV4コーディックという物もあります。(無料版はロゴが入ります)



スペース

リンク

2015/9/2(Wed) 10:28:22|NO.71247

>>ブランクさん
ありがとうございます。
私自身はShadowPlayがあるので全く録画には困っていません。
ですので録画ソフトは好奇心で作ってみたいというだけです。
ちなみにアマレココ等を使えば有料ストリーミングの複製はいくらでも出来ると思います。
言葉足らずで申し訳ございません・・

>>空気さん
AMV安定なんですかね。
ただ、AMV3は問題ないのですが、AMV4だと画面が引き伸ばされたかのようになってしまいます。
https://gyazo.com/8ceeceb9c58548459ab0132c3fac3b66

やはりリアルタイムエンコードは処理が重いので、
VRAMbufferを圧縮して一時的に変数に保存したいのですが、其のようなDLLはあるのでしょうか?
検索した限り、見つかりませんでした。



スペース

リンク

2015/9/2(Wed) 21:05:36|NO.71269

あれ、そもそもBitBltだけで60fps出ない・・・?
いつもは出てた気がするのですが。
皆様、もしよろしければ皆様のpcで何fpsでるのか教えて頂けないでしょうか?


#include "d3m.hsp" #uselib "gdi32.dll" #cfunc CreateDC "CreateDCA" sptr,sptr,sptr,int #func DeleteDC "DeleteDC" int #func BitBlt "BitBlt" int,int,int,int,int,int,int,int,int #define NULL 0 #define SRCCOPY 0x00CC0020 #define CAPTUREBLT 0x40000000 ; デスクトップ画面のサイズでバッファ画面を作成 sx = ginfo_dispx : sy = ginfo_dispy buffer 2, sx, sy:hdc2=hdc Screen 0,sx/4.0,sy/4.0 repeat //60*2 gsel 2 hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL) BitBlt hdc2, 0, 0, sx, sy, hdcScreen, 0, 0, SRCCOPY | CAPTUREBLT DeleteDC hdcScreen gsel 0 title ""+d3getfps() gcopy 2,0,0,1920,1080 await 10 loop



スペース

リンク

2015/9/2(Wed) 21:41:08|NO.71270

大変申し訳ございません。
Aeroが原因でした・・・お騒がせしました。



b

リンク

2015/9/2(Wed) 21:43:24|NO.71272

スペースさん 質問者ではないですが..

>まず、画面の取り込みに関してはBitBltで最低1000fps出るので全く問題ない
ということで1000fps出るようです (違う意図で質問しているのならすみません)

>保存・エンコードに時間がかかってしまいます。
>エンコードや保存をリアルタイムに行うこと
らしいです。

BitBltをAVIに直接してくれるものでもあればいいな



スペース

リンク

2015/9/2(Wed) 22:21:11|NO.71275

>>bさん
BitBltが最低1000fps出る、というのは私の勘違いでした。
申し訳ございません。
とりあえずリアルタイムにaviを出力するのは諦め、他の方法を考えます。



(´ω`)

リンク

2015/9/4(Fri) 10:15:26|NO.71305

例えばPanasonicさんのカメラ録画ソフトでは、同時に16台までのカメラの録画をして
くれるのですが、やはり処理速度がネックらしく、

・画像は画像として、音声は音声としてとりあえず記録する
・動画ファイルが欲しい時は、それらを合成して吐き出す

という手段をとってるようです。
記録先をSSDなどの高速&大容量デバイスに限定し、ものすごい勢いでBMPを吐き出し
後で動画を生成するという手もアリかもしれません。

ご参考までに。(´ω`)



スペース

リンク

2015/9/4(Fri) 11:58:12|NO.71306

>>(´ω`)さん
有難うございます。
やはり動画は後で出力するのが安定なようですね。
ですがpngやjpgで試しているのですがどうしても30枚分ですら1秒以上かかってしまいます。
bmpではそれ以上ですね。どうしたものか・・・



motchy

リンク

2015/9/4(Fri) 12:20:34|NO.71307

bmp形式での保存の際に bmpsave 命令を使ってる
なんてことないですよね?



スペース

リンク

2015/9/4(Fri) 13:07:14|NO.71308

>>motchyさん
はい、そのまさかですね。
他を試してないんですけどやっぱりbmsaveは遅いんですか・・・



スペース

リンク

2015/9/4(Fri) 13:15:41|NO.71309

連投すみません。
GDI使って保存しましたがやはり遅いですね・・・
何か書き方に問題があるのでしょうか?

#uselib "Dwmapi" #define DWM_EC_DISABLECOMPOSITION 0 #define DWM_EC_ENABLECOMPOSITION 1 #func DwmEnableComposition "DwmEnableComposition" int #include "GDIplusImgSaveMod.hsp" #include "winmm.as" #include "hspcv.as" #include "d3m.hsp" #uselib "gdi32.dll" #cfunc CreateDC "CreateDCA" sptr,sptr,sptr,int #func DeleteDC "DeleteDC" int #func BitBlt "BitBlt" int,int,int,int,int,int,int,int,int #define NULL 0 #define SRCCOPY 0x00CC0020 #define CAPTUREBLT 0x40000000 #const SRCINVERT $00660046 ; デスクトップ画面のサイズでバッファ画面を作成 sx = ginfo_dispx : sy = ginfo_dispy buffer 2, sx, sy//ソースバッファ兼、アルファブレンド用 hdc_2=hdc hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL) onexit goto*終了 DwmEnableComposition DWM_EC_DISABLECOMPOSITION repeat gsel 2 BitBlt hdc_2, 0, 0, sx, sy, hdcScreen, 0, 0, SRCCOPY | CAPTUREBLT imgsave_ "a\\"+cnt+".bmp" gsel 0 fps = d3getfps() if fps=0:fps+1 title ""+fps+"fps "+(1000.0/double(fps))+"ms" pos 0,0:gzoom double(sx)/2.0,double(sy)/2.0,2,0,0,sx,sy,0 await 1 loop *終了 //cvendavi DeleteDC hdcScreen DwmEnableComposition DWM_EC_ENABLECOMPOSITION end



motchy

リンク

2015/9/4(Fri) 14:08:42|NO.71310

単一ファイルとして一枚一枚保存しているのが遅い原因だと思うのです。
bmp1枚を保存する度に、ファイルヘッダの作成, ファイルシステムから空き領域の検索, ディスクへの書き込みとファイルシステムの管理情報の更新、とややこしい処理がWindowsによって行われていると思います。

VRAMバッファの内容を bsave で確保済みの巨大ファイルに紙芝居の要領で書き出したらもう少しマシになるのではないかと思います。
bsave では保存先のファイルのオフセットが指定できますから、トランプのカードの山を積み上げるように既存ファイルの末尾にVRAMバッファの生データを爆速で積み上げていけば良いのではないかと。
エンコードには少々時間がかかっても許されるでしょうから、積み上げた山から1枚1枚取り出してゆっくり処理をすれば良いと。

実際に速度を検証したわけではないので、ここから先は無責任なアドバイスになることをはじめに断っておきます。

1フレームの縦横サイズが確定すれば1枚分のVRAMバッファのデータサイズが決まりますね。Fバイトとしましょう。(RGB3バイトx横*縦だと理解しています。)
録画時間があらかじめ分かっている場合、或いは、はっきりとは分かっていなくても上限が知れている場合(高々30分とか)、これと目標フレームレートを掛け算すれば、あり得るフレーム数の上限が決まります。N枚としましょう。(30fpsで3分なら30*60*3=5400枚)
そうすれば全フレームの合計データサイズVが決まります。(V=F*N)

そして録画前にVバイトの巨大ファイル(0埋めとかでいいと思います。)をディスクに作成しておき、録画開始とともにその先頭からVRAMバッファの生データの積み上げを開始します。("録画"ですね。)
こうすればこのファイルは論理的には連続しており、bsave でオフセット付きでVRAMバッファの内容を書き込んでいってもファイルサイズは増大しません。(ファイルシステムの空き領域を検索する処理が省かれます)
HDDの場合、十分な連続空き領域が存在している場合はこのファイルは物理的にも連続して作成されるでしょうからヘッダの移動にかかる時間も少なくて済むと思います。SSDなら関係ない話ですが。

ただ、言うまでもないですがファイルサイズは半端無いです。



スペース

リンク

2015/9/4(Fri) 15:49:39|NO.71312

>>motchyさん
有難うございます。
取り敢えず組んでみたのですが、処理方法に問題はありませんか?
こちらのPCではHDDに書き込む時、1920x1080だと10fpsを切ってしまいます。

#uselib "Dwmapi" #define DWM_EC_DISABLECOMPOSITION 0 #define DWM_EC_ENABLECOMPOSITION 1 #func DwmEnableComposition "DwmEnableComposition" int #include "d3m.hsp" #uselib "gdi32.dll" #cfunc CreateDC "CreateDCA" sptr,sptr,sptr,int #func DeleteDC "DeleteDC" int #func BitBlt "BitBlt" int,int,int,int,int,int,int,int,int #define NULL 0 #define SRCCOPY 0x00CC0020 #define CAPTUREBLT 0x40000000 総フレーム数=100//100以下推奨 倍率=double(1)//倍率 ssx = double(ginfo_dispx) : ssy = double(ginfo_dispy)//元サイズ sx = double(ginfo_dispx)*倍率 : sy = double(ginfo_dispy)*倍率//縮小後のサイズ buffer 2, ssx, ssy//キャプチャ用バッファ hdc_2=hdc pos sx,0:gmode 0,sx,sy,256 buffer 3,sx,sy//縮小 hdc_3 = hdc mref VRAM,66 bsave "テスト.txt",VRAM,-1,-1//ファイルがない状態でオフセットを指定するとエラーになるので //*スラッシュ1つでコメントアウト repeat 総フレーム数//N枚分確保 bsave "テスト.txt",VRAM,sx*sy*3,cnt*(sx*sy*3) loop//*/ Screen 0,sx,sy:onexit goto*終了 hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL)//デスクトップのhdc取得 DwmEnableComposition DWM_EC_DISABLECOMPOSITION//Aero無効 repeat 総フレーム数 BitBlt hdc_2, 0, 0, ssx, ssy, hdcScreen, 0, 0, SRCCOPY | CAPTUREBLT//キャプチャ gsel 3//縮小 pos 0,0:gzoom sx,sy,2,0,0,ssx,ssy,1 bsave "テスト.txt",VRAM,sx*sy*3,cnt*(sx*sy*3) gsel 0 fps = d3getfps() if fps=0:fps+1 title ""+fps+"fps "+(1000.0/double(fps))+"ms" gcopy 3,0,0,sx,sy await (33+(cnt\3=0))//30fps維持 loop Dialog "総フレーム数に達したため終了します" *終了 DeleteDC hdcScreen DwmEnableComposition DWM_EC_ENABLECOMPOSITION//Aero有効 end



motchy

リンク

2015/9/4(Fri) 17:34:25|NO.71313

やり方はそんな感じです。

ダメでしたか...。10fpsじゃ録画ソフトとしては悲しいですね。
こちらでは20〜30fps出ましたが、RAMにあるであろう書き込みキャッシュが定期的(数秒に1回程)一杯になる度に一瞬止まりました(5fps程に落ちる)。
その瞬間にHDDに一気に吐き出されている感じです。そして復活..の繰り返し。
縮小処理やscreen0へのプレビューをやめてみると少しマシになりましたが対して変わりません。

じゃぁ bmpsave は速いのか?と思ったので提示されたスクリプトを書き換え、フレーム数を500に変えてbmpsaveで保存するようにして実験してみたところ、最初の数秒間は威勢が良く30fps出ていますがその後は急落して数fpsの定常状態になります。
恐らくbmpsave でWindowsに要求を出すとHDDへの書き込みが間に合わない分はWindowsがRAMにキャッシュしているのだと思いますが、そのキャッシュが一杯になった後はfpsが激落ちするようです。

結局のところディスクの書き込み速度がボトルネックになって、小手先ではどうしようもない感じです。


良いアドバイスができなくて残念です。とりあえず「VRAM生書きは bmpsave よりは速い」というところまでが成果ですかね。



motchy

リンク

2015/9/4(Fri) 17:46:50|NO.71314

もう一度失礼します。

先ほどの投稿の前に「VRAMに保存して再生する」というのがどんな感じになるか実験していたスクリプトがありまして、結局徒労に終わりましたが「保存・再生はこんな感じになります」という意味で晒しておくことにします。

30秒録画してその後再生するものです。


/* 二重振り子の運動の様子を録画してみる */ wsizex = 600 //ウィンドウサイズ wsizey = 600 /* 物理設定 */ #define dt 0.01 ;[s] タイムステップ #const double hdt dt/2 ;[s] dt/2 #define g 9.8 ;[m/s^2] #define σ 1.0 ;[kg/m^2] 錘の面密度 #define l1 1.5 ;[m] #define l2 2.0 ;[m] #define r1 0.5 ;[m] 錘1の半径 #define r2 0.3 ;[m] 〃2 #const double m1 4.0*m_pi*σ*r1*r1 #const double m2 4.0*m_pi*σ*r2*r2 //#const double η (m1+m2)/m2 ;コンパイルエラー //↓ η = (m1+m2)/m2 θ1 = deg2rad(180) θ2 = deg2rad(135) ω1 = 0.0 ω2 = 0.0 #define mtr2px 100.0 ;[px/meter] メートル→ピクセル 変換係数 wOx = wsizex/2 ;[px] 物理系原点のウィンドウ上でのx座標 wOy = wsizey/2 #const double l1w l1*mtr2px ;[px] l1のウィンドウ上での長さ #const double l2w l2*mtr2px ;[px] #const double r1w r1*mtr2px ;[px] #const double r2w r2*mtr2px ;[px] /* 録画設定 */ #define frmIntvl 32 ;[ms] フレーム間隔 #define len_recTim 30 //[s] "length_recordTime" 録画時間 #const num_wholeFrm 1000/frmIntvl*len_recTim // "number_wholeFrame" 全フレーム数 ds_VRAMBuf = 3*wsizex*wsizey //[byte] "dataSize_VRAMBuffer" VRAMバッファ1枚当たりのデータサイズ ds_wholeFrm = num_wholeFrm*ds_VRAMBuf //[byte] "dataSize_wholeFrame" 全フレームの合計データサイズ #define name_recDataFile "rec.bin" // "name_recordDataFile" 録画データファイル名 *mkwnds screen 0, wsizex,wsizey, 0 sysfont 13 *boot modDetect@record //モジュールの認識をコンパイラへ促す modDetect@play goto *prep@record #module record #deffunc local modDetect //モジュール認識用空命令 return #uselib "winmm.dll" #cfunc timeGetTime "timeGetTime" #define wsizex wsizex@ #define wsizey wsizey@ #define θ1 θ1@ #define θ2 θ2@ #define ω1 ω1@ #define ω2 ω2@ #define dt dt@ #define hdt hdt@ #define wOx wOx@ #define wOy wOy@ #define l1w l1w@ #define l2w l2w@ #define r1w r1w@ #define r2w r2w@ #define frmIntvl frmIntvl@ #define len_recTim len_recTim@ #define num_wholeFrm num_wholeFrm@ #define ds_VRAMBuf ds_VRAMBuf@ #define ds_wholeFrm ds_wholeFrm@ #define name_recDataFile name_recDataFile@ #define mlfreq 2 ;[ms] メインループ周期 *prep //準備 /* 空の録画データファイルの作成 */ gsel 0,0 color : boxf color 255,255,255 : pos 5,5 : mes "録画用のディスク領域("+str(strf("%g",double(ds_wholeFrm)/1024/1024))+"MB)を準備しています。お待ちください..." makeEmptyFile name_recDataFile, ds_wholeFrm //空の録画データファイルの作成 mes "完了。\n\n録画を開始します..." wait 150 sdim VRAMBUF0,1 //未初期化変数警告回避 mref VRAMBuf0,66 //0番ウィンドウのVRAMバッファ *simu etls = 0.0 ;[s] "elapsedTimeFromLastStep" 前回ステップ計算からの経過時間 etlf = 0.0 ;[ms] "elapsedTimeFromLastFrame" 前回画面更新からの経過時間 frmCnt = 0 // "frameCounter" フレームカウンタ etSimu = 0.0 //[s] "elapsedTime_simulation" シミュレーション世界での経過時刻 WinSysTime_prev = timeGetTime() //以前のシステム時刻 repeat WinSysTime = timeGetTime() //現在のシステム時刻 et_thisloop = WinSysTime-WinSysTime_prev //[ms] この1ループに要した時間 WinSysTime_prev = WinSysTime if etls >= dt : gosub *step : etls = -0.001*et_thisloop if etlf >= frmIntvl { //再描画 redraw 0 gosub *draw : frmCnt ++ gosub *saveVRAMBuf //VRAMバッファをファイルに書き込む /* 情報の描画 (VRAM書き出し後でないとビデオに写り込んでしまう)*/ pos 5,5 : mes "recording... "+strf("%4.1f",100.0*frmCnt/num_wholeFrm)+"%\nframe : "+frmCnt+"\ntime : "+strf("%6.3f",etSimu)+" [s]\nfps : "+strf("%5.2f",getFps())+"" redraw 1 etlf = -et_thisloop if frmCnt = num_wholeFrm : break } await mlfreq etSimu += 0.001*et_thisloop etls += 0.001*et_thisloop etlf += et_thisloop loop color : boxf color 255,255,255 : pos 5,5 : mes "録画が完了しました。" wait 100 goto *prep@play *step //dt後の状態を計算 ξn = θ1,θ2,ω1,ω2 : k1 = f1(ξn),f2(ξn),f3(ξn),f4(ξn) ξn2 = ξn+hdt*k1, ξn(1)+hdt*k1(1), ξn(2)+hdt*k1(2), ξn(3)+hdt*k1(3) : k2 = f1(ξn2),f2(ξn2),f3(ξn2),f4(ξn2) ξn3 = ξn+hdt*k2, ξn(1)+hdt*k2(1), ξn(2)+hdt*k2(2), ξn(3)+hdt*k2(3) : k3 = f1(ξn3),f2(ξn3),f3(ξn3),f4(ξn3) ξn4 = ξn+dt*k3, ξn(1)+dt*k3(1), ξn(2)+dt*k3(2), ξn(3)+dt*k3(3) : k4 = f1(ξn4),f2(ξn4),f3(ξn4),f4(ξn4) θ1 += dt/6*(k1+2.0*k2+2.0*k3+k4) θ2 += dt/6*(k1(1)+2.0*k2(1)+2.0*k3(1)+k4(1)) ω1 += dt/6*(k1(2)+2.0*k2(2)+2.0*k3(2)+k4(2)) ω2 += dt/6*(k1(3)+2.0*k2(3)+2.0*k3(3)+k4(3)) return *draw //描画 /* 錘の描画 */ color : boxf color 100,100,100 line -1,wOy, wsizex,wOy : line wOx,-1, wOx,wsizey color 255,255,255 xtmp = wOx+l1w*sin(θ1) : ytmp = wOy+l1w*cos(θ1) line wOx,wOy, xtmp,ytmp : circle xtmp-r1w,ytmp-r1w, xtmp+r1w,ytmp+r1w, 0 xtmp2 = xtmp + l2w*sin(θ2) : ytmp2 = ytmp + l2w*cos(θ2) line xtmp,ytmp,xtmp2,ytmp2 : circle xtmp2-r2w,ytmp2-r2w, xtmp2+r2w,ytmp2+r2w, 0 return *saveVRAMBuf //VRAMバッファのセーブ bsave name_recDataFile, VRAMBuf0, ds_VRAMBuf, ds_VRAMBuf*frmCnt return #global #module RK4 //4次のルンゲクッタ法による計算 #define g g@ #define l1 l1@ #define l2 l2@ #define η η@ #defcfunc f1 array ξ return ξ(2) #defcfunc f2 array ξ return ξ(3) #defcfunc f3 array ξ θ1 = ξ : θ2 = ξ(1) : ω1 = ξ(2) : ω2 = ξ(3) φ = θ1-θ2 : cosφ = cos(φ) return (g*(cosφ*sin(θ2)-η*sin(θ1))-(l1*ω1*ω1*cosφ+l2*ω2*ω2)*sin(φ))/l1/(η-cosφ*cosφ) #defcfunc f4 array ξ θ1 = ξ : θ2 = ξ(1) : ω1 = ξ(2) : ω2 = ξ(3) φ = ξ-ξ(1) : cosφ = cos(φ) return (g*η*(cosφ*sin(θ1)-sin(θ2))+(η*l1*ω1*ω1+l2*ω2*ω2*cosφ)*sin(φ))/l2/(η-cosφ*cosφ) #global #module mod_makeEmptyFile //空ファイルの作成 #deffunc makeEmptyFile str name, int size #const bs 1024*1024*5 //一度に書き込むバイト数 count = size/bs //bs単位での書き込み回数 sdim buf,bs //bsサイズの主記憶領域を確保 bsave name, buf,1 //とりあえず1バイトのファイルを作成 repeat count : bsave name, buf, bs, bs*cnt : await 10 : loop //ステップ書き込み bsave name, buf, size-bs*count,bs*count //半端物の書き込み return #global #module play //録画データから読み込んで再生 #deffunc local modDetect return #uselib "winmm.dll" #cfunc timeGetTime "timeGetTime" #define frmIntvl frmIntvl@ #define len_recTim len_recTim@ #define num_wholeFrm num_wholeFrm@ #define ds_VRAMBuf ds_VRAMBuf@ #define ds_wholeFrm ds_wholeFrm@ #define name_recDataFile name_recDataFile@ #define mlfreq 2 ;[ms] メインループ周期 *prep gsel 0,0 color : boxf color 255,255,255 : pos 5,5 : mes "\n\n録画データを再生します。" wait 150 sdim VRAMBUF0,1 //未初期化変数警告回避 mref VRAMBuf0,66 //0番ウィンドウのVRAMバッファ *main etlf = 0.0 ;[ms] "elapsedTimeFromLastFrame" 前回画面更新からの経過時間 frmCnt = 0 // "frameCounter" フレームカウンタ WinSysTime_prev = timeGetTime() //以前のシステム時刻 repeat WinSysTime = timeGetTime() //現在のシステム時刻 et_thisloop = WinSysTime-WinSysTime_prev //[ms] この1ループに要した時間 WinSysTime_prev = WinSysTime if etlf >= frmIntvl { gosub *draw : frmCnt ++ etlf = -et_thisloop if frmCnt = num_wholeFrm : break } await mlfreq etlf += et_thisloop loop color : boxf color 255,255,255 : pos 5,5 : mes "再生が終了しました。" stop *draw redraw 0 /* VRAM紙芝居 */ bload name_recDataFile, VRAMBuf0, ds_VRAMBuf, ds_VRAMBuf*frmCnt /* 情報 */ pos 5,5 : mes "playing... "+strf("%4.1f",100.0*frmCnt/num_wholeFrm)+"%\nframe : "+frmCnt+"\nfps : "+strf("%5.2f",getFps())+"" redraw 1 return #global #module mod_getFps #uselib "winmm.dll" #cfunc timeGetTime "timeGetTime" t = -1 #defcfunc getFps t_prev = t t = timeGetTime() return 1000.0/(t-t_prev) #global



スペース

リンク

2015/9/4(Fri) 19:48:37|NO.71317

>>motchyさん
おお!これは凄いですね。
やはりHSPで録画ソフトはきつそうですね。
諦めます・・・皆様、何度も何度も返信して頂き有難うございます。
このスレッドは解決とさせていただきます。



Mituki

リンク

2015/9/4(Fri) 20:48:19|NO.71320


#uselib "Dwmapi" #define DWM_EC_DISABLECOMPOSITION 0 #define DWM_EC_ENABLECOMPOSITION 1 #func DwmEnableComposition "DwmEnableComposition" int #include "d3m.hsp" #uselib "gdi32.dll" #cfunc CreateDC "CreateDCA" sptr,sptr,sptr,int #func DeleteDC "DeleteDC" int #func BitBlt "BitBlt" int,int,int,int,int,int,int,int,int #define NULL 0 #define SRCCOPY 0x00CC0020 #define CAPTUREBLT 0x40000000 総フレーム数=100//100以下推奨 倍率=double(1)//倍率 ssx = double(ginfo_dispx) : ssy = double(ginfo_dispy)//元サイズ sx = double(ginfo_dispx)*倍率 : sy = double(ginfo_dispy)*倍率//縮小後のサイズ buffer 2, ssx, ssy//キャプチャ用バッファ hdc_2=hdc pos sx,0:gmode 0,sx,sy,256 buffer 3,sx,sy//縮小 hdc_3 = hdc mref VRAM,66 bsave "テスト.txt",VRAM,-1,-1//ファイルがない状態でオフセットを指定するとエラーになるので //*スラッシュ1つでコメントアウト repeat 総フレーム数//N枚分確保 bsave "テスト.txt",VRAM,sx*sy*3,cnt*(sx*sy*3) loop//*/ Screen 0,sx,sy:onexit goto*終了 hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL)//デスクトップのhdc取得 DwmEnableComposition DWM_EC_DISABLECOMPOSITION//Aero無効 repeat 総フレーム数 BitBlt hdc_2, 0, 0, ssx, ssy, hdcScreen, 0, 0, SRCCOPY | CAPTUREBLT//キャプチャ gsel 3//縮小 pos 0,0:gzoom sx,sy,2,0,0,ssx,ssy,1 bsave "テスト.txt",VRAM,sx*sy*3,cnt*(sx*sy*3) gsel 0 fps = d3getfps() if fps=0:fps+1 title ""+fps+"fps "+(1000.0/double(fps))+"ms" gcopy 3,0,0,sx,sy await (33+(cnt\3=0))//30fps維持 loop Dialog "総フレーム数に達したため終了します" *終了 DeleteDC hdcScreen DwmEnableComposition DWM_EC_ENABLECOMPOSITION//Aero有効 end
これ起動すると、なんかPCがやばいことになる・・・
[低スペックなのでそれが原因かもしれません。]



Mituki

リンク

2015/9/4(Fri) 20:49:06|NO.71321

>>motchyさん
>> おお!これは凄いですね。
>> やはりHSPで録画ソフトはきつそうですね。
>> 諦めます・・・皆様、何度も何度も返信して頂き有難うございます。
>> このスレッドは解決とさせていただきます。
解決されてませんよ?



b

リンク

2015/9/4(Fri) 20:55:50|NO.71322

Mitukiさん

>>これ起動すると、なんかPCがやばいことになる・・・
>>[低スペックなのでそれが原因かもしれません。]
やばいこととはどういう意味か分かりませんが、
ウインドウがずららららっと出てきたりした場合は合わせ鏡と同じです。
わかりやすく見たい場合 ginfoをウインドウにすればそれに合わせてzoomされます

>>解決されてませんよ?
スペースさんですよ投稿者



スペース

リンク

2015/9/5(Sat) 00:17:16|NO.71337

あれ、解決ボタンにチェック入れたと思ってたのですが。



Noa

リンク

2015/9/5(Sat) 00:37:16|NO.71338

素人のタワゴトとして見てほしいのですが

1.
録画する部分の実行ファイルと録画した内容を記録する部分の実行ファイル(非表示)に分けて実行する

2.録画したフレームを保存するメモリを2こほど確保しておく

3.
何フレームか保存する

4.
あるていど録画したらそのデータを記録する方にsendmsgでポインタを渡すかなにかをして別のに録画する

5.
記録し終わればそのデータは解放し新たに確保したメモリのポインタを渡す

6.そのメモリを使い2.にもどる

これを録画が終わるまで繰り返す

ようするにマルチタスク的なことをする

こういうことをすればなんとかなるかと思いましたが、そもそも保存するのにかかる時間としばらく録画する時間をどう同期させるのか、そもそもディスクへの書き込みの速度が問題なので解決策になっていないのではないか、
とうとう思い書いて確かめようにもわたしには難しすぎてどうにもならず投稿しませんでしたが、あきらめるとのことなので投稿します。
たぶん役に立たないとはおもいますが。



スペース

リンク

2015/9/5(Sat) 00:46:14|NO.71339

>>Noaさん
録画(ディスクに保存)とキャプチャを分ける、というのは自分も考えました。
ただどうやって他のプロセスに渡せばいいかわからず・・・
http://chokuto.ifdef.jp/advanced/sharedmem.html
こちらの共有メモリで出来るだろう、と最初は安易に考えていたのですが、
そもそもVRAMを簡単に共有出来ないことが判明。
bsaveで保存もできる、peekで読み出しも出来る、なのに何故・・・
結局どう扱えばいいのかわからず諦めました。
「peekで読み込み→独自形式に変換」は速度的に絶望的だったのでやっていません。

もう解決したスレなので独言程度に聞いて欲しいのですが、
もしVRAMを他のプロセス(HSP製)と共有する方法を知っている方がいましたら、
教えていただけると嬉しいです。

ディスクの書き込み速度的に無理、というのは恐らくそんなことはない気がします。
複数のプロセスから書き込んだら行けるんじゃないかな・・・(希望的観測)



Noa

リンク

2015/9/5(Sat) 00:50:30|NO.71340

ディスクに記録するのに30枚分で1秒以上であればVRAMを直接かきこむのであれば30フレームをまとめて書き込めば1秒以下で書き込めるかなと思ったためそれなら1秒間録画し終わるのに間に合うかと思い投稿しました。
いちおう同じようなことをもうしていないのか確認しましたが、そもそもスクリプトの内容がわたしにはちんぷんかんぷんなので
もう既に試されているのであればすみません。



Noa

リンク

2015/9/5(Sat) 00:54:01|NO.71341

書きこんでいる間に回答してくれてすみません。sendmsgでひょいとポインタをわたせばいいかなと思っただけです。似たようなことをもうすでに試されていたのですか。すみません。



Noa

リンク

2015/9/5(Sat) 01:05:16|NO.71342

そもそもプロセス同士が勝手にポインタのやり取りでメモリを共有することができないことを初めて知りました。とんちんかんなことを投稿してすみません。
VRAMをそのまま共有できないのであればもし仮にmemcpyでコピーしてそれをまとめれば共有できるということもないのでしょうか。たぶんそれもできないということだとは思いますが。
むちゃくちゃなことを書いていたらすみません。



スペース

リンク

2015/9/5(Sat) 01:24:18|NO.71343

メモリのコピーなんて出来ないだろうなーと思いつつ検索したらmemcpyを発見。
でもNoaさんも同じ事書いてたんですね。コード書くのに夢中で掲示版を確認していませんでした・・・
取り敢えず今からもう1度、色々試してみます。本当にありがとうございました。

#include "kernel32.as" #define FILE_MAP_WRITE 2 #define FILE_MAP_READ 4 #define PAGE_READWRITE 4 #define ERROR_ALREADY_EXISTS 183 sx=200 sy=200 screen 0, sx,sy textsize = sx*sy*3 sdim textbuf, textsize onexit *OnAppExit ; 終了時にジャンプ ; ファイルマッピングオブジェクトの作成 name = "HSP_mem_Test" ; ファイルマッピングオブジェクトの名前 CreateFileMapping -1, 0, PAGE_READWRITE, 0, textsize, varptr(name) hmapobj = stat if hmapobj == 0 { dialog "共有メモリを作成できませんでした",1,"エラー" end } ; オブジェクトが作成されていたかどうかの判別 GetLastError ; GetLastError関数によるエラーコード取得 if (stat == ERROR_ALREADY_EXISTS) { ; すでに同じ名前のオブジェクトが存在する場合. ; 現在の共有メモリの内容を読み込んでおく. gosub *ReadSharedMem SC=1//1ならクライアント(受け取る側)、0ならサーバー側(書き込む側) } mref VRAM,66 if SC=1{ title "クライアント" repeat gosub*ReadSharedMem memcpy VRAM,textbuf,(sx*sy*3),0,0//メモリブロックのコピー redraw 1 await 1 loop }else{ title "サーバー" Color 100,200,50 repeat pos mousex,mousey:mes "●" memcpy textbuf,VRAM,(sx*sy*3),0,0 gosub*WritedSharedMem await 1 loop } *WritedSharedMem ; ==== サブルーチン:共有メモリに書き込み ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_WRITE, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域に文字列をコピー sharedbuf = textbuf ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 return *ReadSharedMem ; ==== サブルーチン:共有メモリから読み取り ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_READ, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域に文字列をコピー textbuf = sharedbuf ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 return *OnAppExit ; 終了処理(マッピングオブジェクトのハンドルのクローズ) if hmapobj { CloseHandle hmapobj } end



Noa

リンク

2015/9/5(Sat) 01:35:06|NO.71344

私もmemcpyで解決できないか試そうと同じようなものをつくろうと思っていました。こんなに早く書けるなんてすごいです。もしわたしなら1日たってもできあがっていないかもしれません。



Noa

リンク

2015/9/5(Sat) 01:58:35|NO.71345

もしHSPで録画ソフトがつくれれば革新的だとおもいます。ぜひ完成させてください。覚えていたら心の中で応援します。
ところでカハマルカの瞳を今何か参考にならないかとダウンロードして試していますがカハマルカの瞳も保存と録画を分けて処理しているようです。
(タスクマネージャーで見ましたらojos.exeが録画後のエンコードおよび画像ファイルの保存担当、esmeralda.exeがキャプチャ処理担当のようです。たぶんですが。)
録画と保存の処理を別別に分けるのはふと思い浮かんだことなので同じことをしていることに驚きました。
このことからおそらくこの方法でできると思います。
無責任ですみません。



Noa

リンク

2015/9/5(Sat) 02:07:31|NO.71346

わたしは通信系でIPv6のドメインの名前解決をgetaddinfoでどうするのか悩んでいるところです。(IPv4は実装済みでIPv6はIPアドレスを直接打ちこむのには対応済み)
ただわたしの場合はスペースさんのと違い完成しても役に立つかは疑問ですが。



スペース

リンク

2015/9/5(Sat) 03:18:51|NO.71347

共有メモリでVRAMを共有しているのですが、45行目のBitBltを使うと上手く共有出来ません。
ほぼすべて真っ黒=正常に共有できていない感じです。
画面下の数pxに少しだけ表示されているので、共有メモリがズレて取得されているんですかね。
もし解決策を知っている方が居ましたら、教えていただけないでしょうか?

(1回目の実行でサーバー側、2回目の実行でクライアント側になります。)

; デスクトップ画面のサイズでバッファ画面を作成 sx = double(ginfo_dispx)/2.0 : sy = double(ginfo_dispy)/2.0 textsize = int(sx*sy*3) sdim textbuf, textsize //共有メモリとかBitBltとか色々準備。 #include "kernel32.as" #define FILE_MAP_WRITE 2 #define FILE_MAP_READ 4 #define PAGE_READWRITE 4 #define ERROR_ALREADY_EXISTS 183 #uselib "gdi32.dll" #cfunc CreateDC "CreateDCA" sptr,sptr,sptr,int #func DeleteDC "DeleteDC" int #func BitBlt "BitBlt" int,int,int,int,int,int,int,int,int #define NULL 0 #define SRCCOPY 0x00CC0020 #define CAPTUREBLT 0x40000000 ; ファイルマッピングオブジェクトの作成 name = "HSP_mem_Test" ; ファイルマッピングオブジェクトの名前 CreateFileMapping -1, 0, PAGE_READWRITE, 0, textsize, varptr(name) hmapobj = stat GetLastError ; GetLastError関数によるエラーコード取得 if (stat == ERROR_ALREADY_EXISTS):SC=1//共有メモリが既にあるかどうかで判定。1ならクライアント(受け取る側)、0ならサーバー側(書き込む側) screen 0, sx,sy:hdc_0 = hdc onexit *OnAppExit ; 終了時にジャンプ mref VRAM,66 if SC=1{ title "クライアント" repeat gosub*ReadSharedMem memcpy VRAM,textbuf,(sx*sy*3),0,0//メモリブロックのコピー redraw 1 await 1 loop }else{ title "サーバー" Color 100,200,50 hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL) repeat BitBlt hdc_0,0, 0, sx, sy, hdcScreen, 0, 0, SRCCOPY | CAPTUREBLT//なぜかBitBltを使うとクライアント側に上手く描画されない。 pos mousex,mousey:mes "●" redraw 1 memcpy textbuf,VRAM,(sx*sy*3),0,0 gosub*WritedSharedMem await 1 loop } *WritedSharedMem ; ==== サブルーチン:共有メモリに書き込み ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_WRITE, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域に文字列をコピー sharedbuf = textbuf ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 return *ReadSharedMem ; ==== サブルーチン:共有メモリから読み取り ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_READ, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域に文字列をコピー textbuf = sharedbuf ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 return *OnAppExit ; 終了処理(マッピングオブジェクトのハンドルのクローズ) if hmapobj { CloseHandle hmapobj } DeleteDC hdcScreen end



スペース

リンク

2015/9/5(Sat) 11:49:40|NO.71355

今日試した所完全ではないのですが、殆ど表示できる・・・
やっぱりメモリ関係なのかな・・・
https://gyazo.com/81e84ae7876ddbb4c1a0b59b18709fd3



Noa

リンク

2015/9/5(Sat) 11:53:51|NO.71356

わたしのパソコンでは真っ黒です。
redrawの位置を変えてみる、gcopyで別のウィンドウに写してからそれを共有するなどをしましたがだめでした。



Noa

リンク

2015/9/5(Sat) 13:26:02|NO.71362

もしかして画面が正常に表示されないだけで内部的には共有できているのかもと思いbsaveでデスクトップに保存して止まるようにとりあえず書き換えてみましたがそもそもデータがBitBltを使うと共有できないようです。(bsaveで保存したVRAMの中身がBitBltを使った場合はそれぞれ異なっている)


#include "kernel32.as" #define FILE_MAP_WRITE 2 #define FILE_MAP_READ 4 #define PAGE_READWRITE 4 #define ERROR_ALREADY_EXISTS 183 #uselib "gdi32.dll" #cfunc CreateDC "CreateDCA" sptr,sptr,sptr,int #func DeleteDC "DeleteDC" int #func BitBlt "BitBlt" int,int,int,int,int,int,int,int,int #define NULL 0 #define SRCCOPY 0x00CC0020 #define CAPTUREBLT 0x40000000 sx=200 sy=200 screen 0, sx,sy textsize = sx*sy*3 sdim textbuf, textsize screen 0,sx,sy hdc_0 = hdc onexit *OnAppExit ; 終了時にジャンプ ; ファイルマッピングオブジェクトの作成 name = "HSP_mem_Test" ; ファイルマッピングオブジェクトの名前 CreateFileMapping -1, 0, PAGE_READWRITE, 0, textsize, varptr(name) hmapobj = stat if hmapobj == 0 { dialog "共有メモリを作成できませんでした",1,"エラー" end } ; オブジェクトが作成されていたかどうかの判別 GetLastError ; GetLastError関数によるエラーコード取得 if (stat == ERROR_ALREADY_EXISTS) { ; すでに同じ名前のオブジェクトが存在する場合. ; 現在の共有メモリの内容を読み込んでおく. gosub *ReadSharedMem SC=1//1ならクライアント(受け取る側)、0ならサーバー側(書き込む側) } screen 1,sx,sy //color 255,255,255 mref VRAM,66 gsel 0 if SC=1{ title "クライアント" //repeat gosub*ReadSharedMem gsel 1 redraw 0 //boxf//:stop memcpy VRAM,textbuf,(sx*sy*3),0,0//メモリブロックのコピー redraw 1 gsel 0 gcopy 1,,,sx,sy bsave dir_desktop+"\\みそ後",textbuf,sx*sy*3:stop // await 1 //loop }else{ title "サーバー" Color 100,200,50 hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL) //repeat BitBlt hdc_0,0, 0, sx, sy, hdcScreen, 0, 0, SRCCOPY | CAPTUREBLT:redraw 1 //pos mousex,mousey:mes "●" gsel 1 gcopy ,,,sx,sy memcpy textbuf,VRAM,(sx*sy*3),0,0 gsel 0 gosub*WritedSharedMem bsave dir_desktop+"\\みそ",textbuf,sx*sy*3:stop // await 1 //loop } *WritedSharedMem ; ==== サブルーチン:共有メモリに書き込み ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_WRITE, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域に文字列をコピー sharedbuf = textbuf ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 return *ReadSharedMem ; ==== サブルーチン:共有メモリから読み取り ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_READ, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域に文字列をコピー textbuf = sharedbuf ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 return *OnAppExit ; 終了処理(マッピングオブジェクトのハンドルのクローズ) if hmapobj { CloseHandle hmapobj } end



スペース

リンク

2015/9/5(Sat) 13:53:02|NO.71363

>>Noaさん
有難うございます。
やはりBitBltと共有メモリの間で何か不具合が起きてるんですね。
どっちにしろ自分にはお手上げ・・・



Noa

リンク

2015/9/5(Sat) 13:58:05|NO.71365

もうどうすればいいのかわかりません。



Noa

リンク

2015/9/5(Sat) 14:08:25|NO.71366

後は

録画と保存をするプロセス(ようするに最初にスペースさんが出した案)を複数起動しそれをある程度撮影したら保存をかわりばんこにする

保存プロセスを複数起動しておいてそれぞれBitBltでデスクトップをキャプチャしているウィンドウの中身をキャプチャして保存するのをかわりばんこにする(ようするにデスクトップの撮影と保存の間に別の実行ファイルを挟む)

このくらいしかおもいつきません



Noa

リンク

2015/9/5(Sat) 14:11:29|NO.71367

なぜBitBltを使うと共有できないのでしょうか。ナゾです。



Noa

リンク

2015/9/5(Sat) 14:16:02|NO.71368

1.
デスクトップを撮影する

2.
ある程度たまったらほかのひまなプロセスに交代して自分は保存をがんばる

これをいくつかのプロセスの間でくりかえすということを書きました。
分かりにくければすみません。



Noa

リンク

2015/9/5(Sat) 14:23:39|NO.71369

この場合は
どうひまなプロセスを見分けるのか(順番に処理するようにすればこれはだいじょうぶそう)
どこまで保存したのか(ファイルのオフセットなど)をどう相手に伝えるのか(sendmsgでだいじょうぶそう)
が問題だとおもいます。



暇人

リンク

2015/9/5(Sat) 14:50:12|NO.71370

ん?
>; 共有メモリ領域に文字列をコピー
>sharedbuf = textbuf
これじゃ真っ黒の部分があればそこでコピー終らない?
後、無駄にメモリコピーしてるしてる気がする

; デスクトップ画面のサイズでバッファ画面を作成 sx = double(ginfo_dispx)/2.0 : sy = double(ginfo_dispy)/2.0 textsize = int(sx*sy*3) sdim textbuf, textsize //共有メモリとかBitBltとか色々準備。 #include "kernel32.as" #define FILE_MAP_WRITE 2 #define FILE_MAP_READ 4 #define PAGE_READWRITE 4 #define ERROR_ALREADY_EXISTS 183 #uselib "gdi32.dll" #cfunc CreateDC "CreateDCA" sptr,sptr,sptr,int #func DeleteDC "DeleteDC" int #func BitBlt "BitBlt" int,int,int,int,int,int,int,int,int #define NULL 0 #define SRCCOPY 0x00CC0020 #define CAPTUREBLT 0x40000000 ; ファイルマッピングオブジェクトの作成 name = "HSP_mem_Test" ; ファイルマッピングオブジェクトの名前 CreateFileMapping -1, 0, PAGE_READWRITE, 0, textsize, varptr(name) hmapobj = stat GetLastError ; GetLastError関数によるエラーコード取得 if (stat == ERROR_ALREADY_EXISTS):SC=1//共有メモリが既にあるかどうかで判定。1ならクライアント(受け取る側)、0ならサーバー側(書き込む側) ; ファイルマッピングオブジェクトの作成 name_cnt = "HSP_mem_Test_cnt" ; ファイルマッピングオブジェクトの名前 CreateFileMapping -1, 0, PAGE_READWRITE, 0, 4, varptr(name_cnt) //送信データカウント用 hmapobj_cnt = stat if SC=0 { MapViewOfFile hmapobj_cnt, FILE_MAP_WRITE, 0, 0, 0 lpdata_cnt = stat ; 先頭アドレス dupptr write_cnt_dup, lpdata_cnt, 4, 4 write_cnt_dup=0 }else{ MapViewOfFile hmapobj_cnt, FILE_MAP_READ, 0, 0, 0 lpdata_cnt = stat ; 先頭アドレス dupptr write_cnt_dup, lpdata_cnt, 4, 4 } screen 0, sx,sy:hdc_0 = hdc onexit *OnAppExit ; 終了時にジャンプ mref VRAM,66 if SC=1{ title "クライアント" read_cnt=write_cnt_dup //送受信データカウント同期 repeat gosub*ReadSharedMem if stat=0 {redraw 1} await 10 loop }else{ title "サーバー" Color 100,200,50 hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL) repeat BitBlt hdc_0,0, 0, sx, sy, hdcScreen, 0, 0, SRCCOPY | CAPTUREBLT//なぜかBitBltを使うとクライアント側に上手く描画されない。 pos mousex,mousey:mes "●" redraw 1 gosub*WritedSharedMem read_f=stat await 16 loop } *WritedSharedMem ; ==== サブルーチン:共有メモリに書き込み ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_WRITE, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域にコピー memcpy sharedbuf,VRAM,(sx*sy*3),0,0//メモリブロックのコピー ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 write_cnt_dup++ return 0 *ReadSharedMem if write_cnt_dup<read_cnt {return 1}//まだサーバーがデータを用意できていない ; ==== サブルーチン:共有メモリから読み取り ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_READ, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域にコピー memcpy VRAM,sharedbuf,(sx*sy*3),0,0//メモリブロックのコピー ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 read_cnt=write_cnt_dup return 0 *OnAppExit ; 終了処理(マッピングオブジェクトのハンドルのクローズ) if hmapobj { CloseHandle hmapobj UnmapViewOfFile lpdata_cnt CloseHandle hmapobj_cnt } DeleteDC hdcScreen end



Noa

リンク

2015/9/5(Sat) 14:57:28|NO.71371

ああ確かにそこでもmemcpyを使うべきでした。すみません。



Noa

リンク

2015/9/5(Sat) 15:00:31|NO.71372


sharedbuf = textbuf textbuf = sharedbuf
確かにこうするのは0までしかコピーされませんでした。
いつも0までしか代入されないのがいやなのでmemcpyを使っていましたが完全に見落としていました。
すみません。スペースさんめちゃくちゃなことを伝えて混乱させてしまいすみません。



Noa

リンク

2015/9/5(Sat) 15:02:59|NO.71373

バイナリを扱うときにはいつもmemcpy、peek、pokeなどで操作していましたがこれは完全に見落としていました。



スペース

リンク

2015/9/5(Sat) 15:08:44|NO.71374

>>暇人さん
本当に有難うございます。
まさかそんな簡単なことだったとはw
無駄にメモリコピーしてるという点ですが、ご指摘ありがとうございます。



Noa

リンク

2015/9/5(Sat) 15:08:49|NO.71375

灯台下暗しはこのことだと思います。全く別の原因だけを考えていてとても初歩的なミスを見逃していました。暇人さんありがとうございます。
やはりどうしても分からないときは他人に見てもらうのが大事だとおもいました。



スペース

リンク

2015/9/5(Sat) 15:13:54|NO.71376

>>Noaさん
>>スペースさんめちゃくちゃなことを伝えて混乱させてしまいすみません。
いえいえ、一緒に原因を探していただいて感謝しています。

まさに灯台下暗しですね。
バグの原因究明に必要なことは「決めつけない事」だといつも思っているのですが、
やっぱり慣れてくると無意識に決めつけてしまうもんなんですね・・・



Noa

リンク

2015/9/5(Sat) 15:34:46|NO.71377

そういえば今つくっている通信系のソフトでもバグがありまして、その時はしばらくプログラミングをやめてそれからなんとなく見たら見つかったということがありました。
バグを探す際はプログラミングとは別のことをすればみつかります。
探し物でも探しているときはみつからないのに後でふとみつけることがあります。
どうも探しているときはスペースさんのいうように視界が狭くなって逆にみつからなくなってしまうようです。



暇人

リンク

2015/9/5(Sat) 19:30:11|NO.71384

>if write_cnt_dup<read_cnt {return 1}//まだサーバーがデータを用意できていない
これは write_cnt_dup<=read_cnt じゃないと意味なかった・・・

最初に複数起動してから
サーバーボタンを押すと他のをクライアントとして開始するようにしたやつ

#include "user32.as" #define WM_APP 0x8000 #const MYWM_RECEIVE (WM_APP + $123) //共有メモリとかBitBltとか色々準備。 #include "kernel32.as" #define FILE_MAP_WRITE 2 #define FILE_MAP_READ 4 #define PAGE_READWRITE 4 #define ERROR_ALREADY_EXISTS 183 #uselib "gdi32.dll" #cfunc CreateDC "CreateDCA" sptr,sptr,sptr,int #func DeleteDC "DeleteDC" int #func BitBlt "BitBlt" int,int,int,int,int,int,int,int,int #define NULL 0 #define SRCCOPY 0x00CC0020 #define CAPTUREBLT 0x40000000 oncmd gosub *OnReceive, MYWM_RECEIVE RegisterWindowMessage "HSP_Broadcast_Test" if stat=0 {dialog "ウィンドウメッセージを定義できませんでした":end} msgcode = stat oncmd gosub *OnReceiveBroadcast, msgcode button gosub "サーバー", *Send //送受信両方で使用(メンループ) repeat await 1000 if stat=1 {break}//Broadcast成功 loop ; デスクトップ画面のサイズでバッファ画面を作成 sx = double(ginfo_dispx)/2.0 : sy = double(ginfo_dispy)/2.0 textsize = int(sx*sy*3) sdim textbuf, textsize ; ファイルマッピングオブジェクトの作成 name = "HSP_mem_Test" ; ファイルマッピングオブジェクトの名前 CreateFileMapping -1, 0, PAGE_READWRITE, 0, textsize, varptr(name) hmapobj = stat if SC=0 { screen 0, sx,sy,0,sx-4,0 :hdc_0 = hdc listbox_v=-1 objsize 86,20 listbox listbox_v,20+tcnt*10,hTlist }else{ screen 0, sx/4,sy/4,0,sx+((cid\4)*(sx/4+8)),sy+24+(cid/4)*(sy/4+12) //表示用 buffer 1, sx,sy //受け取り用 hdc_0 = hdc } onexit *OnAppExit ; 終了時にジャンプ mref VRAM,66 write_cnt=0 read_cnt=0 gsel 0,2 if SC=1{//クライアント側 repeat await 1000 if end_f {break}//サーバーが閉じられた gosub *ReadSharedMem if stat=0 {gzoom ginfo_sx,ginfo_sy,1,0,0,sx,sy,1} loop }else{//サーバー側 Color 100,200,50 hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL) repeat BitBlt hdc_0,0, 0, sx, sy, hdcScreen, 0, 0, SRCCOPY | CAPTUREBLT pos mousex,mousey:mes "●" redraw 1 gosub *WritedSharedMem await 16 if end_f {break}//クライアントが閉じられた loop } goto *OnAppExit *WritedSharedMem ; ==== サブルーチン:共有メモリに書き込み ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_WRITE, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域にコピー memcpy sharedbuf,VRAM,(sx*sy*3),0,0//メモリブロックのコピー ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 write_cnt++ hTindx=write_cnt\tcnt //複数のクライアントがあるならwrite_cnt毎に順番に振り分けて転送 sendmsg hTarget(hTindx), MYWM_RECEIVE, 3, write_cnt if stat=0 {end_f=1}//送信失敗(クライアントが閉じられた可能性有り) */ return *ReadSharedMem if write_cnt<=read_cnt {return 1}//まだサーバーがデータを用意できていない ; ==== サブルーチン:共有メモリから読み取り ==== ; ビューのマッピング MapViewOfFile hmapobj, FILE_MAP_READ, 0, 0, 0 lpdata = stat ; 先頭アドレス ; 共有メモリ領域を変数に割り当てる(文字列型) dupptr sharedbuf, lpdata, textsize, 2 ; 共有メモリ領域にコピー memcpy VRAM,sharedbuf,(sx*sy*3),0,0//メモリブロックのコピー ; ビューのマッピング解除 ; (この後で変数 sharedbuf にアクセスするとエラーになります) UnmapViewOfFile lpdata ; (上記エラーの回避のため変数 sharedbuf の再確保) dim sharedbuf, 1 read_cnt=write_cnt return 0 *OnAppExit ; 終了処理(マッピングオブジェクトのハンドルのクローズ) if hmapobj { CloseHandle hmapobj } DeleteDC hdcScreen if SC=0 {//サーバーが閉じられたのでクライアントに終了メッセージ送信 repeat tcnt sendmsg hTarget(cnt), MYWM_RECEIVE, -1, 0 loop } end //送信側 *Send cls 4:color 255 ; ブロードキャスト送信 mes "ブロードキャストメッセージを送信" sendmsg 0xFFFF, msgcode, 0, hwnd mes "ブロードキャストメッセージを送信終了" if tcnt=0 {dialog "クライアントがありません":end} title "サーバー : hwnd="+hwnd+" クライアント数"+tcnt hTlist="" repeat tcnt hTlist+=str(hTarget(cnt))+"\n" loop SC=0 //サーバーフラグセット return 1 //送受信(受信ウィンドウハンドル取得し受信側にクライアントIDを送る) *OnReceive if wParam>0 { if wParam=3 {write_cnt=lParam:return 1}//共有データが更新された if wParam=1 {//クライトからウィンドウハンドルが送られた hTarget(tcnt) = lParam //受信側ウィンドウハンドル sendmsg lParam, MYWM_RECEIVE, 2, tcnt //クライアントID送信 tcnt++ } if wParam=2 {cid=lParam} //クライアントIDセット }else{ end_f=1 } return 1 //受信側 *OnReceiveBroadcast if SC or tcnt {//サーバーが決定してから起動したウィンドウは無視 if SC=0 {sendmsg lParam, MYWM_RECEIVE, -1, 0}//複数ウィンドウがあるならは後から起動したサーバーに終了を送信 return } if hwnd = lParam {return}//自分からのメッセージなら無視 hTarget = lParam sendmsg hTarget, MYWM_RECEIVE, 1, hwnd title "クライアント : hwnd="+hwnd hTindx=0 SC=1 //クライアントフラグセット return 1



ken2

リンク

2015/9/5(Sat) 21:21:17|NO.71386

詳しく読んでいないので何を録画したいのか分かりませんが、保存speedに問題があるならinoviaさん作の
hspdscを使ったら如何でしょうか?保存はDirectShowに任せてしまうという事です。
的外れだったら無視して下さい。



スペース

リンク

2015/9/5(Sat) 22:44:13|NO.71387

>>ken2さん
なるほど、そういうやり方もあるんですね。
参考にさせていただきます。



Noa

リンク

2015/9/5(Sat) 22:53:31|NO.71388

DirectX9はいくらなんでも要求する環境が高すぎる気がします。(少なくとも家の7のパソコンはだめです)
試していないので分かりませんが、また画像をディスクへ保存する速さが問題なのであまり変わらない気がします。



Noa

リンク

2015/9/5(Sat) 23:52:02|NO.71393

マウスがないと物足りないので出してみました。
投稿されているのは使わずC言語のを見てかいたので変かもしれません。

#uselib "gdi32.dll" #cfunc CreateDC "CreateDCA" str,str,int,int #func DeleteDC "DeleteDC" int #func BitBlt "BitBlt" int,int,int,int,int,int,int,int,int #uselib "user32.dll" #func GetCursorInfo "GetCursorInfo" var #func DrawIcon "DrawIcon" int,int,int,int #define SRCCOPY $00CC0020 #define CAPTUREBLT $40000000 #define CURSOR_SHOWING $00000001 #define CURSORINFOSIZE 20 #define CURcbSize 0 //大きさのこと #define CURflags 4 //カーソルがでているか #define CURhCursor 8 //カーソル自体へのハンドル #define CURptScreenPosX 12//カーソルのX座標 #define CURptScreenPosY 16//カーソルのY座標 #define TORUHAYASA 30 mausudasu=1//マウスを出すか 0=出さない 1=出す desktopdc=CreateDC( "display","display",0,0 ) sdim cursorjouhou,CURSORINFOSIZE screen 0,ginfo_dispx,ginfo_dispy,,,,300,300 onexit *owari while BitBlt hdc, 0, 0, ginfo_sx, ginfo_sy, desktopdc, 0, 0, SRCCOPY | CAPTUREBLT if mausudasu{ lpoke cursorjouhou,CURcbSize,CURSORINFOSIZE GetCursorInfo cursorjouhou if lpeek(cursorjouhou,CURflags)==CURSOR_SHOWING{ DrawIcon hdc,ginfo_mx,ginfo_my,lpeek(cursorjouhou,CURhCursor)//マウスを出す } } redraw 1 await 1000/TORUHAYASA wend *owari DeleteDC desktopdc end



Noa

リンク

2015/9/7(Mon) 15:34:47|NO.71439

今さらですがWM_COPYDATAのほうがわかりやすそうです。
http://chokuto.ifdef.jp/advanced/copydata.html



スペース

リンク

2015/9/7(Mon) 16:06:08|NO.71441

皆様有難うございます。参考にさせていただきます。
現在、処理速度の問題をクリアし、一時ファイルの容量を抑える方法を探している所です。
現時点で1分1.3GB程度で、結構実用的な範囲内なので今後も順調に進んでいくと思われます。

皆様、特にNoa様・暇人様・motchy様、本当に有難うございました。
このスレッドは既に解決している為、もし次質問がある場合は新しくスレッドを建てます。

(もちろん、この掲示版に頼らず自力で解決出来るよう善処します)



ONION software Copyright 1997-2023(c) All rights reserved.