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