コマンドプロンプトから sinku.dll を使う

サムネイル方式で動画を管理するソフトウェア WhiteBrowser では映像サイズやコーデック関連情報を取得するために sinku.exe という外部コマンドが用意されています。
しかし 比較的新しいコーデックの H.264/MPEG-4 AVC でエンコードした動画の情報が取得できないようです。
最近の sinku.dll に入れ替えると全部空っぽになってしまうようなので暫定的に代替コマンドを作成することにしました。
C を書くのは久しぶりで関連サイトを右往左往してしまったのでそのときの作業メモ兼です。
なんかの理由で sinku.dll をコマンドライン化しようとしてる人も自由にお使いください。

開発環境

無料の開発ツール
Microsoft Visual Studio Express (Express 2017 for Windows Desktop) の Visual C++ のコンパイラだけを使用

ソースコード sinku.cpp と sinku.hファイル

対象ファイル名漢字コード
ソースおよび exe ファイル
sinku.cpp, sinku.h, sinku.exe
filesinku_console.zipShift JIS

sinku.h

黒羽製作所 [仕様] から入手できるサンプルコードに含まれているヘッダファイルを無編集で使用。

sinku.cpp

飾りっけ、コメントなし

#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <locale.h>
#include "sinku.h"
int expand_len(char *str, int max_len)
{
	int len = 0;
	for (int i = 0; i < max_len; i++) {
		switch (str[i]) {
			case '&' :
			case '\'':
			case '"':
			case '>':
			case '<':
			case '%':
				len += strlen("&#xFF;") - 1;
				break;
		}
		if (str[i] == NULL) break;
	}
	return len;
}
void escape_str(char *src_str, char *dst_str, int max_len)
{
	char *pos = dst_str;
	for (int i = 0; i < max_len; i++) {
		switch (src_str[i]) {
			case '&' : 
			case '\'':
			case '"':
			case '>':
			case '<':
			case '%':
				char esc_str[16];
				sprintf(esc_str, "&#x%02x;", src_str[i]);
				strcat(pos, esc_str);
				pos += strlen("&#xFF;");
				break;
			case NULL:
				*pos++ = src_str[i];
				break;
			default:
				if (iscntrl(src_str[i]))
					*pos++ = ' ';
				else
					*pos++ = src_str[i];
		}
		if (src_str[i] == NULL) break;
	}
}
int _tmain(int argc, _TCHAR* argv[])
{
	SinkuFunc	sf;
	_tsetlocale(LC_ALL, _T(""));
	memset(&sf, 0, sizeof(SinkuFunc));
	if(argc != 2) {
		_tprintf(_T("Usage: %s file\n"), argv[0]);
		exit(1);
	}
	sf.hDLL = LoadLibrary( _T("sinku.dll" ));
	if(sf.hDLL == NULL ) {
		_tprintf(_T("SINKU.DLLをロードできませんでした\n"));
		exit(1);
	}
	*(int  **) &sf.GetDllVersion	= (int  *) GetProcAddress((HMODULE) sf.hDLL, "GetDllVersion");
	*(void **) &sf.GetFileInfoAuto	= (void *) GetProcAddress((HMODULE) sf.hDLL, "GetFileInfoAuto");
	*(int **) &sf.Unicode		= (int *) GetProcAddress((HMODULE) sf.hDLL, "Unicode");
	if(sf.GetDllVersion == NULL || sf.Unicode == NULL || sf.Unicode() == 0) {
		_tprintf(_T("Unicode対応版 SINKU.DLLが必要です\n"));
		FreeLibrary((HMODULE) sf.hDLL );
		exit(1);
	}
	FILE_INFO	fi;
	memset(&fi, 0, sizeof(FILE_INFO));
	_tcsncpy_s(fi.name, sizeof(fi.name), argv[1], _TRUNCATE);
	sf.GetFileInfoAuto(&fi);
	if (strnlen(fi.error, STR_MAX_LENGTH) > 0) {
		printf("DDL error %s\n", fi.error);
		FreeLibrary((HMODULE) sf.hDLL );
		exit(1);
	}
	int video_desc_len = expand_len(fi.video[0], STR_MAX_LENGTH) + STR_MAX_LENGTH;
	int audio_desc_len = expand_len(fi.audio[0], STR_MAX_LENGTH) + STR_MAX_LENGTH;
	int extra_desc_len = expand_len(fi.extra[0], STR_MAX_LENGTH) + STR_MAX_LENGTH;
	char *video_desc = (char *) calloc(video_desc_len, sizeof(char) );
	char *audio_desc = (char *) calloc(audio_desc_len, sizeof(char));
	char *extra_desc = (char *) calloc(extra_desc_len, sizeof(char));
 
	if (video_desc == NULL || audio_desc == NULL || extra_desc == NULL) {
		FreeLibrary((HMODULE) sf.hDLL );
		free(video_desc);
		free(audio_desc);
		free(extra_desc);
		exit(1);
	}
	escape_str(fi.video[0], video_desc, STR_MAX_LENGTH);
	escape_str(fi.audio[0], audio_desc, STR_MAX_LENGTH);
	escape_str(fi.extra[0], extra_desc, STR_MAX_LENGTH);
 
	printf("<fields>\n");
	printf("<container>%s</container>\n", fi.container);
	printf("<video>%s</video>\n", video_desc);
	printf("<audio>%s</audio>\n", audio_desc);
	printf("<extra>%s</extra>\n", extra_desc);
	printf("<movie_length>%.0f</movie_length>\n", fi.playtime > 0 ? fi.playtime: 0);
	printf("<movie_size>%lld</movie_size>\n",  fi.size > 0 ? fi.size/1024: 0); // KiByte
	printf("</fields>\n");
	FreeLibrary((HMODULE) sf.hDLL );
	free(video_desc);
	free(audio_desc);
	free(extra_desc);
	exit(0);
}

