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_DEBUG, QString(
"ShoutCast: Meta : '%1'")
154 LOG(VB_PLAYBACK, LOG_DEBUG,
155 QString(
"ShoutCast: Parsed as: '%1' by '%2' on '%3'")
174 static void myth_av_log(
void *ptr,
int level,
const char* fmt, va_list vl)
179 static QString s_fullLine(
"");
180 static QMutex s_stringLock;
181 uint64_t verbose_mask = VB_GENERAL;
182 LogLevel_t verbose_level = LOG_DEBUG;
188 verbose_level = LOG_EMERG;
191 verbose_level = LOG_CRIT;
194 verbose_level = LOG_ERR;
195 verbose_mask |= VB_LIBAV;
200 verbose_level = LOG_DEBUG;
201 verbose_mask |= VB_LIBAV;
204 verbose_mask |= VB_LIBAV;
214 if (s_fullLine.isEmpty() && ptr) {
215 AVClass* avc = *(AVClass**)ptr;
216 s_fullLine = QString(
"[%1 @ %2] ")
217 .arg(avc->item_name(ptr))
218 .arg(
reinterpret_cast<size_t>(avc),QT_POINTER_SIZE,8,QChar(
'0'));
221 s_fullLine += QString::vasprintf(fmt, vl);
222 if (s_fullLine.endsWith(
"\n"))
224 LOG(verbose_mask, verbose_level, s_fullLine.trimmed());
225 s_fullLine.truncate(0);
227 s_stringLock.unlock();
232 m_outputBuffer((uint8_t *)av_malloc(
AudioOutput::kMaxSizeBuffer))
238 av_log_set_level((
debug) ? AV_LOG_DEBUG : AV_LOG_ERROR);
270 error(
"avfDecoder: initialise called with a NULL audiooutput");
276 error(
"avfDecoder: couldn't allocate memory");
287 error(QString(
"Could not open url (%1)").arg(
m_url));
293 if (
getURL().startsWith(
"http://") ||
getURL().startsWith(
"mmsh://"))
302 if (
getURL().startsWith(
"mmsh://"))
304 AVDictionaryEntry *tag =
nullptr;
325 error(
"Could not determine the stream format.");
332 const AVCodec *codec =
nullptr;
338 error(QString(
"Could not find audio stream."));
350 if (avcodec_open2(
m_audioDec, codec,
nullptr) < 0)
352 error(QString(
"Could not open audio codec: %1")
363 error(QString(
"AVCodecContext tells us %1 channels are "
364 "available, this is bad, bailing.")
375 error(QString(
"Error: Unsupported sample format: %1")
376 .arg(av_get_sample_fmt_name(
m_audioDec->sample_fmt)));
431 AVPacket *pkt = av_packet_alloc();
432 AVPacket *tmp_pkt = av_packet_alloc();
433 if ((pkt ==
nullptr) || (tmp_pkt ==
nullptr))
435 LOG(VB_GENERAL, LOG_ERR,
"packet allocation failed");
452 LOG(VB_GENERAL, LOG_INFO, QString(
"avfdecoder.o: seek time %1")
457 LOG(VB_GENERAL, LOG_ERR,
"Error seeking");
471 if (res != AVERROR_EOF)
473 LOG(VB_GENERAL, LOG_ERR, QString(
"Read frame failed: %1").arg(res));
474 LOG(VB_FILE, LOG_ERR, (
"... for file '" +
m_url) +
"'");
481 av_packet_ref(tmp_pkt, pkt);
483 while (tmp_pkt->size > 0 && !
m_finish &&
497 tmp_pkt->size -= ret;
498 tmp_pkt->data += ret;
506 av_packet_unref(pkt);
516 long count = buffered.count();
517 const struct timespec ns {0, (count - 1000) * 1000000};
518 nanosleep(&ns,
nullptr);
543 av_packet_free(&pkt);
544 av_packet_free(&tmp_pkt);
551 uint8_t *pdata =
nullptr;
555 QString shout = QString::fromUtf8((
const char*) pdata);
564 QString parsed = meta_map[
"title"] +
"\\" + meta_map[
"artist"] +
"\\" + meta_map[
"album"];
569 LOG(VB_PLAYBACK, LOG_INFO, QString(
"avfDecoder: shoutcast metadata changed - %1").arg(shout));
570 LOG(VB_PLAYBACK, LOG_INFO, QString(
"avfDecoder: new metadata (%1)").arg(parsed));
597 QStringList list =
extension().split(
"|", Qt::SkipEmptyParts);
598 return std::any_of(list.cbegin(), list.cend(),
599 [source](
const auto& str)
600 { return str == source.right(str.length()).toLower(); } );
610 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 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
static const Type kStopped
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
static const Type kFinished
static const Type kDecoding
void setOutput(AudioOutput *o)
MusicMetadata & getMetadata()
static const Type kBufferStatus
static bool VERBOSE_LEVEL_NONE()
QString m_lastMetadataParsed
void seek(double pos) override
static const iso6937table * d
~avfDecoder(void) override
virtual void PauseUntilBuffered(void)=0
void checkMetatdata(void)