VP9お試しビルド
うまく行かなかったので下記の方法にて解決
VP9お試しビルド(その2) - fftester06’s blog
refs/heads/master - webm/libvpx - Git at Google
cygwin上で作業
$ ./configure enabling vp8_encoder enabling vp8_decoder enabling vp9_encoder enabling vp9_decoder Configuring for target 'x86-win32-gcc' enabling x86 enabling runtime_cpu_detect enabling mmx enabling sse enabling sse2 enabling sse3 enabling ssse3 enabling sse4_1 enabling avx enabling avx2 enabling avx512 using yasm enabling postproc enabling unit_tests enabling webm_io enabling libyuv Creating makefiles for x86-win32-gcc libs Creating makefiles for x86-win32-gcc examples Creating makefiles for x86-win32-gcc tools Creating makefiles for x86-win32-gcc docs
$ make [CREATE] vpx_scale_rtcd.h [CREATE] vpx_dsp_rtcd.h [CREATE] vp8_rtcd.h [CREATE] vp9_rtcd.h [DEP] test/test_intra_pred_speed.cc.d ・・・・ [AR] libvpx_g.a [STRIP] libvpx.a < libvpx_g.a [CREATE] vpx.pc [CXX] third_party/googletest/src/src/gtest-all.cc.o In file included from /home/ss/libvpx/third_party/googletest/src/include/gtest/i nternal/gtest-internal.h:40:0, from /home/ss/libvpx/third_party/googletest/src/include/gtest/g test.h:59, from third_party/googletest/src/src/gtest-all.cc:38: /home/ss/libvpx/third_party/googletest/src/include/gtest/internal/gtest-port.h: 関数 ‘int testing::internal::posix::FileNo(FILE*)’ 内: /home/ss/libvpx/third_party/googletest/src/include/gtest/internal/gtest-port.h:2 487:51: エラー: ‘fileno’ was not declared in this scope inline int FileNo(FILE* file) { return fileno(file); } ^ /home/ss/libvpx/third_party/googletest/src/include/gtest/internal/gtest-port.h: 関数 ‘char* testing::internal::posix::StrDup(const char*)’ 内: /home/ss/libvpx/third_party/googletest/src/include/gtest/internal/gtest-port.h:2 493:57: エラー: ‘strdup’ was not declared in this scope inline char* StrDup(const char* src) { return strdup(src); } ^ /home/ss/libvpx/third_party/googletest/src/include/gtest/internal/gtest-port.h: 関数 ‘FILE* testing::internal::posix::FDOpen(int, const char*)’ 内: /home/ss/libvpx/third_party/googletest/src/include/gtest/internal/gtest-port.h:2 521:71: エラー: ‘fdopen’ was not declared in this scope inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } ^ In file included from third_party/googletest/src/src/gtest-all.cc:44:0: /home/ss/libvpx/third_party/googletest/src/src/gtest-port.cc: コンストラクタ ‘te sting::internal::CapturedStream::CapturedStream(int)’ 内: /home/ss/libvpx/third_party/googletest/src/src/gtest-port.cc:1034:50: エラー: ‘m kstemp’ was not declared in this scope const int captured_fd = mkstemp(name_template); ^ make[1]: *** [Makefile:168: third_party/googletest/src/src/gtest-all.cc.o] エラ ー 1 make: *** [Makefile:17: .DEFAULT] エラー 2
テストツールでなんかエラーが出てるけど、とりあえずライブラリの生成は成功。
エラーをなくしてビルドを最後まで通してみる。
./configure --disable-tools --disable-unit-tests --disable-docs → [CXX] third_party/libwebm/mkvmuxer/mkvmuxerutil.cc.o third_party/libwebm/mkvmuxer/mkvmuxerutil.cc: 関数 ‘mkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int*)’ 内: third_party/libwebm/mkvmuxer/mkvmuxerutil.cc:640:33: エラー: ‘rand_r’ was not declared in this scope const int32 nn = rand_r(seed); ^ make[1]: *** [Makefile:168: third_party/libwebm/mkvmuxer/mkvmuxerutil.cc.o] エラー 1 make: *** [Makefile:17: .DEFAULT] エラー 2 mkvmuxerutil.cc:640 const int32 nn = rand_r(seed); → const int32 nn = rand(); [CXX] third_party/libwebm/mkvparser/mkvreader.cc.o third_party/libwebm/mkvparser/mkvreader.cc: メンバ関数 ‘virtual int mkvparser::MkvReader::Read(long long int, long int, unsigned char*)’ 内: third_party/libwebm/mkvparser/mkvreader.cc:124:54: エラー: ‘fseeko’ was not declared in this scope fseeko(m_file, static_cast<off_t>(offset), SEEK_SET); ^ make[1]: *** [Makefile:168: third_party/libwebm/mkvparser/mkvreader.cc.o] エラー 1 make: *** [Makefile:17: .DEFAULT] エラー 2
fseekoがないようなのでfseekに書き換え・・・関数の仕様の互換性などは見てません・・・。
まあでもこれでビルドが最後まで通るようになった!
生成されたlibvpx.aをMinGWに持ってきて、simple_encoderをコンパイルしてみる。
C:\Documents and Settings\ss\My Documents\src\imgtrans\VP9\libvpx-refs_heads_mas ter\examples>gcc simple_decoder.c ..\tools_common.c ..\video_writer.c ..\video_r eader.c ..\y4minput.c ..\ivfenc.c ..\ivfdec.c libvpx.a -I.. libvpx.a(vp8_cx_iface.c.o):(.text+0x1af5): undefined reference to `setjmp' libvpx.a(onyx_if.c.o):(.text+0x2fee): undefined reference to `setjmp' libvpx.a(vp8_dx_iface.c.o):(.text+0x522): undefined reference to `setjmp' libvpx.a(vp8_dx_iface.c.o):(.text+0x68b): undefined reference to `setjmp' libvpx.a(vp8_dx_iface.c.o):(.text+0x7bb): undefined reference to `setjmp' libvpx.a(onyxd_if.c.o):(.text+0x7a): more undefined references to `setjmp' follo w libvpx.a(systemdependent.c.o):(.text+0xf): undefined reference to `sysconf' collect2.exe: error: ld returned 1 exit status
cygwinでは不要だったsetjmp.hがMinGWでは必要な模様
→vp8_dx_iface.cに追加
同様にunistd.hが必要
→systemdependent.cに追加
...ここまでくるとMinGW用にbashとmakeがほしいような・・・。
しかもビルドがうまく行かないので、Git bash上に環境構築してみることに。
libjpeg-turbo試用
"libjpeg-turbo"JPEGエンコーダ/デコーダlibjpegの、SIMD指令使用版をWindowsで使ってみる。
libjpeg-turbo | Main / libjpeg-turbo
従来のlibjpegよりも2-6倍速いと言う謳い文句。
Windows用バイナリも提供されていて、実際の速度も割とよさそうだったのでとりあえず試用。
計測例など:
UbuntuでOpenCVをlibjpeg-turboつきでビルドする | さかな前線
libjpeg-turboでjpegの変換が速くなる - かみぽわーる
開発メモ その134 OpenCVにlibjpeg-turboをリンクして性能比較 – A certain engineer "COMPLEX"
libjpeg-turboがいいらしい at softelメモ
比較的当たらしめかと思いきや、2010年のブログにも載っているのでそれなりの歴史もありそう。SIMDに対応のみということで、ガチの人向けにはマルチプロセッサ/マルチコア用最適化などもあるのだろうか・・・・?
超シンプルなCサンプル:
#include <stdio.h> #include "turbojpeg.h" int main() { unsigned char* jpegBuf = NULL, *imgBuf = NULL; FILE* jpegFile; long size, jpegSize; int width, height; int inSubsamp, outSubsamp = -1, inColorspace, pixelFormat = TJPF_UNKNOWN; int numScalingFactors = 0, outQual, flags=0; tjhandle tjInstance = NULL; if ((imgBuf = tjLoadImage("test.bmp", &width, 1, &height, &pixelFormat, 0)) == NULL) printf("loading input image: %s\n", tjGetErrorStr2(tjInstance)); outSubsamp = TJSAMP_444; outQual = 50; if ((tjInstance = tjInitCompress()) == NULL) printf("initializing compressor: %s\n", tjGetErrorStr2(NULL)); if (tjCompress2(tjInstance, imgBuf, width, 0, height, pixelFormat, &jpegBuf, &jpegSize, outSubsamp, outQual, flags) < 0) printf("compressing image: %s\n", tjGetErrorStr2(tjInstance)); tjDestroy(tjInstance); tjInstance = NULL; if ((jpegFile = fopen("turbotest.jpg", "wb")) == NULL) printf("opening output file\n"); if (fwrite(jpegBuf, jpegSize, 1, jpegFile) < 1) printf("writing output file"); fclose(jpegFile); jpegFile = NULL; return 0; }
若干のはまりポイントとしては、APIにポインタを渡して中身を入れてもらう変数については、あらかじめNULLをいれておいてわたさないとSIGSEGVを食らうことがある模様。
まあ当然と言えば当然ですね。
リモートデスクトップアプリ試作版
ができました。
エラーチェックもほぼなし、高速化等の処理もほぼは言ってない、昨日動作確認までですが、いかんせんもっさりした動作・・・。
これから高速化について探っていこうかと思います。
ちなみに、クライアントについてはこちらから拝借して、対応するサーバーソフトを書いたような感じです。ただし、画面全体ではなくウィンドウ単位で転送するようにしたなどの都合で、クライアント側も一部修正しています。
Brynhildr(ブリュンヒルデ) – リモートデスクトップ ( リモートデスクトップエンジニアのブログ。 )
これの、クライアント機能サンプルを使用しました。
いまのとこ生のビットマップをそのまま送っているけど、JPGにしたり、RTSPにのせたりできるのかな・・・?
いろいろチャレンジしてみよう。
VJoy(仮想ジョイパッド)のAPIテスト
XPで動くバージョンでAPIのテスト(v1.2)
Headsoft - VJoy Virtual Joystick Driver - Home
ちなみに最新版はこちら
vJoy download | SourceForge.net
SDKを使用すると、付属のDLLを使用してジョイパッドの入力を生成することが可能。
ただ、implicit(暗黙的)なDLL読み込みがうまくいかなかった。
念のためstatic libraryの生成も行う。VJoy.cpp, Vjoy32.dll, VJoy.h, StdAfx.hを同一ディレクトリに配置し以下を実行。
ちなみにdlltoolはmingwデフォルトインストールで導入済み、pexportはもともと標準だったものがオプションになったらしく、以下から入手。
https://sourceforge.net/projects/mingw/files/MinGW/Extension/pexports/pexports-0.47/pexports-0.47-mingw32-bin.tar.xz/download
tar.xzは7zipで解凍可能。
> pexport VJoy32.dll > VJoy32.def > dlltool --dllname VJoy32.dll --input-def VJoy32.def --output-lib VJoy32.lib > gcc VJoy.cpp VJoy32.dll VJoy.cpp: In function 'int main(int, char**)': VJoy.cpp:15:24: warning: ISO C++ forbids converting a string constant to 'PCHAR' {aka 'char*'} [-Wwrite-strings] VJoy_Initialize("", ""); ^ VJoy.cpp:15:24: warning: ISO C++ forbids converting a string constant to 'PCHAR' {aka 'char*'} [-Wwrite-strings] Temp\ccE9Yzks.o:VJoy.cpp:(.text+0x26): undefined reference to `_imp__VJoy_Initialize@8' Temp\ccE9Yzks.o:VJoy.cpp:(.text+0x6d): undefined reference to `_imp__VJoy_UpdateJoyState@8' Temp\ccE9Yzks.o:VJoy.cpp:(.text+0x77): undefined reference to `_imp__VJoy_Shutdown@0' collect2.exe: error: ld returned 1 exit status
以下で試している明示的リンクではうまくいっているため、DLLファイルそのものには問題はなし。
→namespaceやらなにやらの問題?
ということで、添付のVJoy.cppを明示的リンクに書き換えてテスト。
//main.c #include <stdio.h> #include <windows.h> #include "VJoy.h" int main() { HINSTANCE hinst; JOYSTICK_STATE joyState[2] = {0}; int (*fp_VJoy_Initialize)(char*, char*); int (*fp_VJoy_UpdateJoyState)(int, JOYSTICK_STATE*); int (*fp_VJoy_Shutdown)(); int c; printf("started.\n"); if ((hinst = LoadLibrary("VJoy32.dll")) == NULL) { printf("Error LoadLibrary\n"); } fp_VJoy_Initialize = (int (*)(char*, char*))GetProcAddress(hinst, "VJoy_Initialize"); fp_VJoy_UpdateJoyState = (int (*)(int, JOYSTICK_STATE*))GetProcAddress(hinst, "VJoy_UpdateJoyState"); fp_VJoy_Shutdown = (int (*)())GetProcAddress(hinst, "VJoy_Shutdown"); printf("call VJoy_Initialize.\n"); c = fp_VJoy_Initialize("", ""); joyState[0].XAxis = 32767; joyState[0].YAxis = 32767; joyState[0].ZAxis = 32767; joyState[0].Buttons = 0xAAAAAAAA; joyState[0].POV = (4 << 12) | (4 << 8) | (4 << 4) | 4; c = fp_VJoy_UpdateJoyState(0, &joyState[0]); fp_VJoy_Shutdown(); FreeLibrary(hinst); return 0; }
> gcc VJoy.cpp -o VJoy.exe > VJoy.exe started. call VJoy_Initialize.
うごいたっぽい。
DirectSoundでマイクからの音声入力をキャプチャして保存する
だけなのに、いいサンプルが少なく苦戦した・・・。
MSオフィシャルのドキュメントも見づらい・・・・。
のでソースを置いて自分用メモ。
#include <dsound.h> #include <time.h> #include <stdio.h> #include <windows.h> #include <time.h> #define SAMPLERATE 44100 //Hz #define CHANNELS 2 // 1:monoral, 2:stereo #define BITSPERSAMPLE 16 // bits per sample #pragma comment(lib, "dsound.lib") #pragma comment(lib, "dxguid.lib") typedef struct { char riffID[4]; unsigned long fileSize; char waveID[4]; } RIFFHeader; typedef struct { char chunkID[4]; long chunkSize; short wFormatTag; unsigned short wChannels; unsigned long dwSamplesPerSec; unsigned long dwAvgBytesPerSec; unsigned short wBlockAlign; unsigned short wBitsPerSample; /* Note: there may be additional fields here, depending upon wFormatTag. */ } FormatChunk; typedef struct { char chunkID[4]; long chunkSize; } DataChunk; BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ) { if (lpGUID != NULL) { // NULL only for "Primary Sound Driver". printf("Driver name: %s, Description:%s\n", lpszDrvName, lpszDesc); } return TRUE; } int writeWaveFile(char* copiedBuffer, long copiedLength) { RIFFHeader riffHeader = {{'R','I','F','F'}, sizeof(FormatChunk) + sizeof(DataChunk) + 4 + copiedLength, {'W','A','V','E'}}; FormatChunk formatChunk = {{'f','m','t',' '}, 16, 1, CHANNELS, SAMPLERATE, SAMPLERATE*CHANNELS*BITSPERSAMPLE/8, CHANNELS*BITSPERSAMPLE/8, BITSPERSAMPLE}; DataChunk dataChunk = {{'d','a','t','a'}, copiedLength}; // ファイル出力 HANDLE hFile = CreateFile("test1.wav" , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL); if (hFile == INVALID_HANDLE_VALUE) { MessageBox(NULL , TEXT("ファイルが開けません") , NULL , MB_OK); return -1; } DWORD dwWriteSize; WriteFile(hFile, (void*)&riffHeader, sizeof(RIFFHeader), &dwWriteSize, NULL); WriteFile(hFile, (void*)&formatChunk, sizeof(FormatChunk), &dwWriteSize, NULL); WriteFile(hFile, (void*)&dataChunk, sizeof(DataChunk), &dwWriteSize, NULL); WriteFile(hFile, copiedBuffer, copiedLength, &dwWriteSize, NULL); CloseHandle(hFile); printf("%d bytes written.\n", dwWriteSize); return 0; } //int _tmain(int argc, char* argv[]) int main(int argc, char* argv[]) { LPDIRECTSOUNDCAPTURE captureDevice = NULL;//DirectSoundCaptureDeviceオブジェクト LPDIRECTSOUNDCAPTUREBUFFER captureBuffer = NULL;//DirectSoundCaptureBufferオブジェクト WAVEFORMATEX wfx = {WAVE_FORMAT_PCM, CHANNELS, SAMPLERATE, SAMPLERATE*CHANNELS*BITSPERSAMPLE/8, CHANNELS*BITSPERSAMPLE/8, BITSPERSAMPLE, 0}; // 単純なPCMのWAVEデータを定義 // wFormatTag、Waveのフォーマット // nChannels モノラル1 ステレオ2(データセットの種類) // nSamplesPerSec 1秒あたりのサンプル数 // mAvgBytesPerSec、1秒あたりのバイト数。nSamplesPerSec*nBlockAlign。 // nBlockAlign 1サンプルのバイト数。nChannels×wBitsPerSample÷8 8・・・8ビット=1バイト // wBitsPerSample 1サンプルあたりのビット数。8か16 // cbSize 常に0 DSCBUFFERDESC bufferDescriber = {sizeof(DSCBUFFERDESC), 0, wfx.nAvgBytesPerSec*1, 0, &wfx, 0, NULL}; // DirectSound Capture Buffer DESC キャプチャ バッファを記述する構造体 // dwSize この構造体のサイズ(=sizeof(DSCBUFFERDESC)) // dwFlags デバイス付加能力の指定フラグ(未使用につき0) // dwBufferBytes バッファサイズ(byte) // dwReserved 予約領域(=0) // lpwfxFormat キャプチャフォーマットをWAVEFORMATX構造体で指定 // dwFXCount エフェクトを使用しない場合は0 // lpDSCFXDesc ハードウェアサポートのエフェクト指定 DWORD readablePos, capturedPos, readBufferPos, lockLength, capturedLength, wrappedCapturedLength; DWORD copiedLength = 0; void *capturedData = NULL, *wrappedCapturedData = NULL; char *copiedBuffer; int recordDurationSec = 3; //録音時間(秒) HRESULT Hret; time_t start, end; CoInitialize(NULL); DirectSoundCaptureCreate8( NULL, &captureDevice, NULL ); // サウンドデバイスが複数ある場合に使用 // DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc, (VOID*)NULL); readBufferPos = 0; copiedBuffer = (char*)malloc( wfx.nAvgBytesPerSec * wfx.nChannels * wfx.wBitsPerSample / 8 * recordDurationSec * 2); captureDevice->CreateCaptureBuffer(&bufferDescriber,&captureBuffer,NULL); start = time(NULL); captureBuffer->Start(DSCBSTART_LOOPING); Sleep(100); // キャプチャが少し進んでからデータ取得開始 while(1) { captureBuffer->GetCurrentPosition(&capturedPos, &readablePos); if ( readablePos > readBufferPos ) lockLength = readablePos - readBufferPos; else lockLength = bufferDescriber.dwBufferBytes - readBufferPos + readablePos; // printf("Lock startRead:%d, readable:%d, locklen:%d, captured:%d\n", // readBufferPos, readablePos, lockLength, capturedPos); Hret = captureBuffer->Lock(readBufferPos, lockLength, &capturedData, &capturedLength, &wrappedCapturedData, &wrappedCapturedLength, NULL); if( Hret != DS_OK ) { printf("Lock error:%x\n", Hret); } else { // printf("buffer read, buf1:%d, buf2:%d\n", capturedLength, wrappedCapturedLength); } if (capturedData != NULL) { memcpy(copiedBuffer+copiedLength, capturedData, capturedLength); copiedLength += capturedLength; readBufferPos += capturedLength; if (readBufferPos >= bufferDescriber.dwBufferBytes) readBufferPos = 0; } if (wrappedCapturedData != NULL) { // Ring buffer wrapped memcpy(copiedBuffer+copiedLength, wrappedCapturedData, wrappedCapturedLength); copiedLength += wrappedCapturedLength; readBufferPos = wrappedCapturedLength; } Hret = captureBuffer->Unlock( capturedData, capturedLength, wrappedCapturedData, wrappedCapturedLength); end = time(NULL); if((end-start) > recordDurationSec ){ break; } Sleep(100); } printf("%d bytes recorded.\n", copiedLength); writeWaveFile(copiedBuffer, copiedLength); captureBuffer->Stop(); free(copiedBuffer); CoUninitialize(); return 0; }
画面転送アプリ事始め
WindowsでUDPベースの快適な画面転送ソフト作り始めるための雑多メモ
Win32API、チュートリアル
高速な画面キャプチャの方法について
c++ 保存 スクリーンキャプチャ - Windowsでの画面キャプチャの最も速い方法 - CODE Q&A 問題解決
c++ capture screenshot - Fastest method of screen capturing on Windows - CODE Q&A Solved(上記の英語原文)
Various methods for capturing the screen - CodeProject
ハードウェアエンコーディングをOFFにした方が早い?
Tkinter PhotoImageの参照の寿命について
PhotoImageでボタンの画像を作成しているコードにて、べた書きからクラス形式に変更したところ、画像が表示されなくなった。
どうもこういうことらしい。
Python 2.7 - [tkinter]canvasの写真を更新したい|teratail
import tkinter as tk class MyWidget(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) frame1 = tk.Frame(self) imageicon = tk.PhotoImage(file='button.png') button = tk.Button(frame1, image=imageicon) button.pack() frame1.pack() root = MyWidget() root.mainloop()
→画像が表示されず、ボタンも反応しない
import tkinter as tk class MyWidget(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) frame1 = tk.Frame(self) self.imageicon = tk.PhotoImage(file='button.png') button = tk.Button(frame1, image=self.imageicon) button.pack() frame1.pack() root = MyWidget() root.mainloop()
imageiconの参照をselfで持つことによって、rootが死なない限り破棄されなくなった模様
純粋なオブジェクト指向じゃない?ようなので、こういう仕様は恐ろしい・・・構文エラーでも実行時エラーでもなく、単に期待した動作をしない。
将来的にはリリース前にテストを通すかもしれないけど、これはスルーするかもしれない・・・。