|
|
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)を圧縮して変数に保存するにはどうすればいいのでしょうか?
最終的な目的はエンコードや保存をリアルタイムに行うことなので、
もし他に良い方法を知っている方が居ましたら、教えていただけると幸いです。
|
|
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
|
|
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が原因でした・・・お騒がせしました。
|
|
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ではそれ以上ですね。どうしたものか・・・
|
|
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
| |
|
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
| |
|
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 よりは速い」というところまでが成果ですかね。
|
|
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で録画ソフトはきつそうですね。
諦めます・・・皆様、何度も何度も返信して頂き有難うございます。
このスレッドは解決とさせていただきます。
|
|
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がやばいことになる・・・
[低スペックなのでそれが原因かもしれません。]
| |
|
2015/9/4(Fri) 20:49:06|NO.71321
>>motchyさん
>> おお!これは凄いですね。
>> やはりHSPで録画ソフトはきつそうですね。
>> 諦めます・・・皆様、何度も何度も返信して頂き有難うございます。
>> このスレッドは解決とさせていただきます。
解決されてませんよ?
|
|
2015/9/4(Fri) 20:55:50|NO.71322
Mitukiさん
>>これ起動すると、なんかPCがやばいことになる・・・
>>[低スペックなのでそれが原因かもしれません。]
やばいこととはどういう意味か分かりませんが、
ウインドウがずららららっと出てきたりした場合は合わせ鏡と同じです。
わかりやすく見たい場合 ginfoをウインドウにすればそれに合わせてzoomされます
>>解決されてませんよ?
スペースさんですよ投稿者
|
|
2015/9/5(Sat) 00:17:16|NO.71337
あれ、解決ボタンにチェック入れたと思ってたのですが。
|
|
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製)と共有する方法を知っている方がいましたら、
教えていただけると嬉しいです。
ディスクの書き込み速度的に無理、というのは恐らくそんなことはない気がします。
複数のプロセスから書き込んだら行けるんじゃないかな・・・(希望的観測)
|
|
2015/9/5(Sat) 00:50:30|NO.71340
ディスクに記録するのに30枚分で1秒以上であればVRAMを直接かきこむのであれば30フレームをまとめて書き込めば1秒以下で書き込めるかなと思ったためそれなら1秒間録画し終わるのに間に合うかと思い投稿しました。
いちおう同じようなことをもうしていないのか確認しましたが、そもそもスクリプトの内容がわたしにはちんぷんかんぷんなので
もう既に試されているのであればすみません。
|
|
2015/9/5(Sat) 00:54:01|NO.71341
書きこんでいる間に回答してくれてすみません。sendmsgでひょいとポインタをわたせばいいかなと思っただけです。似たようなことをもうすでに試されていたのですか。すみません。
|
|
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
| |
|
2015/9/5(Sat) 01:35:06|NO.71344
私もmemcpyで解決できないか試そうと同じようなものをつくろうと思っていました。こんなに早く書けるなんてすごいです。もしわたしなら1日たってもできあがっていないかもしれません。
|
|
2015/9/5(Sat) 01:58:35|NO.71345
もしHSPで録画ソフトがつくれれば革新的だとおもいます。ぜひ完成させてください。覚えていたら心の中で応援します。
ところでカハマルカの瞳を今何か参考にならないかとダウンロードして試していますがカハマルカの瞳も保存と録画を分けて処理しているようです。
(タスクマネージャーで見ましたらojos.exeが録画後のエンコードおよび画像ファイルの保存担当、esmeralda.exeがキャプチャ処理担当のようです。たぶんですが。)
録画と保存の処理を別別に分けるのはふと思い浮かんだことなので同じことをしていることに驚きました。
このことからおそらくこの方法でできると思います。
無責任ですみません。
|
|
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
|
|
2015/9/5(Sat) 11:53:51|NO.71356
わたしのパソコンでは真っ黒です。
redrawの位置を変えてみる、gcopyで別のウィンドウに写してからそれを共有するなどをしましたがだめでした。
|
|
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と共有メモリの間で何か不具合が起きてるんですね。
どっちにしろ自分にはお手上げ・・・
|
|
2015/9/5(Sat) 13:58:05|NO.71365
もうどうすればいいのかわかりません。
|
|
2015/9/5(Sat) 14:08:25|NO.71366
後は
録画と保存をするプロセス(ようするに最初にスペースさんが出した案)を複数起動しそれをある程度撮影したら保存をかわりばんこにする
保存プロセスを複数起動しておいてそれぞれBitBltでデスクトップをキャプチャしているウィンドウの中身をキャプチャして保存するのをかわりばんこにする(ようするにデスクトップの撮影と保存の間に別の実行ファイルを挟む)
このくらいしかおもいつきません
|
|
2015/9/5(Sat) 14:11:29|NO.71367
なぜBitBltを使うと共有できないのでしょうか。ナゾです。
|
|
2015/9/5(Sat) 14:16:02|NO.71368
1.
デスクトップを撮影する
2.
ある程度たまったらほかのひまなプロセスに交代して自分は保存をがんばる
これをいくつかのプロセスの間でくりかえすということを書きました。
分かりにくければすみません。
|
|
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
| |
|
2015/9/5(Sat) 14:57:28|NO.71371
ああ確かにそこでもmemcpyを使うべきでした。すみません。
|
|
2015/9/5(Sat) 15:00:31|NO.71372
sharedbuf = textbuf
textbuf = sharedbuf
確かにこうするのは0までしかコピーされませんでした。
いつも0までしか代入されないのがいやなのでmemcpyを使っていましたが完全に見落としていました。
すみません。スペースさんめちゃくちゃなことを伝えて混乱させてしまいすみません。
|
|
2015/9/5(Sat) 15:02:59|NO.71373
バイナリを扱うときにはいつもmemcpy、peek、pokeなどで操作していましたがこれは完全に見落としていました。
|
|
2015/9/5(Sat) 15:08:44|NO.71374
>>暇人さん
本当に有難うございます。
まさかそんな簡単なことだったとはw
無駄にメモリコピーしてるという点ですが、ご指摘ありがとうございます。
|
|
2015/9/5(Sat) 15:08:49|NO.71375
灯台下暗しはこのことだと思います。全く別の原因だけを考えていてとても初歩的なミスを見逃していました。暇人さんありがとうございます。
やはりどうしても分からないときは他人に見てもらうのが大事だとおもいました。
|
|
2015/9/5(Sat) 15:13:54|NO.71376
>>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
| |
|
2015/9/5(Sat) 21:21:17|NO.71386
詳しく読んでいないので何を録画したいのか分かりませんが、保存speedに問題があるならinoviaさん作の
hspdscを使ったら如何でしょうか?保存はDirectShowに任せてしまうという事です。
的外れだったら無視して下さい。
|
|
2015/9/5(Sat) 22:44:13|NO.71387
>>ken2さん
なるほど、そういうやり方もあるんですね。
参考にさせていただきます。
|
|
2015/9/5(Sat) 22:53:31|NO.71388
DirectX9はいくらなんでも要求する環境が高すぎる気がします。(少なくとも家の7のパソコンはだめです)
試していないので分かりませんが、また画像をディスクへ保存する速さが問題なのであまり変わらない気がします。
|
|
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
| |
|
2015/9/7(Mon) 15:34:47|NO.71439
|
|
2015/9/7(Mon) 16:06:08|NO.71441
皆様有難うございます。参考にさせていただきます。
現在、処理速度の問題をクリアし、一時ファイルの容量を抑える方法を探している所です。
現時点で1分1.3GB程度で、結構実用的な範囲内なので今後も順調に進んでいくと思われます。
皆様、特にNoa様・暇人様・motchy様、本当に有難うございました。
このスレッドは既に解決している為、もし次質問がある場合は新しくスレッドを建てます。
(もちろん、この掲示版に頼らず自力で解決出来るよう善処します)
|
|