1 /*
2  * Copyright 2003-2021 The Music Player Daemon Project
3  * http://www.musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 /* necessary because libavutil/common.h uses UINT64_C */
21 #define __STDC_CONSTANT_MACROS
22 
23 #include "lib/ffmpeg/Time.hxx"
24 #include "FfmpegDecoderPlugin.hxx"
25 #include "lib/ffmpeg/Domain.hxx"
26 #include "lib/ffmpeg/Error.hxx"
27 #include "lib/ffmpeg/Init.hxx"
28 #include "lib/ffmpeg/Interleave.hxx"
29 #include "lib/ffmpeg/Buffer.hxx"
30 #include "lib/ffmpeg/Frame.hxx"
31 #include "lib/ffmpeg/Format.hxx"
32 #include "lib/ffmpeg/Codec.hxx"
33 #include "lib/ffmpeg/SampleFormat.hxx"
34 #include "../DecoderAPI.hxx"
35 #include "FfmpegMetaData.hxx"
36 #include "FfmpegIo.hxx"
37 #include "pcm/Interleave.hxx"
38 #include "tag/Builder.hxx"
39 #include "tag/Handler.hxx"
40 #include "tag/ReplayGain.hxx"
41 #include "tag/MixRampParser.hxx"
42 #include "input/InputStream.hxx"
43 #include "pcm/CheckAudioFormat.hxx"
44 #include "util/ScopeExit.hxx"
45 #include "util/ConstBuffer.hxx"
46 #include "util/StringAPI.hxx"
47 #include "Log.hxx"
48 
49 extern "C" {
50 #include <libavcodec/avcodec.h>
51 #include <libavformat/avformat.h>
52 #include <libavformat/avio.h>
53 #include <libavutil/avutil.h>
54 #include <libavutil/frame.h>
55 }
56 
57 #include <cassert>
58 
59 #include <string.h>
60 
61 /**
62  * Muxer options to be passed to avformat_open_input().
63  */
64 static AVDictionary *avformat_options = nullptr;
65 
66 static Ffmpeg::FormatContext
FfmpegOpenInput(AVIOContext * pb,const char * filename,AVInputFormat * fmt)67 FfmpegOpenInput(AVIOContext *pb,
68 		const char *filename,
69 		AVInputFormat *fmt)
70 {
71 	Ffmpeg::FormatContext context(pb);
72 
73 	AVDictionary *options = nullptr;
74 	AtScopeExit(&options) { av_dict_free(&options); };
75 	av_dict_copy(&options, avformat_options, 0);
76 
77 	context.OpenInput(filename, fmt, &options);
78 
79 	return context;
80 }
81 
82 static bool
ffmpeg_init(const ConfigBlock & block)83 ffmpeg_init(const ConfigBlock &block)
84 {
85 	FfmpegInit();
86 
87 	static constexpr const char *option_names[] = {
88 		"probesize",
89 		"analyzeduration",
90 	};
91 
92 	for (const char *name : option_names) {
93 		const char *value = block.GetBlockValue(name);
94 		if (value != nullptr)
95 			av_dict_set(&avformat_options, name, value, 0);
96 	}
97 
98 	return true;
99 }
100 
101 static void
ffmpeg_finish()102 ffmpeg_finish() noexcept
103 {
104 	av_dict_free(&avformat_options);
105 }
106 
107 gcc_pure
108 static bool
IsAudio(const AVStream & stream)109 IsAudio(const AVStream &stream) noexcept
110 {
111 	return stream.codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
112 }
113 
114 gcc_pure
115 static int
ffmpeg_find_audio_stream(const AVFormatContext & format_context)116 ffmpeg_find_audio_stream(const AVFormatContext &format_context) noexcept
117 {
118 	for (unsigned i = 0; i < format_context.nb_streams; ++i)
119 		if (IsAudio(*format_context.streams[i]))
120 			return i;
121 
122 	return -1;
123 }
124 
125 gcc_pure
126 static bool
IsPicture(const AVStream & stream)127 IsPicture(const AVStream &stream) noexcept
128 {
129 	return stream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
130 		(stream.disposition & AV_DISPOSITION_ATTACHED_PIC) != 0 &&
131 		stream.attached_pic.size > 0;
132 }
133 
134 static const AVStream *
FindPictureStream(const AVFormatContext & format_context)135 FindPictureStream(const AVFormatContext &format_context) noexcept
136 {
137 	for (unsigned i = 0; i < format_context.nb_streams; ++i)
138 		if (IsPicture(*format_context.streams[i]))
139 			return format_context.streams[i];
140 
141 	return nullptr;
142 }
143 
144 static const char *
GetMimeType(const AVCodecDescriptor & codec)145 GetMimeType(const AVCodecDescriptor &codec) noexcept
146 {
147 	return codec.mime_types != nullptr
148 		? *codec.mime_types
149 		: nullptr;
150 }
151 
152 static const char *
GetMimeType(const AVStream & stream)153 GetMimeType(const AVStream &stream) noexcept
154 {
155 	const auto *codec = avcodec_descriptor_get(stream.codecpar->codec_id);
156 	if (codec != nullptr)
157 		return GetMimeType(*codec);
158 
159 	return nullptr;
160 }
161 
162 static ConstBuffer<void>
ToConstBuffer(const AVPacket & packet)163 ToConstBuffer(const AVPacket &packet) noexcept
164 {
165 	return {packet.data, size_t(packet.size)};
166 }
167 
168 /**
169  * Accessor for AVStream::start_time that replaces AV_NOPTS_VALUE with
170  * zero.  We can't use AV_NOPTS_VALUE in calculations, and we simply
171  * assume that the stream's start time is zero, which appears to be
172  * the best way out of that situation.
173  */
174 static constexpr int64_t
start_time_fallback(const AVStream & stream)175 start_time_fallback(const AVStream &stream)
176 {
177 	return FfmpegTimestampFallback(stream.start_time, 0);
178 }
179 
180 /**
181  * Convert AVPacket::pts to a stream-relative time stamp (still in
182  * AVStream::time_base units).  Returns a negative value on error.
183  */
184 gcc_pure
185 static int64_t
StreamRelativePts(const AVPacket & packet,const AVStream & stream)186 StreamRelativePts(const AVPacket &packet, const AVStream &stream) noexcept
187 {
188 	auto pts = packet.pts;
189 	if (pts < 0 || pts == int64_t(AV_NOPTS_VALUE))
190 		return -1;
191 
192 	auto start = start_time_fallback(stream);
193 	return pts - start;
194 }
195 
196 /**
197  * Convert a non-negative stream-relative time stamp in
198  * AVStream::time_base units to a PCM frame number.
199  */
200 gcc_pure
201 static uint64_t
PtsToPcmFrame(uint64_t pts,const AVStream & stream,const AVCodecContext & codec_context)202 PtsToPcmFrame(uint64_t pts, const AVStream &stream,
203 	      const AVCodecContext &codec_context) noexcept
204 {
205 	return av_rescale_q(pts, stream.time_base, codec_context.time_base);
206 }
207 
208 /**
209  * Invoke DecoderClient::SubmitData() with the contents of an
210  * #AVFrame.
211  */
212 static DecoderCommand
FfmpegSendFrame(DecoderClient & client,InputStream * is,AVCodecContext & codec_context,const AVFrame & frame,size_t & skip_bytes,FfmpegBuffer & buffer)213 FfmpegSendFrame(DecoderClient &client, InputStream *is,
214 		AVCodecContext &codec_context,
215 		const AVFrame &frame,
216 		size_t &skip_bytes,
217 		FfmpegBuffer &buffer)
218 {
219 	ConstBuffer<void> output_buffer =
220 		Ffmpeg::InterleaveFrame(frame, buffer);
221 
222 	if (skip_bytes > 0) {
223 		if (skip_bytes >= output_buffer.size) {
224 			skip_bytes -= output_buffer.size;
225 			return DecoderCommand::NONE;
226 		}
227 
228 		output_buffer.data =
229 			(const uint8_t *)output_buffer.data + skip_bytes;
230 		output_buffer.size -= skip_bytes;
231 		skip_bytes = 0;
232 	}
233 
234 	return client.SubmitData(is,
235 				 output_buffer.data, output_buffer.size,
236 				 codec_context.bit_rate / 1000);
237 }
238 
239 static DecoderCommand
FfmpegReceiveFrames(DecoderClient & client,InputStream * is,AVCodecContext & codec_context,AVFrame & frame,size_t & skip_bytes,FfmpegBuffer & buffer,bool & eof)240 FfmpegReceiveFrames(DecoderClient &client, InputStream *is,
241 		    AVCodecContext &codec_context,
242 		    AVFrame &frame,
243 		    size_t &skip_bytes,
244 		    FfmpegBuffer &buffer,
245 		    bool &eof)
246 {
247 	while (true) {
248 		DecoderCommand cmd;
249 
250 		int err = avcodec_receive_frame(&codec_context, &frame);
251 		switch (err) {
252 		case 0:
253 			cmd = FfmpegSendFrame(client, is, codec_context,
254 					      frame, skip_bytes,
255 					      buffer);
256 			if (cmd != DecoderCommand::NONE)
257 				return cmd;
258 
259 			break;
260 
261 		case AVERROR_EOF:
262 			eof = true;
263 			return DecoderCommand::NONE;
264 
265 		case AVERROR(EAGAIN):
266 			/* need to call avcodec_send_packet() */
267 			return DecoderCommand::NONE;
268 
269 		default:
270 			{
271 				char msg[256];
272 				av_strerror(err, msg, sizeof(msg));
273 				FmtWarning(ffmpeg_domain,
274 					   "avcodec_send_packet() failed: {}",
275 					   msg);
276 			}
277 
278 			return DecoderCommand::STOP;
279 		}
280 	}
281 }
282 
283 /**
284  * Decode an #AVPacket and send the resulting PCM data to the decoder
285  * API.
286  *
287  * @param min_frame skip all data before this PCM frame number; this
288  * is used after seeking to skip data in an AVPacket until the exact
289  * desired time stamp has been reached
290  */
291 static DecoderCommand
ffmpeg_send_packet(DecoderClient & client,InputStream * is,const AVPacket & packet,AVCodecContext & codec_context,const AVStream & stream,AVFrame & frame,uint64_t min_frame,size_t pcm_frame_size,FfmpegBuffer & buffer)292 ffmpeg_send_packet(DecoderClient &client, InputStream *is,
293 		   const AVPacket &packet,
294 		   AVCodecContext &codec_context,
295 		   const AVStream &stream,
296 		   AVFrame &frame,
297 		   uint64_t min_frame, size_t pcm_frame_size,
298 		   FfmpegBuffer &buffer)
299 {
300 	size_t skip_bytes = 0;
301 
302 	const auto pts = StreamRelativePts(packet, stream);
303 	if (pts >= 0) {
304 		if (min_frame > 0) {
305 			auto cur_frame = PtsToPcmFrame(pts, stream,
306 						       codec_context);
307 			if (cur_frame < min_frame)
308 				skip_bytes = pcm_frame_size * (min_frame - cur_frame);
309 		} else
310 			client.SubmitTimestamp(FfmpegTimeToDouble(pts,
311 								  stream.time_base));
312 	}
313 
314 	bool eof = false;
315 
316 	int err = avcodec_send_packet(&codec_context, &packet);
317 	switch (err) {
318 	case 0:
319 		break;
320 
321 	case AVERROR_EOF:
322 		eof = true;
323 		break;
324 
325 	default:
326 		{
327 			char msg[256];
328 			av_strerror(err, msg, sizeof(msg));
329 			FmtWarning(ffmpeg_domain,
330 				   "avcodec_send_packet() failed: {}", msg);
331 		}
332 
333 		return DecoderCommand::NONE;
334 	}
335 
336 	auto cmd = FfmpegReceiveFrames(client, is, codec_context,
337 				       frame,
338 				       skip_bytes, buffer, eof);
339 
340 	if (eof)
341 		cmd = DecoderCommand::STOP;
342 
343 	return cmd;
344 }
345 
346 gcc_const
347 static SampleFormat
ffmpeg_sample_format(enum AVSampleFormat sample_fmt)348 ffmpeg_sample_format(enum AVSampleFormat sample_fmt) noexcept
349 {
350 	const auto result = Ffmpeg::FromFfmpegSampleFormat(sample_fmt);
351 	if (result != SampleFormat::UNDEFINED)
352 		return result;
353 
354 	char buffer[64];
355 	const char *name = av_get_sample_fmt_string(buffer, sizeof(buffer),
356 						    sample_fmt);
357 	if (name != nullptr)
358 		FmtError(ffmpeg_domain,
359 			 "Unsupported libavcodec SampleFormat value: {} ({})",
360 			 name, sample_fmt);
361 	else
362 		FmtError(ffmpeg_domain,
363 			 "Unsupported libavcodec SampleFormat value: {}",
364 			 sample_fmt);
365 	return SampleFormat::UNDEFINED;
366 }
367 
368 static void
FfmpegParseMetaData(AVDictionary & dict,ReplayGainInfo & rg,MixRampInfo & mr)369 FfmpegParseMetaData(AVDictionary &dict, ReplayGainInfo &rg, MixRampInfo &mr)
370 {
371 	AVDictionaryEntry *i = nullptr;
372 
373 	while ((i = av_dict_get(&dict, "", i,
374 				AV_DICT_IGNORE_SUFFIX)) != nullptr) {
375 		const char *name = i->key;
376 		const char *value = i->value;
377 
378 		if (!ParseReplayGainTag(rg, name, value))
379 			ParseMixRampTag(mr, name, value);
380 	}
381 }
382 
383 static void
FfmpegParseMetaData(const AVStream & stream,ReplayGainInfo & rg,MixRampInfo & mr)384 FfmpegParseMetaData(const AVStream &stream,
385 		    ReplayGainInfo &rg, MixRampInfo &mr)
386 {
387 	FfmpegParseMetaData(*stream.metadata, rg, mr);
388 }
389 
390 static void
FfmpegParseMetaData(const AVFormatContext & format_context,int audio_stream,ReplayGainInfo & rg,MixRampInfo & mr)391 FfmpegParseMetaData(const AVFormatContext &format_context, int audio_stream,
392 		    ReplayGainInfo &rg, MixRampInfo &mr)
393 {
394 	assert(audio_stream >= 0);
395 
396 	FfmpegParseMetaData(*format_context.metadata, rg, mr);
397 	FfmpegParseMetaData(*format_context.streams[audio_stream],
398 				    rg, mr);
399 }
400 
401 static void
FfmpegParseMetaData(DecoderClient & client,const AVFormatContext & format_context,int audio_stream)402 FfmpegParseMetaData(DecoderClient &client,
403 		    const AVFormatContext &format_context, int audio_stream)
404 {
405 	ReplayGainInfo rg;
406 	rg.Clear();
407 
408 	MixRampInfo mr;
409 	mr.Clear();
410 
411 	FfmpegParseMetaData(format_context, audio_stream, rg, mr);
412 
413 	if (rg.IsDefined())
414 		client.SubmitReplayGain(&rg);
415 
416 	if (mr.IsDefined())
417 		client.SubmitMixRamp(std::move(mr));
418 }
419 
420 static void
FfmpegScanMetadata(const AVStream & stream,TagHandler & handler)421 FfmpegScanMetadata(const AVStream &stream, TagHandler &handler) noexcept
422 {
423 	FfmpegScanDictionary(stream.metadata, handler);
424 }
425 
426 static void
FfmpegScanMetadata(const AVFormatContext & format_context,int audio_stream,TagHandler & handler)427 FfmpegScanMetadata(const AVFormatContext &format_context, int audio_stream,
428 		   TagHandler &handler) noexcept
429 {
430 	assert(audio_stream >= 0);
431 
432 	FfmpegScanDictionary(format_context.metadata, handler);
433 	FfmpegScanMetadata(*format_context.streams[audio_stream],
434 			   handler);
435 }
436 
437 static void
FfmpegScanTag(const AVFormatContext & format_context,int audio_stream,TagBuilder & tag)438 FfmpegScanTag(const AVFormatContext &format_context, int audio_stream,
439 	      TagBuilder &tag)
440 {
441 	FullTagHandler h(tag);
442 	FfmpegScanMetadata(format_context, audio_stream, h);
443 }
444 
445 /**
446  * Check if a new stream tag was received and pass it to
447  * DecoderClient::SubmitTag().
448  */
449 static void
FfmpegCheckTag(DecoderClient & client,InputStream * is,AVFormatContext & format_context,int audio_stream)450 FfmpegCheckTag(DecoderClient &client, InputStream *is,
451 	       AVFormatContext &format_context, int audio_stream)
452 {
453 	AVStream &stream = *format_context.streams[audio_stream];
454 	if ((stream.event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) == 0)
455 		/* no new metadata */
456 		return;
457 
458 	/* clear the flag */
459 	stream.event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
460 
461 	TagBuilder tag;
462 	FfmpegScanTag(format_context, audio_stream, tag);
463 	if (!tag.empty())
464 		client.SubmitTag(is, tag.Commit());
465 }
466 
467 static bool
IsSeekable(const AVFormatContext & format_context)468 IsSeekable(const AVFormatContext &format_context) noexcept
469 {
470 #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 6, 100)
471 	return (format_context.ctx_flags & AVFMTCTX_UNSEEKABLE) != 0;
472 #else
473 	(void)format_context;
474 	return false;
475 #endif
476 }
477 
478 static void
FfmpegDecode(DecoderClient & client,InputStream * input,AVFormatContext & format_context)479 FfmpegDecode(DecoderClient &client, InputStream *input,
480 	     AVFormatContext &format_context)
481 {
482 	const int find_result =
483 		avformat_find_stream_info(&format_context, nullptr);
484 	if (find_result < 0) {
485 		LogError(ffmpeg_domain, "Couldn't find stream info");
486 		return;
487 	}
488 
489 	int audio_stream = ffmpeg_find_audio_stream(format_context);
490 	if (audio_stream == -1) {
491 		LogError(ffmpeg_domain, "No audio stream inside");
492 		return;
493 	}
494 
495 	AVStream &av_stream = *format_context.streams[audio_stream];
496 
497 	const auto &codec_params = *av_stream.codecpar;
498 
499 	const AVCodecDescriptor *codec_descriptor =
500 		avcodec_descriptor_get(codec_params.codec_id);
501 	if (codec_descriptor != nullptr)
502 		FmtDebug(ffmpeg_domain, "codec '{}'",
503 			 codec_descriptor->name);
504 
505 	const AVCodec *codec = avcodec_find_decoder(codec_params.codec_id);
506 
507 	if (!codec) {
508 		LogError(ffmpeg_domain, "Unsupported audio codec");
509 		return;
510 	}
511 
512 	Ffmpeg::CodecContext codec_context(*codec);
513 	codec_context.FillFromParameters(*av_stream.codecpar);
514 	codec_context.Open(*codec, nullptr);
515 
516 	const SampleFormat sample_format =
517 		ffmpeg_sample_format(codec_context->sample_fmt);
518 	if (sample_format == SampleFormat::UNDEFINED) {
519 		// (error message already done by ffmpeg_sample_format())
520 		return;
521 	}
522 
523 	const auto audio_format = CheckAudioFormat(codec_context->sample_rate,
524 						   sample_format,
525 						   codec_context->channels);
526 
527 	const SignedSongTime total_time =
528 		av_stream.duration != (int64_t)AV_NOPTS_VALUE
529 		? FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base)
530 		: FromFfmpegTimeChecked(format_context.duration, AV_TIME_BASE_Q);
531 
532 	client.Ready(audio_format,
533 		     input
534 		     ? input->IsSeekable()
535 		     : IsSeekable(format_context),
536 		     total_time);
537 
538 	FfmpegParseMetaData(client, format_context, audio_stream);
539 
540 	Ffmpeg::Frame frame;
541 
542 	FfmpegBuffer interleaved_buffer;
543 
544 	uint64_t min_frame = 0;
545 
546 	DecoderCommand cmd = client.GetCommand();
547 	while (cmd != DecoderCommand::STOP) {
548 		if (cmd == DecoderCommand::SEEK) {
549 			int64_t where =
550 				ToFfmpegTime(client.GetSeekTime(),
551 					     av_stream.time_base) +
552 				start_time_fallback(av_stream);
553 
554 			/* AVSEEK_FLAG_BACKWARD asks FFmpeg to seek to
555 			   the packet boundary before the seek time
556 			   stamp, not after */
557 			if (av_seek_frame(&format_context, audio_stream, where,
558 					  AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0)
559 				client.SeekError();
560 			else {
561 				codec_context.FlushBuffers();
562 				min_frame = client.GetSeekFrame();
563 				client.CommandFinished();
564 			}
565 		}
566 
567 		AVPacket packet;
568 		if (av_read_frame(&format_context, &packet) < 0)
569 			/* end of file */
570 			break;
571 
572 		AtScopeExit(&packet) {
573 			av_packet_unref(&packet);
574 		};
575 
576 		FfmpegCheckTag(client, input, format_context, audio_stream);
577 
578 		if (packet.size > 0 && packet.stream_index == audio_stream) {
579 			cmd = ffmpeg_send_packet(client, input,
580 						 packet,
581 						 *codec_context,
582 						 av_stream,
583 						 *frame,
584 						 min_frame, audio_format.GetFrameSize(),
585 						 interleaved_buffer);
586 			min_frame = 0;
587 		} else
588 			cmd = client.GetCommand();
589 	}
590 }
591 
592 static void
ffmpeg_decode(DecoderClient & client,InputStream & input)593 ffmpeg_decode(DecoderClient &client, InputStream &input)
594 {
595 	AvioStream stream(&client, input);
596 	if (!stream.Open()) {
597 		LogError(ffmpeg_domain, "Failed to open stream");
598 		return;
599 	}
600 
601 	auto format_context =
602 		FfmpegOpenInput(stream.io, input.GetURI(), nullptr);
603 
604 	const auto *input_format = format_context->iformat;
605 	if (input_format->long_name == nullptr)
606 		FmtDebug(ffmpeg_domain, "detected input format '{}'",
607 			 input_format->name);
608 	else
609 		FmtDebug(ffmpeg_domain, "detected input format '{}' ({})",
610 			 input_format->name, input_format->long_name);
611 
612 	FfmpegDecode(client, &input, *format_context);
613 }
614 
615 static bool
FfmpegScanStream(AVFormatContext & format_context,TagHandler & handler)616 FfmpegScanStream(AVFormatContext &format_context, TagHandler &handler)
617 {
618 	const int find_result =
619 		avformat_find_stream_info(&format_context, nullptr);
620 	if (find_result < 0)
621 		return false;
622 
623 	const int audio_stream = ffmpeg_find_audio_stream(format_context);
624 	if (audio_stream < 0)
625 		return false;
626 
627 	const AVStream &stream = *format_context.streams[audio_stream];
628 	if (stream.duration != (int64_t)AV_NOPTS_VALUE)
629 		handler.OnDuration(FromFfmpegTime(stream.duration,
630 						  stream.time_base));
631 	else if (format_context.duration != (int64_t)AV_NOPTS_VALUE)
632 		handler.OnDuration(FromFfmpegTime(format_context.duration,
633 						  AV_TIME_BASE_Q));
634 
635 	const auto &codec_params = *stream.codecpar;
636 	try {
637 		handler.OnAudioFormat(CheckAudioFormat(codec_params.sample_rate,
638 						       ffmpeg_sample_format(AVSampleFormat(codec_params.format)),
639 						       codec_params.channels));
640 	} catch (...) {
641 	}
642 
643 	FfmpegScanMetadata(format_context, audio_stream, handler);
644 
645 	if (handler.WantPicture()) {
646 		const auto *picture_stream = FindPictureStream(format_context);
647 		if (picture_stream != nullptr)
648 			handler.OnPicture(GetMimeType(*picture_stream),
649 					  ToConstBuffer(picture_stream->attached_pic));
650 	}
651 
652 	return true;
653 }
654 
655 static bool
ffmpeg_scan_stream(InputStream & is,TagHandler & handler)656 ffmpeg_scan_stream(InputStream &is, TagHandler &handler)
657 {
658 	AvioStream stream(nullptr, is);
659 	if (!stream.Open())
660 		return false;
661 
662 	auto f = FfmpegOpenInput(stream.io, is.GetURI(), nullptr);
663 	return FfmpegScanStream(*f, handler);
664 }
665 
666 #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 9, 100)
667 
668 static void
ffmpeg_uri_decode(DecoderClient & client,const char * uri)669 ffmpeg_uri_decode(DecoderClient &client, const char *uri)
670 {
671 	auto format_context =
672 		FfmpegOpenInput(nullptr, uri, nullptr);
673 
674 	const auto *input_format = format_context->iformat;
675 	if (input_format->long_name == nullptr)
676 		FmtDebug(ffmpeg_domain, "detected input format '{}'",
677 			 input_format->name);
678 	else
679 		FmtDebug(ffmpeg_domain, "detected input format '{}' ({})",
680 			 input_format->name, input_format->long_name);
681 
682 	FfmpegDecode(client, nullptr, *format_context);
683 }
684 
685 static std::set<std::string>
ffmpeg_protocols()686 ffmpeg_protocols() noexcept
687 {
688 	std::set<std::string> protocols;
689 
690 	const AVInputFormat *format = nullptr;
691 	void *opaque = nullptr;
692 	while ((format = av_demuxer_iterate(&opaque)) != nullptr) {
693 		if (StringIsEqual(format->name, "rtsp")) {
694 			protocols.emplace("rtsp://");
695 			protocols.emplace("rtsps://");
696 		} else if (StringIsEqual(format->name, "rtp"))
697 			protocols.emplace("rtp://");
698 	}
699 
700 	return protocols;
701 }
702 
703 #endif
704 
705 /**
706  * A list of extensions found for the formats supported by ffmpeg.
707  * This list is current as of 02-23-09; To find out if there are more
708  * supported formats, check the ffmpeg changelog since this date for
709  * more formats.
710  */
711 static const char *const ffmpeg_suffixes[] = {
712 	"16sv", "3g2", "3gp", "4xm", "8svx",
713 	"aa3", "aac", "ac3", "adx", "afc", "aif",
714 	"aifc", "aiff", "al", "alaw", "amr", "anim", "apc", "ape", "asf",
715 	"atrac", "au", "aud", "avi", "avm2", "avs", "bap", "bfi", "c93", "cak",
716 	"cin", "cmv", "cpk", "daud", "dct", "divx", "dts", "dv", "dvd", "dxa",
717 	"eac3", "film", "flac", "flc", "fli", "fll", "flx", "flv", "g726",
718 	"gsm", "gxf", "iss", "m1v", "m2v", "m2t", "m2ts",
719 	"m4a", "m4b", "m4v",
720 	"mad",
721 	"mj2", "mjpeg", "mjpg", "mka", "mkv", "mlp", "mm", "mmf", "mov", "mp+",
722 	"mp1", "mp2", "mp3", "mp4", "mpc", "mpeg", "mpg", "mpga", "mpp", "mpu",
723 	"mve", "mvi", "mxf", "nc", "nsv", "nut", "nuv", "oga", "ogm", "ogv",
724 	"ogx", "oma", "ogg", "omg", "opus", "psp", "pva", "qcp", "qt", "r3d", "ra",
725 	"ram", "rl2", "rm", "rmvb", "roq", "rpl", "rvc", "shn", "smk", "snd",
726 	"sol", "son", "spx", "str", "swf", "tak", "tgi", "tgq", "tgv", "thp", "ts",
727 	"tsp", "tta", "xa", "xvid", "uv", "uv2", "vb", "vid", "vob", "voc",
728 	"vp6", "vmd", "wav", "webm", "wma", "wmv", "wsaud", "wsvga", "wv",
729 	"wve",
730 	nullptr
731 };
732 
733 static const char *const ffmpeg_mime_types[] = {
734 	"application/flv",
735 	"application/m4a",
736 	"application/mp4",
737 	"application/octet-stream",
738 	"application/ogg",
739 	"application/x-ms-wmz",
740 	"application/x-ms-wmd",
741 	"application/x-ogg",
742 	"application/x-shockwave-flash",
743 	"application/x-shorten",
744 	"audio/8svx",
745 	"audio/16sv",
746 	"audio/aac",
747 	"audio/aacp",
748 	"audio/ac3",
749 	"audio/aiff",
750 	"audio/amr",
751 	"audio/basic",
752 	"audio/flac",
753 	"audio/m4a",
754 	"audio/mp4",
755 	"audio/mpeg",
756 	"audio/musepack",
757 	"audio/ogg",
758 	"audio/opus",
759 	"audio/qcelp",
760 	"audio/vorbis",
761 	"audio/vorbis+ogg",
762 	"audio/wav",
763 	"audio/x-8svx",
764 	"audio/x-16sv",
765 	"audio/x-aac",
766 	"audio/x-ac3",
767 	"audio/x-adx",
768 	"audio/x-aiff",
769 	"audio/x-alaw",
770 	"audio/x-au",
771 	"audio/x-dca",
772 	"audio/x-eac3",
773 	"audio/x-flac",
774 	"audio/x-gsm",
775 	"audio/x-mace",
776 	"audio/x-matroska",
777 	"audio/x-monkeys-audio",
778 	"audio/x-mpeg",
779 	"audio/x-ms-wma",
780 	"audio/x-ms-wax",
781 	"audio/x-musepack",
782 	"audio/x-ogg",
783 	"audio/x-vorbis",
784 	"audio/x-vorbis+ogg",
785 	"audio/x-pn-realaudio",
786 	"audio/x-pn-multirate-realaudio",
787 	"audio/x-speex",
788 	"audio/x-tta",
789 	"audio/x-voc",
790 	"audio/x-wav",
791 	"audio/x-wma",
792 	"audio/x-wv",
793 	"video/anim",
794 	"video/quicktime",
795 	"video/msvideo",
796 	"video/ogg",
797 	"video/theora",
798 	"video/webm",
799 	"video/x-dv",
800 	"video/x-flv",
801 	"video/x-matroska",
802 	"video/x-mjpeg",
803 	"video/x-mpeg",
804 	"video/x-ms-asf",
805 	"video/x-msvideo",
806 	"video/x-ms-wmv",
807 	"video/x-ms-wvx",
808 	"video/x-ms-wm",
809 	"video/x-ms-wmx",
810 	"video/x-nut",
811 	"video/x-pva",
812 	"video/x-theora",
813 	"video/x-vid",
814 	"video/x-wmv",
815 	"video/x-xvid",
816 
817 	/* special value for the "ffmpeg" input plugin: all streams by
818 	   the "ffmpeg" input plugin shall be decoded by this
819 	   plugin */
820 	"audio/x-mpd-ffmpeg",
821 
822 	nullptr
823 };
824 
825 constexpr DecoderPlugin ffmpeg_decoder_plugin =
826 	DecoderPlugin("ffmpeg", ffmpeg_decode, ffmpeg_scan_stream)
827 	.WithInit(ffmpeg_init, ffmpeg_finish)
828 #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 9, 100)
829 	.WithProtocols(ffmpeg_protocols, ffmpeg_uri_decode)
830 #endif
831 	.WithSuffixes(ffmpeg_suffixes)
832 	.WithMimeTypes(ffmpeg_mime_types);
833