load_ogg.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 13 Jan 2012 03:15:19 -0500
changeset 561 87bdb4c81c0b
parent 518 8bc9b5fd2aae
child 601 05123263dab3
permissions -rw-r--r--
Fixed memory crash loading Ogg Vorbis files on Windows
The pointer to the audio data could come from SDL_LoadWAV_RW() or from our other loaders, and we need to use the correct free() to release the memory. So we'll just use the SDL memory functions for consistency.
This pretty much only matters on Windows where we can't guarantee a certain C runtime so we provide our own malloc() and friends.
slouken@190
     1
/*
slouken@518
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@518
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
slouken@190
     4
slouken@518
     5
  This software is provided 'as-is', without any express or implied
slouken@518
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@518
     7
  arising from the use of this software.
slouken@190
     8
slouken@518
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@518
    10
  including commercial applications, and to alter it and redistribute it
slouken@518
    11
  freely, subject to the following restrictions:
slouken@190
    12
slouken@518
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@518
    14
     claim that you wrote the original software. If you use this software
slouken@518
    15
     in a product, an acknowledgment in the product documentation would be
slouken@518
    16
     appreciated but is not required.
slouken@518
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@518
    18
     misrepresented as being the original software.
slouken@518
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@190
    20
slouken@518
    21
  This is the source needed to decode an Ogg Vorbis into a waveform.
slouken@518
    22
  This file by Vaclav Slavik (vaclav.slavik@matfyz.cz).
slouken@190
    23
*/
slouken@190
    24
slouken@190
    25
/* $Id$ */
slouken@190
    26
slouken@190
    27
#ifdef OGG_MUSIC
slouken@190
    28
slouken@190
    29
#include <stdio.h>
slouken@190
    30
#include <stdlib.h>
slouken@190
    31
#include <string.h>
slouken@190
    32
slouken@190
    33
#include "SDL_mutex.h"
slouken@190
    34
#include "SDL_endian.h"
slouken@190
    35
#include "SDL_timer.h"
slouken@190
    36
slouken@190
    37
#include "SDL_mixer.h"
slouken@312
    38
#include "dynamic_ogg.h"
slouken@190
    39
#include "load_ogg.h"
slouken@190
    40
slouken@190
    41
static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
slouken@190
    42
{
slouken@190
    43
    return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
slouken@190
    44
}
slouken@190
    45
slouken@190
    46
static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
slouken@190
    47
{
slouken@221
    48
    return SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
slouken@190
    49
}
slouken@190
    50
slouken@190
    51
static int sdl_close_func_freesrc(void *datasource)
slouken@190
    52
{
slouken@190
    53
    return SDL_RWclose((SDL_RWops*)datasource);
slouken@190
    54
}
slouken@190
    55
slouken@190
    56
static int sdl_close_func_nofreesrc(void *datasource)
slouken@190
    57
{
slouken@473
    58
    return SDL_RWseek((SDL_RWops*)datasource, 0, RW_SEEK_SET);
slouken@190
    59
}
slouken@190
    60
slouken@190
    61
static long sdl_tell_func(void *datasource)
slouken@190
    62
{
slouken@190
    63
    return SDL_RWtell((SDL_RWops*)datasource);
slouken@190
    64
}
slouken@190
    65
slouken@190
    66
slouken@190
    67
/* don't call this directly; use Mix_LoadWAV_RW() for now. */
slouken@190
    68
