예제 #1
0
CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName, u64 TitleID)
 : m_TitleID(TitleID)
{
	Common::ReadReplacements(replacements);
	strcpy(pathData_bin, FileName);
	memcpy(SD_IV, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10);

	if (!TitleID) // Import
	{
		AES_set_decrypt_key(SDKey, 128, &m_AES_KEY);
		do
		{
			b_valid = true;
			ReadHDR();
			ReadBKHDR();
			ImportWiiSaveFiles();
			// TODO: check_sig()
			if (b_valid)
			{
				SuccessAlertT("Successfully imported save files");
				b_tryAgain = false;
			}
			else
			{
				b_tryAgain = AskYesNoT("Import failed, try again?");
			}
		} while(b_tryAgain);
	}
	else
	{
		AES_set_encrypt_key(SDKey, 128, &m_AES_KEY);
		
		if (getPaths(true))
		{
			do
			{
				b_valid = true;
				WriteHDR();
				WriteBKHDR();
				ExportWiiSaveFiles();
				do_sig();
				if (b_valid)
				{
					SuccessAlertT("Successfully exported file to %s", pathData_bin);
					b_tryAgain = false;
				}
				else
				{
					b_tryAgain = AskYesNoT("Export failed, try again?");
				}
			} while(b_tryAgain);
		}
	}
}
예제 #2
0
bool SysConf::LoadFromFile(const char *filename)
{
	// Basic check
	if (!File::Exists(filename))
	{
		File::CreateFullPath(filename);
		GenerateSysConf();
		return true;
	}

	u64 size = File::GetSize(filename);
	if (size != SYSCONF_SIZE)
	{
		if (AskYesNoT("Your SYSCONF file is the wrong size.\nIt should be 0x%04x (but is 0x%04" PRIx64 ")\nDo you want to generate a new one?",
					SYSCONF_SIZE, size))
		{
			GenerateSysConf();
			return true;
		}
		else
			return false;
	}

	File::IOFile f(filename, "rb");
	if (f.IsOpen())
	{
		if (LoadFromFileInternal(f.ReleaseHandle()))
		{
			m_Filename = filename;
			return true;
		}
	}

	return false;
}
예제 #3
0
static std::string GetDumpPath(const std::string& format)
{
  if (!g_Config.sDumpPath.empty())
    return g_Config.sDumpPath;

  const std::string dump_path = File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump" +
                                std::to_string(s_file_index) + "." + format;

  // Ask to delete file
  if (File::Exists(dump_path))
  {
    if (SConfig::GetInstance().m_DumpFramesSilent ||
        AskYesNoT("Delete the existing file '%s'?", dump_path.c_str()))
    {
      File::Delete(dump_path);
    }
    else
    {
      // Stop and cancel dumping the video
      return "";
    }
  }

  return dump_path;
}
예제 #4
0
// Returns false if the hash fails and the user hits "Yes"
static bool VerifyRoms()
{
  struct DspRomHashes
  {
    u32 hash_irom;  // dsp_rom.bin
    u32 hash_drom;  // dsp_coef.bin
  };

  static const std::array<DspRomHashes, 4> known_roms = {
      {// Official Nintendo ROM
       {0x66f334fe, 0xf3b93527},

       // LM1234 replacement ROM (Zelda UCode only)
       {0x9c8f593c, 0x10000001},

       // delroth's improvement on LM1234 replacement ROM (Zelda and AX only,
       // IPL/Card/GBA still broken)
       {0xd9907f71, 0xb019c2fb},

       // above with improved resampling coefficients
       {0xd9907f71, 0xdb6880c1}}};

  u32 hash_irom = HashAdler32((u8*)g_dsp.irom, DSP_IROM_BYTE_SIZE);
  u32 hash_drom = HashAdler32((u8*)g_dsp.coef, DSP_COEF_BYTE_SIZE);
  int rom_idx = -1;

  for (size_t i = 0; i < known_roms.size(); ++i)
  {
    const DspRomHashes& rom = known_roms[i];
    if (hash_irom == rom.hash_irom && hash_drom == rom.hash_drom)
      rom_idx = static_cast<int>(i);
  }

  if (rom_idx < 0)
  {
    if (AskYesNoT("Your DSP ROMs have incorrect hashes.\n"
                  "Would you like to stop now to fix the problem?\n"
                  "If you select \"No\", audio might be garbled."))
      return false;
  }

  if (rom_idx == 1)
  {
    DSPHost::OSD_AddMessage("You are using an old free DSP ROM made by the Dolphin Team.", 6000);
    DSPHost::OSD_AddMessage("Only games using the Zelda UCode will work correctly.", 6000);
  }
  else if (rom_idx == 2 || rom_idx == 3)
  {
    DSPHost::OSD_AddMessage("You are using a free DSP ROM made by the Dolphin Team.", 8000);
    DSPHost::OSD_AddMessage("All Wii games will work correctly, and most GC games should ", 8000);
    DSPHost::OSD_AddMessage("also work fine, but the GBA/IPL/CARD UCodes will not work.\n", 8000);
  }

  return true;
}
예제 #5
0
void CWiiSaveCrypted::ReadHDR()
{
	File::IOFile fpData_bin(encryptedSavePath, "rb");
	if (!fpData_bin)
	{
		PanicAlertT("Cannot open %s", encryptedSavePath.c_str());
		b_valid = false;
		return;
	}
	if (!fpData_bin.ReadBytes(&_encryptedHeader, HEADER_SZ))
	{
		PanicAlertT("Failed to read header");
		b_valid = false;
		return;
	}
	fpData_bin.Close();

	aes_crypt_cbc(&m_AES_ctx, AES_DECRYPT, HEADER_SZ, SD_IV, (const u8*)&_encryptedHeader, (u8*)&_header);
	u32 bannerSize = Common::swap32(_header.hdr.BannerSize);
	if ((bannerSize < FULL_BNR_MIN) || (bannerSize > FULL_BNR_MAX) ||
		(((bannerSize - BNR_SZ) % ICON_SZ) != 0))
	{
		PanicAlertT("Not a Wii save or read failure for file header size %x", bannerSize);
		b_valid = false;
		return;
	}
	m_TitleID = Common::swap64(_header.hdr.SaveGameTitle);


	u8 md5_file[16];
	u8 md5_calc[16];
	memcpy(md5_file, _header.hdr.Md5, 0x10);
	memcpy(_header.hdr.Md5, MD5_BLANKER, 0x10);
	md5((u8*)&_header, HEADER_SZ, md5_calc);
	if (memcmp(md5_file, md5_calc, 0x10))
	{
		PanicAlertT("MD5 mismatch\n %016" PRIx64 "%016" PRIx64 " != %016" PRIx64 "%016" PRIx64, Common::swap64(md5_file),Common::swap64(md5_file+8), Common::swap64(md5_calc), Common::swap64(md5_calc+8));
		b_valid= false;
	}

	if (!getPaths())
	{
		b_valid = false;
		return;
	}
	std::string BannerFilePath = WiiTitlePath + "banner.bin";
	if (!File::Exists(BannerFilePath) || AskYesNoT("%s already exists, overwrite?", BannerFilePath.c_str()))
	{
		INFO_LOG(CONSOLE, "Creating file %s", BannerFilePath.c_str());
		File::IOFile fpBanner_bin(BannerFilePath, "wb");
		fpBanner_bin.WriteBytes(_header.BNR, bannerSize);
	}
}
예제 #6
0
파일: DSPCore.cpp 프로젝트: Idan345/dolphin
// Returns false iff the hash fails and the user hits "Yes"
static bool VerifyRoms(const char *irom_filename, const char *coef_filename)
{
	struct DspRomHashes
	{
		u32 hash_irom; // dsp_rom.bin
		u32 hash_drom; // dsp_coef.bin
	} KNOWN_ROMS[] = {
		// Official Nintendo ROM
		{ 0x66f334fe, 0xf3b93527 },

		// LM1234 replacement ROM (Zelda UCode only)
		{ 0x9c8f593c, 0x10000001 },

		// delroth's improvement on LM1234 replacement ROM (Zelda and AX only,
		// IPL/Card/GBA still broken)
		{ 0xd9907f71, 0xb019c2fb }
	};

	u32 hash_irom = HashAdler32((u8*)g_dsp.irom, DSP_IROM_BYTE_SIZE);
	u32 hash_drom = HashAdler32((u8*)g_dsp.coef, DSP_COEF_BYTE_SIZE);
	int rom_idx = -1;

	for (u32 i = 0; i < sizeof (KNOWN_ROMS) / sizeof (KNOWN_ROMS[0]); ++i)
	{
		DspRomHashes& rom = KNOWN_ROMS[i];
		if (hash_irom == rom.hash_irom && hash_drom == rom.hash_drom)
			rom_idx = i;
	}

	if (rom_idx < 0)
	{
		if (AskYesNoT("Your DSP ROMs have incorrect hashes.\n"
			"Would you like to stop now to fix the problem?\n"
			"If you select \"No\", audio might be garbled."))
			return false;
	}

	if (rom_idx == 1)
	{
		DSPHost_OSD_AddMessage("You are using an old free DSP ROM made by the Dolphin Team.", 6000);
		DSPHost_OSD_AddMessage("Only games using the Zelda UCode will work correctly.", 6000);
	}

	if (rom_idx == 2)
	{
		DSPHost_OSD_AddMessage("You are using a free DSP ROM made by the Dolphin Team.", 8000);
		DSPHost_OSD_AddMessage("All Wii games will work correctly, and most GC games should ", 8000);
		DSPHost_OSD_AddMessage("also work fine, but the GBA/IPL/CARD UCodes will not work.\n", 8000);
	}

	return true;
}
예제 #7
0
void GamepadPage::DeleteProfile(wxCommandEvent&)
{
	std::string fname;
	GamepadPage::GetProfilePath(fname);

	const char* const fnamecstr = fname.c_str();

	if (File::Exists(fnamecstr) &&
			AskYesNoT("Are you sure you want to delete \"%s\"?",
			STR_FROM_WXSTR(profile_cbox->GetValue()).c_str()))
	{
		File::Delete(fnamecstr);

		m_config_dialog->UpdateProfileComboBox();
	}
}
예제 #8
0
bool Renderer::StartFrameDumpToImage(const FrameDumpConfig& config)
{
  m_frame_dump_image_counter = 1;
  if (!SConfig::GetInstance().m_DumpFramesSilent)
  {
    // Only check for the presence of the first image to confirm overwriting.
    // A previous run will always have at least one image, and it's safe to assume that if the user
    // has allowed the first image to be overwritten, this will apply any remaining images as well.
    std::string filename = GetFrameDumpNextImageFileName();
    if (File::Exists(filename))
    {
      if (!AskYesNoT("Frame dump image(s) '%s' already exists. Overwrite?", filename.c_str()))
        return false;
    }
  }

  return true;
}
예제 #9
0
파일: AVIDump.cpp 프로젝트: jloehr/dolphin
bool AVIDump::CreateFile()
{
  AVCodec* codec = nullptr;

  s_format_context = avformat_alloc_context();
  std::stringstream s_file_index_str;
  s_file_index_str << s_file_index;
  snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s",
           (File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump" + s_file_index_str.str() + ".avi")
               .c_str());
  File::CreateFullPath(s_format_context->filename);

  // Ask to delete file
  if (File::Exists(s_format_context->filename))
  {
    if (SConfig::GetInstance().m_DumpFramesSilent ||
        AskYesNoT("Delete the existing file '%s'?", s_format_context->filename))
    {
      File::Delete(s_format_context->filename);
    }
    else
    {
      // Stop and cancel dumping the video
      return false;
    }
  }

  if (!(s_format_context->oformat = av_guess_format("avi", nullptr, nullptr)) ||
      !(s_stream = avformat_new_stream(s_format_context, codec)))
  {
    return false;
  }

  s_stream->codec->codec_id =
      g_Config.bUseFFV1 ? AV_CODEC_ID_FFV1 : s_format_context->oformat->video_codec;
  if (!g_Config.bUseFFV1)
    s_stream->codec->codec_tag =
        MKTAG('X', 'V', 'I', 'D');  // Force XVID FourCC for better compatibility
  s_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  s_stream->codec->bit_rate = 400000;
  s_stream->codec->width = s_width;
  s_stream->codec->height = s_height;
  s_stream->codec->time_base.num = 1;
  s_stream->codec->time_base.den = VideoInterface::GetTargetRefreshRate();
  s_stream->codec->gop_size = 12;
  s_stream->codec->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P;

  if (!(codec = avcodec_find_encoder(s_stream->codec->codec_id)) ||
      (avcodec_open2(s_stream->codec, codec, nullptr) < 0))
  {
    return false;
  }

  s_src_frame = av_frame_alloc();
  s_scaled_frame = av_frame_alloc();

  s_scaled_frame->format = s_stream->codec->pix_fmt;
  s_scaled_frame->width = s_width;
  s_scaled_frame->height = s_height;

#if LIBAVCODEC_VERSION_MAJOR >= 55
  if (av_frame_get_buffer(s_scaled_frame, 1))
    return false;
#else
  if (avcodec_default_get_buffer(s_stream->codec, s_scaled_frame))
    return false;
#endif

  NOTICE_LOG(VIDEO, "Opening file %s for dumping", s_format_context->filename);
  if (avio_open(&s_format_context->pb, s_format_context->filename, AVIO_FLAG_WRITE) < 0 ||
      avformat_write_header(s_format_context, nullptr))
  {
    WARN_LOG(VIDEO, "Could not open %s", s_format_context->filename);
    return false;
  }

  OSD::AddMessage(StringFromFormat("Dumping Frames to \"%s\" (%dx%d)", s_format_context->filename,
                                   s_width, s_height));

  return true;
}
예제 #10
0
bool AVIDump::CreateFile()
{
	m_totalBytes = 0;
	m_frameCount = 0;

	std::string movie_file_name = StringFromFormat("%sframedump%d.avi", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), m_fileCount);

	// Create path
	File::CreateFullPath(movie_file_name);

	// Ask to delete file
	if (File::Exists(movie_file_name))
	{
		if (AskYesNoT("Delete the existing file '%s'?", movie_file_name.c_str()))
			File::Delete(movie_file_name);
	}

	AVIFileInit();
	NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name.c_str());
	// TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG
	HRESULT hr = AVIFileOpenA(&m_file, movie_file_name.c_str(), OF_WRITE | OF_CREATE, nullptr);
	if (FAILED(hr))
	{
		if (hr == AVIERR_BADFORMAT) NOTICE_LOG(VIDEO, "The file couldn't be read, indicating a corrupt file or an unrecognized format.");
		if (hr == AVIERR_MEMORY)  NOTICE_LOG(VIDEO, "The file could not be opened because of insufficient memory.");
		if (hr == AVIERR_FILEREAD) NOTICE_LOG(VIDEO, "A disk error occurred while reading the file.");
		if (hr == AVIERR_FILEOPEN) NOTICE_LOG(VIDEO, "A disk error occurred while opening the file.");
		if (hr == REGDB_E_CLASSNOTREG) NOTICE_LOG(VIDEO, "AVI class not registered");
		Stop();
		return false;
	}

	SetBitmapFormat();
	NOTICE_LOG(VIDEO, "Setting video format...");
	if (!SetVideoFormat())
	{
		NOTICE_LOG(VIDEO, "Setting video format failed");
		Stop();
		return false;
	}

	if (!m_fileCount)
	{
		if (!SetCompressionOptions())
		{
			NOTICE_LOG(VIDEO, "SetCompressionOptions failed");
			Stop();
			return false;
		}
	}

	if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, nullptr)))
	{
		NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed");
		Stop();
		return false;
	}

	if (FAILED(AVIStreamSetFormat(m_streamCompressed, 0, &m_bitmap, m_bitmap.biSize)))
	{
		NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed");
		Stop();
		return false;
	}

	return true;
}
예제 #11
0
bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRate)
{
  // Ask to delete file
  if (File::Exists(filename))
  {
    if (SConfig::GetInstance().m_DumpAudioSilent ||
        AskYesNoT("Delete the existing file '%s'?", filename.c_str()))
    {
      File::Delete(filename);
    }
    else
    {
      // Stop and cancel dumping the audio
      return false;
    }
  }

  // Check if the file is already open
  if (file)
  {
    PanicAlertT("The file %s was already open, the file header will not be written.",
                filename.c_str());
    return false;
  }

  file.Open(filename, "wb");
  if (!file)
  {
    PanicAlertT("The file %s could not be opened for writing. Please check if it's already opened "
                "by another program.",
                filename.c_str());
    return false;
  }

  audio_size = 0;

  if (basename.empty())
    SplitPath(filename, nullptr, &basename, nullptr);

  current_sample_rate = HLESampleRate;

  // -----------------
  // Write file header
  // -----------------
  Write4("RIFF");
  Write(100 * 1000 * 1000);  // write big value in case the file gets truncated
  Write4("WAVE");
  Write4("fmt ");

  Write(16);          // size of fmt block
  Write(0x00020001);  // two channels, uncompressed

  const u32 sample_rate = HLESampleRate;
  Write(sample_rate);
  Write(sample_rate * 2 * 2);  // two channels, 16bit

  Write(0x00100004);
  Write4("data");
  Write(100 * 1000 * 1000 - 32);

  // We are now at offset 44
  if (file.Tell() != 44)
    PanicAlert("Wrong offset: %lld", (long long)file.Tell());

  return true;
}
예제 #12
0
bool AVIDump::CreateFile()
{
	AVCodec* codec = nullptr;

	s_format_context = avformat_alloc_context();
	snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s",
	         (File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump0.avi").c_str());
	File::CreateFullPath(s_format_context->filename);

	// Ask to delete file
	if (File::Exists(s_format_context->filename))
	{
		if (SConfig::GetInstance().m_DumpFramesSilent ||
			AskYesNoT("Delete the existing file '%s'?", s_format_context->filename))
		{
			File::Delete(s_format_context->filename);
		}
		else
		{
			// Stop and cancel dumping the video
			return false;
		}
	}

	if (!(s_format_context->oformat = av_guess_format("avi", nullptr, nullptr)) ||
	    !(s_stream = avformat_new_stream(s_format_context, codec)))
	{
		return false;
	}

	s_stream->codec->codec_id = g_Config.bUseFFV1 ? AV_CODEC_ID_FFV1
	                                              : s_format_context->oformat->video_codec;
	if (!g_Config.bUseFFV1)
		s_stream->codec->codec_tag = MKTAG('X', 'V', 'I', 'D'); // Force XVID FourCC for better compatibility
	s_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
	s_stream->codec->bit_rate = 400000;
	s_stream->codec->width = s_width;
	s_stream->codec->height = s_height;
	s_stream->codec->time_base.num = 1;
	s_stream->codec->time_base.den = VideoInterface::TargetRefreshRate;
	s_stream->codec->gop_size = 12;
	s_stream->codec->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P;

	if (!(codec = avcodec_find_encoder(s_stream->codec->codec_id)) ||
	    (avcodec_open2(s_stream->codec, codec, nullptr) < 0))
	{
		return false;
	}

	s_src_frame = av_frame_alloc();
	s_scaled_frame = av_frame_alloc();

	s_size = avpicture_get_size(s_stream->codec->pix_fmt, s_width, s_height);

	s_yuv_buffer = new uint8_t[s_size];
	avpicture_fill((AVPicture*)s_scaled_frame, s_yuv_buffer, s_stream->codec->pix_fmt, s_width, s_height);

	NOTICE_LOG(VIDEO, "Opening file %s for dumping", s_format_context->filename);
	if (avio_open(&s_format_context->pb, s_format_context->filename, AVIO_FLAG_WRITE) < 0)
	{
		WARN_LOG(VIDEO, "Could not open %s", s_format_context->filename);
		return false;
	}

	avformat_write_header(s_format_context, nullptr);

	return true;
}
예제 #13
0
void CWiiSaveCrypted::ImportWiiSaveFiles()
{
	if (!b_valid) return;

	File::IOFile fpData_bin(pathData_bin, "rb");
	if (!fpData_bin)
	{
		PanicAlertT("Cannot open %s", pathData_bin);
		b_valid = false;
		return;
	}

	fpData_bin.Seek(HEADER_SZ + BK_SZ, SEEK_SET);


	FileHDR _tmpFileHDR;

	for(u32 i = 0; i < _numberOfFiles; i++)
	{
		memset(&_tmpFileHDR, 0, FILE_HDR_SZ);
		memset(IV, 0, 0x10);
		_fileSize = 0;
		
		if (!fpData_bin.ReadBytes(&_tmpFileHDR, FILE_HDR_SZ))
		{
			PanicAlertT("Failed to write header for file %d", i);
			b_valid = false;
		}
		
		if (Common::swap32(_tmpFileHDR.magic) != FILE_HDR_MAGIC)
		{
			PanicAlertT("Bad File Header");
			break;
		}
		else
		{
			std::string fileName ((char*)_tmpFileHDR.name);
			for (Common::replace_v::const_iterator iter = replacements.begin(); iter != replacements.end(); ++iter)
			{
				for (size_t j = 0; (j = fileName.find(iter->first, j)) != fileName.npos; ++j)
					fileName.replace(j, 1, iter->second);
			}

			std::string fullFilePath = WiiTitlePath + fileName;
			File::CreateFullPath(fullFilePath);
			if (_tmpFileHDR.type == 1)
			{
				_fileSize = Common::swap32(_tmpFileHDR.size);
				u32 RoundedFileSize = ROUND_UP(_fileSize, BLOCK_SZ);
				_encryptedData = new u8[RoundedFileSize];
				_data = new u8[RoundedFileSize];
				if (!fpData_bin.ReadBytes(_encryptedData, RoundedFileSize))
				{
					PanicAlertT("Failed to read data from file %d", i);
					b_valid = false;
					break;
				}
				
				
				memcpy(IV, _tmpFileHDR.IV, 0x10);
				AES_cbc_encrypt((const unsigned char *)_encryptedData, _data, RoundedFileSize, &m_AES_KEY, IV, AES_DECRYPT);
				delete []_encryptedData;
	
				if (!File::Exists(fullFilePath) || AskYesNoT("%s already exists, overwrite?", fullFilePath.c_str()))
				{
					INFO_LOG(CONSOLE, "Creating file %s", fullFilePath.c_str());
	
					File::IOFile fpRawSaveFile(fullFilePath, "wb");
					fpRawSaveFile.WriteBytes(_data, _fileSize);
				}
				delete []_data;
			}
		}	
	}
}
예제 #14
0
bool AVIDump::CreateFile()
{
	s_total_bytes = 0;
	s_frame_count = 0;

	std::string movie_file_name = "";

	//Dragonbane: Movie Logic
	bool lastSide = false;

	movie_file_name = GetCurrDumpFile(s_file_count, false);

	if (Movie::cmp_isRunning)
	{
		if (Movie::cmp_leftFinished || Movie::cmp_rightFinished)
			lastSide = true;
	}

	if (!lastSide) //Dragonbane: Stay silent if last side is recorded
	{
		// Create path
		File::CreateFullPath(movie_file_name);

		// Ask to delete file
		if (File::Exists(movie_file_name))
		{
			if (SConfig::GetInstance().m_DumpFramesSilent ||
				AskYesNoT("Delete the existing file '%s'?", movie_file_name.c_str()))
			{
				File::Delete(movie_file_name);
			}
		}
	}

	AVIFileInit();
	NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name.c_str());

	// TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG
	HRESULT hr = AVIFileOpenA(&s_file, movie_file_name.c_str(), OF_WRITE | OF_CREATE, nullptr);

	if (FAILED(hr))
	{
		if (hr == AVIERR_BADFORMAT) NOTICE_LOG(VIDEO, "The file couldn't be read, indicating a corrupt file or an unrecognized format.");
		if (hr == AVIERR_MEMORY)  NOTICE_LOG(VIDEO, "The file could not be opened because of insufficient memory.");
		if (hr == AVIERR_FILEREAD) NOTICE_LOG(VIDEO, "A disk error occurred while reading the file.");
		if (hr == AVIERR_FILEOPEN) NOTICE_LOG(VIDEO, "A disk error occurred while opening the file.");
		if (hr == REGDB_E_CLASSNOTREG) NOTICE_LOG(VIDEO, "AVI class not registered");
		Stop();
		return false;
	}

	SetBitmapFormat();
	NOTICE_LOG(VIDEO, "Setting video format...");
	if (!SetVideoFormat())
	{
		NOTICE_LOG(VIDEO, "Setting video format failed");
		Stop();
		return false;
	}

	if (!s_file_count && !lastSide) //Dragonbane: Stay silent and re-use settings if last side is recorded
	{
		if (!SetCompressionOptions())
		{
			NOTICE_LOG(VIDEO, "SetCompressionOptions failed");
			Stop();
			return false;
		}
	}

	if (FAILED(AVIMakeCompressedStream(&s_stream_compressed, s_stream, &s_options, nullptr)))
	{
		NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed");
		Stop();
		return false;
	}

	if (FAILED(AVIStreamSetFormat(s_stream_compressed, 0, &s_bitmap, s_bitmap.biSize)))
	{
		NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed");
		Stop();
		return false;
	}

	return true;
}