ページ 11

OggVorbisのデコード

Posted: 2006年11月18日(土) 16:42
by yu0627
 現在、ActiveBasic上でOggVorbisをデコードするプログラムを作っているのですが、どうもうまくいきません。下は問題のコードです。
このコードでデバッグするとov_open_callbacksの部分で止まってしまいます。

OggVorbisSDKの宣言はNoWestさんが配布しているab4apiのものです。
「api_mmsysPro4.sbp」はNoWestさんが以前配布されていたものです。
また、fopen.sbpの中身は以下のようになっています。

コード: 全て選択

Declare Function fopen CDECL Lib "crtdll" (__path As *Byte, __mode As *Byte) As *FILE
Declare Function fclose CDECL Lib "crtdll" (__stream As *FILE) As Long
Declare Function fflush CDECL Lib "crtdll" (__stream As *FILE) As Long
Declare Function fprintf CDECL Lib "crtdll" (__stream As *FILE, __format As *Char, ...) As Long
Declare Function fscanf CDECL Lib "crtdll" (__stream As *FILE, __format As *Char, ...) As Long
Declare Function feof CDECL Lib "crtdll" (__fp As *FILE) As Long
Declare Function ftell CDECL Lib "crtdll" (__fp As *FILE) As Long
Declare Function fread CDECL Lib "crtdll" (__ptr As VoidPtr, __size As DWord, __n As DWord, __stream As *FILE) As DWord
Declare Function fseek CDECL Lib "crtdll" (__stream As *FILE, __offset As Long, __whence As Long) As Long
なお、ovCB構造体にアドレスを指定している各関数はCからの移植です。
下はもともとのCのものです。

コード: 全て選択

size_t ovCB_read(void *buf, unsigned int a, unsigned int b, void * fp) {
    return fread(buf, a, b, (FILE *)fp);
}

int ovCB_close(void * fp) {
    return fclose((FILE *)fp);
}

int ovCB_seek(void *fp, __int64 a, int b) {
    return fseek((FILE *)fp, (long)a, b);
}

long ovCB_tell(void *fp) {
    return ftell((FILE *)fp);
}
 色々と試してみたのですが全く解決しないので、投稿しました。
どこがいけないのでしょうか。

Posted: 2006年11月18日(土) 22:55
by 高信期
試したわけではありませんが、コールバックを受ける関数に例えば、

コード: 全て選択

Function cdecl ovCB_read(ptr As *VoidPtr, size As DWord, nmemb As DWord, datasource As VoidPtr) As DWord 
とcdecl修飾子を付けてみては如何でしょうか?

返信@yu0627

Posted: 2006年11月19日(日) 13:04
by yu0627
> 試したわけではありませんが、コールバックを受ける関数に例えば、

コード: 全て選択

Function cdecl ovCB_read(ptr As *VoidPtr, size As DWord, nmemb As DWord, datasource As VoidPtr) As DWord 
> 
> とcdecl修飾子を付けてみては如何でしょうか?
 cdecl、試してみました。が、コンパイラはAB4.24のを使っているので、Declare以外の関数ではまだ使えないらしく、コンパイルエラー+コンパイル強制終了でした。
 そこで、AB5.0CP3でやってみたところ、cdecl付きでコンパイルすることが出来ましたが、まだov_open_callbacks関数にてエラーが出てしまいます。(EPI=&H0012FFF0)

Posted: 2006年11月20日(月) 01:07
by 高信期
うーん、そうなるとちょっと分かりませんね。
ov_open_callbacks関数内で、コールバックを受ける関数がちゃんと呼び出されているかや、
型変換がfopenなどに有効なのかが気になるところですが・・・。
お役に立てずすみません。

返信@yu0627

Posted: 2006年11月20日(月) 21:48
by yu0627
うーん、そうなるとちょっと分かりませんね。
ov_open_callbacks関数内で、コールバックを受ける関数がちゃんと呼び出されているかや、
型変換がfopenなどに有効なのかが気になるところですが・・・。
お役に立てずすみません。
 いえいえ。

OggVorbisの定義ファイル内のDeclareにもCDECLをつけてやってみましたが、うまくいきませんでした。

コード: 全て選択

