Skip to content

Commit

Permalink
Broken up code in Media
Browse files Browse the repository at this point in the history
  • Loading branch information
captainurist committed Nov 9, 2023
1 parent 0178506 commit 6c8b2ec
Show file tree
Hide file tree
Showing 24 changed files with 520 additions and 453 deletions.
5 changes: 3 additions & 2 deletions src/Media/Audio/AudioPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
#include "Engine/Engine.h"
#include "Engine/MapInfo.h"

#include "Media/Audio/OpenALSoundProvider.h"

#include "GUI/GUIWindow.h"

#include "Media/AudioBufferDataSource.h"

#include "Library/Compression/Compression.h"
#include "Library/Logger/Logger.h"

Expand All @@ -29,6 +29,7 @@
#include "OpenALTrack16.h"
#include "OpenALSample16.h"
#include "OpenALAudioDataSource.h"
#include "OpenALSoundProvider.h"

std::unique_ptr<AudioPlayer> pAudioPlayer;

Expand Down
2 changes: 1 addition & 1 deletion src/Media/Audio/AudioPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "Engine/Spells/SpellEnums.h"
#include "Engine/Objects/ActorEnums.h"

#include "Media/Media.h"
#include "Media/AudioTrack.h"

#include "Utility/String.h"
#include "Utility/Memory/Blob.h"
Expand Down
2 changes: 1 addition & 1 deletion src/Media/Audio/AudioSamplePool.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include "Engine/Pid.h"

#include "Media/Media.h"
#include "Media/AudioSample.h"

#include "SoundEnums.h"

Expand Down
2 changes: 1 addition & 1 deletion src/Media/Audio/OpenALAudioDataSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include <AL/al.h> // NOLINT: not a system C header.

#include "Media/Media.h"
#include "Media/AudioDataSource.h"

// TODO(Nik-RE-dev): this middleware class is temporary because Media API is not fully
// ready to properly support current use cases
Expand Down
5 changes: 3 additions & 2 deletions src/Media/Audio/OpenALSample16.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

#include <AL/al.h>

#include "Library/Geometry/Vec.h"
#include "Media/AudioDataSource.h"
#include "Media/AudioSample.h"

#include "Media/Media.h"
#include "Library/Geometry/Vec.h"

