2014年7月23日水曜日

MediaPlayerでoggファイルがループ再生されてしまう問題(2)

getDuration()で得た再生時間(ms)経過後にMediaPlayerを停止させる方法を行うと、タイミングにずれが発生し、少し早めに停止したり、逆に少し遅くなって一瞬ループして先頭に戻ったりします。

このズレがどうしても許せない場合はこの方法は使えません。別の方法を考えてみました。

ANDROID_LOOP=trueメタデータ付きのoggファイルを直接再生するのではなく、一旦別ファイルにコピーして再生します。さらにコピーの途中で 「ANDROID_LOOP=true」に一致する部分があれば、その部分を空白文字に置き換えてしまいます。

static public boolean copyWithAndroidLoopFalse(InputStream src, OutputStream dst) {
    byte[] android_loop = {0x41, 0x4E, 0x44, 0x52, 0x4F, 0x49, 0x44, 0x5F, 0x4C, 0x4F, 0x4F, 0x50, 0x3D, 0x74, 0x72, 0x75, 0x65};
    while(true) {
        byte[] raw_page = readPageBytes(src);
        if (raw_page == null) return false;
        if (raw_page.length == 0) break;
        int index = findBytePattern(raw_page, android_loop);
        if (index >= 0) { //ANDROID_LOOP=trueが見つかったら空白文字に置き換える
            for(int i=0; i<android_loop.length; i++) {
                raw_page[index + i] = 0x20;
            }
        }
        try {
            dst.write(raw_page);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    return true;
}

static private int findBytePattern(byte[] search_byte, byte[] search_pattern) {
    int byte_length = search_byte.length;
    int pattern_length = search_pattern.length;
    for(int i=0; i<=byte_length - pattern_length; i++) {
        for(int j=0; j<pattern_length; j++) {
            if (search_byte[i+j] == search_pattern[j]) {
                if (j == search_pattern.length - 1) {
                    return i; //search_pattern全て一致
                }
            } else {
                break;
            }
        }
    }
    return -1; //一致しなかった
}

こんなことして大丈夫なの?と思われるかもしれませんが、Vorbisの仕様ではユーザーコメントは長さとコメントの組み合わせで、長さが変わらなければ大丈夫と思います。それよりもむしろ、「ユーザーコメントは名前と値をイコールでつないだもの」とあるのですが、そっちを守っていないのが少し心配です。
フォーマットは以下のサイトを参考にしました
Mitsugu Oyama のソフトウェア倉庫


0 件のコメント:

コメントを投稿