MythTV master
avfdecoder.cpp
Go to the documentation of this file.
1/*
2 MythMusic libav* Decoder
3 Originally written by Kevin Kuphal with contributions and updates from
4 many others
5
6 Special thanks to
7 ffmpeg team for libavcodec and libavformat
8 qemacs team for their av support which I used to understand the libraries
9 getid3.sourceforget.net project for the ASF information used here
10
11 This library decodes various media files into PCM data
12 returned to the MythMusic output buffer.
13
14 Revision History
15 - Initial release
16 - 1/9/2004 - Improved seek support
17 - ?/?/2009 - Extended to support many more filetypes and bug fixes
18 - ?/7/2010 - Add streaming support
19*/
20
21// C++ headers
22#include <algorithm>
23#include <chrono>
24#include <thread>
25
26// QT headers
27#include <QFile>
28#include <QIODevice>
29#include <QObject>
30#include <QRegularExpression>
31#include <QTimer>
32
33// MythTV headers
45
46// Mythmusic Headers
47#include "avfdecoder.h"
48#include "decoderhandler.h"
49#include "musicplayer.h"
51
52extern "C" {
53 #include <libavformat/avio.h>
54 #include <libavutil/opt.h>
55}
56
57/****************************************************************************/
58
59using ShoutCastMetaMap = QMap<QString,QString>;
60
62{
63 public:
64 ShoutCastMetaParser(void) = default;
65 ~ShoutCastMetaParser(void) = default;
66
67 void setMetaFormat(const QString &metaformat);
68 ShoutCastMetaMap parseMeta(const QString &mdata);
69
70 private:
71 QString m_metaFormat;
75};
76
77void ShoutCastMetaParser::setMetaFormat(const QString &metaformat)
78{
79/*
80 We support these metatags :
81 %a - artist
82 %t - track
83 %b - album
84 %r - random bytes
85 */
86 m_metaFormat = metaformat;
87
91
92 int assign_index = 1;
93 int pos = 0;
94
95 pos = m_metaFormat.indexOf("%", pos);
96 while (pos >= 0)
97 {
98 pos++;
99
100 QChar ch;
101
102 if (pos < m_metaFormat.length())
103 ch = m_metaFormat.at(pos);
104
105 if (!ch.isNull() && ch == '%')
106 {
107 pos++;
108 }
109 else if (!ch.isNull() && (ch == 'r' || ch == 'a' || ch == 'b' || ch == 't'))
110 {
111 if (ch == 'a')
112 m_metaArtistPos = assign_index;
113
114 if (ch == 'b')
115 m_metaAlbumPos = assign_index;
116
117 if (ch == 't')
118 m_metaTitlePos = assign_index;
119
120 assign_index++;
121 }
122 else
123 {
124 LOG(VB_GENERAL, LOG_ERR,
125 QString("ShoutCastMetaParser: malformed metaformat '%1'")
126 .arg(m_metaFormat));
127 }
128
129 pos = m_metaFormat.indexOf("%", pos);
130 }
131
132 m_metaFormat.replace("%a", "(.*)");
133 m_metaFormat.replace("%t", "(.*)");
134 m_metaFormat.replace("%b", "(.*)");
135 m_metaFormat.replace("%r", "(.*)");
136 m_metaFormat.replace("%%", "%");
137}
138
140{
141 ShoutCastMetaMap result;
142 int title_begin_pos = mdata.indexOf("StreamTitle='");
143
144 if (title_begin_pos >= 0)
145 {
146 title_begin_pos += 13;
147 int title_end_pos = mdata.indexOf("';", title_begin_pos);
148 QString title = mdata.mid(title_begin_pos, title_end_pos - title_begin_pos);
149 QRegularExpression rx { m_metaFormat };
150 auto match = rx.match(title);
151 if (match.hasMatch())
152 {
153 LOG(VB_PLAYBACK, LOG_DEBUG, QString("ShoutCast: Meta : '%1'")
154 .arg(mdata));
155 LOG(VB_PLAYBACK, LOG_DEBUG,
156 QString("ShoutCast: Parsed as: '%1' by '%2' on '%3'")
157 .arg(m_metaTitlePos ? match.captured(m_metaTitlePos) : "",
158 m_metaArtistPos ? match.captured(m_metaArtistPos) : "",
159 m_metaAlbumPos ? match.captured(m_metaAlbumPos) : ""));
160
161 if (m_metaTitlePos > 0)
162 result["title"] = match.captured(m_metaTitlePos);
163
164 if (m_metaArtistPos > 0)
165 result["artist"] = match.captured(m_metaArtistPos);
166
167 if (m_metaAlbumPos > 0)
168 result["album"] = match.captured(m_metaAlbumPos);
169 }
170 }
171
172 return result;
173}
174
175static void myth_av_log(void *ptr, int level, const char* fmt, va_list vl)
176{
177 if (VERBOSE_LEVEL_NONE())
178 return;
179
180 static QString s_fullLine("");
181 static QMutex s_stringLock;
182 uint64_t verbose_mask = VB_GENERAL;
183 LogLevel_t verbose_level = LOG_DEBUG;
184
185 // determine mythtv debug level from av log level
186 switch (level)
187 {
188 case AV_LOG_PANIC:
189 verbose_level = LOG_EMERG;
190 break;
191 case AV_LOG_FATAL:
192 verbose_level = LOG_CRIT;
193 break;
194 case AV_LOG_ERROR:
195 verbose_level = LOG_ERR;
196 verbose_mask |= VB_LIBAV;
197 break;
198 case AV_LOG_DEBUG:
199 case AV_LOG_VERBOSE:
200 case AV_LOG_INFO:
201 verbose_level = LOG_DEBUG;
202 verbose_mask |= VB_LIBAV;
203 break;
204 case AV_LOG_WARNING:
205 verbose_mask |= VB_LIBAV;
206 break;
207 default:
208 return;
209 }
210
211 if (!VERBOSE_LEVEL_CHECK(verbose_mask, verbose_level))
212 return;
213
214 s_stringLock.lock();
215 if (s_fullLine.isEmpty() && ptr) {
216 AVClass* avc = *(AVClass**)ptr;
217 s_fullLine = QString("[%1 @ %2] ")
218 .arg(avc->item_name(ptr))
219 .arg(reinterpret_cast<size_t>(avc),QT_POINTER_SIZE,8,QChar('0'));
220 }
221
222 s_fullLine += QString::vasprintf(fmt, vl);
223 if (s_fullLine.endsWith("\n"))
224 {
225 LOG(verbose_mask, verbose_level, s_fullLine.trimmed());
226 s_fullLine.truncate(0);
227 }
228 s_stringLock.unlock();
229}
230
232 Decoder(d, o),
233 m_outputBuffer((uint8_t *)av_malloc(AudioOutput::kMaxSizeBuffer))
234{
235 MThread::setObjectName("avfDecoder");
236 setURL(file);
237
238 bool debug = VERBOSE_LEVEL_CHECK(VB_LIBAV, LOG_ANY);
239 av_log_set_level(debug ? AV_LOG_DEBUG : AV_LOG_ERROR);
240 av_log_set_callback(myth_av_log);
241}
242
244{
245 delete m_mdataTimer;
246
247 if (m_inited)
248 deinit();
249
250 if (m_outputBuffer)
251 av_freep(reinterpret_cast<void*>(&m_outputBuffer));
252
253 delete m_inputContext;
254}
255
257{
258 m_userStop = true;
259}
260
262{
263 m_inited = m_userStop = m_finish = false;
264 m_freq = m_bitrate = 0;
265 m_stat = m_channels = 0;
266 m_seekTime = -1.0;
267
268 // give up if we dont have an audiooutput set
269 if (!output())
270 {
271 error("avfDecoder: initialise called with a NULL audiooutput");
272 return false;
273 }
274
275 if (!m_outputBuffer)
276 {
277 error("avfDecoder: couldn't allocate memory");
278 return false;
279 }
280
282
283 delete m_inputContext;
285
286 if (!m_inputContext->isOpen())
287 {
288 error(QString("Could not open url (%1)").arg(m_url));
289 deinit();
290 return false;
291 }
292
293 // if this is a ice/shoutcast or MMS stream start polling for metadata changes and buffer status
294 if (getURL().startsWith("http://") || getURL().startsWith("mmsh://"))
295 {
296 m_mdataTimer = new QTimer;
297 m_mdataTimer->setSingleShot(false);
299
300 m_mdataTimer->start(500ms);
301
302 // we don't get metadata updates for MMS streams so grab the metadata from the headers
303 if (getURL().startsWith("mmsh://"))
304 {
305 AVDictionaryEntry *tag = nullptr;
307
308 tag = av_dict_get(m_inputContext->getContext()->metadata, "title", tag, AV_DICT_IGNORE_SUFFIX);
309 mdata.setTitle(tag->value);
310
311 tag = av_dict_get(m_inputContext->getContext()->metadata, "artist", tag, AV_DICT_IGNORE_SUFFIX);
312 mdata.setArtist(tag->value);
313
314 mdata.setAlbum("");
315 mdata.setLength(-1ms);
316
318 dispatch(ev);
319 }
320 }
321
322 // determine the stream format
323 // this also populates information needed for metadata
324 if (avformat_find_stream_info(m_inputContext->getContext(), nullptr) < 0)
325 {
326 error("Could not determine the stream format.");
327 deinit();
328 return false;
329 }
330
331 // let FFmpeg finds the best audio stream (should only be one), also catter
332 // should the file/stream not be an audio one
333 const AVCodec *codec = nullptr;
334 int selTrack = av_find_best_stream(m_inputContext->getContext(), AVMEDIA_TYPE_AUDIO,
335 -1, -1, &codec, 0);
336
337 if (selTrack < 0)
338 {
339 error(QString("Could not find audio stream."));
340 deinit();
341 return false;
342 }
343
344 // Store the audio codec of the stream
346 (m_inputContext->getContext()->streams[selTrack]);
347
348 // Store the input format of the context
350
351 if (avcodec_open2(m_audioDec, codec, nullptr) < 0)
352 {
353 error(QString("Could not open audio codec: %1")
354 .arg(m_audioDec->codec_id));
355 deinit();
356 return false;
357 }
358
359 m_freq = m_audioDec->sample_rate;
360 m_channels = m_audioDec->ch_layout.nb_channels;
361
362 if (m_channels <= 0)
363 {
364 error(QString("AVCodecContext tells us %1 channels are "
365 "available, this is bad, bailing.")
366 .arg(m_channels));
367 deinit();
368 return false;
369 }
370
371 AudioFormat format =
373 m_audioDec->bits_per_raw_sample);
374 if (format == FORMAT_NONE)
375 {
376 error(QString("Error: Unsupported sample format: %1")
377 .arg(av_get_sample_fmt_name(m_audioDec->sample_fmt)));
378 deinit();
379 return false;
380 }
381
382 const AudioSettings settings(format, m_audioDec->ch_layout.nb_channels,
383 m_audioDec->codec_id,
384 m_audioDec->sample_rate, false);
385
386 output()->Reconfigure(settings);
387 output()->SetSourceBitrate(m_audioDec->bit_rate);
388
389 m_inited = true;
390 return true;
391}
392
393void avfDecoder::seek(double pos)
394{
396 m_inputContext->getContext()->pb->seekable)
397 {
398 m_seekTime = pos;
399 }
400}
401
403{
404 m_inited = m_userStop = m_finish = false;
405 m_freq = m_bitrate = 0;
406 m_stat = m_channels = 0;
407 setOutput(nullptr);
408
409 // Cleanup here
411 {
412 for (uint i = 0; i < m_inputContext->getContext()->nb_streams; i++)
413 {
414 AVStream *st = m_inputContext->getContext()->streams[i];
416 }
417 }
418
419 m_audioDec = nullptr;
420 m_inputFormat = nullptr;
421}
422
424{
425 RunProlog();
426 if (!m_inited)
427 {
428 RunEpilog();
429 return;
430 }
431
432 AVPacket *pkt = av_packet_alloc();
433 AVPacket *tmp_pkt = av_packet_alloc();
434 if ((pkt == nullptr) || (tmp_pkt == nullptr))
435 {
436 LOG(VB_GENERAL, LOG_ERR, "packet allocation failed");
437 return;
438 }
439
441 {
442 DecoderEvent e((DecoderEvent::Type) m_stat);
443 dispatch(e);
444 }
445
446 av_read_play(m_inputContext->getContext());
447
448 while (!m_finish && !m_userStop)
449 {
450 // Look to see if user has requested a seek
451 if (m_seekTime >= 0.0)
452 {
453 LOG(VB_GENERAL, LOG_INFO, QString("avfdecoder.o: seek time %1")
454 .arg(m_seekTime));
455
456 if (av_seek_frame(m_inputContext->getContext(), -1,
457 (int64_t)(m_seekTime * AV_TIME_BASE), 0) < 0)
458 LOG(VB_GENERAL, LOG_ERR, "Error seeking");
459
460 m_seekTime = -1.0;
461 // Play all pending and restart buffering, else REW/FFWD
462 // takes 1 second per keypress at the "buffered" wait below.
463 output()->Drain(); // (see issue #784)
464 }
465
466 while (!m_finish && !m_userStop && m_seekTime <= 0.0)
467 {
468 // Read a packet from the input context
469 int res = av_read_frame(m_inputContext->getContext(), pkt);
470 if (res < 0)
471 {
472 if (res != AVERROR_EOF)
473 {
474 LOG(VB_GENERAL, LOG_ERR, QString("Read frame failed: %1").arg(res));
475 LOG(VB_FILE, LOG_ERR, ("... for file '" + m_url) + "'");
476 }
477
478 m_finish = true;
479 break;
480 }
481
482 av_packet_ref(tmp_pkt, pkt);
483
484 while (tmp_pkt->size > 0 && !m_finish &&
485 !m_userStop && m_seekTime <= 0.0)
486 {
487 int data_size = 0;
488
489 int ret = output()->DecodeAudio(m_audioDec,
491 data_size,
492 tmp_pkt);
493
494 if (ret < 0)
495 break;
496
497 // Increment the output pointer and count
498 tmp_pkt->size -= ret;
499 tmp_pkt->data += ret;
500
501 if (data_size <= 0)
502 continue;
503
504 output()->AddData(m_outputBuffer, data_size, -1ms, 0);
505 }
506
507 av_packet_unref(pkt);
508
509 // Wait until we need to decode or supply more samples
510 while (!m_finish && !m_userStop && m_seekTime <= 0.0)
511 {
512 std::chrono::milliseconds buffered = output()->GetAudioBufferedTime();
513 // never go below 1s buffered
514 if (buffered < 1s)
515 break;
516 std::this_thread::sleep_for(buffered - 1s);
517 }
518 }
519 }
520
521 if (m_userStop)
522 {
523 m_inited = false;
524 }
525 else
526 {
527 // Drain ao buffer, making sure we play all remaining audio samples
528 output()->Drain();
529 }
530
531 if (m_finish)
533 else if (m_userStop)
535
536 {
537 DecoderEvent e((DecoderEvent::Type) m_stat);
538 dispatch(e);
539 }
540
541 av_packet_free(&pkt);
542 av_packet_free(&tmp_pkt);
543 deinit();
544 RunEpilog();
545}
546
548{
549 uint8_t *pdata = nullptr;
550
551 if (av_opt_get(m_inputContext->getContext(), "icy_metadata_packet", AV_OPT_SEARCH_CHILDREN, &pdata) >= 0)
552 {
553 QString shout = QString::fromUtf8((const char*) pdata);
554
555 if (m_lastMetadata != shout)
556 {
557 m_lastMetadata = shout;
560 ShoutCastMetaMap meta_map = parser.parseMeta(shout);
561
562 QString parsed = meta_map["title"] + "\\" + meta_map["artist"] + "\\" + meta_map["album"];
563 if (m_lastMetadataParsed != parsed)
564 {
565 m_lastMetadataParsed = parsed;
566
567 LOG(VB_PLAYBACK, LOG_INFO, QString("avfDecoder: shoutcast metadata changed - %1").arg(shout));
568 LOG(VB_PLAYBACK, LOG_INFO, QString("avfDecoder: new metadata (%1)").arg(parsed));
569
571 mdata.setTitle(meta_map["title"]);
572 mdata.setArtist(meta_map["artist"]);
573 mdata.setAlbum(meta_map["album"]);
574 mdata.setLength(-1ms);
575
577 dispatch(ev);
578 }
579 }
580
581 av_free(pdata);
582 }
583
584 if (m_inputContext->getContext()->pb)
585 {
586 int available = (int) (m_inputContext->getContext()->pb->buf_end - m_inputContext->getContext()->pb->buffer);
587 int maxSize = m_inputContext->getContext()->pb->buffer_size;
589 dispatch(ev);
590 }
591}
592
593bool avfDecoderFactory::supports(const QString &source) const
594{
595 QStringList list = extension().split("|", Qt::SkipEmptyParts);
596 return std::ranges::any_of(std::as_const(list),
597 [source](const auto& str)
598 { return str == source.right(str.length()).toLower(); } );
599}
600
601const QString &avfDecoderFactory::extension() const
602{
604}
605
606const QString &avfDecoderFactory::description() const
607{
608 static QString s_desc(tr("Internal Decoder"));
609 return s_desc;
610}
611
612Decoder *avfDecoderFactory::create(const QString &file, AudioOutput *output, bool deletable)
613{
614 if (deletable)
615 return new avfDecoder(file, this, output);
616
617 static avfDecoder *s_decoder = nullptr;
618 if (!s_decoder)
619 {
620 s_decoder = new avfDecoder(file, this, output);
621 }
622 else
623 {
624 s_decoder->setOutput(output);
625 }
626
627 return s_decoder;
628}
@ FORMAT_NONE
static void myth_av_log(void *ptr, int level, const char *fmt, va_list vl)
Definition: avfdecoder.cpp:175
QMap< QString, QString > ShoutCastMetaMap
Definition: avfdecoder.cpp:59
static AudioFormat AVSampleFormatToFormat(AVSampleFormat format, int bits=0)
Return AVSampleFormat closest equivalent to AudioFormat.
virtual bool AddData(void *buffer, int len, std::chrono::milliseconds timecode, int frames)=0
Add data to the audiobuffer for playback.
virtual void Drain(void)=0
virtual std::chrono::milliseconds GetAudioBufferedTime(void)
report amount of audio buffered in milliseconds.
Definition: audiooutput.h:151
virtual void PauseUntilBuffered(void)=0
int DecodeAudio(AVCodecContext *ctx, uint8_t *buffer, int &data_size, const AVPacket *pkt)
Utility routine.
virtual void Reconfigure(const AudioSettings &settings)=0
virtual void SetSourceBitrate(int)
Definition: audiooutput.h:153
static const Type kStopped
Definition: decoder.h:45
static const Type kDecoding
Definition: decoder.h:44
static const Type kFinished
Definition: decoder.h:46
Events sent by the DecoderHandler and it's helper classes.
static const Type kBufferStatus
static const Type kMeta
MusicMetadata & getMetadata()
void error(const QString &e)
Definition: decoder.cpp:50
QString getURL(void) const
Definition: decoder.h:90
void setURL(const QString &url)
Definition: decoder.h:82
AudioOutput * output()
Definition: decoder.h:80
QString m_url
Definition: decoder.h:104
void setOutput(AudioOutput *o)
Definition: decoder.cpp:43
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:180
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:193
void setObjectName(const QString &name)
Definition: mthread.cpp:222
static const QString kValidFileExtensions
Definition: metaio.h:160
void setLength(T llength)
void setTitle(const QString &ltitle, const QString &ltitle_sort=nullptr)
QString MetadataFormat(void)
void setAlbum(const QString &lalbum, const QString &lalbum_sort=nullptr)
void setArtist(const QString &lartist, const QString &lartist_sort=nullptr)
DecoderHandler * getDecoderHandler(void)
Definition: musicplayer.h:127
AVCodecContext * GetCodecContext(const AVStream *Stream, const AVCodec *Codec=nullptr, bool NullCodec=false)
Definition: mythavutil.cpp:291
void FreeCodecContext(const AVStream *Stream)
Definition: mythavutil.cpp:336
void dispatch(const MythEvent &event)
Dispatch an event to all listeners.
AVFormatContext * getContext(void)
~ShoutCastMetaParser(void)=default
ShoutCastMetaMap parseMeta(const QString &mdata)
Definition: avfdecoder.cpp:139
ShoutCastMetaParser(void)=default
void setMetaFormat(const QString &metaformat)
Definition: avfdecoder.cpp:77
bool supports(const QString &source) const override
Definition: avfdecoder.cpp:593
Decoder * create(const QString &file, AudioOutput *output, bool deletable) override
Definition: avfdecoder.cpp:612
const QString & description() const override
Definition: avfdecoder.cpp:606
const QString & extension() const override
Definition: avfdecoder.cpp:601
void checkMetatdata(void)
Definition: avfdecoder.cpp:547
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: avfdecoder.cpp:423
bool initialize() override
Definition: avfdecoder.cpp:261
void stop() override
Definition: avfdecoder.cpp:256
QTimer * m_mdataTimer
Definition: avfdecoder.h:65
class RemoteAVFormatContext * m_inputContext
Definition: avfdecoder.h:59
int m_stat
Definition: avfdecoder.h:47
void seek(double pos) override
Definition: avfdecoder.cpp:393
double m_seekTime
Definition: avfdecoder.h:54
MythCodecMap m_codecMap
Definition: avfdecoder.h:61
long m_bitrate
Definition: avfdecoder.h:52
void deinit()
Definition: avfdecoder.cpp:402
~avfDecoder(void) override
Definition: avfdecoder.cpp:243
uint8_t * m_outputBuffer
Definition: avfdecoder.h:48
AVCodecContext * m_audioDec
Definition: avfdecoder.h:60
QString m_lastMetadataParsed
Definition: avfdecoder.h:67
const AVInputFormat * m_inputFormat
Definition: avfdecoder.h:58
QString m_lastMetadata
Definition: avfdecoder.h:66
bool m_finish
Definition: avfdecoder.h:50
long m_freq
Definition: avfdecoder.h:51
bool m_inited
Definition: avfdecoder.h:45
avfDecoder(const QString &file, DecoderFactory *d, AudioOutput *o)
Definition: avfdecoder.cpp:231
bool m_userStop
Definition: avfdecoder.h:46
int m_channels
Definition: avfdecoder.h:53
unsigned int uint
Definition: compat.h:60
static const iso6937table * d
MusicPlayer * gPlayer
Definition: musicplayer.cpp:38
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
static bool VERBOSE_LEVEL_NONE()
Definition: mythlogging.h:28
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define output
VERBOSE_PREAMBLE Most debug(nodatabase, notimestamp, noextra)") VERBOSE_MAP(VB_GENERAL