#include "sources/soundsourceffmpeg.h"
#include <mutex>
#include "util/logger.h"
#include "util/sample.h"
#if !defined(VERBOSE_DEBUG_LOG)
#define VERBOSE_DEBUG_LOG false
#endif
namespace mixxx {
namespace {
// FFmpeg constants
constexpr AVSampleFormat kavSampleFormat = AV_SAMPLE_FMT_FLT;
constexpr uint64_t kavChannelLayoutUndefined = 0;
constexpr int64_t kavStreamDefaultStartTime = 0;
// https://ffmpeg.org/doxygen/trunk/structAVPacket.html#details
// "For audio it may contain several compressed frames."
// A stream packet may produce multiple stream frames when decoded.
// Buffering more than a few codec frames with samples in advance
// should be unlikely.
// This is just a best guess that needs to be increased once
// warnings about reallocation of the internal sample buffer
// appear in the logs!
constexpr uint64_t kavMaxDecodedFramesPerPacket = 16;
// 0.5 sec @ 96 kHz / 1 sec @ 48 kHz / 1.09 sec @ 44.1 kHz
constexpr FrameCount kDefaultFrameBufferCapacity = 48000;
constexpr FrameCount kMinFrameBufferCapacity = kDefaultFrameBufferCapacity;
inline FrameCount frameBufferCapacityForStream(
const AVStream& avStream) {
DEBUG_ASSERT(kMinFrameBufferCapacity <= kDefaultFrameBufferCapacity);
if (avStream.codecpar->frame_size > 0) {
return math_max(
static_cast<FrameCount>(
avStream.codecpar->frame_size *
kavMaxDecodedFramesPerPacket),
kMinFrameBufferCapacity);
}
return kDefaultFrameBufferCapacity;
}
// "AAC Audio - Encoder Delay and Synchronization: The 2112 Sample Assumption"
// https://developer.apple.com/library/ios/technotes/tn2258/_index.html
// "It must also be assumed that without an explicit value, the playback
// system will trim 2112 samples from the AAC decoder output when starting
// playback from any point in the bitsream."
// See also: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFAppenG/QTFFAppenG.html
constexpr int64_t kavStreamDecoderFrameDelayAAC = 2112;
// Use 0-based sample frame indexing
constexpr SINT kMinFrameIndex = 0;
constexpr SINT kSamplesPerMP3Frame = 1152;
const Logger kLogger("SoundSourceFFmpeg");
std::once_flag initFFmpegLibFlag;
// FFmpeg API Changes:
// https://github.com/FFmpeg/FFmpeg/blob/master/doc/APIchanges
// This function must be called once during startup.
void initFFmpegLib() {
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
av_register_all();
#endif
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
avcodec_register_all();
#endif
}
inline int64_t getStreamChannelLayout(const AVStream& avStream) {
auto channel_layout = avStream.codecpar->channel_layout;
if (channel_layout == kavChannelLayoutUndefined) {
// Workaround: FFmpeg sometimes fails to determine the channel
// layout, e.g. for a mono WAV files with a single channel!
channel_layout = av_get_default_channel_layout(avStream.codecpar->channels);
kLogger.info()
<< "Unknown channel layout -> using default layout"
<< channel_layout
<< "for"
<< avStream.codecpar->channels
<< "channel(s)";
}
return channel_layout;
}
inline int64_t getStreamStartTime(const AVStream& avStream) {
auto start_time = avStream.start_time;
if (start_time == AV_NOPTS_VALUE) {
// This case is not unlikely, e.g. happens when decoding WAV files.
switch (avStream.codecpar->codec_id) {
case AV_CODEC_ID_AAC:
case AV_CODEC_ID_AAC_LATM: {
// Account for the expected decoder delay instead of simply
// using the default start time.
// Not all M4A files encode the start_time correctly, e.g.
// the test file cover-test-itunes-12.7.0-aac.m4a has a valid
// start_time of 0. Unfortunately, this special case is cannot
// detected and compensated.
start_time = math_max(kavStreamDefaultStartTime,