今回は前回製作したcvcaptureモジュールを改良し、
追加する機能は、
specファイルを記述する
前回のspecファイルをベースに、
リソースを定義する
まずはリソースです。リソースは<resources>タグ内の<resource>タグで記述します。<resoure>タグではname属性でリソース名、
また、
リスト1 リソース定義
<resources>
<resource name="cvcapture" payload="CvCapture" alloc="no">
<description><?data
Storage for CvCapture.
?></description>
<destruct><?data
cvReleaseCapture(&resource);
?></destruct>
</resource>
</resources>
関数を定義する
次に、

リソースを作成する関数cv_
<function name="cv_create_camera_capture">
<proto>resource cvcapture cv_create_camera_capture([int index])</proto>
<summary>Start capturing frames from camera.</summary>
<description>(省略)</description>
<test>
<code><?data
var_dump(cv_create_camera_capture());
?></code>
<result mode="format"><?data
resource(%d) of type (cvcapture)
?></result>
</test>
</function>
<function name="cv_create_file_capture">
<proto>resource cvcapture cv_create_file_capture(string filename)</proto>
<summary>Start capturing frames from video file.</summary>
<description>(省略)</description>
<test>
<skipif><?data
if (!file_exists("sample.3g2")) {
die("skip sample video file does not exist");
}
?></skipif>
<code><?data
var_dump(cv_create_file_capture("sample.3g2"));
?></code>
<result mode="format"><?data
resource(%d) of type (cvcapture)
?></result>
</test>
</function>
cv_
<function name="cv_save_capture">
<proto>bool cv_save_capture(resource cvcapture capture, string filename[, array &size])</proto>
<summary>Capture a frame.</summary>
<description>(省略)</description>
<test>
<code><?data
$capture = cv_create_camera_capture();
if ($capture && cv_save_capture($capture, "test_save.jpg", $size)) {
print_r($size);
}
?></code>
<result mode="format"><?data
Array
(
[0] => %d
[1] => %d
)
?></result>
</test>
</function>
ソースコードを生成する
ここまでできたら、
$ pecl-gen --dir=cvcapture-0.2.0 cvcapture-0.2.0.xml Creating 'cvcapture' extension in './cvcapture-0.2.0' Your extension has been created in directory ./cvcapture. See ./cvcapture-0.2.0/README and/or ./cvcapture-0.2.0/INSTALL for further instructions.
ソースコード解説
生成されたソースコードのうち、
php_
#define FREE_RESOURCE(resource) zend_list_delete(Z_LVAL_P(resource))
CodeGen_
次にcvcapture.
/* {{{ Resource destructors */
int le_cvcapture; /* リソース識別番号 */
void cvcapture_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
/* “CvCapture”は<resource>タグのname属性値 */
CvCapture * resource = (CvCapture *)(rsrc->ptr);
do {
/* ここがspecファイルの<destruct>タグに記述したコード */
cvReleaseCapture(&resource);
} while (0);
}
/* }}} */
cvcapture_
le_
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(cvcapture)
{
/* (定数定義は省略) */
le_cvcapture = zend_register_list_destructors_ex(cvcapture_dtor,
NULL, "cvcapture", module_number);
/* add your stuff here */
return SUCCESS;
}
/* }}} */
関数を実装する
ここからはcvcapture.
リソースを返す関数
まずはcv_
/* {{{ proto resource cvcapture cv_create_camera_capture([int index])
Start capturing frames from camera. */
PHP_FUNCTION(cv_create_camera_capture)
{
/* 戻り値のリソースを代入する変数の宣言 */
/* 変数名は固定。型はプロトタイプが“resource cvcapture”、リソース定義が
<resource name="cvcapture" payload="CvCapture"/>なら、“CvCapture *” */
CvCapture * return_res;
long return_res_id = -1;
/* 引数が代入される変数の宣言 */
long index = 0;
/* 引数をパース */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &index) == FAILURE) {
return;
}
/* 実装されていない旨のエラーを出力 */
php_error(E_WARNING, "cv_create_camera_capture: not yet implemented"); RETURN_FALSE;
/* 戻り値を実体のアドレスがreturn_res、タイプがle_cvcaptureのリソースにする */
ZEND_REGISTER_RESOURCE(return_value, return_res, le_cvcapture);
}
/* }}} cv_create_camera_capture */
戻り値をリソースにするコードは生成されているので、
return_res = cvCreateCameraCapture((int)index);
if (return_res == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create camera capture");
efree(fullpath);
RETURN_FALSE;
}
cv_
リソースを受け取る関数
次に、
/* {{{ proto bool cv_save_capture(resource cvcapture capture, string filename[, array &mixed])
Capture a frame. */
PHP_FUNCTION(cv_save_capture)
{
/* リソース関連変数の宣言 */
zval * capture = NULL;
int capture_id = -1;
CvCapture * res_capture;
/* その他の変数の宣言 */
const char * filename = NULL;
int filename_len = 0;
zval * size = NULL;
/* 引数をパース */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|z", &capture, &filename, &filename_len, &size) == FAILURE) {
return;
}
/* リソースの実体を取得 */
ZEND_FETCH_RESOURCE(res_capture, CvCapture *, &capture, capture_id, "cvcapture", le_cvcapture);
/* 実装されていない旨のエラーを出力 */
php_error(E_WARNING, "cv_save_capture: not yet implemented"); RETURN_FALSE;
RETURN_FALSE;
}
/* }}} cv_save_capture */
引数をリソースをして取得する場合、
もし引数がリソースでない場合はzend_
この関数の実装もcv_
char *fullpath; /* 保存先のフルパス */
IplImage *image; /* イメージ構造体 */
/* パスのチェック */
if (strlen(filename) != filename_len ||
(fullpath = expand_filepath(filename, NULL TSRMLS_CC)) == NULL)
{
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong filename given");
RETURN_FALSE;
}
if (php_check_open_basedir(fullpath TSRMLS_CC) ||
(PG(safe_mode) && !php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR)))
{
efree(fullpath);
RETURN_FALSE;
}
/* フレームを取得・保存 */
image = cvRetrieveFrame(res_capture);
if (image == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot retrieve image");
efree(fullpath);
RETURN_FALSE;
}
if (!cvSaveImage(fullpath, image)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot save image to '%s'", fullpath);
efree(fullpath);
RETURN_FALSE;
}
/* 画像サイズを代入 */
if (size != NULL) {
CvSize imgsize = cvGetSize(image);
zval_dtor(size);
array_init(size);
add_next_index_long(size, (long)imgsize.width);
add_next_index_long(size, (long)imgsize.height);
}
efree(fullpath);
RETURN_TRUE;
インストール
実装が終わったら、
$ phpize $ ./configure --enable-cvcapture $ make $ make test $ sudo make install
実際に使ってみる
リスト12は前回のサンプルをリソースを使うように書き直したものです。
<?php
extension_loaded('cvcapture') || dl('cvcapture.so');
$capture = cv_create_camera_capture();
if ($capture) {
for ($i = 1; $i
今回の目的の一つは、
リソースを使わないとき | リソースを使ったとき | |
---|---|---|
初期化 | - | 0. |
1回目 | 1. | 0. |
2回目 | 0. | 0. |
3回目 | 0. | 0. |
4回目 | 0. | 0. |
5回目 | 0. | 0. |
6回目 | 0. | 0. |
7回目 | 0. | 0. |
8回目 | 0. | 0. |
9回目 | 0. | 0. |
10回目 | 0. | 0. |
合計 | 6. | 1. |
どうやら期待通りの結果が得られたようです。このようにリソースを使えばPHPの組み込み型でない構造体を使い回すことができます。
おわりに
今回はリソースとリソースを扱う関数を定義しました。しかし、
サンプルファイルのダウンロード
付録は後日掲載