Dim vf As OggVorbis_File
ov_open_callbacks(fp, VarPtr(vf), NULL, 0, ovCB)
とやってみてもだめです。
どなたかABでOggVorbisのデコードをされた方はいませんでしょうか。

---追記---
Debugging Tools for Windowsにて各種情報を取得してみました。

Posted: 2007年9月26日(水) 23:33
by ゲスト
そもそもABでOggは再生できないのにデコードもなにもあったものではないだろう

Posted: 2007年9月27日(木) 00:19
by ゲスト
デコードしないと再生できないのに
何言ってんだか

この件に関して

Posted: 2007年9月27日(木) 04:32
by NoWest
色々と謝らないといけない事がありますので書かせてもらいます。

まず、ab4apiの定義ファイルですが、かなり多くの誤植がありまして
コンパイルエラーがでないだけ自分でも凄いと言わざるをえないというのがまず一点

ようするにあんまり当てにしないでくださいということです。


2点目はvorbisfile.sbpのov_open_callbacks関数ですが、
確認してみたところ、おそらくは誤植だと思われます。


長い間更新もせず、また私自身oggvorbisの再生に長らく挑戦していなかったので
誤植に気づきませんでした。

大変申し訳ないです。


コード: 全て選択

Declare Function ov_open_callbacks Lib "vorbisfile" (datasource As VoidPtr, ByRef vf As OggVorbis_File, initial As *Byte, ibytes As Long, callbacks As ov_callbacks) As Long
このファイルを移植した当時、ABの仕様上の問題により
構造体を関数に渡す際は必ず、アドレス参照にしなければならなかったため
苦肉の策としてByRef指定としてしまっていたようです。

最新のAB4ではそのまま構造体を渡せるようになっていると思いますので
とりあえず上記のようにしてみてください。

たぶんCDECLがいると思いますけど・・・

Posted: 2007年9月27日(木) 15:08
by NoWest
と、いうことで

こちらで色々と試してみましたが、結論からいうと
ABからOggVorbisのVorbisfileを使うのはゲストさんの言うとおり「無理」なようです。

cdeclつけたりByRef消してみたり、構造体のメンバを引数にしてみたりしましたが
一向にエラーが消えません。

山本さんに確認してみると現状のABではC言語で作られたDLLでCDECL形式の構造体コピー付き関数をロードすることはできないようです。
※ABとCでは内部の仕様が異なるためのようです。


そんな訳で、vorbisfileを使う場合,stdcall形式に置き換えるラップDLLを別途作成してそこからvorbisfileをロードする必要があります。


因みに、私が同梱して配布しているoggvorbisのDLL※はVisualSdutio6でコンパイルしているので
※現在は配布していない。ご要望があれば再度配布します。

ov_openの中身はWindowsに標準で入っているCランタイムだと思われますので
こちらで試してみるのも1つの手です。
動作する保障はしませんが。。。


P.S.
大急ぎでラッパーDLLを作りました。ダウンロードはこちら

定義ファイルを下記のように2箇所変更してください。
vf_wrapper.dllは下記の2つの関数を__stdcallでラップした関数を提供しています。
この2つ以外の関数はこれまでの指摘にあったとおり、CDECLの指定が必要です。
また、コールバックされる関数※にもCDECLが必要です。
※readとかseekのヤツ

コード: 全て選択

Declare Function ov_open_callbacks Lib "vf_wrapper" (datasource As VoidPtr, vf As *OggVorbis_File, initial As *Char, ibytes As Long, ByRef callbacks As ov_callbacks) As Long
Declare Function ov_test_callbacks Lib "vf_wrapper" (datasource As VoidPtr, vf As *OggVorbis_File, initial As *Char, ibytes As Long, ByRef callbacks As ov_callbacks) As Long
このラッパーはVer5での確認なのでVer4で動くかは分かりませんが、
こちらで試したところエラーは出ずにうまく動いているようなので、試してみる価値はあると思います。

Posted: 2007年9月28日(金) 10:53
by イグトランス
構造体のメンバを引数にしてもだめでしたか。うまくいくと思うのですが。stdcall関数で構造体の値渡しができなかったとき,それでうまくいきましたし,原理的にはcdeclにも応用できるはずです。

こういうDLLをVisual C++で作ります。

