SDL_mixer函数Mix_LoadMUS_RW导致访问冲突
SDL_mixer function Mix_LoadMUS_RW causes Access Violation
我在使用SDL_mixer从内存加载音乐时遇到问题。以下"最小"示例(包括一点错误检查)将始终在音乐::播放中因访问违规而崩溃。
#include <SDLSDL_mixer.h>
#include <SDLSDL.h>
#include <vector>
#include <iostream>
#include <string>
#include <fstream>
class Music {
public:
void play(int loops = 1);
SDL_RWops* m_rw;
std::vector<unsigned char> m_file;
Mix_Music * m_music = nullptr;
};
void Music::play(int loops) {
if (Mix_PlayMusic(m_music, loops) == -1)
std::cout << "Error playing music " + std::string(Mix_GetError()) + " ...n";
}
void readFileToBuffer(std::vector<unsigned char>& buffer, std::string filePath) {
std::ifstream file(filePath, std::ios::binary);
file.seekg(0, std::ios::end);
int fileSize = file.tellg();
file.seekg(0, std::ios::beg);
fileSize -= file.tellg();
buffer.resize(fileSize);
file.read((char *)&(buffer[0]), fileSize);
file.close();
}
void writeFileToBuffer(std::vector<unsigned char>& buffer, std::string filePath) {
std::ofstream file(filePath, std::ios::out | std::ios::binary);
for (size_t i = 0; i < buffer.size(); i++)
file << buffer[i];
file.close();
}
Music loadMusic(std::string filePath) {
Music music;
readFileToBuffer(music.m_file, filePath);
music.m_rw = SDL_RWFromMem(&music.m_file[0], music.m_file.size());
// Uncommenting the next block runs without problems
/*
writeFileToBuffer(music.m_file, filePath);
music.m_rw = SDL_RWFromFile(filePath.c_str(), "r");
*/
if (music.m_rw == nullptr)
std::cout << "Error creating RW " + std::string(Mix_GetError()) + " ...n";
music.m_music = Mix_LoadMUSType_RW(music.m_rw, Mix_MusicType::MUS_OGG, SDL_FALSE);
if (music.m_music == nullptr)
std::cout << "Error creating music " + std::string(Mix_GetError()) + " ...n";
return music;
}
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_AUDIO);
Mix_Init(MIX_INIT_MP3 | MIX_INIT_OGG);
Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 1024);
Music music = loadMusic("Sound/music/XYZ.ogg");
music.play();
std::cin.ignore();
return 0;
}
我的ArchiveManager可以肯定地工作,这也可以看出,因为ucommission将缓冲区写入文件的块并由此创建SDL_RW会运行得很好。我加载的音乐文件只是假设是一个ogg文件,在本例中就是这样,因此从该文件创建SDL_RW可以很好地工作。这意味着没有什么崩溃,音乐从头到尾都能正常播放。
据我所知,音乐课太大了。我只是保留缓冲区m_file和SDL_RW,以确保问题不会来自释放的数据。使用SDL_FALSE运行Mix_LoadMUS_RW还应确保RW未被释放。
值得注意的是,使用Mix_LoadWAV_RW从同一归档文件加载wav文件的类似示例运行良好:
Mix_Chunk * chunk;
std::vector<unsigned char> fileBuf = ArchiveManager::loadFileFromArchive(filePath);
chunk = Mix_LoadWAV_RW(SDL_RWFromConstMem(&fileBuf[0], fileBuf.size()), SDL_TRUE);
在调用Mix_PlayCannel之前,我甚至不会保留缓冲区。此外,我在这里使用SDL_TRUE调用load函数,因为我没有创建显式SDL_RW。尝试类似的方法加载音乐不会有什么不同。
我学习了SDL_mixer源代码,但它对我没有帮助。也许我的知识不够,也许我错过了一些关键的东西。
言归正传:访问违规从哪里来?我如何防止它?
编辑:更改了示例代码,这样任何人都可以直接复制它。所以没有ArchiveManager或类似的东西,只是直接将ogg读取到内存中。关键部分只是loadMusic中的几行。
Music music = loadMusic("Sound/music/XYZ.ogg");
music.play();
第一行将把右边的类Music类型的对象复制到名为Music的新对象中。这将导致向量m_file被复制,包括其中的数据。我们的新对象music的向量的数据显然将存储在与loadMusicoadMusic返回的对象将从堆栈中删除,其向量的数据将被释放,从而使之前创建的Mix_Music对象无效,并在第二行造成访问冲突。
这可以通过只创建一个Music对象来弥补,例如,通过堆上的new创建它,并让loadMusic返回指向该对象的指针。
Music* music = loadMusic("Sound/music/XYZ.ogg");
music->play();
无论如何,在堆上而不是在堆栈上为整个文件分配内存可能是更好的选择,尽管我猜向量在内部会这样做。
这么短的版本,这(我认为)是一个新手的错误,我太专注于指责SDL_Mixer了。坏主意。
- 写入位置0x0000000C时发生访问冲突
- 引发异常:读取访问冲突**dynamicArray**为0x1118235.发生
- 链表中写入访问冲突的未知原因
- C++中的openCV Mat访问冲突
- C++尝试深度复制唯一指针时出现内存访问冲突
- C++ 中动态二维数组的访问冲突
- 从嵌套循环中的 std::list 中删除将返回访问冲突
- 写入访问冲突异常
- 在类 12.exe 中0x7B37FF80 (ucrtbased.dll) 引发异常: 0xC0000005:访问冲突读
- 0xC0000005:访问冲突写入位置0xCDCDCDCD动态分配错误
- 读取访问冲突.这0xCDCDCDCD
- 0xC0000005:访问冲突读取位置 0x00000000. 重载 == 运算符的问题
- 插入数组时违反写访问冲突
- 使用 ReadProcessMemory 获取字符串值的访问冲突
- 尝试通过共享指针使用变量时读取访问冲突
- 堆栈上的 C++ 访问冲突写入异常
- 引发异常:写访问冲突. temp 为 nullptr
- 将静态字符数组中的字符分配给动态分配的字符数组 - 访问冲突
- 在C++中删除双向链表的头节点后出现访问冲突异常
- C++ 读取访问冲突,0xCDCDCDCD