class AudioSample16 : public IAudioSample {
public:
Expand Down
2 changes: 2 additions & 0 deletions src/Media/Audio/OpenALTrack16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <memory>

#include "Media/AudioFileDataSource.h"

#include "Library/Logger/Logger.h"

#include "OpenALSoundProvider.h"
Expand Down
2 changes: 1 addition & 1 deletion src/Media/Audio/OpenALTrack16.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include <AL/al.h> // NOLINT: not a C system header.

#include "Media/Media.h"
#include "Media/AudioTrack.h"

#include "OpenALUpdateThread.h"

Expand Down
4 changes: 2 additions & 2 deletions src/Media/Audio/SoundInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
#include <string>
#include <memory>

#include "Utility/Memory/Blob.h"
#include "Media/AudioDataSource.h"

#include "Media/Media.h"
#include "Utility/Memory/Blob.h"

#include "SoundEnums.h"

Expand Down
167 changes: 167 additions & 0 deletions src/Media/AudioBaseDataSource.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#include "AudioBaseDataSource.h"

#include <utility>

#include "Library/Logger/Logger.h"

AudioBaseDataSource::AudioBaseDataSource() {
pFormatContext = nullptr;
iStreamIndex = -1;
pCodecContext = nullptr;
pConverter = nullptr;
bOpened = false;
}

bool AudioBaseDataSource::Open() {
// Retrieve stream information
if (avformat_find_stream_info(pFormatContext, nullptr) < 0) {
Close();
logger->warning("ffmpeg: Unable to find stream info");
return false;
}

#if LIBAVFORMAT_VERSION_MAJOR >= 59
const AVCodec *codec = nullptr;
#else
AVCodec *codec = nullptr;
#endif
iStreamIndex = av_find_best_stream(pFormatContext, AVMEDIA_TYPE_AUDIO, -1,
-1, &codec, 0);
if (iStreamIndex < 0) {
Close();
logger->warning("ffmpeg: Unable to find audio stream");
return false;
}

AVStream *stream = pFormatContext->streams[iStreamIndex];
pCodecContext = avcodec_alloc_context3(codec);
if (pCodecContext == nullptr) {
Close();
return false;
}

if (avcodec_parameters_to_context(pCodecContext, stream->codecpar) < 0) {
Close();
return false;
}
if (avcodec_open2(pCodecContext, codec, nullptr) < 0) {
Close();
return false;
}

if (!pCodecContext->channel_layout) {
switch (pCodecContext->channels) {
case(1):
pCodecContext->channel_layout = AV_CH_LAYOUT_MONO;
break;
case(2):
pCodecContext->channel_layout = AV_CH_LAYOUT_STEREO;
break;
default:
assert(false);
break;
}
}

pConverter = swr_alloc_set_opts(
pConverter,
pCodecContext->channel_layout,
AV_SAMPLE_FMT_S16, pCodecContext->sample_rate,
pCodecContext->channel_layout,
pCodecContext->sample_fmt, pCodecContext->sample_rate, 0, nullptr);
if (swr_init(pConverter) < 0) {
Close();
logger->warning("ffmpeg: Failed to create converter");
return false;
}

bOpened = true;

return true;
}

void AudioBaseDataSource::Close() {
if (pConverter != nullptr) {
swr_free(&pConverter);
pConverter = nullptr;
}

if (pCodecContext) {
avcodec_close(pCodecContext);
pCodecContext = nullptr;
}

iStreamIndex = -1;

if (pFormatContext != nullptr) {
avformat_close_input(&pFormatContext);
pFormatContext = nullptr;
}

bOpened = false;
}

size_t AudioBaseDataSource::GetSampleRate() {
if (pCodecContext == nullptr) {
return 0;
}

return pCodecContext->sample_rate;
}

size_t AudioBaseDataSource::GetChannelCount() {
if (pCodecContext == nullptr) {
return 0;
}

return pCodecContext->channels;
}

std::shared_ptr<Blob> AudioBaseDataSource::GetNextBuffer() {
std::shared_ptr<Blob> buffer;

if (!queue.empty()) {
buffer = queue.front();
queue.pop();
}

AVPacket *packet = av_packet_alloc();

if (av_read_frame(pFormatContext, packet) >= 0) {
if (avcodec_send_packet(pCodecContext, packet) >= 0) {
std::shared_ptr<Blob> result;
AVFrame *frame = av_frame_alloc();
int res = 0;
while (res >= 0) {
res = avcodec_receive_frame(pCodecContext, frame);
if (res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
break;
}
if (res < 0) {
return buffer;
}
size_t tmp_size = frame->nb_samples * pCodecContext->channels * 2;
std::unique_ptr<void, FreeDeleter> tmp_buf(malloc(tmp_size));
uint8_t *dst_channels[8] = { static_cast<uint8_t *>(tmp_buf.get()) };
int got_samples = swr_convert(
pConverter, dst_channels, frame->nb_samples,
(const uint8_t **)frame->data, frame->nb_samples);

std::shared_ptr<Blob> tmp_blob = std::make_shared<Blob>(Blob::fromMalloc(std::move(tmp_buf), tmp_size));

if (got_samples > 0) {
if (!buffer) {
buffer = tmp_blob;
} else {
queue.push(tmp_blob);
}
}
}
av_frame_free(&frame);
}
}

av_packet_free(&packet);

return buffer;
}
34 changes: 34 additions & 0 deletions src/Media/AudioBaseDataSource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include <queue>
#include <deque>
#include <memory>

extern "C" {
#include <libavcodec/avcodec.h> // NOLINT
#include <libavformat/avformat.h> // NOLINT
#include <libswresample/swresample.h> // NOLINT
}

#include "AudioDataSource.h"

class AudioBaseDataSource : public IAudioDataSource {
public:
AudioBaseDataSource();
virtual ~AudioBaseDataSource() { Close(); }

virtual bool Open() override;
virtual void Close() override;

virtual size_t GetSampleRate() override;
virtual size_t GetChannelCount() override;
virtual std::shared_ptr<Blob> GetNextBuffer() override;

protected:
AVFormatContext *pFormatContext;
int iStreamIndex;
AVCodecContext *pCodecContext;
SwrContext *pConverter;
bool bOpened;
std::queue<std::shared_ptr<Blob>, std::deque<std::shared_ptr<Blob>>> queue;
};
101 changes: 101 additions & 0 deletions src/Media/AudioBufferDataSource.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include "AudioBufferDataSource.h"

#include <algorithm>
#include <utility>

#include "Library/Logger/Logger.h"

AudioBufferDataSource::AudioBufferDataSource(Blob buffer) : buffer(std::move(buffer)) {
buf_pos = nullptr;
buf_end = nullptr;
avio_ctx_buffer = nullptr;
avio_ctx_buffer_size = 4096;
avio_ctx = nullptr;
}

bool AudioBufferDataSource::Open() {
if (bOpened) {
return true;
}

pFormatContext = avformat_alloc_context();
if (pFormatContext == nullptr) {
return false;
}

avio_ctx_buffer = (uint8_t *)av_malloc(avio_ctx_buffer_size);
if (avio_ctx_buffer == nullptr) {
Close();
return false;
}

avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size, 0,
this, &read_packet, nullptr, &seek);
if (!avio_ctx) {
Close();
return false;
}

pFormatContext->pb = avio_ctx;

buf_pos = static_cast<const uint8_t *>(buffer.data());
buf_end = buf_pos + buffer.size();

// Open audio file
if (avformat_open_input(&pFormatContext, nullptr, nullptr, nullptr) < 0) {
logger->warning("ffmpeg: Unable to open input buffer");
return false;
}

// Dump information about buffer onto standard error
av_dump_format(pFormatContext, 0, nullptr, 0);

return AudioBaseDataSource::Open();
}

