mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 17:52:15 -10:00
188 lines
4.1 KiB
C++
188 lines
4.1 KiB
C++
#include "FFmpegAudioReader.h"
|
|
|
|
namespace
|
|
{
|
|
class AVPacketScope
|
|
{
|
|
AVPacket* _packet;
|
|
public:
|
|
explicit AVPacketScope(AVPacket* av_packet)
|
|
: _packet(av_packet) {
|
|
}
|
|
|
|
~AVPacketScope() {
|
|
av_packet_unref(_packet);
|
|
}
|
|
};
|
|
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 24, 100)
|
|
// This version doesn't have the new packet alloc API
|
|
|
|
AVPacket *av_packet_alloc()
|
|
{
|
|
auto packet = (AVPacket*)av_mallocz(sizeof(AVPacket));
|
|
av_packet_unref(packet);
|
|
return packet;
|
|
}
|
|
|
|
AVPacket *av_packet_clone(AVPacket *src)
|
|
{
|
|
auto ret = av_packet_alloc();
|
|
av_packet_ref(ret, src);
|
|
return ret;
|
|
}
|
|
|
|
void av_packet_free(AVPacket **pkt)
|
|
{
|
|
av_packet_unref(*pkt);
|
|
av_freep(pkt);
|
|
}
|
|
#endif
|
|
} // namespace
|
|
|
|
namespace sound {
|
|
namespace ffmpeg {
|
|
FFmpegAudioReader::FFmpegAudioReader(AVFormatContext* av_format_context, AVCodecContext* codec_ctx,
|
|
int stream_idx) : _stream_idx(stream_idx),
|
|
_format_ctx(av_format_context),
|
|
_codec_ctx(codec_ctx) {
|
|
}
|
|
|
|
bool FFmpegAudioReader::readFrame(AVFrame* decode_frame) {
|
|
// FFmpeg 3.1 and onwards has a new, better packet handling API but that version is relatively new so we still need
|
|
// to support the earlier API. The compatibility code can be removed once the new version is supported by most platforms
|
|
|
|
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
|
// Process pending frames
|
|
auto pending_res = avcodec_receive_frame(_codec_ctx, decode_frame);
|
|
|
|
if (pending_res == 0) {
|
|
// Got a frame
|
|
return true;
|
|
}
|
|
if (pending_res == AVERROR_EOF) {
|
|
// No more frames available
|
|
return false;
|
|
}
|
|
|
|
if (pending_res != AVERROR(EAGAIN)) {
|
|
// Unknown error.
|
|
return false;
|
|
}
|
|
#else
|
|
if (_currentPacket != nullptr) {
|
|
// Got some data left
|
|
int finishedFrame = 0;
|
|
auto bytes_read = avcodec_decode_audio4(_codec_ctx, decode_frame, &finishedFrame, _currentPacket);
|
|
|
|
if (bytes_read < 0) {
|
|
// Error!
|
|
return false;
|
|
}
|
|
|
|
_currentPacket->data += bytes_read;
|
|
_currentPacket->size -= bytes_read;
|
|
|
|
if (_currentPacket->size <= 0) {
|
|
// Done with this packet
|
|
av_packet_free(&_currentPacket);
|
|
}
|
|
|
|
if (finishedFrame) {
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
AVPacket packet;
|
|
while (av_read_frame(_format_ctx, &packet) >= 0) {
|
|
AVPacketScope packet_scope(&packet);
|
|
if (packet.stream_index == _stream_idx) {
|
|
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
|
auto res = avcodec_send_packet(_codec_ctx, &packet);
|
|
|
|
if (res != 0) {
|
|
// Error or EOF
|
|
return false;
|
|
}
|
|
|
|
res = avcodec_receive_frame(_codec_ctx, decode_frame);
|
|
|
|
if (res == 0) {
|
|
// Got a frame
|
|
return true;
|
|
}
|
|
if (res == AVERROR_EOF) {
|
|
// No more frames available
|
|
return false;
|
|
}
|
|
|
|
if (res != AVERROR(EAGAIN)) {
|
|
// Unknown error.
|
|
return false;
|
|
}
|
|
// EGAIN was returned, send new input
|
|
#else
|
|
int finishedFrame = 0;
|
|
auto bytes_read = avcodec_decode_audio4(_codec_ctx, decode_frame, &finishedFrame, &packet);
|
|
|
|
if (bytes_read < packet.size) {
|
|
// Not all data was read
|
|
packet.data += bytes_read;
|
|
packet.size -= bytes_read;
|
|
|
|
_currentPacket = av_packet_clone(&packet);
|
|
}
|
|
|
|
if (finishedFrame) {
|
|
return true;
|
|
}
|
|
|
|
if (bytes_read < 0) {
|
|
// Error
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
|
// Flush decoder
|
|
if (avcodec_send_packet(_codec_ctx, nullptr) != 0) {
|
|
return false;
|
|
}
|
|
|
|
auto flush_res = avcodec_receive_frame(_codec_ctx, decode_frame);
|
|
|
|
if (flush_res == 0) {
|
|
// Got a frame
|
|
return true;
|
|
}
|
|
#else
|
|
AVPacket nullPacket;
|
|
memset(&nullPacket, 0, sizeof(nullPacket));
|
|
nullPacket.data = nullptr;
|
|
nullPacket.size = 0;
|
|
|
|
int finishedFrame = 1;
|
|
auto err = avcodec_decode_audio4(_codec_ctx, decode_frame, &finishedFrame, &nullPacket);
|
|
|
|
if (finishedFrame && err >= 0) {
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
// If we are here then read_frame reached the end or returned an error
|
|
return false;
|
|
}
|
|
FFmpegAudioReader::~FFmpegAudioReader() {
|
|
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(57, 24, 255)
|
|
if (_currentPacket != nullptr) {
|
|
av_packet_unref(_currentPacket);
|
|
av_packet_free(&_currentPacket);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
} // namespace ffmpeg
|
|
} // namespace sound
|