コード: 全て選択

//t.cpp
#include <windows.h>
#include <stdio.h>

struct s
{
int a, b, c, d;
};

extern "C" __declspec(dllexport)
void __cdecl s2str(char *buf, size_t size, s x)
{
	_snprintf(buf, size, "%d %d %d %d", x.a, x.b, x.c, x.d);
}

BOOL WINAPI DllMain(HINSTANCE, DWORD, void*)
{
	return TRUE;
}
これをcl t.cpp /link /DLL /out:t.dllとしてコンパイルします。
そして,ABでは次のようにします。

コード: 全て選択

Declare Sub s2str CDecl Lib "t" (buf As *Byte, size As SIZE_T, a As Long, b As Long, c As Long, d As Long)

Dim buf[1024] As Byte
s2str(buf, Len(buf), 1, 2, 3, 4)

MessageBox(0, buf, "", MB_OK)

Posted: 2007年9月28日(金) 16:04
by NoWest
> 構造体のメンバを引数にしてもだめでしたか。うまくいくと思うのですが。stdcall関数で構造体の値渡しができなかったとき,それでうまくいきましたし,原理的にはcdeclにも応用できるはずです。
>
> こういうDLLをVisual C++で作ります。
>

コード: 全て選択

//t.cpp
> #include <windows.h>
> #include <stdio.h>
> 
> struct s
> {
> int a, b, c, d;
> };
> 
> extern "C" __declspec(dllexport)
> void __cdecl s2str(char *buf, size_t size, s x)
> {
> 	_snprintf(buf, size, "%d %d %d %d", x.a, x.b, x.c, x.d);
> }
> 
> BOOL WINAPI DllMain(HINSTANCE, DWORD, void*)
> {
> 	return TRUE;
> }
> これをcl t.cpp /link /DLL /out:t.dllとしてコンパイルします。
> そして,ABでは次のようにします。
>

コード: 全て選択

Declare Sub s2str CDecl Lib "t" (buf As *Byte, size As SIZE_T, a As Long, b As Long, c As Long, d As Long)
> 
> Dim buf[1024] As Byte
> s2str(buf, Len(buf), 1, 2, 3, 4)
> 
> MessageBox(0, buf, "", MB_OK)

構造体のメンバを引数に変える方法は知っていたので試してみたのですが、
その時はうまく動かなかったのです。

今、ラッパーを使っている状態でエラーが出ずに動いているので、
ラッパーを再度、構造体メンバの引数を持つものに差し替えてテストしてみます。

Posted: 2007年9月28日(金) 19:09
by NoWest
イグトランスさんのご指摘どおり、構造体のメンバを引数にすることで動作するようです。

どうやら私が実験していたときは、コールバック関数にCDECL指定をしていない時に
構造体のメンバを関数の引数にしてテストしていたようです。


結論的には、現行のAB5CP以降であればイグトランスさんの提案した方法で実現可能です。
しかしながらAB4.24では自分で作成するコールバック関数にCDECLを指定できないようなので、
そのままでは実現が不可能ということになります。

ですから、ラッパーDLLをコールバック関数がstdcall形式でも動くように改良しておきました。

具体的にはDLL内部にstdcall形式のコールバック関数をコールバックするcdecl形式の関数を準備し、ov_open_callbacksが呼び出されると、
DLL内部のov_callbacks構造体を使ってcdecl形式の関数で初期化を実行しています。

そのため、ov_open_callbacksに指定したov_callbacks構造体と
OggVorbis_Fileのメンバであるov_callbacks構造体は一致しませんの注意してください。


これでおそらくはAB4でもvorbisfileが使えると思います。

Re: 返信@yu0627

Posted: 2007年9月29日(土) 06:08
by NoWest
> どなたかABでOggVorbisのデコードをされた方はいませんでしょうか。
ラッパーDLLを使ってAB4で動作する簡単なOggVorbisデコーダを作ってみましたので参考にしてみてください。

oggvorbis_decoder.lzh

Webからサンプルを拾ってきて、ちょこっと手を加えただけなので、
挙動が怪しい点もありますがご容赦ください。

Posted: 2007年10月03日(水) 13:09
by ゲスト
コンソールアプリだけなのね