int AudioBufferDataSource::read_packet(void *opaque, uint8_t *buf,
int buf_size) {
AudioBufferDataSource *pThis = (AudioBufferDataSource *)opaque;
return pThis->ReadPacket(buf, buf_size);
}

int AudioBufferDataSource::ReadPacket(uint8_t *buf, int buf_size) {
int size = buf_end - buf_pos;
if (size <= 0) {
return AVERROR_EOF;
}
size = std::min(buf_size, size);
memcpy(buf, buf_pos, size);
buf_pos += size;
return size;
}

int64_t AudioBufferDataSource::seek(void *opaque, int64_t offset, int whence) {
AudioBufferDataSource *pThis = (AudioBufferDataSource *)opaque;
return pThis->Seek(opaque, offset, whence);
}

int64_t AudioBufferDataSource::Seek(void *opaque, int64_t offset, int whence) {
if ((whence & AVSEEK_SIZE) == AVSEEK_SIZE) {
return buffer.size();
}
int force = whence & AVSEEK_FORCE;
whence &= ~AVSEEK_FORCE;
whence &= ~AVSEEK_SIZE;
const uint8_t *buf_start = static_cast<const uint8_t *>(buffer.data());
if (whence == SEEK_SET) {
buf_pos = std::clamp(buf_start + offset, buf_start, buf_end);
return buf_pos - buf_start;
} else if (whence == SEEK_CUR) {
buf_pos = std::clamp(buf_pos + offset, buf_start, buf_end);
return buf_pos - buf_start;
} else if (whence == SEEK_END) {
buf_pos = std::clamp(buf_end + offset, buf_start, buf_end);
return buf_pos - buf_start;
}
return AVERROR(EIO);
}

PAudioDataSource CreateAudioBufferDataSource(Blob buffer) {
return std::make_shared<AudioBufferDataSource>(std::move(buffer));
}
Loading

0 comments on commit 6c8b2ec

Please sign in to comment.