mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
FSO doesn't appear to use this any longer. And even when it was enabled the requirements made it largely useless anyway. Removing to clean up cfile a bit and so we don't have to keep maintaining it.
221 lines
5.6 KiB
C++
221 lines
5.6 KiB
C++
|
|
#include "FFmpegContext.h"
|
|
|
|
#include <cstring>
|
|
|
|
namespace {
|
|
const size_t AVIO_BUFFER_SIZE = 8192;
|
|
|
|
int cfileRead(void* ptr, uint8_t* buf, int buf_size) {
|
|
auto cfile = reinterpret_cast<CFILE*>(ptr);
|
|
|
|
auto numRead = cfread(buf, 1, buf_size, cfile);
|
|
|
|
if (numRead == 0) {
|
|
// Read failed
|
|
return -1;
|
|
}
|
|
|
|
return numRead;
|
|
}
|
|
|
|
int64_t cfileSeek(void* ptr, int64_t offset, int whence) {
|
|
auto cfile = reinterpret_cast<CFILE*>(ptr);
|
|
|
|
int op = CF_SEEK_SET;
|
|
switch (whence) {
|
|
case SEEK_SET:
|
|
op = CF_SEEK_SET;
|
|
break;
|
|
case SEEK_CUR:
|
|
op = CF_SEEK_CUR;
|
|
break;
|
|
case SEEK_END:
|
|
op = CF_SEEK_END;
|
|
break;
|
|
case AVSEEK_SIZE:
|
|
return cfilelength(cfile);
|
|
}
|
|
|
|
auto intOff = static_cast<int>(offset);
|
|
if ((int64_t)intOff != offset) {
|
|
// Overflow!!!
|
|
return -1;
|
|
}
|
|
|
|
auto ret = cfseek(cfile, intOff, op);
|
|
|
|
if (ret != 0) {
|
|
// Error
|
|
return -1;
|
|
}
|
|
|
|
// cfseek returns the offset in the archive file (who thought that would be a good idea?)
|
|
return cftell(cfile);
|
|
}
|
|
|
|
int memfile_read(void* opaque, uint8_t* buf, int buf_size) {
|
|
auto memsound = reinterpret_cast<libs::ffmpeg::MemFileCursor*>(opaque);
|
|
auto vec_buf_size = static_cast<SCP_vector<uint8_t>::size_type>(buf_size);
|
|
if ((int)vec_buf_size != buf_size) {
|
|
// Overflow!!!
|
|
return -1;
|
|
}
|
|
|
|
vec_buf_size = std::min(vec_buf_size, memsound->snddata.size() - memsound->cursor_pos);
|
|
|
|
if (vec_buf_size > 0) {
|
|
std::memcpy(buf, memsound->snddata.data() + memsound->cursor_pos, vec_buf_size);
|
|
|
|
memsound->cursor_pos += vec_buf_size;
|
|
|
|
return static_cast<int>(vec_buf_size);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int64_t memfile_seek(void* opaque, int64_t offset, int whence) {
|
|
auto memsound = reinterpret_cast<libs::ffmpeg::MemFileCursor*>(opaque);
|
|
|
|
if (whence == AVSEEK_SIZE) {
|
|
return memsound->snddata.size();
|
|
}
|
|
int64_t cursor_pos = memsound->cursor_pos;
|
|
|
|
switch (whence) {
|
|
case SEEK_SET:
|
|
cursor_pos = offset;
|
|
break;
|
|
case SEEK_CUR:
|
|
cursor_pos += offset;
|
|
break;
|
|
case SEEK_END:
|
|
cursor_pos = memsound->snddata.size() + offset;
|
|
break;
|
|
}
|
|
|
|
memsound->cursor_pos = std::min(static_cast<SCP_vector<uint8_t>::size_type>(cursor_pos), memsound->snddata.size());
|
|
|
|
return static_cast<int64_t>(memsound->cursor_pos);
|
|
}
|
|
|
|
}//namespace
|
|
|
|
namespace libs {
|
|
namespace ffmpeg {
|
|
|
|
MemFileCursor::MemFileCursor(const uint8_t* data, size_t snd_len) : snddata(data, data + snd_len), cursor_pos(0) {
|
|
}
|
|
|
|
MemFileCursor::MemFileCursor() : snddata() , cursor_pos(0) {}
|
|
|
|
FFmpegContext::FFmpegContext(CFILE* inFile) : m_ctx(nullptr), m_file(inFile), m_memsound() {
|
|
Assertion(inFile != nullptr, "Invalid file pointer passed!");
|
|
}
|
|
|
|
FFmpegContext::FFmpegContext(const uint8_t* snddata, size_t snd_len) : m_ctx(nullptr), m_file(nullptr), m_memsound(snddata, snd_len) {
|
|
}
|
|
|
|
FFmpegContext::~FFmpegContext() {
|
|
if (m_ctx) {
|
|
if (m_ctx->pb) {
|
|
if (m_ctx->pb->buffer) {
|
|
av_free(m_ctx->pb->buffer);
|
|
}
|
|
av_free(m_ctx->pb);
|
|
m_ctx->pb = nullptr;
|
|
}
|
|
|
|
avformat_close_input(&m_ctx);
|
|
m_ctx = nullptr;
|
|
}
|
|
|
|
if (m_file) {
|
|
cfclose(m_file);
|
|
m_file = nullptr;
|
|
}
|
|
|
|
}
|
|
|
|
void FFmpegContext::prepare(void *opaque,
|
|
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
|
|
int64_t (*seek)(void *opaque, int64_t offset, int whence)) {
|
|
m_ctx = avformat_alloc_context();
|
|
|
|
if (!m_ctx) {
|
|
throw FFmpegException("Failed to allocate context!");
|
|
}
|
|
|
|
auto avioBuffer = reinterpret_cast<uint8_t*>(av_malloc(AVIO_BUFFER_SIZE));
|
|
|
|
if (!avioBuffer) {
|
|
throw FFmpegException("Failed to allocate IO buffer!");
|
|
}
|
|
|
|
auto ioContext =
|
|
avio_alloc_context(avioBuffer, AVIO_BUFFER_SIZE, 0, opaque, read_packet, nullptr, seek);
|
|
|
|
if (!ioContext) {
|
|
throw FFmpegException("Failed to allocate IO context!");
|
|
}
|
|
|
|
m_ctx->pb = ioContext;
|
|
|
|
auto probe_ret = av_probe_input_buffer2(m_ctx->pb, &m_ctx->iformat, nullptr, nullptr, 0, 0);
|
|
if (probe_ret < 0) {
|
|
char errorStr[1024];
|
|
av_strerror(probe_ret, errorStr, 1024);
|
|
|
|
throw FFmpegException(SCP_string("Could not open movie file! Error: ") + errorStr);
|
|
}
|
|
|
|
m_ctx->flags |= AVFMT_FLAG_CUSTOM_IO;
|
|
|
|
auto ret = avformat_open_input(&m_ctx, nullptr, m_ctx->iformat, nullptr);
|
|
if (ret < 0) {
|
|
char errorStr[1024];
|
|
av_strerror(ret, errorStr, 1024);
|
|
|
|
throw FFmpegException(SCP_string("Could not open movie file! Error: ") + errorStr);
|
|
}
|
|
|
|
ret = avformat_find_stream_info(m_ctx, nullptr);
|
|
if (ret < 0) {
|
|
char errorStr[1024];
|
|
av_strerror(ret, errorStr, 1024);
|
|
|
|
throw FFmpegException(SCP_string("Failed to get stream information! Error: ") + errorStr);
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<FFmpegContext> FFmpegContext::createContext(CFILE* mediaFile) {
|
|
Assertion(mediaFile != nullptr, "File pointer must be valid!");
|
|
|
|
std::unique_ptr<FFmpegContext> instance(new FFmpegContext(mediaFile));
|
|
|
|
instance->prepare(instance->m_file, cfileRead, cfileSeek);
|
|
return instance;
|
|
}
|
|
|
|
|
|
std::unique_ptr<FFmpegContext> FFmpegContext::createContextMem(const uint8_t* snddata, size_t snd_len) {
|
|
std::unique_ptr<FFmpegContext> instance(new FFmpegContext(snddata, snd_len));
|
|
|
|
instance->prepare(&(instance->m_memsound), memfile_read, memfile_seek);
|
|
return instance;
|
|
}
|
|
|
|
std::unique_ptr<FFmpegContext> FFmpegContext::createContext(const SCP_string& path, int dir_type) {
|
|
CFILE* file = cfopen(path.c_str(), "rb", dir_type);
|
|
|
|
if (!file) {
|
|
throw FFmpegException("Failed to open file!");
|
|
}
|
|
|
|
return createContext(file);
|
|
}
|
|
|
|
}
|
|
}
|