SDL_AudioSpec *Mix_LoadOGG_RW (SDL_RWops *src, int freesrc,
slouken@190
    69
        SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
slouken@190
    70
{
slouken@190
    71
    OggVorbis_File vf;
slouken@190
    72
    ov_callbacks callbacks;
slouken@190
    73
    vorbis_info *info;
slouken@190
    74
    Uint8 *buf;
slouken@190
    75
    int bitstream = -1;
slouken@190
    76
    long samplesize;
slouken@190
    77
    long samples;
slouken@190
    78
    int read, to_read;
slouken@190
    79
    int must_close = 1;
slouken@190
    80
    int was_error = 1;
slouken@190
    81
    
slouken@190
    82
    if ( (!src) || (!audio_buf) || (!audio_len) )   /* sanity checks. */
slouken@190
    83
        goto done;
slouken@190
    84
slouken@470
    85
    if ( !Mix_Init(MIX_INIT_OGG) )
slouken@312
    86
        goto done;
slouken@312
    87
slouken@190
    88
    callbacks.read_func = sdl_read_func;
slouken@190
    89
    callbacks.seek_func = sdl_seek_func;
slouken@190
    90
    callbacks.tell_func = sdl_tell_func;
slouken@190
    91
    callbacks.close_func = freesrc ? 
slouken@190
    92
                           sdl_close_func_freesrc : sdl_close_func_nofreesrc;
slouken@190
    93
slouken@312
    94
    if (vorbis.ov_open_callbacks(src, &vf, NULL, 0, callbacks) != 0)
slouken@190
    95
    {
slouken@190
    96
        SDL_SetError("OGG bitstream is not valid Vorbis stream!");
slouken@190
    97
        goto done;
slouken@190
    98
    }
slouken@190
    99
slouken@190
   100
    must_close = 0;
slouken@190
   101
    
slouken@312
   102
    info = vorbis.ov_info(&vf, -1);
slouken@190
   103
    
slouken@190
   104
    *audio_buf = NULL;
slouken@190
   105
    *audio_len = 0;
slouken@190
   106
    memset(spec, '\0', sizeof (SDL_AudioSpec));
slouken@190
   107
slouken@190
   108
    spec->format = AUDIO_S16;
slouken@190
   109
    spec->channels = info->channels;
slouken@190
   110
    spec->freq = info->rate;
slouken@190
   111
    spec->samples = 4096; /* buffer size */
slouken@190
   112
    
slouken@312
   113
    samples = (long)vorbis.ov_pcm_total(&vf, -1);
slouken@190
   114
slouken@190
   115
    *audio_len = spec->size = samples * spec->channels * 2;
slouken@561
   116
    *audio_buf = SDL_malloc(*audio_len);
slouken@190
   117
    if (*audio_buf == NULL)
slouken@190
   118
        goto done;
slouken@190
   119
slouken@190
   120
    buf = *audio_buf;
slouken@190
   121
    to_read = *audio_len;
slouken@353
   122
#ifdef OGG_USE_TREMOR
slouken@353
   123
    for (read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream);
slouken@353
   124
	 read > 0;
slouken@353
   125
	 read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream))
slouken@353
   126
#else
slouken@312
   127
    for (read = vorbis.ov_read(&vf, (char *)buf, to_read, 0/*LE*/, 2/*16bit*/, 1/*signed*/, &bitstream);
slouken@190
   128
         read > 0;
slouken@312
   129
         read = vorbis.ov_read(&vf, (char *)buf, to_read, 0, 2, 1, &bitstream))
slouken@353
   130
#endif	 
slouken@190
   131
    {
slouken@190
   132
        if (read == OV_HOLE || read == OV_EBADLINK)
slouken@190
   133
            break; /* error */
slouken@190
   134
        
slouken@190
   135
        to_read -= read;
slouken@190
   136
        buf += read;
slouken@190
   137
    }
slouken@190
   138
slouken@312
   139
    vorbis.ov_clear(&vf);
slouken@190
   140
    was_error = 0;
slouken@190
   141
slouken@190
   142
    /* Don't return a buffer that isn't a multiple of samplesize */
slouken@190
   143
    samplesize = ((spec->format & 0xFF)/8)*spec->channels;
slouken@190
   144
    *audio_len &= ~(samplesize-1);
slouken@190
   145
slouken@190
   146
done:
slouken@190
   147
    if (src && must_close)
slouken@190
   148
    {
slouken@190
   149
        if (freesrc)
slouken@190
   150
            SDL_RWclose(src);
slouken@190
   151
        else
slouken@473
   152
            SDL_RWseek(src, 0, RW_SEEK_SET);
slouken@190
   153
    }
slouken@190
   154
slouken@190
   155
    if ( was_error )
slouken@190
   156
        spec = NULL;
slouken@190
   157
slouken@190
   158
    return(spec);
slouken@190
   159
} /* Mix_LoadOGG_RW */
slouken@190
   160
slouken@190
   161
/* end of load_ogg.c ... */
slouken@190
   162
slouken@190
   163
#endif