Go to the documentation of this file.
28 #include <QRegularExpression>
32 #include <mythconfig.h>
52 #include <libavformat/avio.h>
53 #include <libavutil/opt.h>
104 if (!ch.isNull() && ch ==
'%')
108 else if (!ch.isNull() && (ch ==
'r' || ch ==
'a' || ch ==
'b' || ch ==
't'))
123 LOG(VB_GENERAL, LOG_ERR,
124 QString(
"ShoutCastMetaParser: malformed metaformat '%1'")
141 int title_begin_pos = mdata.indexOf(
"StreamTitle='");
143 if (title_begin_pos >= 0)
145 title_begin_pos += 13;
146 int title_end_pos = mdata.indexOf(
"';", title_begin_pos);
147 QString title = mdata.mid(title_begin_pos, title_end_pos - title_begin_pos);
149 auto match = rx.match(title);
150 if (match.hasMatch())
152 LOG(VB_PLAYBACK, LOG_INFO, QString(
"ShoutCast: Meta : '%1'")
154 LOG(VB_PLAYBACK, LOG_INFO,
155 QString(
"ShoutCast: Parsed as: '%1' by '%2'")
173 static void myth_av_log(
void *ptr,
int level,
const char* fmt, va_list vl)
178 static QString s_fullLine(
"");
179 static QMutex s_stringLock;
180 uint64_t verbose_mask = VB_GENERAL;
181 LogLevel_t verbose_level = LOG_DEBUG;
187 verbose_level = LOG_EMERG;
190 verbose_level = LOG_CRIT;
193 verbose_level = LOG_ERR;
194 verbose_mask |= VB_LIBAV;
199 verbose_level = LOG_DEBUG;
200 verbose_mask |= VB_LIBAV;
203 verbose_mask |= VB_LIBAV;
213 if (s_fullLine.isEmpty() && ptr) {
214 AVClass* avc = *(AVClass**)ptr;
215 s_fullLine = QString(
"[%1 @ %2] ")
216 .arg(avc->item_name(ptr))
217 .arg(
reinterpret_cast<size_t>(avc),QT_POINTER_SIZE,8,QChar(
'0'));
220 s_fullLine += QString::vasprintf(fmt, vl);
221 if (s_fullLine.endsWith(
"\n"))
223 LOG(verbose_mask, verbose_level, s_fullLine.trimmed());
224 s_fullLine.truncate(0);
226 s_stringLock.unlock();
239 av_log_set_level((
debug) ? AV_LOG_DEBUG : AV_LOG_ERROR);
271 error(
"avfDecoder: initialise called with a NULL audiooutput");
277 error(
"avfDecoder: couldn't allocate memory");
288 error(QString(
"Could not open url (%1)").arg(
m_url));
294 if (
getURL().startsWith(
"http://") ||
getURL().startsWith(
"mmsh://"))
303 if (
getURL().startsWith(
"mmsh://"))
305 AVDictionaryEntry *tag =
nullptr;
326 error(
"Could not determine the stream format.");
333 const AVCodec *codec =
nullptr;
339 error(QString(
"Could not find audio stream."));
351 if (avcodec_open2(
m_audioDec, codec,
nullptr) < 0)
353 error(QString(
"Could not open audio codec: %1")
364 error(QString(
"AVCodecContext tells us %1 channels are "
365 "available, this is bad, bailing.")
376 error(QString(
"Error: Unsupported sample format: %1")
377 .arg(av_get_sample_fmt_name(
m_audioDec->sample_fmt)));
432 AVPacket *pkt = av_packet_alloc();
433 AVPacket *tmp_pkt = av_packet_alloc();
434 if ((pkt ==
nullptr) || (tmp_pkt ==
nullptr))
436 LOG(VB_GENERAL, LOG_ERR,
"packet allocation failed");
453 LOG(VB_GENERAL, LOG_INFO, QString(
"avfdecoder.o: seek time %1")
458 LOG(VB_GENERAL, LOG_ERR,
"Error seeking");
469 if (res != AVERROR_EOF)
471 LOG(VB_GENERAL, LOG_ERR, QString(
"Read frame failed: %1").arg(res));
472 LOG(VB_FILE, LOG_ERR, (
"... for file '" +
m_url) +
"'");
479 av_packet_ref(tmp_pkt, pkt);
481 while (tmp_pkt->size > 0 && !
m_finish &&
495 tmp_pkt->size -= ret;
496 tmp_pkt->data += ret;
504 av_packet_unref(pkt);
514 long count = buffered.count();
515 const struct timespec ns {0, (count - 1000) * 1000000};
516 nanosleep(&ns,
nullptr);
541 av_packet_free(&pkt);
542 av_packet_free(&tmp_pkt);
549 uint8_t *pdata =
nullptr;
553 QString s = QString::fromUtf8((
const char*) pdata);
559 LOG(VB_PLAYBACK, LOG_INFO, QString(
"avfDecoder: shoutcast metadata changed - %1").arg(
m_lastMetadata));
590 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
591 QStringList list =
extension().split(
"|", QString::SkipEmptyParts);
593 QStringList list =
extension().split(
"|", Qt::SkipEmptyParts);
595 return std::any_of(list.cbegin(), list.cend(),
596 [source](
const auto& str)
597 { return str == source.right(str.length()).toLower(); } );
607 static QString s_desc(tr(
"Internal Decoder"));
virtual bool AddData(void *buffer, int len, std::chrono::milliseconds timecode, int frames)=0
Add data to the audiobuffer for playback.
static const int kMaxSizeBuffer
kMaxSizeBuffer is the maximum size of a buffer to be used with DecodeAudio
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
QMap< QString, QString > ShoutCastMetaMap
AVFormatContext * getContext(void)
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
void setObjectName(const QString &name)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
void dispatch(const MythEvent &event)
Dispatch an event to all listeners.
bool initialize() override
RemoteAVFormatContext * m_inputContext
virtual std::chrono::milliseconds GetAudioBufferedTime(void)
report amount of audio buffered in milliseconds.
virtual void Drain(void)=0
Events sent by the DecoderHandler and it's helper classes.
bool supports(const QString &source) const override
virtual void SetSourceBitrate(int)
const QString & description() const override
VERBOSE_PREAMBLE Most debug(nodatabase, notimestamp, noextra)") VERBOSE_MAP(VB_GENERAL
void FreeCodecContext(const AVStream *Stream)
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
avfDecoder(const QString &file, DecoderFactory *d, AudioOutput *o)
const AVInputFormat * m_inputFormat
virtual int DecodeAudio(AVCodecContext *ctx, uint8_t *buffer, int &data_size, const AVPacket *pkt)
Utility routine.
const QString & extension() const override
QString getURL(void) const
void setURL(const QString &url)
Decoder * create(const QString &file, AudioOutput *output, bool deletable) override
void error(const QString &e)
AVCodecContext * m_audioDec
static void myth_av_log(void *ptr, int level, const char *fmt, va_list vl)
DecoderHandler * getDecoderHandler(void)
virtual void Reconfigure(const AudioSettings &settings)=0
void setOutput(AudioOutput *o)
MusicMetadata & getMetadata()
static bool VERBOSE_LEVEL_NONE()
void seek(double pos) override
static const iso6937table * d
~avfDecoder(void) override
virtual void PauseUntilBuffered(void)=0
void checkMetatdata(void)