Browse Source
Previously, we always loaded entire videos in memory before playing them. `libsmacker` does not provide a streaming API but it does provide a `FILE *` file pointer API. We now take advantage of the `FILE *` API by streaming the videos on platforms that support `fopencookie`. This means faster startup and less memory usage on these platforms.pull/1786/head
6 changed files with 130 additions and 29 deletions
@ -0,0 +1,74 @@ |
|||||||
|
#include "storm_file_wrapper.h" |
||||||
|
|
||||||
|
#ifdef DEVILUTIONX_STORM_FILE_WRAPPER_AVAILABLE |
||||||
|
|
||||||
|
#include "storm/storm.h" |
||||||
|
#include "utils/log.hpp" |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
extern "C" { |
||||||
|
|
||||||
|
#ifdef DEVILUTIONX_STORM_FILE_WRAPPER_IMPL_FOPENCOOKIE |
||||||
|
|
||||||
|
ssize_t SFileCookieRead(void *cookie, char *buf, size_t nbytes) |
||||||
|
{ |
||||||
|
DWORD numRead = 0; |
||||||
|
if (!SFileReadFile(static_cast<HANDLE>(cookie), buf, nbytes, &numRead, nullptr)) { |
||||||
|
const DWORD errCode = SErrGetLastError(); |
||||||
|
if (errCode != STORM_ERROR_HANDLE_EOF) { |
||||||
|
Log("SFileRwRead error: {} ERROR CODE {}", (unsigned int)nbytes, (unsigned int)errCode); |
||||||
|
} |
||||||
|
} |
||||||
|
return numRead; |
||||||
|
} |
||||||
|
|
||||||
|
int SFileCookieSeek(void *cookie, off64_t *pos, int whence) |
||||||
|
{ |
||||||
|
int swhence; |
||||||
|
switch (whence) { |
||||||
|
case SEEK_SET: |
||||||
|
swhence = DVL_FILE_BEGIN; |
||||||
|
break; |
||||||
|
case SEEK_CUR: |
||||||
|
swhence = DVL_FILE_CURRENT; |
||||||
|
break; |
||||||
|
case SEEK_END: |
||||||
|
swhence = DVL_FILE_END; |
||||||
|
break; |
||||||
|
default: |
||||||
|
return -1; |
||||||
|
} |
||||||
|
const std::uint64_t spos = SFileSetFilePointer(static_cast<HANDLE>(cookie), *pos, swhence); |
||||||
|
if (spos == static_cast<std::uint64_t>(-1)) { |
||||||
|
Log("SFileRwSeek error: {}", (unsigned int)SErrGetLastError()); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
*pos = static_cast<off64_t>(spos); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int SFileCookieClose(void *cookie) |
||||||
|
{ |
||||||
|
return SFileCloseFile(static_cast<HANDLE>(cookie)) ? 0 : -1; |
||||||
|
} |
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
#endif |
||||||
|
|
||||||
|
FILE *FILE_FromStormHandle(HANDLE handle) |
||||||
|
{ |
||||||
|
#ifdef DEVILUTIONX_STORM_FILE_WRAPPER_IMPL_FOPENCOOKIE |
||||||
|
cookie_io_functions_t ioFns; |
||||||
|
std::memset(&ioFns, 0, sizeof(ioFns)); |
||||||
|
ioFns.read = &SFileCookieRead; |
||||||
|
ioFns.seek = &SFileCookieSeek; |
||||||
|
ioFns.close = &SFileCookieClose; |
||||||
|
return fopencookie(handle, "rb", ioFns); |
||||||
|
#else |
||||||
|
#error "unimplemented" |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,17 @@ |
|||||||
|
/** A pointer to a Storm file as a `FILE *`. Only available on some platforms. */ |
||||||
|
#pragma once |
||||||
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) |
||||||
|
#include <cstdio> |
||||||
|
|
||||||
|
#include "miniwin/miniwin.h" |
||||||
|
|
||||||
|
#define DEVILUTIONX_STORM_FILE_WRAPPER_AVAILABLE |
||||||
|
#define DEVILUTIONX_STORM_FILE_WRAPPER_IMPL_FOPENCOOKIE |
||||||
|
|
||||||
|
namespace devilution { |
||||||
|
|
||||||
|
FILE *FILE_FromStormHandle(HANDLE handle); |
||||||
|
|
||||||
|
} // namespace devilution
|
||||||
|
|
||||||
|
#endif |
||||||
Loading…
Reference in new issue