2010-02-17

Mix_LoadMUS_RW の引数に int freesrc がない件

最近ZinniaさんのSDL_RWops解説を読み直して、fopen/fcloseをRWops系の関数で書き直した。これを抽象化の点として、そのうち暗号化したzipなどから読ませるようにしたいと思う。
画像ファイル(SDL_Image)は問題なく置き換えることができたが、音声ファイル(SDL_Mixer)の部分で落ちるようになった。
検索でGameDev.netのフォーラムのトピックを見つけた。以下会話の流れ。


Mix_LoadMUS_RWで落ちる。どういうこと?
<状況説明とMix_LoadMUS_RWを使ったコード。SDL_Mixerのバージョンは1.2.7で、プラットフォームはOS X>


SDL_mixerのソース(load_ogg.c, music.c, music_ogg.c)を読んでみた。
Ogg形式ならMix_LoadWAV_RW()が代わりに使える。
ただ、データを内部でコピーするから、長い音楽には向かない。
5MB程度のOggでも、メモリ上に解凍すると45MBになってしまう。
Mix_LoadMUS() はディスクから少しずつ解凍しながらストリーミングするから、4KB程度のバッファですむ。
Ogg形式の場合は、Vorbisライブラリがストリーミングの処理を直接扱う。つまり、Vorbisがファイルを開いて、直接FILE *からチャンクを読んでいく。
Mix_LoadMUS_RW() の場合はSDL_RWopsをコピーする手段が無いから、引数に渡したものをそのまま使うしかない。つまり、処理が帰ってきてもfreeされないことになる。
要は、引数に渡したRWopsをfreeせず、 SDL_RWclose(rw) も使わなければOK。
(注:普段私はSDL_Mixerを使わない)


ありがとう。私も読んだけどそこまでは読み取れなかった。
まだ疑問が残っているのは、これが二重freeのエラーになることだ。

Mix_FreeMusic(music);
SDL_FreeRW(rwops);

Mix_FreeMusic()がfreeしているということ?ソースからはわからなかったけど。
まあ、二重free以外は全部うまくいっています。ありがとう。


その通り。RWopsはMix_FreeMusic()でfreeされる。
この処理はVorbisライブラリ(正確に言うと、vorbisfile.c)側でしているから、SDL_Mixerのソースにはない。
どういたしまして :)


なるほど。丁寧な解説をありがとう。Thanks again :)



ということで、Mix_LoadMUS_RWに渡したRWopsはMix_FreeMusicが閉じてくれるらしい。
手元のコードもSDL_RWcloseを省くとうまく動いた。

(copied from tumblr)