ファイルサイズはオリジナルの SinkuConsole 同様、キビバイトに丸め処理をしています。
※ video / audio / extra の先頭部分しか出力していないのでオリジナルと同じ機能を満たしているかは不明。
sinku.dll で設定される video / audio は最大 10 個、extra は最大 5 。
audio / extra は 2つ以上格納されている場合もあるようですがざっくりと無視してます。
sinku.dll 側の format.ini ファイルに出力パターンが書かれています。

コンパイル (sinku.exe の作成)

  • 適当なディレクトリ(C:\work ディレクトリ) に sinku.cpp とサンプルから取り出した sinku.h を置く
  • スタートメニューから 「開発者コマンドプロンプト for VS2017」 を実行
C:\> cd /D C:\work
C:\work> cl /GS /GL /O2 /D "WIN32" ^
            /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /MD /EHsc /nologo ^
         sinku.cpp
 
sinku.cpp
コード生成しています。
コード生成が終了しました。
 
## 動作チェック
C:\work> sinku "ファイル名"

CL コマンド行末の ^ は複数行になるときの記述方法なので 1 行で書く場合は不要

コンパイルせずに添付の sinku.exe だけを使用したい場合

セキュリティ面から自前でコンパイルすることをお勧めしますが…

実行には Visual Studio 2017 の Microsoft Visual C++ 再頒布可能パッケージが必要
VCRUNTIME140.dll がないというエラーが出ないなら作業不要です。

以下の URL から x86 版をインストール
https://www.visualstudio.com/ja/downloads/?q=#other-ja (Microsoft)

動作確認した sinku.dll のバージョン

用意する DLL は UNICODE 対応版の sinku.dll
ANSI 版では動作しません。ver.130101 でのみ動作を確認しました。

sinku.dll と ini ファイルの入れ替え

念のため WhiteBrowser のルートディレクトリにある既存の sinku.exe , sinku.dll , format.ini , codecs.ini の 4ファイルをバックアップ用に作った別ディレクトリに移動しておきます。

作成した sinku.exe および UNICODE 対応の最新版 sinku.dll , format.ini , codecs.ini の 4ファイルを WhiteBrowser のルートディレクトリに配置します。
DLL だけ入れ替えて format.ini , codecs.ini が古いままだと S不明VIDEO / C空VIDEO / C空AUDIO のような戻り値になる場合があるので必ず一緒に更新するようにします。

以上で作業完了 
コンパイル作業で使ったディレクトリ(C:\work) のファイルを削除してください。

免責

「ソースおよび実行ファイルについての改変、配布、転載を含めすべてフリーです。挨拶や連絡も不要です。
ただし、本ソフトウェアまたはソースコードを使用した事により発生した如何なる損害について作者は一切責任を負いません。」
のでご理解の上使用してください。クレームも無しの方向でよろしくお願いします。

 


参考リンク

日本オラクル
■ 日本オラクル 株式会社
■ オラクルマスター資格 (オラクルマスターとは
■ Oracle Web セミナー