forked from OpenEnroth/OpenEnroth
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0178506
commit 6c8b2ec
Showing
24 changed files
with
520 additions
and
453 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} |
Oops, something went wrong.